KDEUI
kxmlguiclient.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2000 Simon Hausmann <hausmann@kde.org> 00003 Copyright (C) 2000 Kurt Granroth <granroth@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License version 2 as published by the Free Software Foundation. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "kxmlguiclient.h" 00021 #include "kxmlguiversionhandler_p.h" 00022 #include "kxmlguifactory.h" 00023 #include "kxmlguibuilder.h" 00024 00025 #include <QtCore/QDir> 00026 #include <QtCore/QFile> 00027 #include <QtXml/QDomDocument> 00028 #include <QtCore/QTextIStream> 00029 #include <QtCore/QRegExp> 00030 #include <QtCore/QPointer> 00031 00032 #include <kcomponentdata.h> 00033 #include <kstandarddirs.h> 00034 #include <kdebug.h> 00035 #include <kauthorized.h> 00036 00037 #include "kaction.h" 00038 #include "kactioncollection.h" 00039 00040 #include <assert.h> 00041 00042 class KXMLGUIClientPrivate 00043 { 00044 public: 00045 KXMLGUIClientPrivate() 00046 { 00047 m_componentData = KGlobal::mainComponent(); 00048 m_parent = 0L; 00049 m_builder = 0L; 00050 m_actionCollection = 0; 00051 } 00052 ~KXMLGUIClientPrivate() 00053 { 00054 } 00055 00056 bool mergeXML( QDomElement &base, QDomElement &additive, 00057 KActionCollection *actionCollection ); 00058 bool isEmptyContainer(const QDomElement& base, 00059 KActionCollection *actionCollection) const; 00060 00061 QDomElement findMatchingElement( const QDomElement &base, 00062 const QDomElement &additive ); 00063 00064 KComponentData m_componentData; 00065 00066 QDomDocument m_doc; 00067 KActionCollection *m_actionCollection; 00068 QDomDocument m_buildDocument; 00069 QPointer<KXMLGUIFactory> m_factory; 00070 KXMLGUIClient *m_parent; 00071 //QPtrList<KXMLGUIClient> m_supers; 00072 QList<KXMLGUIClient*> m_children; 00073 KXMLGUIBuilder *m_builder; 00074 QString m_xmlFile; 00075 QString m_localXMLFile; 00076 00077 // Actions to enable/disable on a state change 00078 QMap<QString,KXMLGUIClient::StateChange> m_actionsStateMap; 00079 }; 00080 00081 00082 KXMLGUIClient::KXMLGUIClient() 00083 : d( new KXMLGUIClientPrivate ) 00084 { 00085 } 00086 00087 KXMLGUIClient::KXMLGUIClient( KXMLGUIClient *parent ) 00088 : d( new KXMLGUIClientPrivate ) 00089 { 00090 parent->insertChildClient( this ); 00091 } 00092 00093 KXMLGUIClient::~KXMLGUIClient() 00094 { 00095 if ( d->m_parent ) { 00096 d->m_parent->removeChildClient( this ); 00097 } 00098 00099 if ( d->m_factory ) { 00100 kWarning(240) << this << "deleted without having been removed from the factory first. This will leak standalone popupmenus and could lead to crashes."; 00101 d->m_factory->forgetClient(this); 00102 } 00103 00104 foreach (KXMLGUIClient* client, d->m_children) { 00105 if (d->m_factory) 00106 d->m_factory->forgetClient(client); 00107 assert( client->d->m_parent == this ); 00108 client->d->m_parent = 0; 00109 } 00110 00111 delete d->m_actionCollection; 00112 delete d; 00113 } 00114 00115 QAction *KXMLGUIClient::action( const char *name ) const 00116 { 00117 QAction* act = actionCollection()->action( name ); 00118 if ( !act ) { 00119 foreach (KXMLGUIClient* client, d->m_children) { 00120 act = client->actionCollection()->action( name ); 00121 if ( act ) 00122 break; 00123 } 00124 } 00125 return act; 00126 } 00127 00128 KActionCollection *KXMLGUIClient::actionCollection() const 00129 { 00130 if ( !d->m_actionCollection ) 00131 { 00132 d->m_actionCollection = new KActionCollection( this ); 00133 d->m_actionCollection->setObjectName( "KXMLGUIClient-KActionCollection" ); 00134 } 00135 return d->m_actionCollection; 00136 } 00137 00138 QAction *KXMLGUIClient::action( const QDomElement &element ) const 00139 { 00140 static const QString &attrName = KGlobal::staticQString( "name" ); 00141 return actionCollection()->action( qPrintable(element.attribute( attrName )) ); 00142 } 00143 00144 KComponentData KXMLGUIClient::componentData() const 00145 { 00146 return d->m_componentData; 00147 } 00148 00149 QDomDocument KXMLGUIClient::domDocument() const 00150 { 00151 return d->m_doc; 00152 } 00153 00154 QString KXMLGUIClient::xmlFile() const 00155 { 00156 return d->m_xmlFile; 00157 } 00158 00159 QString KXMLGUIClient::localXMLFile() const 00160 { 00161 if ( !d->m_localXMLFile.isEmpty() ) 00162 return d->m_localXMLFile; 00163 00164 if ( !QDir::isRelativePath(d->m_xmlFile) ) 00165 return QString(); // can't save anything here 00166 00167 if (d->m_xmlFile.isEmpty()) // setXMLFile not called at all, can't save. Use case: ToolBarHandler 00168 return QString(); 00169 00170 return KStandardDirs::locateLocal( "data", componentData().componentName() + '/' + d->m_xmlFile ); 00171 } 00172 00173 00174 void KXMLGUIClient::reloadXML() 00175 { 00176 // TODO: this method can't be used for the KXmlGuiWindow, since it doesn't merge in ui_standards.rc! 00177 // -> KDE5: load ui_standards_rc in setXMLFile using a flag, and remember that flag? 00178 // and then KEditToolBar can use reloadXML. 00179 QString file( xmlFile() ); 00180 if ( !file.isEmpty() ) 00181 setXMLFile( file ); 00182 } 00183 00184 void KXMLGUIClient::setComponentData(const KComponentData &componentData) 00185 { 00186 d->m_componentData = componentData; 00187 actionCollection()->setComponentData( componentData ); 00188 if ( d->m_builder ) 00189 d->m_builder->setBuilderClient( this ); 00190 } 00191 00192 void KXMLGUIClient::loadStandardsXmlFile() 00193 { 00194 const QString file = KStandardDirs::locate("config", "ui/ui_standards.rc", componentData()); 00195 if (file.isEmpty()) { 00196 kWarning() << "ui/ui_standards.rc not found in" << componentData().dirs()->resourceDirs("config"); 00197 } else { 00198 const QString doc = KXMLGUIFactory::readConfigFile( file ); 00199 setXML( doc ); 00200 } 00201 } 00202 00203 void KXMLGUIClient::setXMLFile( const QString& _file, bool merge, bool setXMLDoc ) 00204 { 00205 // store our xml file name 00206 if ( !_file.isNull() ) 00207 d->m_xmlFile = _file; 00208 00209 if ( !setXMLDoc ) 00210 return; 00211 00212 QString file = _file; 00213 QStringList allFiles; 00214 if ( !QDir::isRelativePath( file ) ) { 00215 allFiles.append( file ); 00216 } else { 00217 const QString filter = componentData().componentName() + '/' + _file; 00218 allFiles = componentData().dirs()->findAllResources("data", filter) + 00219 componentData().dirs()->findAllResources("data", _file); 00220 } 00221 if ( allFiles.isEmpty() && !_file.isEmpty() ) { 00222 // if a non-empty file gets passed and we can't find it, 00223 // inform the developer using some debug output 00224 kWarning() << "cannot find .rc file" << _file << "for component" << componentData().componentName(); 00225 } 00226 00227 // make sure to merge the settings from any file specified by setLocalXMLFile() 00228 if ( !d->m_localXMLFile.isEmpty() && !file.endsWith("ui_standards.rc") ) { 00229 const bool exists = QDir::isRelativePath(d->m_localXMLFile) || QFile::exists(d->m_localXMLFile); 00230 if (exists && !allFiles.contains(d->m_localXMLFile)) 00231 allFiles.prepend( d->m_localXMLFile ); 00232 } 00233 00234 QString doc; 00235 if ( !allFiles.isEmpty() ) 00236 file = findMostRecentXMLFile(allFiles, doc); 00237 00238 // Always call setXML, even on error, so that we don't keep all ui_standards.rc menus. 00239 setXML( doc, merge ); 00240 } 00241 00242 void KXMLGUIClient::setLocalXMLFile( const QString &file ) 00243 { 00244 d->m_localXMLFile = file; 00245 } 00246 00247 void KXMLGUIClient::replaceXMLFile( const QString& xmlfile, const QString& localxmlfile, bool merge ) 00248 { 00249 if ( !QDir::isAbsolutePath ( xmlfile ) ) { 00250 kWarning() << "xml file" << xmlfile << "is not an absolute path"; 00251 } 00252 00253 setLocalXMLFile ( localxmlfile ); 00254 setXMLFile ( xmlfile, merge ); 00255 } 00256 00257 void KXMLGUIClient::setXML( const QString &document, bool merge ) 00258 { 00259 QDomDocument doc; 00260 QString errorMsg; 00261 int errorLine, errorColumn; 00262 // QDomDocument raises a parse error on empty document, but we accept no app-specific document, 00263 // in which case you only get ui_standards.rc layout. 00264 bool result = document.isEmpty() || doc.setContent(document, &errorMsg, &errorLine, &errorColumn); 00265 if ( result ) { 00266 setDOMDocument( doc, merge ); 00267 } else { 00268 #ifdef NDEBUG 00269 kError(240) << "Error parsing XML document:" << errorMsg << "at line" << errorLine << "column" << errorColumn; 00270 setDOMDocument(QDomDocument(), merge); // otherwise empty menus from ui_standards.rc stay around 00271 #else 00272 kFatal() << "Error parsing XML document:" << errorMsg << "at line" << errorLine << "column" << errorColumn; 00273 #endif 00274 } 00275 } 00276 00277 void KXMLGUIClient::setDOMDocument( const QDomDocument &document, bool merge ) 00278 { 00279 if ( merge && !d->m_doc.isNull() ) 00280 { 00281 QDomElement base = d->m_doc.documentElement(); 00282 00283 QDomElement e = document.documentElement(); 00284 00285 // merge our original (global) xml with our new one 00286 d->mergeXML(base, e, actionCollection()); 00287 00288 // reassign our pointer as mergeXML might have done something 00289 // strange to it 00290 base = d->m_doc.documentElement(); 00291 00292 //kDebug(260) << "Result of xmlgui merging:" << d->m_doc.toString(); 00293 00294 // we want some sort of failsafe.. just in case 00295 if ( base.isNull() ) 00296 d->m_doc = document; 00297 } 00298 else 00299 { 00300 d->m_doc = document; 00301 } 00302 00303 setXMLGUIBuildDocument( QDomDocument() ); 00304 } 00305 00306 // if (equals(a,b)) is more readable than if (a.compare(b, Qt::CaseInsensitive)==0) 00307 static bool equalstr(const QString& a, const QString& b) { 00308 return a.compare(b, Qt::CaseInsensitive) == 0; 00309 } 00310 00311 bool KXMLGUIClientPrivate::mergeXML( QDomElement &base, QDomElement &additive, KActionCollection *actionCollection ) 00312 { 00313 static const QString &tagAction = KGlobal::staticQString( "Action" ); 00314 static const QString &tagMerge = KGlobal::staticQString( "Merge" ); 00315 static const QString &tagSeparator = KGlobal::staticQString( "Separator" ); 00316 static const QString &attrName = KGlobal::staticQString( "name" ); 00317 static const QString &attrAppend = KGlobal::staticQString( "append" ); 00318 static const QString &attrWeakSeparator = KGlobal::staticQString( "weakSeparator" ); 00319 static const QString &tagMergeLocal = KGlobal::staticQString( "MergeLocal" ); 00320 static const QString &tagText = KGlobal::staticQString( "text" ); 00321 static const QString &attrAlreadyVisited = KGlobal::staticQString( "alreadyVisited" ); 00322 static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" ); 00323 static const QString &attrOne = KGlobal::staticQString( "1" ); 00324 00325 // there is a possibility that we don't want to merge in the 00326 // additive.. rather, we might want to *replace* the base with the 00327 // additive. this can be for any container.. either at a file wide 00328 // level or a simple container level. we look for the 'noMerge' 00329 // tag, in any event and just replace the old with the new 00330 if ( additive.attribute(attrNoMerge) == attrOne ) // ### use toInt() instead? (Simon) 00331 { 00332 base.parentNode().replaceChild(additive, base); 00333 return true; 00334 } else { 00335 // Merge attributes 00336 { 00337 const QDomNamedNodeMap attribs = additive.attributes(); 00338 const uint attribcount = attribs.count(); 00339 00340 for(uint i = 0; i < attribcount; ++i) { 00341 const QDomNode node = attribs.item(i); 00342 base.setAttribute(node.nodeName(), node.nodeValue()); 00343 } 00344 } 00345 00346 // iterate over all elements in the container (of the global DOM tree) 00347 QDomNode n = base.firstChild(); 00348 while ( !n.isNull() ) 00349 { 00350 QDomElement e = n.toElement(); 00351 n = n.nextSibling(); // Advance now so that we can safely delete e 00352 if (e.isNull()) 00353 continue; 00354 00355 const QString tag = e.tagName(); 00356 00357 // if there's an action tag in the global tree and the action is 00358 // not implemented, then we remove the element 00359 if (equalstr(tag, tagAction)) { 00360 const QString name = e.attribute(attrName); 00361 if (!actionCollection->action(name) || 00362 !KAuthorized::authorizeKAction(name)) 00363 { 00364 // remove this child as we aren't using it 00365 base.removeChild( e ); 00366 continue; 00367 } 00368 } 00369 00370 // if there's a separator defined in the global tree, then add an 00371 // attribute, specifying that this is a "weak" separator 00372 else if (equalstr(tag, tagSeparator)) { 00373 e.setAttribute( attrWeakSeparator, (uint)1 ); 00374 00375 // okay, hack time. if the last item was a weak separator OR 00376 // this is the first item in a container, then we nuke the 00377 // current one 00378 QDomElement prev = e.previousSibling().toElement(); 00379 if (prev.isNull() || 00380 (equalstr(prev.tagName(), tagSeparator) && !prev.attribute(attrWeakSeparator).isNull() ) || 00381 (equalstr(prev.tagName(), tagText))) { 00382 // the previous element was a weak separator or didn't exist 00383 base.removeChild( e ); 00384 continue; 00385 } 00386 } 00387 00388 // the MergeLocal tag lets us specify where non-standard elements 00389 // of the local tree shall be merged in. After inserting the 00390 // elements we delete this element 00391 else if (equalstr(tag, tagMergeLocal)) { 00392 QDomNode it = additive.firstChild(); 00393 while ( !it.isNull() ) 00394 { 00395 QDomElement newChild = it.toElement(); 00396 it = it.nextSibling(); 00397 if (newChild.isNull() ) 00398 continue; 00399 00400 if (equalstr(newChild.tagName(), tagText)) 00401 continue; 00402 00403 if ( newChild.attribute( attrAlreadyVisited ) == attrOne ) 00404 continue; 00405 00406 QString itAppend( newChild.attribute( attrAppend ) ); 00407 QString elemName( e.attribute( attrName ) ); 00408 00409 if ( ( itAppend.isNull() && elemName.isEmpty() ) || 00410 ( itAppend == elemName ) ) 00411 { 00412 // first, see if this new element matches a standard one in 00413 // the global file. if it does, then we skip it as it will 00414 // be merged in, later 00415 QDomElement matchingElement = findMatchingElement( newChild, base ); 00416 if (matchingElement.isNull() || equalstr(newChild.tagName(), tagSeparator)) 00417 base.insertBefore( newChild, e ); 00418 } 00419 } 00420 00421 base.removeChild( e ); 00422 continue; 00423 } 00424 00425 else if (equalstr(tag, tagText)) { 00426 continue; 00427 } 00428 else if (equalstr(tag, tagMerge)) { 00429 continue; 00430 } 00431 00432 // in this last case we check for a separator tag and, if not, we 00433 // can be sure that it is a container --> proceed with child nodes 00434 // recursively and delete the just proceeded container item in 00435 // case it is empty (if the recursive call returns true) 00436 else { 00437 QDomElement matchingElement = findMatchingElement( e, additive ); 00438 if ( !matchingElement.isNull() ) 00439 { 00440 matchingElement.setAttribute( attrAlreadyVisited, (uint)1 ); 00441 00442 if ( mergeXML( e, matchingElement, actionCollection ) ) 00443 { 00444 base.removeChild( e ); 00445 additive.removeChild(matchingElement); // make sure we don't append it below 00446 continue; 00447 } 00448 00449 continue; 00450 } 00451 else 00452 { 00453 // this is an important case here! We reach this point if the 00454 // "local" tree does not contain a container definition for 00455 // this container. However we have to call mergeXML recursively 00456 // and make it check if there are actions implemented for this 00457 // container. *If* none, then we can remove this container now 00458 QDomElement dummy; 00459 if ( mergeXML( e, dummy, actionCollection ) ) 00460 base.removeChild( e ); 00461 continue; 00462 } 00463 } 00464 } 00465 00466 //here we append all child elements which were not inserted 00467 //previously via the LocalMerge tag 00468 n = additive.firstChild(); 00469 while ( !n.isNull() ) 00470 { 00471 QDomElement e = n.toElement(); 00472 n = n.nextSibling(); // Advance now so that we can safely delete e 00473 if (e.isNull()) 00474 continue; 00475 00476 QDomElement matchingElement = findMatchingElement( e, base ); 00477 00478 if ( matchingElement.isNull() ) 00479 { 00480 base.appendChild( e ); 00481 } 00482 } 00483 00484 // do one quick check to make sure that the last element was not 00485 // a weak separator 00486 QDomElement last = base.lastChild().toElement(); 00487 if (equalstr(last.tagName(), tagSeparator) && 00488 (!last.attribute(attrWeakSeparator).isNull())) { 00489 base.removeChild( last ); 00490 } 00491 } 00492 00493 return isEmptyContainer(base, actionCollection); 00494 } 00495 00496 bool KXMLGUIClientPrivate::isEmptyContainer(const QDomElement& base, KActionCollection *actionCollection) const 00497 { 00498 // now we check if we are empty (in which case we return "true", to 00499 // indicate the caller that it can delete "us" (the base element 00500 // argument of "this" call) 00501 QDomNode n = base.firstChild(); 00502 while (!n.isNull()) { 00503 const QDomElement e = n.toElement(); 00504 n = n.nextSibling(); // Advance now so that we can safely delete e 00505 if (e.isNull()) 00506 continue; 00507 00508 const QString tag = e.tagName(); 00509 00510 static const QString &tagAction = KGlobal::staticQString("Action"); 00511 static const QString &tagSeparator = KGlobal::staticQString("Separator"); 00512 static const QString &tagText = KGlobal::staticQString("text"); 00513 static const QString &tagMerge = KGlobal::staticQString("Merge"); 00514 if (equalstr(tag, tagAction)) { 00515 // if base contains an implemented action, then we must not get 00516 // deleted (note that the actionCollection contains both, 00517 // "global" and "local" actions) 00518 static const QString &attrName = KGlobal::staticQString("name"); 00519 if (actionCollection->action(e.attribute(attrName))) { 00520 return false; 00521 } 00522 } 00523 else if (equalstr(tag, tagSeparator)) { 00524 // if we have a separator which has *not* the weak attribute 00525 // set, then it must be owned by the "local" tree in which case 00526 // we must not get deleted either 00527 static const QString &attrWeakSeparator = KGlobal::staticQString("weakSeparator"); 00528 const QString weakAttr = e.attribute(attrWeakSeparator); 00529 if (weakAttr.isEmpty() || weakAttr.toInt() != 1) { 00530 return false; 00531 } 00532 } 00533 00534 else if (equalstr(tag, tagMerge)) { 00535 continue; 00536 } 00537 00538 // a text tag is NOT enough to spare this container 00539 else if (equalstr(tag, tagText)) { 00540 continue; 00541 } 00542 00543 // what's left are non-empty containers! *don't* delete us in this 00544 // case (at this position we can be *sure* that the container is 00545 // *not* empty, as the recursive call for it was in the first loop 00546 // which deleted the element in case the call returned "true" 00547 else { 00548 return false; 00549 } 00550 } 00551 00552 return true; // I'm empty, please delete me. 00553 } 00554 00555 QDomElement KXMLGUIClientPrivate::findMatchingElement( const QDomElement &base, const QDomElement &additive ) 00556 { 00557 static const QString &tagAction = KGlobal::staticQString( "Action" ); 00558 static const QString &tagMergeLocal = KGlobal::staticQString( "MergeLocal" ); 00559 static const QString &attrName = KGlobal::staticQString( "name" ); 00560 00561 QDomNode n = additive.firstChild(); 00562 while ( !n.isNull() ) 00563 { 00564 QDomElement e = n.toElement(); 00565 n = n.nextSibling(); // Advance now so that we can safely delete e -- TODO we don't, so simplify this 00566 if (e.isNull()) 00567 continue; 00568 00569 const QString tag = e.tagName(); 00570 // skip all action and merge tags as we will never use them 00571 if (equalstr(tag, tagAction) 00572 || equalstr(tag, tagMergeLocal)) { 00573 continue; 00574 } 00575 00576 // now see if our tags are equivalent 00577 if (equalstr(tag, base.tagName()) && 00578 e.attribute(attrName) == base.attribute(attrName)) { 00579 return e; 00580 } 00581 } 00582 00583 // nope, return a (now) null element 00584 return QDomElement(); 00585 } 00586 00587 void KXMLGUIClient::setXMLGUIBuildDocument( const QDomDocument &doc ) 00588 { 00589 d->m_buildDocument = doc; 00590 } 00591 00592 QDomDocument KXMLGUIClient::xmlguiBuildDocument() const 00593 { 00594 return d->m_buildDocument; 00595 } 00596 00597 void KXMLGUIClient::setFactory( KXMLGUIFactory *factory ) 00598 { 00599 d->m_factory = factory; 00600 } 00601 00602 KXMLGUIFactory *KXMLGUIClient::factory() const 00603 { 00604 return d->m_factory; 00605 } 00606 00607 KXMLGUIClient *KXMLGUIClient::parentClient() const 00608 { 00609 return d->m_parent; 00610 } 00611 00612 void KXMLGUIClient::insertChildClient( KXMLGUIClient *child ) 00613 { 00614 if ( child->d->m_parent ) 00615 child->d->m_parent->removeChildClient( child ); 00616 d->m_children.append( child ); 00617 child->d->m_parent = this; 00618 } 00619 00620 void KXMLGUIClient::removeChildClient( KXMLGUIClient *child ) 00621 { 00622 assert( d->m_children.contains( child ) ); 00623 d->m_children.removeAll( child ); 00624 child->d->m_parent = 0; 00625 } 00626 00627 /*bool KXMLGUIClient::addSuperClient( KXMLGUIClient *super ) 00628 { 00629 if ( d->m_supers.contains( super ) ) 00630 return false; 00631 d->m_supers.append( super ); 00632 return true; 00633 }*/ 00634 00635 QList<KXMLGUIClient*> KXMLGUIClient::childClients() 00636 { 00637 return d->m_children; 00638 } 00639 00640 void KXMLGUIClient::setClientBuilder( KXMLGUIBuilder *builder ) 00641 { 00642 d->m_builder = builder; 00643 if ( builder ) 00644 builder->setBuilderComponentData( componentData() ); 00645 } 00646 00647 KXMLGUIBuilder *KXMLGUIClient::clientBuilder() const 00648 { 00649 return d->m_builder; 00650 } 00651 00652 void KXMLGUIClient::plugActionList( const QString &name, const QList<QAction*> &actionList ) 00653 { 00654 if ( !d->m_factory ) 00655 return; 00656 00657 d->m_factory->plugActionList( this, name, actionList ); 00658 } 00659 00660 void KXMLGUIClient::unplugActionList( const QString &name ) 00661 { 00662 if ( !d->m_factory ) 00663 return; 00664 00665 d->m_factory->unplugActionList( this, name ); 00666 } 00667 00668 QString KXMLGUIClient::findMostRecentXMLFile( const QStringList &files, QString &doc ) 00669 { 00670 KXmlGuiVersionHandler versionHandler(files); 00671 doc = versionHandler.finalDocument(); 00672 return versionHandler.finalFile(); 00673 } 00674 00675 void KXMLGUIClient::addStateActionEnabled(const QString& state, 00676 const QString& action) 00677 { 00678 StateChange stateChange = getActionsToChangeForState(state); 00679 00680 stateChange.actionsToEnable.append( action ); 00681 //kDebug(260) << "KXMLGUIClient::addStateActionEnabled( " << state << ", " << action << ")"; 00682 00683 d->m_actionsStateMap.insert( state, stateChange ); 00684 } 00685 00686 00687 void KXMLGUIClient::addStateActionDisabled(const QString& state, 00688 const QString& action) 00689 { 00690 StateChange stateChange = getActionsToChangeForState(state); 00691 00692 stateChange.actionsToDisable.append( action ); 00693 //kDebug(260) << "KXMLGUIClient::addStateActionDisabled( " << state << ", " << action << ")"; 00694 00695 d->m_actionsStateMap.insert( state, stateChange ); 00696 } 00697 00698 00699 KXMLGUIClient::StateChange KXMLGUIClient::getActionsToChangeForState(const QString& state) 00700 { 00701 return d->m_actionsStateMap[state]; 00702 } 00703 00704 00705 void KXMLGUIClient::stateChanged(const QString &newstate, KXMLGUIClient::ReverseStateChange reverse) 00706 { 00707 StateChange stateChange = getActionsToChangeForState(newstate); 00708 00709 bool setTrue = (reverse == StateNoReverse); 00710 bool setFalse = !setTrue; 00711 00712 // Enable actions which need to be enabled... 00713 // 00714 for ( QStringList::const_iterator it = stateChange.actionsToEnable.constBegin(); 00715 it != stateChange.actionsToEnable.constEnd(); ++it ) { 00716 00717 QAction *action = actionCollection()->action(qPrintable((*it))); 00718 if (action) action->setEnabled(setTrue); 00719 } 00720 00721 // and disable actions which need to be disabled... 00722 // 00723 for ( QStringList::const_iterator it = stateChange.actionsToDisable.constBegin(); 00724 it != stateChange.actionsToDisable.constEnd(); ++it ) { 00725 00726 QAction *action = actionCollection()->action(qPrintable((*it))); 00727 if (action) action->setEnabled(setFalse); 00728 } 00729 00730 } 00731 00732 void KXMLGUIClient::beginXMLPlug( QWidget* w ) 00733 { 00734 actionCollection()->addAssociatedWidget( w ); 00735 foreach (KXMLGUIClient* client, d->m_children) 00736 client->beginXMLPlug( w ); 00737 } 00738 00739 void KXMLGUIClient::endXMLPlug() 00740 { 00741 } 00742 00743 void KXMLGUIClient::prepareXMLUnplug( QWidget * w ) 00744 { 00745 actionCollection()->removeAssociatedWidget( w ); 00746 foreach (KXMLGUIClient* client, d->m_children) 00747 client->prepareXMLUnplug( w ); 00748 } 00749 00750 void KXMLGUIClient::virtual_hook( int, void* ) 00751 { /*BASE::virtual_hook( id, data );*/ }
KDE 4.6 API Reference