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