9 #include "frontends/LyXView.h"
10 #include "frontends/Alert.h"
11 #include "support/textutils.h"
12 #include "support/lstrings.h"
13 #include "BufferView.h"
17 #include "insets/insettext.h"
23 /// returns true if the specified string is at the specified position
24 bool IsStringInText(Paragraph * par, pos_type pos,
25 string const & str, bool const & = true,
26 bool const & = false);
28 /// if the string is found: return true and set the cursor to the new position
29 SearchResult SearchForward(BufferView *, LyXText * text, string const & str,
30 bool const & = true, bool const & = false);
32 SearchResult SearchBackward(BufferView *, LyXText * text, string const & str,
33 bool const & = true, bool const & = false);
35 int LyXReplace(BufferView * bv,
36 string const & searchstr, string const & replacestr,
37 bool forward, bool casesens, bool matchwrd, bool replaceall,
40 if (!bv->available() || bv->buffer()->isReadonly())
43 // CutSelection cannot cut a single space, so we have to stop
44 // in order to avoid endless loop :-(
45 if (searchstr.length() == 0
46 || (searchstr.length() == 1 && searchstr[0] == ' '))
48 Alert::alert(_("Sorry!"), _("You cannot replace a single space, "
49 "nor an empty character."));
53 // now we can start searching for the first
54 // start at top if replaceall
55 LyXText * text = bv->getLyXText();
58 text->clearSelection();
59 bv->unlockInset(bv->theLockingInset());
62 // override search direction because we search top to bottom
66 // if nothing selected or selection does not equal search string
67 // search and select next occurance and return if no replaceall
72 str2 = text->selectionAsString(bv->buffer(), false);
74 str1 = lowercase(searchstr);
75 str2 = lowercase(text->selectionAsString(bv->buffer(), false));
78 if (!LyXFind(bv, searchstr, fw, casesens, matchwrd) ||
86 int replace_count = 0;
88 text = bv->getLyXText();
89 // We have to do this check only because mathed insets don't
90 // return their own LyXText but the LyXText of it's parent!
91 if (!bv->theLockingInset() ||
92 ((text != bv->text) &&
93 (text->inset_owner == text->inset_owner->getLockingInset())))
96 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
97 bv->toggleSelection(false);
98 text->replaceSelectionWithString(bv, replacestr);
99 text->setSelectionOverString(bv, replacestr);
100 bv->update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
104 found = LyXFind(bv, searchstr, fw, casesens, matchwrd);
105 } while (!once && replaceall && found);
107 return replace_count;
111 bool LyXFind(BufferView * bv,
112 string const & searchstr, bool forward,
113 bool casesens, bool matchwrd)
115 if (!bv->available() || searchstr.empty())
119 bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
121 if (bv->theLockingInset()) {
122 bool found = forward ?
123 bv->theLockingInset()->searchForward(bv, searchstr, casesens, matchwrd) :
124 bv->theLockingInset()->searchBackward(bv, searchstr, casesens, matchwrd);
125 // We found the stuff inside the inset so we don't have to
126 // do anything as the inset did all the update for us!
129 // We now are in the main text but if we did a forward
130 // search we have to put the cursor behind the inset.
132 bv->text->cursorRight(bv, true);
135 // If we arrive here we are in the main text again so we
136 // just start searching from the root LyXText at the position
138 LyXText * text = bv->text;
140 if (text->selection.set())
141 text->cursor = forward ?
142 text->selection.end : text->selection.start;
144 bv->toggleSelection();
145 text->clearSelection();
147 SearchResult result = forward ?
148 SearchForward(bv, text, searchstr, casesens, matchwrd) :
149 SearchBackward(bv, text, searchstr, casesens, matchwrd);
152 // If we found the cursor inside an inset we will get back
153 // SR_FOUND_NOUPDATE and we don't have to do anything as the
154 // inset did it already.
155 if (result == SR_FOUND) {
156 bv->unlockInset(bv->theLockingInset());
157 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
158 text->setSelectionOverString(bv, searchstr);
159 bv->toggleSelection(false);
160 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
161 } else if (result == SR_NOT_FOUND) {
162 bv->unlockInset(bv->theLockingInset());
163 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
171 SearchResult LyXFind(BufferView * bv, LyXText * text,
172 string const & searchstr, bool forward,
173 bool casesens, bool matchwrd)
175 if (text->selection.set())
176 text->cursor = forward ?
177 text->selection.end : text->selection.start;
179 bv->toggleSelection();
180 text->clearSelection();
182 SearchResult result = forward ?
183 SearchForward(bv, text, searchstr, casesens, matchwrd) :
184 SearchBackward(bv, text, searchstr, casesens, matchwrd);
190 // returns true if the specified string is at the specified position
191 bool IsStringInText(Paragraph * par, pos_type pos,
192 string const & str, bool const & cs,
198 string::size_type size = str.length();
200 while (((pos + i) < par->size())
201 && (string::size_type(i) < size)
202 && (cs ? (str[i] == par->getChar(pos + i))
203 : (uppercase(str[i]) == uppercase(par->getChar(pos + i)))))
207 if (size == string::size_type(i)) {
208 // if necessary, check whether string matches word
211 if ((pos <= 0 || !IsLetterCharOrDigit(par->getChar(pos - 1)))
212 && (pos + pos_type(size) >= par->size()
213 || !IsLetterCharOrDigit(par->getChar(pos + size)))) {
221 // if the string can be found: return true and set the cursor to
222 // the new position, cs = casesensitive, mw = matchword
223 SearchResult SearchForward(BufferView * bv, LyXText * text, string const & str,
224 bool const & cs, bool const & mw)
226 Paragraph * par = text->cursor.par();
227 pos_type pos = text->cursor.pos();
228 Paragraph * prev_par = par;
229 UpdatableInset * inset;
231 while (par && !IsStringInText(par, pos, str, cs, mw)) {
232 if (par->isInset(pos) &&
233 (inset = (UpdatableInset *)par->getInset(pos)) &&
234 (inset->isTextInset()))
238 text->setCursor(bv, par, pos);
241 if (inset->searchForward(bv, str, cs, mw))
242 return SR_FOUND_NOUPDATE;
247 if (pos >= par->size()) {
255 text->setCursor(bv, par, pos);
258 // make sure we end up at the end of the text,
259 // not the start point of the last search
260 text->setCursor(bv, prev_par, prev_par->size());
267 // if the string can be found: return true and set the cursor to
268 // the new position, cs = casesensitive, mw = matchword
269 SearchResult SearchBackward(BufferView * bv, LyXText * text,
271 bool const & cs, bool const & mw)
273 Paragraph * par = text->cursor.par();
274 pos_type pos = text->cursor.pos();
275 Paragraph * prev_par = par;
282 // We skip empty paragraphs (Asger)
284 par = par->previous();
286 pos = par->size() - 1;
287 } while (par && pos < 0);
289 UpdatableInset * inset;
290 if (par && par->isInset(pos) &&
291 (inset = (UpdatableInset *)par->getInset(pos)) &&
292 (inset->isTextInset()))
296 text->setCursor(bv, par, pos);
297 inset->edit(bv, false);
299 if (inset->searchBackward(bv, str, cs, mw))
300 return SR_FOUND_NOUPDATE;
302 } while (par && !IsStringInText(par, pos, str, cs, mw));
305 text->setCursor(bv, par, pos);
308 // go to the last part of the unsuccessful search
309 text->setCursor(bv, prev_par, 0);
314 } // end lyxfind namespace