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