summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2016-11-18 16:13:28 +0100
committerUlf Hermann <ulf.hermann@qt.io>2016-12-13 15:08:33 +0000
commitc99c561ee94076c84ddfdf1643a4e50f0a8ce173 (patch)
tree4e904db456fcbda433c94efaa55f38d1d407f968 /tools
parent00cf1300fc127d4656f474de46ff845d917b0a26 (diff)
Optionally generate accessor and signal methods for states
We can easily do this and provide a much nicer API. These methods are not available for dynamically loaded state machines. By default we provide the same API for compiled and loaded state machines. The new methods are only generated if you pass the "--statemethods" parameter to qscxmlc. A new qmake variable called "QSCXMLC_ARGUMENTS" is added for any extra arguments to qscxmlc such as this one. Change-Id: Ie7a4eb4890c9d42f89093f3cf3ea917ef2793518 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
Diffstat (limited to 'tools')
-rw-r--r--tools/qscxmlc/decl.t5
-rw-r--r--tools/qscxmlc/doc/qscxmlc.qdoc8
-rw-r--r--tools/qscxmlc/generator.cpp36
-rw-r--r--tools/qscxmlc/generator.h3
-rw-r--r--tools/qscxmlc/moc.h4
-rw-r--r--tools/qscxmlc/qscxmlc.cpp4
-rw-r--r--tools/qscxmlc/scxmlcppdumper.cpp64
-rw-r--r--tools/qscxmlc/scxmlcppdumper.h6
8 files changed, 117 insertions, 13 deletions
diff --git a/tools/qscxmlc/decl.t b/tools/qscxmlc/decl.t
index 9482885..482c123 100644
--- a/tools/qscxmlc/decl.t
+++ b/tools/qscxmlc/decl.t
@@ -8,6 +8,11 @@ public:
${classname}(QObject *parent = 0);
~${classname}();
+${accessors}
+
+Q_SIGNALS:
+${signals}
+
private:
struct Data;
friend struct Data;
diff --git a/tools/qscxmlc/doc/qscxmlc.qdoc b/tools/qscxmlc/doc/qscxmlc.qdoc
index 07b5c8d..bf38a63 100644
--- a/tools/qscxmlc/doc/qscxmlc.qdoc
+++ b/tools/qscxmlc/doc/qscxmlc.qdoc
@@ -58,7 +58,8 @@
\section1 Command-Line Options
- The \c qscxmlc tool supports the following command-line options:
+ The \c qscxmlc tool supports the following command-line options, which can be specified using
+ the \c QSCXMLC_ARGUMENTS variable in the project file:
\table
\header
@@ -83,5 +84,10 @@
\li The class name of the generated state machine. If none is specified, the value of the
name attribute of the <scxml> tag is taken. If that attribute is not specified either,
the basename (excluding path) is taken from the input file name.
+ \row
+ \li \c --statemethods
+ \li Generate extra accessor and signal methods for states. This way you can connect to
+ state changes with plain QObject::connect() and directly call a method to find out if
+ a state is currently active.
\endtable
*/
diff --git a/tools/qscxmlc/generator.cpp b/tools/qscxmlc/generator.cpp
index 9082efa..02e41c8 100644
--- a/tools/qscxmlc/generator.cpp
+++ b/tools/qscxmlc/generator.cpp
@@ -587,6 +587,7 @@ void Generator::generateCode()
for (int signalindex = 0; signalindex < cdef->signalList.size(); ++signalindex)
generateSignal(&cdef->signalList[signalindex], signalindex);
+ fprintf(out, "\n");
//
// Generate plugin meta data
//
@@ -1149,7 +1150,7 @@ void Generator::generateStaticMetacall()
//---- Changed from the original in moc
if (f.implementation) {
- fprintf(out, f.implementation, methodindex);
+ fprintf(out, f.implementation, "_o", methodindex);
fprintf(out, " break;\n");
continue;
}
@@ -1223,7 +1224,7 @@ void Generator::generateStaticMetacall()
bool anythingUsed = false;
for (int methodindex = 0; methodindex < cdef->signalList.size(); ++methodindex) {
const FunctionDef &f = cdef->signalList.at(methodindex);
- if (f.wasCloned || !f.inPrivateClass.isEmpty() || f.isStatic || f.implementation)
+ if (f.wasCloned || !f.inPrivateClass.isEmpty() || f.isStatic || f.mangledName.isEmpty())
continue;
anythingUsed = true;
fprintf(out, " {\n");
@@ -1246,8 +1247,9 @@ void Generator::generateStaticMetacall()
else
fprintf(out, ");\n");
fprintf(out, " if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&%s::%s)) {\n",
- cdef->classname.constData(), f.name.constData());
+ cdef->classname.constData(), f.mangledName.constData());
fprintf(out, " *result = %d;\n", methodindex);
+ fprintf(out, " return;\n");
fprintf(out, " }\n }\n");
}
if (!anythingUsed)
@@ -1521,6 +1523,34 @@ void Generator::generateSignal(FunctionDef *def,int index)
fprintf(out, "}\n");
}
+void Generator::generateAccessorDefs()
+{
+ for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
+ const PropertyDef &p = cdef->propertyList.at(propindex);
+ if (p.read.isEmpty() || p.mangledName.isEmpty())
+ continue;
+
+ fprintf(out, "bool %s::%s() const\n{\n return %s;\n}\n\n", cdef->classname.constData(),
+ p.mangledName.constData(), p.read.constData());
+ }
+}
+
+void Generator::generateSignalDefs()
+{
+ for (int methodindex = 0; methodindex < cdef->signalList.size(); ++methodindex) {
+ const FunctionDef &f = cdef->signalList.at(methodindex);
+ if (!f.implementation || f.mangledName.isEmpty())
+ continue;
+
+ fprintf(out, "void %s::%s(bool _t1)\n{\n", cdef->classname.constData(),
+ f.mangledName.constData());
+ fprintf(out, " void *_a[] = { Q_NULLPTR, "
+ "const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };\n ");
+ fprintf(out, f.implementation, "this", methodindex);
+ fprintf(out, "\n}\n\n");
+ }
+}
+
#if 0
static void writePluginMetaData(FILE *out, const QJsonObject &data)
{
diff --git a/tools/qscxmlc/generator.h b/tools/qscxmlc/generator.h
index 21d82d3..9109188 100644
--- a/tools/qscxmlc/generator.h
+++ b/tools/qscxmlc/generator.h
@@ -46,6 +46,9 @@ public:
QByteArray> &knownQObjectClasses, const QHash<QByteArray, QByteArray> &knownGadgets,
QIODevice &outfile);
void generateCode();
+ void generateAccessorDefs();
+ void generateSignalDefs();
+
private:
bool registerableMetaType(const QByteArray &propertyType);
void registerClassInfoStrings();
diff --git a/tools/qscxmlc/moc.h b/tools/qscxmlc/moc.h
index 36cff5f..a2ecb88 100644
--- a/tools/qscxmlc/moc.h
+++ b/tools/qscxmlc/moc.h
@@ -83,6 +83,7 @@ struct FunctionDef
QByteArray normalizedType;
QByteArray tag;
QByteArray name;
+ QByteArray mangledName;
bool returnTypeIsVolatile;
QList<ArgumentDef> arguments;
@@ -114,7 +115,8 @@ struct FunctionDef
struct PropertyDef
{
PropertyDef():notifyId(-1), constant(false), final(false), gspec(ValueSpec), revision(0){}
- QByteArray name, type, member, read, write, reset, designable, scriptable, editable, stored, user, notify, inPrivateClass;
+ QByteArray name, mangledName, type, member, read, write, reset, designable, scriptable,
+ editable, stored, user, notify, inPrivateClass;
int notifyId;
bool constant;
bool final;
diff --git a/tools/qscxmlc/qscxmlc.cpp b/tools/qscxmlc/qscxmlc.cpp
index 89abdaa..ce45ed0 100644
--- a/tools/qscxmlc/qscxmlc.cpp
+++ b/tools/qscxmlc/qscxmlc.cpp
@@ -122,6 +122,8 @@ int run(const QStringList &arguments)
QCommandLineOption optionClassName(QLatin1String("classname"),
QCoreApplication::translate("main", "Generate <name> for state machine class name."),
QCoreApplication::translate("main", "name"));
+ QCommandLineOption optionStateMethods(QLatin1String("statemethods"),
+ QCoreApplication::translate("main", "Generate read and notify methods for states"));
cmdParser.addPositionalArgument(QLatin1String("input"),
QCoreApplication::translate("main", "Input SCXML file."));
@@ -130,6 +132,7 @@ int run(const QStringList &arguments)
cmdParser.addOption(optionOutputHeaderName);
cmdParser.addOption(optionOutputSourceName);
cmdParser.addOption(optionClassName);
+ cmdParser.addOption(optionStateMethods);
cmdParser.process(arguments);
@@ -149,6 +152,7 @@ int run(const QStringList &arguments)
const QString scxmlFileName = inputFiles.at(0);
TranslationUnit options;
+ options.stateMethods = cmdParser.isSet(optionStateMethods);
if (cmdParser.isSet(optionNamespace))
options.namespaceName = cmdParser.value(optionNamespace);
QString outFileName = cmdParser.value(optionOutputBaseName);
diff --git a/tools/qscxmlc/scxmlcppdumper.cpp b/tools/qscxmlc/scxmlcppdumper.cpp
index b539e0d..d99b3b0 100644
--- a/tools/qscxmlc/scxmlcppdumper.cpp
+++ b/tools/qscxmlc/scxmlcppdumper.cpp
@@ -506,6 +506,13 @@ void CppDumper::writeClass(const QString &className, const GeneratedTableData::M
Replacements r;
r[QStringLiteral("classname")] = className;
r[QStringLiteral("properties")] = generatePropertyDecls(info);
+ if (m_translationUnit->stateMethods) {
+ r[QStringLiteral("accessors")] = generateAccessorDecls(info);
+ r[QStringLiteral("signals")] = generateSignalDecls(info);
+ } else {
+ r[QStringLiteral("accessors")] = QString();
+ r[QStringLiteral("signals")] = QString();
+ }
genTemplate(h, QStringLiteral(":/decl.t"), r);
}
@@ -699,8 +706,42 @@ QString CppDumper::generatePropertyDecls(const GeneratedTableData::MetaDataInfo
QString decls;
for (const QString &stateName : info.stateNames) {
- if (!stateName.isEmpty())
+ if (stateName.isEmpty())
+ continue;
+
+ if (m_translationUnit->stateMethods) {
+ decls += QString::fromLatin1(" Q_PROPERTY(bool %1 READ %2 NOTIFY %3)\n")
+ .arg(stateName, mangleIdentifier(stateName),
+ mangleIdentifier(stateName + QStringLiteral("Changed")));
+ } else {
decls += QString::fromLatin1(" Q_PROPERTY(bool %1)\n").arg(stateName);
+ }
+ }
+
+ return decls;
+}
+
+QString CppDumper::generateAccessorDecls(const GeneratedTableData::MetaDataInfo &info)
+{
+ QString decls;
+
+ for (const QString &stateName : info.stateNames) {
+ if (!stateName.isEmpty())
+ decls += QString::fromLatin1(" bool %1() const;\n").arg(mangleIdentifier(stateName));
+ }
+
+ return decls;
+}
+
+QString CppDumper::generateSignalDecls(const GeneratedTableData::MetaDataInfo &info)
+{
+ QString decls;
+
+ for (const QString &stateName : info.stateNames) {
+ if (!stateName.isEmpty()) {
+ decls += QString::fromLatin1(" void %1(bool);\n")
+ .arg(mangleIdentifier(stateName + QStringLiteral("Changed")));
+ }
}
return decls;
@@ -721,16 +762,18 @@ QString CppDumper::generateMetaObject(const QString &className,
if (stateName.isEmpty())
continue;
- QByteArray mangledStateName = stateName.toUtf8();
+ QByteArray utf8StateName = stateName.toUtf8();
FunctionDef signal;
signal.type.name = "void";
signal.type.rawName = signal.type.name;
signal.normalizedType = signal.type.name;
- signal.name = mangledStateName + "Changed";
+ signal.name = utf8StateName + "Changed";
+ if (m_translationUnit->stateMethods)
+ signal.mangledName = mangleIdentifier(stateName + QStringLiteral("Changed")).toUtf8();
signal.access = FunctionDef::Public;
signal.isSignal = true;
- signal.implementation = "QMetaObject::activate(_o, &staticMetaObject, %d, _a);";
+ signal.implementation = "QMetaObject::activate(%s, &staticMetaObject, %d, _a);";
ArgumentDef arg;
arg.type.name = "bool";
@@ -744,9 +787,11 @@ QString CppDumper::generateMetaObject(const QString &className,
++classDef.notifyableProperties;
PropertyDef prop;
prop.name = stateName.toUtf8();
+ if (m_translationUnit->stateMethods)
+ prop.mangledName = mangleIdentifier(stateName).toUtf8();
prop.type = "bool";
prop.read = "isActive(" + QByteArray::number(stateIdx++) + ")";
- prop.notify = mangledStateName + "Changed";
+ prop.notify = utf8StateName + "Changed";
prop.notifyId = classDef.signalList.size() - 1;
prop.gspec = PropertyDef::ValueSpec;
prop.scriptable = "true";
@@ -759,8 +804,13 @@ QString CppDumper::generateMetaObject(const QString &className,
QBuffer buf;
buf.open(QIODevice::WriteOnly);
- Generator(&classDef, QList<QByteArray>(), knownQObjectClasses,
- QHash<QByteArray, QByteArray>(), buf).generateCode();
+ Generator generator(&classDef, QList<QByteArray>(), knownQObjectClasses,
+ QHash<QByteArray, QByteArray>(), buf);
+ generator.generateCode();
+ if (m_translationUnit->stateMethods) {
+ generator.generateAccessorDefs();
+ generator.generateSignalDefs();
+ }
buf.close();
return QString::fromUtf8(buf.buffer());
}
diff --git a/tools/qscxmlc/scxmlcppdumper.h b/tools/qscxmlc/scxmlcppdumper.h
index 95fa48a..9c8cfe8 100644
--- a/tools/qscxmlc/scxmlcppdumper.h
+++ b/tools/qscxmlc/scxmlcppdumper.h
@@ -41,12 +41,14 @@ QT_BEGIN_NAMESPACE
struct TranslationUnit
{
TranslationUnit()
- : mainDocument(Q_NULLPTR)
+ : stateMethods(false)
+ , mainDocument(Q_NULLPTR)
{}
QString scxmlFileName;
QString outHFileName, outCppFileName;
QString namespaceName;
+ bool stateMethods;
DocumentModel::ScxmlDocument *mainDocument;
QList<DocumentModel::ScxmlDocument *> allDocuments;
QHash<DocumentModel::ScxmlDocument *, QString> classnameForDocument;
@@ -79,6 +81,8 @@ private:
private:
QString generatePropertyDecls(const QScxmlInternal::GeneratedTableData::MetaDataInfo &info);
+ QString generateAccessorDecls(const QScxmlInternal::GeneratedTableData::MetaDataInfo &info);
+ QString generateSignalDecls(const QScxmlInternal::GeneratedTableData::MetaDataInfo &info);
QString generateMetaObject(const QString &className,
const QScxmlInternal::GeneratedTableData::MetaDataInfo &info);