From fdeb7620f1e7f33e5bb5749a28f84870c9af70ac Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 9 Sep 2011 16:10:57 +0200 Subject: [PATCH] Keep multiple search results in history. Change-Id: I7350c78479343e85b1ca4957e08bccefb5756d20 Reviewed-on: http://codereview.qt-project.org/4556 Reviewed-by: Qt Sanity Bot Reviewed-by: Leandro T. C. Melo --- src/plugins/cpptools/cppfindreferences.cpp | 31 ++-- src/plugins/cpptools/cppfindreferences.h | 2 +- src/plugins/cpptools/symbolsfindfilter.cpp | 11 +- src/plugins/cpptools/symbolsfindfilter.h | 3 +- src/plugins/find/searchresultwidget.cpp | 10 +- src/plugins/find/searchresultwidget.h | 1 - src/plugins/find/searchresultwindow.cpp | 193 ++++++++++++++++-------- src/plugins/find/searchresultwindow.h | 13 +- src/plugins/qmljseditor/qmljsfindreferences.cpp | 22 ++- src/plugins/qmljseditor/qmljsfindreferences.h | 3 +- src/plugins/texteditor/basefilefind.cpp | 17 ++- src/plugins/texteditor/basefilefind.h | 6 +- 12 files changed, 205 insertions(+), 107 deletions(-) diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp index 9bcd6fbea1..16e62d0f13 100644 --- a/src/plugins/cpptools/cppfindreferences.cpp +++ b/src/plugins/cpptools/cppfindreferences.cpp @@ -161,8 +161,7 @@ public: CppFindReferences::CppFindReferences(CppModelManagerInterface *modelManager) : QObject(modelManager), - _modelManager(modelManager), - m_currentSearch(0) + _modelManager(modelManager) { m_watcher.setPendingResultsLimit(1); connect(&m_watcher, SIGNAL(resultsReadyAt(int,int)), this, SLOT(displayResults(int,int))); @@ -227,9 +226,11 @@ static void find_helper(QFutureInterface &future, void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context) { - m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch(Find::SearchResultWindow::SearchOnly); Overview overview; - m_currentSearch->setInfo(tr("C++ Usages:"), QString(), overview(context.fullyQualifiedName(symbol))); + m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch(tr("C++ Usages:"), + QString(), + overview(context.fullyQualifiedName(symbol)), + Find::SearchResultWindow::SearchOnly); connect(m_currentSearch, SIGNAL(activated(Find::SearchResultItem)), this, SLOT(openEditor(Find::SearchResultItem))); @@ -243,10 +244,12 @@ void CppFindReferences::renameUsages(CPlusPlus::Symbol *symbol, const CPlusPlus: const QString textToReplace = replacement.isEmpty() ? QString::fromUtf8(id->chars(), id->size()) : replacement; - m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch( - Find::SearchResultWindow::SearchAndReplace, QLatin1String("CppEditor")); Overview overview; - m_currentSearch->setInfo(tr("C++ Usages:"), QString(), overview(context.fullyQualifiedName(symbol))); + m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch( + tr("C++ Usages:"), + QString(), + overview(context.fullyQualifiedName(symbol)), + Find::SearchResultWindow::SearchAndReplace, QLatin1String("CppEditor")); m_currentSearch->setTextToReplace(textToReplace); connect(m_currentSearch, SIGNAL(activated(Find::SearchResultItem)), @@ -293,6 +296,10 @@ void CppFindReferences::onReplaceButtonClicked(const QString &text, void CppFindReferences::displayResults(int first, int last) { + if (!m_currentSearch) { + m_watcher.cancel(); + return; + } for (int index = first; index != last; ++index) { Usage result = m_watcher.future().resultAt(index); m_currentSearch->addResult(result.path, @@ -305,7 +312,8 @@ void CppFindReferences::displayResults(int first, int last) void CppFindReferences::searchFinished() { - m_currentSearch->finishSearch(); + if (m_currentSearch) + m_currentSearch->finishSearch(); m_currentSearch = 0; emit changed(); } @@ -422,8 +430,11 @@ static void findMacroUses_helper(QFutureInterface &future, void CppFindReferences::findMacroUses(const Macro ¯o) { - m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch(Find::SearchResultWindow::SearchOnly); - m_currentSearch->setInfo(tr("C++ Macro Usages:"), QString(), QString::fromLocal8Bit(macro.name())); + m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch( + tr("C++ Macro Usages:"), + QString(), + macro.name(), + Find::SearchResultWindow::SearchOnly); Find::SearchResultWindow::instance()->popup(true); diff --git a/src/plugins/cpptools/cppfindreferences.h b/src/plugins/cpptools/cppfindreferences.h index 1071e0e6db..09b1828ee4 100644 --- a/src/plugins/cpptools/cppfindreferences.h +++ b/src/plugins/cpptools/cppfindreferences.h @@ -94,7 +94,7 @@ private: private: QPointer _modelManager; - Find::SearchResult *m_currentSearch; + QPointer m_currentSearch; QFutureWatcher m_watcher; mutable QMutex m_depsLock; diff --git a/src/plugins/cpptools/symbolsfindfilter.cpp b/src/plugins/cpptools/symbolsfindfilter.cpp index 3aecc1d6ff..bbb4e637b6 100644 --- a/src/plugins/cpptools/symbolsfindfilter.cpp +++ b/src/plugins/cpptools/symbolsfindfilter.cpp @@ -104,7 +104,6 @@ SymbolsFindFilter::SymbolsFindFilter(CppModelManager *manager) : m_manager(manager), m_isRunning(false), m_enabled(true), - m_currentSearch(0), m_symbolsToSearch(SearchSymbols::AllTypes), m_scope(SearchProjectsOnly) { @@ -150,8 +149,7 @@ void SymbolsFindFilter::findAll(const QString &txt, Find::FindFlags findFlags) m_isRunning = true; emit changed(); Find::SearchResultWindow *window = Find::SearchResultWindow::instance(); - m_currentSearch = window->startNewSearch(); - m_currentSearch->setInfo(label(), toolTip(findFlags), txt); + m_currentSearch = window->startNewSearch(label(), toolTip(findFlags), txt); connect(m_currentSearch, SIGNAL(activated(Find::SearchResultItem)), this, SLOT(openEditor(Find::SearchResultItem))); window->popup(true); @@ -177,6 +175,10 @@ void SymbolsFindFilter::findAll(const QString &txt, Find::FindFlags findFlags) void SymbolsFindFilter::addResults(int begin, int end) { + if (!m_currentSearch) { + m_watcher.cancel(); + return; + } QList items; for (int i = begin; i < end; ++i) items << m_watcher.resultAt(i); @@ -185,7 +187,8 @@ void SymbolsFindFilter::addResults(int begin, int end) void SymbolsFindFilter::finish() { - m_currentSearch->finishSearch(); + if (m_currentSearch) + m_currentSearch->finishSearch(); m_currentSearch = 0; m_isRunning = false; emit changed(); diff --git a/src/plugins/cpptools/symbolsfindfilter.h b/src/plugins/cpptools/symbolsfindfilter.h index 37ebf362ac..f0a241a7be 100644 --- a/src/plugins/cpptools/symbolsfindfilter.h +++ b/src/plugins/cpptools/symbolsfindfilter.h @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -97,7 +98,7 @@ private: bool m_isRunning; bool m_enabled; QFutureWatcher m_watcher; - Find::SearchResult *m_currentSearch; + QPointer m_currentSearch; SearchSymbols::SymbolTypes m_symbolsToSearch; SearchSymbols m_search; SearchScope m_scope; diff --git a/src/plugins/find/searchresultwidget.cpp b/src/plugins/find/searchresultwidget.cpp index f06e28141c..13d9d59282 100644 --- a/src/plugins/find/searchresultwidget.cpp +++ b/src/plugins/find/searchresultwidget.cpp @@ -254,7 +254,6 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) : m_cancelButton->setText(tr("Cancel")); m_cancelButton->setToolButtonStyle(Qt::ToolButtonTextOnly); connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(cancel())); - m_cancelButton->setVisible(false); m_replaceLabel = new QLabel(tr("Replace with:"), topWidget); m_replaceTextEdit = new WideEnoughLineEdit(topWidget); @@ -285,11 +284,6 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) : connect(m_replaceButton, SIGNAL(clicked()), this, SLOT(handleReplaceButton())); } -void SearchResultWidget::startSearch() -{ - m_cancelButton->setVisible(true); -} - void SearchResultWidget::setInfo(const QString &label, const QString &toolTip, const QString &term) { m_label->setText(label); @@ -319,7 +313,7 @@ void SearchResultWidget::addResults(const QList &items, Search m_count += items.size(); m_searchResultTreeView->addResults(items, mode); if (firstItems) { - if (!m_dontAskAgainGroup.isEmpty() && showWarningMessage()) { + if (showWarningMessage()) { Core::InfoBarEntry info("warninglabel", tr("This change cannot be undone.")); info.setCustomButtonInfo(tr("Do not warn again"), this, SLOT(hideNoUndoWarning())); m_infoBar.addInfo(info); @@ -497,6 +491,8 @@ void SearchResultWidget::cancel() bool SearchResultWidget::showWarningMessage() const { + if (m_dontAskAgainGroup.isEmpty()) + return false; // read settings QSettings *settings = Core::ICore::instance()->settings(); settings->beginGroup(m_dontAskAgainGroup); diff --git a/src/plugins/find/searchresultwidget.h b/src/plugins/find/searchresultwidget.h index ed5543c912..a43b0b2c68 100644 --- a/src/plugins/find/searchresultwidget.h +++ b/src/plugins/find/searchresultwidget.h @@ -53,7 +53,6 @@ class SearchResultWidget : public QWidget public: explicit SearchResultWidget(QWidget *parent = 0); - void startSearch(); void setInfo(const QString &label, const QString &toolTip, const QString &term); void addResult(const QString &fileName, int lineNumber, const QString &lineText, diff --git a/src/plugins/find/searchresultwindow.cpp b/src/plugins/find/searchresultwindow.cpp index 28e1c4374e..7692152ce8 100644 --- a/src/plugins/find/searchresultwindow.cpp +++ b/src/plugins/find/searchresultwindow.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include static const char SETTINGSKEYSECTIONNAME[] = "SearchResults"; @@ -56,20 +57,59 @@ namespace Find { namespace Internal { - struct SearchResultWindowPrivate { - SearchResultWindowPrivate(); + class SearchResultWindowPrivate : public QObject { + Q_OBJECT + public: + SearchResultWindowPrivate(SearchResultWindow *window); + bool isSearchVisible() const; + int visibleSearchIndex() const; - Internal::SearchResultWidget *m_searchResultWidget; + SearchResultWindow *q; + QList m_searchResultWidgets; QToolButton *m_expandCollapseButton; QAction *m_expandCollapseAction; static const bool m_initiallyExpand = false; + QWidget *m_spacer; + QComboBox *m_recentSearchesBox; QStackedWidget *m_widget; - SearchResult *m_currentSearch; + QList m_searchResults; + int m_currentIndex; + + public slots: + void setCurrentIndex(int index); }; - SearchResultWindowPrivate::SearchResultWindowPrivate() - : m_currentSearch(0) + SearchResultWindowPrivate::SearchResultWindowPrivate(SearchResultWindow *window) + : q(window) + { + } + + bool SearchResultWindowPrivate::isSearchVisible() const + { + return m_currentIndex > 0; + } + + int SearchResultWindowPrivate::visibleSearchIndex() const { + return m_currentIndex - 1; + } + + void SearchResultWindowPrivate::setCurrentIndex(int index) + { + if (isSearchVisible()) + m_searchResultWidgets.at(visibleSearchIndex())->notifyVisibilityChanged(false); + m_currentIndex = index; + m_widget->setCurrentIndex(index); + m_recentSearchesBox->setCurrentIndex(index); + if (!isSearchVisible()) { + m_widget->currentWidget()->setFocus(); + m_expandCollapseButton->setEnabled(false); + } else { + m_searchResultWidgets.at(visibleSearchIndex())->setFocusInternally(); + m_searchResultWidgets.at(visibleSearchIndex())->notifyVisibilityChanged(true); + m_expandCollapseButton->setEnabled(true); + } + q->navigateStateChanged(); } } @@ -155,16 +195,21 @@ SearchResultWindow *SearchResultWindow::m_instance = 0; \internal */ SearchResultWindow::SearchResultWindow(QWidget *newSearchPanel) - : d(new SearchResultWindowPrivate) + : d(new SearchResultWindowPrivate(this)) { m_instance = this; + d->m_spacer = new QWidget; + d->m_spacer->setMinimumWidth(30); + d->m_recentSearchesBox = new QComboBox; + d->m_recentSearchesBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + d->m_recentSearchesBox->addItem(tr("New Search")); + connect(d->m_recentSearchesBox, SIGNAL(activated(int)), d, SLOT(setCurrentIndex(int))); + d->m_widget = new QStackedWidget; d->m_widget->setWindowTitle(displayName()); d->m_widget->addWidget(newSearchPanel); - - d->m_searchResultWidget = new Internal::SearchResultWidget(d->m_widget); - d->m_widget->addWidget(d->m_searchResultWidget); + d->m_currentIndex = 0; d->m_expandCollapseButton = new QToolButton(d->m_widget); d->m_expandCollapseButton->setAutoRaise(true); @@ -179,7 +224,6 @@ SearchResultWindow::SearchResultWindow(QWidget *newSearchPanel) d->m_expandCollapseButton->setDefaultAction(cmd->action()); connect(d->m_expandCollapseAction, SIGNAL(toggled(bool)), this, SLOT(handleExpandCollapseToolButton(bool))); - connect(d->m_searchResultWidget, SIGNAL(navigateStateChanged()), this, SLOT(navigateStateChanged())); readSettings(); } @@ -190,8 +234,7 @@ SearchResultWindow::SearchResultWindow(QWidget *newSearchPanel) SearchResultWindow::~SearchResultWindow() { writeSettings(); - delete d->m_currentSearch; - d->m_currentSearch = 0; + qDeleteAll(d->m_searchResults); delete d->m_widget; d->m_widget = 0; delete d; @@ -212,7 +255,8 @@ SearchResultWindow *SearchResultWindow::instance() */ void SearchResultWindow::visibilityChanged(bool visible) { - d->m_searchResultWidget->notifyVisibilityChanged(visible); + if (d->isSearchVisible()) + d->m_searchResultWidgets.at(d->visibleSearchIndex())->notifyVisibilityChanged(visible); } /*! @@ -230,31 +274,56 @@ QWidget *SearchResultWindow::outputWidget(QWidget *) */ QList SearchResultWindow::toolBarWidgets() const { - return QList() << d->m_expandCollapseButton; + return QList() << d->m_expandCollapseButton << d->m_spacer << d->m_recentSearchesBox; } /*! \brief Tells the search results window to start a new search. - This will clear the contents of the previous search and initialize the UI - with regard to showing the replace UI or not (depending on the search mode - in \a searchOrSearchAndReplace). + The \a label should be a string that shortly describes the type of + search, i.e. search filter and possibly a most relevant search option, followed by a colon ':'. + E.g. \code{Project 'myproject':} + The \a searchTerm will be shown behind the colon. + The \a toolTip should elaborate on the search parameters, like file patterns that are searched and + find flags. If \a cfgGroup is not empty, it will be used for storing the "do not ask again" setting of a "this change cannot be undone" warning (which is implicitly requested by passing a non-empty group). Returns a SearchResult object that is used for signaling user interaction with the results of this search. + The search result window owns the returned SearchResult + and might delete it any time, even while the search is running + (e.g. when the user clears the search result pane, or if the user opens so many other searches + that this search falls out of the history). + */ -SearchResult *SearchResultWindow::startNewSearch(SearchMode searchOrSearchAndReplace, const QString &cfgGroup) +SearchResult *SearchResultWindow::startNewSearch(const QString &label, + const QString &toolTip, + const QString &searchTerm, + SearchMode searchOrSearchAndReplace, + const QString &cfgGroup) { - clearContents(); - d->m_searchResultWidget->setShowReplaceUI(searchOrSearchAndReplace != SearchOnly); - d->m_searchResultWidget->setDontAskAgainGroup(cfgGroup); - d->m_searchResultWidget->startSearch(); - d->m_widget->setCurrentWidget(d->m_searchResultWidget); - delete d->m_currentSearch; - d->m_currentSearch = new SearchResult(d->m_searchResultWidget); - return d->m_currentSearch; + if (d->m_searchResults.size() >= 5) { + d->m_searchResultWidgets.last()->notifyVisibilityChanged(false); + delete d->m_searchResults.takeLast(); + delete d->m_searchResultWidgets.takeLast(); + d->m_recentSearchesBox->removeItem(d->m_recentSearchesBox->count()-1); + } + Internal::SearchResultWidget *widget = new Internal::SearchResultWidget; + d->m_searchResultWidgets.prepend(widget); + d->m_widget->insertWidget(1, widget); + connect(widget, SIGNAL(navigateStateChanged()), this, SLOT(navigateStateChanged())); + widget->setShowReplaceUI(searchOrSearchAndReplace != SearchOnly); + widget->setInfo(label, toolTip, searchTerm); + if (searchOrSearchAndReplace == SearchAndReplace) + widget->setDontAskAgainGroup(cfgGroup); + SearchResult *result = new SearchResult(widget); + d->m_searchResults.prepend(result); + d->m_recentSearchesBox->insertItem(1, tr("%1 %2").arg(label, searchTerm)); + if (d->m_currentIndex > 0) + ++d->m_currentIndex; // so setCurrentIndex still knows about the right "currentIndex" and its widget + d->setCurrentIndex(1); + return result; } /*! @@ -263,7 +332,18 @@ SearchResult *SearchResultWindow::startNewSearch(SearchMode searchOrSearchAndRep */ void SearchResultWindow::clearContents() { - d->m_searchResultWidget->clear(); + for (int i = d->m_recentSearchesBox->count() - 1; i > 0 /* don't want i==0 */; --i) + d->m_recentSearchesBox->removeItem(i); + foreach (Internal::SearchResultWidget *widget, d->m_searchResultWidgets) + widget->notifyVisibilityChanged(false); + qDeleteAll(d->m_searchResultWidgets); + d->m_searchResultWidgets.clear(); + qDeleteAll(d->m_searchResults); + d->m_searchResults.clear(); + + d->m_currentIndex = 0; + d->m_widget->currentWidget()->setFocus(); + d->m_expandCollapseButton->setEnabled(false); navigateStateChanged(); } @@ -273,7 +353,7 @@ void SearchResultWindow::clearContents() */ bool SearchResultWindow::hasFocus() { - return d->m_searchResultWidget->hasFocusInternally(); + return d->m_widget->focusWidget() && d->m_widget->focusWidget()->hasFocus(); } /*! @@ -282,7 +362,9 @@ bool SearchResultWindow::hasFocus() */ bool SearchResultWindow::canFocus() { - return d->m_searchResultWidget->canFocusInternally(); + if (d->isSearchVisible()) + return d->m_searchResultWidgets.at(d->visibleSearchIndex())->canFocusInternally(); + return true; } /*! @@ -291,11 +373,10 @@ bool SearchResultWindow::canFocus() */ void SearchResultWindow::setFocus() { - int stackIndex = d->m_widget->currentIndex(); - if (stackIndex == 0) + if (!d->isSearchVisible()) d->m_widget->currentWidget()->setFocus(); else - d->m_searchResultWidget->setFocusInternally(); + d->m_searchResultWidgets.at(d->visibleSearchIndex())->setFocusInternally(); } /*! @@ -304,12 +385,13 @@ void SearchResultWindow::setFocus() */ void SearchResultWindow::setTextEditorFont(const QFont &font) { - d->m_searchResultWidget->setTextEditorFont(font); + foreach (Internal::SearchResultWidget *widget, d->m_searchResultWidgets) + widget->setTextEditorFont(font); } void SearchResultWindow::openNewSearchPanel() { - d->m_widget->setCurrentIndex(0); + d->setCurrentIndex(0); popup(); } @@ -319,13 +401,15 @@ void SearchResultWindow::openNewSearchPanel() */ void SearchResultWindow::handleExpandCollapseToolButton(bool checked) { - d->m_searchResultWidget->setAutoExpandResults(checked); + if (!d->isSearchVisible()) + return; + d->m_searchResultWidgets.at(d->visibleSearchIndex())->setAutoExpandResults(checked); if (checked) { d->m_expandCollapseAction->setText(tr("Collapse All")); - d->m_searchResultWidget->expandAll(); + d->m_searchResultWidgets.at(d->visibleSearchIndex())->expandAll(); } else { d->m_expandCollapseAction->setText(tr("Expand All")); - d->m_searchResultWidget->collapseAll(); + d->m_searchResultWidgets.at(d->visibleSearchIndex())->collapseAll(); } } @@ -372,7 +456,9 @@ int SearchResultWindow::priorityInStatusBar() const */ bool SearchResultWindow::canNext() { - return d->m_searchResultWidget->count() > 0; + if (d->isSearchVisible()) + return d->m_searchResultWidgets.at(d->visibleSearchIndex())->count() > 0; + return false; } /*! @@ -381,7 +467,7 @@ bool SearchResultWindow::canNext() */ bool SearchResultWindow::canPrevious() { - return d->m_searchResultWidget->count() > 0; + return canNext(); } /*! @@ -390,7 +476,9 @@ bool SearchResultWindow::canPrevious() */ void SearchResultWindow::goToNext() { - d->m_searchResultWidget->goToNext(); + int index = d->m_widget->currentIndex(); + if (index != 0) + d->m_searchResultWidgets.at(index-1)->goToNext(); } /*! @@ -399,7 +487,9 @@ void SearchResultWindow::goToNext() */ void SearchResultWindow::goToPrev() { - d->m_searchResultWidget->goToPrevious(); + int index = d->m_widget->currentIndex(); + if (index != 0) + d->m_searchResultWidgets.at(index-1)->goToPrevious(); } /*! @@ -460,23 +550,6 @@ QString SearchResult::textToReplace() const } /*! - \fn void SearchResult::setInfo(const QString &label, const QString &toolTip, const QString &term) - \brief Set the information about the search that is show in the top-left corner of - the search result window. - - The \a label should be a string that shortly describes the - search, i.e. search filter and a most relevant search options, followed by a colon ':'. - E.g. \code{Project 'myproject':} - The search \a term will be shown behind the colon. - The \a toolTip should elaborate on the search parameters, like file patterns that are searched and - find flags. -*/ -void SearchResult::setInfo(const QString &label, const QString &toolTip, const QString &term) -{ - m_widget->setInfo(label, toolTip, term); -} - -/*! \fn void SearchResult::addResult(const QString &fileName, int lineNumber, const QString &rowText, int searchTermStart, int searchTermLength, const QVariant &userData) \brief Adds a single result line to the search results. @@ -528,3 +601,5 @@ void SearchResult::setTextToReplace(const QString &textToReplace) } } // namespace Find + +#include "searchresultwindow.moc" diff --git a/src/plugins/find/searchresultwindow.h b/src/plugins/find/searchresultwindow.h index 24f25eae8e..0d09575a66 100644 --- a/src/plugins/find/searchresultwindow.h +++ b/src/plugins/find/searchresultwindow.h @@ -48,7 +48,7 @@ QT_END_NAMESPACE namespace Find { namespace Internal { class SearchResultTreeView; - struct SearchResultWindowPrivate; + class SearchResultWindowPrivate; class SearchResultWidget; } class SearchResultWindow; @@ -98,7 +98,6 @@ public: void setUserData(const QVariant &data); QVariant userData() const; QString textToReplace() const; - void setInfo(const QString &label, const QString &toolTip, const QString &term); public slots: void addResult(const QString &fileName, int lineNumber, const QString &lineText, @@ -156,8 +155,14 @@ public: void setTextEditorFont(const QFont &font); void openNewSearchPanel(); - // search result object is guaranteed to live till its finishSearch method is called - SearchResult *startNewSearch(SearchMode searchOrSearchAndReplace = SearchOnly, + // The search result window owns the returned SearchResult + // and might delete it any time, even while the search is running + // (e.g. when the user clears the search result pane, or if the user opens so many other searches + // that this search falls out of the history). + SearchResult *startNewSearch(const QString &label, + const QString &toolTip, + const QString &searchTerm, + SearchMode searchOrSearchAndReplace = SearchOnly, const QString &cfgGroup = QString()); public slots: diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index 79a7a70bd2..716e448bc4 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -776,8 +776,7 @@ public: } // end of anonymous namespace FindReferences::FindReferences(QObject *parent) - : QObject(parent), - m_currentSearch(0) + : QObject(parent) { m_watcher.setPendingResultsLimit(1); connect(&m_watcher, SIGNAL(resultsReadyAt(int,int)), this, SLOT(displayResults(int,int))); @@ -914,18 +913,20 @@ void FindReferences::displayResults(int first, int last) // the first usage is always a dummy to indicate we now start searching if (first == 0) { Usage dummy = m_watcher.future().resultAt(0); - QString replacement = dummy.path; - QString symbolName = dummy.lineText; + const QString replacement = dummy.path; + const QString symbolName = dummy.lineText; + const QString label = tr("QML/JS Usages:"); if (replacement.isEmpty()) { - m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch(Find::SearchResultWindow::SearchOnly); + m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch( + label, QString(), symbolName, Find::SearchResultWindow::SearchOnly); } else { - m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch(Find::SearchResultWindow::SearchAndReplace); + m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch( + label, QString(), symbolName, Find::SearchResultWindow::SearchAndReplace); m_currentSearch->setTextToReplace(replacement); connect(m_currentSearch, SIGNAL(replaceButtonClicked(QString,QList)), SLOT(onReplaceButtonClicked(QString,QList))); } - m_currentSearch->setInfo(tr("Usages:"), QString(), symbolName); connect(m_currentSearch, SIGNAL(activated(Find::SearchResultItem)), this, SLOT(openEditor(Find::SearchResultItem))); connect(m_currentSearch, SIGNAL(cancelled()), this, SLOT(cancel())); @@ -940,6 +941,10 @@ void FindReferences::displayResults(int first, int last) ++first; } + if (!m_currentSearch) { + m_watcher.cancel(); + return; + } for (int index = first; index != last; ++index) { Usage result = m_watcher.future().resultAt(index); m_currentSearch->addResult(result.path, @@ -952,7 +957,8 @@ void FindReferences::displayResults(int first, int last) void FindReferences::searchFinished() { - m_currentSearch->finishSearch(); + if (m_currentSearch) + m_currentSearch->finishSearch(); m_currentSearch = 0; emit changed(); } diff --git a/src/plugins/qmljseditor/qmljsfindreferences.h b/src/plugins/qmljseditor/qmljsfindreferences.h index db6e548d27..a8c7de639a 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.h +++ b/src/plugins/qmljseditor/qmljsfindreferences.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -90,7 +91,7 @@ private Q_SLOTS: void onReplaceButtonClicked(const QString &text, const QList &items); private: - Find::SearchResult *m_currentSearch; + QPointer m_currentSearch; QFutureWatcher m_watcher; }; diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp index 105fa8f8f9..c910c07bd7 100644 --- a/src/plugins/texteditor/basefilefind.cpp +++ b/src/plugins/texteditor/basefilefind.cpp @@ -113,14 +113,10 @@ void BaseFileFind::runNewSearch(const QString &txt, Find::FindFlags findFlags, updateComboEntries(m_filterCombo, true); m_watcher.setFuture(QFuture()); m_currentSearchCount = 0; - m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch(searchMode, - searchMode == SearchResultWindow::SearchAndReplace - ? QString::fromLatin1("TextEditor") - : QString()); + m_currentSearch = Find::SearchResultWindow::instance()->startNewSearch(label(), + toolTip().arg(Find::IFindFilter::descriptionForFindFlags(findFlags)), + txt, searchMode, QString::fromLatin1("TextEditor")); m_currentSearch->setTextToReplace(txt); - m_currentSearch->setInfo(label(), - toolTip().arg(Find::IFindFilter::descriptionForFindFlags(findFlags)), - txt); QVariantList searchParameters; searchParameters << qVariantFromValue(txt) << qVariantFromValue(findFlags); m_currentSearch->setUserData(searchParameters); @@ -169,6 +165,10 @@ void BaseFileFind::doReplace(const QString &text, } void BaseFileFind::displayResult(int index) { + if (!m_currentSearch) { + m_watcher.cancel(); + return; + } Utils::FileSearchResultList results = m_watcher.future().resultAt(index); QList items; foreach (const Utils::FileSearchResult &result, results) { @@ -190,7 +190,8 @@ void BaseFileFind::displayResult(int index) { void BaseFileFind::searchFinished() { - m_currentSearch->finishSearch(); + if (m_currentSearch) + m_currentSearch->finishSearch(); m_currentSearch = 0; m_isSearching = false; m_resultLabel = 0; diff --git a/src/plugins/texteditor/basefilefind.h b/src/plugins/texteditor/basefilefind.h index 6f757b1003..d3505d0da4 100644 --- a/src/plugins/texteditor/basefilefind.h +++ b/src/plugins/texteditor/basefilefind.h @@ -78,8 +78,8 @@ public: protected: virtual Utils::FileIterator *files() const = 0; - virtual QString label() const = 0; // see Find::SearchResult::setInfo - virtual QString toolTip() const = 0; // see Find::SearchResult::setInfo, + virtual QString label() const = 0; // see Find::SearchResultWindow::startNewSearch + virtual QString toolTip() const = 0; // see Find::SearchResultWindow::startNewSearch, // add %1 placeholder where the find flags should be put void writeCommonSettings(QSettings *settings); @@ -103,7 +103,7 @@ private: void runNewSearch(const QString &txt, Find::FindFlags findFlags, Find::SearchResultWindow::SearchMode searchMode); - Find::SearchResult *m_currentSearch; + QPointer m_currentSearch; int m_currentSearchCount; QFutureWatcher m_watcher; -- 2.11.0