kdeui: implement sub-menu export/import for D-Bus menus

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2023-05-28 23:58:56 +03:00
parent b54ba45a5a
commit 9a86368853
4 changed files with 89 additions and 31 deletions

View file

@ -51,6 +51,7 @@ QDBusArgument& operator<<(QDBusArgument &argument, const KDBusMenuAction &kdbusm
argument << kdbusmenuaction.icondata;
argument << kdbusmenuaction.title;
argument << kdbusmenuaction.exclusive;
argument << kdbusmenuaction.submenu;
argument.endStructure();
return argument;
}
@ -66,6 +67,7 @@ const QDBusArgument& operator>>(const QDBusArgument &argument, KDBusMenuAction &
argument >> kdbusmenuaction.icondata;
argument >> kdbusmenuaction.title;
argument >> kdbusmenuaction.exclusive;
argument >> kdbusmenuaction.submenu;
argument.endStructure();
return argument;
}

View file

@ -61,6 +61,7 @@ struct KDBusMenuAction
QByteArray icondata;
bool title;
bool exclusive;
bool submenu;
};
Q_DECLARE_METATYPE(KDBusMenuAction);
Q_DECLARE_METATYPE(QList<KDBusMenuAction>);

View file

@ -41,7 +41,7 @@ public Q_SLOTS:
KDBusMenu menu() const;
QList<KDBusMenuAction> actions() const;
QList<KDBusMenuAction> actions(quint64 actionid = 0) const;
bool triggerAction(quint64 actionid) const;
private:
@ -107,21 +107,32 @@ KDBusMenu KDBusMenuAdaptor::menu() const
return result;
}
QList<KDBusMenuAction> KDBusMenuAdaptor::actions() const
QList<KDBusMenuAction> KDBusMenuAdaptor::actions(quint64 actionid) const
{
QList<KDBusMenuAction> result;
if (m_menu.isNull()) {
kWarning(s_kdbusmenuarea) << "Menu is null";
return result;
}
foreach (QAction* action, m_menu->actions()) {
QList<QAction*> actionslist;
if (actionid == 0) {
actionslist = m_menu->actions();
} else {
foreach (const QAction* action, m_menu->actions()) {
const quint64 itactionid = kDBusMenuActionID(action);
if (actionid == itactionid) {
const QMenu* actionmenu = action->menu();
if (!actionmenu) {
kWarning(s_kdbusmenuarea) << "Requested actions for non-menu action" << actionid;
return result;
}
actionslist = actionmenu->actions();
}
}
}
foreach (QAction* action, actionslist) {
const quint64 actionid = kDBusMenuActionID(action);
kDebug(s_kdbusmenuarea) << "Exporting action" << actionid;
const QMenu* actionmenu = action->menu();
if (actionmenu) {
kWarning(s_kdbusmenuarea) << "Menu actions are not supported";
continue;
}
KDBusMenuAction actionproperties;
// see kdeui/widgets/kmenu.cpp
actionproperties.title = (action->objectName() == QLatin1String("kmenu_title"));
@ -170,6 +181,8 @@ QList<KDBusMenuAction> KDBusMenuAdaptor::actions() const
}
const QActionGroup* actiongroup = action->actionGroup();
actionproperties.exclusive = (actiongroup && actiongroup->isExclusive());
const QMenu* actionmenu = action->menu();
actionproperties.submenu = (actionmenu != nullptr);
result.append(actionproperties);
}
return result;
@ -183,10 +196,19 @@ bool KDBusMenuAdaptor::triggerAction(quint64 actionid) const
return false;
}
foreach (QAction* action, m_menu->actions()) {
const quint64 itactionid = kDBusMenuActionID(action);
quint64 itactionid = kDBusMenuActionID(action);
if (itactionid == actionid) {
return QMetaObject::invokeMethod(action, "triggered");
}
const QMenu* actionmenu = action->menu();
if (actionmenu) {
foreach (QAction* subaction, actionmenu->actions()) {
itactionid = kDBusMenuActionID(subaction);
if (itactionid == actionid) {
return QMetaObject::invokeMethod(subaction, "triggered");
}
}
}
}
kWarning(s_kdbusmenuarea) << "Could not find action for" << actionid;
return false;

View file

@ -32,6 +32,8 @@ class KDBusMenuImporterPrivate
public:
KDBusMenuImporterPrivate();
static QAction* createAction(QMenu *menu, const KDBusMenuAction &actionproperties);
QDBusInterface* interface;
QMenu* menu;
};
@ -42,6 +44,31 @@ KDBusMenuImporterPrivate::KDBusMenuImporterPrivate()
{
}
QAction* KDBusMenuImporterPrivate::createAction(QMenu *menu, const KDBusMenuAction &actionproperties)
{
QAction* action = new QAction(menu);
action->setText(actionproperties.text);
action->setToolTip(actionproperties.tooltip);
action->setStatusTip(actionproperties.statustip);
action->setWhatsThis(actionproperties.whatsthis);
action->setSeparator(actionproperties.separator);
action->setCheckable(actionproperties.checkable);
action->setChecked(actionproperties.checked);
action->setEnabled(actionproperties.enabled);
action->setVisible(actionproperties.visible);
QList<QKeySequence> shortcuts;
foreach (const QString &keysequence, actionproperties.shortcuts) {
shortcuts.append(QKeySequence::fromString(keysequence));
}
action->setShortcuts(shortcuts);
if (actionproperties.exclusive) {
QActionGroup *actiongroup = new QActionGroup(action);
actiongroup->addAction(action);
}
action->setData(QVariant(actionproperties.id));
return action;
}
KDBusMenuImporter::KDBusMenuImporter(const QString &service, const QString &path, QObject *parent)
: QObject(parent),
@ -107,7 +134,7 @@ void KDBusMenuImporter::updateMenu()
QPixmap actionpixmap;
const bool pixmaploaded = actionpixmap.loadFromData(actionproperties.icondata, s_kdbusmenuiconformat);
if (!pixmaploaded) {
kWarning(s_kdbusmenuarea) << "Could not load icon pixmap" << actionid;
kWarning(s_kdbusmenuarea) << "Could not load action icon pixmap" << actionid;
} else {
actionicon = QIcon(actionpixmap);
}
@ -117,28 +144,34 @@ void KDBusMenuImporter::updateMenu()
// see kdeui/widgets/kmenu.cpp
action = KMenu::titleAction(actionicon, actionproperties.text, d->menu);
} else {
action = new QAction(d->menu);
action->setText(actionproperties.text);
action = KDBusMenuImporterPrivate::createAction(d->menu, actionproperties);
}
if (actionproperties.submenu) {
QDBusReply<QList<KDBusMenuAction>> subactionsreply = d->interface->call("actions", actionid);
if (!subactionsreply.isValid()) {
kWarning(s_kdbusmenuarea) << "Invalid sub-actions reply" << subactionsreply.error();
return;
}
QMenu* subactionmenu = KDBusMenuImporter::createMenu(d->menu);
foreach (const KDBusMenuAction &subactionproperties, subactionsreply.value()) {
QIcon subactionicon = KDBusMenuImporter::iconForName(subactionproperties.icon);
if (subactionicon.isNull() && !subactionproperties.icondata.isEmpty()) {
QPixmap subactionpixmap;
const bool subpixmaploaded = subactionpixmap.loadFromData(subactionproperties.icondata, s_kdbusmenuiconformat);
if (!subpixmaploaded) {
kWarning(s_kdbusmenuarea) << "Could not load sub-action icon pixmap" << actionid;
} else {
subactionicon = QIcon(subactionpixmap);
}
}
QAction* subaction = KDBusMenuImporterPrivate::createAction(subactionmenu, subactionproperties);
subaction->setIcon(subactionicon);
connect(subaction, SIGNAL(triggered()), this, SLOT(slotActionTriggered()));
subactionmenu->addAction(subaction);
}
action->setMenu(subactionmenu);
}
action->setIcon(actionicon);
action->setToolTip(actionproperties.tooltip);
action->setStatusTip(actionproperties.statustip);
action->setWhatsThis(actionproperties.whatsthis);
action->setSeparator(actionproperties.separator);
action->setCheckable(actionproperties.checkable);
action->setChecked(actionproperties.checked);
action->setEnabled(actionproperties.enabled);
action->setVisible(actionproperties.visible);
QList<QKeySequence> shortcuts;
foreach (const QString &keysequence, actionproperties.shortcuts) {
shortcuts.append(QKeySequence::fromString(keysequence));
}
action->setShortcuts(shortcuts);
if (actionproperties.exclusive) {
QActionGroup *actiongroup = new QActionGroup(action);
actiongroup->addAction(action);
}
}
action->setData(QVariant(actionid));
connect(action, SIGNAL(triggered()), this, SLOT(slotActionTriggered()));
d->menu->addAction(action);
}