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