mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 10:52:49 +00:00

for compatibilty reasons automoc4 support is not removed but it shall be in the future. automoc4 has not been maintained for a while (last commit is from 2011) and the stable release is from 2009. CMake version >= 2.8.6 provides the functionality for mocking so I see no reason to not make use of it.
550 lines
15 KiB
C++
550 lines
15 KiB
C++
/***************************************************************************
|
|
* action.cpp
|
|
* This file is part of the KDE project
|
|
* copyright (C)2004-2006 by Sebastian Sauer (mail@dipe.org)
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
* You should have received a copy of the GNU Library General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
***************************************************************************/
|
|
|
|
#include "action.h"
|
|
#include "actioncollection.h"
|
|
#include "interpreter.h"
|
|
#include "script.h"
|
|
#include "manager.h"
|
|
#include "wrapperinterface.h"
|
|
|
|
#include <QtCore/QFile>
|
|
#include <QtCore/QFileInfo>
|
|
|
|
#include <klocale.h>
|
|
#include <kicon.h>
|
|
#include <kmimetype.h>
|
|
|
|
using namespace Kross;
|
|
|
|
namespace Kross {
|
|
|
|
/// \internal d-pointer class.
|
|
class Action::Private
|
|
{
|
|
public:
|
|
|
|
/**
|
|
* The \a Script instance the \a Action uses if initialized. It will
|
|
* be NULL as long as we didn't initialized it what will be done on
|
|
* demand.
|
|
*/
|
|
Script* script;
|
|
|
|
/**
|
|
* The version number this \a Action has. Those version number got
|
|
* used internaly to deal with different releases of scripts.
|
|
*/
|
|
int version;
|
|
|
|
/**
|
|
* The optional description to provide some more details about the
|
|
* Action to the user.
|
|
*/
|
|
QString description;
|
|
|
|
/**
|
|
* The name of the icon.
|
|
*/
|
|
QString iconname;
|
|
|
|
/**
|
|
* The scripting code.
|
|
*/
|
|
QByteArray code;
|
|
|
|
/**
|
|
* The name of the interpreter. This could be something
|
|
* like for example "python" for the python binding.
|
|
*/
|
|
QString interpretername;
|
|
|
|
/**
|
|
* The name of the scriptfile that should be executed. Those
|
|
* scriptfile will be readed and the content will be used to
|
|
* set the scripting code and, if not defined, the used
|
|
* interpreter.
|
|
*/
|
|
QString scriptfile;
|
|
|
|
/**
|
|
* The path list where the \a Script may be located.
|
|
* \todo after BIC break: don't keep it all the time,
|
|
* as it is now passed to [to|from]DomElement
|
|
*/
|
|
QStringList searchpath;
|
|
|
|
/**
|
|
* Map of options that overwritte the \a InterpreterInfo::Option::Map
|
|
* standard options.
|
|
*/
|
|
QMap< QString, QVariant > options;
|
|
|
|
Private() : script(0), version(0) {}
|
|
};
|
|
|
|
}
|
|
|
|
enum InitOptions{Enable=1};
|
|
void static init(Action* th, const QString& name, int options=0)
|
|
{
|
|
th->setEnabled(options&Enable);
|
|
th->setObjectName(name);
|
|
#ifdef KROSS_ACTION_DEBUG
|
|
krossdebug( QString("Action::Action(QObject*,QString,QDir) Ctor name='%1'").arg(th->objectName()) );
|
|
#endif
|
|
QObject::connect(th, SIGNAL(triggered(bool)), th, SLOT(slotTriggered()));
|
|
}
|
|
|
|
Action::Action(QObject* parent, const QString& name, const QDir& packagepath)
|
|
: QAction(parent)
|
|
, QScriptable()
|
|
, ChildrenInterface()
|
|
, ErrorInterface()
|
|
, d( new Private() )
|
|
{
|
|
init(this,name);
|
|
d->searchpath=QStringList(packagepath.absolutePath());
|
|
}
|
|
|
|
Action::Action(QObject* parent, const QUrl& url)
|
|
: QAction(parent)
|
|
, ChildrenInterface()
|
|
, ErrorInterface()
|
|
, d( new Private() )
|
|
{
|
|
init(this,url.path(),Enable);
|
|
QFileInfo fi( url.toLocalFile() );
|
|
setText( fi.fileName() );
|
|
setIconName( KMimeType::iconNameForUrl(url) );
|
|
setFile( url.toLocalFile() );
|
|
}
|
|
|
|
Action::~Action()
|
|
{
|
|
#ifdef KROSS_ACTION_DEBUG
|
|
krossdebug( QString("Action::~Action() Dtor name='%1'").arg(objectName()) );
|
|
#endif
|
|
finalize();
|
|
ActionCollection *coll = qobject_cast<ActionCollection*>(parent());
|
|
if ( coll ) {
|
|
coll->removeAction(this);
|
|
}
|
|
delete d;
|
|
}
|
|
|
|
|
|
void Action::fromDomElement(const QDomElement& element)
|
|
{
|
|
fromDomElement(element, d->searchpath);
|
|
}
|
|
|
|
void Action::fromDomElement(const QDomElement& element, const QStringList& searchPath)
|
|
{
|
|
if( element.isNull() )
|
|
return;
|
|
|
|
QString file = element.attribute("file");
|
|
if( ! file.isEmpty() ) {
|
|
if( QFileInfo(file).exists() ) {
|
|
setFile(file);
|
|
}
|
|
else {
|
|
foreach (const QString& packagepath, searchPath) {
|
|
QFileInfo fi(QDir(packagepath), file);
|
|
if( fi.exists() ) {
|
|
setFile( fi.absoluteFilePath() );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
d->version = QVariant( element.attribute("version",QString(d->version)) ).toInt();
|
|
|
|
setText( i18n( element.attribute("text").toUtf8() ) );
|
|
setDescription( i18n( element.attribute("comment").toUtf8() ) );
|
|
setEnabled( true );
|
|
setInterpreter( element.attribute("interpreter") );
|
|
setEnabled( QVariant(element.attribute("enabled","true")).toBool() && isEnabled() );
|
|
|
|
QString icon = element.attribute("icon");
|
|
if( icon.isEmpty() && ! d->scriptfile.isNull() )
|
|
icon = KMimeType::iconNameForUrl( KUrl(d->scriptfile) );
|
|
setIconName( icon );
|
|
|
|
const QString code = element.attribute("code");
|
|
if( ! code.isNull() )
|
|
setCode(code.toUtf8());
|
|
|
|
for(QDomNode node = element.firstChild(); ! node.isNull(); node = node.nextSibling()) {
|
|
QDomElement e = node.toElement();
|
|
if( ! e.isNull() ) {
|
|
if( e.tagName() == "property" ) {
|
|
const QString n = e.attribute("name", QString());
|
|
if( ! n.isNull() ) {
|
|
#ifdef KROSS_ACTION_DEBUG
|
|
krossdebug(QString("Action::readDomElement: Setting property name=%1 value=%2").arg(n).arg(e.text()));
|
|
#endif
|
|
setProperty(n.toLatin1().constData(), QVariant(e.text()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
QDomElement Action::toDomElement() const
|
|
{
|
|
return toDomElement(QStringList());
|
|
}
|
|
|
|
QDomElement Action::toDomElement(const QStringList& searchPath) const
|
|
{
|
|
QDomDocument doc;
|
|
QDomElement e = doc.createElement("script");
|
|
e.setAttribute("name", objectName());
|
|
if( d->version > 0 )
|
|
e.setAttribute("version", QString(d->version));
|
|
if( ! text().isNull() )
|
|
e.setAttribute("text", text());
|
|
if( ! description().isNull() )
|
|
e.setAttribute("comment", description());
|
|
if( ! iconName().isNull() )
|
|
e.setAttribute("icon", iconName());
|
|
if( ! isEnabled() )
|
|
e.setAttribute("enabled", "false");
|
|
if( ! interpreter().isNull() )
|
|
e.setAttribute("interpreter", interpreter());
|
|
|
|
|
|
QString fileName=file();
|
|
if (!searchPath.isEmpty()) {
|
|
//fileName=QDir(searchPath.first()).relativeFilePath(fileName); //prefer absname if it is short?
|
|
foreach(const QString& packagepath, searchPath) {
|
|
QString nfn=QDir(packagepath).relativeFilePath(file());
|
|
if (nfn.length()<fileName.length())
|
|
fileName=nfn;
|
|
}
|
|
}
|
|
|
|
if( ! fileName.isNull() ) {
|
|
e.setAttribute("file", fileName);
|
|
}
|
|
|
|
QList<QByteArray> props=dynamicPropertyNames();
|
|
foreach(const QByteArray& prop, props) {
|
|
QDomElement p = doc.createElement("property");
|
|
p.setAttribute("name", QString::fromLatin1(prop));
|
|
p.appendChild(doc.createTextNode(property(prop.constData()).toString()));
|
|
e.appendChild(p);
|
|
}
|
|
/*
|
|
else if( ! code().isNull() ) {
|
|
e.setAttribute("code", code());
|
|
}
|
|
*/
|
|
|
|
return e;
|
|
}
|
|
|
|
Kross::Script* Action::script() const
|
|
{
|
|
return d->script;
|
|
}
|
|
|
|
QString Action::name() const
|
|
{
|
|
return objectName();
|
|
}
|
|
|
|
int Action::version() const
|
|
{
|
|
return d->version;
|
|
}
|
|
|
|
QString Action::description() const
|
|
{
|
|
return d->description;
|
|
}
|
|
|
|
void Action::setDescription(const QString& description)
|
|
{
|
|
d->description = description;
|
|
emit dataChanged(this);
|
|
emit updated();
|
|
}
|
|
|
|
QString Action::iconName() const
|
|
{
|
|
return d->iconname;
|
|
}
|
|
|
|
void Action::setIconName(const QString& iconname)
|
|
{
|
|
setIcon( KIcon(iconname) );
|
|
d->iconname = iconname;
|
|
emit dataChanged(this);
|
|
emit updated();
|
|
}
|
|
|
|
bool Action::isEnabled() const
|
|
{
|
|
return QAction::isEnabled();
|
|
}
|
|
|
|
void Action::setEnabled(bool enabled)
|
|
{
|
|
QAction::setEnabled(enabled);
|
|
emit dataChanged(this);
|
|
emit updated();
|
|
}
|
|
|
|
QByteArray Action::code() const
|
|
{
|
|
return d->code;
|
|
}
|
|
|
|
void Action::setCode(const QByteArray& code)
|
|
{
|
|
if( d->code != code ) {
|
|
finalize();
|
|
d->code = code;
|
|
emit dataChanged(this);
|
|
emit updated();
|
|
}
|
|
}
|
|
|
|
QString Action::interpreter() const
|
|
{
|
|
return d->interpretername;
|
|
}
|
|
|
|
void Action::setInterpreter(const QString& interpretername)
|
|
{
|
|
if( d->interpretername != interpretername ) {
|
|
finalize();
|
|
d->interpretername = interpretername;
|
|
setEnabled( Manager::self().interpreters().contains(interpretername) );
|
|
if (!isEnabled())
|
|
krosswarning("Action::setInterpreter: interpreter not found: "+interpretername);
|
|
emit dataChanged(this);
|
|
emit updated();
|
|
}
|
|
}
|
|
|
|
QString Action::file() const
|
|
{
|
|
return d->scriptfile;
|
|
}
|
|
|
|
bool Action::setFile(const QString& scriptfile)
|
|
{
|
|
if( d->scriptfile != scriptfile ) {
|
|
finalize();
|
|
if ( scriptfile.isNull() ) {
|
|
if( ! d->scriptfile.isNull() )
|
|
d->interpretername.clear();
|
|
d->scriptfile.clear();
|
|
d->searchpath.clear();
|
|
}
|
|
else {
|
|
d->scriptfile = scriptfile;
|
|
d->interpretername = Manager::self().interpreternameForFile(scriptfile);
|
|
if( d->interpretername.isNull() )
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
QString Action::currentPath() const
|
|
{
|
|
return file().isEmpty()?QString():QFileInfo(file()).absolutePath();//obey Qt docs and don't cheat
|
|
}
|
|
|
|
QVariantMap Action::options() const
|
|
{
|
|
return d->options;
|
|
}
|
|
|
|
void Action::addQObject(QObject* obj, const QString &name)
|
|
{
|
|
this->addObject(obj, name);
|
|
}
|
|
|
|
QObject* Action::qobject(const QString &name) const
|
|
{
|
|
return this->object(name);
|
|
}
|
|
|
|
QStringList Action::qobjectNames() const
|
|
{
|
|
return this->objects().keys();
|
|
}
|
|
|
|
QVariant Action::option(const QString& name, const QVariant& defaultvalue)
|
|
{
|
|
if(d->options.contains(name))
|
|
return d->options[name];
|
|
InterpreterInfo* info = Manager::self().interpreterInfo( d->interpretername );
|
|
return info ? info->optionValue(name, defaultvalue) : defaultvalue;
|
|
}
|
|
|
|
bool Action::setOption(const QString& name, const QVariant& value)
|
|
{
|
|
InterpreterInfo* info = Manager::self().interpreterInfo( d->interpretername );
|
|
if(info) {
|
|
if(info->hasOption(name)) {
|
|
d->options.insert(name, value);
|
|
return true;
|
|
} else krosswarning( QString("Kross::Action::setOption(%1, %2): No such option").arg(name).arg(value.toString()) );
|
|
} else krosswarning( QString("Kross::Action::setOption(%1, %2): No such interpreterinfo").arg(name).arg(value.toString()) );
|
|
return false;
|
|
}
|
|
|
|
QStringList Action::functionNames()
|
|
{
|
|
if(! d->script) {
|
|
if(! initialize())
|
|
return QStringList();
|
|
}
|
|
return d->script->functionNames();
|
|
}
|
|
|
|
QVariant Action::callFunction(const QString& name, const QVariantList& args)
|
|
{
|
|
if(! d->script) {
|
|
if(! initialize())
|
|
return QVariant();
|
|
}
|
|
return d->script->callFunction(name, args);
|
|
}
|
|
|
|
QVariant Action::evaluate(const QByteArray& code)
|
|
{
|
|
if(! d->script) {
|
|
if(! initialize())
|
|
return QVariant();
|
|
}
|
|
return d->script->evaluate(code);
|
|
}
|
|
|
|
bool Action::initialize()
|
|
{
|
|
finalize();
|
|
|
|
if( ! d->scriptfile.isNull() ) {
|
|
QFile f( d->scriptfile );
|
|
if( ! f.exists() ) {
|
|
setError(i18n("Scriptfile \"%1\" does not exist.", d->scriptfile));
|
|
return false;
|
|
}
|
|
if( d->interpretername.isNull() ) {
|
|
setError(i18n("Failed to determine interpreter for scriptfile \"%1\"", d->scriptfile));
|
|
return false;
|
|
}
|
|
if( ! f.open(QIODevice::ReadOnly) ) {
|
|
setError(i18n("Failed to open scriptfile \"%1\"", d->scriptfile));
|
|
return false;
|
|
}
|
|
d->code = f.readAll();
|
|
f.close();
|
|
}
|
|
|
|
Interpreter* interpreter = Manager::self().interpreter(d->interpretername);
|
|
if( ! interpreter ) {
|
|
InterpreterInfo* info = Manager::self().interpreterInfo(d->interpretername);
|
|
if( info )
|
|
setError(i18n("Failed to load interpreter \"%1\"", d->interpretername));
|
|
else
|
|
setError(i18n("No such interpreter \"%1\"", d->interpretername));
|
|
return false;
|
|
}
|
|
|
|
d->script = interpreter->createScript(this);
|
|
if( ! d->script ) {
|
|
setError(i18n("Failed to create script for interpreter \"%1\"", d->interpretername));
|
|
return false;
|
|
}
|
|
|
|
if( d->script->hadError() ) {
|
|
setError(d->script);
|
|
finalize();
|
|
return false;
|
|
}
|
|
|
|
clearError(); // clear old exception
|
|
return true;
|
|
}
|
|
|
|
void Action::finalize()
|
|
{
|
|
if( d->script )
|
|
emit finalized(this);
|
|
delete d->script;
|
|
d->script = 0;
|
|
}
|
|
|
|
bool Action::isFinalized() const
|
|
{
|
|
return d->script == 0;
|
|
}
|
|
|
|
void Action::slotTriggered()
|
|
{
|
|
#ifdef KROSS_ACTION_DEBUG
|
|
krossdebug( QString("Action::slotTriggered() name=%1").arg(objectName()) );
|
|
#endif
|
|
|
|
emit started(this);
|
|
|
|
if( ! d->script ) {
|
|
if( ! initialize() )
|
|
Q_ASSERT( hadError() );
|
|
}
|
|
|
|
if( hadError() ) {
|
|
#ifdef KROSS_ACTION_DEBUG
|
|
krossdebug( QString("Action::slotTriggered() on init, errorMessage=%2").arg(errorMessage()) );
|
|
#endif
|
|
}
|
|
else {
|
|
d->script->execute();
|
|
if( d->script->hadError() ) {
|
|
#ifdef KROSS_ACTION_DEBUG
|
|
krossdebug( QString("Action::slotTriggered() after exec, errorMessage=%2").arg(errorMessage()) );
|
|
#endif
|
|
setError(d->script);
|
|
//emit finished(this);
|
|
finalize();
|
|
//return;
|
|
}
|
|
}
|
|
|
|
emit finished(this);
|
|
}
|
|
|
|
// --------
|
|
|
|
// interface files
|
|
WrapperInterface::~WrapperInterface()
|
|
{
|
|
}
|
|
|
|
#include "moc_action.cpp"
|