• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.9.5 API Reference
  • 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 NULL actions or those we have seen already.
00367         if (!action || 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         if ( !action->isSeparator() )
00390               kError(240) << "Attempt to use QAction" << action->objectName() << "with KXMLGUIFactory!";
00391             action->setProperty("_k_DefaultShortcut", KShortcut());
00392         }
00393 
00394     }
00395 }
00396 
00397 void KXMLGUIFactory::changeShortcutScheme(const QString &scheme)
00398 {
00399     kDebug(260) << "Changing shortcut scheme to" << scheme;
00400     KConfigGroup cg = KGlobal::config()->group( "Shortcut Schemes" );
00401     cg.writeEntry("Current Scheme", scheme);
00402 
00403     refreshActionProperties();
00404 }
00405 
00406 void KXMLGUIFactory::forgetClient( KXMLGUIClient *client )
00407 {
00408     d->m_clients.removeAll( client );
00409 }
00410 
00411 void KXMLGUIFactory::removeClient( KXMLGUIClient *client )
00412 {
00413     //kDebug(260) << client;
00414 
00415     // don't try to remove the client's GUI if we didn't build it
00416     if ( !client || client->factory() != this )
00417         return;
00418 
00419     if (d->emptyState())
00420         emit makingChanges(true);
00421 
00422     // remove this client from our client list
00423     d->m_clients.removeAll( client );
00424 
00425     // remove child clients first (create a copy of the list just in case the
00426     // original list is modified directly or indirectly in removeClient())
00427     const QList<KXMLGUIClient*> childClients(client->childClients());
00428     foreach (KXMLGUIClient *child, childClients)
00429         removeClient(child);
00430 
00431     //kDebug(260) << "calling removeRecursive";
00432 
00433     d->pushState();
00434 
00435     // cache some variables
00436 
00437     d->guiClient = client;
00438     d->clientName = client->domDocument().documentElement().attribute( d->attrName );
00439     d->clientBuilder = client->clientBuilder();
00440 
00441     client->setFactory( 0L );
00442 
00443     // if we don't have a build document for that client, yet, then create one by
00444     // cloning the original document, so that saving container information in the
00445     // DOM tree does not touch the original document.
00446     QDomDocument doc = client->xmlguiBuildDocument();
00447     if ( doc.documentElement().isNull() )
00448     {
00449         doc = client->domDocument().cloneNode( true ).toDocument();
00450         client->setXMLGUIBuildDocument( doc );
00451     }
00452 
00453     d->m_rootNode->destruct( doc.documentElement(), *d );
00454 
00455     // reset some variables
00456     d->BuildState::reset();
00457 
00458     // This will destruct the KAccel object built around the given widget.
00459     client->prepareXMLUnplug( d->builder->widget() );
00460 
00461     d->popState();
00462 
00463     if (d->emptyState())
00464         emit makingChanges(false);
00465 
00466     emit clientRemoved( client );
00467 }
00468 
00469 QList<KXMLGUIClient*> KXMLGUIFactory::clients() const
00470 {
00471     return d->m_clients;
00472 }
00473 
00474 QWidget *KXMLGUIFactory::container( const QString &containerName, KXMLGUIClient *client,
00475                                     bool useTagName )
00476 {
00477     d->pushState();
00478     d->m_containerName = containerName;
00479     d->guiClient = client;
00480 
00481     QWidget *result = d->findRecursive( d->m_rootNode, useTagName );
00482 
00483     d->guiClient = 0L;
00484     d->m_containerName.clear();
00485 
00486     d->popState();
00487 
00488     return result;
00489 }
00490 
00491 QList<QWidget*> KXMLGUIFactory::containers( const QString &tagName )
00492 {
00493     return d->findRecursive( d->m_rootNode, tagName );
00494 }
00495 
00496 void KXMLGUIFactory::reset()
00497 {
00498     d->m_rootNode->reset();
00499 
00500     d->m_rootNode->clearChildren();
00501 }
00502 
00503 void KXMLGUIFactory::resetContainer( const QString &containerName, bool useTagName )
00504 {
00505     if ( containerName.isEmpty() )
00506         return;
00507 
00508     ContainerNode *container = d->m_rootNode->findContainer( containerName, useTagName );
00509 
00510     if ( !container )
00511         return;
00512 
00513     ContainerNode *parent = container->parent;
00514     if ( !parent )
00515         return;
00516 
00517     //  resetInternal( container );
00518 
00519     parent->removeChild( container );
00520 }
00521 
00522 QWidget *KXMLGUIFactoryPrivate::findRecursive( KXMLGUI::ContainerNode *node, bool tag )
00523 {
00524     if ( ( ( !tag && node->name == m_containerName ) ||
00525            ( tag && node->tagName == m_containerName ) ) &&
00526          ( !guiClient || node->client == guiClient ) )
00527         return node->container;
00528 
00529     foreach (ContainerNode* child, node->children)
00530     {
00531         QWidget *cont = findRecursive( child, tag );
00532         if ( cont )
00533             return cont;
00534     }
00535 
00536     return 0L;
00537 }
00538 
00539 // Case insensitive equality without calling toLower which allocates a new string
00540 static inline bool equals(const QString& str1, const char* str2)
00541 {
00542     return str1.compare(QLatin1String(str2), Qt::CaseInsensitive) == 0;
00543 }
00544 static inline bool equals(const QString& str1, const QString& str2)
00545 {
00546     return str1.compare(str2, Qt::CaseInsensitive) == 0;
00547 }
00548 
00549 
00550 QList<QWidget*> KXMLGUIFactoryPrivate::findRecursive( KXMLGUI::ContainerNode *node,
00551                                                       const QString &tagName )
00552 {
00553     QList<QWidget*> res;
00554 
00555     if ( equals(node->tagName, tagName) )
00556         res.append( node->container );
00557 
00558     foreach (KXMLGUI::ContainerNode* child, node->children)
00559         res << findRecursive( child, tagName );
00560 
00561     return res;
00562 }
00563 
00564 void KXMLGUIFactory::plugActionList( KXMLGUIClient *client, const QString &name,
00565                                      const QList<QAction*> &actionList )
00566 {
00567     d->pushState();
00568     d->guiClient = client;
00569     d->actionListName = name;
00570     d->actionList = actionList;
00571     d->clientName = client->domDocument().documentElement().attribute( d->attrName );
00572 
00573     d->m_rootNode->plugActionList( *d );
00574 
00575     // Load shortcuts for these new actions
00576     d->saveDefaultActionProperties(actionList);
00577     d->refreshActionProperties(client, actionList, client->domDocument());
00578 
00579     d->BuildState::reset();
00580     d->popState();
00581 }
00582 
00583 void KXMLGUIFactory::unplugActionList( KXMLGUIClient *client, const QString &name )
00584 {
00585     d->pushState();
00586     d->guiClient = client;
00587     d->actionListName = name;
00588     d->clientName = client->domDocument().documentElement().attribute( d->attrName );
00589 
00590     d->m_rootNode->unplugActionList( *d );
00591 
00592     d->BuildState::reset();
00593     d->popState();
00594 }
00595 
00596 void KXMLGUIFactoryPrivate::applyActionProperties( const QDomElement &actionPropElement,
00597         ShortcutOption shortcutOption )
00598 {
00599     for (QDomElement e = actionPropElement.firstChildElement();
00600          !e.isNull(); e = e.nextSiblingElement()) {
00601         if ( !equals(e.tagName(), "action") )
00602             continue;
00603 
00604         QAction *action = guiClient->action( e );
00605         if ( !action )
00606             continue;
00607 
00608         configureAction( action, e.attributes(), shortcutOption );
00609     }
00610 }
00611 
00612 void KXMLGUIFactoryPrivate::configureAction( QAction *action, const QDomNamedNodeMap &attributes,
00613         ShortcutOption shortcutOption )
00614 {
00615     for ( uint i = 0; i < attributes.length(); i++ )
00616     {
00617         QDomAttr attr = attributes.item( i ).toAttr();
00618         if ( attr.isNull() )
00619             continue;
00620 
00621         configureAction( action, attr, shortcutOption );
00622     }
00623 }
00624 
00625 void KXMLGUIFactoryPrivate::configureAction( QAction *action, const QDomAttr &attribute,
00626         ShortcutOption shortcutOption )
00627 {
00628     static const QString &attrShortcut = KGlobal::staticQString( "shortcut" );
00629 
00630     QString attrName = attribute.name();
00631     // If the attribute is a deprecated "accel", change to "shortcut".
00632     if ( equals(attrName, "accel") )
00633         attrName = attrShortcut;
00634 
00635     // No need to re-set name, particularly since it's "objectName" in Qt4
00636     if ( equals(attrName, "name") )
00637         return;
00638 
00639     if ( equals(attrName, "icon") ) {
00640         action->setIcon( KIcon( attribute.value() ) );
00641         return;
00642     }
00643 
00644     QVariant propertyValue;
00645 
00646     QVariant::Type propertyType = action->property( attrName.toLatin1() ).type();
00647 
00648     if ( propertyType == QVariant::Int ) {
00649         propertyValue = QVariant( attribute.value().toInt() );
00650     } else if ( propertyType == QVariant::UInt ) {
00651         propertyValue = QVariant( attribute.value().toUInt() );
00652     } else if ( propertyType == QVariant::UserType && action->property( attrName.toLatin1() ).userType() == qMetaTypeId<KShortcut>() ) {
00653         // Setting the shortcut by property also sets the default shortcut (which is incorrect), so we have to do it directly
00654         if (KAction* ka = qobject_cast<KAction*>(action)) {
00655             if (attrName=="globalShortcut") {
00656                 ka->setGlobalShortcut(KShortcut(attribute.value()), KAction::ActiveShortcut);
00657             } else {
00658                 ka->setShortcut(KShortcut(attribute.value()), KAction::ActiveShortcut);
00659             }
00660             if (shortcutOption & KXMLGUIFactoryPrivate::SetDefaultShortcut)
00661                 ka->setShortcut(KShortcut(attribute.value()), KAction::DefaultShortcut);
00662             return;
00663         }
00664         propertyValue = KShortcut( attribute.value() );
00665     } else {
00666         propertyValue = QVariant( attribute.value() );
00667     }
00668     if (!action->setProperty( attrName.toLatin1(), propertyValue )) {
00669         kWarning() << "Error: Unknown action property " << attrName << " will be ignored!";
00670     }
00671 }
00672 
00673 QDomDocument KXMLGUIFactoryPrivate::shortcutSchemeDoc(KXMLGUIClient *client)
00674 {
00675     // Get the name of the current shorcut scheme
00676     KConfigGroup cg = KGlobal::config()->group( "Shortcut Schemes" );
00677     QString schemeName = cg.readEntry("Current Scheme", "Default");
00678 
00679     QDomDocument doc;
00680     if (schemeName != "Default")
00681     {
00682         // Find the document for the shortcut scheme using both current application path
00683         // and current xmlguiclient path but making a preference to app path
00684         QString schemeFileName = KStandardDirs::locateLocal("data",
00685             client->componentData().componentName() + '/' +
00686             client->componentData().componentName() + schemeName.toLower() + "shortcuts.rc" );
00687 
00688         QFile schemeFile(schemeFileName);
00689         if (schemeFile.open(QIODevice::ReadOnly))
00690         {
00691 //             kDebug(260) << "Found shortcut scheme" << schemeFileName;
00692             doc.setContent(&schemeFile);
00693             schemeFile.close();
00694         }
00695     }
00696     return doc;
00697 }
00698 
00699 void KXMLGUIFactoryPrivate::applyShortcutScheme(KXMLGUIClient *client, const QList<QAction*> &actions, const QDomDocument& scheme)
00700 {
00701     static const QString &actionPropElementName = KGlobal::staticQString( "ActionProperties" );
00702 
00703     KConfigGroup cg = KGlobal::config()->group( "Shortcut Schemes" );
00704     QString schemeName = cg.readEntry("Current Scheme", "Default");
00705 
00706     //First clear all existing shortcuts
00707     if (schemeName != "Default") {
00708         foreach (QAction *action, actions) {
00709             if (KAction *kaction = qobject_cast<KAction*>(action)) {
00710                 kaction->setShortcut(KShortcut(), KAction::ActiveShortcut);
00711                 // We clear the default shortcut as well because the shortcut scheme will set its own defaults
00712                 kaction->setShortcut(KShortcut(), KAction::DefaultShortcut);
00713                 continue;
00714             }
00715             if (action) {
00716                 action->setProperty("shortcut", KShortcut());
00717             }
00718         }
00719     } else {
00720         // apply saved default shortcuts
00721         foreach (QAction *action, actions) {
00722             if (KAction *kaction = qobject_cast<KAction*>(action)) {
00723                 QVariant savedDefaultShortcut = kaction->property("_k_DefaultShortcut");
00724                 if (savedDefaultShortcut.isValid()) {
00725                     KShortcut shortcut = savedDefaultShortcut.value<KShortcut>();
00726                     //kDebug() << "scheme said" << shortcut.toString() << "for action" << kaction->objectName();
00727                     kaction->setShortcut(shortcut, KAction::ActiveShortcut);
00728                     kaction->setShortcut(shortcut, KAction::DefaultShortcut);
00729                     continue;
00730                 }
00731             }
00732             if (action) {
00733                 action->setProperty("shortcut", KShortcut());
00734             }
00735         }
00736     }
00737 
00738     if (scheme.isNull())
00739         return;
00740 
00741     QDomElement docElement = scheme.documentElement();
00742     QDomElement actionPropElement = docElement.namedItem( actionPropElementName ).toElement();
00743 
00744     //Check if we really have the shortcut configuration here
00745     if (!actionPropElement.isNull()) {
00746         kDebug(260) << "Applying shortcut scheme for XMLGUI client" << client->componentData().componentName();
00747 
00748         //Apply all shortcuts we have
00749         applyActionProperties(actionPropElement, KXMLGUIFactoryPrivate::SetDefaultShortcut);
00750     } else {
00751         kDebug(260) << "Invalid shortcut scheme file";
00752     }
00753 }
00754 
00755 int KXMLGUIFactory::configureShortcuts(bool letterCutsOk , bool bSaveSettings )
00756 {
00757     KShortcutsDialog dlg(KShortcutsEditor::AllActions,
00758                          letterCutsOk ? KShortcutsEditor::LetterShortcutsAllowed : KShortcutsEditor::LetterShortcutsDisallowed,
00759                          qobject_cast<QWidget*>(parent()));
00760     foreach (KXMLGUIClient *client, d->m_clients) {
00761         if(client) {
00762             dlg.addCollection(client->actionCollection());
00763         }
00764     }
00765     return dlg.configure(bSaveSettings);
00766 }
00767 
00768 // Find or create
00769 QDomElement KXMLGUIFactory::actionPropertiesElement( QDomDocument& doc )
00770 {
00771     // first, lets see if we have existing properties
00772     QDomElement elem = findActionPropertiesElement(doc);
00773 
00774     // if there was none, create one
00775     if(elem.isNull()) {
00776         elem = doc.createElement(QLatin1String("ActionProperties"));
00777         elem.setAttribute("scheme", currentShortcutScheme());
00778         doc.documentElement().appendChild( elem );
00779     }
00780     return elem;
00781 }
00782 
00783 QDomElement KXMLGUIFactory::findActionByName( QDomElement& elem, const QString& sName, bool create )
00784 {
00785         static const QString& attrName = KGlobal::staticQString( "name" );
00786     static const QString& tagAction = KGlobal::staticQString( "Action" );
00787     for( QDomNode it = elem.firstChild(); !it.isNull(); it = it.nextSibling() ) {
00788         QDomElement e = it.toElement();
00789         if( e.attribute( attrName ) == sName )
00790             return e;
00791     }
00792 
00793     if( create ) {
00794         QDomElement act_elem = elem.ownerDocument().createElement( tagAction );
00795         act_elem.setAttribute( attrName, sName );
00796                 elem.appendChild( act_elem );
00797                 return act_elem;
00798     }
00799         return QDomElement();
00800 }
00801 
00802 #include "kxmlguifactory.moc"
00803 
00804 /* vim: et sw=4
00805  */
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:32:46 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

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

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • 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
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal