#include "buffer_funcs.h"
#include "BufferParams.h"
+#include "BufferList.h"
#include "Cursor.h"
#include "FuncRequest.h"
#include "lyxfind.h"
#include "OutputParams.h"
#include "output_latex.h"
#include "TexRow.h"
+#include "alert.h"
#include "support/debug.h"
#include "support/FileName.h"
bool FindAndReplaceWidget::eventFilter(QObject *obj, QEvent *event)
{
- LYXERR(Debug::FIND, "FindAndReplace::eventFilter(): obj=" << obj
- << ", fwa=" << find_work_area_ << ", rwa=" << replace_work_area_
- << "fsa=" << find_scroll_area_ << ", rsa=" << replace_scroll_area_);
if (obj == find_work_area_ && event->type() == QEvent::KeyPress) {
QKeyEvent *e = static_cast<QKeyEvent *> (event);
if (e->key() == Qt::Key_Escape && e->modifiers() == Qt::NoModifier) {
return os.str();
}
+
+/** Switch p_buf to point to next document buffer.
+ **
+ ** Return true if restarted from master-document buffer.
+ **
+ ** @note
+ ** Not using p_buf->allRelatives() here, because I'm not sure
+ ** whether or not the returned order is independent of p_buf.
+ **/
+static bool next_document_buffer(Buffer * & p_buf) {
+ Buffer *p_master = p_buf;
+ Buffer *p_old;
+ do {
+ p_old = p_master;
+ p_master = const_cast<Buffer *>(p_master->masterBuffer());
+ LYXERR(Debug::FIND, "p_old=" << p_old << ", p_master=" << p_master);
+ } while (p_master != p_old);
+ LASSERT(p_master != NULL, /**/);
+ vector<Buffer *> v_children;
+ /* Root master added as first buffer in the vector */
+ v_children.push_back(p_master);
+ p_master->getChildren(v_children, true);
+ LYXERR(Debug::FIND, "v_children.size()=" << v_children.size());
+ vector<Buffer *>::const_iterator it = find(v_children.begin(), v_children.end(), p_buf);
+ LASSERT(it != v_children.end(), /**/)
+ ++it;
+ if (it == v_children.end()) {
+ p_buf = *v_children.begin();
+ return true;
+ }
+ p_buf = *it;
+ return false;
+}
+
+
+/** Switch p_buf to point to previous document buffer.
+ **
+ ** Return true if restarted from last child buffer.
+ **
+ ** @note
+ ** Not using p_buf->allRelatives() here, because I'm not sure
+ ** whether or not the returned order is independent of p_buf.
+ **/
+static bool prev_document_buffer(Buffer * & p_buf) {
+ Buffer *p_master = p_buf;
+ Buffer *p_old;
+ do {
+ p_old = p_master;
+ p_master = const_cast<Buffer *>(p_master->masterBuffer());
+ LYXERR(Debug::FIND, "p_old=" << p_old << ", p_master=" << p_master);
+ } while (p_master != p_old);
+ LASSERT(p_master != NULL, /**/);
+ vector<Buffer *> v_children;
+ /* Root master added as first buffer in the vector */
+ v_children.push_back(p_master);
+ p_master->getChildren(v_children, true);
+ LYXERR(Debug::FIND, "v_children.size()=" << v_children.size());
+ vector<Buffer *>::const_iterator it = find(v_children.begin(), v_children.end(), p_buf);
+ LASSERT(it != v_children.end(), /**/)
+ if (it == v_children.begin()) {
+ it = v_children.end();
+ --it;
+ p_buf = *it;
+ return true;
+ }
+ --it;
+ p_buf = *it;
+ return false;
+}
+
+
+/** Switch buf to point to next or previous buffer in search scope.
+ **
+ ** Return true if restarted from scratch.
+ **/
+static bool next_prev_buffer(Buffer * & buf, FindAndReplaceOptions const & opt) {
+ bool restarted = false;
+ switch (opt.scope) {
+ case FindAndReplaceOptions::S_BUFFER:
+ restarted = true;
+ break;
+ case FindAndReplaceOptions::S_DOCUMENT:
+ if (opt.forward)
+ restarted = next_document_buffer(buf);
+ else
+ restarted = prev_document_buffer(buf);
+ break;
+ case FindAndReplaceOptions::S_OPEN_BUFFERS:
+ if (opt.forward) {
+ buf = theBufferList().next(buf);
+ restarted = buf == *theBufferList().begin();
+ } else {
+ buf = theBufferList().previous(buf);
+ restarted = buf == *(theBufferList().end() - 1);
+ }
+ break;
+ }
+ return restarted;
+}
+
+
+/** Find the finest question message to post to the user */
+docstring question_string(FindAndReplaceOptions const & opt)
+{
+ docstring cur_pos = opt.forward ? _("End") : _("Begin");
+ docstring new_pos = opt.forward ? _("begin") : _("end");
+ docstring scope;
+ switch (opt.scope) {
+ case FindAndReplaceOptions::S_BUFFER:
+ scope = _("file");
+ break;
+ case FindAndReplaceOptions::S_DOCUMENT:
+ scope = _("master document");
+ break;
+ case FindAndReplaceOptions::S_OPEN_BUFFERS:
+ scope = _("open files");
+ break;
+ }
+ docstring dir = opt.forward ? _("forward") : _("backwards");
+ return cur_pos + _(" of ") + scope
+ + _(" reached while searching ") + dir + ".\n"
+ + "\n"
+ + _("Continue searching from ") + new_pos + " ?";
+}
+
+
+void FindAndReplaceWidget::findAndReplaceScope(FindAndReplaceOptions & opt) {
+ int wrap_answer = -1;
+ ostringstream oss;
+ oss << opt;
+ FuncRequest cmd(LFUN_WORD_FINDADV, from_utf8(oss.str()));
+ BufferView * bv = view_.documentBufferView();
+ Buffer * buf = &bv->buffer();
+
+ Buffer * buf_orig = &bv->buffer();
+ Cursor cur_orig(bv->cursor());
+
+ do {
+ LYXERR(Debug::FIND, "Dispatching LFUN_WORD_FINDADV");
+ dispatch(cmd);
+ if (bv->cursor().result().dispatched()) {
+ // Match found, selected and replaced if needed
+ return;
+ }
+
+ // No match found in current buffer: select next buffer in scope, if any
+ bool prompt = next_prev_buffer(buf, opt);
+ if (prompt) {
+ if (wrap_answer != -1)
+ break;
+ docstring q = question_string(opt);
+ wrap_answer = frontend::Alert::prompt(
+ _("Wrap search?"), q,
+ 0, 1, _("&Yes"), _("&No"));
+ if (wrap_answer == 1)
+ break;
+ }
+ lyx::dispatch(FuncRequest(LFUN_BUFFER_SWITCH,
+ buf->absFileName()));
+ bv = view_.documentBufferView();
+ if (opt.forward) {
+ bv->cursor().clear();
+ bv->cursor().push_back(CursorSlice(buf->inset()));
+ } else {
+ lyx::dispatch(FuncRequest(LFUN_BUFFER_END));
+ bv->cursor().setCursor(doc_iterator_end(buf));
+ bv->cursor().backwardPos();
+ LYXERR(Debug::FIND, "findBackAdv5: cur: " << bv->cursor());
+ }
+ bv->clearSelection();
+ } while (wrap_answer != 1);
+ lyx::dispatch(FuncRequest(LFUN_BUFFER_SWITCH,
+ buf_orig->absFileName()));
+ bv = view_.documentBufferView();
+ bv->cursor() = cur_orig;
+}
+
+
void FindAndReplaceWidget::findAndReplace(
bool casesensitive, bool matchword, bool backwards,
bool expandmacros, bool ignoreformat, bool replace,
<< ", scope=" << scope);
FindAndReplaceOptions opt(searchString, casesensitive, matchword, ! backwards,
expandmacros, ignoreformat, regexp, replaceString, keep_case, scope);
- LYXERR(Debug::FIND, "Dispatching LFUN_WORD_FINDADV");
- std::ostringstream oss;
- oss << opt;
- LYXERR(Debug::FIND, "Dispatching LFUN_WORD_FINDADV");
- dispatch(FuncRequest(LFUN_WORD_FINDADV, from_utf8(oss.str())));
+ findAndReplaceScope(opt);
}
}
-/** Switch p_buf to point to next document buffer.
- **
- ** Return true if restarted from master-document buffer.
- **
- ** @note
- ** Not using p_buf->allRelatives() here, because I'm not sure
- ** whether or not the returned order is independent of p_buf.
- **/
-bool next_document_buffer(Buffer * & p_buf) {
- Buffer *p_master = p_buf;
- Buffer *p_old;
- do {
- p_old = p_master;
- p_master = const_cast<Buffer *>(p_master->masterBuffer());
- LYXERR(Debug::FIND, "p_old=" << p_old << ", p_master=" << p_master);
- } while (p_master != p_old);
- LASSERT(p_master != NULL, /**/);
- vector<Buffer *> v_children;
- /* Root master added as first buffer in the vector */
- v_children.push_back(p_master);
- p_master->getChildren(v_children, true);
- LYXERR(Debug::FIND, "v_children.size()=" << v_children.size());
- vector<Buffer *>::const_iterator it = find(v_children.begin(), v_children.end(), p_buf);
- LASSERT(it != v_children.end(), /**/)
- ++it;
- if (it == v_children.end()) {
- p_buf = *v_children.begin();
- return true;
- }
- p_buf = *it;
- return false;
-}
-
-
-/** Switch p_buf to point to previous document buffer.
- **
- ** Return true if restarted from last child buffer.
- **
- ** @note
- ** Not using p_buf->allRelatives() here, because I'm not sure
- ** whether or not the returned order is independent of p_buf.
- **/
-bool prev_document_buffer(Buffer * & p_buf) {
- Buffer *p_master = p_buf;
- Buffer *p_old;
- do {
- p_old = p_master;
- p_master = const_cast<Buffer *>(p_master->masterBuffer());
- LYXERR(Debug::FIND, "p_old=" << p_old << ", p_master=" << p_master);
- } while (p_master != p_old);
- LASSERT(p_master != NULL, /**/);
- vector<Buffer *> v_children;
- /* Root master added as first buffer in the vector */
- v_children.push_back(p_master);
- p_master->getChildren(v_children, true);
- LYXERR(Debug::FIND, "v_children.size()=" << v_children.size());
- vector<Buffer *>::const_iterator it = find(v_children.begin(), v_children.end(), p_buf);
- LASSERT(it != v_children.end(), /**/)
- if (it == v_children.begin()) {
- it = v_children.end();
- --it;
- p_buf = *it;
- return true;
- }
- --it;
- p_buf = *it;
- return false;
-}
-
-
-/** Switch p_buf to point to next open buffer.
- **
- ** Return true if restarted from first open buffer.
- **/
-bool next_open_buffer(Buffer * & p_buf) {
- p_buf = theBufferList().next(p_buf);
- return p_buf == *theBufferList().begin();
-}
-
-
-/** Switch p_buf to point to previous open buffer.
- **
- ** Return true if restarted from last open buffer.
- **/
-bool prev_open_buffer(Buffer * & p_buf) {
- p_buf = theBufferList().previous(p_buf);
- return p_buf == *(theBufferList().end() - 1);
-}
-
-
/// Finds forward
int findForwardAdv(DocIterator & cur, MatchStringAdv & match)
{
if (!cur)
return 0;
- int wrap_answer = -1;
- do {
- while (cur && !match(cur, -1, false)) {
- if (cur.pit() < cur.lastpit())
- cur.forwardPar();
- else {
- cur.forwardPos();
- }
- }
- for (; cur; cur.forwardPos()) {
- if (match(cur))
- return findAdvFinalize(cur, match);
+ while (cur && !match(cur, -1, false)) {
+ if (cur.pit() < cur.lastpit())
+ cur.forwardPar();
+ else {
+ cur.forwardPos();
}
- // No match has been found in current buffer
- bool prompt = false;
- switch (match.opt.scope) {
- case FindAndReplaceOptions::S_BUFFER:
- prompt = true;
- break;
- case FindAndReplaceOptions::S_DOCUMENT:
- prompt = next_document_buffer(match.p_buf);
- break;
- case FindAndReplaceOptions::S_OPEN_BUFFERS:
- prompt = next_open_buffer(match.p_buf);
- break;
- }
- if (prompt) {
- if (wrap_answer != -1)
- break;
- wrap_answer = frontend::Alert::prompt(
- _("Wrap search?"),
- _("End of document/scope reached while searching forward.\n"
- "\n"
- "Continue searching from beginning?"),
- 0, 1, _("&Yes"), _("&No"));
- }
- cur.clear();
- cur.push_back(CursorSlice(match.p_buf->inset()));
- } while (wrap_answer != 1);
+ }
+ for (; cur; cur.forwardPos()) {
+ if (match(cur))
+ return findAdvFinalize(cur, match);
+ }
return 0;
}
/// Find the most backward consecutive match within same paragraph while searching backwards.
-void findMostBackwards(DocIterator & cur, MatchStringAdv const & match, int & len) {
+void findMostBackwards(DocIterator & cur, MatchStringAdv const & match, int & len)
+{
DocIterator cur_begin = doc_iterator_begin(cur.buffer());
len = findAdvFinalize(cur, match);
if (cur != cur_begin) {
LYXERR(Debug::FIND, "findMostBackwards(): cur=" << cur);
}
+
/// Finds backwards
int findBackwardsAdv(DocIterator & cur, MatchStringAdv & match) {
if (! cur)
return 0;
- // Backup of original position (for restoring it in case match not found)
+ // Backup of original position
DocIterator cur_orig(cur);
- // Position beyond which match is not considered
- // (set to end of document after wrap-around question)
- DocIterator cur_orig2(cur);
DocIterator cur_begin = doc_iterator_begin(cur.buffer());
-/* if (match(cur_orig)) */
-/* findAdvFinalize(cur_orig, match); */
- int wrap_answer = 0;
+ if (cur == cur_begin)
+ return 0;
bool found_match;
+ bool pit_changed = false;
+ found_match = false;
do {
- bool pit_changed = false;
- found_match = false;
- // Search in current par occurs from start to end,
- // but in next loop match is discarded if pos > original pos
cur.pos() = 0;
found_match = match(cur, -1, false);
- LYXERR(Debug::FIND, "findBackAdv0: found_match=" << found_match << ", cur: " << cur);
- while (cur != cur_begin) {
- if (found_match)
- break;
- if (cur.pit() > 0)
- --cur.pit();
- else
- cur.backwardPos();
- pit_changed = true;
- // Search in previous pars occurs from start to end
- cur.pos() = 0;
- found_match = match(cur, -1, false);
- LYXERR(Debug::FIND, "findBackAdv1: found_match="
- << found_match << ", cur: " << cur);
- }
- if (pit_changed)
- cur.pos() = cur.lastpos();
- else
- cur.pos() = cur_orig2.pos();
- LYXERR(Debug::FIND, "findBackAdv2: cur: " << cur);
- DocIterator cur_prev_iter;
+
if (found_match) {
+ if (pit_changed)
+ cur.pos() = cur.lastpos();
+ else
+ cur.pos() = cur_orig.pos();
+ LYXERR(Debug::FIND, "findBackAdv2: cur: " << cur);
+ DocIterator cur_prev_iter;
while (true) {
- found_match=match(cur);
+ found_match = match(cur);
LYXERR(Debug::FIND, "findBackAdv3: found_match="
- << found_match << ", cur: " << cur);
+ << found_match << ", cur: " << cur);
if (found_match) {
int len;
findMostBackwards(cur, match, len);
- if (&cur.inset() != &cur_orig2.inset()
- || !(cur.pit() == cur_orig2.pit())
- || cur.pos() < cur_orig2.pos())
+ if (cur < cur_orig)
return len;
}
// Prevent infinite loop at begin of document
break;
cur_prev_iter = cur;
cur.backwardPos();
- };
+ }
}
- // No match has been found in current buffer
- bool prompt = false;
- switch (match.opt.scope) {
- case FindAndReplaceOptions::S_BUFFER:
- prompt = true;
- break;
- case FindAndReplaceOptions::S_DOCUMENT:
- prompt = prev_document_buffer(match.p_buf);
- break;
- case FindAndReplaceOptions::S_OPEN_BUFFERS:
- prompt = prev_open_buffer(match.p_buf);
+ if (cur == cur_begin)
break;
- }
- if (prompt) {
- wrap_answer = frontend::Alert::prompt(
- _("Wrap search?"),
- _("Beginning of document/scope reached while searching backwards\n"
- "\n"
- "Continue searching from end?"),
- 0, 1, _("&Yes"), _("&No"));
- }
- cur = doc_iterator_end(match.p_buf);
- cur.backwardPos();
- LYXERR(Debug::FIND, "findBackAdv5: cur: " << cur);
- cur_orig2 = cur;
- } while (wrap_answer == 0);
- cur = cur_orig;
+ if (cur.pit() > 0)
+ --cur.pit();
+ else
+ cur.backwardPos();
+ pit_changed = true;
+ } while (true);
return 0;
}
bv->message(_("Search text is empty!"));
return false;
}
-// if (! bv->buffer()) {
-// bv->message(_("No open document !"));
-// return false;
-// }
MatchStringAdv matchAdv(bv->buffer(), opt);
try {
LYXERR(Debug::FIND, "Putting selection at buf=" << matchAdv.p_buf
<< "cur=" << cur << " with len: " << match_len);
- lyx::dispatch(FuncRequest(LFUN_BUFFER_SWITCH,
- matchAdv.p_buf->absFileName()));
- bv = theApp()->currentWindow()->documentBufferView();
-
bv->putSelectionAt(cur, match_len, ! opt.forward);
if (opt.replace == docstring(from_utf8(LYX_FR_NULL_STRING))) {
- bv->message(_("Match found !"));
+ bv->message(_("Match found!"));
} else {
string lyx = to_utf8(opt.replace);
// FIXME: Seems so stupid to me to rebuild a buffer here,
bv->message(_("Match found and replaced !"));
} else
LASSERT(false, /**/);
- // dispatch(FuncRequest(LFUN_SELF_INSERT, opt.replace));
}
return true;
}
-void findAdv(BufferView * bv, FuncRequest const & ev)
-{
- if (!bv || ev.action != LFUN_WORD_FINDADV)
- return;
-
- FindAndReplaceOptions opt;
- istringstream iss(to_utf8(ev.argument()));
- iss >> opt;
- findAdv(bv, opt);
-}
-
-
ostringstream & operator<<(ostringstream & os, lyx::FindAndReplaceOptions const & opt)
{
os << to_utf8(opt.search) << "\nEOSS\n"