From f1f797379920403bd68847988f78cab72c0fd111 Mon Sep 17 00:00:00 2001 From: No'am Rosenthal Date: Sun, 9 Aug 2009 23:16:53 -0700 Subject: Statechart Compiler with examples --- scc/README | 13 ++ scc/doc.txt | 78 ++++++++ scc/examples/algotest/algotest.pro | 6 + scc/examples/algotest/main.cpp | 56 ++++++ scc/examples/algotest/test.scxml | 145 ++++++++++++++ scc/examples/animations/animations.pro | 6 + scc/examples/animations/animations.scxml | 19 ++ scc/examples/animations/main.cpp | 81 ++++++++ scc/examples/examples.pro | 2 + scc/examples/loginmvc/controller.scxml | 105 ++++++++++ scc/examples/loginmvc/frame.ui | 123 ++++++++++++ scc/examples/loginmvc/loginmvc.pro | 8 + scc/examples/loginmvc/main.cpp | 192 ++++++++++++++++++ scc/main.cpp | 82 +++++++- scc/scc.prf | 21 ++ scc/scc.pro | 12 +- scc/scc.qrc | 3 +- scc/scc.xslt | 330 ++++++++++++++++++++----------- 18 files changed, 1159 insertions(+), 123 deletions(-) create mode 100644 scc/README create mode 100644 scc/doc.txt create mode 100644 scc/examples/algotest/algotest.pro create mode 100644 scc/examples/algotest/main.cpp create mode 100644 scc/examples/algotest/test.scxml create mode 100644 scc/examples/animations/animations.pro create mode 100644 scc/examples/animations/animations.scxml create mode 100644 scc/examples/animations/main.cpp create mode 100644 scc/examples/examples.pro create mode 100644 scc/examples/loginmvc/controller.scxml create mode 100644 scc/examples/loginmvc/frame.ui create mode 100644 scc/examples/loginmvc/loginmvc.pro create mode 100644 scc/examples/loginmvc/main.cpp create mode 100644 scc/scc.prf diff --git a/scc/README b/scc/README new file mode 100644 index 0000000..35e0ee0 --- /dev/null +++ b/scc/README @@ -0,0 +1,13 @@ +To build: + qmake + make + make install + +To use: + Add to your .pro file: + CONFIG += scc + STATECHARTS += path-to-my-statechart.scxml + +See the examples, and the documentation (currently only in doc.txt) + + diff --git a/scc/doc.txt b/scc/doc.txt new file mode 100644 index 0000000..6c82ebb --- /dev/null +++ b/scc/doc.txt @@ -0,0 +1,78 @@ +This document describes the expected behaviour of SCC (the Qt State Chart Compiler) in regards to SCXML tags and features. + +SCXML + Ignored: version, profile, exmode + +STATE + Ignored: src + +TRANSITION + Ignored: anchor + Additional: Qt:animation, a location expression that points to a QPropertyAnimation* object + Notes: An event in a transition translates to a Qt signal in the state machine object. "*" would occur on any event. Prefix matching is not supported, but * and done events are supported. + Conditions are C++ boolean expressions. +PARALLEL + Ignored: src + +HISTORY: + Notes: The history's default transition cannot have executable content. + +LOG: + Notes: the level of the log translates to QtMsgType. expr is a c++ expression. + +SEND: + Partially supported: target (only "_internal") + Ignored attributes: type, idlocation, hints + Notes: The target attribute can be either empty for a regular event, "_internal" for an internal-queue event, or a location expression to emit a signal in an object. + +CANCEL: + Notes: ID is a string literal, not an expression + +DATA: + Ignored attributes: src + Additional: Qt:type, to define a C++ type for this data element + Notes: A data element is converted to a Qt property of the state-machine object. expr/text are C++ expressions + +ASSIGN: + Notes: If dataid is present rather than location, the generated code would use the Qt property system to assign the value. expr is a c++ expression. + +PARAM + Notes: either name, expr or inline-text can appear, as the parameters are translated to a QVariantList. + +SCRIPT + Notes: raw C++ code + +Fully supported: + INITIAL, FINAL, ONENTRY, ONEXIT, IF, ELSEIF, ELSE, LOG, CANCEL, DATAMODEL + +Unsupported: + INVOKE, CONTENT, DONEDATA, FINALIZE, ANCHOR, VALIDATE + +Qt:property + object + property + value + +Qt:cpp + text() + +system variables + _event + _data + _name + + +INVOKE +CONTENT +VALIDATE +DONEDATA + + +script +Qt:cpp +cond +(variables) +param +log +if/elseif/else +assign diff --git a/scc/examples/algotest/algotest.pro b/scc/examples/algotest/algotest.pro new file mode 100644 index 0000000..e5a1eba --- /dev/null +++ b/scc/examples/algotest/algotest.pro @@ -0,0 +1,6 @@ +TEMPLATE = app +SOURCES += main.cpp +OTHER_FILES += test.scxml +STATECHARTS += test.scxml +CONFIG += scc console +QT -= gui diff --git a/scc/examples/algotest/main.cpp b/scc/examples/algotest/main.cpp new file mode 100644 index 0000000..c8b74e1 --- /dev/null +++ b/scc/examples/algotest/main.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "sc_test.h" +#include +#include +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + SMClass_test stateMachine; + stateMachine.setupStateMachine(); + stateMachine.start(); + QObject::connect(stateMachine.state_Test2Sub1,SIGNAL(entered()),&stateMachine,SIGNAL(event_Event2())); + QObject::connect(&stateMachine,SIGNAL(finished()),&a,SLOT(quit())); + QTimer::singleShot(100,&stateMachine,SIGNAL(event_Event1())); + return a.exec(); +} + diff --git a/scc/examples/algotest/test.scxml b/scc/examples/algotest/test.scxml new file mode 100644 index 0000000..e17f9bf --- /dev/null +++ b/scc/examples/algotest/test.scxml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scc/examples/animations/animations.pro b/scc/examples/animations/animations.pro new file mode 100644 index 0000000..d501c13 --- /dev/null +++ b/scc/examples/animations/animations.pro @@ -0,0 +1,6 @@ +TEMPLATE = app +OTHER_FILES += animations.scxml +STATECHARTS += animations.scxml +CONFIG += scc console +SOURCES += main.cpp +TARGET = animations diff --git a/scc/examples/animations/animations.scxml b/scc/examples/animations/animations.scxml new file mode 100644 index 0000000..0aabb64 --- /dev/null +++ b/scc/examples/animations/animations.scxml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/scc/examples/animations/main.cpp b/scc/examples/animations/main.cpp new file mode 100644 index 0000000..cf816bc --- /dev/null +++ b/scc/examples/animations/main.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "sc_animations.h" +#include +#include +#include +#include +#include +#include +#include +#include +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + SMClass_animations stateMachine; + QGraphicsView* gv = new QGraphicsView(); + QPushButton* b = new QPushButton(); + QWidget* w = new QWidget(); + QVBoxLayout* lyt = new QVBoxLayout(); + lyt->addWidget(gv); + lyt->addWidget(b); + b->setText("Push Me"); + QObject::connect(b,SIGNAL(clicked()),&stateMachine,SIGNAL(event_ev1())); + w->setLayout(lyt); + gv->setScene(new QGraphicsScene()); + gv->setInteractive(true); + gv->setFocus(); + QGraphicsProxyWidget* wdg = gv->scene()->addWidget(new QLabel("Hello World!")); + wdg->setOpacity(0); + QPropertyAnimation* anim = new QPropertyAnimation(); + anim->setPropertyName("opacity"); + anim->setTargetObject(wdg); + anim->setDuration(1000); + anim->setEasingCurve(QEasingCurve(QEasingCurve::InOutCubic)); + stateMachine.set_indicator(wdg); + stateMachine.set_anim(anim); + stateMachine.setupStateMachine(); + w->show(); + stateMachine.start(); + return a.exec(); +} + diff --git a/scc/examples/examples.pro b/scc/examples/examples.pro new file mode 100644 index 0000000..39b6dbb --- /dev/null +++ b/scc/examples/examples.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = loginmvc animations algotest diff --git a/scc/examples/loginmvc/controller.scxml b/scc/examples/loginmvc/controller.scxml new file mode 100644 index 0000000..8bffc1a --- /dev/null +++ b/scc/examples/loginmvc/controller.scxml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scc/examples/loginmvc/frame.ui b/scc/examples/loginmvc/frame.ui new file mode 100644 index 0000000..7f984de --- /dev/null +++ b/scc/examples/loginmvc/frame.ui @@ -0,0 +1,123 @@ + + + Frame + + + + 0 + 0 + 337 + 158 + + + + Frame + + + QFrame::StyledPanel + + + QFrame::Raised + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Username + + + + + + + + + + Password + + + + + + + QLineEdit::Password + + + + + + + Timeout + + + + + + + 20000 + + + 500 + + + 2000 + + + 10000 + + + Qt::Horizontal + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Log In + + + + + + + Logout + + + + + + + Cancel + + + + + + + + + + + + + + diff --git a/scc/examples/loginmvc/loginmvc.pro b/scc/examples/loginmvc/loginmvc.pro new file mode 100644 index 0000000..9af965a --- /dev/null +++ b/scc/examples/loginmvc/loginmvc.pro @@ -0,0 +1,8 @@ +TEMPLATE = app +CONFIG += console scc +SOURCES = main.cpp +FORMS += frame.ui +QT += network +STATECHARTS += controller.scxml +OTHER_FILES += controller.scxml +CONFIG -= app_bundle diff --git a/scc/examples/loginmvc/main.cpp b/scc/examples/loginmvc/main.cpp new file mode 100644 index 0000000..c01a3be --- /dev/null +++ b/scc/examples/loginmvc/main.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "sc_controller.h" +#include +#include +#include "ui_frame.h" +#include +#include +#include +class AbstractModel : public QObject +{ + Q_OBJECT + public: + AbstractModel(QObject* o = NULL) : QObject(o) + { + } + public slots: + virtual void login(const QString & u, const QString & p) = 0; + signals: + void loginComplete(bool); +}; + +class DummyModel : public AbstractModel +{ + Q_OBJECT + public: + DummyModel(QObject* o = NULL) : AbstractModel(o) + { + } + public slots: + void test() + { + emit loginComplete(user == "user" && password == "password"); + } + virtual void login(const QString & u, const QString & p) + { + user = u; password = p; + QTimer::singleShot(5000,this,SLOT(test())); + } + signals: + void loginComplete(bool); + private: + QString user,password; + QNetworkAccessManager netAccess; +}; +class GMailModel : public AbstractModel +{ + Q_OBJECT + public: + GMailModel(QObject* o = NULL) : AbstractModel(o) + { + } + public slots: + void loginFinished() + { + QNetworkReply* rep = qobject_cast(sender()); + rep->deleteLater(); + qDebug() << rep->error() << rep->errorString(); + emit loginComplete(rep->error() == QNetworkReply::NoError); + } + virtual void login(const QString & u, const QString & p) + { + QNetworkRequest req; + QUrl url("https://mail.google.com/mail/feed/atom"); + url.setUserName(u); + url.setPassword(p); + req.setUrl(url); + QNetworkReply* reply = netAccess.get(req); + reply->ignoreSslErrors(); + connect(reply,SIGNAL(finished()),this,SLOT(loginFinished())); + } + private: + QNetworkAccessManager netAccess; +}; + +class MyView : public QFrame, public virtual Ui::Frame +{ + Q_OBJECT + public: + MyView(QWidget* o = NULL) : QFrame(o) + { + setupUi(this); + connect(loginButton,SIGNAL(clicked()),this,SIGNAL(loginIntent())); + connect(logoutButton,SIGNAL(clicked()),this,SIGNAL(logoutIntent())); + connect(cancelButton,SIGNAL(clicked()),this,SIGNAL(cancelIntent())); + } + + public slots: + + void notifyLogin() + { + QMessageBox::information(this,"Logged In","You are now logged in!"); + emit contIntent(); + } + void notifyTimeout() + { + QMessageBox::information(this,"Timeout...","Sorry, login has timed out"); + emit contIntent(); + } + void notifyWelcome() + { + QMessageBox::information(this,"","Welcome!"); + } + void notifyError() + { + qDebug() << "notifyError"; + QMessageBox::warning(this,"Not Logged in","Login has failed..."); + emit contIntent(); + } + + void notifyHello(const QString & name) + { + QMessageBox::information(this,"Welcome",QString("Hello ") + name); + } + + signals: + void loginIntent(); + void logoutIntent(); + void cancelIntent(); + void contIntent(); +}; +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + AbstractModel* model = QSslSocket::supportsSsl () ? (AbstractModel*)new GMailModel() : (AbstractModel*)new DummyModel(); + MyView* view = new MyView(); + SMClass_controller *controller = new SMClass_controller(); + controller->setupStateMachine(); + controller->set_loginButton(view->loginButton); + controller->set_logoutButton(view->logoutButton); + controller->set_cancelButton(view->cancelButton); + QObject::connect(controller,SIGNAL(event_login_action(QString,QString)),model,SLOT(login(QString,QString))); + QObject::connect(controller,SIGNAL(event_notify_loggedIn()),view,SLOT(notifyLogin())); + QObject::connect(controller,SIGNAL(event_notify_error()),view,SLOT(notifyError())); + QObject::connect(controller,SIGNAL(event_notify_hello(QString)),view,SLOT(notifyHello(QString))); + QObject::connect(controller,SIGNAL(event_notify_welcome()),view,SLOT(notifyWelcome())); + QObject::connect(controller,SIGNAL(event_notify_timeout()),view,SLOT(notifyTimeout())); + QObject::connect(model,SIGNAL(loginComplete(bool)),controller,SIGNAL(event_login_complete(bool))); + QObject::connect(view,SIGNAL(loginIntent()),controller,SIGNAL(event_intent_login())); + QObject::connect(view,SIGNAL(cancelIntent()),controller,SIGNAL(event_cancel_login())); + QObject::connect(view,SIGNAL(logoutIntent()),controller,SIGNAL(event_intent_logout())); + QObject::connect(view,SIGNAL(contIntent()),controller,SIGNAL(event_intent_continue())); + QObject::connect(view->usernameEdit,SIGNAL(textChanged(QString)),controller,SLOT(set_username(QString))); + QObject::connect(view->passwordEdit,SIGNAL(textChanged(QString)),controller,SLOT(set_password(QString))); + QObject::connect(view->timeoutSlider,SIGNAL(valueChanged(int)),controller,SLOT(set_loginTimeout(int))); + controller->start(); + view->show(); + QObject::connect(view,SIGNAL(closed()),qApp,SLOT(quit())); + return a.exec(); +} +#include diff --git a/scc/main.cpp b/scc/main.cpp index 4ed1aff..e5f4206 100644 --- a/scc/main.cpp +++ b/scc/main.cpp @@ -1,23 +1,97 @@ -#include +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include #include #include #include #include #include +#include +#include +#include +#include +void usage() +{ + printf("scc [--no-comments] -i input-file -o output-file"); + exit(-1); +} int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QXmlQuery query(QXmlQuery::XSLT20); - QUrl target = QUrl::fromLocalFile(a.arguments()[1]); + if (a.arguments().count() < 3 || a.arguments().contains("--help")) + { + usage(); + } + int idxOfInput = a.arguments().indexOf("-i")+1; + int idxOfOutput = a.arguments().indexOf("-o")+1; + if (idxOfInput <= 1 && idxOfOutput <= 1) + { + usage(); + } + QString input = a.arguments().at(idxOfInput); + QString output = a.arguments().at(idxOfOutput); + QUrl target = QUrl::fromLocalFile(QDir::current().absoluteFilePath(".")).resolved(QUrl(input)); +// QXmlSchema schema; +// QFile schemaFile(":/scxml.xsd"); +// schemaFile.open(QIODevice::ReadOnly); +// schema.load(&schemaFile); +// QXmlSchemaValidator validator; +// if (!validator.validate(target)) { +// return -1; +// } query.setFocus(target); QFile q(":/scc/scc.xslt"); q.open(QIODevice::ReadOnly); query.bindVariable("target",QXmlItem(QFileInfo(target.toLocalFile()).baseName())); + query.bindVariable("comments",QXmlItem(!a.arguments().contains("--no-comments"))); query.setQuery(QString(q.readAll())); + if (!query.isValid()) + return -1; + QString s; query.evaluateTo(&s); - s = s.replace("<","<").replace(">",">").replace("&","&"); - QFile f(a.arguments()[2]); + s = s.replace("<","<").replace(""","\"").replace(">",">").replace("&","&"); + QFile f(output); f.open(QIODevice::WriteOnly); f.write(s.toUtf8()); return 0; diff --git a/scc/scc.prf b/scc/scc.prf new file mode 100644 index 0000000..b6ecc21 --- /dev/null +++ b/scc/scc.prf @@ -0,0 +1,21 @@ +isEmpty(QMAKE_SCC) { + win32:QMAKE_SCC = $$[QT_INSTALL_BINS]\scc.exe + else:QMAKE_SCC = $$[QT_INSTALL_BINS]/scc +} + +isEmpty(QMAKE_MOD_SCC):QMAKE_MOD_SCC = sc_ + +scc.output = $$QMAKE_MOD_SCC${QMAKE_FILE_BASE}.h +scc.commands = $$QMAKE_SCC -i ${QMAKE_FILE_NAME} -o ${QMAKE_FILE_OUT} +scc.depends = ${QMAKE_FILE_NAME} $$QMAKE_SCC +scc.input = STATECHARTS +scc.variable_out = SCC_HEADERS HEADERS GENERATED_FILES +QMAKE_EXTRA_COMPILERS += scc +load(moc) +scc_moc.commands = $$moc_header.commands +scc_moc.output = $$moc_header.output +scc_moc.input = SCC_HEADERS +scc_moc.variable_out = GENERATED_SOURCES +scc_moc.name = $$moc_header.name +QMAKE_EXTRA_COMPILERS += scc_moc + diff --git a/scc/scc.pro b/scc/scc.pro index db41f1e..32008bb 100644 --- a/scc/scc.pro +++ b/scc/scc.pro @@ -1,16 +1,16 @@ # ------------------------------------------------- # Project created by QtCreator 2009-08-02T10:07:01 # ------------------------------------------------- -QT += network \ - xmlpatterns +QT += xmlpatterns QT -= gui TARGET = scc CONFIG += console CONFIG -= app_bundle TEMPLATE = app SOURCES += main.cpp -OTHER_FILES += scc.xslt \ - test.scxml \ - scc-example.hh \ - xipr.xsl RESOURCES += scc.qrc +target.path = $$[QT_INSTALL_PREFIX]/bin +prf.files = scc.prf +prf.path = $$[QMAKE_MKSPECS]/features +INSTALLS += target prf +OTHER_FILES += scc.prf diff --git a/scc/scc.qrc b/scc/scc.qrc index a03d93a..0e4ffa0 100644 --- a/scc/scc.qrc +++ b/scc/scc.qrc @@ -1,6 +1,5 @@ - + scc.xslt - xipr.xsl diff --git a/scc/scc.xslt b/scc/scc.xslt index de42521..e023e96 100644 --- a/scc/scc.xslt +++ b/scc/scc.xslt @@ -1,73 +1,112 @@ - - - + + + - - + + /* + + + + */ + + + this state_ state_ - - if () { + + + if () { - } + } - - } else { + + + } else { - - } else if () { + + + } else if () { - - QDebug((QtMsgType)0) << "" << ; + + + QDebug((QtMsgType)0) << "" << ; - - - set_(); - + + + + + set_(); + + + = (); + + - + + postInternalEvent( - eventSenders[] = new SCC_EventSender(this,0 + _eventSenders[""] = new SCC_EventSender(this,0 , - new QSignalEvent( + new QSignalEvent(this,(*metaObject()).indexOfSignal(""),QVariantList() QVariant() + select="@target" />,metaObject()->indexOfSignal(QMetaObject::normalizedSignature("event_()")),QVariantList() QVariant( + + get_() + + ) )); - - { QObject* obj = eventSenders[]; if (obj) { (*obj).cancel(); } + + es = _eventSenders["]]>"]; + if (es) + es->cancel(); + } +#ifndef __SMCLASS__H +#define __SMCLASS__H #include "QStateMachine" #include "QSignalTransition" - #include "QTimer" - - +#include "QMetaMethod" +#include "QPointer" +#include "QVariant" + + #include "QFinalState" - + #include "QHistoryState" #include "QHash" #include "QSignalEvent" #include "QEventTransition" - + #include "QDebug" -#ifndef __SMCLASS__H -#define __SMCLASS__H + +#include "QPropertyAnimation" + + +#define In(state) (configuration().contains(state_##state)) + + + class SMClass_; - + class SCC_UnconditionalTransition : public QAbstractTransition { public: @@ -78,34 +117,51 @@ class SMClass_; bool eventTest(QEvent *) { return true; } }; - + + I \ + ? QGenericArgument(((QSignalEvent*)event)->arguments()[I].typeName(),((QSignalEvent*)event)->arguments()[I].data()) \ + : QGenericArgument()) + + class SCC_EventSender : public QTimer { Q_OBJECT private: QStateMachine* machine; - QEvent* event; + QSignalEvent* event; public: - SCC_EventSender(QStateMachine* m, int delay, QEvent* e) : QTimer(m), machine(m), event(e) + SCC_EventSender(QStateMachine* m=NULL, int delay=0, QSignalEvent* e=NULL) : QTimer(m), machine(m), event(e) { setInterval(delay); setSingleShot(true); connect(this,SIGNAL(timeout()),this,SLOT(send())); + start(); } public Q_SLOTS: void cancel() { stop(); deleteLater(); } - void send() { machine->postEvent(event); } + void send() { + QVariantList args = event->arguments(); + int acount = args.count(); + event->sender()->metaObject()->method(event->signalIndex()).invoke(event->sender(), + ARG_FROM_VAR(0),ARG_FROM_VAR(1),ARG_FROM_VAR(2),ARG_FROM_VAR(3),ARG_FROM_VAR(4), + ARG_FROM_VAR(5),ARG_FROM_VAR(6),ARG_FROM_VAR(7),ARG_FROM_VAR(8),ARG_FROM_VAR(9)); + deleteLater(); + } }; - - + ]]> + namespace { - - class Transition_ : public QSignalTransition + + + class Transition_ : public QSignalTransition { SMClass_* stateMachine; public: Transition_(QState* parent) - : QSignalTransition(parent),stateMachine((SMClass_*)(*parent).machine()) + : QSignalTransition(parent->machine(),SIGNAL(destroyed())SIGNAL(event_),parent) + ,stateMachine((SMClass_*)parent->machine()) { } @@ -119,145 +175,197 @@ namespace { class SMClass_ : public QStateMachine { Q_OBJECT - - Q_PROPERTY( READ get_ WRITE set_ NOTIFY _changed) + + + Q_PROPERTY( READ get_ WRITE set_ NOTIFY _changed) - - Q_PROPERTY(QAbstractAnimation* READ anim_ WRITE setAnim_) + + + Q_PROPERTY(QPropertyAnimation* READ anim_ WRITE setAnim_) public: - SMClass_(QObject* o) : QStateMachine(o) {} - - QState* ; - - QFinalState* ; + SMClass_(QObject* o = NULL) + : QStateMachine(o) + { + + + + _data. = ; + + + } + + + QState* ; + + + QFinalState* ; - - QHistoryState* ; + + + QHistoryState* ; - - bool testCondition_(const QEvent & _event) + + + inline bool testCondition_() { - Q_UNUSED(_event) return true; } - - get_() const + + + get_() const { return _data.; } - void set_(const & value) - { - _data. = value; - emit _changed(value); - } - + - ; + ]]> + + ; + } _data; - - void initScript() + struct { + QString name; + QVariantList data; + } _event; + QString _name; + + public Q_SLOTS: + + + + void set_( const & value) { - - - _data. = ; - - - + _data. = value; + emit _changed(value); } - + private Q_SLOTS: - +#ifndef QT_NO_PROPERTIES + void assignProperties() + { + + + ->assignProperty(,"",QVariant()); + +#endif + } + + void exec_() { } - Q_SIGNALS: - void event_(); - - void _changed(const &); + Q_SIGNALS: + void event_(); + + + void _changed( const &); - + - (*).assignProperty(,"",QVariant()); - + if (event && !event->type() == QEvent::None) { + switch (event->type()) { + case QEvent::Signal: { + QSignalEvent* e = (QSignalEvent*)event; + _event.data = e->arguments(); + _event.name = e->sender()->metaObject()->method(e->signalIndex()).signature(); + if (e->sender() == this) + _event.name = _event.name.mid(6); + } break; + default: + break; + } + } else { + _event.name = ""; + _event.data.clear(); + } + ]]> + assignProperties(); } -#endif - - + + private: - ]]> _eventSenders; + >]]> _eventSenders; + protected: public: void setupStateMachine() { - setObjectName(""); - - = new + _name = ""; + setObjectName(_name); + + + = new QFinalState QHistoryState QState (); - (*).setObjectName(""); - ->setObjectName(""); + - (*).setInitialState(); + ->setInitialState(); + - (*).setChildMode(ParallelStates); - + ->setChildMode(ParallelStates); + - (*).setHistoryType(QHistoryState:: + ->setHistoryType(QHistoryState:: Deep Shallow History); - + - QAbstractTransition* transition; + QAbstractTransition* transition; + transition = new - Transition_Transition_( QEventTransition(, QSignalTransition(state_,SIGNAL(finished()), - QSignalTransition(this,SIGNAL(event_()), + QSignalTransition(this,SIGNAL(event_()), SCC_UnconditionalTransition(); connect(transition,SIGNAL(triggered()),this,SLOT(exec_())); - - (*transition).addAnimation(); + transition->addAnimation(); - (*transition).setTargetState(state_); + transition->setTargetState(state_); (*transition).setTargetStates(QList<QAbstractState*>() << state_); - + + ->setDefaultState(state_); + + connect(, SIGNAL( entered exited ()),this,SLOT(exec_())); + } }; - + + bool Transition_::eventTest(QEvent* e) { - return QSignalTransition::eventTest(e) - && stateMachine->testCondition_(e?(*e):QEvent(QEvent::None)); + return QSignalTransition::eventTest(e) + (*e).type() != QEvent::None&& stateMachine->testCondition_(); } #endif -- cgit v1.2.3