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