File indexing completed on 2024-03-24 04:02:28

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