kdeui Library API Documentation

kxmlguifactory.cpp

00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1999,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 as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 00019 */ 00020 00021 #include "kxmlguifactory.h" 00022 #include "kxmlguifactory_p.h" 00023 #include "kxmlguiclient.h" 00024 #include "kxmlguibuilder.h" 00025 00026 #include <assert.h> 00027 00028 #include <qfile.h> 00029 #include <qtextstream.h> 00030 #include <qwidget.h> 00031 #include <qdatetime.h> 00032 #include <qvariant.h> 00033 00034 #include <kaction.h> 00035 #include <kdebug.h> 00036 #include <kinstance.h> 00037 #include <kglobal.h> 00038 #include <kshortcut.h> 00039 #include <kstandarddirs.h> 00040 00041 using namespace KXMLGUI; 00042 00043 /* 00044 * TODO: - make more use of QValueList instead of QPtrList 00045 */ 00046 00047 class KXMLGUIFactoryPrivate : public BuildState 00048 { 00049 public: 00050 KXMLGUIFactoryPrivate() 00051 { 00052 static const QString &defaultMergingName = KGlobal::staticQString( "<default>" ); 00053 static const QString &actionList = KGlobal::staticQString( "actionlist" ); 00054 static const QString &name = KGlobal::staticQString( "name" ); 00055 00056 m_rootNode = new ContainerNode( 0L, QString::null, 0L ); 00057 m_defaultMergingName = defaultMergingName; 00058 tagActionList = actionList; 00059 attrName = name; 00060 } 00061 ~KXMLGUIFactoryPrivate() 00062 { 00063 delete m_rootNode; 00064 } 00065 00066 void pushState() 00067 { 00068 m_stateStack.push( *this ); 00069 } 00070 00071 void popState() 00072 { 00073 BuildState::operator=( m_stateStack.pop() ); 00074 } 00075 00076 ContainerNode *m_rootNode; 00077 00078 QString m_defaultMergingName; 00079 00080 /* 00081 * Contains the container which is searched for in ::container . 00082 */ 00083 QString m_containerName; 00084 00085 /* 00086 * List of all clients 00087 */ 00088 QPtrList<KXMLGUIClient> m_clients; 00089 00090 QString tagActionList; 00091 00092 QString attrName; 00093 00094 BuildStateStack m_stateStack; 00095 }; 00096 00097 QString KXMLGUIFactory::readConfigFile( const QString &filename, const KInstance *instance ) 00098 { 00099 return readConfigFile( filename, false, instance ); 00100 } 00101 00102 QString KXMLGUIFactory::readConfigFile( const QString &filename, bool never_null, const KInstance *_instance ) 00103 { 00104 const KInstance *instance = _instance ? _instance : KGlobal::instance(); 00105 QString xml_file; 00106 00107 if (filename[0] == '/') 00108 xml_file = filename; 00109 else 00110 { 00111 xml_file = locate("data", QString::fromLatin1(instance->instanceName() + '/' ) + filename); 00112 if ( !QFile::exists( xml_file ) ) 00113 xml_file = locate( "data", filename ); 00114 } 00115 00116 QFile file( xml_file ); 00117 if ( !file.open( IO_ReadOnly ) ) 00118 { 00119 kdError(1000) << "No such XML file " << filename << endl; 00120 if ( never_null ) 00121 return QString::fromLatin1( "<!DOCTYPE kpartgui>\n<kpartgui name=\"empty\">\n</kpartgui>" ); 00122 else 00123 return QString::null; 00124 } 00125 00126 QByteArray buffer(file.readAll()); 00127 return QString::fromUtf8(buffer.data(), buffer.size()); 00128 } 00129 00130 bool KXMLGUIFactory::saveConfigFile( const QDomDocument& doc, 00131 const QString& filename, const KInstance *_instance ) 00132 { 00133 const KInstance *instance = _instance ? _instance : KGlobal::instance(); 00134 QString xml_file(filename); 00135 00136 if (xml_file[0] != '/') 00137 xml_file = locateLocal("data", QString::fromLatin1( instance->instanceName() + '/' ) 00138 + filename); 00139 00140 QFile file( xml_file ); 00141 if ( !file.open( IO_WriteOnly ) ) 00142 { 00143 kdError(1000) << "Could not write to " << filename << endl; 00144 return false; 00145 } 00146 00147 // write out our document 00148 QTextStream ts(&file); 00149 ts.setEncoding( QTextStream::UnicodeUTF8 ); 00150 ts << doc; 00151 00152 file.close(); 00153 return true; 00154 } 00155 00156 QString KXMLGUIFactory::documentToXML( const QDomDocument& doc ) 00157 { 00158 QString str; 00159 QTextStream ts(&str, IO_WriteOnly); 00160 ts.setEncoding( QTextStream::UnicodeUTF8 ); 00161 ts << doc; 00162 return str; 00163 } 00164 00165 QString KXMLGUIFactory::elementToXML( const QDomElement& elem ) 00166 { 00167 QString str; 00168 QTextStream ts(&str, IO_WriteOnly); 00169 ts.setEncoding( QTextStream::UnicodeUTF8 ); 00170 ts << elem; 00171 return str; 00172 } 00173 00174 void KXMLGUIFactory::removeDOMComments( QDomNode &node ) 00175 { 00176 QDomNode n = node.firstChild(); 00177 while ( !n.isNull() ) 00178 { 00179 if ( n.nodeType() == QDomNode::CommentNode ) 00180 { 00181 QDomNode tmp = n; 00182 n = n.nextSibling(); 00183 node.removeChild( tmp ); 00184 } 00185 else 00186 { 00187 QDomNode tmp = n; 00188 n = n.nextSibling(); 00189 removeDOMComments( tmp ); 00190 } 00191 } 00192 } 00193 00194 KXMLGUIFactory::KXMLGUIFactory( KXMLGUIBuilder *builder, QObject *parent, const char *name ) 00195 : QObject( parent, name ) 00196 { 00197 d = new KXMLGUIFactoryPrivate; 00198 d->builder = builder; 00199 d->guiClient = 0; 00200 if ( d->builder ) 00201 { 00202 d->builderContainerTags = d->builder->containerTags(); 00203 d->builderCustomTags = d->builder->customTags(); 00204 } 00205 } 00206 00207 KXMLGUIFactory::~KXMLGUIFactory() 00208 { 00209 delete d; 00210 } 00211 00212 void KXMLGUIFactory::addClient( KXMLGUIClient *client ) 00213 { 00214 kdDebug(129) << "KXMLGUIFactory::addClient( " << client << " )" << endl; // ellis 00215 static const QString &actionPropElementName = KGlobal::staticQString( "ActionProperties" ); 00216 00217 if ( client->factory() ) { 00218 if ( client->factory() == this ) 00219 return; 00220 else 00221 client->factory()->removeClient( client ); //just in case someone does stupid things ;-) 00222 } 00223 00224 d->pushState(); 00225 00226 // QTime dt; dt.start(); 00227 00228 d->guiClient = client; 00229 00230 // add this client to our client list 00231 if ( d->m_clients.containsRef( client ) == 0 ) 00232 d->m_clients.append( client ); 00233 else 00234 kdDebug(129) << "XMLGUI client already added " << client << endl; 00235 00236 // Tell the client that plugging in is process and 00237 // let it know what builder widget its mainwindow shortcuts 00238 // should be attached to. 00239 client->beginXMLPlug( d->builder->widget() ); 00240 00241 // try to use the build document for building the client's GUI, as the build document 00242 // contains the correct container state information (like toolbar positions, sizes, etc.) . 00243 // if there is non available, then use the "real" document. 00244 QDomDocument doc = client->xmlguiBuildDocument(); 00245 if ( doc.documentElement().isNull() ) 00246 doc = client->domDocument(); 00247 00248 QDomElement docElement = doc.documentElement(); 00249 00250 d->m_rootNode->index = -1; 00251 00252 // cache some variables 00253 00254 d->clientName = docElement.attribute( d->attrName ); 00255 d->clientBuilder = client->clientBuilder(); 00256 00257 if ( d->clientBuilder ) 00258 { 00259 d->clientBuilderContainerTags = d->clientBuilder->containerTags(); 00260 d->clientBuilderCustomTags = d->clientBuilder->customTags(); 00261 } 00262 else 00263 { 00264 d->clientBuilderContainerTags.clear(); 00265 d->clientBuilderCustomTags.clear(); 00266 } 00267 00268 // process a possibly existing actionproperties section 00269 00270 QDomElement actionPropElement = docElement.namedItem( actionPropElementName ).toElement(); 00271 if ( actionPropElement.isNull() ) 00272 actionPropElement = docElement.namedItem( actionPropElementName.lower() ).toElement(); 00273 00274 if ( !actionPropElement.isNull() ) 00275 applyActionProperties( actionPropElement ); 00276 00277 BuildHelper( *d, d->m_rootNode ).build( docElement ); 00278 00279 // let the client know that we built its GUI. 00280 client->setFactory( this ); 00281 00282 // call the finalizeGUI method, to fix up the positions of toolbars for example. 00283 // ### FIXME : obey client builder 00284 // --- Well, toolbars have a bool "positioned", so it doesn't really matter, 00285 // if we call positionYourself on all of them each time. (David) 00286 d->builder->finalizeGUI( d->guiClient ); 00287 00288 // reset some variables, for safety 00289 d->BuildState::reset(); 00290 00291 client->endXMLPlug(); 00292 00293 d->popState(); 00294 00295 emit clientAdded( client ); 00296 00297 // build child clients 00298 if ( client->childClients()->count() > 0 ) 00299 { 00300 const QPtrList<KXMLGUIClient> *children = client->childClients(); 00301 QPtrListIterator<KXMLGUIClient> childIt( *children ); 00302 for (; childIt.current(); ++childIt ) 00303 addClient( childIt.current() ); 00304 } 00305 00306 // kdDebug() << "addClient took " << dt.elapsed() << endl; 00307 } 00308 00309 void KXMLGUIFactory::removeClient( KXMLGUIClient *client ) 00310 { 00311 kdDebug(129) << "KXMLGUIFactory::removeClient( " << client << " )" << endl; // ellis 00312 00313 // don't try to remove the client's GUI if we didn't build it 00314 if ( !client || client->factory() != this ) 00315 return; 00316 00317 // remove this client from our client list 00318 d->m_clients.removeRef( client ); 00319 00320 // remove child clients first 00321 if ( client->childClients()->count() > 0 ) 00322 { 00323 const QPtrList<KXMLGUIClient> *children = client->childClients(); 00324 QPtrListIterator<KXMLGUIClient> childIt( *children ); 00325 childIt.toLast(); 00326 for (; childIt.current(); --childIt ) 00327 removeClient( childIt.current() ); 00328 } 00329 00330 kdDebug(1002) << "KXMLGUIFactory::removeServant, calling removeRecursive" << endl; 00331 00332 d->pushState(); 00333 00334 // cache some variables 00335 00336 d->guiClient = client; 00337 d->clientName = client->domDocument().documentElement().attribute( d->attrName ); 00338 d->clientBuilder = client->clientBuilder(); 00339 00340 client->setFactory( 0L ); 00341 00342 // if we don't have a build document for that client, yet, then create one by 00343 // cloning the original document, so that saving container information in the 00344 // DOM tree does not touch the original document. 00345 QDomDocument doc = client->xmlguiBuildDocument(); 00346 if ( doc.documentElement().isNull() ) 00347 { 00348 doc = client->domDocument().cloneNode( true ).toDocument(); 00349 client->setXMLGUIBuildDocument( doc ); 00350 } 00351 00352 d->m_rootNode->destruct( doc.documentElement(), *d ); 00353 00354 d->builder->finalizeGUI( d->guiClient ); //JoWenn 00355 00356 // reset some variables 00357 d->BuildState::reset(); 00358 00359 // This will destruct the KAccel object built around the given widget. 00360 client->prepareXMLUnplug( d->builder->widget() ); 00361 00362 d->popState(); 00363 00364 emit clientRemoved( client ); 00365 } 00366 00367 QPtrList<KXMLGUIClient> KXMLGUIFactory::clients() const 00368 { 00369 return d->m_clients; 00370 } 00371 00372 QWidget *KXMLGUIFactory::container( const QString &containerName, KXMLGUIClient *client, 00373 bool useTagName ) 00374 { 00375 d->pushState(); 00376 d->m_containerName = containerName; 00377 d->guiClient = client; 00378 00379 QWidget *result = findRecursive( d->m_rootNode, useTagName ); 00380 00381 d->guiClient = 0L; 00382 d->m_containerName = QString::null; 00383 00384 d->popState(); 00385 00386 return result; 00387 } 00388 00389 QPtrList<QWidget> KXMLGUIFactory::containers( const QString &tagName ) 00390 { 00391 return findRecursive( d->m_rootNode, tagName ); 00392 } 00393 00394 void KXMLGUIFactory::reset() 00395 { 00396 d->m_rootNode->reset(); 00397 00398 d->m_rootNode->clearChildren(); 00399 } 00400 00401 void KXMLGUIFactory::resetContainer( const QString &containerName, bool useTagName ) 00402 { 00403 if ( containerName.isEmpty() ) 00404 return; 00405 00406 ContainerNode *container = d->m_rootNode->findContainer( containerName, useTagName ); 00407 00408 if ( !container ) 00409 return; 00410 00411 ContainerNode *parent = container->parent; 00412 if ( !parent ) 00413 return; 00414 00415 // resetInternal( container ); 00416 00417 parent->removeChild( container ); 00418 } 00419 00420 QWidget *KXMLGUIFactory::findRecursive( KXMLGUI::ContainerNode *node, bool tag ) 00421 { 00422 if ( ( ( !tag && node->name == d->m_containerName ) || 00423 ( tag && node->tagName == d->m_containerName ) ) && 00424 ( !d->guiClient || node->client == d->guiClient ) ) 00425 return node->container; 00426 00427 QPtrListIterator<ContainerNode> it( node->children ); 00428 for (; it.current(); ++it ) 00429 { 00430 QWidget *cont = findRecursive( it.current(), tag ); 00431 if ( cont ) 00432 return cont; 00433 } 00434 00435 return 0L; 00436 } 00437 00438 QPtrList<QWidget> KXMLGUIFactory::findRecursive( KXMLGUI::ContainerNode *node, 00439 const QString &tagName ) 00440 { 00441 QPtrList<QWidget> res; 00442 00443 if ( node->tagName == tagName.lower() ) 00444 res.append( node->container ); 00445 00446 QPtrListIterator<KXMLGUI::ContainerNode> it( node->children ); 00447 for (; it.current(); ++it ) 00448 { 00449 QPtrList<QWidget> lst = findRecursive( it.current(), tagName ); 00450 QPtrListIterator<QWidget> wit( lst ); 00451 for (; wit.current(); ++wit ) 00452 res.append( wit.current() ); 00453 } 00454 00455 return res; 00456 } 00457 00458 void KXMLGUIFactory::plugActionList( KXMLGUIClient *client, const QString &name, 00459 const QPtrList<KAction> &actionList ) 00460 { 00461 d->pushState(); 00462 d->guiClient = client; 00463 d->actionListName = name; 00464 d->actionList = actionList; 00465 d->clientName = client->domDocument().documentElement().attribute( d->attrName ); 00466 00467 d->m_rootNode->plugActionList( *d ); 00468 00469 d->BuildState::reset(); 00470 d->popState(); 00471 } 00472 00473 void KXMLGUIFactory::unplugActionList( KXMLGUIClient *client, const QString &name ) 00474 { 00475 d->pushState(); 00476 d->guiClient = client; 00477 d->actionListName = name; 00478 d->clientName = client->domDocument().documentElement().attribute( d->attrName ); 00479 00480 d->m_rootNode->unplugActionList( *d ); 00481 00482 d->BuildState::reset(); 00483 d->popState(); 00484 } 00485 00486 void KXMLGUIFactory::applyActionProperties( const QDomElement &actionPropElement ) 00487 { 00488 static const QString &tagAction = KGlobal::staticQString( "action" ); 00489 00490 QDomElement e = actionPropElement.firstChild().toElement(); 00491 for (; !e.isNull(); e = e.nextSibling().toElement() ) 00492 { 00493 if ( e.tagName().lower() != tagAction ) 00494 continue; 00495 00496 KAction *action = d->guiClient->action( e ); 00497 if ( !action ) 00498 continue; 00499 00500 configureAction( action, e.attributes() ); 00501 } 00502 } 00503 00504 void KXMLGUIFactory::configureAction( KAction *action, const QDomNamedNodeMap &attributes ) 00505 { 00506 for ( uint i = 0; i < attributes.length(); i++ ) 00507 { 00508 QDomAttr attr = attributes.item( i ).toAttr(); 00509 if ( attr.isNull() ) 00510 continue; 00511 00512 configureAction( action, attr ); 00513 } 00514 } 00515 00516 void KXMLGUIFactory::configureAction( KAction *action, const QDomAttr &attribute ) 00517 { 00518 static const QString &attrShortcut = KGlobal::staticQString( "shortcut" ); 00519 00520 QString attrName = attribute.name(); 00521 00522 QVariant propertyValue; 00523 00524 QVariant::Type propertyType = action->property( attribute.name().latin1() ).type(); 00525 00526 // If the attribute is a deprecated "accel", change to "shortcut". 00527 if ( attrName.lower() == "accel" ) 00528 attrName = attrShortcut; 00529 00530 if ( propertyType == QVariant::Int ) 00531 propertyValue = QVariant( attribute.value().toInt() ); 00532 else if ( propertyType == QVariant::UInt ) 00533 propertyValue = QVariant( attribute.value().toUInt() ); 00534 else 00535 propertyValue = QVariant( attribute.value() ); 00536 00537 action->setProperty( attrName.latin1() /* ???????? */, propertyValue ); 00538 } 00539 00540 void KXMLGUIFactory::virtual_hook( int, void* ) 00541 { /*BASE::virtual_hook( id, data );*/ } 00542 00543 #include "kxmlguifactory.moc" 00544 00545 /* vim: et sw=4 00546 */
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 Mon Aug 30 22:54:01 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003