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
#include <kkeydialog.h>
00041
00042
using namespace KXMLGUI;
00043
00044
00045
00046
00047
00048
class KXMLGUIFactoryPrivate :
public BuildState
00049 {
00050
public:
00051 KXMLGUIFactoryPrivate()
00052 {
00053
static const QString &defaultMergingName =
KGlobal::staticQString(
"<default>" );
00054
static const QString &actionList =
KGlobal::staticQString(
"actionlist" );
00055
static const QString &
name =
KGlobal::staticQString(
"name" );
00056
00057 m_rootNode =
new ContainerNode( 0L, QString::null, 0L );
00058 m_defaultMergingName = defaultMergingName;
00059 tagActionList = actionList;
00060 attrName =
name;
00061 }
00062 ~KXMLGUIFactoryPrivate()
00063 {
00064
delete m_rootNode;
00065 }
00066
00067
void pushState()
00068 {
00069 m_stateStack.push( *
this );
00070 }
00071
00072
void popState()
00073 {
00074 BuildState::operator=( m_stateStack.pop() );
00075 }
00076
00077 ContainerNode *m_rootNode;
00078
00079
QString m_defaultMergingName;
00080
00081
00082
00083
00084
QString m_containerName;
00085
00086
00087
00088
00089
QPtrList<KXMLGUIClient> m_clients;
00090
00091
QString tagActionList;
00092
00093
QString attrName;
00094
00095
BuildStateStack m_stateStack;
00096 };
00097
00098
QString KXMLGUIFactory::readConfigFile(
const QString &filename,
const KInstance *instance )
00099 {
00100
return readConfigFile( filename,
false, instance );
00101 }
00102
00103
QString KXMLGUIFactory::readConfigFile(
const QString &filename,
bool never_null,
const KInstance *_instance )
00104 {
00105
const KInstance *
instance = _instance ? _instance :
KGlobal::instance();
00106
QString xml_file;
00107
00108
if (filename[0] ==
'/')
00109 xml_file = filename;
00110
else
00111 {
00112 xml_file =
locate(
"data", QString::fromLatin1(
instance->
instanceName() +
'/' ) + filename);
00113
if ( !QFile::exists( xml_file ) )
00114 xml_file =
locate(
"data", filename );
00115 }
00116
00117
QFile file( xml_file );
00118
if ( !file.open( IO_ReadOnly ) )
00119 {
00120
kdError(240) <<
"No such XML file " << filename <<
endl;
00121
if ( never_null )
00122
return QString::fromLatin1(
"<!DOCTYPE kpartgui>\n<kpartgui name=\"empty\">\n</kpartgui>" );
00123
else
00124
return QString::null;
00125 }
00126
00127
#if QT_VERSION <= 0x030302
00128
00129
QByteArray buffer(file.size() + 1);
00130 buffer = file.readAll();
00131
if(!buffer.isEmpty())
00132 buffer[ buffer.size() - 1 ] =
'\0';
00133
else
00134
return QString::null;
00135
#else
00136
QByteArray buffer(file.readAll());
00137
#endif
00138
return QString::fromUtf8(buffer.data(), buffer.size());
00139 }
00140
00141
bool KXMLGUIFactory::saveConfigFile(
const QDomDocument& doc,
00142
const QString& filename,
const KInstance *_instance )
00143 {
00144
const KInstance *
instance = _instance ? _instance :
KGlobal::instance();
00145
QString xml_file(filename);
00146
00147
if (xml_file[0] !=
'/')
00148 xml_file =
locateLocal(
"data", QString::fromLatin1(
instance->
instanceName() +
'/' )
00149 + filename);
00150
00151
QFile file( xml_file );
00152
if ( !file.open( IO_WriteOnly ) )
00153 {
00154
kdError(240) <<
"Could not write to " << filename <<
endl;
00155
return false;
00156 }
00157
00158
00159
QTextStream ts(&file);
00160 ts.setEncoding( QTextStream::UnicodeUTF8 );
00161 ts << doc;
00162
00163 file.close();
00164
return true;
00165 }
00166
00167
QString KXMLGUIFactory::documentToXML(
const QDomDocument& doc )
00168 {
00169
QString str;
00170
QTextStream ts(&str, IO_WriteOnly);
00171 ts.setEncoding( QTextStream::UnicodeUTF8 );
00172 ts << doc;
00173
return str;
00174 }
00175
00176
QString KXMLGUIFactory::elementToXML(
const QDomElement& elem )
00177 {
00178
QString str;
00179
QTextStream ts(&str, IO_WriteOnly);
00180 ts.setEncoding( QTextStream::UnicodeUTF8 );
00181 ts << elem;
00182
return str;
00183 }
00184
00185 void KXMLGUIFactory::removeDOMComments(
QDomNode &node )
00186 {
00187
QDomNode n = node.firstChild();
00188
while ( !n.isNull() )
00189 {
00190
if ( n.nodeType() == QDomNode::CommentNode )
00191 {
00192
QDomNode tmp = n;
00193 n = n.nextSibling();
00194 node.removeChild( tmp );
00195 }
00196
else
00197 {
00198
QDomNode tmp = n;
00199 n = n.nextSibling();
00200
removeDOMComments( tmp );
00201 }
00202 }
00203 }
00204
00205 KXMLGUIFactory::KXMLGUIFactory(
KXMLGUIBuilder *builder,
QObject *parent,
const char *name )
00206 :
QObject( parent, name )
00207 {
00208 d =
new KXMLGUIFactoryPrivate;
00209 d->builder = builder;
00210 d->guiClient = 0;
00211
if ( d->builder )
00212 {
00213 d->builderContainerTags = d->builder->containerTags();
00214 d->builderCustomTags = d->builder->customTags();
00215 }
00216 }
00217
00218 KXMLGUIFactory::~KXMLGUIFactory()
00219 {
00220
delete d;
00221 }
00222
00223 void KXMLGUIFactory::addClient(
KXMLGUIClient *client )
00224 {
00225
kdDebug(129) <<
"KXMLGUIFactory::addClient( " << client <<
" )" <<
endl;
00226
static const QString &actionPropElementName =
KGlobal::staticQString(
"ActionProperties" );
00227
00228
if ( client->
factory() ) {
00229
if ( client->
factory() ==
this )
00230
return;
00231
else
00232 client->
factory()->
removeClient( client );
00233 }
00234
00235 d->pushState();
00236
00237
00238
00239 d->guiClient = client;
00240
00241
00242
if ( d->m_clients.containsRef( client ) == 0 )
00243 d->m_clients.append( client );
00244
else
00245
kdDebug(129) <<
"XMLGUI client already added " << client <<
endl;
00246
00247
00248
00249
00250 client->
beginXMLPlug( d->builder->widget() );
00251
00252
00253
00254
00255
QDomDocument doc = client->
xmlguiBuildDocument();
00256
if ( doc.documentElement().isNull() )
00257 doc = client->
domDocument();
00258
00259
QDomElement docElement = doc.documentElement();
00260
00261 d->m_rootNode->index = -1;
00262
00263
00264
00265 d->clientName = docElement.attribute( d->attrName );
00266 d->clientBuilder = client->
clientBuilder();
00267
00268
if ( d->clientBuilder )
00269 {
00270 d->clientBuilderContainerTags = d->clientBuilder->containerTags();
00271 d->clientBuilderCustomTags = d->clientBuilder->customTags();
00272 }
00273
else
00274 {
00275 d->clientBuilderContainerTags.clear();
00276 d->clientBuilderCustomTags.clear();
00277 }
00278
00279
00280
00281
QDomElement actionPropElement = docElement.namedItem( actionPropElementName ).toElement();
00282
if ( actionPropElement.isNull() )
00283 actionPropElement = docElement.namedItem( actionPropElementName.lower() ).toElement();
00284
00285
if ( !actionPropElement.isNull() )
00286 applyActionProperties( actionPropElement );
00287
00288 BuildHelper( *d, d->m_rootNode ).build( docElement );
00289
00290
00291 client->
setFactory(
this );
00292
00293
00294
00295
00296
00297 d->builder->finalizeGUI( d->guiClient );
00298
00299
00300 d->BuildState::reset();
00301
00302 client->
endXMLPlug();
00303
00304 d->popState();
00305
00306 emit clientAdded( client );
00307
00308
00309
if ( client->
childClients()->count() > 0 )
00310 {
00311
const QPtrList<KXMLGUIClient> *children = client->
childClients();
00312
QPtrListIterator<KXMLGUIClient> childIt( *children );
00313
for (; childIt.current(); ++childIt )
00314
addClient( childIt.current() );
00315 }
00316
00317
00318 }
00319
00320 void KXMLGUIFactory::removeClient(
KXMLGUIClient *client )
00321 {
00322
kdDebug(129) <<
"KXMLGUIFactory::removeClient( " << client <<
" )" <<
endl;
00323
00324
00325
if ( !client || client->
factory() !=
this )
00326
return;
00327
00328
00329 d->m_clients.removeRef( client );
00330
00331
00332
if ( client->
childClients()->count() > 0 )
00333 {
00334
const QPtrList<KXMLGUIClient> *children = client->
childClients();
00335
QPtrListIterator<KXMLGUIClient> childIt( *children );
00336 childIt.toLast();
00337
for (; childIt.current(); --childIt )
00338
removeClient( childIt.current() );
00339 }
00340
00341
kdDebug(1002) <<
"KXMLGUIFactory::removeServant, calling removeRecursive" <<
endl;
00342
00343 d->pushState();
00344
00345
00346
00347 d->guiClient = client;
00348 d->clientName = client->
domDocument().documentElement().attribute( d->attrName );
00349 d->clientBuilder = client->
clientBuilder();
00350
00351 client->
setFactory( 0L );
00352
00353
00354
00355
00356
QDomDocument doc = client->
xmlguiBuildDocument();
00357
if ( doc.documentElement().isNull() )
00358 {
00359 doc = client->
domDocument().cloneNode(
true ).toDocument();
00360 client->
setXMLGUIBuildDocument( doc );
00361 }
00362
00363 d->m_rootNode->destruct( doc.documentElement(), *d );
00364
00365 d->builder->finalizeGUI( d->guiClient );
00366
00367
00368 d->BuildState::reset();
00369
00370
00371 client->
prepareXMLUnplug( d->builder->widget() );
00372
00373 d->popState();
00374
00375 emit clientRemoved( client );
00376 }
00377
00378 QPtrList<KXMLGUIClient> KXMLGUIFactory::clients()
const
00379
{
00380
return d->m_clients;
00381 }
00382
00383 QWidget *
KXMLGUIFactory::container(
const QString &containerName,
KXMLGUIClient *client,
00384
bool useTagName )
00385 {
00386 d->pushState();
00387 d->m_containerName = containerName;
00388 d->guiClient = client;
00389
00390
QWidget *result = findRecursive( d->m_rootNode, useTagName );
00391
00392 d->guiClient = 0L;
00393 d->m_containerName = QString::null;
00394
00395 d->popState();
00396
00397
return result;
00398 }
00399
00400
QPtrList<QWidget> KXMLGUIFactory::containers(
const QString &tagName )
00401 {
00402
return findRecursive( d->m_rootNode, tagName );
00403 }
00404
00405 void KXMLGUIFactory::reset()
00406 {
00407 d->m_rootNode->reset();
00408
00409 d->m_rootNode->clearChildren();
00410 }
00411
00412 void KXMLGUIFactory::resetContainer(
const QString &containerName,
bool useTagName )
00413 {
00414
if ( containerName.isEmpty() )
00415
return;
00416
00417 ContainerNode *
container = d->m_rootNode->findContainer( containerName, useTagName );
00418
00419
if ( !container )
00420
return;
00421
00422 ContainerNode *parent = container->parent;
00423
if ( !parent )
00424
return;
00425
00426
00427
00428 parent->removeChild( container );
00429 }
00430
00431
QWidget *KXMLGUIFactory::findRecursive( KXMLGUI::ContainerNode *node,
bool tag )
00432 {
00433
if ( ( ( !tag && node->name == d->m_containerName ) ||
00434 ( tag && node->tagName == d->m_containerName ) ) &&
00435 ( !d->guiClient || node->client == d->guiClient ) )
00436
return node->container;
00437
00438
QPtrListIterator<ContainerNode> it( node->children );
00439
for (; it.current(); ++it )
00440 {
00441
QWidget *cont = findRecursive( it.current(), tag );
00442
if ( cont )
00443
return cont;
00444 }
00445
00446
return 0L;
00447 }
00448
00449
QPtrList<QWidget> KXMLGUIFactory::findRecursive( KXMLGUI::ContainerNode *node,
00450
const QString &tagName )
00451 {
00452
QPtrList<QWidget> res;
00453
00454
if ( node->tagName == tagName.lower() )
00455 res.append( node->container );
00456
00457
QPtrListIterator<KXMLGUI::ContainerNode> it( node->children );
00458
for (; it.current(); ++it )
00459 {
00460
QPtrList<QWidget> lst = findRecursive( it.current(), tagName );
00461
QPtrListIterator<QWidget> wit( lst );
00462
for (; wit.current(); ++wit )
00463 res.append( wit.current() );
00464 }
00465
00466
return res;
00467 }
00468
00469
void KXMLGUIFactory::plugActionList(
KXMLGUIClient *client,
const QString &name,
00470
const QPtrList<KAction> &actionList )
00471 {
00472 d->pushState();
00473 d->guiClient = client;
00474 d->actionListName =
name;
00475 d->actionList = actionList;
00476 d->clientName = client->
domDocument().documentElement().attribute( d->attrName );
00477
00478 d->m_rootNode->plugActionList( *d );
00479
00480 d->BuildState::reset();
00481 d->popState();
00482 }
00483
00484
void KXMLGUIFactory::unplugActionList(
KXMLGUIClient *client,
const QString &name )
00485 {
00486 d->pushState();
00487 d->guiClient = client;
00488 d->actionListName =
name;
00489 d->clientName = client->
domDocument().documentElement().attribute( d->attrName );
00490
00491 d->m_rootNode->unplugActionList( *d );
00492
00493 d->BuildState::reset();
00494 d->popState();
00495 }
00496
00497
void KXMLGUIFactory::applyActionProperties(
const QDomElement &actionPropElement )
00498 {
00499
static const QString &tagAction =
KGlobal::staticQString(
"action" );
00500
00501
for (
QDomNode n = actionPropElement.firstChild();
00502 !n.isNull(); n = n.nextSibling() )
00503 {
00504
QDomElement e = n.toElement();
00505
if ( e.tagName().lower() != tagAction )
00506
continue;
00507
00508
KAction *
action = d->guiClient->action( e );
00509
if ( !
action )
00510
continue;
00511
00512 configureAction( action, e.attributes() );
00513 }
00514 }
00515
00516
void KXMLGUIFactory::configureAction(
KAction *action,
const QDomNamedNodeMap &attributes )
00517 {
00518
for ( uint i = 0; i < attributes.length(); i++ )
00519 {
00520
QDomAttr attr = attributes.item( i ).toAttr();
00521
if ( attr.isNull() )
00522
continue;
00523
00524 configureAction( action, attr );
00525 }
00526 }
00527
00528
void KXMLGUIFactory::configureAction(
KAction *action,
const QDomAttr &attribute )
00529 {
00530
static const QString &attrShortcut =
KGlobal::staticQString(
"shortcut" );
00531
00532
QString attrName = attribute.name();
00533
00534
if ( attrName.lower() ==
"accel" )
00535 attrName = attrShortcut;
00536
00537
QVariant propertyValue;
00538
00539 QVariant::Type propertyType =
action->property( attrName.latin1() ).type();
00540
00541
if ( propertyType == QVariant::Int )
00542 propertyValue =
QVariant( attribute.value().toInt() );
00543
else if ( propertyType == QVariant::UInt )
00544 propertyValue =
QVariant( attribute.value().toUInt() );
00545
else
00546 propertyValue =
QVariant( attribute.value() );
00547
00548
action->setProperty( attrName.latin1(), propertyValue );
00549 }
00550
00551
00552 int KXMLGUIFactory::configureShortcuts(
bool bAllowLetterShortcuts ,
bool bSaveSettings )
00553 {
00554
KKeyDialog dlg( bAllowLetterShortcuts, dynamic_cast<QWidget*>(parent()) );
00555
QPtrListIterator<KXMLGUIClient> it( d->m_clients );
00556
KXMLGUIClient *client;
00557
while( (client=it.current()) !=0 )
00558 {
00559 ++it;
00560
if(!client->
xmlFile().isEmpty())
00561 dlg.
insert( client->
actionCollection() );
00562 }
00563
return dlg.
configure(bSaveSettings);
00564 }
00565
00566
QDomElement KXMLGUIFactory::actionPropertiesElement(
QDomDocument& doc )
00567 {
00568
const QString tagActionProp = QString::fromLatin1(
"ActionProperties");
00569
00570
QDomElement elem;
00571
QDomNode it = doc.documentElement().firstChild();
00572
for( ; !it.isNull(); it = it.nextSibling() ) {
00573
QDomElement e = it.toElement();
00574
if( e.tagName() == tagActionProp ) {
00575 elem = e;
00576
break;
00577 }
00578 }
00579
00580
00581
if( elem.isNull() ) {
00582 elem = doc.createElement( tagActionProp );
00583 doc.documentElement().appendChild( elem );
00584 }
00585
return elem;
00586 }
00587
00588
QDomElement KXMLGUIFactory::findActionByName(
QDomElement& elem,
const QString& sName,
bool create )
00589 {
00590
static const QString& attrName =
KGlobal::staticQString(
"name" );
00591
static const QString& tagAction =
KGlobal::staticQString(
"Action" );
00592
for(
QDomNode it = elem.firstChild(); !it.isNull(); it = it.nextSibling() ) {
00593
QDomElement e = it.toElement();
00594
if( e.attribute( attrName ) == sName )
00595
return e;
00596 }
00597
00598
if(
create ) {
00599
QDomElement act_elem = elem.ownerDocument().createElement( tagAction );
00600 act_elem.setAttribute( attrName, sName );
00601 elem.appendChild( act_elem );
00602
return act_elem;
00603 }
00604
return QDomElement();
00605 }
00606
00607
void KXMLGUIFactory::virtual_hook(
int,
void* )
00608 { }
00609
00610
#include "kxmlguifactory.moc"
00611
00612
00613