File indexing completed on 2024-04-28 11:47:25

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, QVector<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 QVector<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     QVector<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     QVector<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 auto associatedWidgets = action->associatedWidgets();
0180 
0181     for (auto *widget : associatedWidgets) {
0182         connectToActionContainer(widget);
0183     }
0184 }
0185 
0186 void ToolBarHandler::Private::connectToActionContainer(QWidget *container)
0187 {
0188     QMenu *popupMenu = qobject_cast<QMenu *>(container);
0189     if (!popupMenu) {
0190         return;
0191     }
0192 
0193     connect(popupMenu, &QMenu::aboutToShow, parent, &ToolBarHandler::setupActions);
0194 }
0195 
0196 ToolBarHandler::ToolBarHandler(KXmlGuiWindow *mainWindow)
0197     : QObject(mainWindow)
0198     , KXMLGUIClient(mainWindow)
0199     , d(new Private(this))
0200 {
0201     d->init(mainWindow);
0202 }
0203 
0204 ToolBarHandler::ToolBarHandler(KXmlGuiWindow *mainWindow, QObject *parent)
0205     : QObject(parent)
0206     , KXMLGUIClient(mainWindow)
0207     , d(new Private(this))
0208 {
0209     d->init(mainWindow);
0210 }
0211 
0212 ToolBarHandler::~ToolBarHandler()
0213 {
0214     qDeleteAll(d->actions);
0215     d->actions.clear();
0216 
0217     delete d;
0218 }
0219 
0220 QAction *ToolBarHandler::toolBarMenuAction()
0221 {
0222     Q_ASSERT(d->actions.count() == 1);
0223     return d->actions.first();
0224 }
0225 
0226 void ToolBarHandler::setupActions()
0227 {
0228     if (!factory() || !d->mainWindow) {
0229         return;
0230     }
0231 
0232     BarActionBuilder builder(actionCollection(), d->mainWindow, d->toolBars);
0233 
0234     if (!builder.needsRebuild()) {
0235         return;
0236     }
0237 
0238     unplugActionList(QLatin1String(actionListName));
0239 
0240     qDeleteAll(d->actions);
0241     d->actions.clear();
0242 
0243     d->actions = builder.create();
0244 
0245     d->toolBars = builder.toolBars();
0246 
0247     // We have no XML file associated with our action collection, so load settings from KConfig
0248     actionCollection()->readSettings(); // #233712
0249 
0250     if (KAuthorized::authorizeAction(QStringLiteral("options_show_toolbar"))) {
0251         plugActionList(QLatin1String(actionListName), d->actions);
0252     }
0253 
0254     d->connectToActionContainers();
0255 }
0256 
0257 void ToolBarHandler::clientAdded(KXMLGUIClient *client)
0258 {
0259     d->clientAdded(client);
0260 }
0261 
0262 #include "moc_ktoolbarhandler_p.cpp"