Kross
action.cpp
Go to the documentation of this file.
00001 /*************************************************************************** 00002 * action.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 "action.h" 00021 #include "actioncollection.h" 00022 #include "interpreter.h" 00023 #include "script.h" 00024 #include "manager.h" 00025 #include "wrapperinterface.h" 00026 00027 #include <QtCore/QFile> 00028 #include <QtCore/QFileInfo> 00029 00030 #include <klocale.h> 00031 #include <kicon.h> 00032 #include <kmimetype.h> 00033 00034 using namespace Kross; 00035 00036 namespace Kross { 00037 00039 class Action::Private 00040 { 00041 public: 00042 00048 Script* script; 00049 00054 int version; 00055 00060 QString description; 00061 00065 QString iconname; 00066 00070 QByteArray code; 00071 00076 QString interpretername; 00077 00084 QString scriptfile; 00085 00091 QStringList searchpath; 00092 00097 QMap< QString, QVariant > options; 00098 00099 Private() : script(0), version(0) {} 00100 }; 00101 00102 } 00103 00104 enum InitOptions{Enable=1}; 00105 void static init(Action* th, const QString& name, int options=0) 00106 { 00107 th->setEnabled(options&Enable); 00108 th->setObjectName(name); 00109 #ifdef KROSS_ACTION_DEBUG 00110 krossdebug( QString("Action::Action(QObject*,QString,QDir) Ctor name='%1'").arg(th->objectName()) ); 00111 #endif 00112 QObject::connect(th, SIGNAL(triggered(bool)), th, SLOT(slotTriggered())); 00113 } 00114 00115 Action::Action(QObject* parent, const QString& name, const QDir& packagepath) 00116 : QAction(parent) 00117 , QScriptable() 00118 , ChildrenInterface() 00119 , ErrorInterface() 00120 , d( new Private() ) 00121 { 00122 init(this,name); 00123 d->searchpath=QStringList(packagepath.absolutePath()); 00124 } 00125 00126 Action::Action(QObject* parent, const QUrl& url) 00127 : QAction(parent) 00128 , ChildrenInterface() 00129 , ErrorInterface() 00130 , d( new Private() ) 00131 { 00132 init(this,url.path(),Enable); 00133 QFileInfo fi( url.toLocalFile() ); 00134 setText( fi.fileName() ); 00135 setIconName( KMimeType::iconNameForUrl(url) ); 00136 setFile( url.toLocalFile() ); 00137 } 00138 00139 Action::~Action() 00140 { 00141 #ifdef KROSS_ACTION_DEBUG 00142 krossdebug( QString("Action::~Action() Dtor name='%1'").arg(objectName()) ); 00143 #endif 00144 finalize(); 00145 ActionCollection *coll = qobject_cast<ActionCollection*>(parent()); 00146 if ( coll ) { 00147 coll->removeAction(this); 00148 } 00149 delete d; 00150 } 00151 00152 00153 void Action::fromDomElement(const QDomElement& element) 00154 { 00155 fromDomElement(element, d->searchpath); 00156 } 00157 00158 void Action::fromDomElement(const QDomElement& element, const QStringList& searchPath) 00159 { 00160 if( element.isNull() ) 00161 return; 00162 00163 QString file = element.attribute("file"); 00164 if( ! file.isEmpty() ) { 00165 if( QFileInfo(file).exists() ) { 00166 setFile(file); 00167 } 00168 else { 00169 foreach (const QString& packagepath, searchPath) { 00170 QFileInfo fi(QDir(packagepath), file); 00171 if( fi.exists() ) { 00172 setFile( fi.absoluteFilePath() ); 00173 break; 00174 } 00175 } 00176 } 00177 } 00178 00179 d->version = QVariant( element.attribute("version",QString(d->version)) ).toInt(); 00180 00181 setText( i18n( element.attribute("text").toUtf8() ) ); 00182 setDescription( i18n( element.attribute("comment").toUtf8() ) ); 00183 setEnabled( true ); 00184 setInterpreter( element.attribute("interpreter") ); 00185 setEnabled( QVariant(element.attribute("enabled","true")).toBool() && isEnabled() ); 00186 00187 QString icon = element.attribute("icon"); 00188 if( icon.isEmpty() && ! d->scriptfile.isNull() ) 00189 icon = KMimeType::iconNameForUrl( KUrl(d->scriptfile) ); 00190 setIconName( icon ); 00191 00192 const QString code = element.attribute("code"); 00193 if( ! code.isNull() ) 00194 setCode(code.toUtf8()); 00195 00196 for(QDomNode node = element.firstChild(); ! node.isNull(); node = node.nextSibling()) { 00197 QDomElement e = node.toElement(); 00198 if( ! e.isNull() ) { 00199 if( e.tagName() == "property" ) { 00200 const QString n = e.attribute("name", QString()); 00201 if( ! n.isNull() ) { 00202 #ifdef KROSS_ACTION_DEBUG 00203 krossdebug(QString("Action::readDomElement: Setting property name=%1 value=%2").arg(n).arg(e.text())); 00204 #endif 00205 setProperty(n.toLatin1().constData(), QVariant(e.text())); 00206 } 00207 } 00208 } 00209 } 00210 } 00211 00212 QDomElement Action::toDomElement() const 00213 { 00214 return toDomElement(QStringList()); 00215 } 00216 00217 QDomElement Action::toDomElement(const QStringList& searchPath) const 00218 { 00219 QDomDocument doc; 00220 QDomElement e = doc.createElement("script"); 00221 e.setAttribute("name", objectName()); 00222 if( d->version > 0 ) 00223 e.setAttribute("version", QString(d->version)); 00224 if( ! text().isNull() ) 00225 e.setAttribute("text", text()); 00226 if( ! description().isNull() ) 00227 e.setAttribute("comment", description()); 00228 if( ! iconName().isNull() ) 00229 e.setAttribute("icon", iconName()); 00230 if( ! isEnabled() ) 00231 e.setAttribute("enabled", "false"); 00232 if( ! interpreter().isNull() ) 00233 e.setAttribute("interpreter", interpreter()); 00234 00235 00236 QString fileName=file(); 00237 if (!searchPath.isEmpty()) { 00238 //fileName=QDir(searchPath.first()).relativeFilePath(fileName); //prefer absname if it is short? 00239 foreach(const QString& packagepath, searchPath) { 00240 QString nfn=QDir(packagepath).relativeFilePath(file()); 00241 if (nfn.length()<fileName.length()) 00242 fileName=nfn; 00243 } 00244 } 00245 00246 if( ! fileName.isNull() ) { 00247 e.setAttribute("file", fileName); 00248 } 00249 00250 QList<QByteArray> props=dynamicPropertyNames(); 00251 foreach(const QByteArray& prop, props) { 00252 QDomElement p = doc.createElement("property"); 00253 p.setAttribute("name", QString::fromLatin1(prop)); 00254 p.appendChild(doc.createTextNode(property(prop.constData()).toString())); 00255 e.appendChild(p); 00256 } 00257 /* 00258 else if( ! code().isNull() ) { 00259 e.setAttribute("code", code()); 00260 } 00261 */ 00262 00263 return e; 00264 } 00265 00266 Kross::Script* Action::script() const 00267 { 00268 return d->script; 00269 } 00270 00271 QString Action::name() const 00272 { 00273 return objectName(); 00274 } 00275 00276 int Action::version() const 00277 { 00278 return d->version; 00279 } 00280 00281 QString Action::description() const 00282 { 00283 return d->description; 00284 } 00285 00286 void Action::setDescription(const QString& description) 00287 { 00288 d->description = description; 00289 emit dataChanged(this); 00290 emit updated(); 00291 } 00292 00293 QString Action::iconName() const 00294 { 00295 return d->iconname; 00296 } 00297 00298 void Action::setIconName(const QString& iconname) 00299 { 00300 setIcon( KIcon(iconname) ); 00301 d->iconname = iconname; 00302 emit dataChanged(this); 00303 emit updated(); 00304 } 00305 00306 bool Action::isEnabled() const 00307 { 00308 return QAction::isEnabled(); 00309 } 00310 00311 void Action::setEnabled(bool enabled) 00312 { 00313 QAction::setEnabled(enabled); 00314 emit dataChanged(this); 00315 emit updated(); 00316 } 00317 00318 QByteArray Action::code() const 00319 { 00320 return d->code; 00321 } 00322 00323 void Action::setCode(const QByteArray& code) 00324 { 00325 if( d->code != code ) { 00326 finalize(); 00327 d->code = code; 00328 emit dataChanged(this); 00329 emit updated(); 00330 } 00331 } 00332 00333 QString Action::interpreter() const 00334 { 00335 return d->interpretername; 00336 } 00337 00338 void Action::setInterpreter(const QString& interpretername) 00339 { 00340 if( d->interpretername != interpretername ) { 00341 finalize(); 00342 d->interpretername = interpretername; 00343 setEnabled( Manager::self().interpreters().contains(interpretername) ); 00344 if (!isEnabled()) 00345 krosswarning("Action::setInterpreter: interpreter not found: "+interpretername); 00346 emit dataChanged(this); 00347 emit updated(); 00348 } 00349 } 00350 00351 QString Action::file() const 00352 { 00353 return d->scriptfile; 00354 } 00355 00356 bool Action::setFile(const QString& scriptfile) 00357 { 00358 if( d->scriptfile != scriptfile ) { 00359 finalize(); 00360 if ( scriptfile.isNull() ) { 00361 if( ! d->scriptfile.isNull() ) 00362 d->interpretername.clear(); 00363 d->scriptfile.clear(); 00364 d->searchpath.clear(); 00365 } 00366 else { 00367 d->scriptfile = scriptfile; 00368 d->interpretername = Manager::self().interpreternameForFile(scriptfile); 00369 if( d->interpretername.isNull() ) 00370 return false; 00371 } 00372 } 00373 return true; 00374 } 00375 00376 QString Action::currentPath() const 00377 { 00378 return file().isEmpty()?QString():QFileInfo(file()).absolutePath();//obey Qt docs and don't cheat 00379 } 00380 00381 QVariantMap Action::options() const 00382 { 00383 return d->options; 00384 } 00385 00386 void Action::addQObject(QObject* obj, const QString &name) 00387 { 00388 this->addObject(obj, name); 00389 } 00390 00391 QObject* Action::qobject(const QString &name) const 00392 { 00393 return this->object(name); 00394 } 00395 00396 QStringList Action::qobjectNames() const 00397 { 00398 return this->objects().keys(); 00399 } 00400 00401 QVariant Action::option(const QString& name, const QVariant& defaultvalue) 00402 { 00403 if(d->options.contains(name)) 00404 return d->options[name]; 00405 InterpreterInfo* info = Manager::self().interpreterInfo( d->interpretername ); 00406 return info ? info->optionValue(name, defaultvalue) : defaultvalue; 00407 } 00408 00409 bool Action::setOption(const QString& name, const QVariant& value) 00410 { 00411 InterpreterInfo* info = Manager::self().interpreterInfo( d->interpretername ); 00412 if(info) { 00413 if(info->hasOption(name)) { 00414 d->options.insert(name, value); 00415 return true; 00416 } else krosswarning( QString("Kross::Action::setOption(%1, %2): No such option").arg(name).arg(value.toString()) ); 00417 } else krosswarning( QString("Kross::Action::setOption(%1, %2): No such interpreterinfo").arg(name).arg(value.toString()) ); 00418 return false; 00419 } 00420 00421 QStringList Action::functionNames() 00422 { 00423 if(! d->script) { 00424 if(! initialize()) 00425 return QStringList(); 00426 } 00427 return d->script->functionNames(); 00428 } 00429 00430 QVariant Action::callFunction(const QString& name, const QVariantList& args) 00431 { 00432 if(! d->script) { 00433 if(! initialize()) 00434 return QVariant(); 00435 } 00436 return d->script->callFunction(name, args); 00437 } 00438 00439 QVariant Action::evaluate(const QByteArray& code) 00440 { 00441 if(! d->script) { 00442 if(! initialize()) 00443 return QVariant(); 00444 } 00445 return d->script->evaluate(code); 00446 } 00447 00448 bool Action::initialize() 00449 { 00450 finalize(); 00451 00452 if( ! d->scriptfile.isNull() ) { 00453 QFile f( d->scriptfile ); 00454 if( ! f.exists() ) { 00455 setError(i18n("Scriptfile \"%1\" does not exist.", d->scriptfile)); 00456 return false; 00457 } 00458 if( d->interpretername.isNull() ) { 00459 setError(i18n("Failed to determine interpreter for scriptfile \"%1\"", d->scriptfile)); 00460 return false; 00461 } 00462 if( ! f.open(QIODevice::ReadOnly) ) { 00463 setError(i18n("Failed to open scriptfile \"%1\"", d->scriptfile)); 00464 return false; 00465 } 00466 d->code = f.readAll(); 00467 f.close(); 00468 } 00469 00470 Interpreter* interpreter = Manager::self().interpreter(d->interpretername); 00471 if( ! interpreter ) { 00472 InterpreterInfo* info = Manager::self().interpreterInfo(d->interpretername); 00473 if( info ) 00474 setError(i18n("Failed to load interpreter \"%1\"", d->interpretername)); 00475 else 00476 setError(i18n("No such interpreter \"%1\"", d->interpretername)); 00477 return false; 00478 } 00479 00480 d->script = interpreter->createScript(this); 00481 if( ! d->script ) { 00482 setError(i18n("Failed to create script for interpreter \"%1\"", d->interpretername)); 00483 return false; 00484 } 00485 00486 if( d->script->hadError() ) { 00487 setError(d->script); 00488 finalize(); 00489 return false; 00490 } 00491 00492 clearError(); // clear old exception 00493 return true; 00494 } 00495 00496 void Action::finalize() 00497 { 00498 if( d->script ) 00499 emit finalized(this); 00500 delete d->script; 00501 d->script = 0; 00502 } 00503 00504 bool Action::isFinalized() const 00505 { 00506 return d->script == 0; 00507 } 00508 00509 void Action::slotTriggered() 00510 { 00511 #ifdef KROSS_ACTION_DEBUG 00512 krossdebug( QString("Action::slotTriggered() name=%1").arg(objectName()) ); 00513 #endif 00514 00515 emit started(this); 00516 00517 if( ! d->script ) { 00518 if( ! initialize() ) 00519 Q_ASSERT( hadError() ); 00520 } 00521 00522 if( hadError() ) { 00523 #ifdef KROSS_ACTION_DEBUG 00524 krossdebug( QString("Action::slotTriggered() on init, errorMessage=%2").arg(errorMessage()) ); 00525 #endif 00526 } 00527 else { 00528 d->script->execute(); 00529 if( d->script->hadError() ) { 00530 #ifdef KROSS_ACTION_DEBUG 00531 krossdebug( QString("Action::slotTriggered() after exec, errorMessage=%2").arg(errorMessage()) ); 00532 #endif 00533 setError(d->script); 00534 //emit finished(this); 00535 finalize(); 00536 //return; 00537 } 00538 } 00539 00540 emit finished(this); 00541 } 00542 00543 // -------- 00544 00545 // interface files 00546 WrapperInterface::~WrapperInterface() 00547 { 00548 } 00549 00550 #include "action.moc"
KDE 4.6 API Reference