| 1 | /* |
| 2 | This file is part of the KDE libraries |
| 3 | SPDX-FileCopyrightText: 1999 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 kxmlguifactory_h |
| 10 | #define kxmlguifactory_h |
| 11 | |
| 12 | #include <kxmlgui_export.h> |
| 13 | |
| 14 | #include <QObject> |
| 15 | #include <memory> |
| 16 | |
| 17 | class QAction; |
| 18 | class KXMLGUIFactoryPrivate; |
| 19 | class KXMLGUIClient; |
| 20 | class KXMLGUIBuilder; |
| 21 | |
| 22 | class QDomAttr; |
| 23 | class QDomDocument; |
| 24 | class QDomElement; |
| 25 | class QDomNode; |
| 26 | class QDomNamedNodeMap; |
| 27 | |
| 28 | namespace KXMLGUI |
| 29 | { |
| 30 | struct MergingIndex; |
| 31 | struct ContainerNode; |
| 32 | struct ContainerClient; |
| 33 | class BuildHelper; |
| 34 | } |
| 35 | |
| 36 | /*! |
| 37 | * \class KXMLGUIFactory |
| 38 | * \inmodule KXmlGui |
| 39 | * |
| 40 | * KXMLGUIFactory, together with KXMLGUIClient objects, can be used to create |
| 41 | * a GUI of container widgets (like menus, toolbars, etc.) and container items |
| 42 | * (menu items, toolbar buttons, etc.) from an XML document and action objects. |
| 43 | * |
| 44 | * Each KXMLGUIClient represents a part of the GUI, composed from containers and |
| 45 | * actions. KXMLGUIFactory takes care of building (with the help of a KXMLGUIBuilder) |
| 46 | * and merging the GUI from an unlimited number of clients. |
| 47 | * |
| 48 | * Each client provides XML through a QDomDocument and actions through a |
| 49 | * KActionCollection . The XML document contains the rules for how to merge the |
| 50 | * GUI. |
| 51 | * |
| 52 | * KXMLGUIFactory processes the DOM tree provided by a client and plugs in the client's actions, |
| 53 | * according to the XML and the merging rules of previously inserted clients. Container widgets |
| 54 | * are built via a KXMLGUIBuilder , which has to be provided with the KXMLGUIFactory constructor. |
| 55 | */ |
| 56 | class KXMLGUI_EXPORT KXMLGUIFactory : public QObject |
| 57 | { |
| 58 | friend class KXMLGUI::BuildHelper; |
| 59 | Q_OBJECT |
| 60 | public: |
| 61 | /*! |
| 62 | * \brief Constructs a KXMLGUIFactory. |
| 63 | * |
| 64 | * The provided \a builder KXMLGUIBuilder with the given \a parent will be called |
| 65 | * for creating and removing container widgets when clients are added/removed from the GUI. |
| 66 | * |
| 67 | * Note that the ownership of the given KXMLGUIBuilder object won't be transferred to this |
| 68 | * KXMLGUIFactory, so you have to take care of deleting it properly. |
| 69 | */ |
| 70 | explicit KXMLGUIFactory(KXMLGUIBuilder *builder, QObject *parent = nullptr); |
| 71 | |
| 72 | /*! |
| 73 | * \brief Destructor. |
| 74 | */ |
| 75 | ~KXMLGUIFactory() override; |
| 76 | |
| 77 | // XXX move to somewhere else? (Simon) |
| 78 | /// \internal |
| 79 | static QString readConfigFile(const QString &filename, const QString &componentName = QString()); |
| 80 | /// \internal |
| 81 | static bool saveConfigFile(const QDomDocument &doc, const QString &filename, const QString &componentName = QString()); |
| 82 | |
| 83 | /*! |
| 84 | * \internal |
| 85 | * Find or create the ActionProperties element, used when saving custom action properties |
| 86 | */ |
| 87 | static QDomElement actionPropertiesElement(QDomDocument &doc); |
| 88 | |
| 89 | /*! |
| 90 | * \internal |
| 91 | * Find or create the element for a given action, by name. |
| 92 | * Used when saving custom action properties |
| 93 | */ |
| 94 | static QDomElement findActionByName(QDomElement &elem, const QString &sName, bool create); |
| 95 | |
| 96 | /*! |
| 97 | * \brief Creates the GUI described by the QDomDocument of the \a client, |
| 98 | * using the client's actions, and merges it with the previously |
| 99 | * created GUI. |
| 100 | * |
| 101 | * This also means that the order in which clients are added to the factory |
| 102 | * is relevant; assuming that your application supports plugins, you should |
| 103 | * first add your application to the factory and then the plugin, so that the |
| 104 | * plugin's UI is merged into the UI of your application, and not the other |
| 105 | * way round. |
| 106 | */ |
| 107 | void addClient(KXMLGUIClient *client); |
| 108 | |
| 109 | /*! |
| 110 | * \brief Removes the GUI described by the \a client by unplugging all |
| 111 | * provided actions and removing all owned containers (and storing |
| 112 | * container state information in the given client). |
| 113 | */ |
| 114 | void removeClient(KXMLGUIClient *client); |
| 115 | |
| 116 | void plugActionList(KXMLGUIClient *client, const QString &name, const QList<QAction *> &actionList); |
| 117 | void unplugActionList(KXMLGUIClient *client, const QString &name); |
| 118 | |
| 119 | /*! |
| 120 | * \brief Returns a list of all clients currently added to this factory. |
| 121 | */ |
| 122 | QList<KXMLGUIClient *> clients() const; |
| 123 | |
| 124 | /*! |
| 125 | * \brief Use this method to get access to a container widget with the |
| 126 | * name specified with \a containerName that is owned by the \a client. |
| 127 | * |
| 128 | * The container name is specified with a "name" attribute in the |
| 129 | * XML document. |
| 130 | * |
| 131 | * This function is particularly useful for getting hold of a popupmenu |
| 132 | * defined in an XMLUI file. |
| 133 | * |
| 134 | * For instance: |
| 135 | * \code |
| 136 | * QMenu *popup = static_cast<QMenu*>(guiFactory()->container("my_popup",this)); |
| 137 | * \endcode |
| 138 | * Where "my_popup" is the name of the menu in the XMLUI file, and |
| 139 | * "this" is XMLGUIClient which owns the popupmenu (e.g. the mainwindow, or the part, or the plugin...). |
| 140 | * |
| 141 | * \a containerName The name of the container widget. |
| 142 | * |
| 143 | * \a client Owner of the container widget. |
| 144 | * |
| 145 | * \a useTagName Whether to compare the specified name with the name attribute |
| 146 | * or the tag name. |
| 147 | * |
| 148 | * This method may return nullptr if no container with the given name |
| 149 | * exists or if the container is not owned by the client. |
| 150 | */ |
| 151 | QWidget *container(const QString &containerName, KXMLGUIClient *client, bool useTagName = false); |
| 152 | |
| 153 | QList<QWidget *> containers(const QString &tagName); |
| 154 | |
| 155 | /*! |
| 156 | * \brief Use this method to free all memory allocated by the KXMLGUIFactory. |
| 157 | * |
| 158 | * This deletes the internal node tree and therefore resets the |
| 159 | * internal state of the class. Please note that the actual GUI is |
| 160 | * NOT touched at all, meaning no containers are deleted nor any |
| 161 | * actions unplugged. That is something you have to do on your own. |
| 162 | * So use this method only if you know what you are doing :-) |
| 163 | * |
| 164 | * \note This will call KXMLGUIClient::setFactory(nullptr) for all inserted clients). |
| 165 | */ |
| 166 | void reset(); |
| 167 | |
| 168 | /*! |
| 169 | * \brief Free all memory allocated by the KXMLGUIFactory for a container |
| 170 | * named \a containerName, including all child containers and actions. |
| 171 | * |
| 172 | * Additionally, you may set whether to compare the specified \a containerName |
| 173 | * with the name attribute or the tag name. |
| 174 | * |
| 175 | * This deletes the internal node subtree for the specified container. |
| 176 | * The actual GUI is not touched, no containers are deleted |
| 177 | * or any actions unplugged. |
| 178 | * |
| 179 | * Use this method only if you know what you are doing :-) |
| 180 | * |
| 181 | * \a useTagName Whether to compare the specified name with the name attribute. |
| 182 | * |
| 183 | * \note This will call KXMLGUIClient::setFactory(nullptr) for all clients of the |
| 184 | * container). |
| 185 | */ |
| 186 | void resetContainer(const QString &containerName, bool useTagName = false); |
| 187 | |
| 188 | /*! |
| 189 | * \brief Use this method to reset and reread action properties |
| 190 | * (shortcuts, etc.) for all actions. |
| 191 | * |
| 192 | * This is needed, for example, when you change shortcuts scheme at runtime. |
| 193 | */ |
| 194 | void refreshActionProperties(); |
| 195 | |
| 196 | public Q_SLOTS: |
| 197 | /*! |
| 198 | * \brief Shows a dialog (KShortcutsDialog) that lists every action in this factory, |
| 199 | * and that can be used to change the shortcuts associated with each action. |
| 200 | * |
| 201 | * This slot can be connected directly to the configure shortcuts action, |
| 202 | * for example: |
| 203 | * \code |
| 204 | * KStandardAction::keyBindings(guiFactory(), &KXMLGUIFactory::showConfigureShortcutsDialog, actionCollection()); |
| 205 | * \endcode |
| 206 | * |
| 207 | * This method constructs a KShortcutsDialog with the default arguments |
| 208 | * (KShortcutsEditor::AllActions and KShortcutsEditor::LetterShortcutsAllowed). |
| 209 | * |
| 210 | * By default the changes will be saved back to the \c *ui.rc file |
| 211 | * they were initially read from. |
| 212 | * |
| 213 | * If you need to run some extra code if the dialog is accepted and the settings |
| 214 | * are saved, you can simply connect to the \l KXMLGUIFactory::shortcutsSaved() |
| 215 | * signal before calling this method, for example: |
| 216 | * \code |
| 217 | * connect(guiFactory(), &KXMLGUIFactory::shortcutsSaved, this, &MyClass::slotShortcutSaved); |
| 218 | * guiFactory()->showConfigureShortcutsDialog(); |
| 219 | * \endcode |
| 220 | * |
| 221 | * \sa KShortcutsDialog, KShortcutsEditor::ActionTypes, KShortcutsEditor::LetterShortcuts |
| 222 | * \since 5.84 |
| 223 | */ |
| 224 | void showConfigureShortcutsDialog(); |
| 225 | |
| 226 | void changeShortcutScheme(const QString &scheme); |
| 227 | |
| 228 | Q_SIGNALS: |
| 229 | void clientAdded(KXMLGUIClient *client); |
| 230 | void clientRemoved(KXMLGUIClient *client); |
| 231 | |
| 232 | /*! |
| 233 | * \brief Emitted when the factory is currently making changes to the GUI, |
| 234 | * i.e. adding or removing clients. |
| 235 | * |
| 236 | * makingChanges(true) is emitted before any change happens, and |
| 237 | * makingChanges(false) is emitted after the change is done. |
| 238 | * |
| 239 | * This allows e.g. KMainWindow to know that the GUI is |
| 240 | * being changed programmatically and not by the user (so there is no reason to |
| 241 | * save toolbar settings afterwards). |
| 242 | * \since 4.1.3 |
| 243 | */ |
| 244 | void makingChanges(bool); |
| 245 | |
| 246 | /*! |
| 247 | * \brief Emitted when the shortcuts have been saved (i.e. the user accepted the dialog). |
| 248 | * |
| 249 | * If you're using multiple instances of the same KXMLGUIClient, you probably want to |
| 250 | * connect to this signal and call \c KXMLGUIClient::reloadXML() for each of your |
| 251 | * KXMLGUIClients, so that the other instances update their shortcuts settings. |
| 252 | * |
| 253 | * \since 5.79 |
| 254 | */ |
| 255 | void shortcutsSaved(); |
| 256 | |
| 257 | private: |
| 258 | /// Internal, called by KXMLGUIClient destructor |
| 259 | KXMLGUI_NO_EXPORT void forgetClient(KXMLGUIClient *client); |
| 260 | |
| 261 | private: |
| 262 | friend class KXMLGUIClient; |
| 263 | std::unique_ptr<KXMLGUIFactoryPrivate> const d; |
| 264 | }; |
| 265 | |
| 266 | #endif |
| 267 | |