| 1 | /* |
| 2 | This file is part of the KDE libraries |
| 3 | SPDX-FileCopyrightText: 2001 Simon Hausmann <hausmann@kde.org> |
| 4 | |
| 5 | SPDX-License-Identifier: LGPL-2.0-or-later |
| 6 | */ |
| 7 | |
| 8 | #ifndef kxmlguifactory_p_h |
| 9 | #define kxmlguifactory_p_h |
| 10 | |
| 11 | #include <QAction> |
| 12 | #include <QDebug> |
| 13 | #include <QDomElement> |
| 14 | #include <QMap> |
| 15 | #include <QStack> |
| 16 | #include <QStringList> |
| 17 | |
| 18 | class QWidget; |
| 19 | class KXMLGUIClient; |
| 20 | class KXMLGUIBuilder; |
| 21 | |
| 22 | namespace KXMLGUI |
| 23 | { |
| 24 | struct BuildState; |
| 25 | |
| 26 | class ActionList : public QList<QAction *> |
| 27 | { |
| 28 | public: |
| 29 | ActionList() |
| 30 | { |
| 31 | } |
| 32 | ActionList(const QList<QAction *> &rhs) |
| 33 | : QList<QAction *>(rhs) |
| 34 | { |
| 35 | } |
| 36 | ActionList &operator=(const QList<QAction *> &rhs) |
| 37 | { |
| 38 | QList<QAction *>::operator=(rhs); |
| 39 | return *this; |
| 40 | } |
| 41 | |
| 42 | void plug(QWidget *container, int index) const; |
| 43 | }; |
| 44 | |
| 45 | typedef QMap<QString, ActionList> ActionListMap; |
| 46 | |
| 47 | /* |
| 48 | * This structure is used to know to which client certain actions and custom elements |
| 49 | * (i.e. menu separators) belong. |
| 50 | * We do not only use a ContainerClient per GUIClient but also per merging group. |
| 51 | * |
| 52 | * groupName : Used for grouped merging. Specifies the group name to which these actions/elements |
| 53 | * belong to. |
| 54 | * actionLists : maps from action list name to action list. |
| 55 | * mergingName : The (named) merging point. |
| 56 | * |
| 57 | * A ContainerClient always belongs to a ContainerNode. |
| 58 | */ |
| 59 | struct ContainerClient { |
| 60 | KXMLGUIClient *client; |
| 61 | ActionList actions; |
| 62 | QList<QAction *> customElements; |
| 63 | QString groupName; // is empty if no group client |
| 64 | ActionListMap actionLists; |
| 65 | QString mergingName; |
| 66 | }; |
| 67 | typedef QList<ContainerClient *> ContainerClientList; |
| 68 | |
| 69 | struct ContainerNode; |
| 70 | |
| 71 | struct MergingIndex { |
| 72 | int value; // the actual index value, used as index for plug() or createContainer() calls |
| 73 | QString mergingName; // the name of the merging index (i.e. the name attribute of the |
| 74 | // Merge or DefineGroup tag) |
| 75 | QString clientName; // the name of the client that defined this index |
| 76 | }; |
| 77 | typedef QList<MergingIndex> MergingIndexList; |
| 78 | |
| 79 | /* |
| 80 | * Here we store detailed information about a container, its clients (client=a guiclient having actions |
| 81 | * plugged into the container), child nodes, naming information (tagname and name attribute) and |
| 82 | * merging index information, to plug/insert new actions/items a the correct position. |
| 83 | * |
| 84 | * The builder variable is needed for using the proper GUIBuilder for destruction ( to use the same for |
| 85 | * con- and destruction ). The builderCustomTags and builderContainerTags variables are cached values |
| 86 | * of what the corresponding methods of the GUIBuilder which built the container return. The stringlists |
| 87 | * is shared all over the place, so there's no need to worry about memory consumption for these |
| 88 | * variables :-) |
| 89 | * |
| 90 | * The mergingIndices list contains the merging indices ;-) , as defined by <Merge>, <DefineGroup> |
| 91 | * or by <ActionList> tags. The order of these index structures within the mergingIndices list |
| 92 | * is (and has to be) identical with the order in the DOM tree. |
| 93 | * |
| 94 | * Beside the merging indices we have the "real" index of the container. It points to the next free |
| 95 | * position. |
| 96 | * (used when no merging index is used for a certain action, custom element or sub-container) |
| 97 | */ |
| 98 | struct ContainerNode { |
| 99 | ContainerNode(QWidget *_container, |
| 100 | const QString &_tagName, |
| 101 | const QString &_name, |
| 102 | ContainerNode *_parent = nullptr, |
| 103 | KXMLGUIClient *_client = nullptr, |
| 104 | KXMLGUIBuilder *_builder = nullptr, |
| 105 | QAction *containerAction = nullptr, |
| 106 | const QString &_mergingName = QString(), |
| 107 | const QString &groupName = QString(), |
| 108 | const QStringList &customTags = QStringList(), |
| 109 | const QStringList &containerTags = QStringList()); |
| 110 | ~ContainerNode(); |
| 111 | |
| 112 | ContainerNode(const ContainerNode &) = delete; |
| 113 | ContainerNode &operator=(const ContainerNode &) = delete; |
| 114 | |
| 115 | ContainerNode *parent; |
| 116 | KXMLGUIClient *client; |
| 117 | KXMLGUIBuilder *builder; |
| 118 | QStringList builderCustomTags; |
| 119 | QStringList builderContainerTags; |
| 120 | QWidget *container; |
| 121 | QAction *containerAction; |
| 122 | |
| 123 | QString tagName; |
| 124 | QString name; |
| 125 | |
| 126 | QString groupName; // is empty if the container is in no group |
| 127 | |
| 128 | ContainerClientList clients; |
| 129 | QList<ContainerNode *> children; |
| 130 | |
| 131 | int index; |
| 132 | MergingIndexList mergingIndices; |
| 133 | |
| 134 | QString mergingName; |
| 135 | |
| 136 | void clearChildren() |
| 137 | { |
| 138 | qDeleteAll(c: children); |
| 139 | children.clear(); |
| 140 | } |
| 141 | void removeChild(ContainerNode *child); |
| 142 | void deleteChild(ContainerNode *child); |
| 143 | void removeActions(const QList<QAction *> &actions); |
| 144 | |
| 145 | MergingIndexList::iterator findIndex(const QString &name); |
| 146 | ContainerNode *findContainer(const QString &_name, bool tag); |
| 147 | ContainerNode *findContainer(const QString &name, const QString &tagName, const QList<QWidget *> *excludeList, KXMLGUIClient *currClient); |
| 148 | |
| 149 | ContainerClient *findChildContainerClient(KXMLGUIClient *currentGUIClient, const QString &groupName, const MergingIndexList::iterator &mergingIdx); |
| 150 | |
| 151 | void plugActionList(BuildState &state); |
| 152 | void plugActionList(BuildState &state, const MergingIndexList::iterator &mergingIdxIt); |
| 153 | |
| 154 | void unplugActionList(BuildState &state); |
| 155 | void unplugActionList(BuildState &state, const MergingIndexList::iterator &mergingIdxIt); |
| 156 | |
| 157 | void adjustMergingIndices(int offset, const MergingIndexList::iterator &it, const QString ¤tClientName); |
| 158 | |
| 159 | bool destruct(QDomElement element, BuildState &state); |
| 160 | void destructChildren(const QDomElement &element, BuildState &state); |
| 161 | static QDomElement findElementForChild(const QDomElement &baseElement, ContainerNode *childNode); |
| 162 | void unplugActions(BuildState &state); |
| 163 | void unplugClient(ContainerClient *client); |
| 164 | |
| 165 | void reset(); |
| 166 | |
| 167 | int calcMergingIndex(const QString &mergingName, MergingIndexList::iterator &it, BuildState &state, bool ignoreDefaultMergingIndex); |
| 168 | |
| 169 | void dump(int offset = 0); |
| 170 | }; |
| 171 | |
| 172 | typedef QList<ContainerNode *> ContainerNodeList; |
| 173 | |
| 174 | class BuildHelper |
| 175 | { |
| 176 | public: |
| 177 | BuildHelper(BuildState &state, ContainerNode *node); |
| 178 | |
| 179 | void build(const QDomElement &element); |
| 180 | |
| 181 | private: |
| 182 | void processElement(const QDomElement &element); |
| 183 | |
| 184 | void processActionOrCustomElement(const QDomElement &e, bool isActionTag); |
| 185 | bool processActionElement(const QDomElement &e, int idx); |
| 186 | bool processCustomElement(const QDomElement &e, int idx); |
| 187 | |
| 188 | void processStateElement(const QDomElement &element); |
| 189 | |
| 190 | void processMergeElement(const QString &tag, const QString &name, const QDomElement &e); |
| 191 | |
| 192 | void processContainerElement(const QDomElement &e, const QString &tag, const QString &name); |
| 193 | |
| 194 | QWidget *createContainer(QWidget *parent, int index, const QDomElement &element, QAction *&containerAction, KXMLGUIBuilder **builder); |
| 195 | |
| 196 | int calcMergingIndex(const QDomElement &element, MergingIndexList::iterator &it, QString &group); |
| 197 | |
| 198 | QStringList customTags; |
| 199 | QStringList containerTags; |
| 200 | |
| 201 | QList<QWidget *> containerList; |
| 202 | |
| 203 | ContainerClient *containerClient; |
| 204 | |
| 205 | bool ignoreDefaultMergingIndex; |
| 206 | |
| 207 | BuildState &m_state; |
| 208 | |
| 209 | ContainerNode *parentNode; |
| 210 | }; |
| 211 | |
| 212 | struct BuildState { |
| 213 | BuildState() |
| 214 | : guiClient(nullptr) |
| 215 | , builder(nullptr) |
| 216 | , clientBuilder(nullptr) |
| 217 | { |
| 218 | } |
| 219 | |
| 220 | void reset(); |
| 221 | |
| 222 | QString clientName; |
| 223 | |
| 224 | QString actionListName; |
| 225 | ActionList actionList; |
| 226 | |
| 227 | KXMLGUIClient *guiClient; |
| 228 | |
| 229 | MergingIndexList::iterator currentDefaultMergingIt; |
| 230 | MergingIndexList::iterator currentClientMergingIt; |
| 231 | |
| 232 | KXMLGUIBuilder *builder; |
| 233 | QStringList builderCustomTags; |
| 234 | QStringList builderContainerTags; |
| 235 | |
| 236 | KXMLGUIBuilder *clientBuilder; |
| 237 | QStringList clientBuilderCustomTags; |
| 238 | QStringList clientBuilderContainerTags; |
| 239 | }; |
| 240 | |
| 241 | typedef QStack<BuildState> BuildStateStack; |
| 242 | |
| 243 | } |
| 244 | |
| 245 | QDebug operator<<(QDebug stream, const KXMLGUI::MergingIndex &mi); |
| 246 | |
| 247 | #endif |
| 248 | |