1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich,
7 * Copyright 1995-2000 The LyX Team.
9 * ====================================================== */
14 #pragma implementation
21 #include "minibuffer.h"
22 #include "lyx_gui_misc.h"
23 #include "support/textutils.h"
24 #include "support/lstrings.h"
25 #include "BufferView.h"
28 // Returns the current selection. If nothing is selected or if the selection
29 // spans 2 paragraphs, an empty string is returned.
31 string GetCurrentSelectionAsString(LyXText * lt)
35 LyXParagraph * par = lt->cursor.par;
36 if (lt->selection && lt->sel_cursor.par == par) {
37 // (selected) and (begin/end in same paragraph)
38 LyXParagraph::size_type pos =
39 lt->sel_start_cursor.pos;
40 LyXParagraph::size_type endpos =
41 lt->sel_end_cursor.pos;
42 bool fPrevIsSpace = false;
44 while (pos < par->Last() && pos < endpos) {
45 ch = par->GetChar(pos);
47 //HB??: Maybe (ch <= ' ')
48 if ((ch == ' ') || (ch <= LyXParagraph::META_INSET)) {
49 // consecutive spaces --> 1 space char
51 ++pos; // Next text pos
52 continue; // same search pos
67 // If nothing selected, select the word at the cursor.
68 // Returns the current selection
70 string GetSelectionOrWordAtCursor(LyXText * lt)
72 lt->SelectWordWhenUnderCursor();
73 return GetCurrentSelectionAsString(lt);
77 // This is a copy of SetSelectionOverString from text.C
78 // It does the same, but uses only the length as a parameter
80 void SetSelectionOverLenChars(LyXText * lt, int len)
82 lt->sel_cursor = lt->cursor;
83 for (int i = 0; i < len; ++i)
89 //------------------------------
92 LyXFindReplace::LyXFindReplace()
97 LyXFindReplace::~LyXFindReplace()
101 void LyXFindReplace::StartSearch(BufferView * b)
104 SF.StartSearch(this);
105 SF.replaceEnabled(!bv->buffer()->isReadonly());
106 searchForward = true;
107 if (SF.SearchString().empty())
108 SF.SetSearchString(GetSelectionOrWordAtCursor(bv->text));
112 // TODO?: the user can insert multiple spaces with this
113 // routine (1999-01-11, dnaber)
114 void LyXFindReplace::SearchReplaceCB()
116 if (!bv->available()) return;
117 if (bv->buffer()->isReadonly()) return;
119 // CutSelection cannot cut a single space, so we have to stop
120 // in order to avoid endless loop :-(
121 if (SF.SearchString().length() == 0
122 || (SF.SearchString().length() == 1
123 && SF.SearchString()[0] == ' ') ) {
124 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
125 "nor an empty character."));
129 string const replacestring = SF.ReplaceString();
134 LyXText * ltCur = bv->text;
135 if (ltCur->selection) {
136 // clear the selection (if there is any)
137 bv->toggleSelection(false);
139 ReplaceSelectionWithString(replacestring.c_str());
141 SetSelectionOverString(replacestring.c_str());
145 // jump to next match:
146 SearchCB(searchForward);
150 // replaces all occurences of a string (1999-01-15, dnaber@mini.gt.owl.de)
151 void LyXFindReplace::SearchReplaceAllCB()
153 if (!bv->available()) return;
154 if (bv->buffer()->isReadonly()) return;
156 // CutSelection cannot cut a single space, so we have to stop
157 // in order to avoid endless loop :-(
158 if (SF.SearchString().length() == 0
159 || (SF.SearchString().length() == 1
160 && SF.SearchString()[0] == ' ') ) {
161 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
162 "nor an empty character."));
166 string const replacestring = SF.ReplaceString();
171 bv->text->ClearSelection();
172 bv->text->CursorTop();
174 int replace_count = 0;
178 if (ltCur->selection) {
180 bv->toggleSelection(false);
182 ReplaceSelectionWithString(replacestring.c_str());
184 SetSelectionOverString(replacestring.c_str());
188 } while (SearchCB(true));
189 if( replace_count == 0 ) {
191 bv->owner()->getMiniBuffer()->Set(
192 _("String not found!"));
194 if (replace_count == 1) {
195 bv->owner()->getMiniBuffer()->Set(
196 _("1 string has been replaced."));
198 string str = tostr(replace_count);
199 str += _(" strings have been replaced.");
200 bv->owner()->getMiniBuffer()->Set(str);
206 bool LyXFindReplace::SearchCB(bool fForward)
208 // store search direction
209 searchForward = fForward;
211 if (!bv->available())
216 LyXText * ltCur = bv->text;
217 if (ltCur->selection)
218 ltCur->cursor = fForward ? ltCur->sel_end_cursor :
219 ltCur->sel_start_cursor;
221 iLenSelected = SF.SearchString().length();
224 if (!SF.ValidSearchData() ||
225 (fForward ? SearchForward(ltCur) : SearchBackward(ltCur))) {
228 // clear the selection (if there is any)
229 bv->toggleSelection();
230 bv->text->ClearSelection();
232 // set the new selection
233 SetSelectionOverLenChars(bv->text, iLenSelected);
234 bv->toggleSelection(false);
235 bv->owner()->getMiniBuffer()->Set(_("Found."));
239 bv->owner()->getMiniBuffer()->Set(_("String not found!"));
250 // if the string can be found: return true and set the cursor to
252 // (was: LyXText::SearchForward(char const* string) in text2.C )
253 bool LyXFindReplace::SearchForward(LyXText * lt)
255 LyXParagraph * par = lt->cursor.par;
256 LyXParagraph::size_type pos = lt->cursor.pos;
258 while (par && !IsSearchStringInText(par, pos)) {
259 if (pos < par->Last() - 1)
267 lt->SetCursor(par, pos);
274 // if the string can be found: return true and set the cursor to
276 // (was: LyXText::SearchBackward(char const* string) in text2.C )
277 bool LyXFindReplace::SearchBackward(LyXText * lt)
279 LyXParagraph * par = lt->cursor.par;
280 int pos = lt->cursor.pos;
286 // We skip empty paragraphs (Asger)
288 par = par->Previous();
290 pos = par->Last() - 1;
291 } while (par && pos < 0);
293 } while (par && !IsSearchStringInText(par, pos));
296 lt->SetCursor(par, pos);
303 /* Compares 2 char values.
305 > 0 if chSearch > ch2
306 = 0 if chSearch == ch2
307 < 0 if chSearch < ch2
309 int LyXFindReplace::CompareChars(char chSearch, char chText) const
311 if (SF.CaseSensitive())
312 return (chSearch - chText);
313 return (toupper(chSearch) - toupper(chText));
317 // returns true if the search string is at the specified position
318 // (Copied from the original "LyXText::IsStringInText" in text2.C )
319 bool LyXFindReplace::IsSearchStringInText(LyXParagraph * par,
320 LyXParagraph::size_type pos) const
322 if (!par) return false;
326 bool fPrevIsSpace = false;
328 string::size_type iSrch = 0;
329 while (pos + iText < par->Last() &&
330 iSrch < SF.SearchString().length()) {
331 chSrch = SF.SearchString()[iSrch];
332 chText = par->GetChar(pos+iText);
335 ++iText; // next Text pos
336 continue; // same search pos
340 fPrevIsSpace = false;
341 if (CompareChars(chSrch, chText) != 0)
348 if (iSrch < SF.SearchString().length())
352 || ((pos <= 0 || !IsLetterCharOrDigit(par->GetChar(pos - 1)))
353 && (pos + iText >= par->Last()
354 || !IsLetterCharOrDigit(par->GetChar(pos + iText))))) {
355 iLenSelected = iText;