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;
121 for (i= 0; i < len; i++)
127 //------------------------------
129 void LyXFindReplace1::StartSearch()
131 LyXFindReplace0::StartSearch();
132 SetReplaceEnabled(!current_view->buffer()->isReadonly());
133 searchForward = true;
134 if (lsSearch.empty())
135 SetSearchString(GetSelectionOrWordAtCursor(current_view->buffer()->text));
139 // TODO?: the user can insert multiple spaces with this routine (1999-01-11, dnaber)
140 void LyXFindReplace1::SearchReplaceCB()
144 if (!current_view->getScreen())
146 if (current_view->buffer()->isReadonly())
149 // CutSelection cannot cut a single space, so we have to stop
150 // in order to avoid endless loop :-(
152 if (SearchString().length() == 0 || (SearchString().length() == 1
153 && SearchString()[0] == ' ') ) {
154 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
155 "nor an empty character."));
159 string const replacestring = ReplaceString();
161 current_view->getScreen()->HideCursor();
162 current_view->buffer()->update(-2);
164 ltCur = current_view->buffer()->text;
165 if (ltCur->selection) {
166 // clear the selection (if there is any)
167 current_view->getScreen()->ToggleSelection(false);
168 current_view->buffer()->text->
169 ReplaceSelectionWithString(replacestring.c_str());
170 current_view->buffer()->text->
171 SetSelectionOverString(replacestring.c_str());
172 current_view->buffer()->update(1);
175 // jump to next match:
176 SearchCB( searchForward );
180 // replaces all occurences of a string (1999-01-15, dnaber@mini.gt.owl.de)
181 void LyXFindReplace1::SearchReplaceAllCB()
185 if (!current_view->getScreen())
187 if (current_view->buffer()->isReadonly())
190 // CutSelection cannot cut a single space, so we have to stop
191 // in order to avoid endless loop :-(
193 if (SearchString().length() == 0 || (SearchString().length() == 1
194 && SearchString()[0] == ' ') ) {
195 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
196 "nor an empty character."));
200 string const replacestring = ReplaceString();
202 current_view->getScreen()->HideCursor();
205 current_view->buffer()->text->ClearSelection();
206 current_view->buffer()->text->CursorTop();
208 int replace_count = 0;
210 ltCur = current_view->buffer()->text;
211 if (ltCur->selection) {
212 current_view->buffer()->update(-2);
213 current_view->getScreen()->ToggleSelection(false);
214 current_view->buffer()->text->
215 ReplaceSelectionWithString(replacestring.c_str());
216 current_view->buffer()->text->
217 SetSelectionOverString(replacestring.c_str());
218 current_view->buffer()->update(1);
221 } while( SearchCB(true) );
223 if( replace_count == 0 ) {
225 minibuffer->Set(_("String not found!"));
227 if( replace_count == 1 ) {
228 minibuffer->Set(_("1 string has been replaced."));
230 string str = tostr(replace_count);
231 str += _(" strings have been replaced.");
232 minibuffer->Set(str);
238 bool LyXFindReplace1::SearchCB(bool fForward)
243 // store search direction
244 searchForward = fForward;
246 if (!current_view->getScreen())
249 current_view->getScreen()->HideCursor();
250 current_view->buffer()->update(-2);
251 ltCur = current_view->buffer()->text;
252 if (ltCur->selection)
253 ltCur->cursor = fForward ? ltCur->sel_end_cursor :
254 ltCur->sel_start_cursor;
257 iLenSelected = SearchString().length();
259 if (!ValidSearchData() ||
260 (fForward ? SearchForward(ltCur) : SearchBackward(ltCur))) {
261 current_view->buffer()->update(-2);
263 // clear the selection (if there is any)
264 current_view->getScreen()->ToggleSelection();
265 current_view->buffer()->text->ClearSelection();
267 // set the new selection
268 SetSelectionOverLenChars(current_view->buffer()->text, iLenSelected);
269 current_view->getScreen()->ToggleSelection(false);
270 minibuffer->Set(_("Found."));
274 minibuffer->Set(_("String not found!"));
278 if (current_view->getWorkArea()->focus)
279 current_view->getScreen()->ShowCursor();
285 // if the string can be found: return true and set the cursor to
287 // (was: LyXText::SearchForward(char const* string) in text2.C )
288 bool LyXFindReplace1::SearchForward(LyXText * lt)
290 LyXParagraph * par = lt->cursor.par;
291 LyXParagraph::size_type pos = lt->cursor.pos;
293 while (par && !IsSearchStringInText(par, pos)) {
294 if (pos<par->Last()-1)
302 lt->SetCursor(par, pos);
309 // if the string can be found: return true and set the cursor to
311 // (was: LyXText::SearchBackward(char const* string) in text2.C )
312 bool LyXFindReplace1::SearchBackward(LyXText *lt)
314 LyXParagraph *par = lt->cursor.par;
315 int pos = lt->cursor.pos;
321 // We skip empty paragraphs (Asger)
323 par = par->Previous();
326 } while (par && pos<0);
328 } while (par && !IsSearchStringInText(par, pos));
331 lt->SetCursor(par, pos);
338 /* Compares 2 char values.
340 > 0 if chSearch > ch2
341 = 0 if chSearch == ch2
342 < 0 if chSearch < ch2
344 int LyXFindReplace1::CompareChars(char chSearch, char chText)
347 return (chSearch - chText);
348 return (toupper(chSearch) - toupper(chText));
352 // returns true if the search string is at the specified position
353 // (Copied from the original "LyXText::IsStringInText" in text2.C )
354 bool LyXFindReplace1::IsSearchStringInText(LyXParagraph * par,
355 LyXParagraph::size_type pos)
363 bool fPrevIsSpace = false;
365 string::size_type iSrch = 0;
366 while (pos + iText < par->Last() &&
367 iSrch < SearchString().length()) {
368 chSrch = SearchString()[iSrch];
369 chText = par->GetChar(pos+iText);
372 iText++; // next Text pos
373 continue; // same search pos
377 fPrevIsSpace = false;
378 if (CompareChars(chSrch, chText) != 0)
385 if (iSrch < SearchString().length())
389 || ((pos <= 0 || !IsLetterCharOrDigit(par->GetChar(pos-1)))
390 && (pos + iText >= par->Last()
391 || !IsLetterCharOrDigit(par->GetChar(pos + iText))))) {
392 iLenSelected = iText;