diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/qscxml.cpp | 1618 | ||||
-rw-r--r-- | src/qscxml.h | 170 | ||||
-rw-r--r-- | src/qscxml.pri | 7 | ||||
-rw-r--r-- | src/qscxmlgui.cpp | 136 | ||||
-rw-r--r-- | src/qscxmlgui.h | 57 | ||||
-rw-r--r-- | src/src.pro | 10 |
6 files changed, 0 insertions, 1998 deletions
diff --git a/src/qscxml.cpp b/src/qscxml.cpp deleted file mode 100644 index daa1ec6..0000000 --- a/src/qscxml.cpp +++ /dev/null @@ -1,1618 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2008-$THISYEAR$ $TROLLTECH$. All rights reserved. -** -** This file is part of the SCXML project on Trolltech Labs. -** -** $TROLLTECH_GPL_LICENSE$ -** -****************************************************************************/ -/*! - \class QScxml - - \brief The QScxml class provides a way to use scripting with the Qt State Machine Framework. - - Though can be used alone, QScxml is mainly a runtime helper to using the - state-machine framework with SCXML files. - - - \sa QStateMachine -*/ -#ifndef QT_NO_STATEMACHINE - -#include "qscxml.h" -#include <QScriptEngine> -#include <QScriptValueIterator> -#include <QDebug> -#include <QTimer> -#include <QSignalMapper> -#include <QUuid> -#include <QHash> -#include <QXmlStreamReader> -#include <QFileInfo> -#include <QDir> -#include <QSet> -#include <QStack> -#include <QHistoryState> -#include <QFinalState> -#include <QState> -#include <QMetaMethod> -#ifdef QT_GUI_LIB -#include "qscxmlgui.h" -#endif - - - -class QtScxmlSnoopInternal : public QObject - { - Q_OBJECT - - friend class QtScxmlSnoop; - - QtScxmlSnoopInternal(QObject* o) :QObject(o) { } - ~QtScxmlSnoopInternal() { - if (parent()) parent()->deleteLater(); - } - - signals: - void signal (const QVariantList &); - }; - class QtScxmlSnoop: public QObject - { - public: - QtScxmlSnoopInternal* inobj; - QtScxmlSnoop(QObject *obj, const char *aSignal):QObject(obj) - { -#ifdef Q_CC_BOR - const int memberOffset = QObject::staticMetaObject.methodCount(); -#else - static const int memberOffset = QObject::staticMetaObject.methodCount(); -#endif - Q_ASSERT(obj); - Q_ASSERT(aSignal); - - if (aSignal[0] - '0' != QSIGNAL_CODE) { - qWarning("QtScxmlSnoop: Not a valid signal, use the SIGNAL macro"); - return; - } - - QByteArray ba = QMetaObject::normalizedSignature(aSignal + 1); - const QMetaObject *mo = obj->metaObject(); - int sigIndex = mo->indexOfMethod(ba.constData()); - if (sigIndex < 0) { - qWarning("QtScxmlSnoop: No such signal: '%s'", ba.constData()); - return; - } - - if (!QMetaObject::connect(obj, sigIndex, this, memberOffset, - Qt::QueuedConnection, 0)) { - qWarning("QtScxmlSnoop: QMetaObject::connect returned false. Unable to connect."); - return; - } - sig = ba; - QMetaMethod member = mo->method(sigIndex); - QList<QByteArray> params = member.parameterTypes(); - for (int i = 0; i < params.count(); ++i) { - int tp = QMetaType::type(params.at(i).constData()); - if (tp == QMetaType::Void) - qWarning("Don't know how to handle '%s', use qRegisterMetaType to register it.", - params.at(i).constData()); - args << tp; - } - inobj = new QtScxmlSnoopInternal (this); - } - - inline bool isValid() const { return !sig.isEmpty(); } - inline QByteArray signal() const { return sig; } - - - int qt_metacall(QMetaObject::Call call, int id, void **a) - { - id = QObject::qt_metacall(call, id, a); - if (id < 0) - return id; - - if (call == QMetaObject::InvokeMetaMethod) { - if (id == 0) { - QVariantList list; - for (int i = 0; i < args.count(); ++i) { - QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i)); - QVariant v(type, a[i + 1]); - list << v; - - } - emit inobj->signal (list); - } - --id; - } - return id; - } - - - - // the full, normalized signal name - QByteArray sig; - // holds the QMetaType types for the argument list of the signal - QList<int> args; - - }; - -QObject* q_snoopConnect ( - QObject* sender, - const char* signal, - QObject* receiver, - const char* method - ) -{ - QtScxmlSnoop* o = new QtScxmlSnoop(sender,signal); - if (o->isValid()) { - QObject::connect (o->inobj, SIGNAL(signal(QVariantList)),receiver,method); - QObject::connect (receiver, SIGNAL(destroyed()), o, SLOT(deleteLater())); - } - return o; -} - -class QScxmlPrivate -{ - public: - - enum { MaxSnapshots = 200}; - - struct AnchorSnapshot - { - QAbstractState* state; - QString location; - QScriptValue snapshot; - QString anchorType; - }; - - void initScriptEngine(QScxml* thiz); - - - QScriptEngine* scriptEng; - QList<QScxmlInvokerFactory*> invokerFactories; - QUrl burl; - QString sessionID; - QString startScript; - - - QStack<AnchorSnapshot> snapshotStack; - QMultiHash<QString,QAbstractTransition*> anchorTransitions; - QHash<QString,AnchorSnapshot> curSnapshot; - - - static QHash<QString,QScxml*> sessions; -}; -QHash<QString,QScxml*> QScxmlPrivate::sessions; - -class QScxmlTimer : public QObject -{ - Q_OBJECT - public: - QScxmlTimer(QScriptEngine* engine, const QScriptValue & scr, int delay) : QObject(engine),script(scr) - { - QTimer::singleShot(delay,this,SLOT(exec())); - } - protected Q_SLOTS: - void exec() - { - if (script.isFunction()) - script.call(); - else if (script.isString()) - script.engine()->evaluate(script.toString()); - deleteLater(); - } - - private: - QScriptValue script; - -}; - -static QScriptValue _q_deepCopy(const QScriptValue & val) -{ - if (val.isObject() || val.isArray()) { - QScriptValue v = val.isArray() ? val.engine()->newArray() : val.engine()->newObject(); - v.setData(val.data()); - QScriptValueIterator it (val); - while (it.hasNext()) { - it.next(); - v.setProperty(it.name(), _q_deepCopy(it.value())); - } - return v; - } else - return val; -} -class QScxmlSignalReceiver : public QObject -{ - Q_OBJECT - QScxml* scxml; - QString eventName; - public: - QScxmlSignalReceiver(QScxml* s, QString ename) : QObject(s),scxml(s),eventName(ename) - { - } - public Q_SLOTS: - void receiveSignal(const QVariantList & pvals) - { - QStringList pnames; - for (int i=0; i < pvals.count(); ++i) { - pnames << QString::number(i); - } - QScxmlEvent* ev = new QScxmlEvent(eventName,pnames,pvals,QScriptValue()); - ev->metaData.kind = QScxmlEvent::MetaData::Platform; - scxml->postEvent(ev); - } -}; -struct QScxmlFunctions -{ -static QScriptValue connectSignalToEvent(QScriptContext* context, QScriptEngine*) -{ - QScxml* scxml = qobject_cast<QScxml*>(context->thisObject().toQObject()); - if (scxml) { - QObject* obj = context->argument(0).toQObject(); - QString sig = ('0'+QSIGNAL_CODE)+context->argument(1).toString(); - QString ename = context->argument(2).toString(); - - if (obj) - { - q_snoopConnect(obj,sig.toAscii().constData(),new QScxmlSignalReceiver(scxml,ename),SLOT(receiveSignal(QVariantList))); - } - } - return QScriptValue(); -} - -static QScriptValue cssTime(QScriptContext *context, QScriptEngine *engine) -{ - QString str; - if (context->argumentCount() > 0) - str = context->argument(0).toString(); - if (str == "") { - return qScriptValueFromValue<int>(engine,0); - } - else if (str.endsWith("ms")) { - return qScriptValueFromValue<int>(engine,(str.left(str.length()-2).toInt())); - } - else if (str.endsWith("s")) { - return qScriptValueFromValue<int>(engine,(str.left(str.length()-1).toInt())*1000); - } - else { - return qScriptValueFromValue<int>(engine, (str.toInt())); - } -} -static QScriptValue setTimeout(QScriptContext *context, QScriptEngine *engine) -{ - if (context->argumentCount() < 2) - return QScriptValue(); - int timeout = context->argument(1).toInt32(); - QScxmlTimer* tmr = new QScxmlTimer(engine,context->argument(0),timeout); - return engine->newQObject(tmr); -} -static QScriptValue script_print(QScriptContext *context, QScriptEngine *) -{ - if (context->argumentCount() > 0) - qDebug() << context->argument(0).toString(); - return QScriptValue(); -} -static QScriptValue clearTimeout(QScriptContext *context, QScriptEngine *) -{ - if (context->argumentCount() > 0) { - QObject* obj = context->argument(0).toQObject(); - obj->deleteLater(); - } - return QScriptValue(); -} - -static QScriptValue deepCopy(QScriptContext *context, QScriptEngine *) -{ - if (context->argumentCount() == 0) - return QScriptValue(); - else - return _q_deepCopy(context->argument(0)); -} - -static QScriptValue postEvent(QScriptContext *context, QScriptEngine *) -{ - QScxml* scxml = qobject_cast<QScxml*>(context->thisObject().toQObject()); - if (scxml) { - QString eventName,target,type; - QStringList pnames; - QVariantList pvals; - QScriptValue cnt; - if (context->argumentCount() > 0) - eventName = context->argument(0).toString(); - if (context->argumentCount() > 1) - target = context->argument(1).toString(); - if (context->argumentCount() > 2) - type = context->argument(2).toString(); - - if (!eventName.isEmpty() || !target.isEmpty()) { - if (context->argumentCount() > 3) - qScriptValueToSequence<QStringList>(context->argument(3),pnames); - if (context->argumentCount() > 4) { - QScriptValueIterator it (context->argument(4)); - while (it.hasNext()) { - it.next(); - pvals.append(it.value().toVariant()); - } - } if (context->argumentCount() > 5) - cnt = context->argument(5); - QScxmlEvent* ev = new QScxmlEvent(eventName,pnames,pvals,cnt); - if (type == "scxml" || type == "") { - bool ok = true; - if (target == "_internal") { - ev->metaData.kind = QScxmlEvent::MetaData::Internal; - scxml->postInternalEvent(ev); - } else if (target == "scxml" || target == "") { - ev->metaData.kind = QScxmlEvent::MetaData::External; - scxml->postEvent(ev); - } else if (target == "_parent") { - QScxmlInvoker* p = qobject_cast<QScxmlInvoker*>(scxml->parent()); - if (p) - p->postParentEvent(ev); - else - ok = false; - } else { - QScxml* session = QScxmlPrivate::sessions[target]; - if (session) { - session->postEvent(ev); - } else - ok = false; - } - if (!ok) - scxml->postNamedEvent("error.targetunavailable"); - - } else { - scxml->postNamedEvent("error.send.typeinvalid"); - } - } - } - return QScriptValue(); -} - -// scxml.invoke (type, target, paramNames, paramValues, content) -static QScriptValue invoke(QScriptContext *context, QScriptEngine *engine) -{ - QScxml* scxml = qobject_cast<QScxml*>(context->thisObject().toQObject()); - if (scxml) { - QString type,target; - QStringList pnames; - QVariantList pvals; - QScriptValue cnt; - if (context->argumentCount() > 0) - type = context->argument(0).toString(); - if (type.isEmpty()) - type = "scxml"; - if (context->argumentCount() > 1) - target = context->argument(1).toString(); - if (context->argumentCount() > 2) - qScriptValueToSequence<QStringList>(context->argument(2),pnames); - if (context->argumentCount() > 3) { - QScriptValueIterator it (context->argument(3)); - while (it.hasNext()) { - it.next(); - pvals.append(it.value().toVariant()); - } - } if (context->argumentCount() > 4) - cnt = context->argument(4); - - QScxmlInvokerFactory* invf = NULL; - for (int i=0; i < scxml->pvt->invokerFactories.count() && invf == NULL; ++i) - if (scxml->pvt->invokerFactories[i]->isTypeSupported(type)) - invf = scxml->pvt->invokerFactories[i]; - if (invf) { - QScxmlEvent* ev = new QScxmlEvent("",pnames,pvals,cnt); - ev->metaData.origin = scxml->baseUrl(); - ev->metaData.target = target; - ev->metaData.targetType = type; - ev->metaData.originType = "scxml"; - ev->metaData.kind = QScxmlEvent::MetaData::External; - QScxmlInvoker* inv = invf->createInvoker(ev,scxml); - if (inv) - inv->activate(); - return engine->newQObject(inv); - } else { - scxml->postNamedEvent("error.invalidtargettype"); - } - - } - return QScriptValue(); -} - - -static QScriptValue isInState(QScriptContext *context, QScriptEngine *engine) -{ - QScxml* scxml = qobject_cast<QScxml*>(context->thisObject().toQObject()); - if (scxml) { - if (context->argumentCount() > 0) { - QString name = context->argument(0).toString(); - if (!name.isEmpty()) { - QSet<QAbstractState*> cfg = scxml->configuration(); - foreach (QAbstractState* st, cfg) { - if (st->objectName() == name) - return qScriptValueFromValue<bool>(engine,true); - } - } - } - } - return qScriptValueFromValue<bool>(engine,false); - -} - -}; - -void QScxmlPrivate::initScriptEngine(QScxml* thiz) -{ - QScriptValue glob = scriptEng->globalObject(); - QScriptValue scxmlObj = scriptEng->newQObject(thiz); - glob.setProperty("In",scriptEng->newFunction(QScxmlFunctions::isInState)); -// glob.setProperty("_rcvSig",scriptEng->newFunction(QScxmlFunctions::receiveSignal)); - scxmlObj.setProperty("print",scriptEng->newFunction(QScxmlFunctions::script_print)); - scxmlObj.setProperty("postEvent",scriptEng->newFunction(QScxmlFunctions::postEvent)); - scxmlObj.setProperty("invoke",scriptEng->newFunction(QScxmlFunctions::invoke)); - scxmlObj.setProperty("cssTime",scriptEng->newFunction(QScxmlFunctions::cssTime)); - scxmlObj.setProperty("clone",scriptEng->newFunction(QScxmlFunctions::deepCopy)); - scxmlObj.setProperty("setTimeout",scriptEng->newFunction(QScxmlFunctions::setTimeout)); - scxmlObj.setProperty("clearTimeout",scriptEng->newFunction(QScxmlFunctions::clearTimeout)); - scxmlObj.setProperty("connectSignalToEvent",scriptEng->newFunction(QScxmlFunctions::connectSignalToEvent)); - QScriptValue dmObj = scriptEng->newObject(); - glob.setProperty("_data",scriptEng->newObject()); - glob.setProperty("_global",scriptEng->globalObject()); - glob.setProperty("scxml",scxmlObj); -} - -/*! - \class QScxmlEvent - \brief The QScxmlEvent class stands for a general named event with a list of parameter names and parameter values. - - Encapsulates an event that conforms to the SCXML definition of events. - - -*/ -/*! \enum QScxmlEvent::MetaData::Kind - - This enum specifies the kind (or context) of the event. - \value Platform An event coming from the itself, such as a script error. - \value Internal An event sent with a <raise> or <send target="_internal">. - \value External An event sent from an invoker, directly from C++, or from a <send target="scxml"> element. -*/ - -/*! - Returns the name of the event. - */ - QString QScxmlEvent::eventName() const -{ - return ename; -} - /*! - Return a list containing the parameter names. - */ -QStringList QScxmlEvent::paramNames () const -{ - return pnames; -} - /*! - Return a list containing the parameter values. - */ -QVariantList QScxmlEvent::paramValues () const -{ - return pvals; -} - /*! - Return a QtScript object that can be passed as an additional parameter. - */ -QScriptValue QScxmlEvent::content () const -{ - return cnt; -} - /*! - Returns the parameter value equivalent to parameter \a name. - */ -QVariant QScxmlEvent::param (const QString & name) const -{ - int idx = pnames.indexOf(name); - if (idx >= 0) - return pvals[idx]; - else - return QVariant(); -} -/*! - Creates a QScxmlEvent named \a name, with parameter names \a paramNames, parameter values \a paramValues, and - a QtScript object \a content as an additional parameter. -*/ -QScxmlEvent::QScxmlEvent( - const QString & name, - const QStringList & paramNames, - const QVariantList & paramValues, - const QScriptValue & content) - - : QEvent(QScxmlEvent::eventType()),ename(name),pnames(paramNames),pvals(paramValues),cnt(content) -{ - metaData.kind = MetaData::Internal; -} - -/*! \class QScxmlTransition - \brief The QScxmlTransition class stands for a transition that responds to QScxmlEvent, and can be made conditional with a \l conditionExpression. - Equivalent to the SCXML transition tag. - - */ - - -/*! \property QScxmlTransition::eventPrefix - The event prefix to be used when testing if the transition needs to be invoked. - Uses SCXML prefix matching. Use * to handle any event. - */ -/*! \property QScxmlTransition::conditionExpression - A QtScript expression that's evaluated to test whether the transition needs to be invoked. - */ - -/*! - Creates a new QScxmlTransition from \a state, that uses \a machine to evaluate the conditions. - */ -QScxmlTransition::QScxmlTransition (QState* state,QScxml* machine) - : QAbstractTransition(state),scxml(machine) -{ -} -/*! - \reimp -*/ -void QScxmlTransition::onTransition(QEvent*) -{ -} -/*! - \internal - */ -bool QScxmlTransition::eventTest(QEvent *e) -{ - QScriptEngine* engine = scxml->scriptEngine(); - QString ev; - - if (e) { - if (e->type() == QScxmlEvent::eventType()) { - ev = ((QScxmlEvent*)e)->eventName(); - } - if (!(eventPrefix() == "*" || eventPrefix() == ev || ev.startsWith(eventPrefix()+"."))) - return false; - } - - - if (!conditionExpression().isEmpty()) { - - - QScriptValue v = engine->evaluate(conditionExpression(),scxml->baseUrl().toLocalFile()); - if (engine->hasUncaughtException()) { - - QScxmlEvent* e = new QScxmlEvent("error.illegalcond", - QStringList()<< "error" << "expr" << "line" << "backtrace", - QVariantList() - << QVariant(engine->uncaughtException().toString()) - << QVariant(conditionExpression()) - << QVariant(engine->uncaughtExceptionLineNumber()) - << QVariant(engine->uncaughtExceptionBacktrace())); - qDebug() << engine->uncaughtException().toString(); - e->metaData.kind = QScxmlEvent::MetaData::Platform; - scxml->postEvent(e); - engine->clearExceptions(); - return false; - } - return v.toBoolean(); - } - - return true; -} - -class QScxmlDefaultInvoker : public QScxmlInvoker -{ - Q_OBJECT - - - public: - QScxmlDefaultInvoker(QScxmlEvent* ievent, QScxml* p) : QScxmlInvoker(ievent,p),cancelled(false),childSm(0) - { - childSm = QScxml::load (ievent->metaData.origin.resolved(ievent->metaData.target).toLocalFile(),this); - if (childSm == NULL) { - postParentEvent("error.targetunavailable"); - } else { - connect(childSm,SIGNAL(finished()),this,SLOT(deleteLater())); - - } - } - - - - static void initInvokerFactory(QScxml*) {} - - static bool isTypeSupported(const QString & t) { return t.isEmpty() || t.toLower() == "scxml"; } - - public Q_SLOTS: - void activate () - { - if (childSm) - childSm->start(); - } - - void cancel () - { - cancelled = true; - if (childSm) - childSm->stop(); - - } - - private: - bool cancelled; - QScxml* childSm; -}; -class QScxmlBindingInvoker : public QScxmlInvoker -{ - Q_OBJECT - QScriptValue content; - QScriptValue stored; - - public: - QScxmlBindingInvoker(QScxmlEvent* ievent, QScxml* p) : QScxmlInvoker(ievent,p) - { - } - - static void initInvokerFactory(QScxml*) {} - - static bool isTypeSupported(const QString & t) { return t.toLower() == "q-bindings"; } - - public Q_SLOTS: - void activate () - { - QScriptEngine* engine = ((QScxml*)parent())->scriptEngine(); - QScriptValue content = initEvent->content(); - if (content.isArray()) { - stored = content.engine()->newArray(content.property("length").toInt32()); - - QScriptValueIterator it (content); - for (int i=0; it.hasNext(); ++i) { - it.next(); - if (it.value().isArray()) { - QScriptValue object = it.value().property(0); - QString property = it.value().property(1).toString(); - QScriptValue val = it.value().property(2); - QScriptValue arr = engine->newArray(3); - arr.setProperty("0",it.value().property(0)); - arr.setProperty("1",it.value().property(1)); - if (object.isQObject()) { - QObject* o = object.toQObject(); - arr.setProperty("2",engine->newVariant(o->property(property.toAscii().constData()))); - o->setProperty(property.toAscii().constData(),val.toVariant()); - } else if (object.isObject()) { - arr.setProperty("2",object.property(property)); - object.setProperty(property,val); - } - stored.setProperty(i,arr); - } - } - } - } - - void cancel () - { - if (stored.isArray()) { - QScriptValueIterator it (stored); - while (it.hasNext()) { - it.next(); - if (it.value().isArray()) { - QScriptValue object = it.value().property(0); - QString property = it.value().property(1).toString(); - QScriptValue val = it.value().property(2); - if (object.isQObject()) { - QObject* o = object.toQObject(); - o->setProperty(property.toAscii().constData(),val.toVariant()); - } else if (object.isObject()) { - object.setProperty(property,val); - } - } - } - } - } -}; - - -/*! -\fn QScxmlInvoker::~QScxmlInvoker() -*/ - - -/*! -\fn QScxml::eventTriggered(const QString & name) - -This signal is emitted when external event \a name is handled in the state machine. -*/ - -void QScxml::init() -{ - static QScxmlAutoInvokerFactory<QScxmlDefaultInvoker> _s_defaultInvokerFactory; - static QScxmlAutoInvokerFactory<QScxmlBindingInvoker> _s_bindingInvokerFactory; - registerInvokerFactory(&_s_defaultInvokerFactory); - registerInvokerFactory(&_s_bindingInvokerFactory); - connect(this,SIGNAL(started()),this,SLOT(registerSession())); - connect(this,SIGNAL(stopped()),this,SLOT(unregisterSession())); - pvt->initScriptEngine(this); -#ifdef QT_GUI_LIB - static QScxmlAutoInvokerFactory<QScxmlMenuInvoker> _s_menuInvokerFactory; - static QScxmlAutoInvokerFactory<QScxmlMessageBoxInvoker> _s_msgboxInvokerFactory; - registerInvokerFactory(&_s_msgboxInvokerFactory); - registerInvokerFactory(&_s_menuInvokerFactory); -#endif -} -/*! - Creates a new QScxml object, with parent \a parent. - */ - -QScxml::QScxml(QObject* parent) - : QStateMachine(parent) -{ - pvt = new QScxmlPrivate; - pvt->scriptEng = new QScriptEngine(this); - init(); - -} -/*! - Creates a new QScxml object, with parent \a parent. The state machine will operate on script-engine \a eng. - */ - -QScxml::QScxml(QScriptEngine* eng, QObject* parent) - : QStateMachine(parent) -{ - pvt = new QScxmlPrivate; - pvt->scriptEng = eng; - init(); -} - -/*! \internal */ -void QScxml::beginSelectTransitions(QEvent* ev) -{ - QScriptValue eventObj = pvt->scriptEng->newObject(); - if (ev) { - if (ev->type() == QScxmlEvent::eventType()) { - QScxmlEvent* se = (QScxmlEvent*)ev; - eventObj.setProperty("name",qScriptValueFromValue<QString>(pvt->scriptEng,se->eventName())); - eventObj.setProperty("target",QScriptValue(se->metaData.target.toString())); - eventObj.setProperty("targettype",qScriptValueFromValue<QString>(pvt->scriptEng,se->metaData.targetType)); - eventObj.setProperty("invokeid",qScriptValueFromValue<QString>(pvt->scriptEng,se->metaData.invokeID)); - eventObj.setProperty("origin",QScriptValue(se->metaData.origin.toString())); - eventObj.setProperty("originType",qScriptValueFromValue<QString>(pvt->scriptEng,se->metaData.originType)); - switch (se->metaData.kind) { - case QScxmlEvent::MetaData::Internal: - eventObj.setProperty("kind",qScriptValueFromValue<QString>(pvt->scriptEng, "internal")); - break; - case QScxmlEvent::MetaData::External: - eventObj.setProperty("kind",qScriptValueFromValue<QString>(pvt->scriptEng, "external")); - break; - case QScxmlEvent::MetaData::Platform: - eventObj.setProperty("kind",qScriptValueFromValue<QString>(pvt->scriptEng, "platform")); - default: - break; - - } - - QScriptValue dataObj = pvt->scriptEng->newObject(); - int i=0; - foreach (QString s, se->paramNames()) { - QScriptValue v = qScriptValueFromValue(pvt->scriptEng, se->paramValues()[i]); - dataObj.setProperty(QString::number(i),v); - dataObj.setProperty(s,v); - ++i; - } - eventObj.setProperty("data",dataObj); - emit eventTriggered(se->eventName()); - } - } - scriptEngine()->globalObject().setProperty("_event",eventObj); - - QHash<QString,QAbstractState*> curTargets; - - for (int i = pvt->snapshotStack.size()-1; i >= 0 && curTargets.size() < pvt->anchorTransitions.keys().size(); --i) { - if (!curTargets.contains(pvt->snapshotStack.at(i).anchorType)) { - curTargets[pvt->snapshotStack.at(i).anchorType] = pvt->snapshotStack.at(i).state; - } - } - for (QMultiHash<QString,QAbstractTransition*>::const_iterator it = pvt->anchorTransitions.constBegin(); it != pvt->anchorTransitions.constEnd(); ++it) { - it.value()->setTargetState(curTargets[it.key()]); - } - -} - -static QString _q_configToString (QAbstractState* from,int level, const QSet<QAbstractState*> & config) -{ - QString str; - if (from) { - if (level >= 0) { - for (int i=0; i < level; ++i) - str += "\t"; - - QState* p = qobject_cast<QState*>(from->parent()); - char c = '$'; - if (qobject_cast<QHistoryState*>(from)) - c = '^'; - else if (qobject_cast<QFinalState*>(from)) - c = '~'; - else if (p) { - if (p->childMode() == QState::ParallelStates) - c = '{'; - } - str += QString("%1%2 %3\n").arg(config.contains(from)?">":" ").arg(c).arg(from->objectName()); - } - QObjectList ch = from->children(); - foreach (QObject* o, ch) - str += _q_configToString(qobject_cast<QAbstractState*>(o),level+1,config); - } - - return str; -} - -/*! \internal */ - - -void QScxml::endMicrostep(QEvent*) -{ - scriptEngine()->globalObject().setProperty("_event",QScriptValue()); - for (QHash<QString,QScxmlPrivate::AnchorSnapshot>::iterator - it = pvt->curSnapshot.begin(); - it != pvt->curSnapshot.end(); ++it) { - - pvt->snapshotStack.push(it.value()); - - } - if (pvt->snapshotStack.size() > QScxmlPrivate::MaxSnapshots) { - pvt->snapshotStack.remove(0,pvt->snapshotStack.size()-100); - } - pvt->curSnapshot.clear(); - /* - if (e->type() == QScxmlEvent::eventType()) { - qDebug() << "\n" + _q_configToString(rootState(),-1,configuration()); - } - */ -} - -/*! Returns the script engine attached to the state-machine. */ -QScriptEngine* QScxml::scriptEngine () const -{ - return pvt->scriptEng; -} - -/*! - Registers object \a o to the script engine attached to the state machine. - The object can be accessible from global variable \a name. If \a name is not provided, - the object's name is used. If \a recursive is true, all the object's decendants are registered - as global objects, with their respective object names as variable names. -*/ -void QScxml::registerObject (QObject* o, const QString & name, bool recursive) -{ - QString n(name); - if (n.isEmpty()) - n = o->objectName(); - if (!n.isEmpty()) - pvt->scriptEng->globalObject().setProperty(n,pvt->scriptEng->newQObject(o)); - if (recursive) { - QObjectList ol = o->findChildren<QObject*>(); - foreach (QObject* oo, ol) { - if (!oo->objectName().isEmpty()) - registerObject(oo); - } - } -} - -/*! - Posts a QScxmlEvent named \a event, with no payload. - \sa QScxmlEvent - */ -void QScxml::postNamedEvent(const QString & event) -{ - QScxmlEvent* e = new QScxmlEvent(event); - e->metaData.kind = QScxmlEvent::MetaData::External; - postEvent(e); -} -/*! - Executes script \a s in the attached script engine. - If the script fails, a "error.illegalvalue" event is posted to the state machine. -*/ - -void QScxml::executeScript (const QString & s) -{ -// qDebug() << "Executing\n--------------------------\n"<<s; - pvt->scriptEng->evaluate (s,baseUrl().toLocalFile()); - if (pvt->scriptEng->hasUncaughtException()) { - QScxmlEvent* e = new QScxmlEvent("error.illegalvalue", - QStringList()<< "error" << "expr" << "line" << "backtrace", - QVariantList() - << QVariant(pvt->scriptEng->uncaughtException().toString()) - << QVariant(s) - << QVariant(pvt->scriptEng->uncaughtExceptionLineNumber()) - << QVariant(pvt->scriptEng->uncaughtExceptionBacktrace())); - e->metaData.kind = QScxmlEvent::MetaData::Platform; - qDebug() << pvt->scriptEng->uncaughtException().toString(); - postEvent(e); - pvt->scriptEng->clearExceptions(); - } -// qDebug() <<"\n--------------------\n"; -} - -/*! - Enabled invoker factory \a f to be called from <invoke /> tags. - */ - -void QScxml::registerInvokerFactory (QScxmlInvokerFactory* f) -{ - pvt->invokerFactories << f; - f->init(this); -} - -/*! \class QScxmlInvoker - \brief The QScxmlInvoker class an invoker, which the state-machine context can activate or cancel - with an <invoke> tag. - - - An invoker is a object that represents an external component that the state machine - can activate when the encompassing state is entered, or cancel when the encompassing - state is exited from. - */ - -/*! \fn QScxmlInvoker::QScxmlInvoker(QScxmlEvent* ievent, QStateMachine* parent) - When reimplementing the constructor, always use the two parameters (\a ievent and \a parent), - as they're called from QScxmlInvokerFactory. -*/ - -/*! \fn QScxmlInvoker::activate() - This function is called when the encompassing state is entered. - The call to this function from the state-machine context is asynchronous, to make sure - that the state is not exited during the same step in which it's entered. - -*/ - -/*! \fn QScxmlInvoker::cancel() - Reimplement this function to allow for asynchronous cancellation of the invoker. - It's the invoker's responsibility to delete itself after this function has been called. - The default implementation deletes the invoker. -*/ - -/*! \fn QScxml* QScxmlInvoker::parentStateMachine() - Returns the state machine encompassing the invoker. - */ - -/*! - Posts an event \a e to the state machine encompassing the invoker. - */ -void QScxmlInvoker::postParentEvent (QScxmlEvent* e) -{ - e->metaData.origin = initEvent->metaData.target; - e->metaData.target = initEvent->metaData.origin; - e->metaData.originType = initEvent->metaData.targetType; - e->metaData.targetType = initEvent->metaData.originType; - e->metaData.kind = QScxmlEvent::MetaData::External; - e->metaData.invokeID = initEvent->metaData.invokeID; - parentStateMachine()->postEvent(e); -} -/*! \overload - Posts a QScxmlEvent named \a e to the encompassing state machine. - */ -void QScxmlInvoker::postParentEvent(const QString & e) -{ - QScxmlEvent* ev = new QScxmlEvent(e); - ev->metaData.kind = QScxmlEvent::MetaData::External; - postParentEvent(ev); -} -/*! \internal */ -QScxml::~QScxml() -{ - delete pvt; -} -/*! -returns the id for this invoker -*/ -QString QScxmlInvoker::id () const -{ - return initEvent->metaData.invokeID; -} -void QScxmlInvoker::setID(const QString & id) -{ - initEvent->metaData.invokeID = id; -} - -QScxmlInvoker::~QScxmlInvoker() -{ - if (cancelled) - postParentEvent("CancelResponse"); - else - postParentEvent(QString("done.invoke.%1").arg(initEvent->metaData.invokeID)); -} -/*! - \property QScxml::baseUrl - The url used to resolve scripts and invoke urls. -*/ -QUrl QScxml::baseUrl() const -{ - return pvt->burl; -} - -void QScxml::setBaseUrl(const QUrl & u) -{ - pvt->burl = u; -} - -void QScxml::registerSession() -{ - pvt->sessionID = QUuid::createUuid().toString(); - pvt->sessions[pvt->sessionID] = this; - pvt->scriptEng->globalObject().setProperty("_sessionid",qScriptValueFromValue<QString>(scriptEngine(), pvt->sessionID)); - executeScript(pvt->startScript); -} - -void QScxml::unregisterSession() -{ - pvt->scriptEng->globalObject().setProperty("_sessionid",QScriptValue()); - pvt->sessions.remove(pvt->sessionID); -} - -/*! - Returns a statically-generated event type to be used by SCXML events. -*/ -QEvent::Type QScxmlEvent::eventType() -{ - static QEvent::Type _t = (QEvent::Type)QEvent::registerEventType(QEvent::User+200); - return _t; -} -const char SCXML_NAMESPACE [] = "http://www.w3.org/2005/07/scxml"; - - - -struct ScTransitionInfo -{ - - QScxmlTransition* transition; - QStringList targets; - QString anchor; - QString script; - ScTransitionInfo() : transition(NULL) {} -}; - -class QScxmlScriptExec : public QObject -{ - Q_OBJECT - QString script; - QScxml* scxml; - public: - QScxmlScriptExec(const QString & scr, QScxml* scx) : script(scr),scxml(scx) - { - } - public Q_SLOTS: - void exec() - { - scxml->executeScript(script); - } -}; - -struct ScStateInfo -{ - QString initial; -}; - -struct ScHistoryInfo -{ - QHistoryState* hstate; - QString defaultStateID; -}; - -struct ScExecContext -{ - QScxml* sm; - QString script; - enum {None, StateEntry,StateExit,Transition } type; - QScxmlTransition* trans; - QAbstractState* state; - ScExecContext() : sm(NULL),type(None),trans(NULL),state(NULL) - { - } - - void applyScript() - { - if (!script.isEmpty()) { - QScxmlScriptExec* exec = new QScxmlScriptExec(script,sm); - switch(type) { - case StateEntry: - QObject::connect(state,SIGNAL(entered()),exec,SLOT(exec())); - break; - case StateExit: - QObject::connect(state,SIGNAL(exited()),exec,SLOT(exec())); - break; - case Transition: - QObject::connect(trans,SIGNAL(triggered()),exec,SLOT(exec())); - break; - default: - delete exec; - break; - } - } - } -}; - -class QScxmlLoader -{ - public: - QScxml* stateMachine; - - QList<ScTransitionInfo> transitions; - QHash<QState*,ScStateInfo> stateInfo; - QList<ScHistoryInfo> historyInfo; - QHash<QString,QAbstractState*> stateByID; - QSet<QString> signalEvents; - QSet<QState*> statesWithFinal; - void loadState (QState* state, QIODevice* dev, const QString & stateID,const QString & filename); - QScxml* load (QIODevice* device, QObject* obj = NULL, const QString & filename = ""); - - QScriptValue evaluateFile (const QString & fn) - { - QFile f (fn); - f.open(QIODevice::ReadOnly); - return stateMachine->scriptEngine()->evaluate(QString::fromUtf8(f.readAll()),fn); - } -}; - -class QScxmlAnchorSave : public QObject -{ - Q_OBJECT - public: - QScxml* sm; - QScxmlPrivate* pvt; - QScxmlPrivate::AnchorSnapshot anchorSnapshot; - QScxmlAnchorSave(QScxml* p,QScxmlPrivate* pv, - const QString & type, const QString & loc, - QAbstractState* s) : - QObject(p),sm(p),pvt(pv) - { - anchorSnapshot.anchorType = type; - anchorSnapshot.location = loc; - anchorSnapshot.state = s; - } - - public Q_SLOTS: - - void save() - { - if (!anchorSnapshot.location.isEmpty()) { - anchorSnapshot.snapshot = _q_deepCopy(sm->scriptEngine()->evaluate(anchorSnapshot.location)); - } - pvt->curSnapshot[anchorSnapshot.anchorType] = anchorSnapshot; - } -}; - -class QScxmlAnchorRestore : public QObject -{ - Q_OBJECT - public: - QScxml* sm; - QScxmlPrivate* pvt; - QString anchorType; - QScxmlAnchorRestore(QScxml* p,QScxmlPrivate* pv, - const QString & type) : - QObject(p),sm(p),pvt(pv),anchorType(type) - { - - } - - public Q_SLOTS: - void restore () - { - pvt->curSnapshot.clear(); - while (!pvt->snapshotStack.isEmpty()) { - QScxmlPrivate::AnchorSnapshot s = pvt->snapshotStack.pop(); - if (s.anchorType == anchorType) { - if (s.location != "") { - sm->scriptEngine()->globalObject().setProperty("_snapshot",s.snapshot); - sm->scriptEngine()->evaluate(QString ("%1 = _snapshot;").arg(s.location)); - sm->scriptEngine()->globalObject().setProperty("_snapshot",QScriptValue()); - } - break; - } - } - } -}; - -static QString sanitize (const QString & str) -{ - return str; -// return QString("eval(unescape(\"%1\"))"). -// arg(QString::fromAscii(str.trimmed().toUtf8().toPercentEncoding(QByteArray("[]()<>;:#/'`_-., \t@!^&*{}")))); -} -static QString sanitize (const QStringRef & str) -{ - return sanitize(str.toString()); -} - -void QScxmlLoader::loadState ( - QState* stateParam, - QIODevice *dev, - const QString & stateID, - const QString & filename) -{ - QXmlStreamReader r (dev); - QState* curState = NULL; - ScExecContext curExecContext; - curExecContext.sm = stateMachine; - QState* topLevelState = NULL; - QHistoryState* curHistoryState = NULL; - QString initialID = ""; - QString idLocation, target, targetType, eventName, delay, content; - QStringList paramNames, paramVals; - QScxmlTransition* curTransition = NULL; - bool inRoot = true; - while (!r.atEnd()) { - r.readNext(); - if (r.hasError()) { - qDebug() << QString("SCXML read error at line %1, column %2: %3").arg(r.lineNumber()).arg(r. columnNumber()).arg(r.errorString()); - return; - } - if (r.namespaceUri() == SCXML_NAMESPACE || r.namespaceUri() == "") { - if (r.isStartElement()) { - if (r.name().toString().compare("scxml",Qt::CaseInsensitive) == 0) { - if (stateID == "") { - topLevelState = curState = stateParam; - stateInfo[curState].initial = r.attributes().value("initial").toString(); - if (curState == stateMachine) { - stateMachine->scriptEngine()->globalObject().setProperty("_name",qScriptValueFromValue<QString>(stateMachine->scriptEngine(),r.attributes().value("name").toString())); - } - - } - } else if (r.name().toString().compare("state",Qt::CaseInsensitive) == 0 || r.name().toString().compare("parallel",Qt::CaseInsensitive) == 0) { - inRoot = false; - QString id = r.attributes().value("id").toString(); - QState* newState = NULL; - if (curState) { - newState= new QState(r.name().toString().compare("parallel",Qt::CaseInsensitive) == 0 ? QState::ParallelStates : QState::ExclusiveStates, - curState); - } else if (id == stateID) { - topLevelState = newState = stateParam; - - } - if (newState) { - stateInfo[newState].initial = r.attributes().value("initial").toString(); - newState->setObjectName(id); - if (!id.isEmpty() && stateInfo[curState].initial == id) { - - if (curState == stateMachine) - stateMachine->setInitialState(newState); - else - curState->setInitialState(newState); - } - QString src = r.attributes().value("src").toString(); - if (!src.isEmpty()) { - int refidx = src.indexOf('#'); - QString srcfile, refid; - if (refidx > 0) { - srcfile = src.left(refidx); - refid = src.mid(refidx+1); - } else - srcfile = src; - srcfile = QDir::cleanPath( QFileInfo(filename).dir().absoluteFilePath(srcfile)); - QFile newFile (srcfile); - if (newFile.exists()) { - newFile.open(QIODevice::ReadOnly); - loadState(newState,&newFile,refid,srcfile); - } - } - initialID = r.attributes().value("initial").toString(); - stateByID[id] = newState; - curState = newState; - curExecContext.state = newState; - } - - } else if (r.name().toString().compare("initial",Qt::CaseInsensitive) == 0) { - if (curState && stateInfo[curState].initial == "") { - QState* newState = new QState(curState); - curState->setInitialState(newState); - } - } else if (r.name().toString().compare("history",Qt::CaseInsensitive) == 0) { - if (curState) { - QString id = r.attributes().value("id").toString(); - curHistoryState = new QHistoryState(r.attributes().value("type") == "shallow" ? QHistoryState::ShallowHistory : QHistoryState::DeepHistory,curState); - curHistoryState->setObjectName(id); - stateByID[id] = curHistoryState; - } - } else if (r.name().toString().compare("final",Qt::CaseInsensitive) == 0) { - if (curState) { - QString id = r.attributes().value("id").toString(); - QFinalState* f = new QFinalState(curState); - f->setObjectName(id); - curExecContext.state = f; - statesWithFinal.insert(curState); - QState* gp = qobject_cast<QState*>(curState->parentState()); - if (gp) { - if (gp->childMode() == QState::ParallelStates) { - statesWithFinal.insert(gp); - } - } - stateByID[id] = f; - } - } else if (r.name().toString().compare("script",Qt::CaseInsensitive) == 0) { - QString txt = r.readElementText().trimmed(); - if (curExecContext.type == ScExecContext::None && curState == topLevelState) { - stateMachine->executeScript(txt); - } else - curExecContext.script += txt; - } else if (r.name().toString().compare("log",Qt::CaseInsensitive) == 0) { - curExecContext.script += - QString("scxml.print('[' + %1 + '][' + %2 + ']' + %3);") - .arg(sanitize(r.attributes().value("label"))) - .arg(sanitize(r.attributes().value("level"))) - .arg(sanitize(r.attributes().value("expr"))); - - } else if (r.name().toString().compare("assign",Qt::CaseInsensitive) == 0) { - QString locattr = r.attributes().value("location").toString(); - if (locattr.isEmpty()) { - locattr = r.attributes().value("dataid").toString(); - if (!locattr.isEmpty()) - locattr = "_data." + locattr; - } - if (!locattr.isEmpty()) { - curExecContext.script += QString ("%1 = %2;").arg(locattr).arg(sanitize(r.attributes().value("expr"))); - } - } else if (r.name().toString().compare("if",Qt::CaseInsensitive) == 0) { - curExecContext.script += QString("if (%1) {").arg(sanitize(r.attributes().value("cond"))); - } else if (r.name().toString().compare("elseif",Qt::CaseInsensitive) == 0) { - curExecContext.script += QString("} elseif (%1) {").arg(sanitize(r.attributes().value("cond"))); - } else if (r.name().toString().compare("else",Qt::CaseInsensitive) == 0) { - curExecContext.script += " } else { "; - } else if (r.name().toString().compare("cancel",Qt::CaseInsensitive) == 0) { - curExecContext.script += QString("scxml.clearTimeout (%1);").arg(sanitize(r.attributes().value("id"))); - } else if (r.name().toString().compare("onentry",Qt::CaseInsensitive) == 0) { - curExecContext.type = ScExecContext::StateEntry; - curExecContext.script = ""; - } else if (r.name().toString().compare("onexit",Qt::CaseInsensitive) == 0) { - curExecContext.type = ScExecContext::StateExit; - curExecContext.script = ""; - } else if (r.name().toString().compare("raise",Qt::CaseInsensitive) == 0 || r.name().toString().compare("event",Qt::CaseInsensitive) == 0 ) { - eventName = QString("\"%1\"").arg(r.attributes().value("event").toString()); - target = "'_internal'"; - targetType = "scxml"; - content = "{}"; - paramNames.clear(); - paramVals.clear(); - } else if (r.name().toString().compare("send",Qt::CaseInsensitive) == 0) { - paramNames.clear (); - paramVals.clear(); - content = "{}"; - - target = r.attributes().value("target").toString(); - if (target == "") - target = "\"\""; - targetType = r.attributes().value("type").toString(); - eventName = r.attributes().value("event").toString(); - QStringList nameList = r.attributes().value("namelist").toString().split(" "); - foreach (QString name,nameList) { - if (name != "") { - paramNames << name; - paramVals << QString("_data.") + name; - } - } - idLocation = r.attributes().value("idlocation").toString(); - if (idLocation.isEmpty()) - idLocation = r.attributes().value("sendid").toString(); - - delay = r.attributes().value("delay").toString(); - if (delay == "") - delay = "0"; - else - delay = QString("scxml.cssTime(%1)").arg(delay); - - } else if (r.name().toString().compare("invoke",Qt::CaseInsensitive) == 0) { - idLocation = r.attributes().value("idlocation").toString(); - if (idLocation.isEmpty()) - idLocation = r.attributes().value("invokeid").toString(); - QObject::connect (curState, SIGNAL(exited()),new QScxmlScriptExec(QString("_data.invoke_%1.cancel();").arg(curState->objectName()),stateMachine),SLOT(exec())); - - QString type = r.attributes().value("type").toString(); - if (type.isEmpty()) - type = "scxml"; - curExecContext.type = ScExecContext::StateEntry; - curExecContext.state = curState; - paramNames.clear (); - paramVals.clear (); - content = "{}"; - target = r.attributes().value("src").toString(); - if (target == "") - target = "\"\""; - targetType = r.attributes().value("type").toString(); - } else if (r.name().toString().compare("transition",Qt::CaseInsensitive) == 0) { - if (curHistoryState) { - ScHistoryInfo inf; - inf.hstate = curHistoryState; - inf.defaultStateID = r.attributes().value("target").toString(); - historyInfo.append(inf); - } else { - ScTransitionInfo inf; - inf.targets = r.attributes().value("target").toString().split(' '); - curExecContext.type = ScExecContext::Transition; - curExecContext.script = ""; - curTransition = new QScxmlTransition(curState,stateMachine); - curTransition->setConditionExpression(r.attributes().value("cond").toString()); - curTransition->setEventPrefix(r.attributes().value("event").toString()); - curExecContext.trans = curTransition; - QString anc = r.attributes().value("anchor").toString(); - if (!anc.isEmpty()) { - stateMachine->pvt->anchorTransitions.insert(anc,curTransition); - QObject::connect (curTransition, SIGNAL(triggered()),new QScxmlAnchorRestore(stateMachine,stateMachine->pvt,anc),SLOT(restore())); - } - inf.transition = curTransition; - transitions.append(inf); - if (curTransition->eventPrefix().startsWith("q-signal:")) { - signalEvents.insert(curTransition->eventPrefix()); - } - curTransition->setObjectName(QString ("%1 to %2 on %3 if %4 (anchor=%5)").arg(curState->objectName()).arg(inf.targets.join(" ")).arg(curTransition->eventPrefix()).arg(curTransition->conditionExpression()).arg(anc)); - } - } else if (r.name().toString().compare("anchor",Qt::CaseInsensitive) == 0) { - QObject::connect(curState,SIGNAL(exited()),new QScxmlAnchorSave(stateMachine,stateMachine->pvt,r.attributes().value("type").toString(),r.attributes().value("snapshot").toString(),curState),SLOT(save())); - } else if (r.name().toString().compare("data",Qt::CaseInsensitive) == 0) { - QScriptValue val = qScriptValueFromValue<QString>(stateMachine->scriptEngine(),"") ; - QString id = r.attributes().value("id").toString(); - if (r.attributes().value("src").length()) - val = evaluateFile(QFileInfo(filename).dir().absoluteFilePath(r.attributes().value("src").toString())); - else { - if (r.attributes().value("expr").length()) { - val = stateMachine->scriptEngine()->evaluate(r.attributes().value("expr").toString()); - } else { - QString t = r.readElementText(); - if (!t.isEmpty()) - val = stateMachine->scriptEngine()->evaluate(t); - } - } - stateMachine->scriptEngine()->evaluate("_data") - .setProperty(id,val); - } else if (r.name().toString().compare("param",Qt::CaseInsensitive) == 0) { - paramNames << r.attributes().value("name").toString(); - paramVals << r.attributes().value("expr").toString(); - } else if (r.name().toString().compare("content",Qt::CaseInsensitive) == 0) { - content = r.readElementText(); - } - } else if (r.isEndElement()) { - if (r.name().toString().compare("state",Qt::CaseInsensitive) == 0 || r.name().toString().compare("parallel",Qt::CaseInsensitive) == 0) { - if (curState == topLevelState) { - return; - } else { - curState = qobject_cast<QState*>(curState->parent()); - curExecContext.state = curState; - } - } else if (r.name().toString().compare("history",Qt::CaseInsensitive) == 0) { - curHistoryState = NULL; - } else if (r.name().toString().compare("final",Qt::CaseInsensitive) == 0) { - curExecContext.state = (curExecContext.state->parentState()); - } else if (r.name().toString().compare("if",Qt::CaseInsensitive) == 0) { - curExecContext.script += "}\n"; - } else if (r.name().toString().compare("send",Qt::CaseInsensitive) == 0 || r.name().toString().compare("raise",Qt::CaseInsensitive) == 0) { - if (!idLocation.isEmpty()) - curExecContext.script += idLocation + " = "; - QString pnames; - bool first = true; - foreach (QString n, paramNames) { - if (!first) - pnames +=","; - pnames += QString("\"%1\"").arg(n); - first = false; - } - QString innerScript = QString("scxml.postEvent(%1,%2,\"%3\",[%4],[%5],%6);") - .arg(eventName).arg(target).arg(targetType) - .arg(pnames).arg(paramVals.join(",")).arg(content); - if (target == "'_internal'") - curExecContext.script += innerScript; - else - curExecContext.script += QString("scxml.setTimeout(function() {%1}, %2);") - .arg(innerScript).arg(delay); - idLocation = ""; - } else if ( - r.name().toString().compare("onentry",Qt::CaseInsensitive) == 0 - || r.name().toString().compare("onexit",Qt::CaseInsensitive) == 0 - || r.name().toString().compare("scxml",Qt::CaseInsensitive) == 0) { - curExecContext.state = curState; - curExecContext.type = r.name().toString().compare("onexit",Qt::CaseInsensitive)==0 ? ScExecContext::StateExit : ScExecContext::StateEntry; - curExecContext.applyScript(); - curExecContext.type = ScExecContext::None; - } else if (r.name().toString().compare("transition",Qt::CaseInsensitive) == 0) { - if (!curHistoryState) { - curExecContext.trans = curTransition; - curExecContext.type = ScExecContext::Transition; - curExecContext.applyScript(); - } - - ScTransitionInfo* ti = &(transitions.last()); - if (!curExecContext.script.isEmpty() && ti->anchor != "") - ti->script = curExecContext.script; - curExecContext.type = ScExecContext::None; - } else if (r.name().toString().compare("invoke",Qt::CaseInsensitive) == 0) { - QString pnames; - bool first = true; - foreach (QString n, paramNames) { - if (!first) - pnames +=","; - pnames += QString("\"%1\"").arg(n); - first = false; - } - curExecContext.script += QString("_data.invoke_%1 = scxml.invoke(\"%2\",%3,[%4],[%5],%6); _data.invoke_%1.id = \"%1\";").arg(curState->objectName()).arg(targetType).arg(target).arg(pnames).arg(paramVals.join(",")).arg(content); - if (!idLocation.isEmpty()) { - curExecContext.script += QString("%1 = _data.invoke_%2;").arg(idLocation).arg(curState->objectName()); - } - curExecContext.state = curState; - curExecContext.type = ScExecContext::StateEntry; - curExecContext.applyScript(); - idLocation = ""; - curExecContext.type = ScExecContext::None; - } - } - } - } -} - - -QScxml* QScxmlLoader::load(QIODevice* device, QObject* obj, const QString & filename) -{ - if (device->bytesAvailable() == 0) { - qWarning() << QString("File %1 invalid or not found").arg(filename); - return NULL; - } - stateMachine = new QScxml(obj); - // traverse through the states - loadState(stateMachine,device,"",filename); - - // resolve history default state - foreach (ScHistoryInfo h, historyInfo) { - h.hstate->setDefaultState(stateByID[h.defaultStateID]); - } - foreach (QString s, signalEvents) { - QString sig = s; - sig = sig.mid(sig.indexOf(':')+1); -// sig = sig.left(sig.indexOf('(')); - int liop = sig.lastIndexOf('.'); - QString obj = sig.left(liop); - sig = sig.mid(liop+1); - stateMachine->pvt->startScript += QString("scxml.connectSignalToEvent(%1,'%2',\"%3\");").arg(obj).arg(sig).arg(s); - -// QString scr = QString("%1.connect({e:\"%2\"},_rcvSig);\n").arg(sig).arg(s); -/// stateMachine->pvt->startScript += scr; - } - - foreach (QState* s, statesWithFinal) { - QObject::connect(s,SIGNAL(finished()),stateMachine,SLOT(handleStateFinished())); - } - - // resolve transitions - - foreach (ScTransitionInfo t, transitions) { - QList<QAbstractState*> states; - if (!t.targets.isEmpty()) { - foreach (QString s, t.targets) { - if (!s.trimmed().isEmpty()) { - QAbstractState* st = stateByID[s]; - if (st) - states.append(st); - } - } - t.transition->setTargetStates(states); - } - } - - return stateMachine; -} - -void QScxml::handleStateFinished() -{ - QState* state = qobject_cast<QState*>(sender()); - if (state) { - postEvent(new QScxmlEvent("done.state." + state->objectName())); - } -} - -/*! - Loads a state machine from an scxml file located at \a filename, with parent object \a o. - */ -QScxml* QScxml::load (const QString & filename, QObject* o) -{ - QScxmlLoader l; - QFile f (filename); - f.open(QIODevice::ReadOnly); - return l.load(&f,o,filename); -} - -#include "qscxml.moc" -#endif diff --git a/src/qscxml.h b/src/qscxml.h deleted file mode 100644 index fc6b590..0000000 --- a/src/qscxml.h +++ /dev/null @@ -1,170 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2008-$THISYEAR$ $TROLLTECH$. All rights reserved. -** -** This file is part of the SCXML project on Trolltech Labs. -** -** $TROLLTECH_GPL_LICENSE$ -** -****************************************************************************/ - -#ifndef QSCXML_H -#define QSCXML_H -#ifndef QT_NO_STATEMACHINE - -#include <QStateMachine> -#include <QAbstractTransition> -#include <QVariant> -#include <QEvent> -#include <QStringList> -#include <QScriptValue> -#include <QUrl> - -class QScriptEngine; -class QScxml; - -class QScxmlEvent : public QEvent -{ - public: - static QEvent::Type eventType(); - QString eventName() const; - QStringList paramNames () const; - QVariantList paramValues () const; - QScriptValue content () const; - QVariant param (const QString & name) const; - QScxmlEvent ( - const QString & name, - const QStringList & paramNames = QStringList(), - const QVariantList & paramValues = QVariantList(), - const QScriptValue & content = QScriptValue()); - - struct MetaData - { - QUrl origin,target; - QString originType, targetType; - QString invokeID; - enum Kind { Platform, Internal, External } kind; - }; - - MetaData metaData; - - private: - QString ename; - QStringList pnames; - QVariantList pvals; - QScriptValue cnt; -}; - - -class QScxmlTransition : public QAbstractTransition -{ - Q_OBJECT - Q_PROPERTY(QString conditionExpression READ conditionExpression WRITE setConditionExpression) - Q_PROPERTY(QString eventPrefix READ eventPrefix WRITE setEventPrefix) - - public: - QScxmlTransition (QState* state, QScxml* machine); - - QString conditionExpression () const { return cond; } - void setConditionExpression (const QString & c) { cond = c; } - QString eventPrefix () const { return ev; } - void setEventPrefix (const QString & e) { ev = e; } - - protected: - bool eventTest(QEvent*); - void onTransition (QEvent*); - private: - QScxml* scxml; - QString ev,cond; -}; - -class QScxmlInvoker : public QObject -{ - Q_OBJECT - Q_PROPERTY (QString id READ id WRITE setID) - - protected: - QScxmlInvoker(QScxmlEvent* ievent, QStateMachine* p) : QObject(p), initEvent(ievent),cancelled(false) {} - - public: - virtual ~QScxmlInvoker(); - QString id () const; - void setID(const QString &); - - public Q_SLOTS: - virtual void activate() = 0; - virtual void cancel() { deleteLater(); } - - protected Q_SLOTS: - void postParentEvent (const QString & event); - - protected: - QScxml* parentStateMachine() { return (QScxml*)parent(); } - void postParentEvent (QScxmlEvent* ev); - QScxmlEvent* initEvent; - bool cancelled; - - friend struct QScxmlFunctions; -}; - -struct QScxmlInvokerFactory -{ - virtual QScxmlInvoker* createInvoker (QScxmlEvent* event, QScxml* stateMachine) = 0; - virtual bool isTypeSupported (const QString & type) const = 0; - virtual void init (QScxml*) = 0; -}; - -template <class T> -class QScxmlAutoInvokerFactory : public QScxmlInvokerFactory -{ - QScxmlInvoker* createInvoker (QScxmlEvent* _e, QScxml* _sm) { return new T(_e,_sm); } - bool isTypeSupported(const QString & _s) const { return T::isTypeSupported(_s); } - void init (QScxml* sm) { T::initInvokerFactory(sm); } -}; - - -class QScxml : public QStateMachine -{ - Q_OBJECT - - Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl) - - - public: - QScxml(QScriptEngine* engine, QObject* o = NULL); - QScxml(QObject* o = NULL); - virtual ~QScxml(); - protected: - // overloaded to store the event for the script environment's use (_event), and to convert - // StateFinished events to "done." named events - virtual void beginSelectTransitions(QEvent*); - virtual void endMicrostep(QEvent*); - - public: - QScriptEngine* scriptEngine () const; - void registerObject (QObject* object, const QString & name = QString(), bool recursive = false); - void registerInvokerFactory (QScxmlInvokerFactory* f); - void setBaseUrl (const QUrl &); - QUrl baseUrl () const; - static QScxml* load (const QString & filename, QObject* o = NULL); - - public Q_SLOTS: - void postNamedEvent(const QString &); - void executeScript (const QString &); - - private Q_SLOTS: - void registerSession(); - void unregisterSession(); - void handleStateFinished(); - - Q_SIGNALS: - void eventTriggered(const QString &); - - private: - class QScxmlPrivate* pvt; - friend class QScxmlLoader; - friend struct QScxmlFunctions; - void init(); -}; -#endif -#endif // QSCXML_H diff --git a/src/qscxml.pri b/src/qscxml.pri deleted file mode 100644 index 873c038..0000000 --- a/src/qscxml.pri +++ /dev/null @@ -1,7 +0,0 @@ -QT += script -SOURCES += $$PWD/qscxml.cpp \ - $$PWD/qscxmlgui.cpp - -HEADERS += $$PWD/qscxml.h \ - $$PWD/qscxmlgui.h -INCLUDEPATH += $$PWD
\ No newline at end of file diff --git a/src/qscxmlgui.cpp b/src/qscxmlgui.cpp deleted file mode 100644 index cb6745f..0000000 --- a/src/qscxmlgui.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2008-$THISYEAR$ $TROLLTECH$. All rights reserved. -** -** This file is part of the SCXML project on Trolltech Labs. -** -** $TROLLTECH_GPL_LICENSE$ -** -****************************************************************************/ - -#include "qscxmlgui.h" -#include <QMenu> -#include <QDebug> -#include <QMessageBox> -#include <QScriptValueIterator> -#include <QScriptEngine> -#include <QSignalMapper> -/* - - { "parent" : parentObject, - "trackHovers" : true/false - "children": {{"type": "action", "text": "",}, - {"type": "menu"}, - {"type": "separator"} }, - */ -namespace -{ - void traverseMenu (QMenu* menu, QScriptValue value, QSignalMapper* clickMap, QSignalMapper* hoverMap, bool trackHover) - { - QScriptValueIterator it (value); - while (it.hasNext()) { - it.next(); - if (it.name() == "trackHover") { - trackHover = it.value().toBoolean(); - } else if (it.name() == "parent") { - } else if (it.name() == "children") { - QScriptValueIterator cit (it.value()); - while (cit.hasNext()) { - cit.next(); - QString type = cit.value().property("type").toString(); - if (type == "action") { - QAction* act = menu->addAction(""); - QScriptValueIterator ait (cit.value()); - while (ait.hasNext()) { - ait.next(); - if (ait.name() != "type") { - act->setProperty(ait.name().toAscii().constData(),ait.value().toVariant()); - } - } - QObject::connect(act,SIGNAL(triggered()),clickMap,SLOT(map())); - clickMap->setMapping(act,QString("menu.action." + cit.value().property("id").toString())); - if (trackHover) { - QObject::connect(act,SIGNAL(hovered()),hoverMap,SLOT(map())); - hoverMap->setMapping(act,QString("menu.hover." + cit.value().property("id").toString())); - } - } else if (type == "menu") { - traverseMenu(menu->addMenu(""),it.value(),clickMap,hoverMap,trackHover); - } else if (type == "separator") { - menu->addSeparator(); - } - } - } else { - menu->setProperty(it.name().toAscii().constData(),it.value().toVariant()); - } - } - } -}; - -void QScxmlMenuInvoker::activate () -{ - QScxmlEvent* ie = initEvent; - QScriptValue v = ie->content(); - QWidget* parent = qobject_cast<QWidget*>(v.property("parent").toQObject()); - menu = new QMenu(parent); - QSignalMapper* clickMap = new QSignalMapper(this); - QSignalMapper* hoverMap = new QSignalMapper(this); - connect (clickMap,SIGNAL(mapped(QString)), this, SLOT(postParentEvent(QString))); - connect (hoverMap,SIGNAL(mapped(QString)), this, SLOT(postParentEvent(QString))); - traverseMenu(menu,v,clickMap,hoverMap,false); - menu->setParent(parent,Qt::Widget); - menu->move(QPoint(0,0)); - menu->resize(parent->size()); - menu->show(); -} -void QScxmlMenuInvoker::cancel () -{ - if (menu) - menu->deleteLater(); - QScxmlInvoker::cancel(); -} - -Q_SCRIPT_DECLARE_QMETAOBJECT(QMenu,QWidget*) -Q_SCRIPT_DECLARE_QMETAOBJECT(QMessageBox,QWidget*) - void QScxmlMenuInvoker::initInvokerFactory(QScxml* sm) - { - QScriptEngine* se = sm->scriptEngine(); - se->globalObject().setProperty("QMenu",qScriptValueFromQMetaObject<QMenu>(se)); - } - void QScxmlMessageBoxInvoker::initInvokerFactory(QScxml* sm) - { - QScriptEngine* se = sm->scriptEngine(); - se->globalObject().setProperty("QMessageBox",qScriptValueFromQMetaObject<QMessageBox>(se)); - } - -void QScxmlMessageBoxInvoker::onFinished(int n) { - postParentEvent(new QScxmlEvent("q-messagebox.finished",QStringList()<<"result",QVariantList()<<QVariant(n))); -} -/* - { "parent": someWidget, "buttons": ...} - */ -void QScxmlMessageBoxInvoker::activate() -{ - QScriptValue v = initEvent->content(); - QWidget* parent = qobject_cast<QWidget*>(v.property("parent").toQObject()); - messageBox = new QMessageBox(parent); - messageBox->setModal(false); - QScriptValueIterator it (v); - while (it.hasNext()) { - it.next(); - if (it.name() == "standardButtons") { - messageBox->setStandardButtons((QMessageBox::StandardButtons)it.value().toInt32()); - } else if (it.name() == "icon") { - messageBox->setIcon((QMessageBox::Icon)it.value().toInt32()); - } else if (it.name() != "parent") { - messageBox->setProperty(it.name().toAscii().constData(),it.value().toVariant()); - } - } - connect(messageBox,SIGNAL(finished(int)),this,SLOT(onFinished(int))); - messageBox->show (); -} - -void QScxmlMessageBoxInvoker::cancel() -{ - messageBox->deleteLater(); - QScxmlInvoker::cancel(); -} diff --git a/src/qscxmlgui.h b/src/qscxmlgui.h deleted file mode 100644 index ad5744c..0000000 --- a/src/qscxmlgui.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2008-$THISYEAR$ $TROLLTECH$. All rights reserved. -** -** This file is part of the SCXML project on Trolltech Labs. -** -** $TROLLTECH_GPL_LICENSE$ -** -****************************************************************************/ -#ifndef QSCXMLGUI_H -#define QSCXMLGUI_H - -#include "qscxml.h" -class QMenu; -class QMessageBox; - -class QScxmlMenuInvoker: public QScxmlInvoker -{ - Q_OBJECT - - public: - QScxmlMenuInvoker(QScxmlEvent* ievent, QScxml* p) : QScxmlInvoker(ievent,p),menu(0) - { - } - static void initInvokerFactory(QScxml*); - static bool isTypeSupported (const QString & s) { return s== "q-menu"; } - public Q_SLOTS: - void activate (); - void cancel (); - - private: - QMenu* menu; -}; - - -class QScxmlMessageBoxInvoker: public QScxmlInvoker -{ - Q_OBJECT - - public: - QScxmlMessageBoxInvoker(QScxmlEvent* ievent, QScxml* p) : QScxmlInvoker(ievent,p),messageBox(0) - { - } - - static void initInvokerFactory(QScxml*); - static bool isTypeSupported (const QString & s) { return s== "q-messagebox"; } - public Q_SLOTS: - void activate (); - void cancel (); - - private Q_SLOTS: - void onFinished (int); - private: - QMessageBox* messageBox; -}; - -#endif // QSSMGUIINVOKERS_P_H diff --git a/src/src.pro b/src/src.pro deleted file mode 100644 index df334f7..0000000 --- a/src/src.pro +++ /dev/null @@ -1,10 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2009-05-24T14:33:48 -# -#------------------------------------------------- -QT += script -TARGET = qscxml -TEMPLATE = lib -CONFIG += staticlib -include (qscxml.pri)
\ No newline at end of file |