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;
120 for (int i = 0; i < len; ++i)
126 //------------------------------
128 void LyXFindReplace1::StartSearch()
130 LyXFindReplace0::StartSearch();
131 SetReplaceEnabled(!current_view->buffer()->isReadonly());
132 searchForward = true;
133 if (lsSearch.empty())
134 SetSearchString(GetSelectionOrWordAtCursor(current_view->text));
138 // TODO?: the user can insert multiple spaces with this
139 // routine (1999-01-11, dnaber)
140 void LyXFindReplace1::SearchReplaceCB()
142 if (!current_view->getScreen()) return;
143 if (current_view->buffer()->isReadonly()) return;
145 // CutSelection cannot cut a single space, so we have to stop
146 // in order to avoid endless loop :-(
148 if (SearchString().length() == 0 || (SearchString().length() == 1
149 && SearchString()[0] == ' ') ) {
150 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
151 "nor an empty character."));
155 string const replacestring = ReplaceString();
157 current_view->getScreen()->HideCursor();
158 current_view->update(-2);
160 LyXText * ltCur = current_view->text;
161 if (ltCur->selection) {
162 // clear the selection (if there is any)
163 current_view->getScreen()->ToggleSelection(false);
165 ReplaceSelectionWithString(replacestring.c_str());
167 SetSelectionOverString(replacestring.c_str());
168 current_view->update(1);
171 // jump to next match:
172 SearchCB( searchForward );
176 // replaces all occurences of a string (1999-01-15, dnaber@mini.gt.owl.de)
177 void LyXFindReplace1::SearchReplaceAllCB()
179 if (!current_view->getScreen()) return;
180 if (current_view->buffer()->isReadonly()) return;
182 // CutSelection cannot cut a single space, so we have to stop
183 // in order to avoid endless loop :-(
185 if (SearchString().length() == 0 || (SearchString().length() == 1
186 && SearchString()[0] == ' ') ) {
187 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
188 "nor an empty character."));
192 string const replacestring = ReplaceString();
194 current_view->getScreen()->HideCursor();
197 current_view->text->ClearSelection();
198 current_view->text->CursorTop();
200 int replace_count = 0;
203 ltCur = current_view->text;
204 if (ltCur->selection) {
205 current_view->update(-2);
206 current_view->getScreen()->ToggleSelection(false);
208 ReplaceSelectionWithString(replacestring.c_str());
210 SetSelectionOverString(replacestring.c_str());
211 current_view->update(1);
214 } while( SearchCB(true) );
215 if( replace_count == 0 ) {
217 minibuffer->Set(_("String not found!"));
219 if( replace_count == 1 ) {
220 minibuffer->Set(_("1 string has been replaced."));
222 string str = tostr(replace_count);
223 str += _(" strings have been replaced.");
224 minibuffer->Set(str);
230 bool LyXFindReplace1::SearchCB(bool fForward)
232 // store search direction
233 searchForward = fForward;
235 if (!current_view->getScreen())
238 current_view->getScreen()->HideCursor();
239 current_view->update(-2);
240 LyXText * ltCur = current_view->text;
241 if (ltCur->selection)
242 ltCur->cursor = fForward ? ltCur->sel_end_cursor :
243 ltCur->sel_start_cursor;
246 iLenSelected = SearchString().length();
249 if (!ValidSearchData() ||
250 (fForward ? SearchForward(ltCur) : SearchBackward(ltCur))) {
251 current_view->update(-2);
253 // clear the selection (if there is any)
254 current_view->getScreen()->ToggleSelection();
255 current_view->text->ClearSelection();
257 // set the new selection
258 SetSelectionOverLenChars(current_view->text, iLenSelected);
259 current_view->getScreen()->ToggleSelection(false);
260 minibuffer->Set(_("Found."));
264 minibuffer->Set(_("String not found!"));
268 if (current_view->getWorkArea()->focus)
269 current_view->getScreen()->ShowCursor();
275 // if the string can be found: return true and set the cursor to
277 // (was: LyXText::SearchForward(char const* string) in text2.C )
278 bool LyXFindReplace1::SearchForward(LyXText * lt)
280 LyXParagraph * par = lt->cursor.par;
281 LyXParagraph::size_type pos = lt->cursor.pos;
283 while (par && !IsSearchStringInText(par, pos)) {
284 if (pos < par->Last() - 1)
292 lt->SetCursor(par, pos);
299 // if the string can be found: return true and set the cursor to
301 // (was: LyXText::SearchBackward(char const* string) in text2.C )
302 bool LyXFindReplace1::SearchBackward(LyXText * lt)
304 LyXParagraph * par = lt->cursor.par;
305 int pos = lt->cursor.pos;
311 // We skip empty paragraphs (Asger)
313 par = par->Previous();
315 pos = par->Last() - 1;
316 } while (par && pos < 0);
318 } while (par && !IsSearchStringInText(par, pos));
321 lt->SetCursor(par, pos);
328 /* Compares 2 char values.
330 > 0 if chSearch > ch2
331 = 0 if chSearch == ch2
332 < 0 if chSearch < ch2
334 int LyXFindReplace1::CompareChars(char chSearch, char chText)
337 return (chSearch - chText);
338 return (toupper(chSearch) - toupper(chText));
342 // returns true if the search string is at the specified position
343 // (Copied from the original "LyXText::IsStringInText" in text2.C )
344 bool LyXFindReplace1::IsSearchStringInText(LyXParagraph * par,
345 LyXParagraph::size_type pos)
347 if (!par) return false;
351 bool fPrevIsSpace = false;
353 string::size_type iSrch = 0;
354 while (pos + iText < par->Last() &&
355 iSrch < SearchString().length()) {
356 chSrch = SearchString()[iSrch];
357 chText = par->GetChar(pos+iText);
360 ++iText; // next Text pos
361 continue; // same search pos
365 fPrevIsSpace = false;
366 if (CompareChars(chSrch, chText) != 0)
373 if (iSrch < SearchString().length())
377 || ((pos <= 0 || !IsLetterCharOrDigit(par->GetChar(pos - 1)))
378 && (pos + iText >= par->Last()
379 || !IsLetterCharOrDigit(par->GetChar(pos + iText))))) {
380 iLenSelected = iText;