File indexing completed on 2024-04-21 15:05:54

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 1999 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 kxmlguifactory_h
0010 #define kxmlguifactory_h
0011 
0012 #include <kxmlgui_export.h>
0013 
0014 #include <QObject>
0015 #include <memory>
0016 
0017 class QAction;
0018 class KXMLGUIFactoryPrivate;
0019 class KXMLGUIClient;
0020 class KXMLGUIBuilder;
0021 
0022 class QDomAttr;
0023 class QDomDocument;
0024 class QDomElement;
0025 class QDomNode;
0026 class QDomNamedNodeMap;
0027 
0028 namespace KXMLGUI
0029 {
0030 struct MergingIndex;
0031 struct ContainerNode;
0032 struct ContainerClient;
0033 class BuildHelper;
0034 }
0035 
0036 /**
0037  * @class KXMLGUIFactory kxmlguifactory.h KXMLGUIFactory
0038  *
0039  * KXMLGUIFactory, together with KXMLGUIClient objects, can be used to create
0040  * a GUI of container widgets (like menus, toolbars, etc.) and container items
0041  * (menu items, toolbar buttons, etc.) from an XML document and action objects.
0042  *
0043  * Each KXMLGUIClient represents a part of the GUI, composed from containers and
0044  * actions. KXMLGUIFactory takes care of building (with the help of a KXMLGUIBuilder)
0045  * and merging the GUI from an unlimited number of clients.
0046  *
0047  * Each client provides XML through a QDomDocument and actions through a
0048  * KActionCollection . The XML document contains the rules for how to merge the
0049  * GUI.
0050  *
0051  * KXMLGUIFactory processes the DOM tree provided by a client and plugs in the client's actions,
0052  * according to the XML and the merging rules of previously inserted clients. Container widgets
0053  * are built via a KXMLGUIBuilder , which has to be provided with the KXMLGUIFactory constructor.
0054  */
0055 class KXMLGUI_EXPORT KXMLGUIFactory : public QObject
0056 {
0057     friend class KXMLGUI::BuildHelper;
0058     Q_OBJECT
0059 public:
0060     /**
0061      * Constructs a KXMLGUIFactory. The provided @p builder KXMLGUIBuilder will be called
0062      * for creating and removing container widgets, when clients are added/removed from the GUI.
0063      *
0064      * Note that the ownership of the given KXMLGUIBuilder object won't be transferred to this
0065      * KXMLGUIFactory, so you have to take care of deleting it properly.
0066      */
0067     explicit KXMLGUIFactory(KXMLGUIBuilder *builder, QObject *parent = nullptr);
0068 
0069     /**
0070      * Destructor
0071      */
0072     ~KXMLGUIFactory() override;
0073 
0074     // XXX move to somewhere else? (Simon)
0075     /// @internal
0076     static QString readConfigFile(const QString &filename, const QString &componentName = QString());
0077     /// @internal
0078     static bool saveConfigFile(const QDomDocument &doc, const QString &filename, const QString &componentName = QString());
0079 
0080     /**
0081      * @internal
0082      * Find or create the ActionProperties element, used when saving custom action properties
0083      */
0084     static QDomElement actionPropertiesElement(QDomDocument &doc);
0085 
0086     /**
0087      * @internal
0088      * Find or create the element for a given action, by name.
0089      * Used when saving custom action properties
0090      */
0091     static QDomElement findActionByName(QDomElement &elem, const QString &sName, bool create);
0092 
0093     /**
0094      * Creates the GUI described by the QDomDocument of the client,
0095      * using the client's actions, and merges it with the previously
0096      * created GUI.
0097      * This also means that the order in which clients are added to the factory
0098      * is relevant; assuming that your application supports plugins, you should
0099      * first add your application to the factory and then the plugin, so that the
0100      * plugin's UI is merged into the UI of your application, and not the other
0101      * way round.
0102      */
0103     void addClient(KXMLGUIClient *client);
0104 
0105     /**
0106      * Removes the GUI described by the client, by unplugging all
0107      * provided actions and removing all owned containers (and storing
0108      * container state information in the given client)
0109      */
0110     void removeClient(KXMLGUIClient *client);
0111 
0112     void plugActionList(KXMLGUIClient *client, const QString &name, const QList<QAction *> &actionList);
0113     void unplugActionList(KXMLGUIClient *client, const QString &name);
0114 
0115     /**
0116      * Returns a list of all clients currently added to this factory
0117      */
0118     QList<KXMLGUIClient *> clients() const;
0119 
0120     /**
0121      * Use this method to get access to a container widget with the name specified with @p containerName
0122      * and which is owned by the @p client. The container name is specified with a "name" attribute in the
0123      * XML document.
0124      *
0125      * This function is particularly useful for getting hold of a popupmenu defined in an XMLUI file.
0126      * For instance:
0127      * \code
0128      * QMenu *popup = static_cast<QMenu*>(guiFactory()->container("my_popup",this));
0129      * \endcode
0130      * where @p "my_popup" is the name of the menu in the XMLUI file, and
0131      * @p "this" is XMLGUIClient which owns the popupmenu (e.g. the mainwindow, or the part, or the plugin...)
0132      *
0133      * @param containerName Name of the container widget
0134      * @param client Owner of the container widget
0135      * @param useTagName Specifies whether to compare the specified name with the name attribute or
0136      *        the tag name.
0137      *
0138      * This method may return nullptr if no container with the given name exists or is not owned by the client.
0139      */
0140     QWidget *container(const QString &containerName, KXMLGUIClient *client, bool useTagName = false);
0141 
0142     QList<QWidget *> containers(const QString &tagName);
0143 
0144     /**
0145      * Use this method to free all memory allocated by the KXMLGUIFactory. This deletes the internal node
0146      * tree and therefore resets the internal state of the class. Please note that the actual GUI is
0147      * NOT touched at all, meaning no containers are deleted nor any actions unplugged. That is
0148      * something you have to do on your own. So use this method only if you know what you are doing :-)
0149      *
0150      * (also note that this will call KXMLGUIClient::setFactory(nullptr) for all inserted clients)
0151      */
0152     void reset();
0153 
0154     /**
0155      * Use this method to free all memory allocated by the KXMLGUIFactory for a specific container,
0156      * including all child containers and actions. This deletes the internal node subtree for the
0157      * specified container. The actual GUI is not touched, no containers are deleted or any actions
0158      * unplugged. Use this method only if you know what you are doing :-)
0159      *
0160      * (also note that this will call KXMLGUIClient::setFactory(nullptr) for all clients of the
0161      * container)
0162      */
0163     void resetContainer(const QString &containerName, bool useTagName = false);
0164 
0165     /**
0166      * Use this method to reset and reread action properties (shortcuts, etc.) for all actions.
0167      * This is needed, for example, when you change shortcuts scheme at runtime.
0168      */
0169     void refreshActionProperties();
0170 
0171 public Q_SLOTS:
0172 #if KXMLGUI_ENABLE_DEPRECATED_SINCE(5, 84)
0173     /**
0174      * Shows a dialog (KShortcutsDialog) that lists every action in this factory,
0175      * and which can be used to change the shortcuts associated with each action.
0176      *
0177      * This slot can be connected directly to the action to configure shortcuts.
0178      * This is very simple to do, for example:
0179      * @code
0180      * KStandardAction::keyBindings(guiFactory(), SLOT(configureShortcuts()), actionCollection());
0181      * @endcode
0182      * Or if you want to use the pointer-to-member-function signal/slot syntax
0183      * (which is generally preferred as it has compile-time type checking) you
0184      * can use:
0185      * @code
0186      * auto shortcutsSlot = [this]() {
0187      *     guiFactory()->configureShortcuts();
0188      * };
0189      * KStandardAction::keyBindings(guiFactory(), shortcutsSlot, actionCollection());
0190      *
0191      * // Alternatively, since 5.84, you can use:
0192      * KStandardAction::keyBindings(guiFactory(), &KXMLGUIFactory::showConfigureShortcutsDialog, actionCollection());
0193      * @endcode
0194      *
0195      * @param bAllowLetterShortcuts Set to @c false if unmodified alphanumeric keys
0196      * ('A', '1', etc.) are not permissible shortcuts; defaults to @c true
0197      * @param bSaveSettings if @c true, the settings will also be saved back to
0198      * the @c *ui.rc file which they were initially read from; defaults to @c true
0199      *
0200      * @deprecated since 5.84, use @ref KXMLGUIFactory::showConfigureShortcutsDialog() instead.
0201      * If your code checked the return value of this method (e.g. to run some extra code if the
0202      * dialog was accepted), you can port that code by connecting to the @c shortcutsSaved()
0203      * signal before calling @c showConfigureShortcutsDialog() (see the latter's API docs for
0204      * a code example).
0205      */
0206     KXMLGUI_DEPRECATED_VERSION(5, 84, "Use KXMLGUIFactory::showConfigureShortcutsDialog() instead.")
0207     int configureShortcuts(bool bAllowLetterShortcuts = true, bool bSaveSettings = true);
0208 #endif
0209 
0210     /**
0211      * Shows a dialog (KShortcutsDialog) that lists every action in this factory,
0212      * and which can be used to change the shortcuts associated with each action.
0213      *
0214      * This slot can be connected directly to the configure shortcuts action,
0215      * for example:
0216      * @code
0217      * KStandardAction::keyBindings(guiFactory(), &KXMLGUIFactory::showConfigureShortcutsDialog, actionCollection());
0218      * @endcode
0219      *
0220      * This method constructs a KShortcutsDialog with the default arguments
0221      * (KShortcutsEditor::AllActions and KShortcutsEditor::LetterShortcutsAllowed).
0222      *
0223      * @see KShortcutsDialog, KShortcutsEditor::ActionTypes, KShortcutsEditor::LetterShortcuts
0224      *
0225      * By default the changes will be saved back to the @c *ui.rc file
0226      * which they were initially read from.
0227      *
0228      * If you need to run some extra code if the dialog is accepted and the settings
0229      * are saved, you can simply connect to the @ref KXMLGUIFactory::shortcutsSaved()
0230      * signal before calling this method, for example:
0231      * @code
0232      * connect(guiFactory(), &KXMLGUIFactory::shortcutsSaved, this, &MyClass::slotShortcutSaved);
0233      * guiFactory()->showConfigureShortcutsDialog();
0234      * @endcode
0235      *
0236      * @since 5.84
0237      */
0238     void showConfigureShortcutsDialog();
0239 
0240     void changeShortcutScheme(const QString &scheme);
0241 
0242 Q_SIGNALS:
0243     void clientAdded(KXMLGUIClient *client);
0244     void clientRemoved(KXMLGUIClient *client);
0245 
0246     /**
0247      * Emitted when the factory is currently making changes to the GUI,
0248      * i.e. adding or removing clients.
0249      * makingChanges(true) is emitted before any change happens, and
0250      * makingChanges(false) is emitted after the change is done.
0251      * This allows e.g. KMainWindow to know that the GUI is
0252      * being changed programmatically and not by the user (so there is no reason to
0253      * save toolbar settings afterwards).
0254      * @since 4.1.3
0255      */
0256     void makingChanges(bool);
0257 
0258     /**
0259      * Emitted when the shortcuts have been saved (i.e. the user accepted the dialog).
0260      *
0261      * If you're using multiple instances of the same KXMLGUIClient, you probably want to
0262      * connect to this signal and call @c KXMLGUIClient::reloadXML() for each of your
0263      * KXMLGUIClients, so that the other instances update their shortcuts settings.
0264      *
0265      * @since 5.79
0266      */
0267     void shortcutsSaved();
0268 
0269 private:
0270     /// Internal, called by KXMLGUIClient destructor
0271     KXMLGUI_NO_EXPORT void forgetClient(KXMLGUIClient *client);
0272 
0273 private:
0274     friend class KXMLGUIClient;
0275     std::unique_ptr<KXMLGUIFactoryPrivate> const d;
0276 };
0277 
0278 #endif