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