author | zautrix <zautrix> | 2004-06-26 19:01:18 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2004-06-26 19:01:18 (UTC) |
commit | b9aad1f15dc600e4dbe4c62d3fcced6363188ba3 (patch) (unidiff) | |
tree | 2c3d4004fb21c72cba65793859f9bcd8ffd3a49c /microkde/kdeui/kxmlguiclient.cpp | |
download | kdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.zip kdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.tar.gz kdepimpi-b9aad1f15dc600e4dbe4c62d3fcced6363188ba3.tar.bz2 |
Initial revision
Diffstat (limited to 'microkde/kdeui/kxmlguiclient.cpp') (more/less context) (show whitespace changes)
-rw-r--r-- | microkde/kdeui/kxmlguiclient.cpp | 958 |
1 files changed, 958 insertions, 0 deletions
diff --git a/microkde/kdeui/kxmlguiclient.cpp b/microkde/kdeui/kxmlguiclient.cpp new file mode 100644 index 0000000..073e30b --- a/dev/null +++ b/microkde/kdeui/kxmlguiclient.cpp | |||
@@ -0,0 +1,958 @@ | |||
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 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License version 2 as published by the Free Software Foundation. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this library; see the file COPYING.LIB. If not, write to | ||
16 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
17 | Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include "kxmlguiclient.h" | ||
21 | |||
22 | /*US | ||
23 | #include "kxmlguifactory.h" | ||
24 | #include "kxmlguibuilder.h" | ||
25 | */ | ||
26 | |||
27 | /*US | ||
28 | #include <qdir.h> | ||
29 | #include <qfile.h> | ||
30 | #include <qdom.h> | ||
31 | #include <qtextstream.h> | ||
32 | #include <qregexp.h> | ||
33 | */ | ||
34 | |||
35 | //US #include <kinstance.h> | ||
36 | #include <kstandarddirs.h> | ||
37 | #include <kdebug.h> | ||
38 | #include <kaction.h> | ||
39 | #include <kapplication.h> | ||
40 | |||
41 | #include <assert.h> | ||
42 | |||
43 | class KXMLGUIClientPrivate | ||
44 | { | ||
45 | public: | ||
46 | KXMLGUIClientPrivate() | ||
47 | { | ||
48 | //US m_instance = KGlobal::instance(); | ||
49 | //US m_factory = 0L; | ||
50 | m_parent = 0L; | ||
51 | //US m_builder = 0L; | ||
52 | m_actionCollection = 0; | ||
53 | } | ||
54 | ~KXMLGUIClientPrivate() | ||
55 | { | ||
56 | } | ||
57 | |||
58 | //US KInstance *m_instance; | ||
59 | |||
60 | //US QDomDocument m_doc; | ||
61 | KActionCollection *m_actionCollection; | ||
62 | //US QDomDocument m_buildDocument; | ||
63 | //US KXMLGUIFactory *m_factory; | ||
64 | KXMLGUIClient *m_parent; | ||
65 | //QPtrList<KXMLGUIClient> m_supers; | ||
66 | QPtrList<KXMLGUIClient> m_children; | ||
67 | //US KXMLGUIBuilder *m_builder; | ||
68 | //US QString m_xmlFile; | ||
69 | //US QString m_localXMLFile; | ||
70 | }; | ||
71 | |||
72 | KXMLGUIClient::KXMLGUIClient() | ||
73 | { | ||
74 | d = new KXMLGUIClientPrivate; | ||
75 | } | ||
76 | |||
77 | KXMLGUIClient::KXMLGUIClient( KXMLGUIClient *parent ) | ||
78 | { | ||
79 | d = new KXMLGUIClientPrivate; | ||
80 | parent->insertChildClient( this ); | ||
81 | } | ||
82 | |||
83 | KXMLGUIClient::~KXMLGUIClient() | ||
84 | { | ||
85 | if ( d->m_parent ) | ||
86 | d->m_parent->removeChildClient( this ); | ||
87 | |||
88 | QPtrListIterator<KXMLGUIClient> it( d->m_children ); | ||
89 | for ( ; it.current(); ++it ) { | ||
90 | assert( it.current()->d->m_parent == this ); | ||
91 | it.current()->d->m_parent = 0; | ||
92 | } | ||
93 | |||
94 | delete d->m_actionCollection; | ||
95 | delete d; | ||
96 | } | ||
97 | |||
98 | KAction *KXMLGUIClient::action( const char *name ) const | ||
99 | { | ||
100 | KAction* act = actionCollection()->action( name ); | ||
101 | if ( !act ) { | ||
102 | QPtrListIterator<KXMLGUIClient> childIt( d->m_children ); | ||
103 | for (; childIt.current(); ++childIt ) { | ||
104 | act = childIt.current()->actionCollection()->action( name ); | ||
105 | if ( act ) | ||
106 | break; | ||
107 | } | ||
108 | } | ||
109 | return act; | ||
110 | } | ||
111 | |||
112 | KActionCollection *KXMLGUIClient::actionCollection() const | ||
113 | { | ||
114 | if ( !d->m_actionCollection ) | ||
115 | d->m_actionCollection = new KActionCollection( 0, 0, | ||
116 | "KXMLGUILClient-KActionCollection" ); | ||
117 | return d->m_actionCollection; | ||
118 | } | ||
119 | |||
120 | /*US | ||
121 | KAction *KXMLGUIClient::action( const QDomElement &element ) const | ||
122 | { | ||
123 | static const QString &attrName = KGlobal::staticQString( "name" ); | ||
124 | return actionCollection()->action( element.attribute( attrName ).latin1() ); | ||
125 | } | ||
126 | |||
127 | KInstance *KXMLGUIClient::instance() const | ||
128 | { | ||
129 | return d->m_instance; | ||
130 | } | ||
131 | |||
132 | QDomDocument KXMLGUIClient::domDocument() const | ||
133 | { | ||
134 | return d->m_doc; | ||
135 | } | ||
136 | |||
137 | QString KXMLGUIClient::xmlFile() const | ||
138 | { | ||
139 | return d->m_xmlFile; | ||
140 | } | ||
141 | |||
142 | QString KXMLGUIClient::localXMLFile() const | ||
143 | { | ||
144 | if ( !d->m_localXMLFile.isEmpty() ) | ||
145 | return d->m_localXMLFile; | ||
146 | |||
147 | if ( d->m_xmlFile[0] == '/' ) | ||
148 | return QString::null; // can't save anything here | ||
149 | |||
150 | return locateLocal( "data", QString::fromLatin1( instance()->instanceName() + '/' ) + d->m_xmlFile ); | ||
151 | } | ||
152 | |||
153 | |||
154 | void KXMLGUIClient::reloadXML() | ||
155 | { | ||
156 | QString file( xmlFile() ); | ||
157 | if ( !file.isEmpty() ) | ||
158 | setXMLFile( file ); | ||
159 | } | ||
160 | |||
161 | void KXMLGUIClient::setInstance( KInstance *instance ) | ||
162 | { | ||
163 | d->m_instance = instance; | ||
164 | actionCollection()->setInstance( instance ); | ||
165 | if ( d->m_builder ) | ||
166 | d->m_builder->setBuilderClient( this ); | ||
167 | } | ||
168 | |||
169 | void KXMLGUIClient::setXMLFile( const QString& _file, bool merge, bool setXMLDoc ) | ||
170 | { | ||
171 | // store our xml file name | ||
172 | if ( !_file.isNull() ) { | ||
173 | d->m_xmlFile = _file; | ||
174 | actionCollection()->setXMLFile( _file ); | ||
175 | } | ||
176 | |||
177 | if ( !setXMLDoc ) | ||
178 | return; | ||
179 | |||
180 | QString file = _file; | ||
181 | if ( file[0] != '/' ) | ||
182 | { | ||
183 | QString doc; | ||
184 | |||
185 | QString filter = QString::fromLatin1( instance()->instanceName() + '/' ) + _file; | ||
186 | |||
187 | QStringList allFiles = instance()->dirs()->findAllResources( "data", filter ) + instance()->dirs()->findAllResources( "data", _file ); | ||
188 | |||
189 | file = findMostRecentXMLFile( allFiles, doc ); | ||
190 | |||
191 | if ( file.isEmpty() ) | ||
192 | { | ||
193 | // this might or might not be an error. for the time being, | ||
194 | // let's treat this as if it isn't a problem and the user just | ||
195 | // wants the global standards file | ||
196 | setXML( QString::null, true ); | ||
197 | return; | ||
198 | } | ||
199 | else if ( !doc.isEmpty() ) | ||
200 | { | ||
201 | setXML( doc, merge ); | ||
202 | return; | ||
203 | } | ||
204 | } | ||
205 | |||
206 | QString xml = KXMLGUIFactory::readConfigFile( file ); | ||
207 | setXML( xml, merge ); | ||
208 | } | ||
209 | |||
210 | void KXMLGUIClient::setLocalXMLFile( const QString &file ) | ||
211 | { | ||
212 | d->m_localXMLFile = file; | ||
213 | } | ||
214 | |||
215 | void KXMLGUIClient::setXML( const QString &document, bool merge ) | ||
216 | { | ||
217 | QDomDocument doc; | ||
218 | doc.setContent( document ); | ||
219 | setDOMDocument( doc, merge ); | ||
220 | } | ||
221 | |||
222 | void KXMLGUIClient::setDOMDocument( const QDomDocument &document, bool merge ) | ||
223 | { | ||
224 | if ( merge ) | ||
225 | { | ||
226 | QDomElement base = d->m_doc.documentElement(); | ||
227 | |||
228 | QDomElement e = document.documentElement(); | ||
229 | KXMLGUIFactory::removeDOMComments( e ); | ||
230 | |||
231 | // merge our original (global) xml with our new one | ||
232 | mergeXML(base, e, actionCollection()); | ||
233 | |||
234 | // reassign our pointer as mergeXML might have done something | ||
235 | // strange to it | ||
236 | base = d->m_doc.documentElement(); | ||
237 | |||
238 | // we want some sort of failsafe.. just in case | ||
239 | if ( base.isNull() ) | ||
240 | d->m_doc = document; | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | d->m_doc = document; | ||
245 | KXMLGUIFactory::removeDOMComments( d->m_doc ); | ||
246 | } | ||
247 | |||
248 | setXMLGUIBuildDocument( QDomDocument() ); | ||
249 | } | ||
250 | */ | ||
251 | |||
252 | /*US | ||
253 | bool KXMLGUIClient::mergeXML( QDomElement &base, const QDomElement &additive, KActionCollection *actionCollection ) | ||
254 | { | ||
255 | static const QString &tagAction = KGlobal::staticQString( "Action" ); | ||
256 | static const QString &tagMerge = KGlobal::staticQString( "Merge" ); | ||
257 | static const QString &tagSeparator = KGlobal::staticQString( "Separator" ); | ||
258 | static const QString &attrName = KGlobal::staticQString( "name" ); | ||
259 | static const QString &attrAppend = KGlobal::staticQString( "append" ); | ||
260 | static const QString &attrWeakSeparator = KGlobal::staticQString( "weakSeparator" ); | ||
261 | static const QString &tagMergeLocal = KGlobal::staticQString( "MergeLocal" ); | ||
262 | static const QString &tagText = KGlobal::staticQString( "text" ); | ||
263 | static const QString &attrAlreadyVisited = KGlobal::staticQString( "alreadyVisited" ); | ||
264 | static const QString &attrNoMerge = KGlobal::staticQString( "noMerge" ); | ||
265 | static const QString &attrOne = KGlobal::staticQString( "1" ); | ||
266 | |||
267 | // there is a possibility that we don't want to merge in the | ||
268 | // additive.. rather, we might want to *replace* the base with the | ||
269 | // additive. this can be for any container.. either at a file wide | ||
270 | // level or a simple container level. we look for the 'noMerge' | ||
271 | // tag, in any event and just replace the old with the new | ||
272 | if ( additive.attribute(attrNoMerge) == attrOne ) // ### use toInt() instead? (Simon) | ||
273 | { | ||
274 | base.parentNode().replaceChild(additive, base); | ||
275 | return true; | ||
276 | } | ||
277 | |||
278 | QString tag; | ||
279 | |||
280 | QDomElement e = base.firstChild().toElement(); | ||
281 | // iterate over all elements in the container (of the global DOM tree) | ||
282 | while ( !e.isNull() ) | ||
283 | { | ||
284 | tag = e.tagName(); | ||
285 | |||
286 | // if there's an action tag in the global tree and the action is | ||
287 | // not implemented, then we remove the element | ||
288 | if ( tag == tagAction ) | ||
289 | { | ||
290 | QCString name = e.attribute( attrName ).utf8(); // WABA | ||
291 | if ( !actionCollection->action( name ) || | ||
292 | (kapp && !kapp->authorizeKAction(name))) | ||
293 | { | ||
294 | // remove this child as we aren't using it | ||
295 | QDomElement oldChild = e; | ||
296 | e = e.nextSibling().toElement(); | ||
297 | base.removeChild( oldChild ); | ||
298 | continue; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | // if there's a separator defined in the global tree, then add an | ||
303 | // attribute, specifying that this is a "weak" separator | ||
304 | else if ( tag == tagSeparator ) | ||
305 | { | ||
306 | e.setAttribute( attrWeakSeparator, (uint)1 ); | ||
307 | |||
308 | // okay, hack time. if the last item was a weak separator OR | ||
309 | // this is the first item in a container, then we nuke the | ||
310 | // current one | ||
311 | QDomElement prev = e.previousSibling().toElement(); | ||
312 | if ( prev.isNull() || | ||
313 | ( prev.tagName() == tagSeparator && !prev.attribute( attrWeakSeparator ).isNull() ) || | ||
314 | ( prev.tagName() == tagText ) ) | ||
315 | { | ||
316 | // the previous element was a weak separator or didn't exist | ||
317 | QDomElement oldChild = e; | ||
318 | e = e.nextSibling().toElement(); | ||
319 | base.removeChild( oldChild ); | ||
320 | continue; | ||
321 | } | ||
322 | } | ||
323 | |||
324 | // the MergeLocal tag lets us specify where non-standard elements | ||
325 | // of the local tree shall be merged in. After inserting the | ||
326 | // elements we delete this element | ||
327 | else if ( tag == tagMergeLocal ) | ||
328 | { | ||
329 | QDomElement currElement = e; | ||
330 | |||
331 | // switch our iterator "e" to the next sibling, so that we don't | ||
332 | // process the local tree's inserted items! | ||
333 | e = e.nextSibling().toElement(); | ||
334 | |||
335 | QDomElement it = additive.firstChild().toElement(); | ||
336 | while ( !it.isNull() ) | ||
337 | { | ||
338 | QDomElement newChild = it; | ||
339 | |||
340 | it = it.nextSibling().toElement(); | ||
341 | |||
342 | if ( newChild.tagName() == tagText ) | ||
343 | continue; | ||
344 | |||
345 | if ( newChild.attribute( attrAlreadyVisited ) == attrOne ) | ||
346 | continue; | ||
347 | |||
348 | QString itAppend( newChild.attribute( attrAppend ) ); | ||
349 | QString elemName( currElement.attribute( attrName ) ); | ||
350 | |||
351 | if ( ( itAppend.isNull() && elemName.isEmpty() ) || | ||
352 | ( itAppend == elemName ) ) | ||
353 | { | ||
354 | // first, see if this new element matches a standard one in | ||
355 | // the global file. if it does, then we skip it as it will | ||
356 | // be merged in, later | ||
357 | QDomElement matchingElement = findMatchingElement( newChild, base ); | ||
358 | if ( matchingElement.isNull() || newChild.tagName() == tagSeparator ) | ||
359 | base.insertBefore( newChild, currElement ); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | base.removeChild( currElement ); | ||
364 | continue; | ||
365 | } | ||
366 | |||
367 | // in this last case we check for a separator tag and, if not, we | ||
368 | // can be sure that its a container --> proceed with child nodes | ||
369 | // recursively and delete the just proceeded container item in | ||
370 | // case its empty (if the recursive call returns true) | ||
371 | else if ( tag != tagMerge ) | ||
372 | { | ||
373 | // handle the text tag | ||
374 | if ( tag == tagText ) | ||
375 | { | ||
376 | e = e.nextSibling().toElement(); | ||
377 | continue; | ||
378 | } | ||
379 | |||
380 | QDomElement matchingElement = findMatchingElement( e, additive ); | ||
381 | |||
382 | QDomElement currElement = e; | ||
383 | e = e.nextSibling().toElement(); | ||
384 | |||
385 | if ( !matchingElement.isNull() ) | ||
386 | { | ||
387 | matchingElement.setAttribute( attrAlreadyVisited, (uint)1 ); | ||
388 | |||
389 | if ( mergeXML( currElement, matchingElement, actionCollection ) ) | ||
390 | { | ||
391 | base.removeChild( currElement ); | ||
392 | continue; | ||
393 | } | ||
394 | |||
395 | // Merge attributes | ||
396 | QDomNamedNodeMap attribs = matchingElement.attributes(); | ||
397 | for(uint i = 0; i < attribs.count(); i++) | ||
398 | { | ||
399 | QDomNode node = attribs.item(i); | ||
400 | currElement.setAttribute(node.nodeName(), node.nodeValue()); | ||
401 | } | ||
402 | |||
403 | continue; | ||
404 | } | ||
405 | else | ||
406 | { | ||
407 | // this is an important case here! We reach this point if the | ||
408 | // "local" tree does not contain a container definition for | ||
409 | // this container. However we have to call mergeXML recursively | ||
410 | // and make it check if there are actions implemented for this | ||
411 | // container. *If* none, then we can remove this container now | ||
412 | if ( mergeXML( currElement, QDomElement(), actionCollection ) ) | ||
413 | base.removeChild( currElement ); | ||
414 | continue; | ||
415 | } | ||
416 | } | ||
417 | |||
418 | //I think this can be removed ;-) | ||
419 | e = e.nextSibling().toElement(); | ||
420 | } | ||
421 | |||
422 | //here we append all child elements which were not inserted | ||
423 | //previously via the LocalMerge tag | ||
424 | e = additive.firstChild().toElement(); | ||
425 | while ( !e.isNull() ) | ||
426 | { | ||
427 | QDomElement matchingElement = findMatchingElement( e, base ); | ||
428 | |||
429 | if ( matchingElement.isNull() ) | ||
430 | { | ||
431 | QDomElement newChild = e; | ||
432 | e = e.nextSibling().toElement(); | ||
433 | base.appendChild( newChild ); | ||
434 | } | ||
435 | else | ||
436 | e = e.nextSibling().toElement(); | ||
437 | } | ||
438 | |||
439 | // do one quick check to make sure that the last element was not | ||
440 | // a weak separator | ||
441 | QDomElement last = base.lastChild().toElement(); | ||
442 | if ( (last.tagName() == tagSeparator) && (!last.attribute( attrWeakSeparator ).isNull()) ) | ||
443 | { | ||
444 | base.removeChild( base.lastChild() ); | ||
445 | } | ||
446 | |||
447 | // now we check if we are empty (in which case we return "true", to | ||
448 | // indicate the caller that it can delete "us" (the base element | ||
449 | // argument of "this" call) | ||
450 | bool deleteMe = true; | ||
451 | e = base.firstChild().toElement(); | ||
452 | for ( ; !e.isNull(); e = e.nextSibling().toElement() ) | ||
453 | { | ||
454 | tag = e.tagName(); | ||
455 | |||
456 | if ( tag == tagAction ) | ||
457 | { | ||
458 | // if base contains an implemented action, then we must not get | ||
459 | // deleted (note that the actionCollection contains both, | ||
460 | // "global" and "local" actions | ||
461 | if ( actionCollection->action( e.attribute( attrName ).utf8() ) ) | ||
462 | { | ||
463 | deleteMe = false; | ||
464 | break; | ||
465 | } | ||
466 | } | ||
467 | else if ( tag == tagSeparator ) | ||
468 | { | ||
469 | // if we have a separator which has *not* the weak attribute | ||
470 | // set, then it must be owned by the "local" tree in which case | ||
471 | // we must not get deleted either | ||
472 | QString weakAttr = e.attribute( attrWeakSeparator ); | ||
473 | if ( weakAttr.isEmpty() || weakAttr.toInt() != 1 ) | ||
474 | { | ||
475 | deleteMe = false; | ||
476 | break; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | // in case of a merge tag we have unlimited lives, too ;-) | ||
481 | else if ( tag == tagMerge ) | ||
482 | { | ||
483 | // deleteMe = false; | ||
484 | // break; | ||
485 | continue; | ||
486 | } | ||
487 | |||
488 | // a text tag is NOT enough to spare this container | ||
489 | else if ( tag == tagText ) | ||
490 | { | ||
491 | continue; | ||
492 | } | ||
493 | |||
494 | // what's left are non-empty containers! *don't* delete us in this | ||
495 | // case (at this position we can be *sure* that the container is | ||
496 | // *not* empty, as the recursive call for it was in the first loop | ||
497 | // which deleted the element in case the call returned "true" | ||
498 | else | ||
499 | { | ||
500 | deleteMe = false; | ||
501 | break; | ||
502 | } | ||
503 | } | ||
504 | |||
505 | return deleteMe; | ||
506 | } | ||
507 | |||
508 | QDomElement KXMLGUIClient::findMatchingElement( const QDomElement &base, const QDomElement &additive ) | ||
509 | { | ||
510 | static const QString &tagAction = KGlobal::staticQString( "Action" ); | ||
511 | static const QString &tagMergeLocal = KGlobal::staticQString( "MergeLocal" ); | ||
512 | static const QString &attrName = KGlobal::staticQString( "name" ); | ||
513 | |||
514 | QDomElement e = additive.firstChild().toElement(); | ||
515 | for ( ; !e.isNull(); e = e.nextSibling().toElement() ) | ||
516 | { | ||
517 | // skip all action and merge tags as we will never use them | ||
518 | if ( ( e.tagName() == tagAction ) || ( e.tagName() == tagMergeLocal ) ) | ||
519 | { | ||
520 | continue; | ||
521 | } | ||
522 | |||
523 | // now see if our tags are equivalent | ||
524 | if ( ( e.tagName() == base.tagName() ) && | ||
525 | ( e.attribute( attrName ) == base.attribute( attrName ) ) ) | ||
526 | { | ||
527 | return e; | ||
528 | } | ||
529 | } | ||
530 | |||
531 | // nope, return a (now) null element | ||
532 | return e; | ||
533 | } | ||
534 | |||
535 | void KXMLGUIClient::conserveMemory() | ||
536 | { | ||
537 | d->m_doc = QDomDocument(); | ||
538 | d->m_buildDocument = QDomDocument(); | ||
539 | } | ||
540 | |||
541 | void KXMLGUIClient::setXMLGUIBuildDocument( const QDomDocument &doc ) | ||
542 | { | ||
543 | d->m_buildDocument = doc; | ||
544 | } | ||
545 | |||
546 | QDomDocument KXMLGUIClient::xmlguiBuildDocument() const | ||
547 | { | ||
548 | return d->m_buildDocument; | ||
549 | } | ||
550 | */ | ||
551 | |||
552 | /*US | ||
553 | void KXMLGUIClient::setFactory( KXMLGUIFactory *factory ) | ||
554 | { | ||
555 | d->m_factory = factory; | ||
556 | } | ||
557 | |||
558 | KXMLGUIFactory *KXMLGUIClient::factory() const | ||
559 | { | ||
560 | return d->m_factory; | ||
561 | } | ||
562 | */ | ||
563 | KXMLGUIClient *KXMLGUIClient::parentClient() const | ||
564 | { | ||
565 | return d->m_parent; | ||
566 | } | ||
567 | |||
568 | void KXMLGUIClient::insertChildClient( KXMLGUIClient *child ) | ||
569 | { | ||
570 | if ( child->d->m_parent ) | ||
571 | child->d->m_parent->removeChildClient( child ); | ||
572 | d->m_children.append( child ); | ||
573 | child->d->m_parent = this; | ||
574 | } | ||
575 | |||
576 | void KXMLGUIClient::removeChildClient( KXMLGUIClient *child ) | ||
577 | { | ||
578 | assert( d->m_children.containsRef( child ) ); | ||
579 | d->m_children.removeRef( child ); | ||
580 | child->d->m_parent = 0; | ||
581 | } | ||
582 | |||
583 | /*bool KXMLGUIClient::addSuperClient( KXMLGUIClient *super ) | ||
584 | { | ||
585 | if ( d->m_supers.contains( super ) ) | ||
586 | return false; | ||
587 | d->m_supers.append( super ); | ||
588 | return true; | ||
589 | }*/ | ||
590 | |||
591 | const QPtrList<KXMLGUIClient> *KXMLGUIClient::childClients() | ||
592 | { | ||
593 | return &d->m_children; | ||
594 | } | ||
595 | /*US | ||
596 | void KXMLGUIClient::setClientBuilder( KXMLGUIBuilder *builder ) | ||
597 | { | ||
598 | d->m_builder = builder; | ||
599 | if ( builder ) | ||
600 | builder->setBuilderInstance( instance() ); | ||
601 | } | ||
602 | |||
603 | KXMLGUIBuilder *KXMLGUIClient::clientBuilder() const | ||
604 | { | ||
605 | return d->m_builder; | ||
606 | } | ||
607 | */ | ||
608 | |||
609 | void KXMLGUIClient::plugActionList( const QString &name, const QPtrList<KAction> &actionList ) | ||
610 | { | ||
611 | /*US | ||
612 | if ( !d->m_factory ) | ||
613 | return; | ||
614 | |||
615 | d->m_factory->plugActionList( this, name, actionList ); | ||
616 | */ | ||
617 | } | ||
618 | |||
619 | void KXMLGUIClient::unplugActionList( const QString &name ) | ||
620 | { | ||
621 | /*US | ||
622 | if ( !d->m_factory ) | ||
623 | return; | ||
624 | |||
625 | d->m_factory->unplugActionList( this, name ); | ||
626 | */ | ||
627 | } | ||
628 | |||
629 | /*US | ||
630 | QString KXMLGUIClient::findMostRecentXMLFile( const QStringList &files, QString &doc ) | ||
631 | { | ||
632 | |||
633 | QValueList<DocStruct> allDocuments; | ||
634 | |||
635 | QStringList::ConstIterator it = files.begin(); | ||
636 | QStringList::ConstIterator end = files.end(); | ||
637 | for (; it != end; ++it ) | ||
638 | { | ||
639 | //kdDebug() << "KXMLGUIClient::findMostRecentXMLFile " << *it << endl; | ||
640 | QString data = KXMLGUIFactory::readConfigFile( *it ); | ||
641 | DocStruct d; | ||
642 | d.file = *it; | ||
643 | d.data = data; | ||
644 | allDocuments.append( d ); | ||
645 | } | ||
646 | |||
647 | QValueList<DocStruct>::Iterator best = allDocuments.end(); | ||
648 | uint bestVersion = 0; | ||
649 | |||
650 | QValueList<DocStruct>::Iterator docIt = allDocuments.begin(); | ||
651 | QValueList<DocStruct>::Iterator docEnd = allDocuments.end(); | ||
652 | for (; docIt != docEnd; ++docIt ) | ||
653 | { | ||
654 | QString versionStr = findVersionNumber( (*docIt).data ); | ||
655 | if ( versionStr.isEmpty() ) | ||
656 | continue; | ||
657 | |||
658 | bool ok = false; | ||
659 | uint version = versionStr.toUInt( &ok ); | ||
660 | if ( !ok ) | ||
661 | continue; | ||
662 | //kdDebug() << "FOUND VERSION " << version << endl; | ||
663 | |||
664 | if ( version > bestVersion ) | ||
665 | { | ||
666 | best = docIt; | ||
667 | //kdDebug() << "best version is now " << version << endl; | ||
668 | bestVersion = version; | ||
669 | } | ||
670 | } | ||
671 | |||
672 | if ( best != docEnd ) | ||
673 | { | ||
674 | if ( best != allDocuments.begin() ) | ||
675 | { | ||
676 | QValueList<DocStruct>::Iterator local = allDocuments.begin(); | ||
677 | |||
678 | // load the local document and extract the action properties | ||
679 | QDomDocument document; | ||
680 | document.setContent( (*local).data ); | ||
681 | |||
682 | ActionPropertiesMap properties = extractActionProperties( document ); | ||
683 | |||
684 | // in case the document has a ActionProperties section | ||
685 | // we must not delete it but copy over the global doc | ||
686 | // to the local and insert the ActionProperties section | ||
687 | if ( !properties.isEmpty() ) | ||
688 | { | ||
689 | // now load the global one with the higher version number | ||
690 | // into memory | ||
691 | document.setContent( (*best).data ); | ||
692 | // and store the properties in there | ||
693 | storeActionProperties( document, properties ); | ||
694 | |||
695 | (*local).data = document.toString(); | ||
696 | // make sure we pick up the new local doc, when we return later | ||
697 | best = local; | ||
698 | |||
699 | // write out the new version of the local document | ||
700 | QFile f( (*local).file ); | ||
701 | if ( f.open( IO_WriteOnly ) ) | ||
702 | { | ||
703 | QCString utf8data = (*local).data.utf8(); | ||
704 | f.writeBlock( utf8data.data(), utf8data.length() ); | ||
705 | f.close(); | ||
706 | } | ||
707 | } | ||
708 | else | ||
709 | { | ||
710 | QString f = (*local).file; | ||
711 | QString backup = f + QString::fromLatin1( ".backup" ); | ||
712 | QDir dir; | ||
713 | dir.rename( f, backup ); | ||
714 | } | ||
715 | } | ||
716 | doc = (*best).data; | ||
717 | return (*best).file; | ||
718 | } | ||
719 | else if ( files.count() > 0 ) | ||
720 | { | ||
721 | //kdDebug() << "returning first one..." << endl; | ||
722 | doc = (*allDocuments.begin()).data; | ||
723 | return (*allDocuments.begin()).file; | ||
724 | } | ||
725 | |||
726 | return QString::null; | ||
727 | } | ||
728 | |||
729 | |||
730 | |||
731 | QString KXMLGUIClient::findVersionNumber( const QString &xml ) | ||
732 | { | ||
733 | enum { ST_START, ST_AFTER_OPEN, ST_AFTER_GUI, | ||
734 | ST_EXPECT_VERSION, ST_VERSION_NUM} state = ST_START; | ||
735 | for (unsigned int pos = 0; pos < xml.length(); pos++) | ||
736 | { | ||
737 | switch (state) | ||
738 | { | ||
739 | case ST_START: | ||
740 | if (xml[pos] == '<') | ||
741 | state = ST_AFTER_OPEN; | ||
742 | break; | ||
743 | case ST_AFTER_OPEN: | ||
744 | { | ||
745 | //Jump to gui.. | ||
746 | int guipos = xml.find("gui", pos, false); | ||
747 | if (guipos == -1) | ||
748 | return QString::null; //Reject | ||
749 | |||
750 | pos = guipos + 2; //Position at i, so we're moved ahead to the next character by the ++; | ||
751 | state = ST_AFTER_GUI; | ||
752 | break; | ||
753 | } | ||
754 | case ST_AFTER_GUI: | ||
755 | state = ST_EXPECT_VERSION; | ||
756 | break; | ||
757 | case ST_EXPECT_VERSION: | ||
758 | { | ||
759 | int verpos = xml.find("version=\"", pos, false ); | ||
760 | if (verpos == -1) | ||
761 | return QString::null; //Reject | ||
762 | |||
763 | pos = verpos + 8; //v = 0, e = +1, r = +2, s = +3 , i = +4, o = +5, n = +6, = = +7, " = + 8 | ||
764 | state = ST_VERSION_NUM; | ||
765 | break; | ||
766 | } | ||
767 | case ST_VERSION_NUM: | ||
768 | { | ||
769 | unsigned int endpos; | ||
770 | for (endpos = pos; endpos < xml.length(); endpos++) | ||
771 | { | ||
772 | if (xml[endpos].unicode() >= '0' && xml[endpos].unicode() <= '9') | ||
773 | continue; //Number.. | ||
774 | if (xml[endpos].unicode() == '"') //End of parameter | ||
775 | break; | ||
776 | else //This shouldn't be here.. | ||
777 | { | ||
778 | endpos = xml.length(); | ||
779 | } | ||
780 | } | ||
781 | |||
782 | if (endpos != pos && endpos < xml.length() ) | ||
783 | { | ||
784 | QString matchCandidate = xml.mid(pos, endpos - pos); //Don't include " ". | ||
785 | return matchCandidate; | ||
786 | } | ||
787 | |||
788 | state = ST_EXPECT_VERSION; //Try to match a well-formed version.. | ||
789 | break; | ||
790 | } //case.. | ||
791 | } //switch | ||
792 | } //for | ||
793 | |||
794 | return QString::null; | ||
795 | } | ||
796 | |||
797 | KXMLGUIClient::ActionPropertiesMap KXMLGUIClient::extractActionProperties( const QDomDocument &doc ) | ||
798 | { | ||
799 | ActionPropertiesMap properties; | ||
800 | |||
801 | QDomElement actionPropElement = doc.documentElement().namedItem( "ActionProperties" ).toElement(); | ||
802 | |||
803 | if ( actionPropElement.isNull() ) | ||
804 | return properties; | ||
805 | |||
806 | QDomNode n = actionPropElement.firstChild(); | ||
807 | for (; !n.isNull(); n = n.nextSibling() ) | ||
808 | { | ||
809 | QDomElement e = n.toElement(); | ||
810 | if ( e.isNull() ) | ||
811 | continue; | ||
812 | |||
813 | if ( e.tagName().lower() != "action" ) | ||
814 | continue; | ||
815 | |||
816 | QString actionName = e.attribute( "name" ); | ||
817 | |||
818 | if ( actionName.isEmpty() ) | ||
819 | continue; | ||
820 | |||
821 | QMap<QString, QMap<QString, QString> >::Iterator propIt = properties.find( actionName ); | ||
822 | if ( propIt == properties.end() ) | ||
823 | propIt = properties.insert( actionName, QMap<QString, QString>() ); | ||
824 | |||
825 | QDomNamedNodeMap attributes = e.attributes(); | ||
826 | for ( uint i = 0; i < attributes.length(); ++i ) | ||
827 | { | ||
828 | QDomAttr attr = attributes.item( i ).toAttr(); | ||
829 | |||
830 | if ( attr.isNull() ) | ||
831 | continue; | ||
832 | |||
833 | QString name = attr.name(); | ||
834 | |||
835 | if ( name == "name" || name.isEmpty() ) | ||
836 | continue; | ||
837 | |||
838 | (*propIt)[ name ] = attr.value(); | ||
839 | } | ||
840 | |||
841 | } | ||
842 | |||
843 | return properties; | ||
844 | } | ||
845 | |||
846 | void KXMLGUIClient::storeActionProperties( QDomDocument &doc, const ActionPropertiesMap &properties ) | ||
847 | { | ||
848 | QDomElement actionPropElement = doc.documentElement().namedItem( "ActionProperties" ).toElement(); | ||
849 | |||
850 | if ( actionPropElement.isNull() ) | ||
851 | { | ||
852 | actionPropElement = doc.createElement( "ActionProperties" ); | ||
853 | doc.documentElement().appendChild( actionPropElement ); | ||
854 | } | ||
855 | |||
856 | while ( !actionPropElement.firstChild().isNull() ) | ||
857 | actionPropElement.removeChild( actionPropElement.firstChild() ); | ||
858 | |||
859 | ActionPropertiesMap::ConstIterator it = properties.begin(); | ||
860 | ActionPropertiesMap::ConstIterator end = properties.end(); | ||
861 | for (; it != end; ++it ) | ||
862 | { | ||
863 | QDomElement action = doc.createElement( "Action" ); | ||
864 | action.setAttribute( "name", it.key() ); | ||
865 | actionPropElement.appendChild( action ); | ||
866 | |||
867 | QMap<QString, QString> attributes = (*it); | ||
868 | QMap<QString, QString>::ConstIterator attrIt = attributes.begin(); | ||
869 | QMap<QString, QString>::ConstIterator attrEnd = attributes.end(); | ||
870 | for (; attrIt != attrEnd; ++attrIt ) | ||
871 | action.setAttribute( attrIt.key(), attrIt.data() ); | ||
872 | } | ||
873 | } | ||
874 | */ | ||
875 | |||
876 | void KXMLGUIClient::addStateActionEnabled(const QString& state, | ||
877 | const QString& action) | ||
878 | { | ||
879 | StateChange stateChange = getActionsToChangeForState(state); | ||
880 | |||
881 | stateChange.actionsToEnable.append( action ); | ||
882 | //kdDebug() << "KXMLGUIClient::addStateActionEnabled( " << state << ", " << action << ")" << endl; | ||
883 | |||
884 | m_actionsStateMap.replace( state, stateChange ); | ||
885 | } | ||
886 | |||
887 | |||
888 | void KXMLGUIClient::addStateActionDisabled(const QString& state, | ||
889 | const QString& action) | ||
890 | { | ||
891 | StateChange stateChange = getActionsToChangeForState(state); | ||
892 | |||
893 | stateChange.actionsToDisable.append( action ); | ||
894 | //kdDebug() << "KXMLGUIClient::addStateActionDisabled( " << state << ", " << action << ")" << endl; | ||
895 | |||
896 | m_actionsStateMap.replace( state, stateChange ); | ||
897 | } | ||
898 | |||
899 | |||
900 | KXMLGUIClient::StateChange KXMLGUIClient::getActionsToChangeForState(const QString& state) | ||
901 | { | ||
902 | return m_actionsStateMap[state]; | ||
903 | } | ||
904 | |||
905 | |||
906 | void KXMLGUIClient::stateChanged(const QString &newstate, KXMLGUIClient::ReverseStateChange reverse) | ||
907 | { | ||
908 | StateChange stateChange = getActionsToChangeForState(newstate); | ||
909 | |||
910 | bool setTrue = (reverse == StateNoReverse); | ||
911 | bool setFalse = !setTrue; | ||
912 | |||
913 | // Enable actions which need to be enabled... | ||
914 | // | ||
915 | for ( QStringList::Iterator it = stateChange.actionsToEnable.begin(); | ||
916 | it != stateChange.actionsToEnable.end(); ++it ) { | ||
917 | |||
918 | KAction *action = actionCollection()->action((*it).latin1()); | ||
919 | if (action) action->setEnabled(setTrue); | ||
920 | } | ||
921 | |||
922 | // and disable actions which need to be disabled... | ||
923 | // | ||
924 | for ( QStringList::Iterator it = stateChange.actionsToDisable.begin(); | ||
925 | it != stateChange.actionsToDisable.end(); ++it ) { | ||
926 | |||
927 | KAction *action = actionCollection()->action((*it).latin1()); | ||
928 | if (action) action->setEnabled(setFalse); | ||
929 | } | ||
930 | |||
931 | } | ||
932 | /*US | ||
933 | void KXMLGUIClient::beginXMLPlug( QWidget *w ) | ||
934 | { | ||
935 | actionCollection()->beginXMLPlug( w ); | ||
936 | QPtrListIterator<KXMLGUIClient> childIt( d->m_children ); | ||
937 | for (; childIt.current(); ++childIt ) | ||
938 | childIt.current()->actionCollection()->beginXMLPlug( w ); | ||
939 | } | ||
940 | |||
941 | void KXMLGUIClient::endXMLPlug() | ||
942 | { | ||
943 | actionCollection()->endXMLPlug(); | ||
944 | QPtrListIterator<KXMLGUIClient> childIt( d->m_children ); | ||
945 | for (; childIt.current(); ++childIt ) | ||
946 | childIt.current()->actionCollection()->endXMLPlug(); | ||
947 | } | ||
948 | |||
949 | void KXMLGUIClient::prepareXMLUnplug( QWidget * ) | ||
950 | { | ||
951 | actionCollection()->prepareXMLUnplug(); | ||
952 | QPtrListIterator<KXMLGUIClient> childIt( d->m_children ); | ||
953 | for (; childIt.current(); ++childIt ) | ||
954 | childIt.current()->actionCollection()->prepareXMLUnplug(); | ||
955 | } | ||
956 | */ | ||
957 | void KXMLGUIClient::virtual_hook( int, void* ) | ||
958 | { /*BASE::virtual_hook( id, data );*/ } | ||