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 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
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
00343
00344
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 );
00355
00356
00357 d->BuildState::reset();
00358
00359
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
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
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 { }
00542
00543
#include "kxmlguifactory.moc"
00544
00545
00546