File indexing completed on 2024-12-01 12:40:43
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 #include "kxmlguifactory_p.h" 0009 0010 #include "ktoolbar.h" 0011 #include "kxmlguibuilder.h" 0012 #include "kxmlguiclient.h" 0013 0014 #include <QVector> 0015 #include <QWidget> 0016 0017 #include "debug.h" 0018 #include <cassert> 0019 0020 using namespace KXMLGUI; 0021 0022 void ActionList::plug(QWidget *container, int index) const 0023 { 0024 QAction *before = nullptr; // Insert after end of widget's current actions (default). 0025 0026 if ((index < 0) || (index > container->actions().count())) { 0027 qCWarning(DEBUG_KXMLGUI) << "Index " << index << " is not within range (0 - " << container->actions().count() << ")"; 0028 } else if (index != container->actions().count()) { 0029 before = container->actions().at(index); // Insert before indexed action. 0030 } 0031 0032 for (QAction *action : *this) { 0033 container->insertAction(before, action); 0034 // before = action; // BUG FIX: do not insert actions in reverse order. 0035 } 0036 } 0037 0038 ContainerNode::ContainerNode(QWidget *_container, 0039 const QString &_tagName, 0040 const QString &_name, 0041 ContainerNode *_parent, 0042 KXMLGUIClient *_client, 0043 KXMLGUIBuilder *_builder, 0044 QAction *_containerAction, 0045 const QString &_mergingName, 0046 const QString &_groupName, 0047 const QStringList &customTags, 0048 const QStringList &containerTags) 0049 : parent(_parent) 0050 , client(_client) 0051 , builder(_builder) 0052 , builderCustomTags(customTags) 0053 , builderContainerTags(containerTags) 0054 , container(_container) 0055 , containerAction(_containerAction) 0056 , tagName(_tagName) 0057 , name(_name) 0058 , groupName(_groupName) 0059 , index(0) 0060 , mergingName(_mergingName) 0061 { 0062 if (parent) { 0063 parent->children.append(this); 0064 } 0065 } 0066 0067 ContainerNode::~ContainerNode() 0068 { 0069 qDeleteAll(children); 0070 qDeleteAll(clients); 0071 } 0072 0073 void ContainerNode::removeChild(ContainerNode *child) 0074 { 0075 children.removeAll(child); 0076 deleteChild(child); 0077 } 0078 0079 void ContainerNode::deleteChild(ContainerNode *child) 0080 { 0081 MergingIndexList::iterator mergingIt = findIndex(child->mergingName); 0082 adjustMergingIndices(-1, mergingIt, QString()); 0083 delete child; 0084 } 0085 0086 /* 0087 * Find a merging index with the given name. Used to find an index defined by <Merge name="blah"/> 0088 * or by a <DefineGroup name="foo" /> tag. 0089 */ 0090 MergingIndexList::iterator ContainerNode::findIndex(const QString &name) 0091 { 0092 return std::find_if(mergingIndices.begin(), mergingIndices.end(), [&name](const MergingIndex &idx) { 0093 return idx.mergingName == name; 0094 }); 0095 } 0096 0097 /* 0098 * Find a container recursively with the given name. Either compares _name with the 0099 * container's tag name or the value of the container's name attribute. Specified by 0100 * the tag bool . 0101 */ 0102 ContainerNode *ContainerNode::findContainer(const QString &_name, bool tag) 0103 { 0104 if ((tag && tagName == _name) || (!tag && name == _name)) { 0105 return this; 0106 } 0107 0108 for (ContainerNode *child : std::as_const(children)) { 0109 ContainerNode *res = child->findContainer(_name, tag); 0110 if (res) { 0111 return res; 0112 } 0113 } 0114 0115 return nullptr; 0116 } 0117 0118 /* 0119 * Finds a child container node (not recursively) with the given name and tagname. Explicitly 0120 * leaves out container widgets specified in the exludeList . Also ensures that the containers 0121 * belongs to currClient. 0122 */ 0123 ContainerNode *ContainerNode::findContainer(const QString &name, const QString &tagName, const QList<QWidget *> *excludeList, KXMLGUIClient * /*currClient*/) 0124 { 0125 if (!name.isEmpty()) { 0126 auto it = std::find_if(children.cbegin(), children.cend(), [&name, excludeList](ContainerNode *node) { 0127 return node->name == name && !excludeList->contains(node->container); 0128 }); 0129 return it != children.cend() ? *it : nullptr; 0130 } 0131 0132 if (!tagName.isEmpty()) { 0133 // It is a bad idea to also compare the client (node->client == currClient), 0134 // because we don't want to do so in situations like these: 0135 // 0136 // <MenuBar> 0137 // <Menu> 0138 // ... 0139 // 0140 // other client: 0141 // <MenuBar> 0142 // <Menu> 0143 // ... 0144 auto it = std::find_if(children.cbegin(), children.cend(), [&tagName, excludeList](ContainerNode *node) { 0145 return node->tagName == tagName && !excludeList->contains(node->container); 0146 }); 0147 return it != children.cend() ? *it : nullptr; 0148 }; 0149 0150 return {}; 0151 } 0152 0153 ContainerClient * 0154 ContainerNode::findChildContainerClient(KXMLGUIClient *currentGUIClient, const QString &groupName, const MergingIndexList::iterator &mergingIdx) 0155 { 0156 auto it = std::find_if(clients.cbegin(), clients.cend(), [&groupName, currentGUIClient](ContainerClient *cl) { 0157 return cl->client == currentGUIClient && (groupName.isEmpty() || groupName == cl->groupName); 0158 }); 0159 if (it != clients.cend()) { 0160 return *it; 0161 } 0162 0163 ContainerClient *client = new ContainerClient; 0164 client->client = currentGUIClient; 0165 client->groupName = groupName; 0166 0167 if (mergingIdx != mergingIndices.end()) { 0168 client->mergingName = (*mergingIdx).mergingName; 0169 } 0170 0171 clients.append(client); 0172 0173 return client; 0174 } 0175 0176 void ContainerNode::plugActionList(BuildState &state) 0177 { 0178 MergingIndexList::iterator mIt(mergingIndices.begin()); 0179 MergingIndexList::iterator mEnd(mergingIndices.end()); 0180 for (; mIt != mEnd; ++mIt) { 0181 plugActionList(state, mIt); 0182 } 0183 0184 for (ContainerNode *child : std::as_const(children)) { 0185 child->plugActionList(state); 0186 } 0187 } 0188 0189 void ContainerNode::plugActionList(BuildState &state, const MergingIndexList::iterator &mergingIdxIt) 0190 { 0191 const QLatin1String tagActionList("actionlist"); 0192 0193 const MergingIndex &mergingIdx = *mergingIdxIt; 0194 if (mergingIdx.clientName != state.clientName) { 0195 return; 0196 } 0197 if (!mergingIdx.mergingName.startsWith(tagActionList)) { 0198 return; 0199 } 0200 const QString k = mergingIdx.mergingName.mid(tagActionList.size()); 0201 if (k != state.actionListName) { 0202 return; 0203 } 0204 0205 ContainerClient *client = findChildContainerClient(state.guiClient, QString(), mergingIndices.end()); 0206 0207 client->actionLists.insert(k, state.actionList); 0208 0209 state.actionList.plug(container, mergingIdx.value); 0210 0211 adjustMergingIndices(state.actionList.count(), mergingIdxIt, QString()); 0212 } 0213 0214 void ContainerNode::unplugActionList(BuildState &state) 0215 { 0216 MergingIndexList::iterator mIt(mergingIndices.begin()); 0217 MergingIndexList::iterator mEnd(mergingIndices.end()); 0218 for (; mIt != mEnd; ++mIt) { 0219 unplugActionList(state, mIt); 0220 } 0221 0222 for (ContainerNode *child : std::as_const(children)) { 0223 child->unplugActionList(state); 0224 } 0225 } 0226 0227 void ContainerNode::unplugActionList(BuildState &state, const MergingIndexList::iterator &mergingIdxIt) 0228 { 0229 const QLatin1String tagActionList("actionlist"); 0230 0231 MergingIndex mergingIdx = *mergingIdxIt; 0232 0233 QString k = mergingIdx.mergingName; 0234 0235 if (k.indexOf(tagActionList) == -1) { 0236 return; 0237 } 0238 0239 k.remove(0, tagActionList.size()); 0240 0241 if (mergingIdx.clientName != state.clientName) { 0242 return; 0243 } 0244 0245 if (k != state.actionListName) { 0246 return; 0247 } 0248 0249 ContainerClient *client = findChildContainerClient(state.guiClient, QString(), mergingIndices.end()); 0250 0251 ActionListMap::Iterator lIt(client->actionLists.find(k)); 0252 if (lIt == client->actionLists.end()) { 0253 return; 0254 } 0255 0256 removeActions(lIt.value()); 0257 0258 client->actionLists.erase(lIt); 0259 } 0260 0261 void ContainerNode::adjustMergingIndices(int offset, const MergingIndexList::iterator &it, const QString ¤tClientName) 0262 { 0263 MergingIndexList::iterator mergingIt = it; 0264 MergingIndexList::iterator mergingEnd = mergingIndices.end(); 0265 0266 for (; mergingIt != mergingEnd; ++mergingIt) { 0267 if ((*mergingIt).clientName != currentClientName) { 0268 (*mergingIt).value += offset; 0269 } 0270 } 0271 0272 index += offset; 0273 } 0274 0275 bool ContainerNode::destruct( 0276 QDomElement element, 0277 BuildState &state) // krazy:exclude=passbyvalue (this is correct QDom usage, and a ref wouldn't allow passing doc.documentElement() as argument) 0278 { 0279 destructChildren(element, state); 0280 0281 unplugActions(state); 0282 0283 // remove all merging indices the client defined 0284 QMutableVectorIterator<MergingIndex> cmIt = mergingIndices; 0285 while (cmIt.hasNext()) { 0286 if (cmIt.next().clientName == state.clientName) { 0287 cmIt.remove(); 0288 } 0289 } 0290 0291 // ### check for merging index count, too? 0292 if (clients.isEmpty() && children.isEmpty() && container && client == state.guiClient) { 0293 QWidget *parentContainer = nullptr; 0294 if (parent && parent->container) { 0295 parentContainer = parent->container; 0296 } 0297 0298 Q_ASSERT(builder); 0299 builder->removeContainer(container, parentContainer, element, containerAction); 0300 0301 client = nullptr; 0302 return true; 0303 } 0304 0305 if (client == state.guiClient) { 0306 client = nullptr; 0307 } 0308 0309 return false; 0310 } 0311 0312 void ContainerNode::destructChildren(const QDomElement &element, BuildState &state) 0313 { 0314 QMutableListIterator<ContainerNode *> childIt = children; 0315 while (childIt.hasNext()) { 0316 ContainerNode *childNode = childIt.next(); 0317 0318 QDomElement childElement = findElementForChild(element, childNode); 0319 0320 // destruct returns true in case the container really got deleted 0321 if (childNode->destruct(childElement, state)) { 0322 deleteChild(childNode); 0323 childIt.remove(); 0324 } 0325 } 0326 } 0327 0328 QDomElement ContainerNode::findElementForChild(const QDomElement &baseElement, ContainerNode *childNode) 0329 { 0330 // ### slow 0331 for (QDomNode n = baseElement.firstChild(); !n.isNull(); n = n.nextSibling()) { 0332 QDomElement e = n.toElement(); 0333 if (e.tagName().toLower() == childNode->tagName // 0334 && e.attribute(QStringLiteral("name")) == childNode->name) { 0335 return e; 0336 } 0337 } 0338 0339 return QDomElement(); 0340 } 0341 0342 void ContainerNode::unplugActions(BuildState &state) 0343 { 0344 if (!container) { 0345 return; 0346 } 0347 0348 QMutableListIterator<ContainerClient *> clientIt(clients); 0349 while (clientIt.hasNext()) { 0350 // only unplug the actions of the client we want to remove, as the container might be owned 0351 // by a different client 0352 ContainerClient *cClient = clientIt.next(); 0353 if (cClient->client == state.guiClient) { 0354 unplugClient(cClient); 0355 delete cClient; 0356 clientIt.remove(); 0357 } 0358 } 0359 } 0360 0361 void ContainerNode::removeActions(const QList<QAction *> &actions) 0362 { 0363 for (QAction *action : actions) { 0364 const int pos = container->actions().indexOf(action); 0365 if (pos != -1) { 0366 container->removeAction(action); 0367 for (MergingIndex &idx : mergingIndices) { 0368 if (idx.value > pos) { 0369 --idx.value; 0370 } 0371 } 0372 --index; 0373 } 0374 } 0375 } 0376 0377 void ContainerNode::unplugClient(ContainerClient *client) 0378 { 0379 assert(builder); 0380 0381 KToolBar *bar = qobject_cast<KToolBar *>(container); 0382 if (bar) { 0383 bar->removeXMLGUIClient(client->client); 0384 } 0385 0386 // now quickly remove all custom elements (i.e. separators) and unplug all actions 0387 removeActions(client->customElements); 0388 removeActions(client->actions); 0389 0390 // unplug all actionslists 0391 0392 for (const auto &actionList : std::as_const(client->actionLists)) { 0393 removeActions(actionList); 0394 } 0395 } 0396 0397 void ContainerNode::reset() 0398 { 0399 for (ContainerNode *child : std::as_const(children)) { 0400 child->reset(); 0401 } 0402 0403 if (client) { 0404 client->setFactory(nullptr); 0405 } 0406 } 0407 0408 int ContainerNode::calcMergingIndex(const QString &mergingName, MergingIndexList::iterator &it, BuildState &state, bool ignoreDefaultMergingIndex) 0409 { 0410 const MergingIndexList::iterator mergingIt = findIndex(mergingName.isEmpty() ? state.clientName : mergingName); 0411 const MergingIndexList::iterator mergingEnd = mergingIndices.end(); 0412 0413 if (ignoreDefaultMergingIndex || (mergingIt == mergingEnd && state.currentDefaultMergingIt == mergingEnd)) { 0414 it = mergingEnd; 0415 return index; 0416 } 0417 0418 if (mergingIt != mergingEnd) { 0419 it = mergingIt; 0420 } else { 0421 it = state.currentDefaultMergingIt; 0422 } 0423 0424 return (*it).value; 0425 } 0426 0427 void ContainerNode::dump(int offset) 0428 { 0429 QString indent; 0430 indent.fill(QLatin1Char(' '), offset); 0431 qCDebug(DEBUG_KXMLGUI) << qPrintable(indent) << name << tagName << groupName << mergingName << mergingIndices; 0432 for (ContainerNode *child : std::as_const(children)) { 0433 child->dump(offset + 2); 0434 } 0435 } 0436 0437 // TODO: return a struct with 3 members rather than 1 ret val + 2 out params 0438 int BuildHelper::calcMergingIndex(const QDomElement &element, MergingIndexList::iterator &it, QString &group) 0439 { 0440 const QLatin1String attrGroup("group"); 0441 0442 bool haveGroup = false; 0443 group = element.attribute(attrGroup); 0444 if (!group.isEmpty()) { 0445 group.prepend(attrGroup); 0446 haveGroup = true; 0447 } 0448 0449 int idx; 0450 if (haveGroup) { 0451 idx = parentNode->calcMergingIndex(group, it, m_state, ignoreDefaultMergingIndex); 0452 } else { 0453 it = m_state.currentClientMergingIt; 0454 if (it == parentNode->mergingIndices.end()) { 0455 idx = parentNode->index; 0456 } else { 0457 idx = (*it).value; 0458 } 0459 } 0460 0461 return idx; 0462 } 0463 0464 BuildHelper::BuildHelper(BuildState &state, ContainerNode *node) 0465 : containerClient(nullptr) 0466 , ignoreDefaultMergingIndex(false) 0467 , m_state(state) 0468 , parentNode(node) 0469 { 0470 // create a list of supported container and custom tags 0471 customTags = m_state.builderCustomTags; 0472 containerTags = m_state.builderContainerTags; 0473 0474 if (parentNode->builder != m_state.builder) { 0475 customTags += parentNode->builderCustomTags; 0476 containerTags += parentNode->builderContainerTags; 0477 } 0478 0479 if (m_state.clientBuilder) { 0480 customTags = m_state.clientBuilderCustomTags + customTags; 0481 containerTags = m_state.clientBuilderContainerTags + containerTags; 0482 } 0483 0484 m_state.currentDefaultMergingIt = parentNode->findIndex(QStringLiteral("<default>")); 0485 parentNode->calcMergingIndex(QString(), m_state.currentClientMergingIt, m_state, /*ignoreDefaultMergingIndex*/ false); 0486 } 0487 0488 void BuildHelper::build(const QDomElement &element) 0489 { 0490 for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { 0491 QDomElement e = n.toElement(); 0492 if (e.isNull()) { 0493 continue; 0494 } 0495 processElement(e); 0496 } 0497 } 0498 0499 void BuildHelper::processElement(const QDomElement &e) 0500 { 0501 QString tag(e.tagName().toLower()); 0502 QString currName(e.attribute(QStringLiteral("name"))); 0503 0504 const bool isActionTag = (tag == QLatin1String("action")); 0505 0506 if (isActionTag || customTags.indexOf(tag) != -1) { 0507 processActionOrCustomElement(e, isActionTag); 0508 } else if (containerTags.indexOf(tag) != -1) { 0509 processContainerElement(e, tag, currName); 0510 } else if (tag == QLatin1String("merge") || tag == QLatin1String("definegroup") || tag == QLatin1String("actionlist")) { 0511 processMergeElement(tag, currName, e); 0512 } else if (tag == QLatin1String("state")) { 0513 processStateElement(e); 0514 } 0515 } 0516 0517 void BuildHelper::processActionOrCustomElement(const QDomElement &e, bool isActionTag) 0518 { 0519 if (!parentNode->container) { 0520 return; 0521 } 0522 0523 MergingIndexList::iterator it(m_state.currentClientMergingIt); 0524 0525 QString group; 0526 int idx = calcMergingIndex(e, it, group); 0527 0528 containerClient = parentNode->findChildContainerClient(m_state.guiClient, group, it); 0529 0530 bool guiElementCreated = false; 0531 if (isActionTag) { 0532 guiElementCreated = processActionElement(e, idx); 0533 } else { 0534 guiElementCreated = processCustomElement(e, idx); 0535 } 0536 0537 if (guiElementCreated) { 0538 // adjust any following merging indices and the current running index for the container 0539 parentNode->adjustMergingIndices(1, it, m_state.clientName); 0540 } 0541 } 0542 0543 bool BuildHelper::processActionElement(const QDomElement &e, int idx) 0544 { 0545 assert(m_state.guiClient); 0546 0547 // look up the action and plug it in 0548 QAction *action = m_state.guiClient->action(e); 0549 0550 if (!action) { 0551 return false; 0552 } 0553 0554 // qCDebug(DEBUG_KXMLGUI) << e.attribute(QStringLiteral("name")) << "->" << action << "inserting at idx=" << idx; 0555 0556 QAction *before = nullptr; 0557 if (idx >= 0 && idx < parentNode->container->actions().count()) { 0558 before = parentNode->container->actions().at(idx); 0559 } 0560 0561 parentNode->container->insertAction(before, action); 0562 0563 // save a reference to the plugged action, in order to properly unplug it afterwards. 0564 containerClient->actions.append(action); 0565 0566 return true; 0567 } 0568 0569 bool BuildHelper::processCustomElement(const QDomElement &e, int idx) 0570 { 0571 assert(parentNode->builder); 0572 0573 QAction *action = parentNode->builder->createCustomElement(parentNode->container, idx, e); 0574 if (!action) { 0575 return false; 0576 } 0577 0578 containerClient->customElements.append(action); 0579 return true; 0580 } 0581 0582 void BuildHelper::processStateElement(const QDomElement &element) 0583 { 0584 QString stateName = element.attribute(QStringLiteral("name")); 0585 0586 if (stateName.isEmpty()) { 0587 return; 0588 } 0589 0590 for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { 0591 QDomElement e = n.toElement(); 0592 if (e.isNull()) { 0593 continue; 0594 } 0595 0596 QString tagName = e.tagName().toLower(); 0597 0598 if (tagName != QLatin1String("enable") && tagName != QLatin1String("disable")) { 0599 continue; 0600 } 0601 0602 const bool processingActionsToEnable = (tagName == QLatin1String("enable")); 0603 0604 // process action names 0605 for (QDomNode n2 = n.firstChild(); !n2.isNull(); n2 = n2.nextSibling()) { 0606 QDomElement actionEl = n2.toElement(); 0607 if (actionEl.tagName().compare(QLatin1String("action"), Qt::CaseInsensitive) != 0) { 0608 continue; 0609 } 0610 0611 QString actionName = actionEl.attribute(QStringLiteral("name")); 0612 if (actionName.isEmpty()) { 0613 return; 0614 } 0615 0616 if (processingActionsToEnable) { 0617 m_state.guiClient->addStateActionEnabled(stateName, actionName); 0618 } else { 0619 m_state.guiClient->addStateActionDisabled(stateName, actionName); 0620 } 0621 } 0622 } 0623 } 0624 0625 void BuildHelper::processMergeElement(const QString &tag, const QString &name, const QDomElement &e) 0626 { 0627 const QLatin1String tagDefineGroup("definegroup"); 0628 const QLatin1String tagActionList("actionlist"); 0629 const QLatin1String defaultMergingName("<default>"); 0630 const QLatin1String attrGroup("group"); 0631 0632 QString mergingName(name); 0633 if (mergingName.isEmpty()) { 0634 if (tag == tagDefineGroup) { 0635 qCCritical(DEBUG_KXMLGUI) << "cannot define group without name!"; 0636 return; 0637 } 0638 if (tag == tagActionList) { 0639 qCCritical(DEBUG_KXMLGUI) << "cannot define actionlist without name!"; 0640 return; 0641 } 0642 mergingName = defaultMergingName; 0643 } 0644 0645 if (tag == tagDefineGroup) { 0646 mergingName.prepend(attrGroup); // avoid possible name clashes by prepending 0647 // "group" to group definitions 0648 } else if (tag == tagActionList) { 0649 mergingName.prepend(tagActionList); 0650 } 0651 0652 if (parentNode->findIndex(mergingName) != parentNode->mergingIndices.end()) { 0653 return; // do not allow the redefinition of merging indices! 0654 } 0655 0656 MergingIndexList::iterator mIt(parentNode->mergingIndices.end()); 0657 0658 QString group(e.attribute(attrGroup)); 0659 if (!group.isEmpty()) { 0660 group.prepend(attrGroup); 0661 } 0662 0663 // calculate the index of the new merging index. Usually this does not need any calculation, 0664 // we just want the last available index (i.e. append) . But in case the <Merge> tag appears 0665 // "inside" another <Merge> tag from a previously build client, then we have to use the 0666 // "parent's" index. That's why we call calcMergingIndex here. 0667 MergingIndex newIdx; 0668 newIdx.value = parentNode->calcMergingIndex(group, mIt, m_state, ignoreDefaultMergingIndex); 0669 newIdx.mergingName = mergingName; 0670 newIdx.clientName = m_state.clientName; 0671 0672 // if that merging index is "inside" another one, then append it right after the "parent". 0673 if (mIt != parentNode->mergingIndices.end()) { 0674 parentNode->mergingIndices.insert(++mIt, newIdx); 0675 } else { 0676 parentNode->mergingIndices.append(newIdx); 0677 } 0678 0679 if (mergingName == defaultMergingName) { 0680 ignoreDefaultMergingIndex = true; 0681 } 0682 0683 // re-calculate the running default and client merging indices 0684 // (especially important in case the QList data got reallocated due to growing!) 0685 m_state.currentDefaultMergingIt = parentNode->findIndex(defaultMergingName); 0686 parentNode->calcMergingIndex(QString(), m_state.currentClientMergingIt, m_state, ignoreDefaultMergingIndex); 0687 } 0688 0689 void BuildHelper::processContainerElement(const QDomElement &e, const QString &tag, const QString &name) 0690 { 0691 ContainerNode *containerNode = parentNode->findContainer(name, tag, &containerList, m_state.guiClient); 0692 0693 if (!containerNode) { 0694 MergingIndexList::iterator it(m_state.currentClientMergingIt); 0695 QString group; 0696 0697 int idx = calcMergingIndex(e, it, group); 0698 0699 QAction *containerAction; 0700 0701 KXMLGUIBuilder *builder; 0702 0703 QWidget *container = createContainer(parentNode->container, idx, e, containerAction, &builder); 0704 0705 // no container? (probably some <text> tag or so ;-) 0706 if (!container) { 0707 return; 0708 } 0709 0710 parentNode->adjustMergingIndices(1, it, m_state.clientName); 0711 0712 // Check that the container widget is not already in parentNode. 0713 Q_ASSERT(std::find_if(parentNode->children.constBegin(), 0714 parentNode->children.constEnd(), 0715 [container](ContainerNode *child) { 0716 return child->container == container; 0717 }) 0718 == parentNode->children.constEnd()); 0719 0720 containerList.append(container); 0721 0722 QString mergingName; 0723 if (it != parentNode->mergingIndices.end()) { 0724 mergingName = (*it).mergingName; 0725 } 0726 0727 QStringList cusTags = m_state.builderCustomTags; 0728 QStringList conTags = m_state.builderContainerTags; 0729 if (builder != m_state.builder) { 0730 cusTags = m_state.clientBuilderCustomTags; 0731 conTags = m_state.clientBuilderContainerTags; 0732 } 0733 0734 containerNode = new ContainerNode(container, tag, name, parentNode, m_state.guiClient, builder, containerAction, mergingName, group, cusTags, conTags); 0735 } else { 0736 if (tag == QLatin1String("toolbar")) { 0737 KToolBar *bar = qobject_cast<KToolBar *>(containerNode->container); 0738 if (bar) { 0739 if (m_state.guiClient && !m_state.guiClient->xmlFile().isEmpty()) { 0740 bar->addXMLGUIClient(m_state.guiClient); 0741 } 0742 } else { 0743 qCWarning(DEBUG_KXMLGUI) << "toolbar container is not a KToolBar"; 0744 } 0745 } 0746 } 0747 0748 BuildHelper(m_state, containerNode).build(e); 0749 0750 // and re-calculate running values, for better performance 0751 m_state.currentDefaultMergingIt = parentNode->findIndex(QStringLiteral("<default>")); 0752 parentNode->calcMergingIndex(QString(), m_state.currentClientMergingIt, m_state, ignoreDefaultMergingIndex); 0753 } 0754 0755 QWidget *BuildHelper::createContainer(QWidget *parent, int index, const QDomElement &element, QAction *&containerAction, KXMLGUIBuilder **builder) 0756 { 0757 QWidget *res = nullptr; 0758 0759 if (m_state.clientBuilder) { 0760 res = m_state.clientBuilder->createContainer(parent, index, element, containerAction); 0761 0762 if (res) { 0763 *builder = m_state.clientBuilder; 0764 return res; 0765 } 0766 } 0767 0768 KXMLGUIClient *oldClient = m_state.builder->builderClient(); 0769 0770 m_state.builder->setBuilderClient(m_state.guiClient); 0771 0772 res = m_state.builder->createContainer(parent, index, element, containerAction); 0773 0774 m_state.builder->setBuilderClient(oldClient); 0775 0776 if (res) { 0777 *builder = m_state.builder; 0778 } 0779 0780 return res; 0781 } 0782 0783 void BuildState::reset() 0784 { 0785 clientName.clear(); 0786 actionListName.clear(); 0787 actionList.clear(); 0788 guiClient = nullptr; 0789 clientBuilder = nullptr; 0790 0791 currentDefaultMergingIt = currentClientMergingIt = MergingIndexList::iterator(); 0792 } 0793 0794 QDebug operator<<(QDebug stream, const MergingIndex &mi) 0795 { 0796 QDebugStateSaver saver(stream); 0797 stream.nospace() << "clientName=" << mi.clientName << " mergingName=" << mi.mergingName << " value=" << mi.value; 0798 return stream; 0799 }