kxmlguifactory.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
00082
00083 QString m_containerName;
00084
00085
00086
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
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;
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 );
00222 }
00223
00224 d->pushState();
00225
00226
00227
00228 d->guiClient = client;
00229
00230
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
00237
00238
00239 client->beginXMLPlug( d->builder->widget() );
00240
00241
00242
00243
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
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
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
00280 client->setFactory( this );
00281
00282
00283
00284
00285
00286 d->builder->finalizeGUI( d->guiClient );
00287
00288
00289 d->BuildState::reset();
00290
00291 client->endXMLPlug();
00292
00293 d->popState();
00294
00295 emit clientAdded( client );
00296
00297
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
00307 }
00308
00309 void KXMLGUIFactory::removeClient( KXMLGUIClient *client )
00310 {
00311 kdDebug(129) << "KXMLGUIFactory::removeClient( " << client << " )" << endl;
00312
00313
00314 if ( !client || client->factory() != this )
00315 return;
00316
00317
00318 d->m_clients.removeRef( client );
00319
00320
00321 if ( client->childClients()->count() > 0 )
00322 {
00323 const QPtrList<KXMLGUIClient> *children = client->childClients();
00324 QPtrListIterator<KXMLGUIClient> childIt( *children );
00325 for (; childIt.current(); ++childIt )
00326 removeClient( childIt.current() );
00327 }
00328
00329 kdDebug(1002) << "KXMLGUIFactory::removeServant, calling removeRecursive" << endl;
00330
00331 d->pushState();
00332
00333
00334
00335 d->guiClient = client;
00336 d->clientName = client->domDocument().documentElement().attribute( d->attrName );
00337 d->clientBuilder = client->clientBuilder();
00338
00339 client->setFactory( 0L );
00340
00341
00342
00343
00344 QDomDocument doc = client->xmlguiBuildDocument();
00345 if ( doc.documentElement().isNull() )
00346 {
00347 doc = client->domDocument().cloneNode( true ).toDocument();
00348 client->setXMLGUIBuildDocument( doc );
00349 }
00350
00351 d->m_rootNode->destruct( doc.documentElement(), *d );
00352
00353 d->builder->finalizeGUI( d->guiClient );
00354
00355
00356 d->BuildState::reset();
00357
00358
00359 client->prepareXMLUnplug( d->builder->widget() );
00360
00361 d->popState();
00362
00363 emit clientRemoved( client );
00364 }
00365
00366 QPtrList<KXMLGUIClient> KXMLGUIFactory::clients() const
00367 {
00368 return d->m_clients;
00369 }
00370
00371 QWidget *KXMLGUIFactory::container( const QString &containerName, KXMLGUIClient *client,
00372 bool useTagName )
00373 {
00374 d->pushState();
00375 d->m_containerName = containerName;
00376 d->guiClient = client;
00377
00378 QWidget *result = findRecursive( d->m_rootNode, useTagName );
00379
00380 d->guiClient = 0L;
00381 d->m_containerName = QString::null;
00382
00383 d->popState();
00384
00385 return result;
00386 }
00387
00388 QPtrList<QWidget> KXMLGUIFactory::containers( const QString &tagName )
00389 {
00390 return findRecursive( d->m_rootNode, tagName );
00391 }
00392
00393 void KXMLGUIFactory::reset()
00394 {
00395 d->m_rootNode->reset();
00396
00397 d->m_rootNode->clearChildren();
00398 }
00399
00400 void KXMLGUIFactory::resetContainer( const QString &containerName, bool useTagName )
00401 {
00402 if ( containerName.isEmpty() )
00403 return;
00404
00405 ContainerNode *container = d->m_rootNode->findContainer( containerName, useTagName );
00406
00407 if ( !container )
00408 return;
00409
00410 ContainerNode *parent = container->parent;
00411 if ( !parent )
00412 return;
00413
00414
00415
00416 parent->removeChild( container );
00417 }
00418
00419 QWidget *KXMLGUIFactory::findRecursive( KXMLGUI::ContainerNode *node, bool tag )
00420 {
00421 if ( ( ( !tag && node->name == d->m_containerName ) ||
00422 ( tag && node->tagName == d->m_containerName ) ) &&
00423 ( !d->guiClient || node->client == d->guiClient ) )
00424 return node->container;
00425
00426 QPtrListIterator<ContainerNode> it( node->children );
00427 for (; it.current(); ++it )
00428 {
00429 QWidget *cont = findRecursive( it.current(), tag );
00430 if ( cont )
00431 return cont;
00432 }
00433
00434 return 0L;
00435 }
00436
00437 QPtrList<QWidget> KXMLGUIFactory::findRecursive( KXMLGUI::ContainerNode *node,
00438 const QString &tagName )
00439 {
00440 QPtrList<QWidget> res;
00441
00442 if ( node->tagName == tagName.lower() )
00443 res.append( node->container );
00444
00445 QPtrListIterator<KXMLGUI::ContainerNode> it( node->children );
00446 for (; it.current(); ++it )
00447 {
00448 QPtrList<QWidget> lst = findRecursive( it.current(), tagName );
00449 QPtrListIterator<QWidget> wit( lst );
00450 for (; wit.current(); ++wit )
00451 res.append( wit.current() );
00452 }
00453
00454 return res;
00455 }
00456
00457 void KXMLGUIFactory::plugActionList( KXMLGUIClient *client, const QString &name,
00458 const QPtrList<KAction> &actionList )
00459 {
00460 d->pushState();
00461 d->guiClient = client;
00462 d->actionListName = name;
00463 d->actionList = actionList;
00464 d->clientName = client->domDocument().documentElement().attribute( d->attrName );
00465
00466 d->m_rootNode->plugActionList( *d );
00467
00468 d->BuildState::reset();
00469 d->popState();
00470 }
00471
00472 void KXMLGUIFactory::unplugActionList( KXMLGUIClient *client, const QString &name )
00473 {
00474 d->pushState();
00475 d->guiClient = client;
00476 d->actionListName = name;
00477 d->clientName = client->domDocument().documentElement().attribute( d->attrName );
00478
00479 d->m_rootNode->unplugActionList( *d );
00480
00481 d->BuildState::reset();
00482 d->popState();
00483 }
00484
00485 void KXMLGUIFactory::applyActionProperties( const QDomElement &actionPropElement )
00486 {
00487 static const QString &tagAction = KGlobal::staticQString( "action" );
00488
00489 QDomElement e = actionPropElement.firstChild().toElement();
00490 for (; !e.isNull(); e = e.nextSibling().toElement() )
00491 {
00492 if ( e.tagName().lower() != tagAction )
00493 continue;
00494
00495 KAction *action = d->guiClient->action( e );
00496 if ( !action )
00497 continue;
00498
00499 configureAction( action, e.attributes() );
00500 }
00501 }
00502
00503 void KXMLGUIFactory::configureAction( KAction *action, const QDomNamedNodeMap &attributes )
00504 {
00505 for ( uint i = 0; i < attributes.length(); i++ )
00506 {
00507 QDomAttr attr = attributes.item( i ).toAttr();
00508 if ( attr.isNull() )
00509 continue;
00510
00511 configureAction( action, attr );
00512 }
00513 }
00514
00515 void KXMLGUIFactory::configureAction( KAction *action, const QDomAttr &attribute )
00516 {
00517 static const QString &attrShortcut = KGlobal::staticQString( "shortcut" );
00518
00519 QString attrName = attribute.name();
00520
00521 QVariant propertyValue;
00522
00523 QVariant::Type propertyType = action->property( attribute.name().latin1() ).type();
00524
00525
00526 if ( attrName.lower() == "accel" )
00527 attrName = attrShortcut;
00528
00529 if ( propertyType == QVariant::Int )
00530 propertyValue = QVariant( attribute.value().toInt() );
00531 else if ( propertyType == QVariant::UInt )
00532 propertyValue = QVariant( attribute.value().toUInt() );
00533 else
00534 propertyValue = QVariant( attribute.value() );
00535
00536 action->setProperty( attrName.latin1() , propertyValue );
00537 }
00538
00539 void KXMLGUIFactory::virtual_hook( int, void* )
00540 { }
00541
00542 #include "kxmlguifactory.moc"
00543
00544
00545
This file is part of the documentation for kdeui Library Version 3.2.0.