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