• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDEUI

kxmlguifactory.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, 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 <QtCore/QDir>
00029 #include <QtXml/QDomDocument>
00030 #include <QtCore/QFile>
00031 #include <QtCore/QTextIStream>
00032 #include <QtGui/QWidget>
00033 #include <QtCore/QDate>
00034 #include <QtCore/QVariant>
00035 #include <QTextCodec>
00036 
00037 #include <kdebug.h>
00038 #include <kcomponentdata.h>
00039 #include <kglobal.h>
00040 #include <kshortcut.h>
00041 #include <kstandarddirs.h>
00042 
00043 #include "kaction.h"
00044 #include "kshortcutsdialog.h"
00045 #include "kactioncollection.h"
00046 
00047 using namespace KXMLGUI;
00048 
00049 class KXMLGUIFactoryPrivate : public BuildState
00050 {
00051 public:
00052     enum ShortcutOption { SetActiveShortcut = 1, SetDefaultShortcut = 2};
00053 
00054     KXMLGUIFactoryPrivate()
00055     {
00056         static const QString &defaultMergingName = KGlobal::staticQString( "<default>" );
00057         static const QString &actionList = KGlobal::staticQString( "actionlist" );
00058         static const QString &name = KGlobal::staticQString( "name" );
00059 
00060         m_rootNode = new ContainerNode( 0L, QString(), 0L );
00061         m_defaultMergingName = defaultMergingName;
00062         tagActionList = actionList;
00063         attrName = name;
00064     }
00065     ~KXMLGUIFactoryPrivate()
00066     {
00067         delete m_rootNode;
00068     }
00069 
00070     void pushState()
00071     {
00072         m_stateStack.push( *this );
00073     }
00074 
00075     void popState()
00076     {
00077         BuildState::operator=( m_stateStack.pop() );
00078     }
00079 
00080     bool emptyState() const { return m_stateStack.isEmpty(); }
00081 
00082     QWidget *findRecursive( KXMLGUI::ContainerNode *node, bool tag );
00083     QList<QWidget*> findRecursive( KXMLGUI::ContainerNode *node, const QString &tagName );
00084     void applyActionProperties( const QDomElement &element,
00085         ShortcutOption shortcutOption = KXMLGUIFactoryPrivate::SetActiveShortcut );
00086     void configureAction( QAction *action, const QDomNamedNodeMap &attributes,
00087         ShortcutOption shortcutOption = KXMLGUIFactoryPrivate::SetActiveShortcut );
00088     void configureAction( QAction *action, const QDomAttr &attribute,
00089         ShortcutOption shortcutOption = KXMLGUIFactoryPrivate::SetActiveShortcut );
00090 
00091     QDomDocument shortcutSchemeDoc(KXMLGUIClient *client);
00092     void applyShortcutScheme(KXMLGUIClient *client, const QList<QAction*>& actions, const QDomDocument& scheme);
00093     void refreshActionProperties(KXMLGUIClient *client, const QList<QAction*>& actions, const QDomDocument& doc);
00094     void saveDefaultActionProperties(const QList<QAction*>& actions);
00095 
00096     ContainerNode *m_rootNode;
00097 
00098     QString m_defaultMergingName;
00099 
00100     /*
00101      * Contains the container which is searched for in ::container .
00102      */
00103     QString m_containerName;
00104 
00105     /*
00106      * List of all clients
00107      */
00108     QList<KXMLGUIClient*> m_clients;
00109 
00110     QString tagActionList;
00111 
00112     QString attrName;
00113 
00114     BuildStateStack m_stateStack;
00115 };
00116 
00117 QString KXMLGUIFactory::readConfigFile( const QString &filename, const KComponentData &_componentData )
00118 {
00119     QString xml_file;
00120 
00121     if (!QDir::isRelativePath(filename))
00122         xml_file = filename;
00123     else
00124     {
00125         KComponentData componentData = _componentData.isValid() ? _componentData : KGlobal::mainComponent();
00126         xml_file = KStandardDirs::locate("data", componentData.componentName() + '/' + filename);
00127         if ( !QFile::exists( xml_file ) )
00128           xml_file = KStandardDirs::locate( "data", filename );
00129     }
00130 
00131     QFile file( xml_file );
00132     if ( xml_file.isEmpty() || !file.open( QIODevice::ReadOnly ) )
00133     {
00134         kError(240) << "No such XML file" << filename;
00135         return QString();
00136     }
00137 
00138     QByteArray buffer(file.readAll());
00139     return QString::fromUtf8(buffer.constData(), buffer.size());
00140 }
00141 
00142 bool KXMLGUIFactory::saveConfigFile( const QDomDocument& doc,
00143                                      const QString& filename, const KComponentData &_componentData )
00144 {
00145     KComponentData componentData = _componentData.isValid() ? _componentData : KGlobal::mainComponent();
00146     QString xml_file(filename);
00147 
00148     if (QDir::isRelativePath(xml_file))
00149         xml_file = KStandardDirs::locateLocal("data", componentData.componentName() + '/' + filename);
00150 
00151     QFile file( xml_file );
00152     if ( xml_file.isEmpty() || !file.open( QIODevice::WriteOnly ) )
00153     {
00154         kError(240) << "Could not write to" << filename;
00155         return false;
00156     }
00157 
00158     // write out our document
00159     QTextStream ts(&file);
00160     ts.setCodec( QTextCodec::codecForName( "UTF-8" ) );
00161     ts << doc;
00162 
00163     file.close();
00164     return true;
00165 }
00166 
00170 static void removeDOMComments( QDomNode &node )
00171 {
00172     QDomNode n = node.firstChild();
00173     while ( !n.isNull() )
00174     {
00175         if ( n.nodeType() == QDomNode::CommentNode )
00176         {
00177             QDomNode tmp = n;
00178             n = n.nextSibling();
00179             node.removeChild( tmp );
00180         }
00181         else
00182         {
00183             QDomNode tmp = n;
00184             n = n.nextSibling();
00185             removeDOMComments( tmp );
00186         }
00187     }
00188 }
00189 
00190 KXMLGUIFactory::KXMLGUIFactory( KXMLGUIBuilder *builder, QObject *parent )
00191     : QObject( parent ),d(new KXMLGUIFactoryPrivate)
00192 {
00193     d->builder = builder;
00194     d->guiClient = 0;
00195     if ( d->builder )
00196     {
00197         d->builderContainerTags = d->builder->containerTags();
00198         d->builderCustomTags = d->builder->customTags();
00199     }
00200 }
00201 
00202 KXMLGUIFactory::~KXMLGUIFactory()
00203 {
00204     foreach (KXMLGUIClient *client, d->m_clients) {
00205         client->setFactory ( 0L );
00206     }
00207     delete d;
00208 }
00209 
00210 void KXMLGUIFactory::addClient( KXMLGUIClient *client )
00211 {
00212     //kDebug(260) << client;
00213     if ( client->factory() ) {
00214         if ( client->factory() == this )
00215             return;
00216         else
00217             client->factory()->removeClient( client ); //just in case someone does stupid things ;-)
00218     }
00219 
00220     if (d->emptyState())
00221         emit makingChanges(true);
00222     d->pushState();
00223 
00224 //    QTime dt; dt.start();
00225 
00226     d->guiClient = client;
00227 
00228     // add this client to our client list
00229     if ( !d->m_clients.contains( client ) )
00230         d->m_clients.append( client );
00231     else
00232         kDebug(260) << "XMLGUI client already added " << client;
00233 
00234     // Tell the client that plugging in is process and
00235     //  let it know what builder widget its mainwindow shortcuts
00236     //  should be attached to.
00237     client->beginXMLPlug( d->builder->widget() );
00238 
00239     // try to use the build document for building the client's GUI, as the build document
00240     // contains the correct container state information (like toolbar positions, sizes, etc.) .
00241     // if there is non available, then use the "real" document.
00242     QDomDocument doc = client->xmlguiBuildDocument();
00243     if ( doc.documentElement().isNull() )
00244         doc = client->domDocument();
00245 
00246     QDomElement docElement = doc.documentElement();
00247 
00248     d->m_rootNode->index = -1;
00249 
00250     // cache some variables
00251 
00252     d->clientName = docElement.attribute( d->attrName );
00253     d->clientBuilder = client->clientBuilder();
00254 
00255     if ( d->clientBuilder )
00256     {
00257         d->clientBuilderContainerTags = d->clientBuilder->containerTags();
00258         d->clientBuilderCustomTags = d->clientBuilder->customTags();
00259     }
00260     else
00261     {
00262         d->clientBuilderContainerTags.clear();
00263         d->clientBuilderCustomTags.clear();
00264     }
00265 
00266     // load shortcut schemes, user-defined shortcuts and other action properties
00267     d->saveDefaultActionProperties(client->actionCollection()->actions());
00268     if (!doc.isNull())
00269         d->refreshActionProperties(client, client->actionCollection()->actions(), doc);
00270 
00271     BuildHelper( *d, d->m_rootNode ).build( docElement );
00272 
00273     // let the client know that we built its GUI.
00274     client->setFactory( this );
00275 
00276     // call the finalizeGUI method, to fix up the positions of toolbars for example.
00277     // ### FIXME : obey client builder
00278     // --- Well, toolbars have a bool "positioned", so it doesn't really matter,
00279     // if we call positionYourself on all of them each time. (David)
00280     d->builder->finalizeGUI( d->guiClient );
00281 
00282     // reset some variables, for safety
00283     d->BuildState::reset();
00284 
00285     client->endXMLPlug();
00286 
00287     d->popState();
00288 
00289     emit clientAdded( client );
00290 
00291     // build child clients
00292     foreach (KXMLGUIClient *child, client->childClients())
00293         addClient( child );
00294 
00295     if (d->emptyState())
00296         emit makingChanges(false);
00297 /*
00298     QString unaddedActions;
00299     foreach (KActionCollection* ac, KActionCollection::allCollections())
00300       foreach (QAction* action, ac->actions())
00301         if (action->associatedWidgets().isEmpty())
00302           unaddedActions += action->objectName() + ' ';
00303 
00304     if (!unaddedActions.isEmpty())
00305       kWarning() << "The following actions are not plugged into the gui (shortcuts will not work): " << unaddedActions;
00306 */
00307 
00308 //    kDebug() << "addClient took " << dt.elapsed();
00309 }
00310 
00311 void KXMLGUIFactory::refreshActionProperties()
00312 {
00313     foreach (KXMLGUIClient *client, d->m_clients)
00314     {
00315         d->guiClient = client;
00316         QDomDocument doc = client->xmlguiBuildDocument();
00317         if ( doc.documentElement().isNull() )
00318         {
00319             client->reloadXML();
00320             doc = client->domDocument();
00321         }
00322         d->refreshActionProperties(client, client->actionCollection()->actions(), doc);
00323     }
00324     d->guiClient = 0;
00325 }
00326 
00327 static QString currentShortcutScheme()
00328 {
00329     const KConfigGroup cg = KGlobal::config()->group("Shortcut Schemes");
00330     return cg.readEntry("Current Scheme", "Default");
00331 }
00332 
00333 // Find the right ActionProperties element, otherwise return null element
00334 static QDomElement findActionPropertiesElement(const QDomDocument& doc)
00335 {
00336     const QLatin1String tagActionProp("ActionProperties");
00337     const QString schemeName = currentShortcutScheme();
00338     QDomElement e = doc.documentElement().firstChildElement();
00339     for( ; !e.isNull(); e = e.nextSiblingElement() ) {
00340         if (QString::compare(e.tagName(), tagActionProp, Qt::CaseInsensitive) == 0
00341             && (e.attribute("scheme", "Default") == schemeName) ) {
00342             return e;
00343         }
00344     }
00345     return QDomElement();
00346 }
00347 
00348 void KXMLGUIFactoryPrivate::refreshActionProperties(KXMLGUIClient *client, const QList<QAction*>& actions, const QDomDocument& doc)
00349 {
00350     // try to find and apply shortcuts schemes
00351     QDomDocument scheme = shortcutSchemeDoc(client);
00352     applyShortcutScheme(client, actions, scheme);
00353 
00354     // try to find and apply user-defined shortcuts
00355     const QDomElement actionPropElement = findActionPropertiesElement(doc);
00356     if ( !actionPropElement.isNull() )
00357         applyActionProperties( actionPropElement );
00358 }
00359 
00360 void KXMLGUIFactoryPrivate::saveDefaultActionProperties(const QList<QAction *>& actions)
00361 {
00362     // This method is called every time the user activated a new
00363     // kxmlguiclient. We only want to execute the following code only once in
00364     // the lifetime of an action.
00365     foreach (QAction *action, actions) {
00366         // Skip actions we have seen already.
00367         if (action->property("_k_DefaultShortcut").isValid()) continue;
00368 
00369         if (KAction* kaction = qobject_cast<KAction*>(action)) {
00370             // Check if the default shortcut is set
00371             KShortcut defaultShortcut = kaction->shortcut(KAction::DefaultShortcut);
00372             KShortcut activeShortcut  = kaction->shortcut(KAction::ActiveShortcut);
00373             //kDebug() << kaction->objectName() << "default=" << defaultShortcut.toString() << "active=" << activeShortcut.toString();
00374 
00375             // Check if we have an empty default shortcut and an non empty
00376             // custom shortcut. This should only happen if a developer called
00377             // QAction::setShortcut on an KAction. Print out a warning and
00378             // correct the mistake
00379             if ((!activeShortcut.isEmpty()) && defaultShortcut.isEmpty()) {
00380                 kError(240) << "Shortcut for KAction " << kaction->objectName() << kaction->text() << "set with QShortcut::setShortcut()! See KAction documentation.";
00381                 kaction->setProperty("_k_DefaultShortcut", activeShortcut);
00382             } else {
00383                 kaction->setProperty("_k_DefaultShortcut", defaultShortcut);
00384             }
00385         }
00386         else
00387         {
00388             // A QAction used with KXMLGUI? Set our property and ignore it.
00389             kError(240) << "Attempt to use QAction" << action->objectName() << "with KXMLGUIFactory!";
00390             action->setProperty("_k_DefaultShortcut", KShortcut());
00391         }
00392 
00393     }
00394 }
00395 
00396 void KXMLGUIFactory::changeShortcutScheme(const QString &scheme)
00397 {
00398     kDebug(260) << "Changing shortcut scheme to" << scheme;
00399     KConfigGroup cg = KGlobal::config()->group( "Shortcut Schemes" );
00400     cg.writeEntry("Current Scheme", scheme);
00401 
00402     refreshActionProperties();
00403 }
00404 
00405 void KXMLGUIFactory::forgetClient( KXMLGUIClient *client )
00406 {
00407     d->m_clients.removeAll( client );
00408 }
00409 
00410 void KXMLGUIFactory::removeClient( KXMLGUIClient *client )
00411 {
00412     //kDebug(260) << client;
00413 
00414     // don't try to remove the client's GUI if we didn't build it
00415     if ( !client || client->factory() != this )
00416         return;
00417 
00418     if (d->emptyState())
00419         emit makingChanges(true);
00420 
00421     // remove this client from our client list
00422     d->m_clients.removeAll( client );
00423 
00424     // remove child clients first (create a copy of the list just in case the
00425     // original list is modified directly or indirectly in removeClient())
00426     const QList<KXMLGUIClient*> childClients(client->childClients());
00427     foreach (KXMLGUIClient *child, childClients)
00428         removeClient(child);
00429 
00430     //kDebug(260) << "calling removeRecursive";
00431 
00432     d->pushState();
00433 
00434     // cache some variables
00435 
00436     d->guiClient = client;
00437     d->clientName = client->domDocument().documentElement().attribute( d->attrName );
00438     d->clientBuilder = client->clientBuilder();
00439 
00440     client->setFactory( 0L );
00441 
00442     // if we don't have a build document for that client, yet, then create one by
00443     // cloning the original document, so that saving container information in the
00444     // DOM tree does not touch the original document.
00445     QDomDocument doc = client->xmlguiBuildDocument();
00446     if ( doc.documentElement().isNull() )
00447     {
00448         doc = client->domDocument().cloneNode( true ).toDocument();
00449         client->setXMLGUIBuildDocument( doc );
00450     }
00451 
00452     d->m_rootNode->destruct( doc.documentElement(), *d );
00453 
00454     // reset some variables
00455     d->BuildState::reset();
00456 
00457     // This will destruct the KAccel object built around the given widget.
00458     client->prepareXMLUnplug( d->builder->widget() );
00459 
00460     d->popState();
00461 
00462     if (d->emptyState())
00463         emit makingChanges(false);
00464 
00465     emit clientRemoved( client );
00466 }
00467 
00468 QList<KXMLGUIClient*> KXMLGUIFactory::clients() const
00469 {
00470     return d->m_clients;
00471 }
00472 
00473 QWidget *KXMLGUIFactory::container( const QString &containerName, KXMLGUIClient *client,
00474                                     bool useTagName )
00475 {
00476     d->pushState();
00477     d->m_containerName = containerName;
00478     d->guiClient = client;
00479 
00480     QWidget *result = d->findRecursive( d->m_rootNode, useTagName );
00481 
00482     d->guiClient = 0L;
00483     d->m_containerName.clear();
00484 
00485     d->popState();
00486 
00487     return result;
00488 }
00489 
00490 QList<QWidget*> KXMLGUIFactory::containers( const QString &tagName )
00491 {
00492     return d->findRecursive( d->m_rootNode, tagName );
00493 }
00494 
00495 void KXMLGUIFactory::reset()
00496 {
00497     d->m_rootNode->reset();
00498 
00499     d->m_rootNode->clearChildren();
00500 }
00501 
00502 void KXMLGUIFactory::resetContainer( const QString &containerName, bool useTagName )
00503 {
00504     if ( containerName.isEmpty() )
00505         return;
00506 
00507     ContainerNode *container = d->m_rootNode->findContainer( containerName, useTagName );
00508 
00509     if ( !container )
00510         return;
00511 
00512     ContainerNode *parent = container->parent;
00513     if ( !parent )
00514         return;
00515 
00516     //  resetInternal( container );
00517 
00518     parent->removeChild( container );
00519 }
00520 
00521 QWidget *KXMLGUIFactoryPrivate::findRecursive( KXMLGUI::ContainerNode *node, bool tag )
00522 {
00523     if ( ( ( !tag && node->name == m_containerName ) ||
00524            ( tag && node->tagName == m_containerName ) ) &&
00525          ( !guiClient || node->client == guiClient ) )
00526         return node->container;
00527 
00528     foreach (ContainerNode* child, node->children)
00529     {
00530         QWidget *cont = findRecursive( child, tag );
00531         if ( cont )
00532             return cont;
00533     }
00534 
00535     return 0L;
00536 }
00537 
00538 // Case insensitive equality without calling toLower which allocates a new string
00539 static inline bool equals(const QString& str1, const char* str2)
00540 {
00541     return str1.compare(QLatin1String(str2), Qt::CaseInsensitive) == 0;
00542 }
00543 static inline bool equals(const QString& str1, const QString& str2)
00544 {
00545     return str1.compare(str2, Qt::CaseInsensitive) == 0;
00546 }
00547 
00548 
00549 QList<QWidget*> KXMLGUIFactoryPrivate::findRecursive( KXMLGUI::ContainerNode *node,
00550                                                       const QString &tagName )
00551 {
00552     QList<QWidget*> res;
00553 
00554     if ( equals(node->tagName, tagName) )
00555         res.append( node->container );
00556 
00557     foreach (KXMLGUI::ContainerNode* child, node->children)
00558         res << findRecursive( child, tagName );
00559 
00560     return res;
00561 }
00562 
00563 void KXMLGUIFactory::plugActionList( KXMLGUIClient *client, const QString &name,
00564                                      const QList<QAction*> &actionList )
00565 {
00566     d->pushState();
00567     d->guiClient = client;
00568     d->actionListName = name;
00569     d->actionList = actionList;
00570     d->clientName = client->domDocument().documentElement().attribute( d->attrName );
00571 
00572     d->m_rootNode->plugActionList( *d );
00573 
00574     // Load shortcuts for these new actions
00575     d->saveDefaultActionProperties(actionList);
00576     d->refreshActionProperties(client, actionList, client->domDocument());
00577 
00578     d->BuildState::reset();
00579     d->popState();
00580 }
00581 
00582 void KXMLGUIFactory::unplugActionList( KXMLGUIClient *client, const QString &name )
00583 {
00584     d->pushState();
00585     d->guiClient = client;
00586     d->actionListName = name;
00587     d->clientName = client->domDocument().documentElement().attribute( d->attrName );
00588 
00589     d->m_rootNode->unplugActionList( *d );
00590 
00591     d->BuildState::reset();
00592     d->popState();
00593 }
00594 
00595 void KXMLGUIFactoryPrivate::applyActionProperties( const QDomElement &actionPropElement,
00596         ShortcutOption shortcutOption )
00597 {
00598     for (QDomElement e = actionPropElement.firstChildElement();
00599          !e.isNull(); e = e.nextSiblingElement()) {
00600         if ( !equals(e.tagName(), "action") )
00601             continue;
00602 
00603         QAction *action = guiClient->action( e );
00604         if ( !action )
00605             continue;
00606 
00607         configureAction( action, e.attributes(), shortcutOption );
00608     }
00609 }
00610 
00611 void KXMLGUIFactoryPrivate::configureAction( QAction *action, const QDomNamedNodeMap &attributes,
00612         ShortcutOption shortcutOption )
00613 {
00614     for ( uint i = 0; i < attributes.length(); i++ )
00615     {
00616         QDomAttr attr = attributes.item( i ).toAttr();
00617         if ( attr.isNull() )
00618             continue;
00619 
00620         configureAction( action, attr, shortcutOption );
00621     }
00622 }
00623 
00624 void KXMLGUIFactoryPrivate::configureAction( QAction *action, const QDomAttr &attribute,
00625         ShortcutOption shortcutOption )
00626 {
00627     static const QString &attrShortcut = KGlobal::staticQString( "shortcut" );
00628 
00629     QString attrName = attribute.name();
00630     // If the attribute is a deprecated "accel", change to "shortcut".
00631     if ( equals(attrName, "accel") )
00632         attrName = attrShortcut;
00633 
00634     // No need to re-set name, particularly since it's "objectName" in Qt4
00635     if ( equals(attrName, "name") )
00636         return;
00637 
00638     if ( equals(attrName, "icon") ) {
00639         action->setIcon( KIcon( attribute.value() ) );
00640         return;
00641     }
00642 
00643     QVariant propertyValue;
00644 
00645     QVariant::Type propertyType = action->property( attrName.toLatin1() ).type();
00646 
00647     if ( propertyType == QVariant::Int ) {
00648         propertyValue = QVariant( attribute.value().toInt() );
00649     } else if ( propertyType == QVariant::UInt ) {
00650         propertyValue = QVariant( attribute.value().toUInt() );
00651     } else if ( propertyType == QVariant::UserType && action->property( attrName.toLatin1() ).userType() == qMetaTypeId<KShortcut>() ) {
00652         // Setting the shortcut by property also sets the default shortcut (which is incorrect), so we have to do it directly
00653         if (KAction* ka = qobject_cast<KAction*>(action)) {
00654             if (attrName=="globalShortcut") {
00655                 ka->setGlobalShortcut(KShortcut(attribute.value()), KAction::ActiveShortcut);
00656             } else {
00657                 ka->setShortcut(KShortcut(attribute.value()), KAction::ActiveShortcut);
00658             }
00659             if (shortcutOption & KXMLGUIFactoryPrivate::SetDefaultShortcut)
00660                 ka->setShortcut(KShortcut(attribute.value()), KAction::DefaultShortcut);
00661             return;
00662         }
00663         propertyValue = KShortcut( attribute.value() );
00664     } else {
00665         propertyValue = QVariant( attribute.value() );
00666     }
00667     if (!action->setProperty( attrName.toLatin1(), propertyValue )) {
00668         kWarning() << "Error: Unknown action property " << attrName << " will be ignored!";
00669     }
00670 }
00671 
00672 QDomDocument KXMLGUIFactoryPrivate::shortcutSchemeDoc(KXMLGUIClient *client)
00673 {
00674     // Get the name of the current shorcut scheme
00675     KConfigGroup cg = KGlobal::config()->group( "Shortcut Schemes" );
00676     QString schemeName = cg.readEntry("Current Scheme", "Default");
00677 
00678     QDomDocument doc;
00679     if (schemeName != "Default")
00680     {
00681         // Find the document for the shortcut scheme using both current application path
00682         // and current xmlguiclient path but making a preference to app path
00683         QString schemeFileName = KStandardDirs::locateLocal("data",
00684             client->componentData().componentName() + '/' +
00685             client->componentData().componentName() + schemeName.toLower() + "shortcuts.rc" );
00686 
00687         QFile schemeFile(schemeFileName);
00688         if (schemeFile.open(QIODevice::ReadOnly))
00689         {
00690 //             kDebug(260) << "Found shortcut scheme" << schemeFileName;
00691             doc.setContent(&schemeFile);
00692             schemeFile.close();
00693         }
00694     }
00695     return doc;
00696 }
00697 
00698 void KXMLGUIFactoryPrivate::applyShortcutScheme(KXMLGUIClient *client, const QList<QAction*> &actions, const QDomDocument& scheme)
00699 {
00700     static const QString &actionPropElementName = KGlobal::staticQString( "ActionProperties" );
00701 
00702     KConfigGroup cg = KGlobal::config()->group( "Shortcut Schemes" );
00703     QString schemeName = cg.readEntry("Current Scheme", "Default");
00704 
00705     //First clear all existing shortcuts
00706     if (schemeName != "Default") {
00707         foreach (QAction *action, actions) {
00708             if (KAction *kaction = qobject_cast<KAction*>(action)) {
00709                 kaction->setShortcut(KShortcut(), KAction::ActiveShortcut);
00710                 // We clear the default shortcut as well because the shortcut scheme will set its own defaults
00711                 kaction->setShortcut(KShortcut(), KAction::DefaultShortcut);
00712             }
00713             else
00714                 action->setProperty("shortcut", KShortcut());
00715         }
00716     } else {
00717         // apply saved default shortcuts
00718         foreach (QAction *action, actions) {
00719             if (KAction *kaction = qobject_cast<KAction*>(action)) {
00720                 QVariant savedDefaultShortcut = kaction->property("_k_DefaultShortcut");
00721                 if (savedDefaultShortcut.isValid()) {
00722                     KShortcut shortcut = savedDefaultShortcut.value<KShortcut>();
00723                     //kDebug() << "scheme said" << shortcut.toString() << "for action" << kaction->objectName();
00724                     kaction->setShortcut(shortcut, KAction::ActiveShortcut);
00725                     kaction->setShortcut(shortcut, KAction::DefaultShortcut);
00726                     continue;
00727                 }
00728             }
00729             action->setProperty("shortcut", KShortcut());
00730         }
00731     }
00732 
00733     if (scheme.isNull())
00734         return;
00735 
00736     QDomElement docElement = scheme.documentElement();
00737     QDomElement actionPropElement = docElement.namedItem( actionPropElementName ).toElement();
00738 
00739     //Check if we really have the shortcut configuration here
00740     if (!actionPropElement.isNull()) {
00741         kDebug(260) << "Applying shortcut scheme for XMLGUI client" << client->componentData().componentName();
00742 
00743         //Apply all shortcuts we have
00744         applyActionProperties(actionPropElement, KXMLGUIFactoryPrivate::SetDefaultShortcut);
00745     } else {
00746         kDebug(260) << "Invalid shortcut scheme file";
00747     }
00748 }
00749 
00750 int KXMLGUIFactory::configureShortcuts(bool letterCutsOk , bool bSaveSettings )
00751 {
00752     KShortcutsDialog dlg(KShortcutsEditor::AllActions,
00753                          letterCutsOk ? KShortcutsEditor::LetterShortcutsAllowed : KShortcutsEditor::LetterShortcutsDisallowed,
00754                          qobject_cast<QWidget*>(parent()));
00755     foreach (KXMLGUIClient *client, d->m_clients) {
00756         if(client) {
00757             dlg.addCollection(client->actionCollection());
00758         }
00759     }
00760     return dlg.configure(bSaveSettings);
00761 }
00762 
00763 // Find or create
00764 QDomElement KXMLGUIFactory::actionPropertiesElement( QDomDocument& doc )
00765 {
00766     // first, lets see if we have existing properties
00767     QDomElement elem = findActionPropertiesElement(doc);
00768 
00769     // if there was none, create one
00770     if(elem.isNull()) {
00771         elem = doc.createElement(QLatin1String("ActionProperties"));
00772         elem.setAttribute("scheme", currentShortcutScheme());
00773         doc.documentElement().appendChild( elem );
00774     }
00775     return elem;
00776 }
00777 
00778 QDomElement KXMLGUIFactory::findActionByName( QDomElement& elem, const QString& sName, bool create )
00779 {
00780         static const QString& attrName = KGlobal::staticQString( "name" );
00781     static const QString& tagAction = KGlobal::staticQString( "Action" );
00782     for( QDomNode it = elem.firstChild(); !it.isNull(); it = it.nextSibling() ) {
00783         QDomElement e = it.toElement();
00784         if( e.attribute( attrName ) == sName )
00785             return e;
00786     }
00787 
00788     if( create ) {
00789         QDomElement act_elem = elem.ownerDocument().createElement( tagAction );
00790         act_elem.setAttribute( attrName, sName );
00791                 elem.appendChild( act_elem );
00792                 return act_elem;
00793     }
00794         return QDomElement();
00795 }
00796 
00797 #include "kxmlguifactory.moc"
00798 
00799 /* vim: et sw=4
00800  */

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal