diff options
author | Erik Verbruggen <erik.verbruggen@theqtcompany.com> | 2015-08-14 14:49:09 +0200 |
---|---|---|
committer | Erik Verbruggen <erik.verbruggen@theqtcompany.com> | 2015-08-25 12:55:10 +0300 |
commit | 39ea04908cc0eeaaa474ba1320cc6b7109ad6434 (patch) | |
tree | ba6954c5ba42b8113c21c9c15a5c5b3a7888dd49 /tools | |
parent | 837b69a4aaee8c7262acbf8bfb6919377408b1a9 (diff) |
Pass data in & out of a state-machine.
For both C++ and QML, both for dynamically instantiated state machines
and for state machines that are compiled to C++:
- all states are exposed by name as properties
- all signals of type "qt:signal" are signals
- all events on which transitions react are slots
Both signals and slots take a QVariant as parameter, which holds the
_event.data property contents/params.
The mediaplayer examples use the signals and slots to pass data out of,
respectively into the state machine.
Change-Id: Id4198450c2cc4b3ebdea25c6da729751bbdd194c
Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/qscxmlc/scxmlcppdumper.cpp | 101 |
1 files changed, 81 insertions, 20 deletions
diff --git a/tools/qscxmlc/scxmlcppdumper.cpp b/tools/qscxmlc/scxmlcppdumper.cpp index f8dfe2e..8c926b5 100644 --- a/tools/qscxmlc/scxmlcppdumper.cpp +++ b/tools/qscxmlc/scxmlcppdumper.cpp @@ -51,22 +51,24 @@ struct StringListDumper { return text.isEmpty(); } - void write(QTextStream &out, const QString &prefix, const QString &suffix) const + void write(QTextStream &out, const QString &prefix, const QString &suffix, const QString &mainClassName = QString()) const { - foreach (const QString &line, text) + foreach (QString line, text) { + if (!mainClassName.isEmpty() && line.contains(QStringLiteral("%"))) { + line = line.arg(mainClassName); + } out << prefix << line << suffix; + } } QStringList text; }; struct Method { - QString name; - StringListDumper publicDeclaration; // void f(int i = 0); - StringListDumper implementationHeader; // void f(int i) StringListDumper initializer; - StringListDumper publicImplementationCode; // d->f(i); - StringListDumper impl; // m_i = ++i; + Method(const QString &decl = QString()): decl(decl) {} + QString decl; // void f(int i = 0); + StringListDumper impl; // void f(int i) { m_i = ++i; } }; struct MainClass { @@ -79,11 +81,11 @@ struct MainClass { StringListDumper dataMethods; Method constructor; Method destructor; + StringListDumper properties; StringListDumper signalMethods; QList<Method> publicMethods; StringListDumper publicSlotDeclarations; StringListDumper publicSlotDefinitions; - QList<Method> privateMethods; }; namespace { @@ -267,7 +269,15 @@ protected: bool visit(State *node) Q_DECL_OVERRIDE { - auto stateName = QStringLiteral("state_") + mangledName(node); + auto name = mangledName(node); + auto stateName = QStringLiteral("state_") + name; + // Property stuff: + clazz.properties << QStringLiteral("Q_PROPERTY(QAbstractState *%1 READ %1() CONSTANT)").arg(name); // FIXME: notify! + Method getter(QStringLiteral("QAbstractState *%1() const").arg(name)); + getter.impl << QStringLiteral("QAbstractState *%2::%1() const").arg(name) + << QStringLiteral("{ return &data->%1; }").arg(stateName); + clazz.publicMethods << getter; + // Declaration: if (node->type == State::Final) { clazz.classFields << QStringLiteral("Scxml::ScxmlFinalState ") + stateName + QLatin1Char(';'); @@ -438,6 +448,18 @@ protected: return false; } + bool visit(Send *node) Q_DECL_OVERRIDE + { + if (node->type == QStringLiteral("qt:signal")) { + if (!m_signals.contains(node->event)) { + m_signals.insert(node->event); + clazz.signalMethods << QStringLiteral("void event_%1(const QVariant &data);").arg(CppDumper::mangleId(node->event)); + } + } + + return ExecutableContent::Builder::visit(node); + } + private: QString mangledName(AbstractState *state) { @@ -522,7 +544,7 @@ private: { QStringList knownEventsList = m_knownEvents.toList(); std::sort(knownEventsList.begin(), knownEventsList.end()); - foreach (QString event, knownEventsList) { + foreach (const QString &event, knownEventsList) { if (event.startsWith(QStringLiteral("done.")) || event.startsWith(QStringLiteral("qsignal.")) || event.startsWith(QStringLiteral("qevent."))) { continue; @@ -530,12 +552,27 @@ private: if (event.contains(QLatin1Char('*'))) continue; - clazz.publicSlotDeclarations << QStringLiteral("void event_") + CppDumper::mangleId(event) + QStringLiteral("();"); + clazz.publicSlotDeclarations << QStringLiteral("void event_") + CppDumper::mangleId(event) + QStringLiteral("(const QVariant &eventData = QVariant());"); clazz.publicSlotDefinitions << QStringLiteral("void ") + m_mainClassName + QStringLiteral("::event_") + CppDumper::mangleId(event) - + QStringLiteral("()\n{ submitEvent(data->") + qba(event) - + QStringLiteral("); }"); + + QStringLiteral("(const QVariant &eventData)\n{ submitEvent(data->") + qba(event) + + QStringLiteral(", eventData); }"); + } + + if (!m_signals.isEmpty()) { + clazz.init.impl << QStringLiteral("stateMachine.setScxmlEventFilter(this);"); + auto &dm = clazz.dataMethods; + dm << QStringLiteral("bool handle(Scxml::ScxmlEvent *event, Scxml::StateMachine *stateMachine) Q_DECL_OVERRIDE {") + << QStringLiteral(" if (event->origintype() != QStringLiteral(\"qt:signal\")) { return true; }") + << QStringLiteral(" %1 *m = qobject_cast<%1 *>(stateMachine);").arg(m_mainClassName); + foreach (const QString &s, m_signals) { + dm << QStringLiteral(" if (event->name() == %1) { emit m->event_%2(event->data()); return false; }") + .arg(qba(s), CppDumper::mangleId(s)); + } + dm << QStringLiteral(" return true;") + << QStringLiteral("}") + << QString(); } } @@ -627,9 +664,9 @@ private: return QString(); }); t << QStringLiteral("};") << QStringLiteral(""); - clazz.dataMethods << QStringLiteral("Scxml::ExecutableContent::Instructions instructions() const Q_DECL_OVERRIDE"); - clazz.dataMethods << QStringLiteral("{ return theInstructions; }"); - clazz.dataMethods << QString(); + clazz.dataMethods << QStringLiteral("Scxml::ExecutableContent::Instructions instructions() const Q_DECL_OVERRIDE") + << QStringLiteral("{ return theInstructions; }") + << QString(); } { // strings @@ -831,6 +868,7 @@ private: QHash<DocumentModel::AbstractState *, QString> m_mangledNames; QVector<Node *> m_parents; QSet<QString> m_knownEvents; + QSet<QString> m_signals; QString m_currentTransitionName; bool m_bindLate; QVector<DocumentModel::DataElement *> m_dataElements; @@ -864,11 +902,26 @@ void CppDumper::dump(DocumentModel::ScxmlDocument *doc) if (!options.namespaceName.isEmpty()) h << l("namespace ") << options.namespaceName << l(" {") << endl << endl; h << l("class ") << mainClassName << l(" : public Scxml::StateMachine\n{") << endl; - h << QLatin1String(" Q_OBJECT\n\n"); - h << QLatin1String("public:\n"); + h << QLatin1String(" Q_OBJECT\n"); + clazz.properties.write(h, QStringLiteral(" "), QStringLiteral("\n")); + h << QLatin1String("\npublic:\n"); h << l(" ") << mainClassName << l("(QObject *parent = 0);") << endl; h << l(" ~") << mainClassName << "();" << endl; + if (!clazz.publicMethods.isEmpty()) { + h << endl; + foreach (const Method &m, clazz.publicMethods) { + h << QStringLiteral(" ") << m.decl << QLatin1Char(';') << endl; + } + } + + if (!clazz.signalMethods.isEmpty()) { + h << endl + << QStringLiteral("signals:") + << endl; + clazz.signalMethods.write(h, QStringLiteral(" "), QStringLiteral("\n")); + } + if (!clazz.publicSlotDeclarations.isEmpty()) { h << "\npublic slots:\n"; clazz.publicSlotDeclarations.write(h, QStringLiteral(" "), QStringLiteral("\n")); @@ -897,7 +950,11 @@ void CppDumper::dump(DocumentModel::ScxmlDocument *doc) if (!options.namespaceName.isEmpty()) cpp << l("namespace ") << options.namespaceName << l(" {") << endl << endl; - cpp << l("struct ") << mainClassName << l("::Data: private Scxml::TableData {") << endl; + cpp << l("struct ") << mainClassName << l("::Data: private Scxml::TableData"); + if (!clazz.signalMethods.isEmpty()) { + cpp << QStringLiteral(", public Scxml::ScxmlEventFilter"); + } + cpp << l(" {") << endl; cpp << QStringLiteral(" Data(%1 &stateMachine)\n : stateMachine(stateMachine)").arg(mainClassName) << endl; clazz.constructor.initializer.write(cpp, QStringLiteral(" , "), QStringLiteral("\n")); @@ -919,11 +976,15 @@ void CppDumper::dump(DocumentModel::ScxmlDocument *doc) cpp << mainClassName << l("::") << mainClassName << l("(QObject *parent)") << endl << l(" : Scxml::StateMachine(parent)") << endl << l(" , data(new Data(*this))") << endl - << l("{}") << endl + << l("{ qRegisterMetaType<QAbstractState *>(); }") << endl << endl; cpp << mainClassName << l("::~") << mainClassName << l("()") << endl << l("{ delete data; }") << endl << endl; + foreach (const Method &m, clazz.publicMethods) { + m.impl.write(cpp, QStringLiteral(""), QStringLiteral("\n"), mainClassName); + cpp << endl; + } clazz.publicSlotDefinitions.write(cpp, QStringLiteral("\n"), QStringLiteral("\n")); cpp << endl; |