diff --git a/src/frontends/Application.h b/src/frontends/Application.h index c12d8a938d..0bba5cea55 100644 --- a/src/frontends/Application.h +++ b/src/frontends/Application.h @@ -239,6 +239,14 @@ public: /// Handle a accented char key sequence /// FIXME: this is only needed for LFUN_ACCENT_* in Text::dispatch() virtual void handleKeyFunc(FuncCode action) = 0; + + /// Start a long operation with some cancel possibility (button or ESC) + virtual void startLongOperation() = 0; + /// This needs to be periodically called to avoid freezing the GUI + virtual bool longOperationCancelled() = 0; + /// Stop the long operation mode (i.e., release the GUI) + virtual void stopLongOperation() = 0; + }; /// Return the list of loadable formats. diff --git a/src/frontends/qt4/FindAndReplace.cpp b/src/frontends/qt4/FindAndReplace.cpp index 1d2a81d4f6..82844bcbf9 100644 --- a/src/frontends/qt4/FindAndReplace.cpp +++ b/src/frontends/qt4/FindAndReplace.cpp @@ -294,6 +294,8 @@ bool FindAndReplaceWidget::findAndReplaceScope(FindAndReplaceOptions & opt, bool oss << opt; FuncRequest cmd(LFUN_WORD_FINDADV, from_utf8(oss.str())); + view_.message(_("Advanced search started: please wait . . .")); + theApp()->startLongOperation(); view_.setBusy(true); if (opt.scope == FindAndReplaceOptions::S_ALL_MANUALS) { vector const & v = allManualsFiles(); @@ -301,7 +303,9 @@ bool FindAndReplaceWidget::findAndReplaceScope(FindAndReplaceOptions & opt, bool FileName const & fname = FileName(*v.begin()); if (!theBufferList().exists(fname)) { guiApp->currentView()->setBusy(false); + theApp()->stopLongOperation(); guiApp->currentView()->loadDocument(fname, false); + theApp()->startLongOperation(); guiApp->currentView()->setBusy(true); } buf = theBufferList().getBuffer(fname); @@ -327,10 +331,19 @@ bool FindAndReplaceWidget::findAndReplaceScope(FindAndReplaceOptions & opt, bool if (replace_all) continue; view_.setBusy(false); + theApp()->stopLongOperation(); return true; } else if (replace_all) bv->clearSelection(); + if (theApp()->longOperationCancelled()) { + // Search aborted by user + view_.message(_("Advanced search cancelled by user")); + view_.setBusy(false); + theApp()->stopLongOperation(); + return false; + } + // No match found in current buffer (however old selection might have been replaced) // select next buffer in scope, if any bool const prompt = nextPrevBuffer(buf, opt); @@ -341,9 +354,11 @@ bool FindAndReplaceWidget::findAndReplaceScope(FindAndReplaceOptions & opt, bool break; docstring q = getQuestionString(opt); view_.setBusy(false); + theApp()->stopLongOperation(); wrap_answer = frontend::Alert::prompt( _("Wrap search?"), q, 0, 1, _("&Yes"), _("&No")); + theApp()->startLongOperation(); view_.setBusy(true); if (wrap_answer == 1) break; @@ -373,6 +388,7 @@ bool FindAndReplaceWidget::findAndReplaceScope(FindAndReplaceOptions & opt, bool cur_orig.pos() = cur_orig.lastpos(); bv->cursor().setCursor(cur_orig); view_.setBusy(false); + theApp()->stopLongOperation(); return false; } diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp index a49a995210..0f6c38fb83 100644 --- a/src/frontends/qt4/GuiApplication.cpp +++ b/src/frontends/qt4/GuiApplication.cpp @@ -80,12 +80,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -98,6 +100,7 @@ #include #include #include +#include #include #include #include @@ -675,6 +678,43 @@ public: #endif // Q_WS_WIN + +/// Allows to check whether ESC was pressed during a long operation +class KeyChecker : public QObject { +private: + bool pressed_; +public: + KeyChecker() { + pressed_ = false; + } + void start() { + QCoreApplication::instance()->installEventFilter(this); + pressed_ = false; + } + void stop() { + QCoreApplication::instance()->removeEventFilter(this); + } + bool pressed() { + QCoreApplication::processEvents(); + return pressed_; + } + bool eventFilter(QObject *obj, QEvent *event) { + LYXERR(Debug::ACTION, "Event Type: " << event->type()); + switch (event->type()) { + case QEvent::Show: + case QEvent::Hide: + case QEvent::Resize: + return QObject::eventFilter(obj, event); + default: + QKeyEvent *keyEvent = dynamic_cast(event); + if (keyEvent && keyEvent->key() == Qt::Key_Escape) + pressed_ = true; + return true; + } + } +}; + + //////////////////////////////////////////////////////////////////////// // GuiApplication::Private definition and implementation. //////////////////////////////////////////////////////////////////////// @@ -752,6 +792,9 @@ struct GuiApplication::Private /// WMF Mime handler for Windows clipboard. QWindowsMimeMetafile * wmf_mime_; #endif + + /// Allows to check whether ESC was pressed during a long operation + KeyChecker key_checker_; }; @@ -2529,6 +2572,21 @@ void GuiApplication::onLastWindowClosed() } +void GuiApplication::startLongOperation() { + d->key_checker_.start(); +} + + +bool GuiApplication::longOperationCancelled() { + return d->key_checker_.pressed(); +} + + +void GuiApplication::stopLongOperation() { + d->key_checker_.stop(); +} + + //////////////////////////////////////////////////////////////////////// // // X11 specific stuff goes here... diff --git a/src/frontends/qt4/GuiApplication.h b/src/frontends/qt4/GuiApplication.h index d1a10784b8..b4c7615749 100644 --- a/src/frontends/qt4/GuiApplication.h +++ b/src/frontends/qt4/GuiApplication.h @@ -169,6 +169,13 @@ public: /// not the current buffer void gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer); + /// Start a long operation with some cancel possibility (button or ESC) + void startLongOperation(); + /// This needs to be periodically called to avoid freezing the GUI + bool longOperationCancelled(); + /// Stop the long operation mode (i.e., release the GUI) + void stopLongOperation(); + private Q_SLOTS: /// void execBatchCommands(); diff --git a/src/lyxfind.cpp b/src/lyxfind.cpp index b67f915d7c..f90e530d82 100644 --- a/src/lyxfind.cpp +++ b/src/lyxfind.cpp @@ -1133,12 +1133,12 @@ int findForwardAdv(DocIterator & cur, MatchStringAdv & match) { if (!cur) return 0; - while (cur) { + while (!theApp()->longOperationCancelled() && cur) { LYXERR(Debug::FIND, "findForwardAdv() cur: " << cur); int match_len = match(cur, -1, false); LYXERR(Debug::FIND, "match_len: " << match_len); if (match_len) { - for (; cur; cur.forwardPos()) { + for (; !theApp()->longOperationCancelled() && cur; cur.forwardPos()) { LYXERR(Debug::FIND, "Advancing cur: " << cur); int match_len = match(cur); LYXERR(Debug::FIND, "match_len: " << match_len); @@ -1235,7 +1235,7 @@ int findBackwardsAdv(DocIterator & cur, MatchStringAdv & match) { else cur.backwardPos(); pit_changed = true; - } while (true); + } while (!theApp()->longOperationCancelled()); return 0; }