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

source code of kxmlgui/src/kxmlguiclient.h