File indexing completed on 2024-04-14 14:30:05

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2000 Simon Hausmann <hausmann@kde.org>
0004     SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #ifndef KXMLGUICLIENT_H
0010 #define KXMLGUICLIENT_H
0011 
0012 #include <kxmlgui_export.h>
0013 
0014 #include <QStringList>
0015 #include <memory>
0016 
0017 class QDomDocument;
0018 class QDomElement;
0019 class QWidget;
0020 
0021 class QAction;
0022 class KActionCollection;
0023 class KXMLGUIClientPrivate;
0024 class KXMLGUIFactory;
0025 class KXMLGUIBuilder;
0026 
0027 namespace KDEPrivate
0028 {
0029 class KEditToolBarWidget;
0030 }
0031 
0032 /**
0033  * @class KXMLGUIClient kxmlguiclient.h KXMLGUIClient
0034  *
0035  * A KXMLGUIClient can be used with KXMLGUIFactory to create a
0036  * GUI from actions and an XML document, and can be dynamically merged
0037  * with other KXMLGUIClients.
0038  */
0039 class KXMLGUI_EXPORT KXMLGUIClient
0040 {
0041     friend class KDEPrivate::KEditToolBarWidget; // for setXMLFile(3 args)
0042 public:
0043     /**
0044      * Constructs a KXMLGUIClient which can be used with a
0045      * KXMLGUIFactory to create a GUI from actions and an XML document, and
0046      * which can be dynamically merged with other KXMLGUIClients.
0047      */
0048     KXMLGUIClient();
0049 
0050     /**
0051      * Constructs a KXMLGUIClient which can be used with a KXMLGUIFactory
0052      * to create a GUI from actions and an XML document,
0053      * and which can be dynamically merged with other KXMLGUIClients.
0054      *
0055      * This constructor takes an additional @p parent argument, which makes
0056      * the client a child client of the parent.
0057      *
0058      * Child clients are automatically added to the GUI if the parent is added.
0059      *
0060      */
0061     explicit KXMLGUIClient(KXMLGUIClient *parent);
0062 
0063     /**
0064      * Destructs the KXMLGUIClient.
0065      *
0066      * If the client was in a factory, the factory is NOT informed about the client
0067      * being removed. This is a feature, it makes window destruction fast (the xmlgui
0068      * is not updated for every client being deleted), but if you want to simply remove
0069      * one client and to keep using the window, make sure to call factory->removeClient(client)
0070      * before deleting the client.
0071      */
0072     virtual ~KXMLGUIClient();
0073 
0074     /**
0075      * Retrieves an action of the client by name.  If not found, it looks in its child clients.
0076      * This method is provided for convenience, as it uses actionCollection()
0077      * to get the action object.
0078      */
0079     QAction *action(const char *name) const;
0080 
0081     /**
0082      * Retrieves an action for a given QDomElement. The default
0083      * implementation uses the "name" attribute to query the action
0084      * object via the other action() method.
0085      */
0086     virtual QAction *action(const QDomElement &element) const;
0087 
0088     /**
0089      * Retrieves the entire action collection for the GUI client.
0090      */
0091     virtual KActionCollection *actionCollection() const;
0092 
0093     /**
0094      * @return The component name for this GUI client.
0095      */
0096     virtual QString componentName() const;
0097 
0098     /**
0099      * @return The parsed XML in a QDomDocument, set by
0100      * setXMLFile() or setXML().
0101      * This document describes the layout of the GUI.
0102      */
0103     virtual QDomDocument domDocument() const;
0104 
0105     /**
0106      * This will return the name of the XML file as set by setXMLFile().
0107      * If setXML() is used directly, then this will return an empty string.
0108      *
0109      * The filename that this returns is obvious for components as each
0110      * component has exactly one XML file.  In non-components, however,
0111      * there are usually two: the global file and the local file.  This
0112      * function doesn't really care about that, though.  It will always
0113      * return the last XML file set.  This, in almost all cases, will
0114      * be the local XML file.
0115      *
0116      * @return The name of the XML file or QString()
0117      */
0118     virtual QString xmlFile() const;
0119 
0120     virtual QString localXMLFile() const;
0121 
0122     /**
0123      * @internal
0124      */
0125     void setXMLGUIBuildDocument(const QDomDocument &doc);
0126     /**
0127      * @internal
0128      */
0129     QDomDocument xmlguiBuildDocument() const;
0130 
0131     /**
0132      * This method is called by the KXMLGUIFactory as soon as the client
0133      * is added to the KXMLGUIFactory's GUI.
0134      */
0135     void setFactory(KXMLGUIFactory *factory);
0136     /**
0137      * Retrieves a pointer to the KXMLGUIFactory this client is
0138      * associated with (will return nullptr if the client's GUI has not been built
0139      * by a KXMLGUIFactory.
0140      */
0141     KXMLGUIFactory *factory() const;
0142 
0143     /**
0144      * KXMLGUIClients can form a simple child/parent object tree. This
0145      * method returns a pointer to the parent client or nullptr if it has no
0146      * parent client assigned.
0147      */
0148     KXMLGUIClient *parentClient() const;
0149 
0150     /**
0151      * Use this method to make a client a child client of another client.
0152      * Usually you don't need to call this method, as it is called
0153      * automatically when using the second constructor, which takes a
0154      * parent argument.
0155      */
0156     void insertChildClient(KXMLGUIClient *child);
0157 
0158     /**
0159      * Removes the given @p child from the client's children list.
0160      */
0161     void removeChildClient(KXMLGUIClient *child);
0162 
0163     /**
0164      * Retrieves a list of all child clients.
0165      */
0166     QList<KXMLGUIClient *> childClients();
0167 
0168     /**
0169      * A client can have an own KXMLGUIBuilder.
0170      * Use this method to assign your builder instance to the client (so that the
0171      * KXMLGUIFactory can use it when building the client's GUI)
0172      *
0173      * Client specific guibuilders are useful if you want to create
0174      * custom container widgets for your GUI.
0175      */
0176     void setClientBuilder(KXMLGUIBuilder *builder);
0177 
0178     /**
0179      * Retrieves the client's GUI builder or nullptr if no client specific
0180      * builder has been assigned via setClientBuilder()
0181      */
0182     KXMLGUIBuilder *clientBuilder() const;
0183 
0184     /**
0185      * Forces this client to re-read its XML resource file.  This is
0186      * intended to be used when you know that the resource file has
0187      * changed and you will soon be rebuilding the GUI. This will only have
0188      * an effect if the client is then removed and re-added to the factory.
0189      *
0190      * This method is only for child clients, do not call it for a mainwindow!
0191      * For a mainwindow, use loadStandardsXmlFile + setXmlFile(xmlFile()) instead.
0192      */
0193     void reloadXML();
0194 
0195     /**
0196      * ActionLists are a way for XMLGUI to support dynamic lists of
0197      * actions.  E.g. if you are writing a file manager, and there is a
0198      * menu file whose contents depend on the mimetype of the file that
0199      * is selected, then you can achieve this using ActionLists. It
0200      * works as follows:
0201      * In your xxxui.rc file ( the one that you set in setXMLFile() / pass to setupGUI()
0202      * ), you put a tag <tt>\<ActionList name="xxx"\></tt>.
0203      *
0204      * Example:
0205      * \code
0206      * <gui name="xxx_part" version="1">
0207      * <MenuBar>
0208      *   <Menu name="file">
0209      *     ...  <!-- some useful actions-->
0210      *     <ActionList name="xxx_file_actionlist" />
0211      *     ...  <!-- even more useful actions-->
0212      *   </Menu>
0213      *   ...
0214      * </MenuBar>
0215      * </gui>
0216      * \endcode
0217      *
0218      * This tag will get expanded to a list of actions.  In the example
0219      * above ( a file manager with a dynamic file menu ), you would call
0220      * \code
0221      * QList<QAction*> file_actions;
0222      * for( ... )
0223      *   if( ... )
0224      *     file_actions.append( cool_action );
0225      * unplugActionList( "xxx_file_actionlist" );
0226      * plugActionList( "xxx_file_actionlist", file_actions );
0227      * \endcode
0228      * every time a file is selected, unselected or ...
0229      *
0230      * \note You should not call KXmlGuiWindow::createGUI() after calling this
0231      *       function.  In fact, that would remove the newly added
0232      *       actionlists again...
0233      * \note Forgetting to call unplugActionList() before
0234      *       plugActionList() would leave the previous actions in the
0235      *       menu too..
0236      * \see unplugActionList()
0237      */
0238     void plugActionList(const QString &name, const QList<QAction *> &actionList);
0239 
0240     /**
0241      * Unplugs the action list \p name from the XMLGUI.
0242      * Calling this removes the specified action list, i.e. this is the
0243      * complement to plugActionList(). See plugActionList() for a more
0244      * detailed example.
0245      * \see plugActionList()
0246      */
0247     void unplugActionList(const QString &name);
0248 
0249     static QString findMostRecentXMLFile(const QStringList &files, QString &doc);
0250 
0251     void addStateActionEnabled(const QString &state, const QString &action);
0252 
0253     void addStateActionDisabled(const QString &state, const QString &action);
0254 
0255     enum ReverseStateChange { StateNoReverse, StateReverse };
0256     struct StateChange {
0257         QStringList actionsToEnable;
0258         QStringList actionsToDisable;
0259     };
0260 
0261     StateChange getActionsToChangeForState(const QString &state);
0262 
0263     void beginXMLPlug(QWidget *);
0264     void endXMLPlug();
0265     void prepareXMLUnplug(QWidget *);
0266 
0267     /**
0268      * Sets a new xmlFile() and localXMLFile(). The purpose of this public
0269      * method is to allow non-inherited objects to replace the ui definition
0270      * of an embedded client with a customized version. It corresponds to the
0271      * usual calls to setXMLFile() and setLocalXMLFile().
0272      *
0273      * @param xmlfile The xml file to use. Contrary to setXMLFile(), this
0274      *                must be an absolute file path.
0275      * @param localxmlfile The local xml file to set. This should be the full path
0276      *                    to a writeable file, usually using QStandardPaths::writableLocation.
0277      *                    You can set this to QString(), but no user changes to shortcuts / toolbars
0278      *                    will be possible in this case.
0279      * @param merge Whether to merge with the global document
0280      *
0281      * @note If in any doubt whether you need this or not, use setXMLFile()
0282      *       and setLocalXMLFile(), instead of this function.
0283      * @note Just like setXMLFile(), this function has to be called before
0284      *       the client is added to a KXMLGUIFactory in order to have an
0285      *       effect.
0286      *
0287      * @see setLocalXMLFile()
0288      * @since 4.4
0289      */
0290     void replaceXMLFile(const QString &xmlfile, const QString &localxmlfile, bool merge = false);
0291 
0292     /**
0293      * Returns the version number of the given xml data (belonging to an xml rc file)
0294      *
0295      * @since 5.73
0296      */
0297     static QString findVersionNumber(const QString &xml);
0298 
0299 protected:
0300     /**
0301      * Sets the component name for this part.
0302      *
0303      * Call this first in the inherited class constructor.
0304      * (At least before setXMLFile().)
0305      * @param componentName the name of the directory where the XMLGUI files will be found
0306      * @param componentDisplayName a user-visible name (e.g. for the toolbar editor)
0307      */
0308     virtual void setComponentName(const QString &componentName, const QString &componentDisplayName);
0309 
0310     /**
0311      * Sets the name of the rc file containing the XML for the part.
0312      *
0313      * Call this in the inherited class constructor, for parts and plugins.
0314      * @note For mainwindows, don't call this, pass the name of the xml file
0315      * to KXmlGuiWindow::setupGUI() or KXmlGuiWindow::createGUI().
0316      *
0317      * @param file Either an absolute path for the file, or simply the
0318      *             filename. See below for details.
0319      *             If you pass an absolute path here, make sure to also call
0320      *             setLocalXMLFile, otherwise toolbar editing won't work.
0321      * @param merge Whether to merge with the global document.
0322      * @param setXMLDoc Specify whether to call setXML. Default is true.
0323      *
0324      * The preferred way to call this method is with a simple filename for the @p file argument.
0325      *
0326      * Since KF 5.1, the file will then be assumed to be installed in DATADIR/kxmlgui5/, under a directory
0327      * named after the component name.
0328      * You should use ${KDE_INSTALL_KXMLGUI5DIR}/componentname in your CMakeLists.txt file, to install
0329      * the .rc file(s).
0330      *
0331      * Since KF 5.4, the file will then be assumed to be installed in a Qt resource in :/kxmlgui5/,
0332      * under a directory named after the component name.
0333      *
0334      * Compatibility notes:
0335      * Fallback lookups exist to older locations: DATADIR/componentname/file and DATADIR/file.
0336      * The latter was there so that setXMLFile("componentname/filename") worked (but this was
0337      * undocumented). Do not do this anymore after porting to KDE_INSTALL_KXMLGUI5DIR, use
0338      * setComponentName("componentname") and setXMLFile("filename").
0339      **/
0340     virtual void setXMLFile(const QString &file, bool merge = false, bool setXMLDoc = true);
0341 
0342     /**
0343      * Return the full path to the ui_standards.rc, might return a resource path.
0344      * @return full path to ui_standards.rc, always non-empty.
0345      * @since 5.16
0346      */
0347     static QString standardsXmlFileLocation();
0348 
0349     /**
0350      * Load the ui_standards.rc file. Usually followed by setXMLFile(xmlFile, true), for merging.
0351      * @since 4.6
0352      */
0353     void loadStandardsXmlFile();
0354 
0355     /**
0356      * Set the full path to the "local" xml file, the one used for saving
0357      * toolbar and shortcut changes. You normally don't need to call this,
0358      * if you pass a simple filename to setXMLFile.
0359      */
0360     virtual void setLocalXMLFile(const QString &file);
0361 
0362     /**
0363      * Sets the XML for the part.
0364      *
0365      * Call this in the Part-inherited class constructor if you
0366      *  don't call setXMLFile().
0367      **/
0368     virtual void setXML(const QString &document, bool merge = false);
0369 
0370     /**
0371      * Sets the Document for the part, describing the layout of the GUI.
0372      *
0373      * Call this in the Part-inherited class constructor if you don't call
0374      * setXMLFile() or setXML().
0375      *
0376      * @warning Using this method is not recommended. Many code paths
0377      * lead to reloading from the XML file on disk. And editing toolbars requires
0378      * that the result is written to disk anyway, and loaded from there the next time.
0379      *
0380      * For application-specific changes to a client's XML, it is a better idea to
0381      * save the modified dom document to an app/default-client.xml and define a local-xml-file
0382      * to something specific like app/local-client.xml, using replaceXMLFile().
0383      * See kdepimlibs/kontactinterface/plugin.cpp for an example.
0384      */
0385     virtual void setDOMDocument(const QDomDocument &document, bool merge = false);
0386 
0387     /**
0388      * Actions can collectively be assigned a "State". To accomplish this
0389      * the respective actions are tagged as \<enable\> or \<disable\> in
0390      * a \<State\> \</State\> group of the XMLfile. During program execution the
0391      * programmer can call stateChanged() to set actions to a defined state.
0392      *
0393      * @param newstate Name of a State in the XMLfile.
0394      * @param reverse If the flag reverse is set to StateReverse, the State is reversed.
0395      * (actions to be enabled will be disabled and action to be disabled will be enabled)
0396      * Default is reverse=false.
0397      */
0398     virtual void stateChanged(const QString &newstate, ReverseStateChange reverse = StateNoReverse);
0399 
0400     // KDE5 TODO: virtual void loadActionLists() {}, called when the guiclient is added to the xmlgui factory
0401 
0402 protected:
0403     virtual void virtual_hook(int id, void *data);
0404 
0405 private:
0406     // TODO  Post KF 5.79 make std::unique_ptr, when there is a Konsole released with bug:432421 fixed
0407     // std::unique_ptr<KXMLGUIClientPrivate> const d;
0408     KXMLGUIClientPrivate *const d;
0409 };
0410 
0411 #endif