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 | |