1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2000 Simon Hausmann <hausmann@kde.org>
4 SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-only
7*/
8
9#ifndef KXMLGUICLIENT_H
10#define KXMLGUICLIENT_H
11
12#include <kxmlgui_export.h>
13
14#include <QStringList>
15#include <memory>
16
17class QDomDocument;
18class QDomElement;
19class QWidget;
20
21class QAction;
22class KActionCollection;
23class KXMLGUIClientPrivate;
24class KXMLGUIFactory;
25class KXMLGUIBuilder;
26
27namespace KDEPrivate
28{
29class KEditToolBarWidget;
30}
31
32/*!
33 * \class KXMLGUIClient
34 * \inmodule KXmlGui
35 *
36 * A KXMLGUIClient can be used with KXMLGUIFactory to create a
37 * GUI from actions and an XML document, and can be dynamically merged
38 * with other KXMLGUIClients.
39 */
40class KXMLGUI_EXPORT KXMLGUIClient
41{
42 friend class KDEPrivate::KEditToolBarWidget; // for setXMLFile(3 args)
43public:
44 /*!
45 * \brief Constructs a KXMLGUIClient that can be used with a
46 * KXMLGUIFactory to create a GUI from actions and an XML document, and
47 * that can be dynamically merged with other KXMLGUIClients.
48 */
49 KXMLGUIClient();
50
51 /*!
52 * \brief Constructs a KXMLGUIClient that can be used with a KXMLGUIFactory
53 * to create a GUI from actions and an XML document,
54 * and that can be dynamically merged with other KXMLGUIClients.
55 *
56 * This constructor takes an additional \a parent argument, which makes
57 * the client a child client of the parent.
58 *
59 * Child clients are automatically added to the GUI if the parent is added.
60 *
61 */
62 explicit KXMLGUIClient(KXMLGUIClient *parent);
63
64 /*!
65 * \brief Destructs the KXMLGUIClient.
66 *
67 * If the client was in a factory, the factory is NOT informed about the client
68 * being removed. This is a feature, it makes window destruction fast (the xmlgui
69 * is not updated for every client being deleted), but if you want to simply remove
70 * one client and to keep using the window, make sure to call factory->removeClient(client)
71 * before deleting the client.
72 */
73 virtual ~KXMLGUIClient();
74
75 /*!
76 * \brief Retrieves an action of the client by \a name.
77 *
78 * If not found, it looks in its child clients.
79 *
80 * This method is provided for convenience, as it uses actionCollection()
81 * to get the action object.
82 *
83 * \since 6.0
84 */
85 QAction *action(const QString &name) const;
86
87 /*!
88 * \brief Retrieves an action for a given QDomElement \a element.
89 *
90 * The default implementation uses the "name" attribute to query the action
91 * object via the other action() method.
92 */
93 virtual QAction *action(const QDomElement &element) const;
94
95 /*!
96 * \brief Retrieves the entire action collection for the GUI client.
97 */
98 virtual KActionCollection *actionCollection() const;
99
100 /*!
101 * \brief Returns the component name for this GUI client.
102 */
103 virtual QString componentName() const;
104
105 /*!
106 * \brief Returns the parsed XML in a QDomDocument, set by
107 * setXMLFile() or setXML().
108 *
109 * This document describes the layout of the GUI.
110 */
111 virtual QDomDocument domDocument() const;
112
113 /*!
114 * \brief Returns the name of the XML file as set by setXMLFile();
115 * if setXML() is used directly, then this will return an empty string.
116 *
117 * The filename that this returns is obvious for components as each
118 * component has exactly one XML file. In non-components, however,
119 * there are usually two: the global file and the local file. This
120 * function doesn't really care about that, though. It will always
121 * return the last XML file set. This, in almost all cases, will
122 * be the local XML file.
123 */
124 virtual QString xmlFile() const;
125
126 virtual QString localXMLFile() const;
127
128 /*!
129 * \internal
130 */
131 void setXMLGUIBuildDocument(const QDomDocument &doc);
132 /*!
133 * \internal
134 */
135 QDomDocument xmlguiBuildDocument() const;
136
137 /*!
138 * \brief Sets a new \a factory.
139 *
140 * This method is called by the KXMLGUIFactory as soon as the client
141 * is added to the KXMLGUIFactory's GUI.
142 */
143 void setFactory(KXMLGUIFactory *factory);
144 /*!
145 * \brief Retrieves a pointer to the KXMLGUIFactory this client is
146 * associated with.
147 *
148 * Will return nullptr if the client's GUI has not been built
149 * by a KXMLGUIFactory.
150 */
151 KXMLGUIFactory *factory() const;
152
153 /*!
154 * \brief Returns a pointer to the parent client or nullptr if it has no
155 * parent client assigned.
156 *
157 * KXMLGUIClients can form a simple child/parent object tree.
158 */
159 KXMLGUIClient *parentClient() const;
160
161 /*!
162 * \brief Makes a client a \a child client of another client.
163 *
164 * Usually you don't need to call this method, as it is called
165 * automatically when using the second constructor, which takes a
166 * parent argument.
167 */
168 void insertChildClient(KXMLGUIClient *child);
169
170 /*!
171 * \brief Removes the given \a child from the client's children list.
172 */
173 void removeChildClient(KXMLGUIClient *child);
174
175 /*!
176 * \brief Retrieves a list of all child clients.
177 */
178 QList<KXMLGUIClient *> childClients();
179
180 /*!
181 * \brief Use this method to assign your \a builder instance to the client
182 * (so that the KXMLGUIFactory can use it when building the client's GUI).
183 *
184 * A client can have its own KXMLGUIBuilder.
185 *
186 * Client specific guibuilders are useful if you want to create
187 * custom container widgets for your GUI.
188 */
189 void setClientBuilder(KXMLGUIBuilder *builder);
190
191 /*!
192 * \brief Retrieves the client's GUI builder or nullptr if no client specific
193 * builder has been assigned via setClientBuilder().
194 */
195 KXMLGUIBuilder *clientBuilder() const;
196
197 /*!
198 * \brief Forces this client to re-read its XML resource file.
199 *
200 * This is intended to be used when you know that the resource file has
201 * changed and you will soon be rebuilding the GUI. This will only have
202 * an effect if the client is then removed and re-added to the factory.
203 *
204 * This method is only for child clients, do not call it for a mainwindow!
205 * For a mainwindow, use loadStandardsXmlFile + setXmlFile(xmlFile()) instead.
206 */
207 void reloadXML();
208
209 /*!
210 * \brief Plugs a new \a actionList with the given \a name.
211 *
212 * ActionLists are a way for XMLGUI to support dynamic lists of
213 * actions. E.g. if you are writing a file manager, and there is a
214 * menu file whose contents depend on the mimetype of the file that
215 * is selected, then you can achieve this using ActionLists. It
216 * works as follows:
217 * In your xxxui.rc file (the one that you set in setXMLFile() / pass
218 * to setupGUI()), you put a tag <ActionList name="xxx">.
219 *
220 * Example:
221 * \code
222 * <gui name="xxx_part" version="1">
223 * <MenuBar>
224 * <Menu name="file">
225 * ... <!-- some useful actions-->
226 * <ActionList name="xxx_file_actionlist" />
227 * ... <!-- even more useful actions-->
228 * </Menu>
229 * ...
230 * </MenuBar>
231 * </gui>
232 * \endcode
233 *
234 * This tag will get expanded to a list of actions. In the example
235 * above ( a file manager with a dynamic file menu ), you would call:
236 *
237 * \code
238 * QList<QAction*> file_actions;
239 * for( ... )
240 * if( ... )
241 * file_actions.append( cool_action );
242 * unplugActionList( "xxx_file_actionlist" );
243 * plugActionList( "xxx_file_actionlist", file_actions );
244 * \endcode
245 *
246 * Every time a file is selected, unselected or ...
247 *
248 * \note You should not call KXmlGuiWindow::createGUI() after calling this
249 * function. In fact, that would remove the newly added
250 * actionlists again...
251 * \note Forgetting to call unplugActionList() before
252 * plugActionList() would leave the previous actions in the
253 * menu too..
254 * \sa unplugActionList()
255 */
256 void plugActionList(const QString &name, const QList<QAction *> &actionList);
257
258 /*!
259 * \brief Unplugs the action list \a name from the XMLGUI.
260 *
261 * Calling this removes the specified action list, i.e. this is the
262 * complement to plugActionList(). See plugActionList() for a more
263 * detailed example.
264 * \sa plugActionList()
265 */
266 void unplugActionList(const QString &name);
267
268 static QString findMostRecentXMLFile(const QStringList &files, QString &doc);
269
270 void addStateActionEnabled(const QString &state, const QString &action);
271
272 void addStateActionDisabled(const QString &state, const QString &action);
273
274 enum ReverseStateChange {
275 StateNoReverse,
276 StateReverse
277 };
278 struct StateChange {
279 QStringList actionsToEnable;
280 QStringList actionsToDisable;
281 };
282
283 StateChange getActionsToChangeForState(const QString &state);
284
285 void beginXMLPlug(QWidget *);
286 void endXMLPlug();
287 void prepareXMLUnplug(QWidget *);
288
289 /*!
290 * \brief Sets a new \a xmlfile and \a localxmlfile.
291 *
292 * The purpose of this public
293 * method is to allow non-inherited objects to replace the ui definition
294 * of an embedded client with a customized version. It corresponds to the
295 * usual calls to setXMLFile() and setLocalXMLFile().
296 *
297 * \a xmlfile The xml file to use. Contrary to setXMLFile(), this
298 * must be an absolute file path.
299 *
300 * \a localxmlfile The local xml file to set. This should be the full path
301 * to a writeable file, usually using QStandardPaths::writableLocation.
302 * You can set this to QString(), but no user changes to shortcuts / toolbars
303 * will be possible in this case.
304 *
305 * \a merge Whether to merge with the global document.
306 *
307 * \note If in any doubt whether you need this or not, use setXMLFile()
308 * and setLocalXMLFile(), instead of this function.
309 * \note Just like setXMLFile(), this function has to be called before
310 * the client is added to a KXMLGUIFactory in order to have an
311 * effect.
312 *
313 * \sa setLocalXMLFile()
314 * \since 4.4
315 */
316 void replaceXMLFile(const QString &xmlfile, const QString &localxmlfile, bool merge = false);
317
318 /*!
319 * \brief Returns the version number of the given \a xml data
320 * belonging to an XML rc file.
321 *
322 * \since 5.73
323 */
324 static QString findVersionNumber(const QString &xml);
325
326protected:
327 /*!
328 * \brief Sets the component name for this part.
329 *
330 * Call this first in the inherited class constructor
331 * (at least before setXMLFile()).
332 *
333 * \a componentName The name of the directory where the XMLGUI files will be found.
334 *
335 * \a componentDisplayName A user-visible name (e.g. for the toolbar editor).
336 */
337 virtual void setComponentName(const QString &componentName, const QString &componentDisplayName);
338
339 /*!
340 * \brief Sets the name of the rc \a file containing the XML for the part.
341 *
342 * Call this in the inherited class constructor, for parts and plugins.
343 * \note For mainwindows, don't call this, pass the name of the xml file
344 * to KXmlGuiWindow::setupGUI() or KXmlGuiWindow::createGUI().
345 *
346 * \a file Either an absolute path for the file, or simply the filename.
347 * See below for details.
348 * If you pass an absolute path here, make sure to also call
349 * setLocalXMLFile, otherwise toolbar editing won't work.
350 *
351 * \a merge Whether to merge with the global document.
352 *
353 * \a setXMLDoc Specify whether to call setXML. Default is true.
354 *
355 * The preferred way to call this method is with a simple filename
356 * for the \a file argument.
357 *
358 * Since 5.1, the file will then be assumed to be installed in
359 * DATADIR/kxmlgui5/, under a directory named after the component name.
360 * You should use ${KDE_INSTALL_KXMLGUIDIR}/componentname in your
361 * CMakeLists.txt file to install the .rc file(s).
362 *
363 * Since 5.4, the file will then be assumed to be installed in a Qt
364 * resource in :/kxmlgui5/, under a directory named after the component name.
365 **/
366 virtual void setXMLFile(const QString &file, bool merge = false, bool setXMLDoc = true);
367
368 /*!
369 * \brief Returns the full path to the ui_standards.rc, always non-empty.
370 *
371 * Might return a resource path.
372 *
373 * \since 5.16
374 */
375 static QString standardsXmlFileLocation();
376
377 /*!
378 * \brief Load the ui_standards.rc file.
379 *
380 * Usually followed by setXMLFile(xmlFile, true) for merging.
381 *
382 * \since 4.6
383 */
384 void loadStandardsXmlFile();
385
386 /*!
387 * \brief Set the full path to the "local" xml \a file used for saving
388 * toolbar and shortcut changes.
389 *
390 * You normally don't need to call this if you pass a simple filename to setXMLFile().
391 */
392 virtual void setLocalXMLFile(const QString &file);
393
394 /*!
395 * \brief Sets the XML \a document for the part and whether to \a merge
396 * with the global document.
397 *
398 * Call this in the Part-inherited class constructor if you
399 * don't call setXMLFile().
400 **/
401 virtual void setXML(const QString &document, bool merge = false);
402
403 /*!
404 * \brief Sets the \a document for the part, describing the layout of the GUI,
405 * and whether to \a merge with the global document.
406 *
407 * Call this in the Part-inherited class constructor if you don't call
408 * setXMLFile() or setXML().
409 *
410 * \warning Using this method is not recommended. Many code paths
411 * lead to reloading from the XML file on disk. And editing toolbars requires
412 * that the result is written to disk anyway, and loaded from there the next time.
413 *
414 * For application-specific changes to a client's XML, it is a better idea to
415 * save the modified dom document to an app/default-client.xml and define a local-xml-file
416 * to something specific like app/local-client.xml, using replaceXMLFile().
417 * See kdepimlibs/kontactinterface/plugin.cpp for an example.
418 */
419 virtual void setDOMDocument(const QDomDocument &document, bool merge = false);
420
421 /*!
422 * \brief Emitted when an action has changed state to \a newstate.
423 *
424 * Actions can collectively be assigned a "State". To accomplish this
425 * the respective actions are tagged as <enable> or <disable> in
426 * a <State> </State> group of the XMLfile. During program execution the
427 * programmer can call stateChanged() to set actions to a defined state.
428 *
429 * \a newstate Name of a State in the XMLfile.
430 *
431 * \a reverse If the \a reverse flag is set to StateReverse, the State is reversed
432 * (actions to be enabled will be disabled and action to be disabled will be enabled).
433 */
434 virtual void stateChanged(const QString &newstate, ReverseStateChange reverse = StateNoReverse);
435
436 // KDE5 TODO: virtual void loadActionLists() {}, called when the guiclient is added to the xmlgui factory
437
438protected:
439 virtual void virtual_hook(int id, void *data);
440
441private:
442 std::unique_ptr<KXMLGUIClientPrivate> const d;
443};
444
445#endif
446

source code of kxmlgui/src/kxmlguiclient.h