10 #include "lyx_gui_misc.h"
11 #include "support/textutils.h"
12 #include "support/lstrings.h"
13 #include "BufferView.h"
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!
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);
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);
44 SearchResult SearchBackward(BufferView *, LyXText * text, string const & str,
45 bool const & = true, bool const & = false);
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)
53 if (!bv->available() || bv->buffer()->isReadonly())
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] == ' '))
61 WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
62 "nor an empty character."));
66 LyXText * text = bv->getLyXText();
68 // now we can start searching for the first
69 // start at top if replaceall
72 text->clearSelection(bv);
73 if (text->inset_owner) {
74 bv->unlockInset(bv->theLockingInset());
78 // override search direction because we search top to bottom
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) ||
93 int replace_count = 0;
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);
102 found = LyXFind(bv, searchstr, fw, false, casesens, matchwrd);
103 } while (replaceall && found);
108 return replace_count;
111 bool LyXFind(BufferView * bv,
112 string const & searchstr, bool const & forward,
113 bool const & frominset,
114 bool const & casesens, bool const & matchwrd)
116 if (!bv->available() || searchstr.empty())
119 LyXText * text = bv->getLyXText();
122 bv->update(text, BufferView::SELECT|BufferView::FITCUR);
124 if (text->selection.set())
125 text->cursor = forward ?
126 text->selection.end : text->selection.start;
128 SearchResult result = SR_NOT_FOUND;
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);
135 result = SR_FOUND_NOUPDATE;
138 SearchForward(bv, text, searchstr, casesens, matchwrd) :
139 SearchBackward(bv, text, searchstr, casesens, matchwrd);
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)
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,
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)))))
178 if (size == string::size_type(i)) {
179 // if necessary, check whether string matches word
181 (mw && ((pos <= 0 || !IsLetterCharOrDigit(par->getChar(pos - 1)))
182 && (pos + Paragraph::size_type(size) >= par->size()
183 || !IsLetterCharOrDigit(par->getChar(pos + size))))
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)
198 Paragraph * par = text->cursor.par();
199 Paragraph::size_type pos = text->cursor.pos();
200 UpdatableInset * inset;
202 while (par && !IsStringInText(par, pos, str, cs, mw)) {
203 if (par->isInset(pos) &&
204 (inset = (UpdatableInset *)par->getInset(pos)) &&
205 (inset->isTextInset()))
208 text->setCursor(bv, par, pos);
210 if (inset->searchForward(bv, str, cs, mw))
211 return SR_FOUND_NOUPDATE;
212 text = bv->getLyXText();
214 if (pos < par->size() - 1)
222 text->setCursor(bv, par, pos);
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)
239 text->setCursor(bv, par, pos);
240 return SearchForward(bv, text, str, cs, mw);
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,
251 bool const & cs, bool const & mw)
253 Paragraph * par = text->cursor.par();
254 Paragraph::size_type pos = text->cursor.pos();
260 // We skip empty paragraphs (Asger)
262 par = par->previous();
264 pos = par->size() - 1;
265 } while (par && pos < 0);
267 UpdatableInset * inset;
268 if (par && par->isInset(pos) &&
269 (inset = (UpdatableInset *)par->getInset(pos)) &&
270 (inset->isTextInset()))
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();
279 } while (par && !IsStringInText(par, pos, str, cs, mw));
282 text->setCursor(bv, par, pos);
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);