00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "action.h"
00021 #include "interpreter.h"
00022 #include "script.h"
00023 #include "manager.h"
00024
00025 #include <QtCore/QFile>
00026 #include <QtCore/QFileInfo>
00027
00028 #include <klocale.h>
00029 #include <kicon.h>
00030 #include <kmimetype.h>
00031
00032 using namespace Kross;
00033
00034 namespace Kross {
00035
00037 class Action::Private
00038 {
00039 public:
00040
00046 Script* script;
00047
00052 int version;
00053
00058 QString description;
00059
00063 QString iconname;
00064
00068 QByteArray code;
00069
00074 QString interpretername;
00075
00082 QString scriptfile;
00083
00088 QString currentpath;
00089
00094 QMap< QString, QVariant > options;
00095
00096 Private() : script(0), version(0) {}
00097 };
00098
00099 }
00100
00101 Action::Action(QObject* parent, const QString& name, const QDir& packagepath)
00102 : QAction(parent)
00103 , QScriptable()
00104 , ChildrenInterface()
00105 , ErrorInterface()
00106 , d( new Private() )
00107 {
00108 setObjectName(name);
00109 #ifdef KROSS_ACTION_DEBUG
00110 krossdebug( QString("Action::Action(QObject*,QString,QDir) Ctor name='%1'").arg(objectName()) );
00111 #endif
00112 setEnabled( false );
00113 d->currentpath = packagepath.absolutePath();
00114 connect(this, SIGNAL(triggered(bool)), this, SLOT(slotTriggered()));
00115 }
00116
00117 Action::Action(QObject* parent, const QUrl& url)
00118 : QAction(parent)
00119 , ChildrenInterface()
00120 , ErrorInterface()
00121 , d( new Private() )
00122 {
00123 setObjectName( url.path() );
00124 #ifdef KROSS_ACTION_DEBUG
00125 krossdebug( QString("Action::Action(QObject*,QUrl) Ctor name='%1'").arg(objectName()) );
00126 #endif
00127 QFileInfo fi( url.path() );
00128 setText( fi.fileName() );
00129 setIconName( KMimeType::iconNameForUrl(url) );
00130 setFile( url.path() );
00131 connect(this, SIGNAL(triggered(bool)), this, SLOT(slotTriggered()));
00132 }
00133
00134 Action::~Action()
00135 {
00136 #ifdef KROSS_ACTION_DEBUG
00137 krossdebug( QString("Action::~Action() Dtor name='%1'").arg(objectName()) );
00138 #endif
00139 finalize();
00140 delete d;
00141 }
00142
00143 void Action::fromDomElement(const QDomElement& element)
00144 {
00145 if( element.isNull() )
00146 return;
00147
00148 QDir packagepath( d->currentpath );
00149 QString file = element.attribute("file");
00150 if( ! file.isEmpty() ) {
00151 if( QFileInfo(file).exists() ) {
00152 setFile(file);
00153 }
00154 else {
00155 QFileInfo fi(packagepath, file);
00156 if( fi.exists() )
00157 setFile( fi.absoluteFilePath() );
00158 }
00159 }
00160
00161 d->version = QVariant( element.attribute("version",QString(d->version)) ).toInt();
00162
00163 setText( element.attribute("text") );
00164 setDescription( element.attribute("comment") );
00165 setEnabled( true );
00166 setInterpreter( element.attribute("interpreter") );
00167 setEnabled( QVariant(element.attribute("enabled","true")).toBool() && isEnabled() );
00168
00169 QString icon = element.attribute("icon");
00170 if( icon.isEmpty() && ! d->scriptfile.isNull() )
00171 icon = KMimeType::iconNameForUrl( KUrl(d->scriptfile) );
00172 setIconName( icon );
00173
00174 const QString code = element.attribute("code");
00175 if( ! code.isNull() )
00176 setCode(code.toUtf8());
00177
00178 for(QDomNode node = element.firstChild(); ! node.isNull(); node = node.nextSibling()) {
00179 QDomElement e = node.toElement();
00180 if( ! e.isNull() ) {
00181 if( e.tagName() == "property" ) {
00182 const QString n = e.attribute("name", QString());
00183 if( ! n.isNull() ) {
00184 #ifdef KROSS_ACTION_DEBUG
00185 krossdebug(QString("Action::readDomElement: Setting property name=%1 value=%2").arg(n).arg(e.text()));
00186 #endif
00187 setProperty(n.toLatin1().constData(), QVariant(e.text()));
00188 }
00189 }
00190 }
00191 }
00192 }
00193
00194 QDomElement Action::toDomElement() const
00195 {
00196 QDomDocument doc;
00197 QDomElement e = doc.createElement("script");
00198 e.setAttribute("name", objectName());
00199 if( d->version > 0 )
00200 e.setAttribute("version", QString(d->version));
00201 if( ! text().isNull() )
00202 e.setAttribute("text", text());
00203 if( ! description().isNull() )
00204 e.setAttribute("comment", description());
00205 if( ! iconName().isNull() )
00206 e.setAttribute("icon", iconName());
00207 if( ! isEnabled() )
00208 e.setAttribute("enabled", "false");
00209 if( ! interpreter().isNull() )
00210 e.setAttribute("interpreter", interpreter());
00211
00212 if( ! file().isNull() ) {
00213 e.setAttribute("file", file());
00214 }
00215
00216
00217
00218
00219
00220
00221 return e;
00222 }
00223
00224 Kross::Script* Action::script() const
00225 {
00226 return d->script;
00227 }
00228
00229 QString Action::name() const
00230 {
00231 return objectName();
00232 }
00233
00234 int Action::version() const
00235 {
00236 return d->version;
00237 }
00238
00239 QString Action::description() const
00240 {
00241 return d->description;
00242 }
00243
00244 void Action::setDescription(const QString& description)
00245 {
00246 d->description = description;
00247 emit updated();
00248 }
00249
00250 QString Action::iconName() const
00251 {
00252 return d->iconname;
00253 }
00254
00255 void Action::setIconName(const QString& iconname)
00256 {
00257 setIcon( KIcon(iconname) );
00258 d->iconname = iconname;
00259 emit updated();
00260 }
00261
00262 bool Action::isEnabled() const
00263 {
00264 return QAction::isEnabled();
00265 }
00266
00267 void Action::setEnabled(bool enabled)
00268 {
00269 QAction::setEnabled(enabled);
00270 emit updated();
00271 }
00272
00273 QByteArray Action::code() const
00274 {
00275 return d->code;
00276 }
00277
00278 void Action::setCode(const QByteArray& code)
00279 {
00280 if( d->code != code ) {
00281 finalize();
00282 d->code = code;
00283 emit updated();
00284 }
00285 }
00286
00287 QString Action::interpreter() const
00288 {
00289 return d->interpretername;
00290 }
00291
00292 void Action::setInterpreter(const QString& interpretername)
00293 {
00294 if( d->interpretername != interpretername ) {
00295 finalize();
00296 d->interpretername = interpretername;
00297 setEnabled( Manager::self().interpreters().contains(interpretername) );
00298 emit updated();
00299 }
00300 }
00301
00302 QString Action::file() const
00303 {
00304 return d->scriptfile;
00305 }
00306
00307 bool Action::setFile(const QString& scriptfile)
00308 {
00309 if( d->scriptfile != scriptfile ) {
00310 finalize();
00311 if ( scriptfile.isNull() ) {
00312 if( ! d->scriptfile.isNull() )
00313 d->interpretername.clear();
00314 d->scriptfile.clear();
00315 d->currentpath.clear();
00316 }
00317 else {
00318 d->scriptfile = scriptfile;
00319 d->currentpath = QFileInfo(scriptfile).absolutePath();
00320 d->interpretername = Manager::self().interpreternameForFile(scriptfile);
00321 if( d->interpretername.isNull() )
00322 return false;
00323 }
00324 }
00325 return true;
00326 }
00327
00328 QString Action::currentPath() const
00329 {
00330 return d->currentpath;
00331 }
00332
00333 QVariantMap Action::options() const
00334 {
00335 return d->options;
00336 }
00337
00338 void Action::addQObject(QObject* obj, const QString &name)
00339 {
00340 this->addObject(obj, name);
00341 }
00342
00343 QObject* Action::qobject(const QString &name) const
00344 {
00345 return this->object(name);
00346 }
00347
00348 QStringList Action::qobjectNames() const
00349 {
00350 return this->objects().keys();
00351 }
00352
00353 QVariant Action::option(const QString& name, const QVariant& defaultvalue)
00354 {
00355 if(d->options.contains(name))
00356 return d->options[name];
00357 InterpreterInfo* info = Manager::self().interpreterInfo( d->interpretername );
00358 return info ? info->optionValue(name, defaultvalue) : defaultvalue;
00359 }
00360
00361 bool Action::setOption(const QString& name, const QVariant& value)
00362 {
00363 InterpreterInfo* info = Manager::self().interpreterInfo( d->interpretername );
00364 if(info) {
00365 if(info->hasOption(name)) {
00366 d->options.insert(name, value);
00367 return true;
00368 } else krosswarning( QString("Kross::Action::setOption(%1, %2): No such option").arg(name).arg(value.toString()) );
00369 } else krosswarning( QString("Kross::Action::setOption(%1, %2): No such interpreterinfo").arg(name).arg(value.toString()) );
00370 return false;
00371 }
00372
00373 QStringList Action::functionNames()
00374 {
00375 if(! d->script) {
00376 if(! initialize())
00377 return QStringList();
00378 }
00379 return d->script->functionNames();
00380 }
00381
00382 QVariant Action::callFunction(const QString& name, const QVariantList& args)
00383 {
00384 if(! d->script) {
00385 if(! initialize())
00386 return QVariant();
00387 }
00388 return d->script->callFunction(name, args);
00389 }
00390
00391 bool Action::initialize()
00392 {
00393 finalize();
00394
00395 if( ! d->scriptfile.isNull() ) {
00396 QFile f( d->scriptfile );
00397 if( ! f.exists() ) {
00398 setError(i18n("Scriptfile \"%1\" does not exist.", d->scriptfile));
00399 return false;
00400 }
00401 if( d->interpretername.isNull() ) {
00402 setError(i18n("Failed to determine interpreter for scriptfile \"%1\"", d->scriptfile));
00403 return false;
00404 }
00405 if( ! f.open(QIODevice::ReadOnly) ) {
00406 setError(i18n("Failed to open scriptfile \"%1\"", d->scriptfile));
00407 return false;
00408 }
00409 d->code = f.readAll();
00410 f.close();
00411 }
00412
00413 Interpreter* interpreter = Manager::self().interpreter(d->interpretername);
00414 if( ! interpreter ) {
00415 InterpreterInfo* info = Manager::self().interpreterInfo(d->interpretername);
00416 if( info )
00417 setError(i18n("Failed to load interpreter \"%1\"", d->interpretername));
00418 else
00419 setError(i18n("No such interpreter \"%1\"", d->interpretername));
00420 return false;
00421 }
00422
00423 d->script = interpreter->createScript(this);
00424 if( ! d->script ) {
00425 setError(i18n("Failed to create script for interpreter \"%1\"", d->interpretername));
00426 return false;
00427 }
00428
00429 if( d->script->hadError() ) {
00430 setError(d->script);
00431 finalize();
00432 return false;
00433 }
00434
00435 clearError();
00436 return true;
00437 }
00438
00439 void Action::finalize()
00440 {
00441 if( d->script )
00442 emit finalized(this);
00443 delete d->script;
00444 d->script = 0;
00445 }
00446
00447 bool Action::isFinalized() const
00448 {
00449 return d->script == 0;
00450 }
00451
00452 void Action::slotTriggered()
00453 {
00454 #ifdef KROSS_ACTION_DEBUG
00455 krossdebug( QString("Action::slotTriggered() name=%1").arg(objectName()) );
00456 #endif
00457
00458 emit started(this);
00459
00460 if( ! d->script ) {
00461 if( ! initialize() )
00462 Q_ASSERT( hadError() );
00463 }
00464
00465 if( hadError() ) {
00466 #ifdef KROSS_ACTION_DEBUG
00467 krossdebug( QString("Action::slotTriggered() on init, errorMessage=%2").arg(errorMessage()) );
00468 #endif
00469 }
00470 else {
00471 d->script->execute();
00472 if( d->script->hadError() ) {
00473 #ifdef KROSS_ACTION_DEBUG
00474 krossdebug( QString("Action::slotTriggered() after exec, errorMessage=%2").arg(errorMessage()) );
00475 #endif
00476 setError(d->script);
00477
00478 finalize();
00479
00480 }
00481 }
00482
00483 emit finished(this);
00484 }
00485
00486 #include "action.moc"