kdeui Library API Documentation

kxmlguiclient.cpp

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., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 00018 */ 00019 00020 #include "kxmlguiclient.h" 00021 #include "kxmlguifactory.h" 00022 #include "kxmlguibuilder.h" 00023 00024 #include <qdir.h> 00025 #include <qfile.h> 00026 #include <qdom.h> 00027 #include <qtextstream.h> 00028 #include <qregexp.h> 00029 #include <qguardedptr.h> 00030 00031 #include <kinstance.h> 00032 #include <kstandarddirs.h> 00033 #include <kdebug.h> 00034 #include <kaction.h> 00035 #include <kapplication.h> 00036 00037 #include <assert.h> 00038 00039 class KXMLGUIClientPrivate 00040 { 00041 public: 00042 KXMLGUIClientPrivate() 00043 { 00044 m_instance = KGlobal::instance(); 00045 m_parent = 0L; 00046 m_builder = 0L; 00047 m_actionCollection = 0; 00048 } 00049 ~KXMLGUIClientPrivate() 00050 { 00051 } 00052 00053 KInstance *m_instance; 00054 00055 QDomDocument m_doc; 00056 KActionCollection *m_actionCollection; 00057 QDomDocument m_buildDocument; 00058 QGuardedPtr<KXMLGUIFactory> m_factory; 00059 KXMLGUIClient *m_parent; 00060 //QPtrList<KXMLGUIClient> m_supers; 00061 QPtrList<KXMLGUIClient> m_children; 00062 KXMLGUIBuilder *m_builder; 00063 QString m_xmlFile; 00064 QString m_localXMLFile; 00065 }; 00066 00067 KXMLGUIClient::KXMLGUIClient() 00068 { 00069 d = new KXMLGUIClientPrivate; 00070 } 00071 00072 KXMLGUIClient::KXMLGUIClient( KXMLGUIClient *parent ) 00073 { 00074 d = new KXMLGUIClientPrivate; 00075 parent->insertChildClient( this ); 00076 } 00077 00078 KXMLGUIClient::~KXMLGUIClient() 00079 { 00080 if ( d->m_parent ) 00081 d->m_parent->removeChildClient( this ); 00082 00083 QPtrListIterator<KXMLGUIClient> it( d->m_children ); 00084 for ( ; it.current(); ++it ) { 00085 assert( it.current()->d->m_parent == this ); 00086 it.current()->d->m_parent = 0; 00087 } 00088 00089 delete d->m_actionCollection; 00090 delete d; 00091 } 00092 00093 KAction *KXMLGUIClient::action( const char *name ) const 00094 { 00095 KAction* act = actionCollection()->action( name ); 00096 if ( !act ) { 00097 QPtrListIterator<KXMLGUIClient> childIt( d->m_children ); 00098 for (; childIt.current(); ++childIt ) { 00099 act = childIt.current()->actionCollection()->action( name ); 00100 if ( act ) 00101 break; 00102 } 00103 } 00104 return act; 00105 } 00106 00107 KActionCollection *KXMLGUIClient::actionCollection() const 00108 { 00109 if ( !d->m_actionCollection ) 00110 { 00111 d->m_actionCollection = new KActionCollection( 00112 "KXMLGUIClient-KActionCollection", this ); 00113 } 00114 return d->m_actionCollection; 00115 } 00116 00117 KAction *KXMLGUIClient::action( const QDomElement &element ) const 00118 { 00119 static const QString &attrName = KGlobal::staticQString( "name" ); 00120 return actionCollection()->action( element.attribute( attrName ).latin1() ); 00121 } 00122 00123 KInstance *KXMLGUIClient::instance() const 00124 { 00125 return d->m_instance; 00126 } 00127 00128 QDomDocument KXMLGUIClient::domDocument() const 00129 { 00130 return d->m_doc; 00131 } 00132 00133 QString KXMLGUIClient::xmlFile() const 00134 { 00135 return d->m_xmlFile; 00136 } 00137 00138 QString KXMLGUIClient::localXMLFile() const 00139 { 00140 if ( !d->m_localXMLFile.isEmpty() ) 00141 return d->m_localXMLFile; 00142 00143 if ( !QDir::isRelativePath(d->m_xmlFile) ) 00144 return QString::null; // can't save anything here 00145 00146 return locateLocal( "data", QString::fromLatin1( instance()->instanceName() + '/' ) + d->m_xmlFile ); 00147 } 00148 00149 00150 void KXMLGUIClient::reloadXML() 00151 { 00152 QString file( xmlFile() ); 00153 if ( !file.isEmpty() ) 00154 setXMLFile( file ); 00155 } 00156 00157 void KXMLGUIClient::setInstance( KInstance *instance ) 00158 { 00159 d->m_instance = instance; 00160 actionCollection()->setInstance( instance ); 00161 if ( d->m_builder ) 00162 d->m_builder->setBuilderClient( this ); 00163 } 00164 00165 void KXMLGUIClient::setXMLFile( const QString& _file, bool merge, bool setXMLDoc ) 00166 { 00167 // store our xml file name 00168 if ( !_file.isNull() ) { 00169 d->m_xmlFile = _file; 00170 actionCollection()->setXMLFile( _file ); 00171 } 00172 00173 if ( !setXMLDoc ) 00174 return; 00175 00176 QString file = _file; 00177 if ( QDir::isRelativePath(file) ) 00178 { 00179 QString doc; 00180 00181 QString filter = QString::fromLatin1( instance()->instanceName() + '/' ) + _file; 00182 00183 QStringList allFiles = instance()->dirs()->findAllResources( "data", filter ) + instance()->dirs()->findAllResources( "data", _file ); 00184 00185 file = findMostRecentXMLFile( allFiles, doc ); 00186 00187 if ( file.isEmpty() ) 00188 { 00189 // this might or might not be an error. for the time being, 00190 // let's treat this as if it isn't a problem and the user just 00191 // wants the global standards file 00192 00193 // however if a non-empty file gets passed and we can't find it we might 00194 // inform the developer using some debug output 00195 if ( !_file.isEmpty() ) 00196 kdWarning() << "KXMLGUIClient::setXMLFile: cannot find .rc file " << _file << endl; 00197 00198 setXML( QString::null, true ); 00199 return; 00200 } 00201 else if ( !doc.isEmpty() ) 00202 { 00203 setXML( doc, merge ); 00204 return; 00205 } 00206 } 00207 00208 QString xml = KXMLGUIFactory::readConfigFile( file ); 00209 setXML( xml, merge ); 00210 } 00211 00212 void KXMLGUIClient::setLocalXMLFile( const QString &file ) 00213 { 00214 d->m_localXMLFile = file; 00215 } 00216 00217 void KXMLGUIClient::setXML( const QString &document, bool merge ) 00218 { 00219 QDomDocument doc; 00220 doc.setContent( document ); 00221 setDOMDocument( doc, merge ); 00222 } 00223 00224 void KXMLGUIClient::setDOMDocument( const QDomDocument &document, bool merge ) 00225 { 00226 if ( merge ) 00227 { 00228 QDomElement base = d->m_doc.documentElement(); 00229 00230 QDomElement e = document.documentElement(); 00231 00232 // merge our original (global) xml with our new one 00233 mergeXML(base, e, actionCollection()); 00234 00235 // reassign our pointer as mergeXML might have done something 00236 // strange to it 00237 base = d->m_doc.documentElement(); 00238 00239 // we want some sort of failsafe.. just in case 00240 if ( base.isNull() ) 00241 d->m_doc = document; 00242 } 00243 else 00244 { 00245 d->m_doc = document; 00246 } 00247 00248 setXMLGUIBuildDocument( QDomDocument() ); 00249 } 00250 00251 bool KXMLGUIClient::mergeXML( QDomElement &base, const QDomElement &additive, KActionCollection *actionCollection ) 00252 { 00253 static const QString &tagAction = KGlobal::staticQString( "Action" ); 00254 static const QString &tagMerge = KGlobal::staticQString( "Merge" ); 00255 static const QString &tagSeparator = KGlobal::staticQString( "Separator" ); 00256 static const QString &attrName = KGlobal::staticQString( "name" ); 00257 static const QString &attrAppend = KGlobal::staticQString( "append" ); 00258 static const QString &attrWeakSeparator = KGlobal::staticQString( "weakSeparator" ); 00259 static const QString &tagMergeLocal = KGlobal::staticQString( "MergeLocal" ); 00260 static const QString &tagText = KGlobal::staticQString( "text" ); 00261 static const QString &attrAlreadyVisited = KGlobal::staticQString( "alreadyVisited" ); 00262 static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" ); 00263 static const QString &attrOne = KGlobal::staticQString( "1" ); 00264 00265 // there is a possibility that we don't want to merge in the 00266 // additive.. rather, we might want to *replace* the base with the 00267 // additive. this can be for any container.. either at a file wide 00268 // level or a simple container level. we look for the 'noMerge' 00269 // tag, in any event and just replace the old with the new 00270 if ( additive.attribute(attrNoMerge) == attrOne ) // ### use toInt() instead? (Simon) 00271 { 00272 base.parentNode().replaceChild(additive, base); 00273 return true; 00274 } 00275 00276 QString tag; 00277 00278 // iterate over all elements in the container (of the global DOM tree) 00279 QDomNode n = base.firstChild(); 00280 while ( !n.isNull() ) 00281 { 00282 QDomElement e = n.toElement(); 00283 n = n.nextSibling(); // Advance now so that we can safely delete e 00284 if (e.isNull()) 00285 continue; 00286 00287 tag = e.tagName(); 00288 00289 // if there's an action tag in the global tree and the action is 00290 // not implemented, then we remove the element 00291 if ( tag == tagAction ) 00292 { 00293 QCString name = e.attribute( attrName ).utf8(); // WABA 00294 if ( !actionCollection->action( name ) || 00295 (kapp && !kapp->authorizeKAction(name))) 00296 { 00297 // remove this child as we aren't using it 00298 base.removeChild( e ); 00299 continue; 00300 } 00301 } 00302 00303 // if there's a separator defined in the global tree, then add an 00304 // attribute, specifying that this is a "weak" separator 00305 else if ( tag == tagSeparator ) 00306 { 00307 e.setAttribute( attrWeakSeparator, (uint)1 ); 00308 00309 // okay, hack time. if the last item was a weak separator OR 00310 // this is the first item in a container, then we nuke the 00311 // current one 00312 QDomElement prev = e.previousSibling().toElement(); 00313 if ( prev.isNull() || 00314 ( prev.tagName() == tagSeparator && !prev.attribute( attrWeakSeparator ).isNull() ) || 00315 ( prev.tagName() == tagText ) ) 00316 { 00317 // the previous element was a weak separator or didn't exist 00318 base.removeChild( e ); 00319 continue; 00320 } 00321 } 00322 00323 // the MergeLocal tag lets us specify where non-standard elements 00324 // of the local tree shall be merged in. After inserting the 00325 // elements we delete this element 00326 else if ( tag == tagMergeLocal ) 00327 { 00328 QDomNode it = additive.firstChild(); 00329 while ( !it.isNull() ) 00330 { 00331 QDomElement newChild = it.toElement(); 00332 it = it.nextSibling(); 00333 if (newChild.isNull() ) 00334 continue; 00335 00336 if ( newChild.tagName() == tagText ) 00337 continue; 00338 00339 if ( newChild.attribute( attrAlreadyVisited ) == attrOne ) 00340 continue; 00341 00342 QString itAppend( newChild.attribute( attrAppend ) ); 00343 QString elemName( e.attribute( attrName ) ); 00344 00345 if ( ( itAppend.isNull() && elemName.isEmpty() ) || 00346 ( itAppend == elemName ) ) 00347 { 00348 // first, see if this new element matches a standard one in 00349 // the global file. if it does, then we skip it as it will 00350 // be merged in, later 00351 QDomElement matchingElement = findMatchingElement( newChild, base ); 00352 if ( matchingElement.isNull() || newChild.tagName() == tagSeparator ) 00353 base.insertBefore( newChild, e ); 00354 } 00355 } 00356 00357 base.removeChild( e ); 00358 continue; 00359 } 00360 00361 // in this last case we check for a separator tag and, if not, we 00362 // can be sure that its a container --> proceed with child nodes 00363 // recursively and delete the just proceeded container item in 00364 // case its empty (if the recursive call returns true) 00365 else if ( tag != tagMerge ) 00366 { 00367 // handle the text tag 00368 if ( tag == tagText ) 00369 continue; 00370 00371 QDomElement matchingElement = findMatchingElement( e, additive ); 00372 00373 if ( !matchingElement.isNull() ) 00374 { 00375 matchingElement.setAttribute( attrAlreadyVisited, (uint)1 ); 00376 00377 if ( mergeXML( e, matchingElement, actionCollection ) ) 00378 { 00379 base.removeChild( e ); 00380 continue; 00381 } 00382 00383 // Merge attributes 00384 const QDomNamedNodeMap attribs = matchingElement.attributes(); 00385 const uint attribcount = attribs.count(); 00386 00387 for(uint i = 0; i < attribcount; ++i) 00388 { 00389 const QDomNode node = attribs.item(i); 00390 e.setAttribute(node.nodeName(), node.nodeValue()); 00391 } 00392 00393 continue; 00394 } 00395 else 00396 { 00397 // this is an important case here! We reach this point if the 00398 // "local" tree does not contain a container definition for 00399 // this container. However we have to call mergeXML recursively 00400 // and make it check if there are actions implemented for this 00401 // container. *If* none, then we can remove this container now 00402 if ( mergeXML( e, QDomElement(), actionCollection ) ) 00403 base.removeChild( e ); 00404 continue; 00405 } 00406 } 00407 } 00408 00409 //here we append all child elements which were not inserted 00410 //previously via the LocalMerge tag 00411 n = additive.firstChild(); 00412 while ( !n.isNull() ) 00413 { 00414 QDomElement e = n.toElement(); 00415 n = n.nextSibling(); // Advance now so that we can safely delete e 00416 if (e.isNull()) 00417 continue; 00418 00419 QDomElement matchingElement = findMatchingElement( e, base ); 00420 00421 if ( matchingElement.isNull() ) 00422 { 00423 base.appendChild( e ); 00424 } 00425 } 00426 00427 // do one quick check to make sure that the last element was not 00428 // a weak separator 00429 QDomElement last = base.lastChild().toElement(); 00430 if ( (last.tagName() == tagSeparator) && (!last.attribute( attrWeakSeparator ).isNull()) ) 00431 { 00432 base.removeChild( last ); 00433 } 00434 00435 // now we check if we are empty (in which case we return "true", to 00436 // indicate the caller that it can delete "us" (the base element 00437 // argument of "this" call) 00438 bool deleteMe = true; 00439 00440 n = base.firstChild(); 00441 while ( !n.isNull() ) 00442 { 00443 QDomElement e = n.toElement(); 00444 n = n.nextSibling(); // Advance now so that we can safely delete e 00445 if (e.isNull()) 00446 continue; 00447 00448 tag = e.tagName(); 00449 00450 if ( tag == tagAction ) 00451 { 00452 // if base contains an implemented action, then we must not get 00453 // deleted (note that the actionCollection contains both, 00454 // "global" and "local" actions 00455 if ( actionCollection->action( e.attribute( attrName ).utf8() ) ) 00456 { 00457 deleteMe = false; 00458 break; 00459 } 00460 } 00461 else if ( tag == tagSeparator ) 00462 { 00463 // if we have a separator which has *not* the weak attribute 00464 // set, then it must be owned by the "local" tree in which case 00465 // we must not get deleted either 00466 QString weakAttr = e.attribute( attrWeakSeparator ); 00467 if ( weakAttr.isEmpty() || weakAttr.toInt() != 1 ) 00468 { 00469 deleteMe = false; 00470 break; 00471 } 00472 } 00473 00474 // in case of a merge tag we have unlimited lives, too ;-) 00475 else if ( tag == tagMerge ) 00476 { 00477 // deleteMe = false; 00478 // break; 00479 continue; 00480 } 00481 00482 // a text tag is NOT enough to spare this container 00483 else if ( tag == tagText ) 00484 { 00485 continue; 00486 } 00487 00488 // what's left are non-empty containers! *don't* delete us in this 00489 // case (at this position we can be *sure* that the container is 00490 // *not* empty, as the recursive call for it was in the first loop 00491 // which deleted the element in case the call returned "true" 00492 else 00493 { 00494 deleteMe = false; 00495 break; 00496 } 00497 } 00498 00499 return deleteMe; 00500 } 00501 00502 QDomElement KXMLGUIClient::findMatchingElement( const QDomElement &base, const QDomElement &additive ) 00503 { 00504 static const QString &tagAction = KGlobal::staticQString( "Action" ); 00505 static const QString &tagMergeLocal = KGlobal::staticQString( "MergeLocal" ); 00506 static const QString &attrName = KGlobal::staticQString( "name" ); 00507 00508 QDomNode n = additive.firstChild(); 00509 while ( !n.isNull() ) 00510 { 00511 QDomElement e = n.toElement(); 00512 n = n.nextSibling(); // Advance now so that we can safely delete e 00513 if (e.isNull()) 00514 continue; 00515 00516 // skip all action and merge tags as we will never use them 00517 if ( ( e.tagName() == tagAction ) || ( e.tagName() == tagMergeLocal ) ) 00518 { 00519 continue; 00520 } 00521 00522 // now see if our tags are equivalent 00523 if ( ( e.tagName() == base.tagName() ) && 00524 ( e.attribute( attrName ) == base.attribute( attrName ) ) ) 00525 { 00526 return e; 00527 } 00528 } 00529 00530 // nope, return a (now) null element 00531 return QDomElement(); 00532 } 00533 00534 void KXMLGUIClient::conserveMemory() 00535 { 00536 d->m_doc = QDomDocument(); 00537 d->m_buildDocument = QDomDocument(); 00538 } 00539 00540 void KXMLGUIClient::setXMLGUIBuildDocument( const QDomDocument &doc ) 00541 { 00542 d->m_buildDocument = doc; 00543 } 00544 00545 QDomDocument KXMLGUIClient::xmlguiBuildDocument() const 00546 { 00547 return d->m_buildDocument; 00548 } 00549 00550 void KXMLGUIClient::setFactory( KXMLGUIFactory *factory ) 00551 { 00552 d->m_factory = factory; 00553 } 00554 00555 KXMLGUIFactory *KXMLGUIClient::factory() const 00556 { 00557 return d->m_factory; 00558 } 00559 00560 KXMLGUIClient *KXMLGUIClient::parentClient() const 00561 { 00562 return d->m_parent; 00563 } 00564 00565 void KXMLGUIClient::insertChildClient( KXMLGUIClient *child ) 00566 { 00567 if ( child->d->m_parent ) 00568 child->d->m_parent->removeChildClient( child ); 00569 d->m_children.append( child ); 00570 child->d->m_parent = this; 00571 } 00572 00573 void KXMLGUIClient::removeChildClient( KXMLGUIClient *child ) 00574 { 00575 assert( d->m_children.containsRef( child ) ); 00576 d->m_children.removeRef( child ); 00577 child->d->m_parent = 0; 00578 } 00579 00580 /*bool KXMLGUIClient::addSuperClient( KXMLGUIClient *super ) 00581 { 00582 if ( d->m_supers.contains( super ) ) 00583 return false; 00584 d->m_supers.append( super ); 00585 return true; 00586 }*/ 00587 00588 const QPtrList<KXMLGUIClient> *KXMLGUIClient::childClients() 00589 { 00590 return &d->m_children; 00591 } 00592 00593 void KXMLGUIClient::setClientBuilder( KXMLGUIBuilder *builder ) 00594 { 00595 d->m_builder = builder; 00596 if ( builder ) 00597 builder->setBuilderInstance( instance() ); 00598 } 00599 00600 KXMLGUIBuilder *KXMLGUIClient::clientBuilder() const 00601 { 00602 return d->m_builder; 00603 } 00604 00605 void KXMLGUIClient::plugActionList( const QString &name, const QPtrList<KAction> &actionList ) 00606 { 00607 if ( !d->m_factory ) 00608 return; 00609 00610 d->m_factory->plugActionList( this, name, actionList ); 00611 } 00612 00613 void KXMLGUIClient::unplugActionList( const QString &name ) 00614 { 00615 if ( !d->m_factory ) 00616 return; 00617 00618 d->m_factory->unplugActionList( this, name ); 00619 } 00620 00621 QString KXMLGUIClient::findMostRecentXMLFile( const QStringList &files, QString &doc ) 00622 { 00623 00624 QValueList<DocStruct> allDocuments; 00625 00626 QStringList::ConstIterator it = files.begin(); 00627 QStringList::ConstIterator end = files.end(); 00628 for (; it != end; ++it ) 00629 { 00630 //kdDebug() << "KXMLGUIClient::findMostRecentXMLFile " << *it << endl; 00631 QString data = KXMLGUIFactory::readConfigFile( *it ); 00632 DocStruct d; 00633 d.file = *it; 00634 d.data = data; 00635 allDocuments.append( d ); 00636 } 00637 00638 QValueList<DocStruct>::Iterator best = allDocuments.end(); 00639 uint bestVersion = 0; 00640 00641 QValueList<DocStruct>::Iterator docIt = allDocuments.begin(); 00642 QValueList<DocStruct>::Iterator docEnd = allDocuments.end(); 00643 for (; docIt != docEnd; ++docIt ) 00644 { 00645 QString versionStr = findVersionNumber( (*docIt).data ); 00646 if ( versionStr.isEmpty() ) 00647 continue; 00648 00649 bool ok = false; 00650 uint version = versionStr.toUInt( &ok ); 00651 if ( !ok ) 00652 continue; 00653 //kdDebug() << "FOUND VERSION " << version << endl; 00654 00655 if ( version > bestVersion ) 00656 { 00657 best = docIt; 00658 //kdDebug() << "best version is now " << version << endl; 00659 bestVersion = version; 00660 } 00661 } 00662 00663 if ( best != docEnd ) 00664 { 00665 if ( best != allDocuments.begin() ) 00666 { 00667 QValueList<DocStruct>::Iterator local = allDocuments.begin(); 00668 00669 // load the local document and extract the action properties 00670 QDomDocument document; 00671 document.setContent( (*local).data ); 00672 00673 ActionPropertiesMap properties = extractActionProperties( document ); 00674 00675 // in case the document has a ActionProperties section 00676 // we must not delete it but copy over the global doc 00677 // to the local and insert the ActionProperties section 00678 if ( !properties.isEmpty() ) 00679 { 00680 // now load the global one with the higher version number 00681 // into memory 00682 document.setContent( (*best).data ); 00683 // and store the properties in there 00684 storeActionProperties( document, properties ); 00685 00686 (*local).data = document.toString(); 00687 // make sure we pick up the new local doc, when we return later 00688 best = local; 00689 00690 // write out the new version of the local document 00691 QFile f( (*local).file ); 00692 if ( f.open( IO_WriteOnly ) ) 00693 { 00694 QCString utf8data = (*local).data.utf8(); 00695 f.writeBlock( utf8data.data(), utf8data.length() ); 00696 f.close(); 00697 } 00698 } 00699 else 00700 { 00701 QString f = (*local).file; 00702 QString backup = f + QString::fromLatin1( ".backup" ); 00703 QDir dir; 00704 dir.rename( f, backup ); 00705 } 00706 } 00707 doc = (*best).data; 00708 return (*best).file; 00709 } 00710 else if ( files.count() > 0 ) 00711 { 00712 //kdDebug() << "returning first one..." << endl; 00713 doc = (*allDocuments.begin()).data; 00714 return (*allDocuments.begin()).file; 00715 } 00716 00717 return QString::null; 00718 } 00719 00720 00721 00722 QString KXMLGUIClient::findVersionNumber( const QString &xml ) 00723 { 00724 enum { ST_START, ST_AFTER_OPEN, ST_AFTER_GUI, 00725 ST_EXPECT_VERSION, ST_VERSION_NUM} state = ST_START; 00726 for (unsigned int pos = 0; pos < xml.length(); pos++) 00727 { 00728 switch (state) 00729 { 00730 case ST_START: 00731 if (xml[pos] == '<') 00732 state = ST_AFTER_OPEN; 00733 break; 00734 case ST_AFTER_OPEN: 00735 { 00736 //Jump to gui.. 00737 int guipos = xml.find("gui", pos, false /*case-insensitive*/); 00738 if (guipos == -1) 00739 return QString::null; //Reject 00740 00741 pos = guipos + 2; //Position at i, so we're moved ahead to the next character by the ++; 00742 state = ST_AFTER_GUI; 00743 break; 00744 } 00745 case ST_AFTER_GUI: 00746 state = ST_EXPECT_VERSION; 00747 break; 00748 case ST_EXPECT_VERSION: 00749 { 00750 int verpos = xml.find("version=\"", pos, false /*case-insensitive*/); 00751 if (verpos == -1) 00752 return QString::null; //Reject 00753 00754 pos = verpos + 8; //v = 0, e = +1, r = +2, s = +3 , i = +4, o = +5, n = +6, = = +7, " = + 8 00755 state = ST_VERSION_NUM; 00756 break; 00757 } 00758 case ST_VERSION_NUM: 00759 { 00760 unsigned int endpos; 00761 for (endpos = pos; endpos < xml.length(); endpos++) 00762 { 00763 if (xml[endpos].unicode() >= '0' && xml[endpos].unicode() <= '9') 00764 continue; //Number.. 00765 if (xml[endpos].unicode() == '"') //End of parameter 00766 break; 00767 else //This shouldn't be here.. 00768 { 00769 endpos = xml.length(); 00770 } 00771 } 00772 00773 if (endpos != pos && endpos < xml.length() ) 00774 { 00775 QString matchCandidate = xml.mid(pos, endpos - pos); //Don't include " ". 00776 return matchCandidate; 00777 } 00778 00779 state = ST_EXPECT_VERSION; //Try to match a well-formed version.. 00780 break; 00781 } //case.. 00782 } //switch 00783 } //for 00784 00785 return QString::null; 00786 } 00787 00788 KXMLGUIClient::ActionPropertiesMap KXMLGUIClient::extractActionProperties( const QDomDocument &doc ) 00789 { 00790 ActionPropertiesMap properties; 00791 00792 QDomElement actionPropElement = doc.documentElement().namedItem( "ActionProperties" ).toElement(); 00793 00794 if ( actionPropElement.isNull() ) 00795 return properties; 00796 00797 QDomNode n = actionPropElement.firstChild(); 00798 while(!n.isNull()) 00799 { 00800 QDomElement e = n.toElement(); 00801 n = n.nextSibling(); // Advance now so that we can safely delete e 00802 if ( e.isNull() ) 00803 continue; 00804 00805 if ( e.tagName().lower() != "action" ) 00806 continue; 00807 00808 QString actionName = e.attribute( "name" ); 00809 00810 if ( actionName.isEmpty() ) 00811 continue; 00812 00813 QMap<QString, QMap<QString, QString> >::Iterator propIt = properties.find( actionName ); 00814 if ( propIt == properties.end() ) 00815 propIt = properties.insert( actionName, QMap<QString, QString>() ); 00816 00817 const QDomNamedNodeMap attributes = e.attributes(); 00818 const uint attributeslength = attributes.length(); 00819 00820 for ( uint i = 0; i < attributeslength; ++i ) 00821 { 00822 const QDomAttr attr = attributes.item( i ).toAttr(); 00823 00824 if ( attr.isNull() ) 00825 continue; 00826 00827 const QString name = attr.name(); 00828 00829 if ( name == "name" || name.isEmpty() ) 00830 continue; 00831 00832 (*propIt)[ name ] = attr.value(); 00833 } 00834 00835 } 00836 00837 return properties; 00838 } 00839 00840 void KXMLGUIClient::storeActionProperties( QDomDocument &doc, const ActionPropertiesMap &properties ) 00841 { 00842 QDomElement actionPropElement = doc.documentElement().namedItem( "ActionProperties" ).toElement(); 00843 00844 if ( actionPropElement.isNull() ) 00845 { 00846 actionPropElement = doc.createElement( "ActionProperties" ); 00847 doc.documentElement().appendChild( actionPropElement ); 00848 } 00849 00850 while ( !actionPropElement.firstChild().isNull() ) 00851 actionPropElement.removeChild( actionPropElement.firstChild() ); 00852 00853 ActionPropertiesMap::ConstIterator it = properties.begin(); 00854 ActionPropertiesMap::ConstIterator end = properties.end(); 00855 for (; it != end; ++it ) 00856 { 00857 QDomElement action = doc.createElement( "Action" ); 00858 action.setAttribute( "name", it.key() ); 00859 actionPropElement.appendChild( action ); 00860 00861 QMap<QString, QString> attributes = (*it); 00862 QMap<QString, QString>::ConstIterator attrIt = attributes.begin(); 00863 QMap<QString, QString>::ConstIterator attrEnd = attributes.end(); 00864 for (; attrIt != attrEnd; ++attrIt ) 00865 action.setAttribute( attrIt.key(), attrIt.data() ); 00866 } 00867 } 00868 00869 void KXMLGUIClient::addStateActionEnabled(const QString& state, 00870 const QString& action) 00871 { 00872 StateChange stateChange = getActionsToChangeForState(state); 00873 00874 stateChange.actionsToEnable.append( action ); 00875 //kdDebug() << "KXMLGUIClient::addStateActionEnabled( " << state << ", " << action << ")" << endl; 00876 00877 m_actionsStateMap.replace( state, stateChange ); 00878 } 00879 00880 00881 void KXMLGUIClient::addStateActionDisabled(const QString& state, 00882 const QString& action) 00883 { 00884 StateChange stateChange = getActionsToChangeForState(state); 00885 00886 stateChange.actionsToDisable.append( action ); 00887 //kdDebug() << "KXMLGUIClient::addStateActionDisabled( " << state << ", " << action << ")" << endl; 00888 00889 m_actionsStateMap.replace( state, stateChange ); 00890 } 00891 00892 00893 KXMLGUIClient::StateChange KXMLGUIClient::getActionsToChangeForState(const QString& state) 00894 { 00895 return m_actionsStateMap[state]; 00896 } 00897 00898 00899 void KXMLGUIClient::stateChanged(const QString &newstate, KXMLGUIClient::ReverseStateChange reverse) 00900 { 00901 StateChange stateChange = getActionsToChangeForState(newstate); 00902 00903 bool setTrue = (reverse == StateNoReverse); 00904 bool setFalse = !setTrue; 00905 00906 // Enable actions which need to be enabled... 00907 // 00908 for ( QStringList::Iterator it = stateChange.actionsToEnable.begin(); 00909 it != stateChange.actionsToEnable.end(); ++it ) { 00910 00911 KAction *action = actionCollection()->action((*it).latin1()); 00912 if (action) action->setEnabled(setTrue); 00913 } 00914 00915 // and disable actions which need to be disabled... 00916 // 00917 for ( QStringList::Iterator it = stateChange.actionsToDisable.begin(); 00918 it != stateChange.actionsToDisable.end(); ++it ) { 00919 00920 KAction *action = actionCollection()->action((*it).latin1()); 00921 if (action) action->setEnabled(setFalse); 00922 } 00923 00924 } 00925 00926 void KXMLGUIClient::beginXMLPlug( QWidget *w ) 00927 { 00928 actionCollection()->beginXMLPlug( w ); 00929 QPtrListIterator<KXMLGUIClient> childIt( d->m_children ); 00930 for (; childIt.current(); ++childIt ) 00931 childIt.current()->actionCollection()->beginXMLPlug( w ); 00932 } 00933 00934 void KXMLGUIClient::endXMLPlug() 00935 { 00936 actionCollection()->endXMLPlug(); 00937 QPtrListIterator<KXMLGUIClient> childIt( d->m_children ); 00938 for (; childIt.current(); ++childIt ) 00939 childIt.current()->actionCollection()->endXMLPlug(); 00940 } 00941 00942 void KXMLGUIClient::prepareXMLUnplug( QWidget * ) 00943 { 00944 actionCollection()->prepareXMLUnplug(); 00945 QPtrListIterator<KXMLGUIClient> childIt( d->m_children ); 00946 for (; childIt.current(); ++childIt ) 00947 childIt.current()->actionCollection()->prepareXMLUnplug(); 00948 } 00949 00950 void KXMLGUIClient::virtual_hook( int, void* ) 00951 { /*BASE::virtual_hook( id, data );*/ }
KDE Logo
This file is part of the documentation for kdeui Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:10:18 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003