1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2002 Simon Hausmann <hausmann@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6*/
7
8#include "ktoolbarhandler_p.h"
9
10#include <QAction>
11#include <QDomDocument>
12#include <QMenu>
13#include <QPointer>
14
15#include <KActionMenu>
16#include <KAuthorized>
17#include <KLocalizedString>
18
19#include "kactioncollection.h"
20#include "ktoggletoolbaraction.h"
21#include "ktoolbar.h"
22#include "kxmlguifactory.h"
23#include "kxmlguiwindow.h"
24
25namespace
26{
27const char actionListName[] = "show_menu_and_toolbar_actionlist";
28
29const char guiDescription[] =
30 ""
31 "<!DOCTYPE gui><gui name=\"StandardToolBarMenuHandler\">"
32 "<MenuBar>"
33 " <Menu name=\"settings\">"
34 " <ActionList name=\"%1\" />"
35 " </Menu>"
36 "</MenuBar>"
37 "</gui>";
38
39class BarActionBuilder
40{
41public:
42 BarActionBuilder(KActionCollection *actionCollection, KXmlGuiWindow *mainWindow, QList<KToolBar *> &oldToolBarList)
43 : m_actionCollection(actionCollection)
44 , m_mainWindow(mainWindow)
45 , m_needsRebuild(false)
46 {
47 const QList<KToolBar *> toolBars = m_mainWindow->findChildren<KToolBar *>();
48
49 for (KToolBar *toolBar : toolBars) {
50 if (toolBar->mainWindow() != m_mainWindow) {
51 continue;
52 }
53
54 if (!oldToolBarList.contains(t: toolBar)) {
55 m_needsRebuild = true;
56 }
57
58 m_toolBars.append(t: toolBar);
59 }
60
61 if (!m_needsRebuild) {
62 m_needsRebuild = (oldToolBarList.count() != m_toolBars.count());
63 }
64 }
65
66 bool needsRebuild() const
67 {
68 return m_needsRebuild;
69 }
70
71 QList<QAction *> create()
72 {
73 QList<QAction *> actions;
74
75 if (!m_needsRebuild) {
76 return actions;
77 }
78
79 for (KToolBar *bar : std::as_const(t&: m_toolBars)) {
80 handleToolBar(toolBar: bar);
81 }
82
83 if (m_toolBarActions.count() == 0) {
84 return actions;
85 }
86
87 if (m_toolBarActions.count() == 1) {
88 KToggleToolBarAction *action = static_cast<KToggleToolBarAction *>(m_toolBarActions.first());
89 action->setText(KStandardShortcut::label(id: KStandardShortcut::ShowToolbar));
90 return m_toolBarActions;
91 }
92
93 KActionMenu *menuAction = new KActionMenu(i18n("Toolbars Shown"), m_actionCollection);
94 m_actionCollection->addAction(QStringLiteral("toolbars_submenu_action"), action: menuAction);
95
96 for (QAction *action : std::as_const(t&: m_toolBarActions)) {
97 menuAction->menu()->addAction(action);
98 }
99
100 actions.append(t: menuAction);
101
102 return actions;
103 }
104
105 const QList<KToolBar *> &toolBars() const
106 {
107 return m_toolBars;
108 }
109
110private:
111 void handleToolBar(KToolBar *toolBar)
112 {
113 KToggleToolBarAction *action = new KToggleToolBarAction(toolBar, toolBar->windowTitle(), m_actionCollection);
114 m_actionCollection->addAction(name: toolBar->objectName(), action);
115
116 // ## tooltips, whatsthis?
117 m_toolBarActions.append(t: action);
118 }
119
120 KActionCollection *m_actionCollection;
121 KXmlGuiWindow *m_mainWindow;
122
123 QList<KToolBar *> m_toolBars;
124 QList<QAction *> m_toolBarActions;
125
126 bool m_needsRebuild : 1;
127};
128}
129
130using namespace KDEPrivate;
131
132class Q_DECL_HIDDEN ToolBarHandler::Private
133{
134public:
135 Private(ToolBarHandler *_parent)
136 : parent(_parent)
137 {
138 }
139
140 void clientAdded(KXMLGUIClient *client)
141 {
142 Q_UNUSED(client)
143 parent->setupActions();
144 }
145
146 void init(KXmlGuiWindow *mainWindow);
147 void connectToActionContainers();
148 void connectToActionContainer(QAction *action);
149 void connectToActionContainer(QWidget *container);
150
151 ToolBarHandler *parent;
152 QPointer<KXmlGuiWindow> mainWindow;
153 QList<QAction *> actions;
154 QList<KToolBar *> toolBars;
155};
156
157void ToolBarHandler::Private::init(KXmlGuiWindow *mw)
158{
159 mainWindow = mw;
160
161 QObject::connect(sender: mainWindow->guiFactory(), signal: &KXMLGUIFactory::clientAdded, context: parent, slot: &ToolBarHandler::clientAdded);
162
163 if (parent->domDocument().documentElement().isNull()) {
164 QString completeDescription = QString::fromLatin1(ba: guiDescription).arg(a: QLatin1String(actionListName));
165
166 parent->setXML(document: completeDescription, merge: false /*merge*/);
167 }
168}
169
170void ToolBarHandler::Private::connectToActionContainers()
171{
172 for (QAction *action : std::as_const(t&: actions)) {
173 connectToActionContainer(action);
174 }
175}
176
177void ToolBarHandler::Private::connectToActionContainer(QAction *action)
178{
179 const QList<QObject *> associatedObjects = action->associatedObjects();
180
181 for (auto object : associatedObjects) {
182 if (auto widget = qobject_cast<QWidget *>(o: object)) {
183 connectToActionContainer(container: widget);
184 }
185 }
186}
187
188void ToolBarHandler::Private::connectToActionContainer(QWidget *container)
189{
190 QMenu *popupMenu = qobject_cast<QMenu *>(object: container);
191 if (!popupMenu) {
192 return;
193 }
194
195 connect(sender: popupMenu, signal: &QMenu::aboutToShow, context: parent, slot: &ToolBarHandler::setupActions);
196}
197
198ToolBarHandler::ToolBarHandler(KXmlGuiWindow *mainWindow)
199 : QObject(mainWindow)
200 , KXMLGUIClient(mainWindow)
201 , d(new Private(this))
202{
203 d->init(mw: mainWindow);
204}
205
206ToolBarHandler::ToolBarHandler(KXmlGuiWindow *mainWindow, QObject *parent)
207 : QObject(parent)
208 , KXMLGUIClient(mainWindow)
209 , d(new Private(this))
210{
211 d->init(mw: mainWindow);
212}
213
214ToolBarHandler::~ToolBarHandler()
215{
216 qDeleteAll(c: d->actions);
217 d->actions.clear();
218
219 delete d;
220}
221
222QAction *ToolBarHandler::toolBarMenuAction()
223{
224 Q_ASSERT(d->actions.count() == 1);
225 return d->actions.first();
226}
227
228void ToolBarHandler::setupActions()
229{
230 if (!factory() || !d->mainWindow) {
231 return;
232 }
233
234 BarActionBuilder builder(actionCollection(), d->mainWindow, d->toolBars);
235
236 if (!builder.needsRebuild()) {
237 return;
238 }
239
240 unplugActionList(name: QLatin1String(actionListName));
241
242 qDeleteAll(c: d->actions);
243 d->actions.clear();
244
245 d->actions = builder.create();
246
247 d->toolBars = builder.toolBars();
248
249 // We have no XML file associated with our action collection, so load settings from KConfig
250 actionCollection()->readSettings(); // #233712
251
252 if (KAuthorized::authorizeAction(QStringLiteral("options_show_toolbar"))) {
253 plugActionList(name: QLatin1String(actionListName), actionList: d->actions);
254 }
255
256 d->connectToActionContainers();
257}
258
259void ToolBarHandler::clientAdded(KXMLGUIClient *client)
260{
261 d->clientAdded(client);
262}
263
264#include "moc_ktoolbarhandler_p.cpp"
265

source code of kxmlgui/src/ktoolbarhandler.cpp