forked from qt-creator/qt-creator
CppEditor: Avoid blocking context menu invocation
Show the menu always immediately. If the needed use selections are not up to date for the refactoring actions, then trigger an async run and if that one finishes, then update the refactoring menu. In the meanwhile, show a place holder menu item showing on-going progress (Utils::ProgressIndicator). Change-Id: Iae7ab37738d79c20aeb1ccda2b1781091e90fdc3 Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io> Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -80,8 +80,9 @@
|
||||
#include <cplusplus/ASTPath.h>
|
||||
#include <cplusplus/FastPreprocessor.h>
|
||||
#include <cplusplus/MatchingText.h>
|
||||
#include <utils/textutils.h>
|
||||
#include <utils/progressindicator.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/textutils.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QAction>
|
||||
@@ -93,6 +94,7 @@
|
||||
#include <QTextEdit>
|
||||
#include <QTimer>
|
||||
#include <QToolButton>
|
||||
#include <QWidgetAction>
|
||||
|
||||
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"
|
||||
|
@@ -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<CppEditorWidget *>(m_editorWidget);
|
||||
QTC_ASSERT(cppEditorWidget, return);
|
||||
QTC_ASSERT(cppEditorWidget, return RunnerInfo::FailedToStart);
|
||||
|
||||
auto *cppEditorDocument = qobject_cast<CppEditorDocument *>(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<CursorInfo> 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;
|
||||
}
|
||||
|
||||
|
@@ -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<QTextEdit::ExtraSelection> &);
|
||||
|
||||
private:
|
||||
|
Reference in New Issue
Block a user