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

KDEUI

  • 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
31struct DocStruct
32{
33 QString file;
34 QString data;
35};
36
37static 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
49static 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
58static 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
73typedef QMap<QString, QMap<QString, QString> > ActionPropertiesMap;
74
75static 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
126static 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
168QString 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
238KXmlGuiVersionHandler::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::localkdedir
QString localkdedir() const
KStandardDirs::saveLocation
QString saveLocation(const char *type, const QString &suffix=QString(), bool create=true) const
KXMLGUIFactory::readConfigFile
static QString readConfigFile(const QString &filename, const KComponentData &componentData=KComponentData())
Definition: kxmlguifactory.cpp:117
QList
QMap
kDebug
#define kDebug
kdebug.h
kglobal.h
kstandarddirs.h
kxmlguifactory.h
extractActionProperties
static ActionPropertiesMap extractActionProperties(const QDomDocument &doc)
Definition: kxmlguiversionhandler.cpp:75
insertToolBars
static void insertToolBars(QDomDocument &doc, const QList< QDomElement > &toolBars)
Definition: kxmlguiversionhandler.cpp:58
removeAllToolBars
static void removeAllToolBars(QDomDocument &doc)
Definition: kxmlguiversionhandler.cpp:49
ActionPropertiesMap
QMap< QString, QMap< QString, QString > > ActionPropertiesMap
Definition: kxmlguiversionhandler.cpp:73
extractToolBars
static QList< QDomElement > extractToolBars(const QDomDocument &doc)
Definition: kxmlguiversionhandler.cpp:37
storeActionProperties
static void storeActionProperties(QDomDocument &doc, const ActionPropertiesMap &properties)
Definition: kxmlguiversionhandler.cpp:126
KGlobal::dirs
KStandardDirs * dirs()
KStandardGuiItem::properties
KGuiItem properties()
Returns the 'Properties' gui item.
Definition: kstandardguiitem.cpp:299
KStandardGuiItem::ok
KGuiItem ok()
Returns the 'Ok' gui item.
Definition: kstandardguiitem.cpp:107
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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.14.38 API Reference

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