From ee8245d8aaa4e34d2773c572aa05a4ca5866f151 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 12 Apr 2024 12:53:27 +0200 Subject: Core: allow multiple contexts per widget This makes it possible to allow different sets of actions for a specific widget depending on the defined contexts for that widget. Fixes: QTCREATORBUG-30675 Fixes: QTCREATORBUG-30677 Change-Id: I408e0ae445b364d4f450ccdd2fbdfc81ece45015 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/icore.cpp | 63 ++++++++++++++--------------- src/plugins/coreplugin/icore.h | 4 +- src/plugins/coreplugin/statusbarmanager.cpp | 10 ++--- src/plugins/help/helpplugin.cpp | 30 ++++++++++++-- 4 files changed, 61 insertions(+), 46 deletions(-) diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 8a727494c2d..85401aa8bc7 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -314,7 +314,7 @@ public: QList m_activeContext; - std::unordered_map m_contextWidgets; + std::unordered_map> m_contextWidgets; ShortcutSettings *m_shortcutSettings = nullptr; ToolSettings *m_toolSettings = nullptr; @@ -836,16 +836,18 @@ QString ICore::versionString() } /*! - Returns the top level IContext of the current context, or \c nullptr if + Returns a list IContexts for the current top level context widget, or an empty list if there is none. \sa updateAdditionalContexts() \sa addContextObject() \sa {The Action Manager and Commands} */ -IContext *ICore::currentContextObject() +QList ICore::currentContextObjects() { - return d->m_activeContext.isEmpty() ? nullptr : d->m_activeContext.first(); + if (d->m_activeContext.isEmpty()) + return {}; + return d->m_contextWidgets[d->m_activeContext.first()->widget()]; } /*! @@ -856,8 +858,7 @@ IContext *ICore::currentContextObject() */ QWidget *ICore::currentContextWidget() { - IContext *context = currentContextObject(); - return context ? context->widget() : nullptr; + return d->m_activeContext.isEmpty() ? nullptr : d->m_activeContext.first()->widget(); } /*! @@ -1525,8 +1526,10 @@ void ICore::extensionsInitialized() void ICore::aboutToShutdown() { disconnect(qApp, &QApplication::focusChanged, d, &ICorePrivate::updateFocusWidget); - for (auto contextPair : d->m_contextWidgets) - disconnect(contextPair.second, &QObject::destroyed, d->m_mainwindow, nullptr); + for (auto contextsPair : d->m_contextWidgets) { + for (auto context : contextsPair.second) + disconnect(context, &QObject::destroyed, d->m_mainwindow, nullptr); + } d->m_activeContext.clear(); d->m_mainwindow->hide(); } @@ -2281,13 +2284,14 @@ void ICore::openFileWith() } /*! - Returns the registered IContext instance for the specified \a widget, + Returns all registered IContext instance for the specified \a widget, if any. */ -IContext *ICore::contextObject(QWidget *widget) +QList ICore::contextObjects(QWidget *widget) { - const auto it = d->m_contextWidgets.find(widget); - return it == d->m_contextWidgets.end() ? nullptr : it->second; + if (auto it = d->m_contextWidgets.find(widget); it != d->m_contextWidgets.end()) + return it->second; + return {}; } /*! @@ -2306,11 +2310,7 @@ void ICore::addContextObject(IContext *context) { if (!context) return; - QWidget *widget = context->widget(); - if (d->m_contextWidgets.find(widget) != d->m_contextWidgets.end()) - return; - - d->m_contextWidgets.insert({widget, context}); + d->m_contextWidgets[context->widget()].append(context); connect(context, &QObject::destroyed, m_core, [context] { removeContextObject(context); }); } @@ -2331,15 +2331,19 @@ void ICore::removeContextObject(IContext *context) disconnect(context, &QObject::destroyed, m_core, nullptr); - const auto it = std::find_if(d->m_contextWidgets.cbegin(), - d->m_contextWidgets.cend(), - [context](const std::pair &v) { - return v.second == context; - }); - if (it == d->m_contextWidgets.cend()) + auto it = std::find_if( + d->m_contextWidgets.begin(), + d->m_contextWidgets.end(), + [context](const std::pair> &v) { + return v.second.contains(context); + }); + if (it == d->m_contextWidgets.end()) return; - d->m_contextWidgets.erase(it); + it->second.removeAll(context); + if (it->second.isEmpty()) + d->m_contextWidgets.erase(it); + if (d->m_activeContext.removeAll(context) > 0) d->updateContextObject(d->m_activeContext); } @@ -2355,15 +2359,8 @@ void ICorePrivate::updateFocusWidget(QWidget *old, QWidget *now) return; QList newContext; - if (QWidget *p = QApplication::focusWidget()) { - IContext *context = nullptr; - while (p) { - context = ICore::contextObject(p); - if (context) - newContext.append(context); - p = p->parentWidget(); - } - } + for (QWidget *p = QApplication::focusWidget(); p; p = p->parentWidget()) + newContext.append(ICore::contextObjects(p)); // ignore toplevels that define no context, like popups without parent if (!newContext.isEmpty() || QApplication::focusWidget() == m_mainwindow->focusWidget()) diff --git a/src/plugins/coreplugin/icore.h b/src/plugins/coreplugin/icore.h index 8c713e156f4..2c2dbc3c57a 100644 --- a/src/plugins/coreplugin/icore.h +++ b/src/plugins/coreplugin/icore.h @@ -87,9 +87,9 @@ public: static void raiseWindow(QWidget *widget); static void raiseMainWindow(); - static IContext *currentContextObject(); + static QList currentContextObjects(); static QWidget *currentContextWidget(); - static IContext *contextObject(QWidget *widget); + static QList contextObjects(QWidget *widget); static void updateAdditionalContexts(const Context &remove, const Context &add, ContextPriority priority = ContextPriority::Low); static void addAdditionalContext(const Context &context, diff --git a/src/plugins/coreplugin/statusbarmanager.cpp b/src/plugins/coreplugin/statusbarmanager.cpp index c590b3f29ef..e85996b053a 100644 --- a/src/plugins/coreplugin/statusbarmanager.cpp +++ b/src/plugins/coreplugin/statusbarmanager.cpp @@ -156,13 +156,9 @@ StatusBarContext::StatusBarContext(QObject *parent) Context StatusBarContext::context() const { - IMode *currentMode = ModeManager::currentMode(); - QWidget *modeWidget = currentMode ? currentMode->widget() : nullptr; - if (modeWidget) { - if (IContext *context = ICore::contextObject(modeWidget)) - return context->context(); - } - return Context(); + if (IMode *currentMode = ModeManager::currentMode()) + return currentMode->context(); + return {}; } } // Core diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index e9706a3db18..49b4624b269 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -102,6 +102,7 @@ public: void modeChanged(Id mode, Id old); void requestContextHelp(); + void requestContextHelpFor(QList> contexts); void showContextHelp(const HelpItem &contextHelp); void activateIndex(); void activateContents(); @@ -464,11 +465,32 @@ void HelpPluginPrivate::requestContextHelp() const HelpItem tipHelp = tipHelpValue.canConvert() ? tipHelpValue.value() : HelpItem(tipHelpValue.toString()); - IContext *context = ICore::currentContextObject(); - if (tipHelp.isEmpty() && context) - context->contextHelp([this](const HelpItem &item) { showContextHelp(item); }); - else + const QList contexts = ICore::currentContextObjects(); + if (contexts.isEmpty() && !tipHelp.isEmpty()) { showContextHelp(tipHelp); + } else { + requestContextHelpFor(Utils::transform(contexts, [](IContext *context) { + return QPointer(context); + })); + } +} + +void HelpPluginPrivate::requestContextHelpFor(QList> contexts) +{ + if (contexts.isEmpty()) + return; + QPointer context = contexts.takeFirst(); + while (!context) { + if (contexts.isEmpty()) + return; + context = contexts.takeFirst(); + } + context->contextHelp([contexts, this](const HelpItem &item) { + if (!item.isEmpty()) + showContextHelp(item); + else + requestContextHelpFor(contexts); + }); } void HelpPluginPrivate::showContextHelp(const HelpItem &contextHelp) -- cgit v1.2.3