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