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

KDEUI

  • sources
  • kde-4.14
  • kdelibs
  • kdeui
  • xmlgui
kxmlguiversionhandler.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (C) 2000 Simon Hausmann <hausmann@kde.org>
3  Copyright (C) 2000 Kurt Granroth <granroth@kde.org>
4  Copyright 2007 David Faure <faure@kde.org>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include "kxmlguiversionhandler_p.h"
23 #include <kdebug.h>
24 #include <QFile>
25 #include <QDomDocument>
26 #include "kxmlguifactory.h"
27 #include <kglobal.h>
28 #include <kstandarddirs.h>
29 #include <QtXml/QDomElement>
30 
31 struct DocStruct
32 {
33  QString file;
34  QString data;
35 };
36 
37 static QList<QDomElement> extractToolBars(const QDomDocument& doc)
38 {
39  QList<QDomElement> toolbars;
40  QDomElement parent = doc.documentElement();
41  for (QDomElement e = parent.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
42  if (e.tagName().compare(QLatin1String("ToolBar"), Qt::CaseInsensitive) == 0) {
43  toolbars.append(e);
44  }
45  }
46  return toolbars;
47 }
48 
49 static void removeAllToolBars(QDomDocument& doc)
50 {
51  QDomElement parent = doc.documentElement();
52  const QList<QDomElement> toolBars = extractToolBars(doc);
53  foreach(const QDomElement& e, toolBars) {
54  parent.removeChild(e);
55  }
56 }
57 
58 static void insertToolBars(QDomDocument& doc, const QList<QDomElement>& toolBars)
59 {
60  QDomElement parent = doc.documentElement();
61  QDomElement menuBar = parent.namedItem("MenuBar").toElement();
62  QDomElement insertAfter = menuBar;
63  if (menuBar.isNull())
64  insertAfter = parent.firstChildElement(); // if null, insertAfter will do an append
65  foreach(const QDomElement& e, toolBars) {
66  QDomNode result = parent.insertAfter(e, insertAfter);
67  Q_ASSERT(!result.isNull());
68  }
69 }
70 
71 //
72 
73 typedef QMap<QString, QMap<QString, QString> > ActionPropertiesMap;
74 
75 static ActionPropertiesMap extractActionProperties(const QDomDocument &doc)
76 {
77  ActionPropertiesMap properties;
78 
79  QDomElement actionPropElement = doc.documentElement().namedItem( "ActionProperties" ).toElement();
80 
81  if ( actionPropElement.isNull() )
82  return properties;
83 
84  QDomNode n = actionPropElement.firstChild();
85  while(!n.isNull())
86  {
87  QDomElement e = n.toElement();
88  n = n.nextSibling(); // Advance now so that we can safely delete e
89  if ( e.isNull() )
90  continue;
91 
92  if ( e.tagName().compare("action", Qt::CaseInsensitive) != 0 )
93  continue;
94 
95  const QString actionName = e.attribute( "name" );
96  if ( actionName.isEmpty() )
97  continue;
98 
99  QMap<QString, QMap<QString, QString> >::Iterator propIt = properties.find( actionName );
100  if ( propIt == properties.end() )
101  propIt = properties.insert( actionName, QMap<QString, QString>() );
102 
103  const QDomNamedNodeMap attributes = e.attributes();
104  const uint attributeslength = attributes.length();
105 
106  for ( uint i = 0; i < attributeslength; ++i )
107  {
108  const QDomAttr attr = attributes.item( i ).toAttr();
109 
110  if ( attr.isNull() )
111  continue;
112 
113  const QString name = attr.name();
114 
115  if ( name == "name" || name.isEmpty() )
116  continue;
117 
118  (*propIt)[ name ] = attr.value();
119  }
120 
121  }
122 
123  return properties;
124 }
125 
126 static void storeActionProperties( QDomDocument &doc,
127  const ActionPropertiesMap &properties )
128 {
129  QDomElement actionPropElement = doc.documentElement().namedItem( "ActionProperties" ).toElement();
130 
131  if ( actionPropElement.isNull() )
132  {
133  actionPropElement = doc.createElement( "ActionProperties" );
134  doc.documentElement().appendChild( actionPropElement );
135  }
136 
137 //Remove only those ActionProperties entries from the document, that are present
138 //in the properties argument. In real life this means that local ActionProperties
139 //takes precedence over global ones, if they exists (think local override of shortcuts).
140  QDomNode actionNode = actionPropElement.firstChild();
141  while (!actionNode.isNull())
142  {
143  if (properties.contains(actionNode.toElement().attribute("name")))
144  {
145  QDomNode nextNode = actionNode.nextSibling();
146  actionPropElement.removeChild( actionNode );
147  actionNode = nextNode;
148  } else
149  actionNode = actionNode.nextSibling();
150  }
151 
152  ActionPropertiesMap::ConstIterator it = properties.begin();
153  const ActionPropertiesMap::ConstIterator end = properties.end();
154  for (; it != end; ++it )
155  {
156  QDomElement action = doc.createElement( "Action" );
157  action.setAttribute( "name", it.key() );
158  actionPropElement.appendChild( action );
159 
160  const QMap<QString, QString> attributes = (*it);
161  QMap<QString, QString>::ConstIterator attrIt = attributes.begin();
162  const QMap<QString, QString>::ConstIterator attrEnd = attributes.end();
163  for (; attrIt != attrEnd; ++attrIt )
164  action.setAttribute( attrIt.key(), attrIt.value() );
165  }
166 }
167 
168 QString KXmlGuiVersionHandler::findVersionNumber( const QString &xml )
169 {
170  enum { ST_START, ST_AFTER_OPEN, ST_AFTER_GUI,
171  ST_EXPECT_VERSION, ST_VERSION_NUM} state = ST_START;
172  const int length = xml.length();
173  for (int pos = 0; pos < length; pos++) {
174  switch (state) {
175  case ST_START:
176  if (xml[pos] == '<')
177  state = ST_AFTER_OPEN;
178  break;
179  case ST_AFTER_OPEN:
180  {
181  //Jump to gui..
182  const int guipos = xml.indexOf("gui", pos, Qt::CaseInsensitive);
183  if (guipos == -1)
184  return QString(); //Reject
185 
186  pos = guipos + 2; //Position at i, so we're moved ahead to the next character by the ++;
187  state = ST_AFTER_GUI;
188  break;
189  }
190  case ST_AFTER_GUI:
191  state = ST_EXPECT_VERSION;
192  break;
193  case ST_EXPECT_VERSION:
194  {
195  const int verpos = xml.indexOf("version", pos, Qt::CaseInsensitive);
196  if (verpos == -1)
197  return QString(); //Reject
198  pos = verpos + 7; // strlen("version") is 7
199  while (xml.at(pos).isSpace())
200  ++pos;
201  if (xml.at(pos++) != '=')
202  return QString(); //Reject
203  while (xml.at(pos).isSpace())
204  ++pos;
205 
206  state = ST_VERSION_NUM;
207  break;
208  }
209  case ST_VERSION_NUM:
210  {
211  int endpos;
212  for (endpos = pos; endpos < length; endpos++) {
213  const ushort ch = xml[endpos].unicode();
214  if (ch >= '0' && ch <= '9')
215  continue; //Number..
216  if (ch == '"') //End of parameter
217  break;
218  else { //This shouldn't be here..
219  endpos = length;
220  }
221  }
222 
223  if (endpos != pos && endpos < length ) {
224  const QString matchCandidate = xml.mid(pos, endpos - pos); //Don't include " ".
225  return matchCandidate;
226  }
227 
228  state = ST_EXPECT_VERSION; //Try to match a well-formed version..
229  break;
230  } //case..
231  } //switch
232  } //for
233 
234  return QString();
235 }
236 
237 
238 KXmlGuiVersionHandler::KXmlGuiVersionHandler(const QStringList& files)
239 {
240  Q_ASSERT(!files.isEmpty());
241 
242  if (files.count() == 1) {
243  // No need to parse version numbers if there's only one file anyway
244  m_file = files.first();
245  m_doc = KXMLGUIFactory::readConfigFile(m_file);
246  return;
247  }
248 
249 
250  QList<DocStruct> allDocuments;
251 
252  foreach (const QString &file, files) {
253  DocStruct d;
254  d.file = file;
255  d.data = KXMLGUIFactory::readConfigFile( file );
256  allDocuments.append( d );
257  }
258 
259  QList<DocStruct>::iterator best = allDocuments.end();
260  uint bestVersion = 0;
261 
262  QList<DocStruct>::iterator docIt = allDocuments.begin();
263  const QList<DocStruct>::iterator docEnd = allDocuments.end();
264  for (; docIt != docEnd; ++docIt ) {
265  const QString versionStr = findVersionNumber( (*docIt).data );
266  if ( versionStr.isEmpty() ) {
267  kDebug(260) << "found no version in" << (*docIt).file;
268  continue;
269  }
270 
271  bool ok = false;
272  uint version = versionStr.toUInt( &ok );
273  if ( !ok )
274  continue;
275  //kDebug(260) << "found version" << version << "for" << (*docIt).file;
276 
277  if ( version > bestVersion ) {
278  best = docIt;
279  //kDebug(260) << "best version is now " << version;
280  bestVersion = version;
281  }
282  }
283 
284  if ( best != docEnd ) {
285  if ( best != allDocuments.begin() ) {
286  QList<DocStruct>::iterator local = allDocuments.begin();
287 
288  if ( (*local).file.startsWith(KGlobal::dirs()->localkdedir()) ||
289  (*local).file.startsWith(KGlobal::dirs()->saveLocation("appdata")) ) {
290  // load the local document and extract the action properties
291  QDomDocument localDocument;
292  localDocument.setContent( (*local).data );
293 
294  const ActionPropertiesMap properties = extractActionProperties(localDocument);
295  const QList<QDomElement> toolbars = extractToolBars(localDocument);
296 
297  // in case the document has a ActionProperties section
298  // we must not delete it but copy over the global doc
299  // to the local and insert the ActionProperties section
300 
301  // TODO: kedittoolbar should mark toolbars as modified so that
302  // we don't keep old toolbars just because the user defined a shortcut
303 
304  if ( !properties.isEmpty() || !toolbars.isEmpty() ) {
305  // now load the global one with the higher version number
306  // into memory
307  QDomDocument document;
308  document.setContent( (*best).data );
309  // and store the properties in there
310  storeActionProperties( document, properties );
311  if (!toolbars.isEmpty()) {
312  // remove application toolbars
313  removeAllToolBars(document);
314  // add user toolbars
315  insertToolBars(document, toolbars);
316  }
317 
318  (*local).data = document.toString();
319  // make sure we pick up the new local doc, when we return later
320  best = local;
321 
322  // write out the new version of the local document
323  QFile f( (*local).file );
324  if ( f.open( QIODevice::WriteOnly ) )
325  {
326  const QByteArray utf8data = (*local).data.toUtf8();
327  f.write( utf8data.constData(), utf8data.length() );
328  f.close();
329  }
330  } else {
331  // Move away the outdated local file, to speed things up next time
332  const QString f = (*local).file;
333  const QString backup = f + QLatin1String( ".backup" );
334  QFile::rename( f, backup );
335  }
336  }
337  }
338  m_doc = (*best).data;
339  m_file = (*best).file;
340  } else {
341  //kDebug(260) << "returning first one...";
342  m_doc = allDocuments.first().data;
343  m_file = allDocuments.first().file;
344  }
345 }
KStandardDirs::saveLocation
QString saveLocation(const char *type, const QString &suffix=QString(), bool create=true) const
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QMap::contains
bool contains(const Key &key) const
kdebug.h
QDomAttr::name
QString name() const
QDomNode::appendChild
QDomNode appendChild(const QDomNode &newChild)
QByteArray
QDomElement::attribute
QString attribute(const QString &name, const QString &defValue) const
QDomDocument::toString
QString toString(int indent) const
QDomNode::insertAfter
QDomNode insertAfter(const QDomNode &newChild, const QDomNode &refChild)
QMap
QFile::rename
bool rename(const QString &newName)
KGlobal::dirs
KStandardDirs * dirs()
KStandardAction::name
const char * name(StandardAction id)
This will return the internal name of a given standard action.
Definition: kstandardaction.cpp:223
kxmlguifactory.h
QDomDocument::documentElement
QDomElement documentElement() const
QDomNode
QByteArray::length
int length() const
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
QFile
QDomNode::nextSibling
QDomNode nextSibling() const
QDomNode::toElement
QDomElement toElement() const
QDomNamedNodeMap
kglobal.h
insertToolBars
static void insertToolBars(QDomDocument &doc, const QList< QDomElement > &toolBars)
Definition: kxmlguiversionhandler.cpp:58
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
QChar::isSpace
bool isSpace() const
QDomAttr
removeAllToolBars
static void removeAllToolBars(QDomDocument &doc)
Definition: kxmlguiversionhandler.cpp:49
QDomElement::setAttribute
void setAttribute(const QString &name, const QString &value)
QList::isEmpty
bool isEmpty() const
QString::isEmpty
bool isEmpty() const
KXMLGUIFactory::readConfigFile
static QString readConfigFile(const QString &filename, const KComponentData &componentData=KComponentData())
Definition: kxmlguifactory.cpp:117
QByteArray::constData
const char * constData() const
QList::first
T & first()
QString
QList< QDomElement >
QMap::end
iterator end()
QList::iterator
QMap::begin
iterator begin()
QStringList
ActionPropertiesMap
QMap< QString, QMap< QString, QString > > ActionPropertiesMap
Definition: kxmlguiversionhandler.cpp:73
QList::end
iterator end()
QDomNode::removeChild
QDomNode removeChild(const QDomNode &oldChild)
QDomNode::namedItem
QDomNode namedItem(const QString &name) const
QDomDocument
QDomAttr::value
QString value() const
KStandardGuiItem::ok
KGuiItem ok()
Returns the 'Ok' gui item.
Definition: kstandardguiitem.cpp:107
QDomNode::isNull
bool isNull() const
QMap::key
const Key key(const T &value) const
QString::unicode
const QChar * unicode() const
QDomNode::firstChild
QDomNode firstChild() const
QString::mid
QString mid(int position, int n) const
extractToolBars
static QList< QDomElement > extractToolBars(const QDomDocument &doc)
Definition: kxmlguiversionhandler.cpp:37
QLatin1String
QDomNamedNodeMap::length
uint length() const
kstandarddirs.h
version
unsigned int version()
KStandardGuiItem::properties
KGuiItem properties()
Returns the 'Properties' gui item.
Definition: kstandardguiitem.cpp:299
QString::at
const QChar at(int position) const
storeActionProperties
static void storeActionProperties(QDomDocument &doc, const ActionPropertiesMap &properties)
Definition: kxmlguiversionhandler.cpp:126
QDomNode::firstChildElement
QDomElement firstChildElement(const QString &tagName) const
QDomNode::toAttr
QDomAttr toAttr() const
QString::length
int length() const
QByteArray::data
char * data()
KStandardDirs::localkdedir
QString localkdedir() const
QMap::insert
iterator insert(const Key &key, const T &value)
QMap::isEmpty
bool isEmpty() const
QDomElement::tagName
QString tagName() const
QDomDocument::createElement
QDomElement createElement(const QString &tagName)
QMap::ConstIterator
typedef ConstIterator
QDomNamedNodeMap::item
QDomNode item(int index) const
QDomElement
QString::compare
int compare(const QString &other) const
KStandardShortcut::end
const KShortcut & end()
Goto end of the document.
Definition: kstandardshortcut.cpp:348
QMap::find
iterator find(const Key &key)
QList::begin
iterator begin()
extractActionProperties
static ActionPropertiesMap extractActionProperties(const QDomDocument &doc)
Definition: kxmlguiversionhandler.cpp:75
QDomDocument::setContent
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
QMap::value
const T value(const Key &key) const
QString::toUInt
uint toUInt(bool *ok, int base) const
QDomElement::attributes
QDomNamedNodeMap attributes() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:24:00 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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

Search



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