10 #include "frontends/LyXView.h"
11 #include "frontends/Alert.h"
12 #include "support/textutils.h"
13 #include "support/lstrings.h"
14 #include "BufferView.h"
18 #include "insets/insettext.h"
24 /// returns true if the specified string is at the specified position
25 bool IsStringInText(Paragraph * par, pos_type pos,
26 string const & str, bool const & = true,
27 bool const & = false);
29 /// if the string is found: return true and set the cursor to the new position
30 SearchResult SearchForward(BufferView *, LyXText * text, string const & str,
31 bool const & = true, bool const & = false);
33 SearchResult SearchBackward(BufferView *, LyXText * text, string const & str,
34 bool const & = true, bool const & = false);
36 int LyXReplace(BufferView * bv,
37 string const & searchstr, string const & replacestr,
38 bool forward, bool casesens, bool matchwrd, bool replaceall,
41 if (!bv->available() || bv->buffer()->isReadonly())
44 // CutSelection cannot cut a single space, so we have to stop
45 // in order to avoid endless loop :-(
46 if (searchstr.length() == 0
47 || (searchstr.length() == 1 && searchstr[0] == ' '))
49 Alert::alert(_("Sorry!"), _("You cannot replace a single space, "
50 "nor an empty character."));
54 // now we can start searching for the first
55 // start at top if replaceall
56 LyXText * text = bv->getLyXText();
59 text->clearSelection();
60 bv->unlockInset(bv->theLockingInset());
63 // override search direction because we search top to bottom
67 // if nothing selected or selection does not equal search string
68 // search and select next occurance and return if no replaceall
73 str2 = text->selectionAsString(bv->buffer(), false);
75 str1 = lowercase(searchstr);
76 str2 = lowercase(text->selectionAsString(bv->buffer(), false));
79 if (!LyXFind(bv, searchstr, fw, casesens, matchwrd) ||
87 int replace_count = 0;
89 text = bv->getLyXText();
90 // We have to do this check only because mathed insets don't
91 // return their own LyXText but the LyXText of it's parent!
92 if (!bv->theLockingInset() ||
93 ((text != bv->text) &&
94 (text->inset_owner == text->inset_owner->getLockingInset())))
97 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
98 bv->toggleSelection(false);
99 text->replaceSelectionWithString(bv, replacestr);
100 text->setSelectionOverString(bv, replacestr);
101 bv->update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
105 found = LyXFind(bv, searchstr, fw, casesens, matchwrd);
106 } while (!once && replaceall && found);
108 return replace_count;
112 bool LyXFind(BufferView * bv,
113 string const & searchstr, bool forward,
114 bool casesens, bool matchwrd)
116 if (!bv->available() || searchstr.empty())
120 bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
122 if (bv->theLockingInset()) {
123 bool found = forward ?
124 bv->theLockingInset()->searchForward(bv, searchstr, casesens, matchwrd) :
125 bv->theLockingInset()->searchBackward(bv, searchstr, casesens, matchwrd);
126 // We found the stuff inside the inset so we don't have to
127 // do anything as the inset did all the update for us!
130 // We now are in the main text but if we did a forward
131 // search we have to put the cursor behind the inset.
133 bv->text->cursorRight(bv, true);
136 // If we arrive here we are in the main text again so we
137 // just start searching from the root LyXText at the position
139 LyXText * text = bv->text;
141 if (text->selection.set())
142 text->cursor = forward ?
143 text->selection.end : text->selection.start;
145 bv->toggleSelection();
146 text->clearSelection();
148 SearchResult result = forward ?
149 SearchForward(bv, text, searchstr, casesens, matchwrd) :
150 SearchBackward(bv, text, searchstr, casesens, matchwrd);
153 // If we found the cursor inside an inset we will get back
154 // SR_FOUND_NOUPDATE and we don't have to do anything as the
155 // inset did it already.
156 if (result == SR_FOUND) {
157 bv->unlockInset(bv->theLockingInset());
158 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
159 text->setSelectionOverString(bv, searchstr);
160 bv->toggleSelection(false);
161 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
162 } else if (result == SR_NOT_FOUND) {
163 bv->unlockInset(bv->theLockingInset());
164 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
172 SearchResult LyXFind(BufferView * bv, LyXText * text,
173 string const & searchstr, bool forward,
174 bool casesens, bool matchwrd)
176 if (text->selection.set())
177 text->cursor = forward ?
178 text->selection.end : text->selection.start;
180 bv->toggleSelection();
181 text->clearSelection();
183 SearchResult result = forward ?
184 SearchForward(bv, text, searchstr, casesens, matchwrd) :
185 SearchBackward(bv, text, searchstr, casesens, matchwrd);
191 // returns true if the specified string is at the specified position
192 bool IsStringInText(Paragraph * par, pos_type pos,
193 string const & str, bool const & cs,
199 string::size_type size = str.length();
201 while (((pos + i) < par->size())
202 && (string::size_type(i) < size)
203 && (cs ? (str[i] == par->getChar(pos + i))
204 : (uppercase(str[i]) == uppercase(par->getChar(pos + i)))))
208 if (size == string::size_type(i)) {
209 // if necessary, check whether string matches word
212 if ((pos <= 0 || !IsLetterCharOrDigit(par->getChar(pos - 1)))
213 && (pos + pos_type(size) >= par->size()
214 || !IsLetterCharOrDigit(par->getChar(pos + size)))) {
222 // if the string can be found: return true and set the cursor to
223 // the new position, cs = casesensitive, mw = matchword
224 SearchResult SearchForward(BufferView * bv, LyXText * text, string const & str,
225 bool const & cs, bool const & mw)
227 Paragraph * par = text->cursor.par();
228 pos_type pos = text->cursor.pos();
229 Paragraph * prev_par = par;
230 UpdatableInset * inset;
232 while (par && !IsStringInText(par, pos, str, cs, mw)) {
233 if (par->isInset(pos) &&
234 (inset = (UpdatableInset *)par->getInset(pos)) &&
235 (inset->isTextInset()))
239 text->setCursor(bv, par, pos);
242 if (inset->searchForward(bv, str, cs, mw))
243 return SR_FOUND_NOUPDATE;
248 if (pos >= par->size()) {
256 text->setCursor(bv, par, pos);
259 // make sure we end up at the end of the text,
260 // not the start point of the last search
261 text->setCursor(bv, prev_par, prev_par->size());
268 // if the string can be found: return true and set the cursor to
269 // the new position, cs = casesensitive, mw = matchword
270 SearchResult SearchBackward(BufferView * bv, LyXText * text,
272 bool const & cs, bool const & mw)
274 Paragraph * par = text->cursor.par();
275 pos_type pos = text->cursor.pos();
276 Paragraph * prev_par = par;
283 // We skip empty paragraphs (Asger)
285 par = par->previous();
287 pos = par->size() - 1;
288 } while (par && pos < 0);
290 UpdatableInset * inset;
291 if (par && par->isInset(pos) &&
292 (inset = (UpdatableInset *)par->getInset(pos)) &&
293 (inset->isTextInset()))
297 text->setCursor(bv, par, pos);
298 inset->edit(bv, false);
300 if (inset->searchBackward(bv, str, cs, mw))
301 return SR_FOUND_NOUPDATE;
303 } while (par && !IsStringInText(par, pos, str, cs, mw));
306 text->setCursor(bv, par, pos);
309 // go to the last part of the unsuccessful search
310 text->setCursor(bv, prev_par, 0);
315 } // end lyxfind namespace