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"
36 #include "support/textutils.h"
38 extern BufferView *current_view; // called too many times in this file...
39 extern MiniBuffer *minibuffer;
41 // Maximum length copied from the current selection to the search string
42 const int LYXSEARCH_MAXLEN = 128;
44 // function prototypes
46 // If nothing selected, select the word at the cursor.
47 // Returns the current selection
48 // Note: this function should be in LyXText!
49 string const GetSelectionOrWordAtCursor(LyXText *lt);
51 // Returns the current selection. If nothing is selected or if the selection
52 // spans 2 paragraphs, an empty string is returned.
53 string const GetCurrentSelectionAsString(LyXText *lt);
55 // This is a copy of SetSelectionOverString from text.C
56 // It does the same, but uses only the length as a parameter
57 void SetSelectionOverLenChars(LyXText *lt, int len);
59 //-------------------------------------------------------------
63 // Returns the current selection. If nothing is selected or if the selection
64 // spans 2 paragraphs, an empty string is returned.
65 string const GetCurrentSelectionAsString(LyXText * lt)
67 char sz[LYXSEARCH_MAXLEN];
70 LyXParagraph * par = lt->cursor.par;
71 if (lt->selection && (lt->sel_cursor.par == par)) {
72 // (selected) and (begin/end in same paragraph)
73 LyXParagraph::size_type pos =
74 lt->sel_start_cursor.pos;
75 LyXParagraph::size_type endpos =
76 lt->sel_end_cursor.pos;
78 bool fPrevIsSpace = false;
80 while ((i < LYXSEARCH_MAXLEN-2) &&
81 (pos < par->Last()) && (pos < endpos)) {
82 ch = par->GetChar(pos);
84 //HB??: Maybe (ch <= ' ')
85 if ((ch == ' ') || (ch <= LyXParagraph::META_INSET)) {
86 // consecutive spaces --> 1 space char
88 pos++; // Next text pos
89 continue; // same search pos
106 // If nothing selected, select the word at the cursor.
107 // Returns the current selection
108 string const GetSelectionOrWordAtCursor(LyXText *lt)
110 lt->SelectWordWhenUnderCursor();
111 return GetCurrentSelectionAsString(lt);
115 // This is a copy of SetSelectionOverString from text.C
116 // It does the same, but uses only the length as a parameter
117 void SetSelectionOverLenChars(LyXText *lt, int len)
119 lt->sel_cursor = lt->cursor;
121 for (i= 0; i < len; i++)
127 //------------------------------
129 void LyXFindReplace1::StartSearch()
131 LyXFindReplace0::StartSearch();
132 SetReplaceEnabled(!current_view->buffer()->isReadonly());
133 searchForward = true;
135 if (lsSearch.empty())
136 SetSearchString(GetSelectionOrWordAtCursor(current_view->text));
138 if (lsSearch.empty())
139 SetSearchString(GetSelectionOrWordAtCursor(current_view->buffer()->text));
144 // TODO?: the user can insert multiple spaces with this routine (1999-01-11, dnaber)
145 void LyXFindReplace1::SearchReplaceCB()
147 if (!current_view->getScreen())
149 if (current_view->buffer()->isReadonly())
152 // CutSelection cannot cut a single space, so we have to stop
153 // in order to avoid endless loop :-(
155 if (SearchString().length() == 0 || (SearchString().length() == 1
156 && SearchString()[0] == ' ') ) {
157 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
158 "nor an empty character."));
162 string const replacestring = ReplaceString();
164 current_view->getScreen()->HideCursor();
166 current_view->update(-2);
168 LyXText * ltCur = current_view->text;
169 if (ltCur->selection) {
170 // clear the selection (if there is any)
171 current_view->getScreen()->ToggleSelection(false);
173 ReplaceSelectionWithString(replacestring.c_str());
175 SetSelectionOverString(replacestring.c_str());
176 current_view->update(1);
179 current_view->buffer()->update(-2);
181 LyXText * ltCur = current_view->buffer()->text;
182 if (ltCur->selection) {
183 // clear the selection (if there is any)
184 current_view->getScreen()->ToggleSelection(false);
185 current_view->buffer()->text->
186 ReplaceSelectionWithString(replacestring.c_str());
187 current_view->buffer()->text->
188 SetSelectionOverString(replacestring.c_str());
189 current_view->buffer()->update(1);
193 // jump to next match:
194 SearchCB( searchForward );
198 // replaces all occurences of a string (1999-01-15, dnaber@mini.gt.owl.de)
199 void LyXFindReplace1::SearchReplaceAllCB()
203 if (!current_view->getScreen())
205 if (current_view->buffer()->isReadonly())
208 // CutSelection cannot cut a single space, so we have to stop
209 // in order to avoid endless loop :-(
211 if (SearchString().length() == 0 || (SearchString().length() == 1
212 && SearchString()[0] == ' ') ) {
213 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
214 "nor an empty character."));
218 string const replacestring = ReplaceString();
220 current_view->getScreen()->HideCursor();
224 current_view->text->ClearSelection();
225 current_view->text->CursorTop();
227 int replace_count = 0;
229 ltCur = current_view->text;
230 if (ltCur->selection) {
231 current_view->update(-2);
232 current_view->getScreen()->ToggleSelection(false);
234 ReplaceSelectionWithString(replacestring.c_str());
236 SetSelectionOverString(replacestring.c_str());
237 current_view->update(1);
240 } while( SearchCB(true) );
243 current_view->buffer()->text->ClearSelection();
244 current_view->buffer()->text->CursorTop();
246 int replace_count = 0;
248 ltCur = current_view->buffer()->text;
249 if (ltCur->selection) {
250 current_view->buffer()->update(-2);
251 current_view->getScreen()->ToggleSelection(false);
252 current_view->buffer()->text->
253 ReplaceSelectionWithString(replacestring.c_str());
254 current_view->buffer()->text->
255 SetSelectionOverString(replacestring.c_str());
256 current_view->buffer()->update(1);
259 } while( SearchCB(true) );
261 if( replace_count == 0 ) {
263 minibuffer->Set(_("String not found!"));
265 if( replace_count == 1 ) {
266 minibuffer->Set(_("1 string has been replaced."));
268 string str = tostr(replace_count);
269 str += _(" strings have been replaced.");
270 minibuffer->Set(str);
276 bool LyXFindReplace1::SearchCB(bool fForward)
281 // store search direction
282 searchForward = fForward;
284 if (!current_view->getScreen())
287 current_view->getScreen()->HideCursor();
289 current_view->update(-2);
290 ltCur = current_view->text;
292 current_view->buffer()->update(-2);
293 ltCur = current_view->buffer()->text;
295 if (ltCur->selection)
296 ltCur->cursor = fForward ? ltCur->sel_end_cursor :
297 ltCur->sel_start_cursor;
300 iLenSelected = SearchString().length();
302 if (!ValidSearchData() ||
303 (fForward ? SearchForward(ltCur) : SearchBackward(ltCur))) {
305 current_view->update(-2);
307 // clear the selection (if there is any)
308 current_view->getScreen()->ToggleSelection();
309 current_view->text->ClearSelection();
311 // set the new selection
312 SetSelectionOverLenChars(current_view->text, iLenSelected);
314 current_view->buffer()->update(-2);
316 // clear the selection (if there is any)
317 current_view->getScreen()->ToggleSelection();
318 current_view->buffer()->text->ClearSelection();
320 // set the new selection
321 SetSelectionOverLenChars(current_view->buffer()->text, iLenSelected);
323 current_view->getScreen()->ToggleSelection(false);
324 minibuffer->Set(_("Found."));
328 minibuffer->Set(_("String not found!"));
332 if (current_view->getWorkArea()->focus)
333 current_view->getScreen()->ShowCursor();
339 // if the string can be found: return true and set the cursor to
341 // (was: LyXText::SearchForward(char const* string) in text2.C )
342 bool LyXFindReplace1::SearchForward(LyXText * lt)
344 LyXParagraph * par = lt->cursor.par;
345 LyXParagraph::size_type pos = lt->cursor.pos;
347 while (par && !IsSearchStringInText(par, pos)) {
348 if (pos<par->Last()-1)
356 lt->SetCursor(par, pos);
363 // if the string can be found: return true and set the cursor to
365 // (was: LyXText::SearchBackward(char const* string) in text2.C )
366 bool LyXFindReplace1::SearchBackward(LyXText *lt)
368 LyXParagraph *par = lt->cursor.par;
369 int pos = lt->cursor.pos;
375 // We skip empty paragraphs (Asger)
377 par = par->Previous();
380 } while (par && pos<0);
382 } while (par && !IsSearchStringInText(par, pos));
385 lt->SetCursor(par, pos);
392 /* Compares 2 char values.
394 > 0 if chSearch > ch2
395 = 0 if chSearch == ch2
396 < 0 if chSearch < ch2
398 int LyXFindReplace1::CompareChars(char chSearch, char chText)
401 return (chSearch - chText);
402 return (toupper(chSearch) - toupper(chText));
406 // returns true if the search string is at the specified position
407 // (Copied from the original "LyXText::IsStringInText" in text2.C )
408 bool LyXFindReplace1::IsSearchStringInText(LyXParagraph * par,
409 LyXParagraph::size_type pos)
417 bool fPrevIsSpace = false;
419 string::size_type iSrch = 0;
420 while (pos + iText < par->Last() &&
421 iSrch < SearchString().length()) {
422 chSrch = SearchString()[iSrch];
423 chText = par->GetChar(pos+iText);
426 iText++; // next Text pos
427 continue; // same search pos
431 fPrevIsSpace = false;
432 if (CompareChars(chSrch, chText) != 0)
439 if (iSrch < SearchString().length())
443 || ((pos <= 0 || !IsLetterCharOrDigit(par->GetChar(pos-1)))
444 && (pos + iText >= par->Last()
445 || !IsLetterCharOrDigit(par->GetChar(pos + iText))))) {
446 iLenSelected = iText;