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...
40 // Maximum length copied from the current selection to the search string
41 const int LYXSEARCH_MAXLEN = 128;
43 // function prototypes
45 // If nothing selected, select the word at the cursor.
46 // Returns the current selection
47 // Note: this function should be in LyXText!
48 string const GetSelectionOrWordAtCursor(LyXText * lt);
50 // Returns the current selection. If nothing is selected or if the selection
51 // spans 2 paragraphs, an empty string is returned.
52 string const GetCurrentSelectionAsString(LyXText * lt);
54 // This is a copy of SetSelectionOverString from text.C
55 // It does the same, but uses only the length as a parameter
56 void SetSelectionOverLenChars(LyXText * lt, int len);
58 //-------------------------------------------------------------
62 // Returns the current selection. If nothing is selected or if the selection
63 // spans 2 paragraphs, an empty string is returned.
64 string const GetCurrentSelectionAsString(LyXText * lt)
66 char sz[LYXSEARCH_MAXLEN];
69 LyXParagraph * par = lt->cursor.par;
70 if (lt->selection && (lt->sel_cursor.par == par)) {
71 // (selected) and (begin/end in same paragraph)
72 LyXParagraph::size_type pos =
73 lt->sel_start_cursor.pos;
74 LyXParagraph::size_type endpos =
75 lt->sel_end_cursor.pos;
77 bool fPrevIsSpace = false;
79 while ((i < LYXSEARCH_MAXLEN - 2) &&
80 (pos < par->Last()) && (pos < endpos)) {
81 ch = par->GetChar(pos);
83 //HB??: Maybe (ch <= ' ')
84 if ((ch == ' ') || (ch <= LyXParagraph::META_INSET)) {
85 // consecutive spaces --> 1 space char
87 ++pos; // Next text pos
88 continue; // same search pos
105 // If nothing selected, select the word at the cursor.
106 // Returns the current selection
107 string const GetSelectionOrWordAtCursor(LyXText * lt)
109 lt->SelectWordWhenUnderCursor();
110 return GetCurrentSelectionAsString(lt);
114 // This is a copy of SetSelectionOverString from text.C
115 // It does the same, but uses only the length as a parameter
116 void SetSelectionOverLenChars(LyXText * lt, int len)
118 lt->sel_cursor = lt->cursor;
119 for (int i = 0; i < len; ++i)
125 //------------------------------
127 void LyXFindReplace1::StartSearch()
129 LyXFindReplace0::StartSearch();
130 SetReplaceEnabled(!current_view->buffer()->isReadonly());
131 searchForward = true;
132 if (lsSearch.empty())
133 SetSearchString(GetSelectionOrWordAtCursor(current_view->text));
137 // TODO?: the user can insert multiple spaces with this
138 // routine (1999-01-11, dnaber)
139 void LyXFindReplace1::SearchReplaceCB()
141 if (!current_view->getScreen()) return;
142 if (current_view->buffer()->isReadonly()) return;
144 // CutSelection cannot cut a single space, so we have to stop
145 // in order to avoid endless loop :-(
147 if (SearchString().length() == 0 || (SearchString().length() == 1
148 && SearchString()[0] == ' ') ) {
149 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
150 "nor an empty character."));
154 string const replacestring = ReplaceString();
156 current_view->getScreen()->HideCursor();
157 current_view->update(-2);
159 LyXText * ltCur = current_view->text;
160 if (ltCur->selection) {
161 // clear the selection (if there is any)
162 current_view->getScreen()->ToggleSelection(false);
164 ReplaceSelectionWithString(replacestring.c_str());
166 SetSelectionOverString(replacestring.c_str());
167 current_view->update(1);
170 // jump to next match:
171 SearchCB( searchForward );
175 // replaces all occurences of a string (1999-01-15, dnaber@mini.gt.owl.de)
176 void LyXFindReplace1::SearchReplaceAllCB()
178 if (!current_view->getScreen()) return;
179 if (current_view->buffer()->isReadonly()) return;
181 // CutSelection cannot cut a single space, so we have to stop
182 // in order to avoid endless loop :-(
184 if (SearchString().length() == 0 || (SearchString().length() == 1
185 && SearchString()[0] == ' ') ) {
186 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
187 "nor an empty character."));
191 string const replacestring = ReplaceString();
193 current_view->getScreen()->HideCursor();
196 current_view->text->ClearSelection();
197 current_view->text->CursorTop();
199 int replace_count = 0;
202 ltCur = current_view->text;
203 if (ltCur->selection) {
204 current_view->update(-2);
205 current_view->getScreen()->ToggleSelection(false);
207 ReplaceSelectionWithString(replacestring.c_str());
209 SetSelectionOverString(replacestring.c_str());
210 current_view->update(1);
213 } while( SearchCB(true) );
214 if( replace_count == 0 ) {
216 current_view->owner()->getMiniBuffer()->Set(
217 _("String not found!"));
219 if (replace_count == 1) {
220 current_view->owner()->getMiniBuffer()->Set(
221 _("1 string has been replaced."));
223 string str = tostr(replace_count);
224 str += _(" strings have been replaced.");
225 current_view->owner()->getMiniBuffer()->Set(str);
231 bool LyXFindReplace1::SearchCB(bool fForward)
233 // store search direction
234 searchForward = fForward;
236 if (!current_view->getScreen())
239 current_view->getScreen()->HideCursor();
240 current_view->update(-2);
241 LyXText * ltCur = current_view->text;
242 if (ltCur->selection)
243 ltCur->cursor = fForward ? ltCur->sel_end_cursor :
244 ltCur->sel_start_cursor;
247 iLenSelected = SearchString().length();
250 if (!ValidSearchData() ||
251 (fForward ? SearchForward(ltCur) : SearchBackward(ltCur))) {
252 current_view->update(-2);
254 // clear the selection (if there is any)
255 current_view->getScreen()->ToggleSelection();
256 current_view->text->ClearSelection();
258 // set the new selection
259 SetSelectionOverLenChars(current_view->text, iLenSelected);
260 current_view->getScreen()->ToggleSelection(false);
261 current_view->owner()->getMiniBuffer()->Set(_("Found."));
265 current_view->owner()->getMiniBuffer()->Set(_("String not found!"));
270 if (current_view->focus())
271 current_view->getScreen()->ShowCursor();
273 if (current_view->getWorkArea()->focus)
274 current_view->getScreen()->ShowCursor();
280 // if the string can be found: return true and set the cursor to
282 // (was: LyXText::SearchForward(char const* string) in text2.C )
283 bool LyXFindReplace1::SearchForward(LyXText * lt)
285 LyXParagraph * par = lt->cursor.par;
286 LyXParagraph::size_type pos = lt->cursor.pos;
288 while (par && !IsSearchStringInText(par, pos)) {
289 if (pos < par->Last() - 1)
297 lt->SetCursor(par, pos);
304 // if the string can be found: return true and set the cursor to
306 // (was: LyXText::SearchBackward(char const* string) in text2.C )
307 bool LyXFindReplace1::SearchBackward(LyXText * lt)
309 LyXParagraph * par = lt->cursor.par;
310 int pos = lt->cursor.pos;
316 // We skip empty paragraphs (Asger)
318 par = par->Previous();
320 pos = par->Last() - 1;
321 } while (par && pos < 0);
323 } while (par && !IsSearchStringInText(par, pos));
326 lt->SetCursor(par, pos);
333 /* Compares 2 char values.
335 > 0 if chSearch > ch2
336 = 0 if chSearch == ch2
337 < 0 if chSearch < ch2
339 int LyXFindReplace1::CompareChars(char chSearch, char chText)
342 return (chSearch - chText);
343 return (toupper(chSearch) - toupper(chText));
347 // returns true if the search string is at the specified position
348 // (Copied from the original "LyXText::IsStringInText" in text2.C )
349 bool LyXFindReplace1::IsSearchStringInText(LyXParagraph * par,
350 LyXParagraph::size_type pos)
352 if (!par) return false;
356 bool fPrevIsSpace = false;
358 string::size_type iSrch = 0;
359 while (pos + iText < par->Last() &&
360 iSrch < SearchString().length()) {
361 chSrch = SearchString()[iSrch];
362 chText = par->GetChar(pos+iText);
365 ++iText; // next Text pos
366 continue; // same search pos
370 fPrevIsSpace = false;
371 if (CompareChars(chSrch, chText) != 0)
378 if (iSrch < SearchString().length())
382 || ((pos <= 0 || !IsLetterCharOrDigit(par->GetChar(pos - 1)))
383 && (pos + iText >= par->Last()
384 || !IsLetterCharOrDigit(par->GetChar(pos + iText))))) {
385 iLenSelected = iText;