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;
});
if (it == d->m_contextWidgets.cend())
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.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<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())