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 <eike.ziller@qt.io>
This commit is contained in:
David Schulz
2024-04-12 12:53:27 +02:00
parent 310d3cc041
commit ee8245d8aa
4 changed files with 61 additions and 46 deletions

View File

@@ -314,7 +314,7 @@ public:
QList<IContext *> m_activeContext;
std::unordered_map<QWidget *, IContext *> m_contextWidgets;
std::unordered_map<QWidget *, QList<IContext *>> 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<IContext *> 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<IContext *> 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<QWidget *, IContext *> &v) {
return v.second == context;
auto it = std::find_if(
d->m_contextWidgets.begin(),
d->m_contextWidgets.end(),
[context](const std::pair<QWidget *, QList<IContext *>> &v) {
return v.second.contains(context);
});
if (it == d->m_contextWidgets.cend())
if (it == d->m_contextWidgets.end())
return;
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<IContext *> 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())

View File

@@ -87,9 +87,9 @@ public:
static void raiseWindow(QWidget *widget);
static void raiseMainWindow();
static IContext *currentContextObject();
static QList<IContext *> currentContextObjects();
static QWidget *currentContextWidget();
static IContext *contextObject(QWidget *widget);
static QList<IContext *> contextObjects(QWidget *widget);
static void updateAdditionalContexts(const Context &remove, const Context &add,
ContextPriority priority = ContextPriority::Low);
static void addAdditionalContext(const Context &context,

View File

@@ -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

View File

@@ -102,6 +102,7 @@ public:
void modeChanged(Id mode, Id old);
void requestContextHelp();
void requestContextHelpFor(QList<QPointer<IContext>> contexts);
void showContextHelp(const HelpItem &contextHelp);
void activateIndex();
void activateContents();
@@ -464,11 +465,32 @@ void HelpPluginPrivate::requestContextHelp()
const HelpItem tipHelp = tipHelpValue.canConvert<HelpItem>()
? tipHelpValue.value<HelpItem>()
: HelpItem(tipHelpValue.toString());
IContext *context = ICore::currentContextObject();
if (tipHelp.isEmpty() && context)
context->contextHelp([this](const HelpItem &item) { showContextHelp(item); });
else
const QList<IContext *> contexts = ICore::currentContextObjects();
if (contexts.isEmpty() && !tipHelp.isEmpty()) {
showContextHelp(tipHelp);
} else {
requestContextHelpFor(Utils::transform(contexts, [](IContext *context) {
return QPointer<IContext>(context);
}));
}
}
void HelpPluginPrivate::requestContextHelpFor(QList<QPointer<IContext>> contexts)
{
if (contexts.isEmpty())
return;
QPointer<IContext> 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)