File indexing completed on 2024-04-14 03:57:15

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2001 Simon Hausmann <hausmann@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #ifndef kxmlguifactory_p_h
0009 #define kxmlguifactory_p_h
0010 
0011 #include <QAction>
0012 #include <QDebug>
0013 #include <QDomElement>
0014 #include <QMap>
0015 #include <QStack>
0016 #include <QStringList>
0017 
0018 class QWidget;
0019 class KXMLGUIClient;
0020 class KXMLGUIBuilder;
0021 
0022 namespace KXMLGUI
0023 {
0024 struct BuildState;
0025 
0026 class ActionList : public QList<QAction *>
0027 {
0028 public:
0029     ActionList()
0030     {
0031     }
0032     ActionList(const QList<QAction *> &rhs)
0033         : QList<QAction *>(rhs)
0034     {
0035     }
0036     ActionList &operator=(const QList<QAction *> &rhs)
0037     {
0038         QList<QAction *>::operator=(rhs);
0039         return *this;
0040     }
0041 
0042     void plug(QWidget *container, int index) const;
0043 };
0044 
0045 typedef QMap<QString, ActionList> ActionListMap;
0046 
0047 /*
0048  * This structure is used to know to which client certain actions and custom elements
0049  * (i.e. menu separators) belong.
0050  * We do not only use a ContainerClient per GUIClient but also per merging group.
0051  *
0052  * groupName : Used for grouped merging. Specifies the group name to which these actions/elements
0053  * belong to.
0054  * actionLists : maps from action list name to action list.
0055  * mergingName : The (named) merging point.
0056  *
0057  * A ContainerClient always belongs to a ContainerNode.
0058  */
0059 struct ContainerClient {
0060     KXMLGUIClient *client;
0061     ActionList actions;
0062     QList<QAction *> customElements;
0063     QString groupName; // is empty if no group client
0064     ActionListMap actionLists;
0065     QString mergingName;
0066 };
0067 typedef QList<ContainerClient *> ContainerClientList;
0068 
0069 struct ContainerNode;
0070 
0071 struct MergingIndex {
0072     int value; // the actual index value, used as index for plug() or createContainer() calls
0073     QString mergingName; // the name of the merging index (i.e. the name attribute of the
0074     // Merge or DefineGroup tag)
0075     QString clientName; // the name of the client that defined this index
0076 };
0077 typedef QList<MergingIndex> MergingIndexList;
0078 
0079 /*
0080  * Here we store detailed information about a container, its clients (client=a guiclient having actions
0081  * plugged into the container), child nodes, naming information (tagname and name attribute) and
0082  * merging index information, to plug/insert new actions/items a the correct position.
0083  *
0084  * The builder variable is needed for using the proper GUIBuilder for destruction ( to use the same for
0085  * con- and destruction ). The builderCustomTags and builderContainerTags variables are cached values
0086  * of what the corresponding methods of the GUIBuilder which built the container return. The stringlists
0087  * is shared all over the place, so there's no need to worry about memory consumption for these
0088  * variables :-)
0089  *
0090  * The mergingIndices list contains the merging indices ;-) , as defined by <Merge>, <DefineGroup>
0091  * or by <ActionList> tags. The order of these index structures within the mergingIndices list
0092  * is (and has to be) identical with the order in the DOM tree.
0093  *
0094  * Beside the merging indices we have the "real" index of the container. It points to the next free
0095  * position.
0096  * (used when no merging index is used for a certain action, custom element or sub-container)
0097  */
0098 struct ContainerNode {
0099     ContainerNode(QWidget *_container,
0100                   const QString &_tagName,
0101                   const QString &_name,
0102                   ContainerNode *_parent = nullptr,
0103                   KXMLGUIClient *_client = nullptr,
0104                   KXMLGUIBuilder *_builder = nullptr,
0105                   QAction *containerAction = nullptr,
0106                   const QString &_mergingName = QString(),
0107                   const QString &groupName = QString(),
0108                   const QStringList &customTags = QStringList(),
0109                   const QStringList &containerTags = QStringList());
0110     ~ContainerNode();
0111 
0112     ContainerNode(const ContainerNode &) = delete;
0113     ContainerNode &operator=(const ContainerNode &) = delete;
0114 
0115     ContainerNode *parent;
0116     KXMLGUIClient *client;
0117     KXMLGUIBuilder *builder;
0118     QStringList builderCustomTags;
0119     QStringList builderContainerTags;
0120     QWidget *container;
0121     QAction *containerAction;
0122 
0123     QString tagName;
0124     QString name;
0125 
0126     QString groupName; // is empty if the container is in no group
0127 
0128     ContainerClientList clients;
0129     QList<ContainerNode *> children;
0130 
0131     int index;
0132     MergingIndexList mergingIndices;
0133 
0134     QString mergingName;
0135 
0136     void clearChildren()
0137     {
0138         qDeleteAll(children);
0139         children.clear();
0140     }
0141     void removeChild(ContainerNode *child);
0142     void deleteChild(ContainerNode *child);
0143     void removeActions(const QList<QAction *> &actions);
0144 
0145     MergingIndexList::iterator findIndex(const QString &name);
0146     ContainerNode *findContainer(const QString &_name, bool tag);
0147     ContainerNode *findContainer(const QString &name, const QString &tagName, const QList<QWidget *> *excludeList, KXMLGUIClient *currClient);
0148 
0149     ContainerClient *findChildContainerClient(KXMLGUIClient *currentGUIClient, const QString &groupName, const MergingIndexList::iterator &mergingIdx);
0150 
0151     void plugActionList(BuildState &state);
0152     void plugActionList(BuildState &state, const MergingIndexList::iterator &mergingIdxIt);
0153 
0154     void unplugActionList(BuildState &state);
0155     void unplugActionList(BuildState &state, const MergingIndexList::iterator &mergingIdxIt);
0156 
0157     void adjustMergingIndices(int offset, const MergingIndexList::iterator &it, const QString &currentClientName);
0158 
0159     bool destruct(QDomElement element, BuildState &state);
0160     void destructChildren(const QDomElement &element, BuildState &state);
0161     static QDomElement findElementForChild(const QDomElement &baseElement, ContainerNode *childNode);
0162     void unplugActions(BuildState &state);
0163     void unplugClient(ContainerClient *client);
0164 
0165     void reset();
0166 
0167     int calcMergingIndex(const QString &mergingName, MergingIndexList::iterator &it, BuildState &state, bool ignoreDefaultMergingIndex);
0168 
0169     void dump(int offset = 0);
0170 };
0171 
0172 typedef QList<ContainerNode *> ContainerNodeList;
0173 
0174 class BuildHelper
0175 {
0176 public:
0177     BuildHelper(BuildState &state, ContainerNode *node);
0178 
0179     void build(const QDomElement &element);
0180 
0181 private:
0182     void processElement(const QDomElement &element);
0183 
0184     void processActionOrCustomElement(const QDomElement &e, bool isActionTag);
0185     bool processActionElement(const QDomElement &e, int idx);
0186     bool processCustomElement(const QDomElement &e, int idx);
0187 
0188     void processStateElement(const QDomElement &element);
0189 
0190     void processMergeElement(const QString &tag, const QString &name, const QDomElement &e);
0191 
0192     void processContainerElement(const QDomElement &e, const QString &tag, const QString &name);
0193 
0194     QWidget *createContainer(QWidget *parent, int index, const QDomElement &element, QAction *&containerAction, KXMLGUIBuilder **builder);
0195 
0196     int calcMergingIndex(const QDomElement &element, MergingIndexList::iterator &it, QString &group);
0197 
0198     QStringList customTags;
0199     QStringList containerTags;
0200 
0201     QList<QWidget *> containerList;
0202 
0203     ContainerClient *containerClient;
0204 
0205     bool ignoreDefaultMergingIndex;
0206 
0207     BuildState &m_state;
0208 
0209     ContainerNode *parentNode;
0210 };
0211 
0212 struct BuildState {
0213     BuildState()
0214         : guiClient(nullptr)
0215         , builder(nullptr)
0216         , clientBuilder(nullptr)
0217     {
0218     }
0219 
0220     void reset();
0221 
0222     QString clientName;
0223 
0224     QString actionListName;
0225     ActionList actionList;
0226 
0227     KXMLGUIClient *guiClient;
0228 
0229     MergingIndexList::iterator currentDefaultMergingIt;
0230     MergingIndexList::iterator currentClientMergingIt;
0231 
0232     KXMLGUIBuilder *builder;
0233     QStringList builderCustomTags;
0234     QStringList builderContainerTags;
0235 
0236     KXMLGUIBuilder *clientBuilder;
0237     QStringList clientBuilderCustomTags;
0238     QStringList clientBuilderContainerTags;
0239 };
0240 
0241 typedef QStack<BuildState> BuildStateStack;
0242 
0243 }
0244 
0245 QDebug operator<<(QDebug stream, const KXMLGUI::MergingIndex &mi);
0246 
0247 #endif