diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index 37f152fe58a..c14bb541bef 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -80,8 +80,9 @@ #include #include #include -#include +#include #include +#include #include #include @@ -93,6 +94,7 @@ #include #include #include +#include enum { UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL = 200 }; @@ -176,9 +178,11 @@ void CppEditorWidget::finalizeInitialization() &CppLocalRenaming::updateSelectionsForVariableUnderCursor); connect(&d->m_useSelectionsUpdater, &CppUseSelectionsUpdater::finished, this, - [this] (SemanticInfo::LocalUseMap localUses) { - d->m_lastSemanticInfo.localUsesUpdated = true; - d->m_lastSemanticInfo.localUses = localUses; + [this] (SemanticInfo::LocalUseMap localUses, bool success) { + if (success) { + d->m_lastSemanticInfo.localUsesUpdated = true; + d->m_lastSemanticInfo.localUses = localUses; + } }); connect(document(), &QTextDocument::contentsChange, @@ -750,6 +754,20 @@ static void addRefactoringActions(QMenu *menu, AssistInterface *iface) } } +class ProgressIndicatorMenuItem : public QWidgetAction +{ + Q_OBJECT + +public: + ProgressIndicatorMenuItem(QObject *parent) : QWidgetAction(parent) {} + +protected: + QWidget *createWidget(QWidget *parent = nullptr) override + { + return new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Small, parent); + } +}; + QMenu *CppEditorWidget::createRefactorMenu(QWidget *parent) const { auto *menu = new QMenu(tr("&Refactor"), parent); @@ -759,8 +777,30 @@ QMenu *CppEditorWidget::createRefactorMenu(QWidget *parent) const // updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource())); if (isSemanticInfoValidExceptLocalUses()) { - d->m_useSelectionsUpdater.update(CppUseSelectionsUpdater::CallType::Synchronous); - addRefactoringActions(menu, createAssistInterface(QuickFix, ExplicitlyInvoked)); + d->m_useSelectionsUpdater.abortSchedule(); + + const CppUseSelectionsUpdater::RunnerInfo runnerInfo = d->m_useSelectionsUpdater.update(); + switch (runnerInfo) { + case CppUseSelectionsUpdater::RunnerInfo::AlreadyUpToDate: + addRefactoringActions(menu, createAssistInterface(QuickFix, ExplicitlyInvoked)); + break; + case CppUseSelectionsUpdater::RunnerInfo::Started: { + // Update the refactor menu once we get the results. + auto *progressIndicatorMenuItem = new ProgressIndicatorMenuItem(menu); + menu->addAction(progressIndicatorMenuItem); + + connect(&d->m_useSelectionsUpdater, &CppUseSelectionsUpdater::finished, + menu, [=] (SemanticInfo::LocalUseMap, bool success) { + QTC_CHECK(success); + menu->removeAction(progressIndicatorMenuItem); + addRefactoringActions(menu, createAssistInterface(QuickFix, ExplicitlyInvoked)); + }); + break; + } + case CppUseSelectionsUpdater::RunnerInfo::FailedToStart: + case CppUseSelectionsUpdater::RunnerInfo::Invalid: + QTC_CHECK(false && "Unexpected CppUseSelectionsUpdater runner result"); + } } return menu; @@ -1041,3 +1081,5 @@ void CppEditorWidget::invokeTextEditorWidgetAssist(TextEditor::AssistKind assist } // namespace Internal } // namespace CppEditor + +#include "cppeditorwidget.moc" diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.cpp b/src/plugins/cppeditor/cppuseselectionsupdater.cpp index 5b8d1d27dfe..da7a7a1d92a 100644 --- a/src/plugins/cppeditor/cppuseselectionsupdater.cpp +++ b/src/plugins/cppeditor/cppuseselectionsupdater.cpp @@ -66,13 +66,13 @@ void CppUseSelectionsUpdater::abortSchedule() m_timer.stop(); } -void CppUseSelectionsUpdater::update(CallType callType) +CppUseSelectionsUpdater::RunnerInfo CppUseSelectionsUpdater::update(CallType callType) { auto *cppEditorWidget = qobject_cast(m_editorWidget); - QTC_ASSERT(cppEditorWidget, return); + QTC_ASSERT(cppEditorWidget, return RunnerInfo::FailedToStart); auto *cppEditorDocument = qobject_cast(cppEditorWidget->textDocument()); - QTC_ASSERT(cppEditorDocument, return); + QTC_ASSERT(cppEditorDocument, return RunnerInfo::FailedToStart); CppTools::CursorInfoParams params; params.semanticInfo = cppEditorWidget->semanticInfo(); @@ -80,7 +80,7 @@ void CppUseSelectionsUpdater::update(CallType callType) if (callType == CallType::Asynchronous) { if (isSameIdentifierAsBefore(params.textCursor)) - return; + return RunnerInfo::AlreadyUpToDate; if (m_runnerWatcher) m_runnerWatcher->cancel(); @@ -93,25 +93,28 @@ void CppUseSelectionsUpdater::update(CallType callType) m_runnerWordStartPosition = params.textCursor.position(); m_runnerWatcher->setFuture(cppEditorDocument->cursorInfo(params)); + return RunnerInfo::Started; } else { // synchronous case abortSchedule(); const int startRevision = cppEditorDocument->document()->revision(); QFuture future = cppEditorDocument->cursorInfo(params); if (future.isCanceled()) - return; + return RunnerInfo::Invalid; // QFuture::waitForFinished seems to block completely, not even // allowing to process events from QLocalSocket. while (!future.isFinished()) { if (future.isCanceled()) - return; + return RunnerInfo::Invalid; - QTC_ASSERT(startRevision == cppEditorDocument->document()->revision(), return); + QTC_ASSERT(startRevision == cppEditorDocument->document()->revision(), + return RunnerInfo::Invalid); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } processResults(future.result()); + return RunnerInfo::Invalid; } } @@ -134,18 +137,25 @@ void CppUseSelectionsUpdater::processResults(const CursorInfo &result) updateUnusedSelections(result.unusedVariablesRanges); emit selectionsForVariableUnderCursorUpdated(localVariableSelections); - emit finished(result.localUses); + emit finished(result.localUses, true); } void CppUseSelectionsUpdater::onFindUsesFinished() { - QTC_ASSERT(m_runnerWatcher, return); - if (m_runnerWatcher->isCanceled()) + QTC_ASSERT(m_runnerWatcher, + emit finished(CppTools::SemanticInfo::LocalUseMap(), false); return); + + if (m_runnerWatcher->isCanceled()) { + emit finished(CppTools::SemanticInfo::LocalUseMap(), false); return; - if (m_runnerRevision != m_editorWidget->document()->revision()) + } + if (m_runnerRevision != m_editorWidget->document()->revision()) { + emit finished(CppTools::SemanticInfo::LocalUseMap(), false); return; + } if (m_runnerWordStartPosition != Utils::Text::wordStartCursor(m_editorWidget->textCursor()).position()) { + emit finished(CppTools::SemanticInfo::LocalUseMap(), false); return; } diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.h b/src/plugins/cppeditor/cppuseselectionsupdater.h index 7e10eeb680c..ec18b222f45 100644 --- a/src/plugins/cppeditor/cppuseselectionsupdater.h +++ b/src/plugins/cppeditor/cppuseselectionsupdater.h @@ -50,10 +50,11 @@ public: void abortSchedule(); enum class CallType { Synchronous, Asynchronous }; - void update(CallType callType = CallType::Asynchronous); + enum class RunnerInfo { AlreadyUpToDate, Started, FailedToStart, Invalid }; // For async case. + RunnerInfo update(CallType callType = CallType::Asynchronous); signals: - void finished(CppTools::SemanticInfo::LocalUseMap localUses); + void finished(CppTools::SemanticInfo::LocalUseMap localUses, bool success); void selectionsForVariableUnderCursorUpdated(const QList &); private: