cf12defd28
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
243 lines
7.2 KiB
C++
243 lines
7.2 KiB
C++
/*
|
|
This file is part of the KDE project
|
|
SPDX-FileCopyrightText: 2006 Olivier Goffart <ogoffart@kde.org>
|
|
|
|
SPDX-License-Identifier: LGPL-2.0-or-later
|
|
*/
|
|
|
|
#include "kmenumenuhandler_p.h"
|
|
|
|
#include "debug.h"
|
|
#include "kactioncollection.h"
|
|
#include "kmainwindow.h"
|
|
#include "kshortcutwidget.h"
|
|
#include "ktoolbar.h"
|
|
#include "kxmlguibuilder.h"
|
|
#include "kxmlguiclient.h"
|
|
#include "kxmlguifactory.h"
|
|
|
|
#include <QAction>
|
|
#include <QContextMenuEvent>
|
|
#include <QDialog>
|
|
#include <QDialogButtonBox>
|
|
#include <QDomDocument>
|
|
#include <QDomNode>
|
|
#include <QMenu>
|
|
#include <QVBoxLayout>
|
|
|
|
#include <KLocalizedString>
|
|
#include <KSelectAction>
|
|
|
|
namespace KDEPrivate
|
|
{
|
|
KMenuMenuHandler::KMenuMenuHandler(KXMLGUIBuilder *builder)
|
|
: QObject()
|
|
, m_builder(builder)
|
|
{
|
|
m_toolbarAction = new KSelectAction(i18n("Add to Toolbar"), this);
|
|
connect(m_toolbarAction, &KSelectAction::indexTriggered, this, &KMenuMenuHandler::slotAddToToolBar);
|
|
}
|
|
|
|
void KMenuMenuHandler::insertMenu(QMenu *popup)
|
|
{
|
|
popup->installEventFilter(this);
|
|
}
|
|
|
|
bool KMenuMenuHandler::eventFilter(QObject *watched, QEvent *event)
|
|
{
|
|
switch (event->type()) {
|
|
case QEvent::MouseButtonPress:
|
|
if (m_contextMenu && m_contextMenu->isVisible()) {
|
|
m_contextMenu->hide();
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case QEvent::MouseButtonRelease:
|
|
if (m_contextMenu && m_contextMenu->isVisible()) {
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case QEvent::ContextMenu: {
|
|
QContextMenuEvent *e = static_cast<QContextMenuEvent *>(event);
|
|
QMenu *menu = static_cast<QMenu *>(watched);
|
|
if (e->reason() == QContextMenuEvent::Mouse) {
|
|
showContextMenu(menu, e->pos());
|
|
} else if (menu->activeAction()) {
|
|
showContextMenu(menu, menu->actionGeometry(menu->activeAction()).center());
|
|
}
|
|
}
|
|
event->accept();
|
|
return true;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void KMenuMenuHandler::buildToolbarAction()
|
|
{
|
|
KMainWindow *window = qobject_cast<KMainWindow *>(m_builder->widget());
|
|
if (!window) {
|
|
return;
|
|
}
|
|
QStringList toolbarlist;
|
|
const auto toolbars = window->toolBars();
|
|
toolbarlist.reserve(toolbars.size());
|
|
for (KToolBar *b : toolbars) {
|
|
toolbarlist << (b->windowTitle().isEmpty() ? b->objectName() : b->windowTitle());
|
|
}
|
|
m_toolbarAction->setItems(toolbarlist);
|
|
}
|
|
|
|
static KActionCollection *findParentCollection(KXMLGUIFactory *factory, QAction *action)
|
|
{
|
|
const auto clients = factory->clients();
|
|
for (KXMLGUIClient *client : clients) {
|
|
KActionCollection *collection = client->actionCollection();
|
|
// if the call to actions() is too slow, add KActionCollection::contains(QAction*).
|
|
if (collection->actions().contains(action)) {
|
|
return collection;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void KMenuMenuHandler::slotSetShortcut()
|
|
{
|
|
if (!m_popupMenu || !m_popupAction) {
|
|
return;
|
|
}
|
|
|
|
QDialog dialog(m_builder->widget());
|
|
auto *layout = new QVBoxLayout(&dialog);
|
|
|
|
KShortcutWidget swidget(&dialog);
|
|
swidget.setShortcut(m_popupAction->shortcuts());
|
|
layout->addWidget(&swidget);
|
|
|
|
QDialogButtonBox box(&dialog);
|
|
box.setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
|
connect(&box, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
|
connect(&box, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
|
layout->addWidget(&box);
|
|
|
|
KActionCollection *parentCollection = nullptr;
|
|
if (dynamic_cast<KXMLGUIClient *>(m_builder)) {
|
|
QList<KActionCollection *> checkCollections;
|
|
KXMLGUIFactory *factory = dynamic_cast<KXMLGUIClient *>(m_builder)->factory();
|
|
parentCollection = findParentCollection(factory, m_popupAction);
|
|
const auto clients = factory->clients();
|
|
checkCollections.reserve(clients.size());
|
|
for (KXMLGUIClient *client : clients) {
|
|
checkCollections += client->actionCollection();
|
|
}
|
|
swidget.setCheckActionCollections(checkCollections);
|
|
}
|
|
|
|
if (dialog.exec()) {
|
|
m_popupAction->setShortcuts(swidget.shortcut());
|
|
swidget.applyStealShortcut();
|
|
if (parentCollection) {
|
|
parentCollection->writeSettings();
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMenuMenuHandler::slotAddToToolBar(int tb)
|
|
{
|
|
KMainWindow *window = qobject_cast<KMainWindow *>(m_builder->widget());
|
|
if (!window) {
|
|
return;
|
|
}
|
|
|
|
if (!m_popupMenu || !m_popupAction) {
|
|
return;
|
|
}
|
|
|
|
KXMLGUIFactory *factory = dynamic_cast<KXMLGUIClient *>(m_builder)->factory();
|
|
QString actionName = m_popupAction->objectName(); // set by KActionCollection::addAction
|
|
KActionCollection *collection = nullptr;
|
|
if (factory) {
|
|
collection = findParentCollection(factory, m_popupAction);
|
|
}
|
|
if (!collection) {
|
|
qCWarning(DEBUG_KXMLGUI) << "Cannot find the action collection for action " << actionName;
|
|
return;
|
|
}
|
|
|
|
KToolBar *toolbar = window->toolBars().at(tb);
|
|
toolbar->addAction(m_popupAction);
|
|
|
|
const KXMLGUIClient *client = collection->parentGUIClient();
|
|
QString xmlFile = client->localXMLFile();
|
|
QDomDocument document;
|
|
document.setContent(KXMLGUIFactory::readConfigFile(client->xmlFile(), client->componentName()));
|
|
QDomElement elem = document.documentElement().toElement();
|
|
|
|
const QLatin1String tagToolBar("ToolBar");
|
|
const QLatin1String attrNoEdit("noEdit");
|
|
const QLatin1String attrName("name");
|
|
|
|
QDomElement toolbarElem;
|
|
QDomNode n = elem.firstChild();
|
|
for (; !n.isNull(); n = n.nextSibling()) {
|
|
QDomElement elem = n.toElement();
|
|
if (!elem.isNull() && elem.tagName() == tagToolBar && elem.attribute(attrName) == toolbar->objectName()) {
|
|
if (elem.attribute(attrNoEdit) == QLatin1String("true")) {
|
|
qCWarning(DEBUG_KXMLGUI) << "The toolbar is not editable";
|
|
return;
|
|
}
|
|
toolbarElem = elem;
|
|
break;
|
|
}
|
|
}
|
|
if (toolbarElem.isNull()) {
|
|
toolbarElem = document.createElement(tagToolBar);
|
|
toolbarElem.setAttribute(attrName, toolbar->objectName());
|
|
elem.appendChild(toolbarElem);
|
|
}
|
|
|
|
KXMLGUIFactory::findActionByName(toolbarElem, actionName, true);
|
|
KXMLGUIFactory::saveConfigFile(document, xmlFile);
|
|
factory->refreshActionProperties();
|
|
}
|
|
|
|
void KMenuMenuHandler::showContextMenu(QMenu *menu, const QPoint &pos)
|
|
{
|
|
Q_ASSERT(!m_popupMenu);
|
|
Q_ASSERT(!m_popupAction);
|
|
Q_ASSERT(!m_contextMenu);
|
|
|
|
auto *action = menu->actionAt(pos);
|
|
if (!action || action->isSeparator()) {
|
|
return;
|
|
}
|
|
|
|
m_popupMenu = menu;
|
|
m_popupAction = action;
|
|
|
|
m_contextMenu = new QMenu;
|
|
m_contextMenu->addAction(i18nc("@action:inmenu", "Configure Shortcut…"), this, &KMenuMenuHandler::slotSetShortcut);
|
|
|
|
KMainWindow *window = qobject_cast<KMainWindow *>(m_builder->widget());
|
|
if (window) {
|
|
m_contextMenu->addAction(m_toolbarAction);
|
|
buildToolbarAction();
|
|
}
|
|
|
|
m_contextMenu->exec(menu->mapToGlobal(pos));
|
|
delete m_contextMenu;
|
|
m_contextMenu = nullptr;
|
|
|
|
m_popupAction = nullptr;
|
|
m_popupMenu = nullptr;
|
|
}
|
|
|
|
} // END namespace KDEPrivate
|
|
|
|
#include "moc_kmenumenuhandler_p.cpp"
|