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
18class QWidget;
19class KXMLGUIClient;
20class KXMLGUIBuilder;
21
22namespace KXMLGUI
23{
24struct BuildState;
25
26class ActionList : public QList<QAction *>
27{
28public:
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
45typedef 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 */
59struct 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};
67typedef QList<ContainerClient *> ContainerClientList;
68
69struct ContainerNode;
70
71struct 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};
77typedef 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 */
98struct 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 &currentClientName);
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
172typedef QList<ContainerNode *> ContainerNodeList;
173
174class BuildHelper
175{
176public:
177 BuildHelper(BuildState &state, ContainerNode *node);
178
179 void build(const QDomElement &element);
180
181private:
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
212struct 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
241typedef QStack<BuildState> BuildStateStack;
242
243}
244
245QDebug operator<<(QDebug stream, const KXMLGUI::MergingIndex &mi);
246
247#endif
248

source code of kxmlgui/src/kxmlguifactory_p.h