]> git.lyx.org Git - lyx.git/blob - src/lyxfind.C
- Applied the thesaurus patch.
[lyx.git] / src / lyxfind.C
1 #include <config.h>
2
3 #ifdef __GNUG__
4 #pragma implementation
5 #endif
6
7 #include "lyxtext.h"
8 #include "lyxfind.h"
9 #include "LyXView.h"
10 #include "lyx_gui_misc.h"
11 #include "support/textutils.h"
12 #include "support/lstrings.h"
13 #include "BufferView.h"
14 #include "buffer.h"
15 #include "gettext.h"
16
17 ///
18 // locally used enum
19 ///
20 enum SearchResult {
21         //
22         SR_NOT_FOUND = 0,
23         //
24         SR_FOUND,
25         //
26         SR_FOUND_NOUPDATE
27 };
28
29
30 /// returns true if the specified string is at the specified  position
31 bool IsStringInText(Paragraph * par, Paragraph::size_type pos,
32                     string const & str, bool const & = true,
33                     bool const & = false);
34
35 /// if the string is found: return true and set the cursor to the new position
36 SearchResult SearchForward(BufferView *, LyXText * text, string const & str,
37                            bool const & = true, bool const & = false);
38 ///
39 SearchResult SearchBackward(BufferView *, LyXText * text, string const & str,
40                             bool const & = true, bool const & = false);
41
42
43 int LyXReplace(BufferView * bv,
44                string const & searchstr, string const & replacestr,
45                bool forward, bool casesens, bool matchwrd, bool replaceall,
46                bool once)
47 {
48         if (!bv->available() || bv->buffer()->isReadonly()) 
49                 return 0;
50    
51         // CutSelection cannot cut a single space, so we have to stop
52         // in order to avoid endless loop :-(
53         if (searchstr.length() == 0
54                 || (searchstr.length() == 1 && searchstr[0] == ' '))
55         {
56                 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
57                                           "nor an empty character."));
58                 return 0;
59         }
60         
61         LyXText * text = bv->getLyXText();
62
63         // now we can start searching for the first 
64         // start at top if replaceall
65         bool fw = forward;
66         if (replaceall) {
67                 text->clearSelection(bv);
68                 if (text->inset_owner) {
69                         bv->unlockInset(bv->theLockingInset());
70                         text = bv->text;
71                 }
72                 text->cursorTop(bv);
73                 // override search direction because we search top to bottom
74                 fw = true;
75         }
76         
77         // if nothing selected or selection does not equal search string
78         // search and select next occurance and return if no replaceall
79         if (searchstr!=text->selectionAsString(bv->buffer())) {
80                 if (!LyXFind(bv, searchstr, fw, false, casesens, matchwrd) ||
81                         !replaceall)
82                 {
83                         return 0;
84                 }
85         }
86    
87         bool found;
88         int replace_count = 0;
89         do {
90                 bv->hideCursor();
91                 bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
92                 bv->toggleSelection(false);
93                 bv->getLyXText()->replaceSelectionWithString(bv, replacestr);
94                 bv->getLyXText()->setSelectionOverString(bv, replacestr);
95                 bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
96                 ++replace_count;
97                 if (!once)
98                   found = LyXFind(bv, searchstr, fw, false, casesens, matchwrd);
99         } while (!once && replaceall && found);
100    
101         if (bv->focus())
102                 bv->showCursor();
103         
104         return replace_count;
105 }
106
107 bool LyXFind(BufferView * bv,
108              string const & searchstr, bool forward,
109              bool frominset, bool casesens, bool matchwrd)
110 {
111         if (!bv->available() || searchstr.empty())
112                 return false;
113         
114         LyXText * text = bv->getLyXText();
115
116         bv->hideCursor();
117         bv->update(text, BufferView::SELECT|BufferView::FITCUR);
118         
119         if (text->selection.set())
120                 text->cursor = forward ?
121                         text->selection.end : text->selection.start;
122
123         SearchResult result = SR_NOT_FOUND;
124
125         if (!frominset && bv->theLockingInset()) {
126                 bool found = forward ?
127                         bv->theLockingInset()->searchForward(bv, searchstr, casesens, matchwrd) :
128                         bv->theLockingInset()->searchBackward(bv, searchstr, casesens, matchwrd);
129                 if (found)
130                         result = SR_FOUND_NOUPDATE;
131         } else {
132                 result = forward ? 
133                         SearchForward(bv, text, searchstr, casesens, matchwrd) :
134                         SearchBackward(bv, text, searchstr, casesens, matchwrd);
135         }
136
137         bool found = true;
138         if (result == SR_FOUND) {
139                 // the actual text pointer could have changed!
140                 bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
141                 bv->toggleSelection();
142                 bv->getLyXText()->clearSelection(bv);
143                 bv->getLyXText()->setSelectionOverString(bv, searchstr);
144                 bv->toggleSelection(false);
145                 bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
146         } else if (result == SR_NOT_FOUND)
147                 found = false;
148    
149         if (bv->focus())
150                 bv->showCursor();
151    
152         return found;
153 }
154
155
156 // returns true if the specified string is at the specified position
157 bool IsStringInText(Paragraph * par, Paragraph::size_type pos,
158                     string const & str, bool const & cs,
159                     bool const & mw)
160 {
161         if (!par)
162                 return false;
163    
164         string::size_type size = str.length();
165         Paragraph::size_type i = 0;
166         while (((pos + i) < par->size())
167                && (string::size_type(i) < size)
168                && (cs ? (str[i] == par->getChar(pos + i))
169                    : (toupper(str[i]) == toupper(par->getChar(pos + i)))))
170         {
171                 ++i;
172         }
173         if (size == string::size_type(i)) {
174                 // if necessary, check whether string matches word
175                 if (!mw || 
176                     (mw && ((pos <= 0 || !IsLetterCharOrDigit(par->getChar(pos - 1)))
177                              && (pos + Paragraph::size_type(size) >= par->size()
178                                  || !IsLetterCharOrDigit(par->getChar(pos + size))))
179                      ))
180                 {
181                         return true;
182                 }
183         }
184         return false;
185 }
186
187 // forward search:
188 // if the string can be found: return true and set the cursor to
189 // the new position, cs = casesensitive, mw = matchword
190 SearchResult SearchForward(BufferView * bv, LyXText * text, string const & str,
191                            bool const & cs, bool const & mw)
192 {
193         Paragraph * par = text->cursor.par();
194         Paragraph::size_type pos = text->cursor.pos();
195         UpdatableInset * inset;
196
197         while (par && !IsStringInText(par, pos, str, cs, mw)) {
198                 if (par->isInset(pos) &&
199                         (inset = (UpdatableInset *)par->getInset(pos)) &&
200                         (inset->isTextInset()))
201                 {
202                         // lock the inset!
203                         text->setCursor(bv, par, pos);
204                         inset->edit(bv);
205                         if (inset->searchForward(bv, str, cs, mw))
206                                 return SR_FOUND_NOUPDATE;
207                         text = bv->getLyXText();
208                 }
209                 if (pos < par->size() - 1)
210                         ++pos;
211                 else {
212                         pos = 0;
213                         par = par->next();
214                 }
215         }
216         if (par) {
217                 text->setCursor(bv, par, pos);
218                 return SR_FOUND;
219         } else if (text->inset_owner) {
220                 // test if we're inside an inset if yes unlock the inset
221                 // and recall us with the outside LyXText!
222                 bv->unlockInset((UpdatableInset *)text->inset_owner);
223                 text = bv->getLyXText();
224                 par = text->cursor.par();
225                 pos = text->cursor.pos();
226                 if (pos < par->size() - 1)
227                         ++pos;
228                 else {
229                         pos = 0;
230                         par = par->next();
231                 }
232                 if (!par)
233                         return SR_NOT_FOUND;
234                 text->setCursor(bv, par, pos);
235                 return SearchForward(bv, text, str, cs, mw);
236         } else
237                 return SR_NOT_FOUND;
238 }
239
240
241 // backward search:
242 // if the string can be found: return true and set the cursor to
243 // the new position, cs = casesensitive, mw = matchword
244 SearchResult SearchBackward(BufferView * bv, LyXText * text,
245                             string const & str,
246                             bool const & cs, bool const & mw)
247 {
248         Paragraph * par = text->cursor.par();
249         Paragraph::size_type pos = text->cursor.pos();
250
251         do {
252                 if (pos > 0)
253                         --pos;
254                 else {
255                         // We skip empty paragraphs (Asger)
256                         do {
257                                 par = par->previous();
258                                 if (par)
259                                         pos = par->size() - 1;
260                         } while (par && pos < 0);
261                 }
262                 UpdatableInset * inset;
263                 if (par && par->isInset(pos) &&
264                         (inset = (UpdatableInset *)par->getInset(pos)) &&
265                         (inset->isTextInset()))
266                 {
267                         // lock the inset!
268                         text->setCursor(bv, par, pos);
269                         inset->edit(bv, false);
270                         if (inset->searchBackward(bv, str, cs, mw))
271                                 return SR_FOUND_NOUPDATE;
272                         text = bv->getLyXText();
273                 }               
274         } while (par && !IsStringInText(par, pos, str, cs, mw));
275   
276         if (par) {
277                 text->setCursor(bv, par, pos);
278                 return SR_FOUND;
279         } else if (text->inset_owner) {
280                 // test if we're inside an inset if yes unlock the inset
281                 // and recall us with the outside LyXText!
282                 bv->unlockInset((UpdatableInset *)text->inset_owner);
283                 return SearchBackward(bv, bv->getLyXText(), str, cs, mw);
284         } else {
285                 return SR_NOT_FOUND;
286         }
287 }
288