10 #include "frontends/Alert.h"
11 #include "support/textutils.h"
12 #include "support/lstrings.h"
13 #include "BufferView.h"
33 /// returns true if the specified string is at the specified position
34 bool IsStringInText(Paragraph * par, pos_type pos,
35 string const & str, bool const & = true,
36 bool const & = false);
38 /// if the string is found: return true and set the cursor to the new position
39 SearchResult SearchForward(BufferView *, LyXText * text, string const & str,
40 bool const & = true, bool const & = false);
42 SearchResult SearchBackward(BufferView *, LyXText * text, string const & str,
43 bool const & = true, bool const & = false);
46 int LyXReplace(BufferView * bv,
47 string const & searchstr, string const & replacestr,
48 bool forward, bool casesens, bool matchwrd, bool replaceall,
51 if (!bv->available() || bv->buffer()->isReadonly())
54 // CutSelection cannot cut a single space, so we have to stop
55 // in order to avoid endless loop :-(
56 if (searchstr.length() == 0
57 || (searchstr.length() == 1 && searchstr[0] == ' '))
59 Alert::alert(_("Sorry!"), _("You cannot replace a single space, "
60 "nor an empty character."));
64 LyXText * text = bv->getLyXText();
66 // now we can start searching for the first
67 // start at top if replaceall
70 text->clearSelection();
71 if (text->inset_owner) {
72 bv->unlockInset(bv->theLockingInset());
76 // override search direction because we search top to bottom
80 // if nothing selected or selection does not equal search string
81 // search and select next occurance and return if no replaceall
86 str2 = text->selectionAsString(bv->buffer(), false);
88 str1 = lowercase(searchstr);
89 str2 = lowercase(text->selectionAsString(bv->buffer(), false));
92 if (!LyXFind(bv, searchstr, fw, false, casesens, matchwrd) ||
100 int replace_count = 0;
103 bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
104 bv->toggleSelection(false);
105 bv->getLyXText()->replaceSelectionWithString(bv, replacestr);
106 bv->getLyXText()->setSelectionOverString(bv, replacestr);
107 bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
110 found = LyXFind(bv, searchstr, fw, false, casesens, matchwrd);
111 } while (!once && replaceall && found);
116 return replace_count;
119 bool LyXFind(BufferView * bv,
120 string const & searchstr, bool forward,
121 bool frominset, bool casesens, bool matchwrd)
123 if (!bv->available() || searchstr.empty())
126 LyXText * text = bv->getLyXText();
129 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
131 if (text->selection.set())
132 text->cursor = forward ?
133 text->selection.end : text->selection.start;
135 SearchResult result = SR_NOT_FOUND;
137 if (!frominset && bv->theLockingInset()) {
138 bool found = forward ?
139 bv->theLockingInset()->searchForward(bv, searchstr, casesens, matchwrd) :
140 bv->theLockingInset()->searchBackward(bv, searchstr, casesens, matchwrd);
142 result = SR_FOUND_NOUPDATE;
144 text = bv->getLyXText();
145 Paragraph * par = text->cursor.par();
146 pos_type pos = text->cursor.pos();
148 if (pos < par->size() - 1)
155 text->setCursor(bv, par, pos);
159 SearchForward(bv, text, searchstr, casesens, matchwrd) :
160 SearchBackward(bv, text, searchstr, casesens, matchwrd);
165 SearchForward(bv, text, searchstr, casesens, matchwrd) :
166 SearchBackward(bv, text, searchstr, casesens, matchwrd);
170 if (result == SR_FOUND) {
171 // the actual text pointer could have changed!
172 bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
173 bv->toggleSelection();
174 bv->getLyXText()->clearSelection();
175 bv->getLyXText()->setSelectionOverString(bv, searchstr);
176 bv->toggleSelection(false);
177 bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
178 } else if (result == SR_NOT_FOUND)
188 // returns true if the specified string is at the specified position
189 bool IsStringInText(Paragraph * par, pos_type pos,
190 string const & str, bool const & cs,
196 string::size_type size = str.length();
198 while (((pos + i) < par->size())
199 && (string::size_type(i) < size)
200 && (cs ? (str[i] == par->getChar(pos + i))
201 : (toupper(str[i]) == toupper(par->getChar(pos + i)))))
205 if (size == string::size_type(i)) {
206 // if necessary, check whether string matches word
209 if ((pos <= 0 || !IsLetterCharOrDigit(par->getChar(pos - 1)))
210 && (pos + pos_type(size) >= par->size()
211 || !IsLetterCharOrDigit(par->getChar(pos + size)))) {
219 // if the string can be found: return true and set the cursor to
220 // the new position, cs = casesensitive, mw = matchword
221 SearchResult SearchForward(BufferView * bv, LyXText * text, string const & str,
222 bool const & cs, bool const & mw)
224 Paragraph * par = text->cursor.par();
225 pos_type pos = text->cursor.pos();
226 UpdatableInset * inset;
228 while (par && !IsStringInText(par, pos, str, cs, mw)) {
229 if (par->isInset(pos) &&
230 (inset = (UpdatableInset *)par->getInset(pos)) &&
231 (inset->isTextInset()))
234 text->setCursor(bv, par, pos);
236 if (inset->searchForward(bv, str, cs, mw))
237 return SR_FOUND_NOUPDATE;
238 text = bv->getLyXText();
240 if (pos < par->size() - 1)
248 text->setCursor(bv, par, pos);
251 } else if (text->inset_owner) {
252 // test if we're inside an inset if yes unlock the inset
253 // and recall us with the outside LyXText!
254 bv->unlockInset((UpdatableInset *)text->inset_owner);
255 if (!bv->theLockingInset()) {
256 text = bv->getLyXText();
257 par = text->cursor.par();
258 pos = text->cursor.pos();
259 if (pos < par->size() - 1)
267 text->setCursor(bv, par, pos);
268 return SearchForward(bv, text, str, cs, mw);
279 // if the string can be found: return true and set the cursor to
280 // the new position, cs = casesensitive, mw = matchword
281 SearchResult SearchBackward(BufferView * bv, LyXText * text,
283 bool const & cs, bool const & mw)
285 Paragraph * par = text->cursor.par();
286 pos_type pos = text->cursor.pos();
292 // We skip empty paragraphs (Asger)
294 par = par->previous();
296 pos = par->size() - 1;
297 } while (par && pos < 0);
299 UpdatableInset * inset;
300 if (par && par->isInset(pos) &&
301 (inset = (UpdatableInset *)par->getInset(pos)) &&
302 (inset->isTextInset()))
305 text->setCursor(bv, par, pos);
306 inset->edit(bv, false);
307 if (inset->searchBackward(bv, str, cs, mw))
308 return SR_FOUND_NOUPDATE;
309 text = bv->getLyXText();
311 } while (par && !IsStringInText(par, pos, str, cs, mw));
314 text->setCursor(bv, par, pos);
318 else if (text->inset_owner) {
319 // test if we're inside an inset if yes unlock the inset
320 // and recall us with the outside LyXText!
321 bv->unlockInset((UpdatableInset *)text->inset_owner);
322 if (!bv->theLockingInset()) {
323 return SearchBackward(bv, bv->getLyXText(), str, cs, mw);