1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich,
7 * Copyright 1995-1999 The LyX Team.
9 * ======================================================*/
18 #pragma implementation
23 #include FORMS_H_LOCATION
28 #include "lyxscreen.h"
33 #include "lyx_gui_misc.h"
34 #include "minibuffer.h"
35 #include "support/lstrings.h"
37 extern BufferView *current_view; // called too many times in this file...
38 extern MiniBuffer *minibuffer;
40 // Maximum length copied from the current selection to the search string
41 const int LYXSEARCH_MAXLEN = 128;
43 // function prototypes
45 bool IsLetterCharOrDigit(char ch);
47 // If nothing selected, select the word at the cursor.
48 // Returns the current selection
49 // Note: this function should be in LyXText!
50 string const GetSelectionOrWordAtCursor(LyXText *lt);
52 // Returns the current selection. If nothing is selected or if the selection
53 // spans 2 paragraphs, an empty string is returned.
54 string const GetCurrentSelectionAsString(LyXText *lt);
56 // This is a copy of SetSelectionOverString from text.C
57 // It does the same, but uses only the length as a parameter
58 void SetSelectionOverLenChars(LyXText *lt, int len);
60 //-------------------------------------------------------------
62 bool IsLetterCharOrDigit(char ch)
64 return IsLetterChar(ch) || isdigit(ch);
68 // Returns the current selection. If nothing is selected or if the selection
69 // spans 2 paragraphs, an empty string is returned.
70 string const GetCurrentSelectionAsString(LyXText * lt)
72 char sz[LYXSEARCH_MAXLEN];
75 LyXParagraph * par = lt->cursor.par;
76 if (lt->selection && (lt->sel_cursor.par == par)) {
77 // (selected) and (begin/end in same paragraph)
79 LyXParagraph::size_type pos =
80 lt->sel_start_cursor.pos;
81 LyXParagraph::size_type endpos =
82 lt->sel_end_cursor.pos;
85 lt->sel_start_cursor.pos;
87 lt->sel_end_cursor.pos;
90 bool fPrevIsSpace = false;
92 while ((i < LYXSEARCH_MAXLEN-2) &&
93 (pos < par->Last()) && (pos < endpos)) {
94 ch = par->GetChar(pos);
96 //HB??: Maybe (ch <= ' ')
97 if ((ch == ' ') || (ch <= LYX_META_INSET)) {
98 // consecutive spaces --> 1 space char
100 pos++; // Next text pos
101 continue; // same search pos
107 fPrevIsSpace = false;
118 // If nothing selected, select the word at the cursor.
119 // Returns the current selection
120 string const GetSelectionOrWordAtCursor(LyXText *lt)
122 lt->SelectWordWhenUnderCursor();
123 return GetCurrentSelectionAsString(lt);
127 // This is a copy of SetSelectionOverString from text.C
128 // It does the same, but uses only the length as a parameter
129 void SetSelectionOverLenChars(LyXText *lt, int len)
131 lt->sel_cursor = lt->cursor;
133 for (i=0; i < len; i++)
139 //------------------------------
141 void LyXFindReplace1::StartSearch()
143 LyXFindReplace0::StartSearch();
144 SetReplaceEnabled(!current_view->currentBuffer()->isReadonly());
145 searchForward = true;
146 if (lsSearch.empty())
147 SetSearchString(GetSelectionOrWordAtCursor(current_view->currentBuffer()->text));
151 // TODO?: the user can insert multiple spaces with this routine (1999-01-11, dnaber)
152 void LyXFindReplace1::SearchReplaceCB()
156 if (!current_view->getScreen())
158 if (current_view->currentBuffer()->isReadonly())
161 // CutSelection cannot cut a single space, so we have to stop
162 // in order to avoid endless loop :-(
164 if (SearchString().length() == 0 || (SearchString().length() == 1
165 && SearchString()[0] == ' ') ) {
166 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
167 "nor an empty character."));
171 string const replacestring = ReplaceString();
173 current_view->getScreen()->HideCursor();
174 current_view->currentBuffer()->update(-2);
176 ltCur = current_view->currentBuffer()->text;
177 if (ltCur->selection) {
178 // clear the selection (if there is any)
179 current_view->getScreen()->ToggleSelection(false);
180 current_view->currentBuffer()->text->
181 ReplaceSelectionWithString(replacestring.c_str());
182 current_view->currentBuffer()->text->
183 SetSelectionOverString(replacestring.c_str());
184 current_view->currentBuffer()->update(1);
187 // jump to next match:
188 SearchCB( searchForward );
192 // replaces all occurences of a string (1999-01-15, dnaber@mini.gt.owl.de)
193 void LyXFindReplace1::SearchReplaceAllCB()
197 if (!current_view->getScreen())
199 if (current_view->currentBuffer()->isReadonly())
202 // CutSelection cannot cut a single space, so we have to stop
203 // in order to avoid endless loop :-(
205 if (SearchString().length() == 0 || (SearchString().length() == 1
206 && SearchString()[0] == ' ') ) {
207 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
208 "nor an empty character."));
212 string const replacestring = ReplaceString();
214 current_view->getScreen()->HideCursor();
217 current_view->currentBuffer()->text->ClearSelection();
218 current_view->currentBuffer()->text->CursorTop();
220 int replace_count = 0;
222 ltCur = current_view->currentBuffer()->text;
223 if (ltCur->selection) {
224 current_view->currentBuffer()->update(-2);
225 current_view->getScreen()->ToggleSelection(false);
226 current_view->currentBuffer()->text->
227 ReplaceSelectionWithString(replacestring.c_str());
228 current_view->currentBuffer()->text->
229 SetSelectionOverString(replacestring.c_str());
230 current_view->currentBuffer()->update(1);
233 } while( SearchCB(true) );
235 if( replace_count == 0 ) {
237 minibuffer->Set(_("String not found!"));
239 if( replace_count == 1 ) {
240 minibuffer->Set(_("1 string has been replaced."));
242 string str = tostr(replace_count);
243 str += _(" strings have been replaced.");
244 minibuffer->Set(str);
250 bool LyXFindReplace1::SearchCB(bool fForward)
255 // store search direction
256 searchForward = fForward;
258 if (!current_view->getScreen())
261 current_view->getScreen()->HideCursor();
262 current_view->currentBuffer()->update(-2);
263 ltCur = current_view->currentBuffer()->text;
264 if (ltCur->selection)
265 ltCur->cursor = fForward ? ltCur->sel_end_cursor :
266 ltCur->sel_start_cursor;
269 iLenSelected = SearchString().length();
271 if (!ValidSearchData() ||
272 (fForward ? SearchForward(ltCur) : SearchBackward(ltCur))) {
273 current_view->currentBuffer()->update(-2);
275 // clear the selection (if there is any)
276 current_view->getScreen()->ToggleSelection();
277 current_view->currentBuffer()->text->ClearSelection();
279 // set the new selection
280 SetSelectionOverLenChars(current_view->currentBuffer()->text, iLenSelected);
281 current_view->getScreen()->ToggleSelection(false);
282 minibuffer->Set(_("Found."));
286 minibuffer->Set(_("String not found!"));
290 if (current_view->getWorkArea()->focus)
291 current_view->getScreen()->ShowCursor();
297 // if the string can be found: return true and set the cursor to
299 // (was: LyXText::SearchForward(char const* string) in text2.C )
300 bool LyXFindReplace1::SearchForward(LyXText * lt)
302 LyXParagraph * par = lt->cursor.par;
304 LyXParagraph::size_type pos = lt->cursor.pos;
306 int pos = lt->cursor.pos;
309 while (par && !IsSearchStringInText(par,pos)) {
310 if (pos<par->Last()-1)
318 lt->SetCursor(par,pos);
325 // if the string can be found: return true and set the cursor to
327 // (was: LyXText::SearchBackward(char const* string) in text2.C )
328 bool LyXFindReplace1::SearchBackward(LyXText *lt)
330 LyXParagraph *par = lt->cursor.par;
331 int pos = lt->cursor.pos;
337 // We skip empty paragraphs (Asger)
339 par = par->Previous();
342 } while (par && pos<0);
344 } while (par && !IsSearchStringInText(par,pos));
347 lt->SetCursor(par,pos);
354 /* Compares 2 char values.
356 > 0 if chSearch > ch2
357 = 0 if chSearch == ch2
358 < 0 if chSearch < ch2
360 int LyXFindReplace1::CompareChars(char chSearch, char chText)
363 return (chSearch - chText);
364 return (toupper(chSearch) - toupper(chText));
368 // returns true if the search string is at the specified position
369 // (Copied from the original "LyXText::IsStringInText" in text2.C )
371 bool LyXFindReplace1::IsSearchStringInText(LyXParagraph * par,
372 LyXParagraph::size_type pos)
374 bool LyXFindReplace1::IsSearchStringInText(LyXParagraph * par,
384 bool fPrevIsSpace = false;
386 string::size_type iSrch = 0;
387 while (pos + iText < par->Last() &&
388 iSrch < SearchString().length()) {
389 chSrch = SearchString()[iSrch];
390 chText = par->GetChar(pos+iText);
393 iText++; // next Text pos
394 continue; // same search pos
398 fPrevIsSpace = false;
399 if (CompareChars(chSrch, chText) != 0)
406 if (iSrch < SearchString().length())
410 || ((pos <= 0 || !IsLetterCharOrDigit(par->GetChar(pos-1)))
411 && (pos + iText >= par->Last()
412 || !IsLetterCharOrDigit(par->GetChar(pos + iText))))) {
413 iLenSelected = iText;