Kross

action.cpp
1 /***************************************************************************
2  * action.cpp
3  * This file is part of the KDE project
4  * copyright (C)2004-2006 by Sebastian Sauer ([email protected])
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  * You should have received a copy of the GNU Library General Public License
15  * along with this program; see the file COPYING. If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  ***************************************************************************/
19 
20 #include "action.h"
21 #include "actioncollection.h"
22 #include "interpreter.h"
23 #include "script.h"
24 #include "manager.h"
25 #include "wrapperinterface.h"
26 #include "kross_debug.h"
27 
28 #include <QFile>
29 #include <QFileInfo>
30 
31 #include <klocalizedstring.h>
32 #include <qmimedatabase.h>
33 
34 using namespace Kross;
35 
36 namespace Kross
37 {
38 
40 class Action::Private
41 {
42 public:
43 
49  Script *script;
50 
55  int version;
56 
62 
66  QString iconname;
67 
72 
77  QString interpretername;
78 
85  QString scriptfile;
86 
92  QStringList searchpath;
93 
99 
100  Private() : script(nullptr), version(0) {}
101 };
102 
103 }
104 
105 enum InitOptions {Enable = 1};
106 void static init(Action *th, const QString &name, int options = 0)
107 {
108  th->setEnabled(options & Enable);
109  th->setObjectName(name);
110 #ifdef KROSS_ACTION_DEBUG
111  qCDebug(KROSS_LOG) << "Action::Action(QObject*,QString,QDir) Ctor name=" << th->objectName();
112 #endif
113  QObject::connect(th, SIGNAL(triggered(bool)), th, SLOT(slotTriggered()));
114 }
115 
116 Action::Action(QObject *parent, const QString &name, const QDir &packagepath)
117  : QAction(parent)
118  , QScriptable()
120  , ErrorInterface()
121  , d(new Private())
122 {
123  init(this, name);
124  d->searchpath = QStringList(packagepath.absolutePath());
125 }
126 
128  : QAction(parent)
130  , ErrorInterface()
131  , d(new Private())
132 {
133  init(this, url.path(), Enable);
134  QFileInfo fi(url.toLocalFile());
135  setText(fi.fileName());
136  QMimeDatabase db;
137  setIconName(db.mimeTypeForUrl(url).iconName());
138  setFile(url.toLocalFile());
139 }
140 
142 {
143 #ifdef KROSS_ACTION_DEBUG
144  qCDebug(KROSS_LOG) << QStringLiteral("Action::~Action() Dtor name='%1'").arg(objectName());
145 #endif
146  finalize();
148  if (coll) {
149  coll->removeAction(this);
150  }
151  delete d;
152 }
153 
155 {
156  fromDomElement(element, d->searchpath);
157 }
158 
159 void Action::fromDomElement(const QDomElement &element, const QStringList &searchPath)
160 {
161  if (element.isNull()) {
162  return;
163  }
164 
165  QString file = element.attribute("file");
166  if (! file.isEmpty()) {
167  if (QFileInfo(file).exists()) {
168  setFile(file);
169  } else {
170  foreach (const QString &packagepath, searchPath) {
171  QFileInfo fi(QDir(packagepath), file);
172  if (fi.exists()) {
174  break;
175  }
176  }
177  }
178  }
179 
180  d->version = QVariant(element.attribute("version", QString(d->version))).toInt();
181 
182  setText(i18nd(KLocalizedString::applicationDomain().constData(), element.attribute("text").toUtf8().constData()));
183  const QString comment = element.attribute("comment");
184  if (!comment.isEmpty()) {
186  }
187  setEnabled(true);
188  setInterpreter(element.attribute("interpreter"));
189  setEnabled(QVariant(element.attribute("enabled", "true")).toBool() && isEnabled());
190 
191  QString icon = element.attribute("icon");
192  if (icon.isEmpty() && ! d->scriptfile.isNull()) {
193  QMimeDatabase db;
194  icon = db.mimeTypeForUrl(QUrl::fromLocalFile(d->scriptfile)).iconName();
195  }
196  setIconName(icon);
197 
198  const QString code = element.attribute("code");
199  if (! code.isNull()) {
200  setCode(code.toUtf8());
201  }
202 
203  for (QDomNode node = element.firstChild(); ! node.isNull(); node = node.nextSibling()) {
204  QDomElement e = node.toElement();
205  if (! e.isNull()) {
206  if (e.tagName() == "property") {
207  const QString n = e.attribute("name", QString());
208  if (! n.isNull()) {
209 #ifdef KROSS_ACTION_DEBUG
210  qCDebug(KROSS_LOG) << "Action::readDomElement: Setting property name=" <<
211  n << " value=" << e.text();
212 #endif
214  }
215  }
216  }
217  }
218 }
219 
221 {
222  return toDomElement(QStringList());
223 }
224 
226 {
227  QDomDocument doc;
228  QDomElement e = doc.createElement("script");
229  e.setAttribute("name", objectName());
230  if (d->version > 0) {
231  e.setAttribute("version", QString(d->version));
232  }
233  if (! text().isNull()) {
234  e.setAttribute("text", text());
235  }
236  if (! description().isNull()) {
237  e.setAttribute("comment", description());
238  }
239  if (! iconName().isNull()) {
240  e.setAttribute("icon", iconName());
241  }
242  if (! isEnabled()) {
243  e.setAttribute("enabled", "false");
244  }
245  if (! interpreter().isNull()) {
246  e.setAttribute("interpreter", interpreter());
247  }
248 
249  QString fileName = file();
250  if (!searchPath.isEmpty()) {
251  //fileName=QDir(searchPath.first()).relativeFilePath(fileName); //prefer absname if it is short?
252  foreach (const QString &packagepath, searchPath) {
253  QString nfn = QDir(packagepath).relativeFilePath(file());
254  if (nfn.length() < fileName.length()) {
255  fileName = nfn;
256  }
257  }
258  }
259 
260  if (! fileName.isNull()) {
261  e.setAttribute("file", fileName);
262  }
263 
265  foreach (const QByteArray &prop, props) {
266  QDomElement p = doc.createElement("property");
267  p.setAttribute("name", QString::fromLatin1(prop));
268  p.appendChild(doc.createTextNode(property(prop.constData()).toString()));
269  e.appendChild(p);
270  }
271  /*
272  else if( ! code().isNull() ) {
273  e.setAttribute("code", code());
274  }
275  */
276 
277  return e;
278 }
279 
281 {
282  return d->script;
283 }
284 
286 {
287  return objectName();
288 }
289 
290 int Action::version() const
291 {
292  return d->version;
293 }
294 
296 {
297  return d->description;
298 }
299 
301 {
302  d->description = description;
303  emit dataChanged(this);
304  emit updated();
305 }
306 
308 {
309  return d->iconname;
310 }
311 
312 void Action::setIconName(const QString &iconname)
313 {
314  setIcon(QIcon::fromTheme(iconname));
315  d->iconname = iconname;
316  emit dataChanged(this);
317  emit updated();
318 }
319 
320 bool Action::isEnabled() const
321 {
322  return QAction::isEnabled();
323 }
324 
326 {
327  QAction::setEnabled(enabled);
328  emit dataChanged(this);
329  emit updated();
330 }
331 
333 {
334  return d->code;
335 }
336 
338 {
339  if (d->code != code) {
340  finalize();
341  d->code = code;
342  emit dataChanged(this);
343  emit updated();
344  }
345 }
346 
348 {
349  return d->interpretername;
350 }
351 
352 void Action::setInterpreter(const QString &interpretername)
353 {
354  if (d->interpretername != interpretername) {
355  finalize();
356  d->interpretername = interpretername;
357  setEnabled(Manager::self().interpreters().contains(interpretername));
358  if (!isEnabled()) {
359  qCWarning(KROSS_LOG) << "Action::setInterpreter: interpreter not found: " << interpretername;
360  }
361  emit dataChanged(this);
362  emit updated();
363  }
364 }
365 
367 {
368  return d->scriptfile;
369 }
370 
371 bool Action::setFile(const QString &scriptfile)
372 {
373  if (d->scriptfile != scriptfile) {
374  finalize();
375  if (scriptfile.isNull()) {
376  if (! d->scriptfile.isNull()) {
377  d->interpretername.clear();
378  }
379  d->scriptfile.clear();
380  d->searchpath.clear();
381  } else {
382  d->scriptfile = scriptfile;
383  d->interpretername = Manager::self().interpreternameForFile(scriptfile);
384  if (d->interpretername.isNull()) {
385  return false;
386  }
387  }
388  }
389  return true;
390 }
391 
393 {
394  return file().isEmpty() ? QString() : QFileInfo(file()).absolutePath(); //obey Qt docs and don't cheat
395 }
396 
397 QVariantMap Action::options() const
398 {
399  return d->options;
400 }
401 
402 void Action::addQObject(QObject *obj, const QString &name)
403 {
404  this->addObject(obj, name);
405 }
406 
407 QObject *Action::qobject(const QString &name) const
408 {
409  return this->object(name);
410 }
411 
413 {
414  return this->objects().keys();
415 }
416 
417 QVariant Action::option(const QString &name, const QVariant &defaultvalue)
418 {
419  if (d->options.contains(name)) {
420  return d->options[name];
421  }
422  InterpreterInfo *info = Manager::self().interpreterInfo(d->interpretername);
423  return info ? info->optionValue(name, defaultvalue) : defaultvalue;
424 }
425 
426 bool Action::setOption(const QString &name, const QVariant &value)
427 {
428  InterpreterInfo *info = Manager::self().interpreterInfo(d->interpretername);
429  if (info) {
430  if (info->hasOption(name)) {
431  d->options.insert(name, value);
432  return true;
433  } else {
434  qCWarning(KROSS_LOG) << QStringLiteral("Kross::Action::setOption(%1, %2): No such option")
435  .arg(name).arg(value.toString());
436  }
437  } else {
438  qCWarning(KROSS_LOG) << QStringLiteral("Kross::Action::setOption(%1, %2): No such interpreterinfo")
439  .arg(name).arg(value.toString());
440  }
441  return false;
442 }
443 
445 {
446  if (! d->script) {
447  if (! initialize()) {
448  return QStringList();
449  }
450  }
451  return d->script->functionNames();
452 }
453 
454 QVariant Action::callFunction(const QString &name, const QVariantList &args)
455 {
456  if (! d->script) {
457  if (! initialize()) {
458  return QVariant();
459  }
460  }
461  return d->script->callFunction(name, args);
462 }
463 
465 {
466  if (! d->script) {
467  if (! initialize()) {
468  return QVariant();
469  }
470  }
471  return d->script->evaluate(code);
472 }
473 
475 {
476  finalize();
477 
478  if (! d->scriptfile.isNull()) {
479  QFile f(d->scriptfile);
480  if (! f.exists()) {
481  setError(i18n("Scriptfile \"%1\" does not exist.", d->scriptfile));
482  return false;
483  }
484  if (d->interpretername.isNull()) {
485  setError(i18n("Failed to determine interpreter for scriptfile \"%1\"", d->scriptfile));
486  return false;
487  }
488  if (! f.open(QIODevice::ReadOnly)) {
489  setError(i18n("Failed to open scriptfile \"%1\"", d->scriptfile));
490  return false;
491  }
492  d->code = f.readAll();
493  f.close();
494  }
495 
496  Interpreter *interpreter = Manager::self().interpreter(d->interpretername);
497  if (! interpreter) {
498  InterpreterInfo *info = Manager::self().interpreterInfo(d->interpretername);
499  if (info) {
500  setError(i18n("Failed to load interpreter \"%1\"", d->interpretername));
501  } else {
502  setError(i18n("No such interpreter \"%1\"", d->interpretername));
503  }
504  return false;
505  }
506 
507  d->script = interpreter->createScript(this);
508  if (! d->script) {
509  setError(i18n("Failed to create script for interpreter \"%1\"", d->interpretername));
510  return false;
511  }
512 
513  if (d->script->hadError()) {
514  setError(d->script);
515  finalize();
516  return false;
517  }
518 
519  clearError(); // clear old exception
520  return true;
521 }
522 
524 {
525  if (d->script) {
526  emit finalized(this);
527  }
528  delete d->script;
529  d->script = nullptr;
530 }
531 
533 {
534  return d->script == nullptr;
535 }
536 
537 void Action::slotTriggered()
538 {
539 #ifdef KROSS_ACTION_DEBUG
540  qCDebug(KROSS_LOG) << "Action::slotTriggered() name=" << objectName();
541 #endif
542 
543  emit started(this);
544 
545  if (! d->script) {
546  if (! initialize()) {
547  Q_ASSERT(hadError());
548  }
549  }
550 
551  if (hadError()) {
552 #ifdef KROSS_ACTION_DEBUG
553  qCDebug(KROSS_LOG) << "Action::slotTriggered() on init, errorMessage=" << errorMessage();
554 #endif
555  } else {
556  d->script->execute();
557  if (d->script->hadError()) {
558 #ifdef KROSS_ACTION_DEBUG
559  qCDebug(KROSS_LOG) << "Action::slotTriggered() after exec, errorMessage=" << errorMessage();
560 #endif
561  setError(d->script);
562  //emit finished(this);
563  finalize();
564  //return;
565  }
566  }
567 
568  emit finished(this);
569 }
570 
571 // --------
572 
573 // interface files
575 {
576 }
577 
bool initialize()
Initialize the Script instance.
Definition: action.cpp:474
void setText(const QString &text)
bool hadError() const
void triggered(bool checked)
void setEnabled(bool enabled)
Set the enable state of this Action to enabled .
Definition: action.cpp:325
QString relativeFilePath(const QString &fileName) const const
void addObject(QObject *object, const QString &name=QString(), Options options=NoOption)
Add a QObject to the list of children.
QString description() const
Definition: action.cpp:295
QVariant option(const QString &name, const QVariant &defaultvalue=QVariant())
Definition: action.cpp:417
Base class for interpreter dependent functionality each script provides.
Definition: core/script.h:44
Interface for error-handling.
QDomNode appendChild(const QDomNode &newChild)
QString attribute(const QString &name, const QString &defValue) const const
Definition: action.cpp:36
QObject * qobject(const QString &name) const
Definition: action.cpp:407
virtual ~Action()
Destructor.
Definition: action.cpp:141
void started(Kross::Action *)
This signal is emitted before the script got executed.
QIcon icon() const const
QDomElement toDomElement() const
Definition: action.cpp:220
QString iconName() const
Return the name of the icon.
Definition: action.cpp:307
QString file() const
Definition: action.cpp:366
void updated()
This signal is emitted if the content of the Action was changed.
QVariant callFunction(const QString &name, const QVariantList &args=QVariantList())
Call a function in the script.
Definition: action.cpp:454
InterpreterInfo * interpreterInfo(const QString &interpretername) const
Definition: manager.cpp:244
bool exists() const const
Action(QObject *parent, const QString &name, const QDir &packagepath=QDir())
Constructor.
Definition: action.cpp:116
QString interpreter() const
Definition: action.cpp:347
QString name() const
Definition: action.cpp:285
bool isNull() const const
The InterpreterInfo class provides abstract information about a Interpreter before the interpreter-ba...
QHash< QString, QObject * > objects() const
bool hasOption(const QString &name) const
QDomElement toElement() const const
const QString errorMessage() const
void setDescription(const QString &description)
Set the optional description for this Action.
Definition: action.cpp:300
void dataChanged(Action *)
This signal is emitted when the data of the Action is changed.
QVariant property(const char *name) const const
QString text() const const
virtual Script * createScript(Action *Action)=0
Create and return a new interpreter dependent Script instance.
QMimeType mimeTypeForUrl(const QUrl &url) const const
void setAttribute(const QString &name, const QString &value)
void clearError()
Clear the error.
Script * script() const
Definition: action.cpp:280
bool isEmpty() const const
void setObjectName(const QString &name)
QString absoluteFilePath() const const
bool isEmpty() const const
const char * constData() const const
Interface for managing Object collections.
static QByteArray applicationDomain()
QByteArray readAll()
QByteArray code() const
Definition: action.cpp:332
QString path(QUrl::ComponentFormattingOptions options) const const
const QString interpreternameForFile(const QString &file)
Return the name of the Interpreter that feels responsible for the defined file .
Definition: manager.cpp:249
const QVariant optionValue(const QString &name, const QVariant &defaultvalue=QVariant()) const
QVariantMap options() const
Definition: action.cpp:397
void finalized(Kross::Action *)
This signal is emitted once a script finalized.
void fromDomElement(const QDomElement &element)
Method to read settings from the QDomElement element that contains details about e.g.
Definition: action.cpp:154
Base class for interpreter implementations.
virtual bool open(QIODevice::OpenMode mode) override
QList< Key > keys() const const
QString toLocalFile() const const
QDomText createTextNode(const QString &value)
Interpreter * interpreter(const QString &interpretername) const
Return the Interpreter instance defined by the interpretername.
Definition: manager.cpp:267
bool exists() const const
QCA_EXPORT void init()
bool isNull() const const
QObject * object(const QString &name) const
QVariant evaluate(const QByteArray &code)
Evaluate some scripting code.
Definition: action.cpp:464
QString i18n(const char *text, const TYPE &arg...)
void finished(Kross::Action *)
This signal is emitted after the script got executed.
bool setFile(const QString &scriptfile)
Set the script file that should be executed.
Definition: action.cpp:371
QDomNode firstChild() const const
QByteArray toLatin1() const const
static Manager & self()
Return the Manager instance.
Definition: manager.cpp:74
QStringList qobjectNames() const
Definition: action.cpp:412
void setError(const QString &errormessage, const QString &tracemessage=QString(), long lineno=-1)
Set the error message.
QString absolutePath() const const
virtual void close() override
void finalize()
Finalize the Script instance and frees any cached or still running executions.
Definition: action.cpp:523
void setInterpreter(const QString &interpretername)
Set the name of the interpreter (javascript, python or ruby).
Definition: action.cpp:352
bool isEnabled() const
Return true if this Action is enabled else false is returned.
Definition: action.cpp:320
void setCode(const QByteArray &code)
Set the scriptcode code this Action should execute.
Definition: action.cpp:337
int length() const const
QString fromLatin1(const char *str, int size)
QIcon fromTheme(const QString &name)
bool setProperty(const char *name, const QVariant &value)
bool isFinalized() const
Definition: action.cpp:532
QString tagName() const const
The Action class is an abstract container to deal with scripts like a single standalone script file...
Definition: action.h:95
int version() const
Definition: action.cpp:290
QString currentPath() const
Definition: action.cpp:392
QList< QByteArray > dynamicPropertyNames() const const
QDomElement createElement(const QString &tagName)
QString i18nd(const char *domain, const char *text, const TYPE &arg...)
The ActionCollection class manages collections of Action instances.
QString absolutePath() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
T qobject_cast(QObject *object)
QObject * parent() const const
QString toString() const const
QStringList functionNames()
Definition: action.cpp:444
bool isEnabled() const const
virtual ~WrapperInterface()
Destructor.
Definition: action.cpp:574
QUrl fromLocalFile(const QString &localFile)
void addQObject(QObject *obj, const QString &name=QString())
Add a QObject instance to the action.
Definition: action.cpp:402
bool setOption(const QString &name, const QVariant &value)
Set the Interpreter::Option value.
Definition: action.cpp:426
void setIconName(const QString &iconname)
Set the name of the icon to iconname .
Definition: action.cpp:312
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Wed Aug 5 2020 22:56:58 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.