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 | |
17 | class QDomDocument; |
18 | class QDomElement; |
19 | class QWidget; |
20 | |
21 | class QAction; |
22 | class KActionCollection; |
23 | class KXMLGUIClientPrivate; |
24 | class KXMLGUIFactory; |
25 | class KXMLGUIBuilder; |
26 | |
27 | namespace KDEPrivate |
28 | { |
29 | class 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 | */ |
40 | class KXMLGUI_EXPORT KXMLGUIClient |
41 | { |
42 | friend class KDEPrivate::KEditToolBarWidget; // for setXMLFile(3 args) |
43 | public: |
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 | |
326 | protected: |
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 | |
438 | protected: |
439 | virtual void virtual_hook(int id, void *data); |
440 | |
441 | private: |
442 | std::unique_ptr<KXMLGUIClientPrivate> const d; |
443 | }; |
444 | |
445 | #endif |
446 | |