File indexing completed on 2024-12-22 04:14:09

0001 /* This file is part of the KDE libraries
0002    SPDX-FileCopyrightText: 2002 Simon Hausmann <hausmann@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #include "ktoolbarhandler_p.h"
0008 #include "config-xmlgui.h"
0009 #include <QDomDocument>
0010 #include <QAction>
0011 #include <QMenu>
0012 
0013 #include <kactionmenu.h>
0014 #include <klocalizedstring.h>
0015 
0016 #include "kxmlguiwindow.h"
0017 #include "ktoggletoolbaraction.h"
0018 #include "ktoolbar.h"
0019 #include "kxmlguifactory.h"
0020 #include "kactioncollection.h"
0021 
0022 #if defined(KCONFIG_BEFORE_5_24)
0023 # define authorizeAction authorizeKAction
0024 #endif
0025 
0026 namespace
0027 {
0028 const char actionListName[] = "show_menu_and_toolbar_actionlist";
0029 
0030 const char guiDescription[] = ""
0031                              "<!DOCTYPE kpartgui><kpartgui name=\"StandardToolBarMenuHandler\">"
0032                              "<MenuBar>"
0033                              "    <Menu name=\"settings\">"
0034                              "        <ActionList name=\"%1\" />"
0035                              "    </Menu>"
0036                              "</MenuBar>"
0037                              "</kpartgui>";
0038 
0039 class BarActionBuilder
0040 {
0041 public:
0042     BarActionBuilder(KisKActionCollection *actionCollection, KXmlGuiWindow *mainWindow,
0043                      QLinkedList<KisToolBar *> &oldToolBarList)
0044         : m_actionCollection(actionCollection), m_mainWindow(mainWindow), m_needsRebuild(false)
0045     {
0046         QList<KisToolBar *> toolBars = m_mainWindow->findChildren<KisToolBar *>();
0047 
0048         Q_FOREACH (KisToolBar *toolBar, toolBars) {
0049             if (toolBar->mainWindow() != m_mainWindow) {
0050                 continue;
0051             }
0052 
0053             if (!oldToolBarList.contains(toolBar)) {
0054                 m_needsRebuild = true;
0055             }
0056 
0057             m_toolBars.append(toolBar);
0058         }
0059 
0060         if (!m_needsRebuild) {
0061             m_needsRebuild = (oldToolBarList.count() != m_toolBars.count());
0062         }
0063     }
0064 
0065     bool needsRebuild() const
0066     {
0067         return m_needsRebuild;
0068     }
0069 
0070     QList<QAction *> create()
0071     {
0072         QList<QAction *> actions;
0073 
0074         if (!m_needsRebuild) {
0075             return actions;
0076         }
0077 
0078         Q_FOREACH (KisToolBar *bar, m_toolBars) {
0079             handleToolBar(bar);
0080         }
0081 
0082         if (m_toolBarActions.count() == 0) {
0083             return actions;
0084         }
0085 
0086         if (m_toolBarActions.count() == 1) {
0087             KToggleToolBarAction *action = static_cast<KToggleToolBarAction *>(m_toolBarActions.first());
0088             action->setText(KStandardShortcut::label(KStandardShortcut::ShowToolbar));
0089             return m_toolBarActions;
0090         }
0091 
0092         KActionMenu *menuAction = new KActionMenu(i18n("Toolbars Shown"), m_actionCollection);
0093         m_actionCollection->addAction(QStringLiteral("toolbars_submenu_action"), menuAction);
0094 
0095         Q_FOREACH (QAction *action, m_toolBarActions) {
0096             menuAction->menu()->addAction(action);
0097         }
0098 
0099         actions.append(menuAction);
0100 
0101         return actions;
0102     }
0103 
0104     const QLinkedList<KisToolBar *> &toolBars() const
0105     {
0106         return m_toolBars;
0107     }
0108 
0109 private:
0110     void handleToolBar(KisToolBar *toolBar)
0111     {
0112         KToggleToolBarAction *action = new KToggleToolBarAction(
0113             toolBar,
0114             toolBar->windowTitle(),
0115             m_actionCollection);
0116         m_actionCollection->addAction(toolBar->objectName(), action);
0117 
0118         // ## tooltips, whatsthis?
0119         m_toolBarActions.append(action);
0120     }
0121 
0122     KisKActionCollection *m_actionCollection;
0123     KXmlGuiWindow *m_mainWindow;
0124 
0125     QLinkedList<KisToolBar *> m_toolBars;
0126     QList<QAction *> m_toolBarActions;
0127 
0128     bool m_needsRebuild : 1;
0129 };
0130 }
0131 
0132 using namespace KDEPrivate;
0133 
0134 class ToolBarHandler::Private
0135 {
0136 public:
0137     Private(ToolBarHandler *_parent)
0138         : parent(_parent)
0139     {
0140     }
0141 
0142     void clientAdded(KisKXMLGUIClient *client)
0143     {
0144         Q_UNUSED(client);
0145         parent->setupActions();
0146     }
0147 
0148     void init(KXmlGuiWindow *mainWindow);
0149     void connectToActionContainers();
0150     void connectToActionContainer(QAction *action);
0151     void connectToActionContainer(QWidget *container);
0152 
0153     ToolBarHandler *parent;
0154     QPointer<KXmlGuiWindow> mainWindow;
0155     QList<QAction *> actions;
0156     QLinkedList<KisToolBar *> toolBars;
0157 };
0158 
0159 void ToolBarHandler::Private::init(KXmlGuiWindow *mw)
0160 {
0161     mainWindow = mw;
0162 
0163     QObject::connect(mainWindow->guiFactory(), SIGNAL(clientAdded(KisKXMLGUIClient*)),
0164                      parent, SLOT(clientAdded(KisKXMLGUIClient*)));
0165 
0166     if (parent->domDocument().documentElement().isNull()) {
0167 
0168         QString completeDescription = QString::fromLatin1(guiDescription)
0169                                       .arg(QLatin1String(actionListName));
0170 
0171         parent->setXML(completeDescription, false /*merge*/);
0172     }
0173 }
0174 
0175 void ToolBarHandler::Private::connectToActionContainers()
0176 {
0177     Q_FOREACH (QAction *action, actions) {
0178         connectToActionContainer(action);
0179     }
0180 }
0181 
0182 void ToolBarHandler::Private::connectToActionContainer(QAction *action)
0183 {
0184     uint containerCount = action->associatedWidgets().count();
0185 
0186     for (uint i = 0; i < containerCount; ++i) {
0187         connectToActionContainer(action->associatedWidgets().value(i));
0188     }
0189 }
0190 
0191 void ToolBarHandler::Private::connectToActionContainer(QWidget *container)
0192 {
0193     QMenu *popupMenu = qobject_cast<QMenu *>(container);
0194     if (!popupMenu) {
0195         return;
0196     }
0197 
0198     connect(popupMenu, SIGNAL(aboutToShow()),
0199             parent, SLOT(setupActions()));
0200 }
0201 
0202 ToolBarHandler::ToolBarHandler(KXmlGuiWindow *mainWindow)
0203     : QObject(mainWindow), KisKXMLGUIClient(mainWindow),
0204       d(new Private(this))
0205 {
0206     d->init(mainWindow);
0207 }
0208 
0209 ToolBarHandler::ToolBarHandler(KXmlGuiWindow *mainWindow, QObject *parent)
0210     : QObject(parent), KisKXMLGUIClient(mainWindow),
0211       d(new Private(this))
0212 {
0213     d->init(mainWindow);
0214 }
0215 
0216 ToolBarHandler::~ToolBarHandler()
0217 {
0218     qDeleteAll(d->actions);
0219     d->actions.clear();
0220 
0221     delete d;
0222 }
0223 
0224 QAction *ToolBarHandler::toolBarMenuAction()
0225 {
0226     Q_ASSERT(d->actions.count() == 1);
0227     return d->actions.first();
0228 }
0229 
0230 void ToolBarHandler::setupActions()
0231 {
0232     if (!factory() || !d->mainWindow) {
0233         return;
0234     }
0235 
0236     BarActionBuilder builder(actionCollection(), d->mainWindow, d->toolBars);
0237 
0238     if (!builder.needsRebuild()) {
0239         return;
0240     }
0241 
0242     unplugActionList(QLatin1String(actionListName));
0243 
0244     qDeleteAll(d->actions);
0245     d->actions.clear();
0246 
0247     d->actions = builder.create();
0248 
0249     d->toolBars = builder.toolBars();
0250 
0251     // We have no XML file associated with our action collection, so load settings from KConfig
0252     actionCollection()->readSettings(); // #233712
0253 
0254     plugActionList(QLatin1String(actionListName), d->actions);
0255 
0256     d->connectToActionContainers();
0257 }
0258 
0259 #include "moc_ktoolbarhandler_p.cpp"