From 5cc2d6d73c2a68bc1f5baa7a58b6e2784d3e619a Mon Sep 17 00:00:00 2001 From: Tommaso Cucinotta Date: Mon, 4 Jan 2010 12:29:38 +0000 Subject: [PATCH] Advanced F&R rework: - scopes now handled in FindAndReplaceWidget, while lyxfind.cpp only searches within single buffer - cursor().result().dispatched() now encodes whether a match was found or not, after LFUN_WORD_FINDADV dispatch - removed a few unneeded functions - followed a few cosmetic advices git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@32760 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/BufferView.cpp | 11 +- src/frontends/qt4/FindAndReplace.cpp | 189 ++++++++++++++++- src/frontends/qt4/FindAndReplace.h | 12 +- src/frontends/qt4/ui/FindAndReplaceUi.ui | 3 + src/lyxfind.cpp | 252 ++++------------------- src/lyxfind.h | 3 - 6 files changed, 239 insertions(+), 231 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index cb06810f7a..f70661ad8c 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -1503,9 +1503,16 @@ bool BufferView::dispatch(FuncRequest const & cmd) break; } - case LFUN_WORD_FINDADV: - findAdv(this, cmd); + case LFUN_WORD_FINDADV: { + FindAndReplaceOptions opt; + istringstream iss(to_utf8(cmd.argument())); + iss >> opt; + if (findAdv(this, opt)) + cur.dispatched(); + else + cur.undispatched(); break; + } case LFUN_MARK_OFF: cur.clearSelection(); diff --git a/src/frontends/qt4/FindAndReplace.cpp b/src/frontends/qt4/FindAndReplace.cpp index 7164aa25db..2eadfcd2d3 100644 --- a/src/frontends/qt4/FindAndReplace.cpp +++ b/src/frontends/qt4/FindAndReplace.cpp @@ -19,12 +19,14 @@ #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" @@ -62,9 +64,6 @@ FindAndReplaceWidget::FindAndReplaceWidget(GuiView & view) 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 (event); if (e->key() == Qt::Key_Escape && e->modifiers() == Qt::NoModifier) { @@ -125,6 +124,184 @@ static docstring buffer_to_latex(Buffer & buffer) { 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(p_master->masterBuffer()); + LYXERR(Debug::FIND, "p_old=" << p_old << ", p_master=" << p_master); + } while (p_master != p_old); + LASSERT(p_master != NULL, /**/); + vector 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::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(p_master->masterBuffer()); + LYXERR(Debug::FIND, "p_old=" << p_old << ", p_master=" << p_master); + } while (p_master != p_old); + LASSERT(p_master != NULL, /**/); + vector 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::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, @@ -184,11 +361,7 @@ void FindAndReplaceWidget::findAndReplace( << ", 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); } diff --git a/src/frontends/qt4/FindAndReplace.h b/src/frontends/qt4/FindAndReplace.h index 22abb650ca..e940606f35 100644 --- a/src/frontends/qt4/FindAndReplace.h +++ b/src/frontends/qt4/FindAndReplace.h @@ -22,6 +22,7 @@ #include "LyX.h" #include "LyXFunc.h" #include "Text.h" +#include "lyxfind.h" #include @@ -42,15 +43,20 @@ private: /// GuiView & view_; - // add a string to the combo if needed + /// add a string to the combo if needed void remember(std::string const & find, QComboBox & combo); + + /// FIXME Probably to be merged with findAndReplace(bool, bool) void findAndReplace( bool casesensitive, bool matchword, bool backwards, bool expandmacros, bool ignoreformat, bool replace, bool keep_case ); -// void find(docstring const & str, int len, bool casesens, -// bool words, bool backwards, bool expandmacros); + + /// Perform the scope-related buffer switch while searching + void findAndReplaceScope(FindAndReplaceOptions & opt); + + /// Collect options from the GUI elements, then perform the search void findAndReplace(bool backwards, bool replace); bool eventFilter(QObject *obj, QEvent *event); diff --git a/src/frontends/qt4/ui/FindAndReplaceUi.ui b/src/frontends/qt4/ui/FindAndReplaceUi.ui index 3a2cf46da9..af4010f074 100644 --- a/src/frontends/qt4/ui/FindAndReplaceUi.ui +++ b/src/frontends/qt4/ui/FindAndReplaceUi.ui @@ -64,6 +64,9 @@ 0 + + Qt::NoFocus + diff --git a/src/lyxfind.cpp b/src/lyxfind.cpp index 4e3dd9c17c..77b48cf8e0 100644 --- a/src/lyxfind.cpp +++ b/src/lyxfind.cpp @@ -936,146 +936,29 @@ int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match) } -/** 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(p_master->masterBuffer()); - LYXERR(Debug::FIND, "p_old=" << p_old << ", p_master=" << p_master); - } while (p_master != p_old); - LASSERT(p_master != NULL, /**/); - vector 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::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(p_master->masterBuffer()); - LYXERR(Debug::FIND, "p_old=" << p_old << ", p_master=" << p_master); - } while (p_master != p_old); - LASSERT(p_master != NULL, /**/); - vector 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::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) { @@ -1098,59 +981,38 @@ void findMostBackwards(DocIterator & cur, MatchStringAdv const & match, int & le 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 @@ -1158,35 +1020,16 @@ int findBackwardsAdv(DocIterator & cur, MatchStringAdv & match) { 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; } @@ -1278,10 +1121,6 @@ bool findAdv(BufferView * bv, FindAndReplaceOptions const & opt) bv->message(_("Search text is empty!")); return false; } -// if (! bv->buffer()) { -// bv->message(_("No open document !")); -// return false; -// } MatchStringAdv matchAdv(bv->buffer(), opt); try { @@ -1303,13 +1142,9 @@ bool findAdv(BufferView * bv, FindAndReplaceOptions const & opt) 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, @@ -1355,25 +1190,12 @@ bool findAdv(BufferView * bv, FindAndReplaceOptions const & opt) 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" diff --git a/src/lyxfind.h b/src/lyxfind.h index ff68b8ee64..7d660eed11 100644 --- a/src/lyxfind.h +++ b/src/lyxfind.h @@ -115,9 +115,6 @@ std::ostringstream & operator<<(std::ostringstream & os, lyx::FindAndReplaceOpti /// Read a FindAdvOptions instance from a stringstream std::istringstream & operator>>(std::istringstream & is, lyx::FindAndReplaceOptions & opt); -/// Dispatch a LFUN_WORD_FINDADV command request -void findAdv(BufferView * bv, FuncRequest const & ev); - /// Perform a FindAdv operation. bool findAdv(BufferView * bv, FindAndReplaceOptions const & opt); -- 2.39.2