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