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"
36 extern BufferView *current_view; // called too many times in this file...
37 extern MiniBuffer *minibuffer;
39 // Maximum length copied from the current selection to the search string
40 const int LYXSEARCH_MAXLEN = 128;
42 // function prototypes
44 bool IsLetterCharOrDigit(char ch);
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 //-------------------------------------------------------------
61 bool IsLetterCharOrDigit(char ch)
63 return IsLetterChar(ch) || isdigit(ch);
67 // Returns the current selection. If nothing is selected or if the selection
68 // spans 2 paragraphs, an empty string is returned.
69 string const GetCurrentSelectionAsString(LyXText *lt)
75 char sz[LYXSEARCH_MAXLEN];
81 if (lt->selection && (lt->sel_cursor.par == par)) {
82 // (selected) and (begin/end in same paragraph)
83 pos = lt->sel_start_cursor.pos;
84 endpos = lt->sel_end_cursor.pos;
87 while ((i < LYXSEARCH_MAXLEN-2) &&
88 (pos < par->Last()) && (pos < endpos)) {
89 ch = par->GetChar(pos);
91 //HB??: Maybe (ch <= ' ')
92 if ((ch == ' ') || ((unsigned char)ch <= LYX_META_INSET)) {
93 // consecutive spaces --> 1 space char
95 pos++; // Next text pos
96 continue; // same search pos
102 fPrevIsSpace = false;
113 // If nothing selected, select the word at the cursor.
114 // Returns the current selection
115 string const GetSelectionOrWordAtCursor(LyXText *lt)
117 lt->SelectWordWhenUnderCursor();
118 return GetCurrentSelectionAsString(lt);
122 // This is a copy of SetSelectionOverString from text.C
123 // It does the same, but uses only the length as a parameter
124 void SetSelectionOverLenChars(LyXText *lt, int len)
126 lt->sel_cursor = lt->cursor;
128 for (i=0; i < len; i++)
134 //------------------------------
136 void LyXFindReplace1::StartSearch()
138 LyXFindReplace0::StartSearch();
139 SetReplaceEnabled(!current_view->currentBuffer()->isReadonly());
140 searchForward = true;
141 if (lsSearch.empty())
142 SetSearchString(GetSelectionOrWordAtCursor(current_view->currentBuffer()->text));
146 // TODO?: the user can insert multiple spaces with this routine (1999-01-11, dnaber)
147 void LyXFindReplace1::SearchReplaceCB()
151 if (!current_view->getScreen())
153 if (current_view->currentBuffer()->isReadonly())
156 // CutSelection cannot cut a single space, so we have to stop
157 // in order to avoid endless loop :-(
159 if (SearchString().length() == 0 || (SearchString().length() == 1
160 && SearchString()[0] == ' ') ) {
161 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
162 "nor an empty character."));
166 string const replacestring = ReplaceString();
168 current_view->getScreen()->HideCursor();
169 current_view->currentBuffer()->update(-2);
171 ltCur = current_view->currentBuffer()->text;
172 if (ltCur->selection) {
173 // clear the selection (if there is any)
174 current_view->getScreen()->ToggleSelection(false);
175 current_view->currentBuffer()->text->
176 ReplaceSelectionWithString(replacestring.c_str());
177 current_view->currentBuffer()->text->
178 SetSelectionOverString(replacestring.c_str());
179 current_view->currentBuffer()->update(1);
182 // jump to next match:
183 SearchCB( searchForward );
187 // replaces all occurences of a string (1999-01-15, dnaber@mini.gt.owl.de)
188 void LyXFindReplace1::SearchReplaceAllCB()
192 if (!current_view->getScreen())
194 if (current_view->currentBuffer()->isReadonly())
197 // CutSelection cannot cut a single space, so we have to stop
198 // in order to avoid endless loop :-(
200 if (SearchString().length() == 0 || (SearchString().length() == 1
201 && SearchString()[0] == ' ') ) {
202 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
203 "nor an empty character."));
207 string const replacestring = ReplaceString();
209 current_view->getScreen()->HideCursor();
212 current_view->currentBuffer()->text->ClearSelection();
213 current_view->currentBuffer()->text->CursorTop();
215 int replace_count = 0;
217 ltCur = current_view->currentBuffer()->text;
218 if (ltCur->selection) {
219 current_view->currentBuffer()->update(-2);
220 current_view->getScreen()->ToggleSelection(false);
221 current_view->currentBuffer()->text->
222 ReplaceSelectionWithString(replacestring.c_str());
223 current_view->currentBuffer()->text->
224 SetSelectionOverString(replacestring.c_str());
225 current_view->currentBuffer()->update(1);
228 } while( SearchCB(true) );
230 if( replace_count == 0 ) {
232 minibuffer->Set(_("String not found!"));
234 if( replace_count == 1 ) {
235 minibuffer->Set(_("1 string has been replaced."));
238 str += replace_count;
239 str += _(" strings have been replaced.");
240 minibuffer->Set(str);
246 bool LyXFindReplace1::SearchCB(bool fForward)
251 // store search direction
252 searchForward = fForward;
254 if (!current_view->getScreen())
257 current_view->getScreen()->HideCursor();
258 current_view->currentBuffer()->update(-2);
259 ltCur = current_view->currentBuffer()->text;
260 if (ltCur->selection)
261 ltCur->cursor = fForward ? ltCur->sel_end_cursor :
262 ltCur->sel_start_cursor;
265 iLenSelected = SearchString().length();
267 if (!ValidSearchData() ||
268 (fForward ? SearchForward(ltCur) : SearchBackward(ltCur))) {
269 current_view->currentBuffer()->update(-2);
271 // clear the selection (if there is any)
272 current_view->getScreen()->ToggleSelection();
273 current_view->currentBuffer()->text->ClearSelection();
275 // set the new selection
276 SetSelectionOverLenChars(current_view->currentBuffer()->text, iLenSelected);
277 current_view->getScreen()->ToggleSelection(false);
278 minibuffer->Set(_("Found."));
282 minibuffer->Set(_("String not found!"));
286 if (current_view->getWorkArea()->focus)
287 current_view->getScreen()->ShowCursor();
293 // if the string can be found: return true and set the cursor to
295 // (was: LyXText::SearchForward(char const* string) in text2.C )
296 bool LyXFindReplace1::SearchForward(LyXText *lt)
301 par = lt->cursor.par;
302 pos = lt->cursor.pos;
304 while (par && !IsSearchStringInText(par,pos)) {
305 if (pos<par->Last()-1)
313 lt->SetCursor(par,pos);
320 // if the string can be found: return true and set the cursor to
322 // (was: LyXText::SearchBackward(char const* string) in text2.C )
323 bool LyXFindReplace1::SearchBackward(LyXText *lt)
325 LyXParagraph *par = lt->cursor.par;
326 int pos = lt->cursor.pos;
332 // We skip empty paragraphs (Asger)
334 par = par->Previous();
337 } while (par && pos<0);
339 } while (par && !IsSearchStringInText(par,pos));
342 lt->SetCursor(par,pos);
349 /* Compares 2 char values.
351 > 0 if chSearch > ch2
352 = 0 if chSearch == ch2
353 < 0 if chSearch < ch2
355 int LyXFindReplace1::CompareChars(char chSearch, char chText)
358 return (chSearch - chText);
359 return (toupper((unsigned char) chSearch) - toupper((unsigned char) chText));
363 // returns true if the search string is at the specified position
364 // (Copied from the original "LyXText::IsStringInText" in text2.C )
365 bool LyXFindReplace1::IsSearchStringInText(LyXParagraph *par, int pos)
371 string::size_type iSrch;
376 fPrevIsSpace = false;
377 iText = 0; iSrch = 0;
378 while (pos+iText < par->Last() &&
379 iSrch < SearchString().length()) {
380 chSrch = SearchString()[iSrch];
381 chText = par->GetChar(pos+iText);
382 // Why was this code there ??? Insets are *not* spaces!
383 // It seems that there is some code here to handle multiple spaces. I
384 // wonder why this is useful... (JMarc)
385 // if ((chText == ' ') ||
386 // ((unsigned char)chText <= LYX_META_INSET))
389 iText++; // next Text pos
390 continue; // same search pos
395 fPrevIsSpace = false;
396 if (CompareChars(chSrch, chText) != 0)
403 if (iSrch < SearchString().length())
407 || ((pos <= 0 || !IsLetterCharOrDigit(par->GetChar(pos-1)))
408 && (pos+iText >= par->Last()
409 || !IsLetterCharOrDigit(par->GetChar(pos + iText))))) {
410 iLenSelected = iText;