]> git.lyx.org Git - lyx.git/blob - src/lyxfind.C
remove some very old dead code
[lyx.git] / src / lyxfind.C
1 #include <config.h>
2
3 #include "lyxtext.h"
4 #include "lyxfind.h"
5 #include "paragraph.h"
6 #include "frontends/LyXView.h"
7 #include "frontends/Alert.h"
8 #include "support/textutils.h"
9 #include "support/lstrings.h"
10 #include "BufferView.h"
11 #include "buffer.h"
12 #include "debug.h"
13 #include "gettext.h"
14 #include "insets/insettext.h"
15 #include "changes.h"
16
17 using lyx::pos_type;
18 using std::endl;
19
20 namespace lyxfind {
21
22 /// returns true if the specified string is at the specified  position
23 bool IsStringInText(Paragraph * par, pos_type pos,
24                     string const & str, bool const & = true,
25                     bool const & = false);
26
27 /// if the string is found: return true and set the cursor to the new position
28 SearchResult SearchForward(BufferView *, LyXText * text, string const & str,
29                            bool const & = true, bool const & = false);
30 ///
31 SearchResult SearchBackward(BufferView *, LyXText * text, string const & str,
32                             bool const & = true, bool const & = false);
33
34 int LyXReplace(BufferView * bv,
35                string const & searchstr, string const & replacestr,
36                bool forward, bool casesens, bool matchwrd, bool replaceall,
37                bool once)
38 {
39         if (!bv->available() || bv->buffer()->isReadonly())
40                 return 0;
41
42         // CutSelection cannot cut a single space, so we have to stop
43         // in order to avoid endless loop :-(
44         if (searchstr.length() == 0
45                 || (searchstr.length() == 1 && searchstr[0] == ' '))
46         {
47                 Alert::alert(_("Sorry!"), _("You cannot replace a single space, "
48                                           "nor an empty character."));
49                 return 0;
50         }
51
52         // now we can start searching for the first
53         // start at top if replaceall
54         LyXText * text = bv->getLyXText();
55         bool fw = forward;
56         if (replaceall) {
57                 text->clearSelection();
58                 bv->unlockInset(bv->theLockingInset());
59                 text = bv->text;
60                 text->cursorTop(bv);
61                 // override search direction because we search top to bottom
62                 fw = true;
63         }
64
65         // if nothing selected or selection does not equal search string
66         // search and select next occurance and return if no replaceall
67         string str1;
68         string str2;
69         if (casesens) {
70                 str1 = searchstr;
71                 str2 = text->selectionAsString(bv->buffer(), false);
72         } else {
73                 str1 = lowercase(searchstr);
74                 str2 = lowercase(text->selectionAsString(bv->buffer(), false));
75         }
76         if (str1 != str2) {
77                 if (!LyXFind(bv, searchstr, fw, casesens, matchwrd) ||
78                         !replaceall)
79                 {
80                         return 0;
81                 }
82         }
83
84         bool found = false;
85         int replace_count = 0;
86         do {
87                 text = bv->getLyXText();
88                 // We have to do this check only because mathed insets don't
89                 // return their own LyXText but the LyXText of it's parent!
90                 if (!bv->theLockingInset() ||
91                         ((text != bv->text) &&
92                          (text->inset_owner == text->inset_owner->getLockingInset())))
93                 {
94                         bv->hideCursor();
95                         bv->update(text, BufferView::SELECT|BufferView::FITCUR);
96                         bv->toggleSelection(false);
97                         text->replaceSelectionWithString(bv, replacestr);
98                         text->setSelectionRange(bv, replacestr.length());
99                         bv->update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
100                         ++replace_count;
101                 }
102                 if (!once)
103                         found = LyXFind(bv, searchstr, fw, casesens, matchwrd);
104         } while (!once && replaceall && found);
105
106         return replace_count;
107 }
108
109
110 bool LyXFind(BufferView * bv,
111              string const & searchstr, bool forward,
112              bool casesens, bool matchwrd)
113 {
114         if (!bv->available() || searchstr.empty())
115                 return false;
116
117         bv->hideCursor();
118         bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
119
120         if (bv->theLockingInset()) {
121                 bool found = forward ?
122                         bv->theLockingInset()->searchForward(bv, searchstr, casesens, matchwrd) :
123                         bv->theLockingInset()->searchBackward(bv, searchstr, casesens, matchwrd);
124                 // We found the stuff inside the inset so we don't have to
125                 // do anything as the inset did all the update for us!
126                 if (found)
127                         return true;
128                 // We now are in the main text but if we did a forward
129                 // search we have to put the cursor behind the inset.
130                 if (forward) {
131                         bv->text->cursorRight(bv, true);
132                 }
133         }
134         // If we arrive here we are in the main text again so we
135         // just start searching from the root LyXText at the position
136         // we are!
137         LyXText * text = bv->text;
138
139         if (text->selection.set())
140                 text->cursor = forward ?
141                         text->selection.end : text->selection.start;
142
143         bv->toggleSelection();
144         text->clearSelection();
145
146         SearchResult result = forward ?
147                 SearchForward(bv, text, searchstr, casesens, matchwrd) :
148                 SearchBackward(bv, text, searchstr, casesens, matchwrd);
149
150         bool found = true;
151         // If we found the cursor inside an inset we will get back
152         // SR_FOUND_NOUPDATE and we don't have to do anything as the
153         // inset did it already.
154         if (result == SR_FOUND) {
155                 bv->unlockInset(bv->theLockingInset());
156                 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
157                 text->setSelectionRange(bv, searchstr.length());
158                 bv->toggleSelection(false);
159                 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
160         } else if (result == SR_NOT_FOUND) {
161                 bv->unlockInset(bv->theLockingInset());
162                 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
163                 found = false;
164         }
165
166         return found;
167 }
168
169
170 SearchResult LyXFind(BufferView * bv, LyXText * text,
171                      string const & searchstr, bool forward,
172                      bool casesens, bool matchwrd)
173 {
174         if (text->selection.set())
175                 text->cursor = forward ?
176                         text->selection.end : text->selection.start;
177
178         bv->toggleSelection();
179         text->clearSelection();
180
181         SearchResult result = forward ?
182                 SearchForward(bv, text, searchstr, casesens, matchwrd) :
183                 SearchBackward(bv, text, searchstr, casesens, matchwrd);
184
185         return result;
186 }
187
188
189 // returns true if the specified string is at the specified position
190 bool IsStringInText(Paragraph * par, pos_type pos,
191                     string const & str, bool const & cs,
192                     bool const & mw)
193 {
194         if (!par)
195                 return false;
196
197         string::size_type size = str.length();
198         pos_type i = 0;
199         while (((pos + i) < par->size())
200                && (string::size_type(i) < size)
201                && (cs ? (str[i] == par->getChar(pos + i))
202                    : (uppercase(str[i]) == uppercase(par->getChar(pos + i)))))
203         {
204                 ++i;
205         }
206         if (size == string::size_type(i)) {
207                 // if necessary, check whether string matches word
208                 if (!mw)
209                         return true;
210                 if ((pos <= 0 || !IsLetterCharOrDigit(par->getChar(pos - 1)))
211                         && (pos + pos_type(size) >= par->size()
212                         || !IsLetterCharOrDigit(par->getChar(pos + size)))) {
213                         return true;
214                 }
215         }
216         return false;
217 }
218
219 // forward search:
220 // if the string can be found: return true and set the cursor to
221 // the new position, cs = casesensitive, mw = matchword
222 SearchResult SearchForward(BufferView * bv, LyXText * text, string const & str,
223                            bool const & cs, bool const & mw)
224 {
225         Paragraph * par = text->cursor.par();
226         pos_type pos = text->cursor.pos();
227         Paragraph * prev_par = par;
228         UpdatableInset * inset;
229
230         while (par && !IsStringInText(par, pos, str, cs, mw)) {
231                 if (par->isInset(pos) &&
232                         (inset = (UpdatableInset *)par->getInset(pos)) &&
233                         (inset->isTextInset()))
234                 {
235 #if 0
236                         // lock the inset!
237                         text->setCursor(bv, par, pos);
238                         inset->edit(bv);
239 #endif
240                         if (inset->searchForward(bv, str, cs, mw))
241                                 return SR_FOUND_NOUPDATE;
242                 }
243
244                 ++pos;
245
246                 if (pos >= par->size()) {
247                         prev_par = par;
248                         par = par->next();
249                         pos = 0;
250                 }
251         }
252
253         if (par) {
254                 text->setCursor(bv, par, pos);
255                 return SR_FOUND;
256         } else {
257                 // make sure we end up at the end of the text,
258                 // not the start point of the last search
259                 text->setCursor(bv, prev_par, prev_par->size());
260                 return SR_NOT_FOUND;
261         }
262 }
263
264
265 // backward search:
266 // if the string can be found: return true and set the cursor to
267 // the new position, cs = casesensitive, mw = matchword
268 SearchResult SearchBackward(BufferView * bv, LyXText * text,
269                             string const & str,
270                             bool const & cs, bool const & mw)
271 {
272         Paragraph * par = text->cursor.par();
273         pos_type pos = text->cursor.pos();
274         Paragraph * prev_par = par;
275
276         do {
277                 if (pos > 0)
278                         --pos;
279                 else {
280                         prev_par = par;
281                         // We skip empty paragraphs (Asger)
282                         do {
283                                 par = par->previous();
284                                 if (par)
285                                         pos = par->size() - 1;
286                         } while (par && pos < 0);
287                 }
288                 UpdatableInset * inset;
289                 if (par && par->isInset(pos) &&
290                         (inset = (UpdatableInset *)par->getInset(pos)) &&
291                         (inset->isTextInset()))
292                 {
293 #if 0
294                         // lock the inset!
295                         text->setCursor(bv, par, pos);
296                         inset->edit(bv, false);
297 #endif
298                         if (inset->searchBackward(bv, str, cs, mw))
299                                 return SR_FOUND_NOUPDATE;
300                 }
301         } while (par && !IsStringInText(par, pos, str, cs, mw));
302
303         if (par) {
304                 text->setCursor(bv, par, pos);
305                 return SR_FOUND;
306         } else {
307                 // go to the last part of the unsuccessful search
308                 text->setCursor(bv, prev_par, 0);
309                 return SR_NOT_FOUND;
310         }
311 }
312
313  
314 SearchResult nextChange(BufferView * bv, LyXText * text, pos_type & length)
315 {
316         Paragraph * par = text->cursor.par();
317         pos_type pos = text->cursor.pos();
318         Paragraph * prev_par = par;
319         UpdatableInset * inset;
320
321         while (par) {
322                 if ((!par->size() || pos != par->size())
323                         && par->lookupChange(pos) != Change::UNCHANGED)
324                         break;
325
326                 if (par->isInset(pos) &&
327                         (inset = (UpdatableInset *)par->getInset(pos)) &&
328                         (inset->isTextInset())) {
329                         if (inset->nextChange(bv, length))
330                                 return SR_FOUND_NOUPDATE;
331                 }
332
333                 ++pos;
334
335                 if (pos >= par->size()) {
336                         prev_par = par;
337                         par = par->next();
338                         pos = 0;
339                 }
340         }
341
342         if (par) {
343                 text->setCursor(bv, par, pos);
344                 Change orig_change = par->lookupChangeFull(pos);
345                 pos_type end = pos;
346
347                 for (; end != par->size(); ++end) {
348                         Change change = par->lookupChangeFull(end);
349                         if (change != orig_change) {
350                                 // slight UI optimisation: for replacements, we get
351                                 // text like : _old_new. Consider that as one change.
352                                 if (!(orig_change.type == Change::DELETED &&
353                                         change.type == Change::INSERTED))
354                                         break;
355                         }
356                 }
357                 length = end - pos;
358                 return SR_FOUND;
359         } else {
360                 // make sure we end up at the end of the text,
361                 // not the start point of the last search
362                 text->setCursor(bv, prev_par, prev_par->size());
363                 return SR_NOT_FOUND;
364         }
365 }
366  
367  
368 SearchResult findNextChange(BufferView * bv, LyXText * text, pos_type & length)
369 {
370         if (text->selection.set())
371                 text->cursor = text->selection.end;
372
373         bv->toggleSelection();
374         text->clearSelection();
375
376         return nextChange(bv, text, length);
377 }
378
379
380 bool findNextChange(BufferView * bv)
381 {
382         if (!bv->available())
383                 return false;
384
385         bv->hideCursor();
386         bv->update(bv->getLyXText(), BufferView::SELECT | BufferView::FITCUR);
387
388         pos_type length;
389  
390         if (bv->theLockingInset()) {
391                 bool found = bv->theLockingInset()->nextChange(bv, length);
392  
393                 // We found the stuff inside the inset so we don't have to
394                 // do anything as the inset did all the update for us!
395                 if (found)
396                         return true;
397  
398                 // We now are in the main text but if we did a forward
399                 // search we have to put the cursor behind the inset.
400                 bv->text->cursorRight(bv, true);
401         }
402         // If we arrive here we are in the main text again so we
403         // just start searching from the root LyXText at the position
404         // we are!
405         LyXText * text = bv->text;
406
407         if (text->selection.set())
408                 text->cursor = text->selection.end;
409
410         bv->toggleSelection();
411         text->clearSelection();
412         
413         SearchResult result = nextChange(bv, text, length);
414
415         lyxerr << "Result is " << result << endl;
416  
417         bool found = true;
418  
419         // If we found the cursor inside an inset we will get back
420         // SR_FOUND_NOUPDATE and we don't have to do anything as the
421         // inset did it already.
422         if (result == SR_FOUND) {
423                 bv->unlockInset(bv->theLockingInset());
424                 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
425                 text->setSelectionRange(bv, length);
426                 bv->toggleSelection(false);
427                 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
428         } else if (result == SR_NOT_FOUND) {
429                 bv->unlockInset(bv->theLockingInset());
430                 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
431                 found = false;
432         }
433
434         return found;
435 }
436  
437 } // end lyxfind namespace