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(BufferView * bv)
72 bv->text->SelectWordWhenUnderCursor(bv);
73 return GetCurrentSelectionAsString(bv->text);
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(BufferView * bv, int len)
82 bv->text->sel_cursor = bv->text->cursor;
83 for (int i = 0; i < len; ++i)
84 bv->text->CursorRight(bv);
85 bv->text->SetSelection(bv);
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));
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();
132 bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
134 LyXText * ltCur = bv->text;
135 if (ltCur->selection) {
136 // clear the selection (if there is any)
137 bv->toggleSelection(false);
139 ReplaceSelectionWithString(bv, replacestring);
141 SetSelectionOverString(bv, replacestring);
142 bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
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(bv);
172 bv->text->CursorTop(bv);
174 int replace_count = 0;
178 if (ltCur->selection) {
179 bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
180 bv->toggleSelection(false);
182 ReplaceSelectionWithString(bv, replacestring);
184 SetSelectionOverString(bv, replacestring);
185 bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
188 } while (SearchCB(true));
189 if (replace_count == 0) {
190 bv->owner()->getMiniBuffer()->Set(
191 _("String not found!"));
193 if (replace_count == 1) {
194 bv->owner()->getMiniBuffer()->Set(
195 _("1 string has been replaced."));
197 string str = tostr(replace_count);
198 str += _(" strings have been replaced.");
199 bv->owner()->getMiniBuffer()->Set(str);
205 bool LyXFindReplace::SearchCB(bool fForward)
207 // store search direction
208 searchForward = fForward;
210 if (!bv->available())
214 bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
215 LyXText * ltCur = bv->text;
216 if (ltCur->selection)
217 ltCur->cursor = fForward ? ltCur->sel_end_cursor :
218 ltCur->sel_start_cursor;
220 iLenSelected = SF.SearchString().length();
223 if (!SF.ValidSearchData() ||
224 (fForward ? SearchForward(bv):SearchBackward(bv))) {
225 bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
227 // clear the selection (if there is any)
228 bv->toggleSelection();
229 bv->text->ClearSelection(bv);
231 // set the new selection
232 SetSelectionOverLenChars(bv, iLenSelected);
233 bv->toggleSelection(false);
234 bv->owner()->getMiniBuffer()->Set(_("Found."));
237 bv->owner()->getMiniBuffer()->Set(_("String not found!"));
248 // if the string can be found: return true and set the cursor to
250 // (was: LyXText::SearchForward(char const* string) in text2.C )
251 bool LyXFindReplace::SearchForward(BufferView * bv)
253 LyXParagraph * par = bv->text->cursor.par();
254 LyXParagraph::size_type pos = bv->text->cursor.pos();
256 while (par && !IsSearchStringInText(par, pos)) {
257 if (pos < par->Last() - 1)
265 bv->text->SetCursor(bv, par, pos);
272 // if the string can be found: return true and set the cursor to
274 // (was: LyXText::SearchBackward(char const* string) in text2.C )
275 bool LyXFindReplace::SearchBackward(BufferView * bv)
277 LyXParagraph * par = bv->text->cursor.par();
278 int pos = bv->text->cursor.pos();
284 // We skip empty paragraphs (Asger)
286 par = par->Previous();
288 pos = par->Last() - 1;
289 } while (par && pos < 0);
291 } while (par && !IsSearchStringInText(par, pos));
294 bv->text->SetCursor(bv, par, pos);
301 /* Compares 2 char values.
303 > 0 if chSearch > ch2
304 = 0 if chSearch == ch2
305 < 0 if chSearch < ch2
307 int LyXFindReplace::CompareChars(char chSearch, char chText) const
309 if (SF.CaseSensitive())
310 return (chSearch - chText);
311 return (toupper(chSearch) - toupper(chText));
315 // returns true if the search string is at the specified position
316 // (Copied from the original "LyXText::IsStringInText" in text2.C )
317 bool LyXFindReplace::IsSearchStringInText(LyXParagraph * par,
318 LyXParagraph::size_type pos) const
320 if (!par) return false;
324 bool fPrevIsSpace = false;
326 string::size_type iSrch = 0;
327 while (pos + iText < par->Last() &&
328 iSrch < SF.SearchString().length()) {
329 chSrch = SF.SearchString()[iSrch];
330 chText = par->GetChar(pos+iText);
333 ++iText; // next Text pos
334 continue; // same search pos
338 fPrevIsSpace = false;
339 if (CompareChars(chSrch, chText) != 0)
346 if (iSrch < SF.SearchString().length())
350 || ((pos <= 0 || !IsLetterCharOrDigit(par->GetChar(pos - 1)))
351 && (pos + iText >= par->Last()
352 || !IsLetterCharOrDigit(par->GetChar(pos + iText))))) {
353 iLenSelected = iText;