Kross
actioncollection.cpp
Go to the documentation of this file.
00001 /*************************************************************************** 00002 * actioncollection.cpp 00003 * This file is part of the KDE project 00004 * copyright (C)2004-2006 by Sebastian Sauer (mail@dipe.org) 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Library General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2 of the License, or (at your option) any later version. 00010 * This program 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 * You should have received a copy of the GNU Library General Public License 00015 * along with this program; see the file COPYING. If not, write to 00016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 * Boston, MA 02110-1301, USA. 00018 ***************************************************************************/ 00019 00020 #include "actioncollection.h" 00021 #include "action.h" 00022 #include "manager.h" 00023 00024 #include <QtCore/QHash> 00025 #include <QtCore/QStringList> 00026 #include <QtCore/QPointer> 00027 #include <QtCore/QIODevice> 00028 #include <QtCore/QFile> 00029 #include <QtCore/QFileInfo> 00030 #include <QtXml/QDomAttr> 00031 00032 #include <kicon.h> 00033 #include <klocalizedstring.h> 00034 00035 using namespace Kross; 00036 00037 namespace Kross { 00038 00040 class ActionCollection::Private 00041 { 00042 public: 00043 QPointer<ActionCollection> parent; 00044 QHash< QString, QPointer<ActionCollection> > collections; 00045 QStringList collectionnames; 00046 00047 QList< Action* > actionList; 00048 QHash< QString, Action* > actionMap; 00049 00050 QString text; 00051 QString description; 00052 QString iconname; 00053 bool enabled; 00054 bool blockupdated; 00055 00056 Private(ActionCollection* const p) : parent(p) {} 00057 }; 00058 00059 } 00060 00061 ActionCollection::ActionCollection(const QString& name, ActionCollection* parent) 00062 : QObject(0) 00063 , d( new Private(0) ) 00064 { 00065 setObjectName(name); 00066 d->text = name; 00067 d->enabled = true; 00068 d->blockupdated = false; 00069 00070 setParentCollection(parent); 00071 } 00072 00073 ActionCollection::~ActionCollection() 00074 { 00075 if ( d->parent ) { 00076 emit d->parent->collectionToBeRemoved(this, d->parent); 00077 d->parent->unregisterCollection( objectName() ); 00078 emit d->parent->collectionRemoved( this, d->parent ); 00079 } 00080 delete d; 00081 } 00082 00083 QString ActionCollection::name() const { return objectName(); } 00084 00085 QString ActionCollection::text() const { return d->text; } 00086 void ActionCollection::setText(const QString& text) { d->text = text; emit dataChanged(this); emitUpdated(); } 00087 00088 QString ActionCollection::description() const { return d->description; } 00089 void ActionCollection::setDescription(const QString& description) { d->description = description; emit dataChanged(this); emitUpdated(); } 00090 00091 QString ActionCollection::iconName() const { return d->iconname; } 00092 void ActionCollection::setIconName(const QString& iconname) { d->iconname = iconname; emit dataChanged(this); } 00093 QIcon ActionCollection::icon() const { return KIcon(d->iconname); } 00094 00095 bool ActionCollection::isEnabled() const { return d->enabled; } 00096 void ActionCollection::setEnabled(bool enabled) { d->enabled = enabled; emit dataChanged(this); emitUpdated(); } 00097 00098 ActionCollection* ActionCollection::parentCollection() const 00099 { 00100 return d->parent; 00101 } 00102 00103 void ActionCollection::setParentCollection( ActionCollection *parent ) 00104 { 00105 if ( d->parent ) { 00106 emit d->parent->collectionToBeRemoved(this, d->parent); 00107 d->parent->unregisterCollection( objectName() ); 00108 setParent( 0 ); 00109 emit d->parent->collectionRemoved( this, d->parent ); 00110 d->parent = 0; 00111 } 00112 setParent(0); 00113 if ( parent ) { 00114 emit parent->collectionToBeInserted(this, parent); 00115 setParent( parent ); 00116 d->parent = parent; 00117 parent->registerCollection( this ); 00118 emit parent->collectionInserted( this, parent ); 00119 } 00120 emitUpdated(); 00121 } 00122 00123 bool ActionCollection::hasCollection(const QString& name) const 00124 { 00125 return d->collections.contains(name); 00126 } 00127 00128 ActionCollection* ActionCollection::collection(const QString& name) const 00129 { 00130 return d->collections.contains(name) ? d->collections[name] : QPointer<ActionCollection>(0); 00131 } 00132 00133 QStringList ActionCollection::collections() const 00134 { 00135 return d->collectionnames; 00136 } 00137 00138 void ActionCollection::registerCollection(ActionCollection* collection) 00139 { 00140 Q_ASSERT(collection); 00141 const QString name = collection->objectName(); 00142 //Q_ASSERT( !name.isNull() ); 00143 if (!d->collections.contains(name)) 00144 { 00145 d->collections.insert(name, collection); 00146 d->collectionnames.append(name); 00147 } 00148 connectSignals(collection, true); 00149 emitUpdated(); 00150 } 00151 00152 void ActionCollection::unregisterCollection(const QString& name) 00153 { 00154 if( ! d->collections.contains(name) ) 00155 return; 00156 ActionCollection* collection = d->collections[name]; 00157 d->collectionnames.removeAll(name); 00158 d->collections.remove(name); 00159 connectSignals(collection, false); 00160 emitUpdated(); 00161 } 00162 00163 QList<Action*> ActionCollection::actions() const 00164 { 00165 return d->actionList; 00166 } 00167 00168 Action* ActionCollection::action(const QString& name) const 00169 { 00170 return d->actionMap.contains(name) ? d->actionMap[name] : 0; 00171 } 00172 00173 void ActionCollection::addAction(Action* action) 00174 { 00175 Q_ASSERT( action && ! action->objectName().isEmpty() ); 00176 addAction(action->objectName(), action); 00177 } 00178 00179 void ActionCollection::addAction(const QString& name, Action* action) 00180 { 00181 Q_ASSERT( action && ! name.isEmpty() ); 00182 emit actionToBeInserted(action, this); 00183 if( d->actionMap.contains(name) ) 00184 d->actionList.removeAll( d->actionMap[name] ); 00185 d->actionMap.insert(name, action); 00186 d->actionList.append(action); 00187 action->setParent(this); // in case it is not set 00188 connectSignals(action, true); 00189 emit actionInserted(action, this); 00190 emitUpdated(); 00191 } 00192 00193 void ActionCollection::removeAction(const QString& name) 00194 { 00195 if( ! d->actionMap.contains(name) ) 00196 return; 00197 Action* action = d->actionMap[name]; 00198 connectSignals(action, false); 00199 emit actionToBeRemoved(action, this); 00200 d->actionList.removeAll(action); 00201 d->actionMap.remove(name); 00202 //krossdebug( QString("ActionCollection::removeAction: %1 %2").arg(action->name()).arg(action->parent()->objectName()) ); 00203 action->setParent( 0 ); 00204 emit actionRemoved(action, this); 00205 emitUpdated(); 00206 } 00207 00208 void ActionCollection::removeAction(Action* action) 00209 { 00210 Q_ASSERT( action && ! action->objectName().isEmpty() ); 00211 if( ! d->actionMap.contains(action->objectName()) ) { 00212 Q_ASSERT( ! d->actionList.contains(action) ); 00213 return; 00214 } 00215 removeAction( action->objectName() ); 00216 } 00217 00218 void ActionCollection::connectSignals(Action *action, bool conn) 00219 { 00220 if ( conn ) { 00221 connect(action, SIGNAL(dataChanged(Action*)), this, SIGNAL(dataChanged(Action*))); 00222 connect(action, SIGNAL(updated()), this, SLOT(emitUpdated())); 00223 } else { 00224 disconnect(action, SIGNAL(dataChanged(Action*)), this, SIGNAL(dataChanged(Action*))); 00225 disconnect(action, SIGNAL(updated()), this, SLOT(emitUpdated())); 00226 } 00227 } 00228 00229 void ActionCollection::connectSignals(ActionCollection *collection, bool conn) 00230 { 00231 if ( conn ) { 00232 connect(collection, SIGNAL(dataChanged(Action*)), this, SIGNAL(dataChanged(Action*))); 00233 connect(collection, SIGNAL(dataChanged(ActionCollection*)), this, SIGNAL(dataChanged(ActionCollection*))); 00234 00235 connect(collection, SIGNAL(collectionToBeInserted(ActionCollection*, ActionCollection*)), this, SIGNAL(collectionToBeInserted(ActionCollection*, ActionCollection*))); 00236 connect(collection, SIGNAL(collectionInserted(ActionCollection*, ActionCollection*)), this, SIGNAL(collectionInserted(ActionCollection*, ActionCollection*))); 00237 connect(collection, SIGNAL(collectionToBeRemoved(ActionCollection*, ActionCollection*)), this, SIGNAL(collectionToBeRemoved(ActionCollection*, ActionCollection*))); 00238 connect(collection, SIGNAL(collectionRemoved(ActionCollection*, ActionCollection*)), this, SIGNAL(collectionRemoved(ActionCollection*, ActionCollection*))); 00239 00240 connect(collection, SIGNAL(actionToBeInserted(Action*, ActionCollection*)), this, SIGNAL(actionToBeInserted(Action*, ActionCollection*))); 00241 connect(collection, SIGNAL(actionInserted(Action*, ActionCollection*)), this, SIGNAL(actionInserted(Action*, ActionCollection*))); 00242 connect(collection, SIGNAL(actionToBeRemoved(Action*, ActionCollection*)), this, SIGNAL(actionToBeRemoved(Action*, ActionCollection*))); 00243 connect(collection, SIGNAL(actionRemoved(Action*, ActionCollection*)), this, SIGNAL(actionRemoved(Action*, ActionCollection*))); 00244 connect(collection, SIGNAL(updated()), this, SLOT(emitUpdated())); 00245 } else { 00246 disconnect(collection, SIGNAL(dataChanged(ActionCollection*)), this, SIGNAL(dataChanged(ActionCollection*))); 00247 00248 disconnect(collection, SIGNAL(collectionToBeInserted(ActionCollection*, ActionCollection*)), this, SIGNAL(collectionToBeInserted(ActionCollection*, ActionCollection*))); 00249 disconnect(collection, SIGNAL(collectionInserted(ActionCollection*, ActionCollection*)), this, SIGNAL(collectionInserted(ActionCollection*, ActionCollection*))); 00250 disconnect(collection, SIGNAL(collectionToBeRemoved(ActionCollection*, ActionCollection*)), this, SIGNAL(collectionToBeRemoved(ActionCollection*, ActionCollection*))); 00251 disconnect(collection, SIGNAL(collectionRemoved(ActionCollection*, ActionCollection*)), this, SIGNAL(collectionRemoved(ActionCollection*, ActionCollection*))); 00252 00253 disconnect(collection, SIGNAL(actionToBeInserted(Action*, ActionCollection*)), this, SIGNAL(actionToBeInserted(Action*, ActionCollection*))); 00254 disconnect(collection, SIGNAL(actionInserted(Action*, ActionCollection*)), this, SIGNAL(actionInserted(Action*, ActionCollection*))); 00255 disconnect(collection, SIGNAL(actionToBeRemoved(Action*, ActionCollection*)), this, SIGNAL(actionToBeRemoved(Action*, ActionCollection*))); 00256 disconnect(collection, SIGNAL(actionRemoved(Action*, ActionCollection*)), this, SIGNAL(actionRemoved(Action*, ActionCollection*))); 00257 disconnect(collection, SIGNAL(updated()), this, SLOT(emitUpdated())); 00258 } 00259 } 00260 00261 void ActionCollection::emitUpdated() 00262 { 00263 if (!d->blockupdated) emit updated(); 00264 } 00265 00266 /********************************************************************* 00267 * Unserialize from XML / QIODevice / file / resource to child 00268 * ActionCollection's and Action's this ActionCollection has. 00269 */ 00270 00271 bool ActionCollection::readXml(const QDomElement& element, const QDir& directory) 00272 { 00273 return readXml(element, QStringList(directory.absolutePath())); 00274 } 00275 00276 bool ActionCollection::readXml(const QDomElement& element, const QStringList& searchPath) 00277 { 00278 #ifdef KROSS_ACTIONCOLLECTION_DEBUG 00279 krossdebug( QString("ActionCollection::readXml tagName=\"%1\"").arg(element.tagName()) ); 00280 #endif 00281 00282 d->blockupdated = true; // block updated() signals and emit it only once if everything is done 00283 bool ok = true; 00284 QDomNodeList list = element.childNodes(); 00285 const int size = list.size(); 00286 for(int i = 0; i < size; ++i) { 00287 QDomElement elem = list.item(i).toElement(); 00288 if( elem.isNull() ) continue; 00289 00290 #ifdef KROSS_ACTIONCOLLECTION_DEBUG 00291 krossdebug( QString(" ActionCollection::readXml child=%1 tagName=\"%2\"").arg(i).arg(elem.tagName()) ); 00292 #endif 00293 00294 if( elem.tagName() == "collection") { 00295 const QString name = elem.attribute("name"); 00296 const QByteArray text = elem.attribute("text").toUtf8(); 00297 const QByteArray description = elem.attribute("comment").toUtf8(); 00298 const QString iconname = elem.attribute("icon"); 00299 bool enabled = QVariant(elem.attribute("enabled","true")).toBool(); 00300 ActionCollection* c = d->collections.contains(name) ? d->collections[name] : QPointer<ActionCollection>(0); 00301 if( ! c ) 00302 c = new ActionCollection(name, this); 00303 00304 c->setText( text.isEmpty() ? name : i18n( text ) ); 00305 c->setDescription( description.isEmpty() ? c->text() : i18n( description ) ); 00306 c->setIconName( iconname ); 00307 00308 if( ! enabled ) 00309 c->setEnabled(false); 00310 if( ! c->readXml(elem, searchPath) ) 00311 ok = false; 00312 } 00313 else if( elem.tagName() == "script") { 00314 QString name = elem.attribute("name"); 00315 Action* a = dynamic_cast< Action* >( action(name) ); 00316 if( a ) { 00317 #ifdef KROSS_ACTIONCOLLECTION_DEBUG 00318 krossdebug( QString(" ActionCollection::readXml Updating Action \"%1\"").arg(a->objectName()) ); 00319 #endif 00320 } 00321 else { 00322 #ifdef KROSS_ACTIONCOLLECTION_DEBUG 00323 krossdebug( QString(" ActionCollection::readXml Creating Action \"%1\"").arg(name) ); 00324 #endif 00325 00326 a = new Action(this, name); 00327 addAction(name, a); 00328 connect(a, SIGNAL( started(Kross::Action*) ), &Manager::self(), SIGNAL( started(Kross::Action*)) ); 00329 connect(a, SIGNAL( finished(Kross::Action*) ), &Manager::self(), SIGNAL( finished(Kross::Action*) )); 00330 } 00331 a->fromDomElement(elem, searchPath); 00332 } 00333 //else if( ! fromXml(elem) ) ok = false; 00334 } 00335 00336 d->blockupdated = false; // unblock signals 00337 emitUpdated(); 00338 return ok; 00339 } 00340 00341 bool ActionCollection::readXml(QIODevice* device, const QDir& directory) 00342 { 00343 return readXml(device, QStringList(directory.absolutePath())); 00344 } 00345 00346 bool ActionCollection::readXml(QIODevice* device, const QStringList& searchPath) 00347 { 00348 QString errMsg; 00349 int errLine, errCol; 00350 QDomDocument document; 00351 bool ok = document.setContent(device, false, &errMsg, &errLine, &errCol); 00352 if( ! ok ) { 00353 #ifdef KROSS_ACTIONCOLLECTION_DEBUG 00354 krosswarning( QString("ActionCollection::readXml Error at line %1 in col %2: %3").arg(errLine).arg(errCol).arg(errMsg) ); 00355 #endif 00356 return false; 00357 } 00358 return readXml(document.documentElement(), searchPath); 00359 } 00360 00361 bool ActionCollection::readXmlFile(const QString& file) 00362 { 00363 #ifdef KROSS_ACTIONCOLLECTION_DEBUG 00364 krossdebug( QString("ActionCollection::readXmlFile file=\"%1\"").arg(file) ); 00365 #endif 00366 00367 QFile f(file); 00368 if( ! f.open(QIODevice::ReadOnly) ) { 00369 #ifdef KROSS_ACTIONCOLLECTION_DEBUG 00370 krosswarning( QString("ActionCollection::readXmlFile reading file \"%1\" failed.").arg(file) ); 00371 #endif 00372 return false; 00373 } 00374 bool ok = readXml(&f, QFileInfo(file).dir()); 00375 f.close(); 00376 00377 #ifdef KROSS_ACTIONCOLLECTION_DEBUG 00378 if( ! ok ) 00379 krosswarning( QString("ActionCollection::readXmlFile parsing XML content of file \"%1\" failed.").arg(file) ); 00380 #endif 00381 return ok; 00382 } 00383 00384 /********************************************************************* 00385 * Serialize from child ActionCollection's and Action's this 00386 * ActionCollection has to XML / QIODevice / file / resource. 00387 */ 00388 00389 QDomElement ActionCollection::writeXml() 00390 { 00391 return writeXml(QStringList()); 00392 } 00393 00394 QDomElement ActionCollection::writeXml(const QStringList& searchPath) 00395 { 00396 #ifdef KROSS_ACTIONCOLLECTION_DEBUG 00397 krossdebug( QString("ActionCollection::writeXml collection.objectName=\"%1\"").arg(objectName()) ); 00398 #endif 00399 00400 QDomDocument document; 00401 QDomElement element = document.createElement("collection"); 00402 if( ! objectName().isNull() ) 00403 element.setAttribute("name", objectName()); 00404 if( ! text().isNull() && text() != objectName() ) 00405 element.setAttribute("text", text()); 00406 if( ! d->description.isNull() ) 00407 element.setAttribute("comment", d->description); 00408 if( ! d->iconname.isNull() ) 00409 element.setAttribute("icon", d->iconname); 00410 if( ! d->enabled ) 00411 element.setAttribute("enabled", d->enabled); 00412 00413 foreach(Action* a, actions()) { 00414 Q_ASSERT(a); 00415 #ifdef KROSS_ACTIONCOLLECTION_DEBUG 00416 krossdebug( QString(" ActionCollection::writeXml action.objectName=\"%1\" action.file=\"%2\"").arg(a->objectName()).arg(a->file()) ); 00417 #endif 00418 QDomElement e = a->toDomElement(searchPath); 00419 if( ! e.isNull() ) 00420 element.appendChild(e); 00421 } 00422 00423 foreach(const QString &name, d->collectionnames) { 00424 ActionCollection* c = d->collections[name]; 00425 if( ! c ) continue; 00426 QDomElement e = c->writeXml(searchPath); 00427 if( ! e.isNull() ) 00428 element.appendChild(e); 00429 } 00430 00431 return element; 00432 } 00433 00434 bool ActionCollection::writeXml(QIODevice* device, int indent) 00435 { 00436 return writeXml(device, indent, QStringList()); 00437 } 00438 00439 bool ActionCollection::writeXml(QIODevice* device, int indent, const QStringList& searchPath) 00440 { 00441 QDomDocument document; 00442 QDomElement root = document.createElement("KrossScripting"); 00443 00444 foreach(Action* a, actions()) { 00445 QDomElement e = a->toDomElement(searchPath); 00446 if( ! e.isNull() ) 00447 root.appendChild(e); 00448 } 00449 00450 foreach(const QString &name, d->collectionnames) { 00451 ActionCollection* c = d->collections[name]; 00452 if( ! c ) continue; 00453 QDomElement e = c->writeXml(searchPath); 00454 if( ! e.isNull() ) 00455 root.appendChild(e); 00456 } 00457 00458 document.appendChild(root); 00459 return device->write( document.toByteArray(indent) ) != -1; 00460 } 00461 00462 #include "actioncollection.moc"
KDE 4.7 API Reference