00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "actioncollection.h"
00021 #include "action.h"
00022 #include "manager.h"
00023
00024 #include <QStringList>
00025 #include <QPointer>
00026 #include <QIODevice>
00027 #include <QFile>
00028 #include <QFileInfo>
00029 #include <QDomElement>
00030
00031
00032
00033 #include <kicon.h>
00034 #include <kmimetype.h>
00035 #include <kstandarddirs.h>
00036
00037 using namespace Kross;
00038
00039 namespace Kross {
00040
00042 class ActionCollection::Private
00043 {
00044 public:
00045 QPointer<ActionCollection> parent;
00046 QHash< QString, QPointer<ActionCollection> > collections;
00047 QStringList collectionnames;
00048
00049 QString text;
00050
00051 Private(ActionCollection* const p) : parent(p) {}
00052 };
00053
00054 }
00055
00056 ActionCollection::ActionCollection(const QString& name, ActionCollection* parent)
00057 : KActionCollection(parent)
00058 , d( new Private(parent) )
00059 {
00060 setObjectName(name);
00061 d->text = name;
00062 if( d->parent )
00063 d->parent->registerCollection(this);
00064 }
00065
00066 ActionCollection::~ActionCollection()
00067 {
00068 if( d->parent )
00069 d->parent->unregisterCollection(objectName());
00070 delete d;
00071 }
00072
00073 QString ActionCollection::text() const { return d->text; }
00074 void ActionCollection::setText(const QString& text) { d->text = text; }
00075
00076 ActionCollection* ActionCollection::parentCollection() const
00077 {
00078 return d->parent;
00079 }
00080
00081 bool ActionCollection::hasCollection(const QString& name) const
00082 {
00083 return d->collections.contains(name);
00084 }
00085
00086 ActionCollection* ActionCollection::collection(const QString& name) const
00087 {
00088 return d->collections[name];
00089 }
00090
00091 QStringList ActionCollection::collections() const
00092 {
00093 return d->collectionnames;
00094 }
00095
00096 void ActionCollection::registerCollection(ActionCollection* collection)
00097 {
00098 const QString name = collection->objectName();
00099
00100 d->collections.insert(name, collection);
00101 d->collectionnames.append(name);
00102 }
00103
00104 void ActionCollection::unregisterCollection(const QString& name)
00105 {
00106 d->collectionnames.removeAll(name);
00107 d->collections.remove(name);
00108 }
00109
00110
00111
00112
00113
00114
00115 bool ActionCollection::readXml(const QDomElement& element, const QDir& directory)
00116 {
00117 #ifdef KROSS_ACTIONCOLLECTION_DEBUG
00118 krossdebug( QString("ActionCollection::readXml tagName=\"%1\"").arg(element.tagName()) );
00119 #endif
00120
00121 bool ok = true;
00122 QDomNodeList list = element.childNodes();
00123 const int size = list.size();
00124 for(int i = 0; i < size; ++i) {
00125 QDomElement elem = list.item(i).toElement();
00126 if( elem.isNull() ) continue;
00127
00128 #ifdef KROSS_ACTIONCOLLECTION_DEBUG
00129 krossdebug( QString(" ActionCollection::readXml child=%1 tagName=\"%2\"").arg(i).arg(elem.tagName()) );
00130 #endif
00131
00132 if( elem.tagName() == "collection") {
00133 const QString name = elem.attribute("name");
00134 const QString text = elem.attribute("text");
00135 ActionCollection* c = d->collections.contains(name) ? d->collections[name] : 0;
00136 if( ! c )
00137 c = new ActionCollection(name, this);
00138 if( ! text.isNull() )
00139 c->setText(text);
00140 if( ! c->readXml(elem) )
00141 ok = false;
00142 }
00143 else if( elem.tagName() == "script") {
00144 QString name = elem.attribute("name");
00145
00146 QString file = elem.attribute("file");
00147 if(! QFileInfo(file).exists()) {
00148 QFileInfo fi(directory, file);
00149 if( fi.exists() ) {
00150 file = fi.absoluteFilePath();
00151 }
00152 else {
00153 #ifdef KROSS_ACTIONCOLLECTION_DEBUG
00154 krosswarning( QString(" ActionCollection::readXml Failed to find file \"%1\" in the script-tag with name=\"%2\"").arg(file).arg(name) );
00155 #endif
00156
00157
00158 file = QString();
00159 }
00160 }
00161
00162 QString text = elem.attribute("text");
00163 if( text.isEmpty() )
00164 text = file;
00165
00166 QString description = elem.attribute("comment");
00167 if( description.isEmpty() )
00168 description = text.isEmpty() ? name : text;
00169
00170 QString icon = elem.attribute("icon");
00171 if( icon.isEmpty() )
00172 icon = KMimeType::iconNameForUrl( KUrl(file) );
00173
00174 QString interpreter = elem.attribute("interpreter");
00175
00176 Action* a = dynamic_cast< Action* >( action(name) );
00177 if( a ) {
00178 #ifdef KROSS_ACTIONCOLLECTION_DEBUG
00179 krossdebug( QString(" ActionCollection::readXml Updating Action \"%1\"").arg(a->objectName()) );
00180 #endif
00181 }
00182 else {
00183 #ifdef KROSS_ACTIONCOLLECTION_DEBUG
00184 krossdebug( QString(" ActionCollection::readXml Creating Action \"%1\"").arg(name) );
00185 #endif
00186
00187 a = new Action(this, name);
00188
00189 connect(a, SIGNAL( started(Kross::Action*) ), &Manager::self(), SIGNAL( started(Kross::Action*)) );
00190 connect(a, SIGNAL( finished(Kross::Action*) ), &Manager::self(), SIGNAL( finished(Kross::Action*) ));
00191 }
00192
00193 a->setText(text);
00194 a->setDescription(description);
00195 if( ! icon.isNull() )
00196 a->setIcon(KIcon(icon));
00197 if( ! interpreter.isNull() )
00198 a->setInterpreter(interpreter);
00199 a->setFile(file);
00200 }
00201
00202 }
00203 return ok;
00204 }
00205
00206 bool ActionCollection::readXml(QIODevice* device, const QDir& directory)
00207 {
00208 QString errMsg;
00209 int errLine, errCol;
00210 QDomDocument document;
00211 bool ok = document.setContent(device, false, &errMsg, &errLine, &errCol);
00212 if( ! ok ) {
00213 #ifdef KROSS_ACTIONCOLLECTION_DEBUG
00214 krosswarning( QString("ActionCollection::readXml Error at line %1 in col %2: %3").arg(errLine).arg(errCol).arg(errMsg) );
00215 #endif
00216 return false;
00217 }
00218 return readXml(document.documentElement(), directory);
00219 }
00220
00221 bool ActionCollection::readXmlFile(const QString& file)
00222 {
00223 #ifdef KROSS_ACTIONCOLLECTION_DEBUG
00224 krossdebug( QString("ActionCollection::readXmlFile file=\"%1\"").arg(file) );
00225 #endif
00226
00227 QFile f(file);
00228 if( ! f.open(QIODevice::ReadOnly) ) {
00229 #ifdef KROSS_ACTIONCOLLECTION_DEBUG
00230 krosswarning( QString("ActionCollection::readXmlFile reading file \"%1\" failed.").arg(file) );
00231 #endif
00232 return false;
00233 }
00234 bool ok = readXml(&f, QFileInfo(file).dir());
00235 f.close();
00236
00237 #ifdef KROSS_ACTIONCOLLECTION_DEBUG
00238 if( ! ok )
00239 krosswarning( QString("ActionCollection::readXmlFile parsing XML content of file \"%1\" failed.").arg(file) );
00240 #endif
00241 return ok;
00242 }
00243
00244 bool ActionCollection::readXmlResource(const QByteArray& resource, const QString& filer)
00245 {
00246
00247 QStringList files = KGlobal::dirs()->findAllResources(resource, filer);
00248
00249 bool ok = true;
00250 foreach(QString s, files)
00251 if( ! readXmlFile(s) )
00252 ok = false;
00253 return ok;
00254 }
00255
00256
00257
00258
00259
00260
00261 QDomElement ActionCollection::writeXml()
00262 {
00263 #ifdef KROSS_ACTIONCOLLECTION_DEBUG
00264 krossdebug( QString("ActionCollection::writeXml collection.objectName=\"%1\"").arg(objectName()) );
00265 #endif
00266
00267 QDomDocument document;
00268 QDomElement element = document.createElement("collection");
00269 if( ! objectName().isNull() )
00270 element.setAttribute("name", objectName());
00271 if( ! text().isNull() && text() != objectName() )
00272 element.setAttribute("text", text());
00273
00274 foreach(QString name, d->collectionnames) {
00275 ActionCollection* c = d->collections[name];
00276 if( ! c ) continue;
00277 QDomElement e = c->writeXml();
00278 if( e.isNull() ) continue;
00279 element.appendChild(e);
00280 }
00281
00282 foreach(KAction* action, actions()) {
00283 Action* a = dynamic_cast< Action* >(action);
00284 if( ! a ) continue;
00285
00286 #ifdef KROSS_ACTIONCOLLECTION_DEBUG
00287 krossdebug( QString(" ActionCollection::writeXml action.objectName=\"%1\" action.file=\"%2\"").arg(a->objectName()).arg(a->file()) );
00288 #endif
00289
00290 QDomElement e = document.createElement("script");
00291 e.setAttribute("name", a->objectName());
00292 e.setAttribute("text", a->text());
00293 e.setAttribute("comment", a->description());
00294
00295
00296 e.setAttribute("interpreter", a->interpreter());
00297 e.setAttribute("file", a->file());
00298 element.appendChild(e);
00299 }
00300
00301 return element;
00302 }
00303
00304 bool ActionCollection::writeXml(QIODevice* device, int indent)
00305 {
00306 QDomDocument document;
00307 document.documentElement().appendChild( writeXml() );
00308 return device->write( document.toByteArray(indent) ) != -1;
00309 }
00310
00311 #if 0
00312 bool Manager::readConfig()
00313 {
00314 KConfig* config = KApplication::kApplication()->sessionConfig();
00315 krossdebug( QString("Manager::readConfig hasGroup=%1 isReadOnly=%2 isImmutable=%3 ConfigState=%4").arg(config->hasGroup("scripts")).arg(config->isReadOnly()).arg(config->isImmutable()).arg(config->getConfigState()) );
00316 if(! config->hasGroup("scripts"))
00317 return false;
00318
00319
00320 QStringList actionnames;
00321 foreach(KAction* a, d->actioncollection->actions())
00322 actionnames.append( a->objectName() );
00323
00324
00325 config->setGroup("scripts");
00326 foreach(QString name, config->readEntry("names", QStringList())) {
00327 bool needsupdate = actionnames.contains( name );
00328 if( needsupdate )
00329 actionnames.removeAll( name );
00330
00331 QString text = config->readEntry(QString("%1_text").arg(name).toLatin1());
00332 QString description = config->readEntry(QString("%1_description").arg(name).toLatin1());
00333 QString icon = config->readEntry(QString("%1_icon").arg(name).toLatin1());
00334 QString file = config->readEntry(QString("%1_file").arg(name).toLatin1());
00335 QString interpreter = config->readEntry(QString("%1_interpreter").arg(name).toLatin1());
00336
00337 if( text.isEmpty() )
00338 text = file;
00339 if( description.isEmpty() )
00340 description = text.isEmpty() ? name : text;
00341 if( icon.isEmpty() )
00342 icon = KMimeType::iconNameForUrl( KUrl(file) );
00343
00344 Action* action = needsupdate
00345 ? dynamic_cast< Action* >( d->actioncollection->action(name) )
00346 : new Action(d->actioncollection, name);
00347 Q_ASSERT(action);
00348
00349 action->setText(text);
00350 action->setDescription(description);
00351 if( ! icon.isNull() )
00352 action->setIcon(KIcon(icon));
00353 if( ! interpreter.isNull() )
00354 action->setInterpreter(interpreter);
00355 action->setFile(file);
00356
00357 connect(action, SIGNAL( started(Kross::Action*) ), this, SIGNAL( started(Kross::Action*)) );
00358 connect(action, SIGNAL( finished(Kross::Action*) ), this, SIGNAL( finished(Kross::Action*) ));
00359 }
00360
00361
00362 foreach(QString n, actionnames) {
00363 KAction* a = d->actioncollection->action(n);
00364 Q_ASSERT(a);
00365 d->actioncollection->remove(a);
00366 delete a;
00367 }
00368
00369 return true;
00370 }
00371
00372 bool Manager::writeConfig()
00373 {
00374 KConfig* config = KApplication::kApplication()->sessionConfig();
00375 krossdebug( QString("Manager::writeConfig hasGroup=%1 isReadOnly=%2 isImmutable=%3 ConfigState=%4").arg(config->hasGroup("scripts")).arg(config->isReadOnly()).arg(config->isImmutable()).arg(config->getConfigState()) );
00376 if(config->isReadOnly())
00377 return false;
00378
00379 config->deleteGroup("scripts");
00380 config->setGroup("scripts");
00381
00382 QStringList names;
00383 foreach(KAction* a, d->actioncollection->actions(QString::null)) {
00384 Action* action = static_cast< Action* >(a);
00385 const QString name = action->objectName();
00386 names << name;
00387 config->writeEntry(QString("%1_text").arg(name).toLatin1(), action->text());
00388 config->writeEntry(QString("%1_description").arg(name).toLatin1(), action->description());
00389
00390
00391
00392
00393 config->writeEntry(QString("%1_file").arg(name).toLatin1(), action->file());
00394 config->writeEntry(QString("%1_interpreter").arg(name).toLatin1(), action->interpreter());
00395 }
00396
00397 config->writeEntry("names", names);
00398
00399 return true;
00400 }
00401 #endif
00402
00403 #include "actioncollection.moc"