File indexing completed on 2024-12-22 04:14:02
0001 /* This file is part of the KDE libraries 0002 SPDX-FileCopyrightText: 1999 Reginald Stadlbauer <reggie@kde.org> 0003 SPDX-FileCopyrightText: 1999 Simon Hausmann <hausmann@kde.org> 0004 SPDX-FileCopyrightText: 2000 Nicolas Hadacek <haadcek@kde.org> 0005 SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org> 0006 SPDX-FileCopyrightText: 2000 Michael Koch <koch@kde.org> 0007 SPDX-FileCopyrightText: 2001 Holger Freyther <freyther@kde.org> 0008 SPDX-FileCopyrightText: 2002 Ellis Whitehead <ellis@kde.org> 0009 SPDX-FileCopyrightText: 2002 Joseph Wenninger <jowenn@kde.org> 0010 SPDX-FileCopyrightText: 2005-2007 Hamish Rodda <rodda@kde.org> 0011 0012 SPDX-License-Identifier: LGPL-2.0-only 0013 */ 0014 0015 #include "kactioncollection.h" 0016 #include "config-xmlgui.h" 0017 #include "kactioncategory.h" 0018 #include "kxmlguiclient.h" 0019 #include "kxmlguifactory.h" 0020 #include "kis_action_registry.h" 0021 0022 #include <kconfiggroup.h> 0023 #include <ksharedconfig.h> 0024 0025 #include <QDebug> 0026 #include <QDomDocument> 0027 #include <QSet> 0028 #include <QGuiApplication> 0029 #include <QMap> 0030 #include <QList> 0031 #include <QAction> 0032 #include <QMetaMethod> 0033 #include <QTextStream> 0034 #include <stdio.h> 0035 0036 #if defined(KCONFIG_BEFORE_5_24) 0037 # define authorizeAction authorizeKAction 0038 #endif 0039 0040 class KisKActionCollectionPrivate 0041 { 0042 public: 0043 KisKActionCollectionPrivate() 0044 : m_parentGUIClient(0L), 0045 configGroup(QStringLiteral("Shortcuts")), 0046 q(0) 0047 0048 { 0049 } 0050 0051 void setComponentForAction(QAction *action) 0052 { 0053 Q_UNUSED(action); 0054 } 0055 0056 static QList<KisKActionCollection *> s_allCollections; 0057 0058 void _k_associatedWidgetDestroyed(QObject *obj); 0059 void _k_actionDestroyed(QObject *obj); 0060 0061 bool writeKisKXMLGUIConfigFile(); 0062 0063 QString m_componentName; 0064 QString m_componentDisplayName; 0065 0066 //! Remove a action from our internal bookkeeping. Returns 0 if the 0067 //! action doesn't belong to us. 0068 QAction *unlistAction(QObject *); 0069 0070 QMap<QString, QAction *> actionByName; 0071 QList<QAction *> actions; 0072 0073 const KisKXMLGUIClient *m_parentGUIClient {nullptr}; 0074 0075 QString configGroup; 0076 0077 bool connectTriggered {false}; 0078 bool connectHovered {false}; 0079 0080 KisKActionCollection *q {nullptr}; 0081 0082 QList<QWidget *> associatedWidgets; 0083 }; 0084 0085 QList<KisKActionCollection *> KisKActionCollectionPrivate::s_allCollections; 0086 0087 KisKActionCollection::KisKActionCollection(QObject *parent, const QString &cName) 0088 : QObject(parent) 0089 , d(new KisKActionCollectionPrivate) 0090 { 0091 d->q = this; 0092 KisKActionCollectionPrivate::s_allCollections.append(this); 0093 0094 setComponentName(cName); 0095 } 0096 0097 KisKActionCollection::KisKActionCollection(const KisKXMLGUIClient *parent) 0098 : QObject(0) 0099 , d(new KisKActionCollectionPrivate) 0100 { 0101 d->q = this; 0102 KisKActionCollectionPrivate::s_allCollections.append(this); 0103 0104 d->m_parentGUIClient = parent; 0105 d->m_componentName = parent->componentName(); 0106 } 0107 0108 KisKActionCollection::~KisKActionCollection() 0109 { 0110 KisKActionCollectionPrivate::s_allCollections.removeAll(this); 0111 0112 delete d; 0113 } 0114 0115 0116 QList<KisKActionCategory *> KisKActionCollection::categories() const 0117 { 0118 return this->findChildren<KisKActionCategory *>(); 0119 } 0120 0121 KisKActionCategory *KisKActionCollection::getCategory(const QString &name) { 0122 KisKActionCategory *category = 0; 0123 foreach (KisKActionCategory *c, categories()) { 0124 if (c->text() == name) { 0125 category = c; 0126 } 0127 } 0128 0129 if (category == 0) { 0130 category = new KisKActionCategory(name, this); 0131 } 0132 return category; 0133 } 0134 0135 0136 void KisKActionCollection::clear() 0137 { 0138 d->actionByName.clear(); 0139 qDeleteAll(d->actions); 0140 d->actions.clear(); 0141 } 0142 0143 QAction *KisKActionCollection::action(const QString &name) const 0144 { 0145 QAction *action = 0L; 0146 0147 if (!name.isEmpty()) { 0148 action = d->actionByName.value(name); 0149 } 0150 0151 return action; 0152 } 0153 0154 QAction *KisKActionCollection::action(int index) const 0155 { 0156 // ### investigate if any apps use this at all 0157 return actions().value(index); 0158 } 0159 0160 int KisKActionCollection::count() const 0161 { 0162 return d->actions.count(); 0163 } 0164 0165 bool KisKActionCollection::isEmpty() const 0166 { 0167 return count() == 0; 0168 } 0169 0170 void KisKActionCollection::setComponentName(const QString &cName) 0171 { 0172 if (count() > 0) { 0173 // Its component name is part of an action's signature in the context of 0174 // global shortcuts and the semantics of changing an existing action's 0175 // signature are, as it seems, impossible to get right. 0176 // As of now this only matters for global shortcuts. We could 0177 // thus relax the requirement and only refuse to change the component data 0178 // if we have actions with global shortcuts in this collection. 0179 qWarning() << "this does not work on a KisKActionCollection containing actions!"; 0180 } 0181 0182 if (!cName.isEmpty()) { 0183 d->m_componentName = cName; 0184 } else { 0185 d->m_componentName = QCoreApplication::applicationName(); 0186 } 0187 } 0188 0189 QString KisKActionCollection::componentName() const 0190 { 0191 return d->m_componentName; 0192 } 0193 0194 void KisKActionCollection::setComponentDisplayName(const QString &displayName) 0195 { 0196 d->m_componentDisplayName = displayName; 0197 } 0198 0199 QString KisKActionCollection::componentDisplayName() const 0200 { 0201 if (!d->m_componentDisplayName.isEmpty()) { 0202 return d->m_componentDisplayName; 0203 } 0204 if (!QGuiApplication::applicationDisplayName().isEmpty()) { 0205 return QGuiApplication::applicationDisplayName(); 0206 } 0207 return QCoreApplication::applicationName(); 0208 } 0209 0210 const KisKXMLGUIClient *KisKActionCollection::parentGUIClient() const 0211 { 0212 return d->m_parentGUIClient; 0213 } 0214 0215 QList<QAction *> KisKActionCollection::actions() const 0216 { 0217 return d->actions; 0218 } 0219 0220 const QList< QAction * > KisKActionCollection::actionsWithoutGroup() const 0221 { 0222 QList<QAction *> ret; 0223 Q_FOREACH (QAction *action, d->actions) 0224 if (!action->actionGroup()) { 0225 ret.append(action); 0226 } 0227 return ret; 0228 } 0229 0230 const QList< QActionGroup * > KisKActionCollection::actionGroups() const 0231 { 0232 QSet<QActionGroup *> set; 0233 Q_FOREACH (QAction *action, d->actions) 0234 if (action->actionGroup()) { 0235 set.insert(action->actionGroup()); 0236 } 0237 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0) 0238 return QList<QActionGroup*>(set.begin(), set.end()); 0239 #else 0240 return QList<QActionGroup*>::fromSet(set); 0241 #endif 0242 } 0243 0244 QAction *KisKActionCollection::addCategorizedAction(const QString &name, QAction *action, const QString &categoryName) 0245 { 0246 return getCategory(categoryName)->addAction(name, action); 0247 } 0248 0249 QAction *KisKActionCollection::addAction(const QString &name, QAction *action) 0250 { 0251 if (!action) { 0252 return action; 0253 } 0254 0255 const QString objectName = action->objectName(); 0256 QString indexName = name; 0257 0258 if (indexName.isEmpty()) { 0259 // No name provided. Use the objectName. 0260 indexName = objectName; 0261 0262 } else { 0263 // Set the new name 0264 action->setObjectName(indexName); 0265 } 0266 0267 // No name provided and the action had no name. Make one up. This will not 0268 // work when trying to save shortcuts. 0269 if (indexName.isEmpty()) { 0270 QTextStream(&indexName) << (void *)action; 0271 0272 action->setObjectName(indexName); 0273 } 0274 0275 // From now on the objectName has to have a value. Else we cannot safely 0276 // remove actions. 0277 Q_ASSERT(!action->objectName().isEmpty()); 0278 0279 // look if we already have THIS action under THIS name ;) 0280 if (d->actionByName.value(indexName, 0) == action) { 0281 // This is not a multi map! 0282 Q_ASSERT(d->actionByName.count(indexName) == 1); 0283 return action; 0284 } 0285 0286 // Check if we have another action under this name 0287 if (QAction *oldAction = d->actionByName.value(indexName)) { 0288 takeAction(oldAction); 0289 } 0290 0291 // Check if we have this action under a different name. 0292 // Not using takeAction because we don't want to remove it from categories, 0293 // and because it has the new name already. 0294 const int oldIndex = d->actions.indexOf(action); 0295 if (oldIndex != -1) { 0296 d->actionByName.remove(d->actionByName.key(action)); 0297 d->actions.removeAt(oldIndex); 0298 } 0299 0300 // Add action to our lists. 0301 d->actionByName.insert(indexName, action); 0302 d->actions.append(action); 0303 0304 Q_FOREACH (QWidget *widget, d->associatedWidgets) { 0305 widget->addAction(action); 0306 } 0307 0308 connect(action, SIGNAL(destroyed(QObject*)), SLOT(_k_actionDestroyed(QObject*))); 0309 0310 d->setComponentForAction(action); 0311 0312 if (d->connectHovered) { 0313 connect(action, SIGNAL(hovered()), SLOT(slotActionHovered())); 0314 } 0315 0316 if (d->connectTriggered) { 0317 connect(action, SIGNAL(triggered(bool)), SLOT(slotActionTriggered())); 0318 } 0319 0320 emit inserted(action); 0321 return action; 0322 } 0323 0324 void KisKActionCollection::addActions(const QList<QAction *> &actions) 0325 { 0326 Q_FOREACH (QAction *action, actions) { 0327 addAction(action->objectName(), action); 0328 } 0329 } 0330 0331 void KisKActionCollection::removeAction(QAction *action) 0332 { 0333 delete takeAction(action); 0334 } 0335 0336 QAction *KisKActionCollection::takeAction(QAction *action) 0337 { 0338 if (!d->unlistAction(action)) { 0339 return 0; 0340 } 0341 0342 // Remove the action from all widgets 0343 Q_FOREACH (QWidget *widget, d->associatedWidgets) { 0344 widget->removeAction(action); 0345 } 0346 0347 action->disconnect(this); 0348 0349 return action; 0350 } 0351 0352 QAction *KisKActionCollection::addAction(KStandardAction::StandardAction actionType, const QObject *receiver, const char *member) 0353 { 0354 QAction *action = KStandardAction::create(actionType, receiver, member, this); 0355 return action; 0356 } 0357 0358 QAction *KisKActionCollection::addAction(KStandardAction::StandardAction actionType, const QString &name, 0359 const QObject *receiver, const char *member) 0360 { 0361 // pass 0 as parent, because if the parent is a KisKActionCollection KStandardAction::create automatically 0362 // adds the action to it under the default name. We would trigger the 0363 // warning about renaming the action then. 0364 QAction *action = KStandardAction::create(actionType, receiver, member, 0); 0365 // Give it a parent for gc. 0366 action->setParent(this); 0367 // Remove the name to get rid of the "rename action" warning above 0368 action->setObjectName(name); 0369 // And now add it with the desired name. 0370 return addAction(name, action); 0371 } 0372 0373 QAction *KisKActionCollection::addAction(const QString &name, const QObject *receiver, const char *member) 0374 { 0375 QAction *a = new QAction(this); 0376 if (receiver && member) { 0377 connect(a, SIGNAL(triggered(bool)), receiver, member); 0378 } 0379 return addAction(name, a); 0380 } 0381 0382 QKeySequence KisKActionCollection::defaultShortcut(QAction *action) const 0383 { 0384 const QList<QKeySequence> shortcuts = defaultShortcuts(action); 0385 return shortcuts.isEmpty() ? QKeySequence() : shortcuts.first(); 0386 } 0387 0388 QList<QKeySequence> KisKActionCollection::defaultShortcuts(QAction *action) const 0389 { 0390 return action->property("defaultShortcuts").value<QList<QKeySequence> >(); 0391 } 0392 0393 void KisKActionCollection::setDefaultShortcut(QAction *action, const QKeySequence &shortcut) 0394 { 0395 setDefaultShortcuts(action, QList<QKeySequence>() << shortcut); 0396 } 0397 0398 void KisKActionCollection::setDefaultShortcuts(QAction *action, const QList<QKeySequence> &shortcuts) 0399 { 0400 action->setShortcuts(shortcuts); 0401 action->setProperty("defaultShortcuts", QVariant::fromValue(shortcuts)); 0402 } 0403 0404 bool KisKActionCollection::isShortcutsConfigurable(QAction *action) const 0405 { 0406 // Considered as true by default 0407 const QVariant value = action->property("isShortcutConfigurable"); 0408 return value.isValid() ? value.toBool() : true; 0409 } 0410 0411 void KisKActionCollection::setShortcutsConfigurable(QAction *action, bool configurable) 0412 { 0413 action->setProperty("isShortcutConfigurable", configurable); 0414 } 0415 0416 QString KisKActionCollection::configGroup() const 0417 { 0418 return d->configGroup; 0419 } 0420 0421 void KisKActionCollection::setConfigGroup(const QString &group) 0422 { 0423 d->configGroup = group; 0424 } 0425 0426 void KisKActionCollection::updateShortcuts() 0427 { 0428 auto actionRegistry = KisActionRegistry::instance(); 0429 0430 for (QMap<QString, QAction *>::ConstIterator it = d->actionByName.constBegin(); 0431 it != d->actionByName.constEnd(); ++it) { 0432 actionRegistry->updateShortcut(it.key(), it.value()); 0433 } 0434 } 0435 0436 0437 void KisKActionCollection::readSettings() 0438 { 0439 auto ar = KisActionRegistry::instance(); 0440 ar->loadCustomShortcuts(); 0441 0442 for (QMap<QString, QAction *>::ConstIterator it = d->actionByName.constBegin(); 0443 it != d->actionByName.constEnd(); ++it) { 0444 QAction *action = it.value(); 0445 if (!action) { 0446 continue; 0447 } 0448 0449 if (isShortcutsConfigurable(action)) { 0450 QString actionName = it.key(); 0451 ar->updateShortcut(actionName, action); 0452 } 0453 } 0454 } 0455 0456 0457 bool KisKActionCollectionPrivate::writeKisKXMLGUIConfigFile() 0458 { 0459 const KisKXMLGUIClient *kxmlguiClient = q->parentGUIClient(); 0460 // return false if there is no KisKXMLGUIClient 0461 if (!kxmlguiClient || kxmlguiClient->xmlFile().isEmpty()) { 0462 return false; 0463 } 0464 0465 0466 QString attrShortcut = QStringLiteral("shortcut"); 0467 0468 // Read XML file 0469 QString sXml(KisKXMLGUIFactory::readConfigFile(kxmlguiClient->xmlFile(), q->componentName())); 0470 QDomDocument doc; 0471 doc.setContent(sXml); 0472 0473 // Process XML data 0474 0475 // Get hold of ActionProperties tag 0476 QDomElement elem = KisKXMLGUIFactory::actionPropertiesElement(doc); 0477 0478 // now, iterate through our actions 0479 for (QMap<QString, QAction *>::ConstIterator it = actionByName.constBegin(); 0480 it != actionByName.constEnd(); ++it) { 0481 QAction *action = it.value(); 0482 if (!action) { 0483 continue; 0484 } 0485 0486 QString actionName = it.key(); 0487 0488 // If the action name starts with unnamed- spit out a warning and ignore 0489 // it. That name will change at will and will break loading writing 0490 if (actionName.startsWith(QLatin1String("unnamed-"))) { 0491 qCritical() << "Skipped writing shortcut for action " << actionName << "(" << action->text() << ")!"; 0492 continue; 0493 } 0494 0495 bool bSameAsDefault = (action->shortcuts() == q->defaultShortcuts(action)); 0496 0497 // now see if this element already exists 0498 // and create it if necessary (unless bSameAsDefault) 0499 QDomElement act_elem = KisKXMLGUIFactory::findActionByName(elem, actionName, !bSameAsDefault); 0500 if (act_elem.isNull()) { 0501 continue; 0502 } 0503 0504 if (bSameAsDefault) { 0505 act_elem.removeAttribute(attrShortcut); 0506 if (act_elem.attributes().count() == 1) { 0507 elem.removeChild(act_elem); 0508 } 0509 } else { 0510 act_elem.setAttribute(attrShortcut, QKeySequence::listToString(action->shortcuts())); 0511 } 0512 } 0513 0514 // Write back to XML file 0515 KisKXMLGUIFactory::saveConfigFile(doc, kxmlguiClient->localXMLFile(), q->componentName()); 0516 return true; 0517 } 0518 0519 void KisKActionCollection::writeSettings(KConfigGroup *config, 0520 bool writeScheme, 0521 QAction *oneAction) const 0522 { 0523 // If the caller didn't provide a config group we try to save the KisKXMLGUI 0524 // Configuration file. (This will work if the parentGUI was set and has a 0525 // valid configuration file.) 0526 if (config == 0 && d->writeKisKXMLGUIConfigFile()) { 0527 return; 0528 } 0529 0530 0531 KConfigGroup cg(KSharedConfig::openConfig(), configGroup()); 0532 if (!config) { 0533 config = &cg; 0534 } 0535 0536 QList<QAction *> writeActions; 0537 if (oneAction) { 0538 writeActions.append(oneAction); 0539 } else { 0540 writeActions = actions(); 0541 } 0542 0543 for (QMap<QString, QAction *>::ConstIterator it = d->actionByName.constBegin(); 0544 it != d->actionByName.constEnd(); ++it) { 0545 0546 QAction *action = it.value(); 0547 if (!action) { 0548 continue; 0549 } 0550 0551 QString actionName = it.key(); 0552 0553 // If the action name starts with unnamed- spit out a warning and ignore 0554 // it. That name will change at will and will break loading writing 0555 if (actionName.startsWith(QLatin1String("unnamed-"))) { 0556 qCritical() << "Skipped saving shortcut for action without name " \ 0557 << action->text() << "!"; 0558 continue; 0559 } 0560 0561 // Write the shortcut 0562 if (isShortcutsConfigurable(action)) { 0563 bool bConfigHasAction = !config->readEntry(actionName, QString()).isEmpty(); 0564 bool bSameAsDefault = (action->shortcuts() == defaultShortcuts(action)); 0565 // If the current shortcut differs from the default, we want to write. 0566 0567 KConfigGroup::WriteConfigFlags flags = KConfigGroup::Persistent; 0568 0569 if (writeScheme || !bSameAsDefault) { 0570 // We are instructed to write all shortcuts or the shortcut is 0571 // not set to its default value. Write it 0572 QString s = QKeySequence::listToString(action->shortcuts()); 0573 if (s.isEmpty()) { 0574 s = QStringLiteral("none"); 0575 } 0576 config->writeEntry(actionName, s, flags); 0577 } else if (bConfigHasAction) { 0578 // This key is the same as default but exists in config file. 0579 // Remove it. 0580 config->deleteEntry(actionName, flags); 0581 } 0582 } 0583 } 0584 0585 config->sync(); 0586 } 0587 0588 void KisKActionCollection::slotActionTriggered() 0589 { 0590 QAction *action = qobject_cast<QAction *>(sender()); 0591 if (action) { 0592 emit actionTriggered(action); 0593 } 0594 } 0595 0596 void KisKActionCollection::slotActionHighlighted() 0597 { 0598 slotActionHovered(); 0599 } 0600 0601 void KisKActionCollection::slotActionHovered() 0602 { 0603 QAction *action = qobject_cast<QAction *>(sender()); 0604 if (action) { 0605 emit actionHighlighted(action); 0606 emit actionHovered(action); 0607 } 0608 } 0609 0610 void KisKActionCollectionPrivate::_k_actionDestroyed(QObject *obj) 0611 { 0612 unlistAction(obj); 0613 } 0614 0615 void KisKActionCollection::connectNotify(const QMetaMethod &signal) 0616 { 0617 if (d->connectHovered && d->connectTriggered) { 0618 return; 0619 } 0620 0621 if (signal.methodSignature() == "actionHighlighted(QAction*)" || 0622 signal.methodSignature() == "actionHovered(QAction*)") { 0623 if (!d->connectHovered) { 0624 d->connectHovered = true; 0625 Q_FOREACH (QAction *action, actions()) { 0626 connect(action, SIGNAL(hovered()), SLOT(slotActionHovered())); 0627 } 0628 } 0629 0630 } else if (signal.methodSignature() == "actionTriggered(QAction*)") { 0631 if (!d->connectTriggered) { 0632 d->connectTriggered = true; 0633 Q_FOREACH (QAction *action, actions()) { 0634 connect(action, SIGNAL(triggered(bool)), SLOT(slotActionTriggered())); 0635 } 0636 } 0637 } 0638 0639 QObject::connectNotify(signal); 0640 } 0641 0642 const QList< KisKActionCollection * > &KisKActionCollection::allCollections() 0643 { 0644 return KisKActionCollectionPrivate::s_allCollections; 0645 } 0646 0647 void KisKActionCollection::associateWidget(QWidget *widget) const 0648 { 0649 Q_FOREACH (QAction *action, actions()) { 0650 if (!widget->actions().contains(action)) { 0651 widget->addAction(action); 0652 } 0653 } 0654 } 0655 0656 void KisKActionCollection::addAssociatedWidget(QWidget *widget) 0657 { 0658 if (!d->associatedWidgets.contains(widget)) { 0659 widget->addActions(actions()); 0660 0661 d->associatedWidgets.append(widget); 0662 connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(_k_associatedWidgetDestroyed(QObject*))); 0663 } 0664 } 0665 0666 void KisKActionCollection::removeAssociatedWidget(QWidget *widget) 0667 { 0668 Q_FOREACH (QAction *action, actions()) { 0669 widget->removeAction(action); 0670 } 0671 0672 d->associatedWidgets.removeAll(widget); 0673 disconnect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(_k_associatedWidgetDestroyed(QObject*))); 0674 } 0675 0676 QAction *KisKActionCollectionPrivate::unlistAction(QObject *action) 0677 { 0678 // ATTENTION: 0679 // This method is called with an QObject formerly known as a QAction 0680 // during _k_actionDestroyed(). So don't do fancy stuff here that needs a 0681 // real QAction! 0682 0683 // Get the index for the action 0684 const auto indexOf = [&](const QObject *action, int from = 0) -> int { 0685 for (int i = from; i < actions.size(); i++) { 0686 if (actions[i] == action) { 0687 return i; 0688 } 0689 } 0690 return -1; 0691 }; 0692 0693 int index = indexOf(action); 0694 0695 // Action not found. 0696 if (index == -1) { 0697 return 0; 0698 } 0699 0700 // An action collection can't have the same action twice. 0701 Q_ASSERT(indexOf(action, index + 1) == -1); 0702 0703 // Get the actions name 0704 const QString name = action->objectName(); 0705 0706 // Remove the action 0707 actionByName.remove(name); 0708 // Retrieve the typed QObject* pointer 0709 // ATTENTION: THIS ACTION IS PARTIALLY DESTROYED! 0710 QAction *tmp = actions.at(index); 0711 actions.removeAt(index); 0712 0713 // Remove the action from the categories. Should be only one 0714 QList<KisKActionCategory *> categories = q->findChildren<KisKActionCategory *>(); 0715 Q_FOREACH (KisKActionCategory *category, categories) { 0716 category->unlistAction(tmp); 0717 } 0718 0719 return tmp; 0720 } 0721 0722 QList< QWidget * > KisKActionCollection::associatedWidgets() const 0723 { 0724 return d->associatedWidgets; 0725 } 0726 0727 void KisKActionCollection::clearAssociatedWidgets() 0728 { 0729 Q_FOREACH (QWidget *widget, d->associatedWidgets) 0730 Q_FOREACH (QAction *action, actions()) { 0731 widget->removeAction(action); 0732 } 0733 0734 d->associatedWidgets.clear(); 0735 } 0736 0737 void KisKActionCollectionPrivate::_k_associatedWidgetDestroyed(QObject *obj) 0738 { 0739 associatedWidgets.removeAll(static_cast<QWidget *>(obj)); 0740 } 0741 0742 #include "moc_kactioncollection.cpp"