]> git.lyx.org Git - lyx.git/blob - src/lyxfr1.C
white-space changes, removed definitions.h several enum changes because of this,...
[lyx.git] / src / lyxfr1.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *           Copyright 1995 Matthias Ettrich,
7  *           Copyright 1995-1999 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #include <cctype>
14 #include <cstring>
15 #include <cstdlib>
16
17 #ifdef __GNUG__
18 #pragma implementation
19 #endif
20
21 #include "LString.h"
22 #include "lyx_main.h"
23 #include FORMS_H_LOCATION
24 #include "form1.h"
25 #include "lyxfr0.h"
26 #include "lyxfr1.h"
27 #include "lyxfunc.h"
28 #include "lyxscreen.h"
29 #include "debug.h"
30 #include "lyxtext.h"
31 #include "gettext.h"
32 #include "LyXView.h"
33 #include "lyx_gui_misc.h"
34 #include "minibuffer.h"
35 #include "support/lstrings.h"
36 #include "support/textutils.h"
37
38 extern BufferView *current_view; // called too many times in this file...
39 extern MiniBuffer *minibuffer;
40
41 // Maximum length copied from the current selection to the search string
42 const int LYXSEARCH_MAXLEN =  128;
43
44 // function prototypes
45
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);
50
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);
54
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);
58
59 //-------------------------------------------------------------
60
61
62
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) 
66 {
67         char            sz[LYXSEARCH_MAXLEN];
68
69         sz[0] = 0;
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;
77                 int i = 0;
78                 bool fPrevIsSpace = false;
79                 char ch;
80                 while ((i < LYXSEARCH_MAXLEN-2) && 
81                         (pos < par->Last()) && (pos < endpos)) {
82                         ch = par->GetChar(pos);
83
84                         //HB??: Maybe (ch <= ' ') 
85                         if ((ch == ' ') || (ch <= LyXParagraph::META_INSET)) {
86                                 // consecutive spaces --> 1 space char
87                                 if (fPrevIsSpace) {
88                                         pos++;          // Next text pos
89                                         continue;       // same search pos
90                                 }
91                                 sz[i] = ' ';
92                                 fPrevIsSpace = true;
93                         } else {
94                                 sz[i] = ch;
95                                 fPrevIsSpace = false;
96                         }
97                         pos++;
98                         i++;
99                 } 
100                 sz[i] = 0;
101         }
102         return string(sz);
103 }
104
105
106 // If nothing selected, select the word at the cursor.
107 // Returns the current selection
108 string const GetSelectionOrWordAtCursor(LyXText *lt) 
109 {
110         lt->SelectWordWhenUnderCursor();
111         return GetCurrentSelectionAsString(lt);
112 }
113
114
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)
118 {
119         lt->sel_cursor = lt->cursor;
120         int i;
121         for (i= 0; i < len; i++)
122                 lt->CursorRight();
123         lt->SetSelection();
124 }
125
126
127 //------------------------------
128
129 void LyXFindReplace1::StartSearch()
130 {
131         LyXFindReplace0::StartSearch();
132         SetReplaceEnabled(!current_view->buffer()->isReadonly());
133         searchForward = true;
134         if (lsSearch.empty()) 
135                 SetSearchString(GetSelectionOrWordAtCursor(current_view->buffer()->text));
136 }       
137
138
139 // TODO?: the user can insert multiple spaces with this routine (1999-01-11, dnaber)
140 void LyXFindReplace1::SearchReplaceCB()
141 {
142         LyXText         *ltCur;
143
144         if (!current_view->getScreen())
145                 return;
146         if (current_view->buffer()->isReadonly())
147                 return;
148         
149         // CutSelection cannot cut a single space, so we have to stop
150         // in order to avoid endless loop :-(
151         ReInitFromForm();
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."));
156                 return;
157         }
158         
159         string const replacestring = ReplaceString();
160
161         current_view->getScreen()->HideCursor();
162         current_view->buffer()->update(-2);
163
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);
173         }
174         
175         // jump to next match:
176         SearchCB( searchForward );
177 }
178
179
180 // replaces all occurences of a string (1999-01-15, dnaber@mini.gt.owl.de)
181 void LyXFindReplace1::SearchReplaceAllCB()
182 {
183         LyXText         *ltCur;
184
185         if (!current_view->getScreen())
186                 return;
187         if (current_view->buffer()->isReadonly())
188                 return;
189
190         // CutSelection cannot cut a single space, so we have to stop
191         // in order to avoid endless loop :-(
192         ReInitFromForm();
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."));
197                return;
198        }
199
200         string const replacestring = ReplaceString();
201
202         current_view->getScreen()->HideCursor();
203
204         // start at top
205         current_view->buffer()->text->ClearSelection();
206         current_view->buffer()->text->CursorTop();
207
208         int replace_count = 0;
209         do {
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); 
219                         replace_count++;
220                 }
221         } while( SearchCB(true) );
222
223         if( replace_count == 0 ) {
224                 LyXBell();      
225                 minibuffer->Set(_("String not found!"));
226         } else {
227                 if( replace_count == 1 ) {
228                         minibuffer->Set(_("1 string has been replaced."));
229                 } else {
230                         string str = tostr(replace_count);
231                         str += _(" strings have been replaced.");
232                         minibuffer->Set(str);
233                 }
234         }
235 }
236
237
238 bool LyXFindReplace1::SearchCB(bool fForward)
239 {
240         LyXText         *ltCur;
241         bool result;
242
243         // store search direction
244         searchForward = fForward;
245         
246         if (!current_view->getScreen())
247                 return(false);
248    
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;
255
256         ReInitFromForm();
257         iLenSelected = SearchString().length();
258    
259         if (!ValidSearchData() ||
260             (fForward ? SearchForward(ltCur) : SearchBackward(ltCur))) {
261                 current_view->buffer()->update(-2);
262
263                 // clear the selection (if there is any) 
264                 current_view->getScreen()->ToggleSelection();
265                 current_view->buffer()->text->ClearSelection();
266
267                 // set the new selection 
268                 SetSelectionOverLenChars(current_view->buffer()->text, iLenSelected);
269                 current_view->getScreen()->ToggleSelection(false);
270                 minibuffer->Set(_("Found."));
271                 result = true;
272         } else {
273                 LyXBell();
274                 minibuffer->Set(_("String not found!"));
275                 result = false;
276         }
277    
278         if (current_view->getWorkArea()->focus)
279                 current_view->getScreen()->ShowCursor();
280
281         return(result);
282 }
283
284
285 // if the string can be found: return true and set the cursor to
286 // the new position 
287 // (was: LyXText::SearchForward(char const* string) in text2.C )
288 bool LyXFindReplace1::SearchForward(LyXText * lt)
289 {
290         LyXParagraph * par = lt->cursor.par;
291         LyXParagraph::size_type pos = lt->cursor.pos;
292
293         while (par && !IsSearchStringInText(par, pos)) {
294                 if (pos<par->Last()-1)
295                         pos++;
296                 else {
297                         pos = 0;
298                         par = par->Next();
299                 }
300         }
301         if (par) {
302                 lt->SetCursor(par, pos);
303                 return true;
304         } else
305                 return false;
306 }
307
308
309 // if the string can be found: return true and set the cursor to
310 // the new position 
311 // (was: LyXText::SearchBackward(char const* string) in text2.C )
312 bool LyXFindReplace1::SearchBackward(LyXText *lt)
313 {
314         LyXParagraph *par = lt->cursor.par;
315         int pos = lt->cursor.pos;
316
317         do {
318                 if (pos>0)
319                         pos--;
320                 else {
321                         // We skip empty paragraphs (Asger)
322                         do {
323                                 par = par->Previous();
324                                 if (par)
325                                         pos = par->Last()-1;
326                         } while (par && pos<0);
327                 }
328         } while (par && !IsSearchStringInText(par, pos));
329   
330         if (par) {
331                 lt->SetCursor(par, pos);
332                 return true;
333         } else
334                 return false;
335 }
336
337
338 /* Compares 2 char values. 
339 return value is
340     > 0 if chSearch > ch2
341     = 0 if chSearch == ch2
342     < 0 if chSearch < ch2
343 */
344 int LyXFindReplace1::CompareChars(char chSearch, char chText)
345 {
346         if (CaseSensitive())
347                 return (chSearch - chText);
348         return (toupper(chSearch) - toupper(chText));
349 }
350
351
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)
356 {
357         char            chSrch = 0;
358         char            chText;
359
360         if (!par) 
361                 return false;
362
363         bool fPrevIsSpace = false;
364         int iText = 0;
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);
370                 if (chText == ' ') {
371                         if (fPrevIsSpace) {
372                                 iText++;  // next Text pos
373                                 continue; // same search pos
374                         }
375                         fPrevIsSpace = true;
376                 } else
377                         fPrevIsSpace = false;
378                 if (CompareChars(chSrch, chText) != 0)
379                         break;
380                 
381                 ++iSrch;
382                 ++iText;
383         }
384
385         if (iSrch < SearchString().length())
386                 return false;
387
388         if (!MatchWord() 
389             || ((pos <= 0 || !IsLetterCharOrDigit(par->GetChar(pos-1)))
390                 && (pos + iText >= par->Last() 
391                     || !IsLetterCharOrDigit(par->GetChar(pos + iText))))) {
392                 iLenSelected = iText;
393                 return true;
394         }
395
396         return false;
397 }