1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-12-11 19:24:10 +01:00
LibrePilot/ground/uavobjgenerator/generators/gcs/uavobjectgeneratorgcs.cpp
Philippe Renon df350cda44 LP-183 generated UAV objects are now more Qt and Qml friendly
use lower camel case for properties and getters
introduce better enums and expose them to Qml
backward compatibilty is preserved for now
2015-11-29 16:53:33 +01:00

685 lines
27 KiB
C++

/**
******************************************************************************
*
* @file uavobjectgeneratorgcs.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief produce gcs code for uavobjects
*
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "uavobjectgeneratorgcs.h"
#define VERBOSE false
#define DEPRECATED true
#define DEFAULT_ENUM_PREFIX "E_"
using namespace std;
void error(QString msg)
{
cerr << "error: " << msg.toStdString() << endl;
}
void warning(ObjectInfo *object, QString msg)
{
cerr << "warning: " << object->filename.toStdString() << ": " << msg.toStdString() << endl;
}
void info(ObjectInfo *object, QString msg)
{
if (VERBOSE) {
cout << "info: " << object->filename.toStdString() << ": " << msg.toStdString() << endl;
}
}
struct Context {
ObjectInfo *object;
// enums
QString enums;
QString registerImpl;
// interface
QString fields;
QString fieldsInfo;
QString properties;
QString deprecatedProperties;
QString getters;
QString setters;
QString notifications;
// implementation
QString fieldsInit;
QString fieldsDefault;
QString propertiesImpl;
QString notificationsImpl;
};
struct FieldContext {
FieldInfo *field;
// field
QString fieldName;
QString fieldType;
// property
QString propName;
QString ucPropName;
QString propType;
QString propRefType;
// deprecation
bool hasDeprecatedProperty;
bool hasDeprecatedGetter;
bool hasDeprecatedSetter;
bool hasDeprecatedNotification;
};
QString fieldTypeStrCPP(int type)
{
QStringList fieldTypeStrCPP;
fieldTypeStrCPP << "qint8" << "qint16" << "qint32" << "quint8" << "quint16" << "quint32" << "float" << "quint8";
return fieldTypeStrCPP[type];
}
QString fieldTypeStrCPPClass(int type)
{
QStringList fieldTypeStrCPPClass;
fieldTypeStrCPPClass << "INT8" << "INT16" << "INT32" << "UINT8" << "UINT16" << "UINT32" << "FLOAT32" << "ENUM";
return fieldTypeStrCPPClass[type];
}
QString toPropertyName(const QString & name)
{
QString str = name;
// make sure 1st letter is upper case
str[0] = str[0].toUpper();
// handle underscore
int p = str.indexOf('_');
while (p != -1) {
str.remove(p, 1);
str[p] = str[p].toUpper();
p = str.indexOf('_', p);
}
return str;
}
/*
* Convert a string to lower camel case.
* Handles following cases :
* - Property -> property
* - MyProperty -> myProperty
* - MYProperty -> myProperty
* - MY_Property -> my_Property
* - MY -> my
*/
QString toLowerCamelCase(const QString & name)
{
QString str = name;
for (int i = 0; i < str.length(); ++i) {
if (str[i].isLower() || !str[i].isLetter()) {
break;
}
if (i > 0 && i < str.length() - 1) {
// after first, look ahead one
if (str[i + 1].isLower()) {
break;
}
}
str[i] = str[i].toLower();
}
return str;
}
QString toEnumName(ObjectInfo *object, FieldInfo *field, int index)
{
QString option = field->options[index];
if (option.contains(QRegExp(ENUM_SPECIAL_CHARS))) {
info(object, "Enumeration value \"" + option + "\" contains special chars, cleaning.");
option.replace(QRegExp(ENUM_SPECIAL_CHARS), "");
}
if (option[0].isDigit()) {
info(object, "Enumeration value \"" + option + "\" starts with a digit, prefixing with \"" + DEFAULT_ENUM_PREFIX "\".");
option = DEFAULT_ENUM_PREFIX + option;
}
if (option == option.toLower()) {
warning(object, "Enumeration value \"" + option + "\" is all lower case, consider capitalizing.");
}
if (option[0].isLower()) {
warning(object, "Enumeration value \"" + option + "\" does not start with an upper case letter.");
option[0] = option[0].toUpper();
}
if (option == "FALSE") {
warning(object, "Invalid enumeration name FALSE, converting to False.");
option = "False";
}
if (option == "TRUE") {
warning(object, "Invalid enumeration name TRUE, converting to True.");
option = "True";
}
return option;
}
QString toEnumStringList(ObjectInfo *object, FieldInfo *field)
{
QString enumListString;
for (int m = 0; m < field->options.length(); ++m) {
if (m > 0) {
enumListString.append(", ");
}
QString option = toEnumName(object, field, m);
enumListString.append(option);
}
return enumListString;
}
QString generate(Context &ctxt, const QString &fragment)
{
QString str = fragment;
str.replace(":ClassName", ctxt.object->name);
str.replace(":className", ctxt.object->namelc);
return str;
}
QString generate(Context &ctxt, FieldContext &fieldCtxt, const QString &fragment)
{
QString str = generate(ctxt, fragment);
str.replace(":PropName", fieldCtxt.ucPropName);
str.replace(":propName", fieldCtxt.propName);
str.replace(":propType", fieldCtxt.propType);
str.replace(":propRefType", fieldCtxt.propRefType);
str.replace(":fieldName", fieldCtxt.fieldName);
str.replace(":fieldType", fieldCtxt.fieldType);
str.replace(":fieldDesc", fieldCtxt.field->description);
str.replace(":fieldUnits", fieldCtxt.field->units);
str.replace(":fieldLimitValues", fieldCtxt.field->limitValues);
str.replace(":elementCount", QString::number(fieldCtxt.field->numElements));
return str;
}
void generateFieldInfo(Context &ctxt, FieldContext &fieldCtxt)
{
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, " // :fieldName\n");
if (fieldCtxt.field->type == FIELDTYPE_ENUM) {
QStringList options = fieldCtxt.field->options;
ctxt.fieldsInfo += " typedef enum { ";
for (int m = 0; m < options.length(); ++m) {
if (m > 0) {
ctxt.fieldsInfo.append(", ");
}
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, "%1_%2=%3")
.arg(fieldCtxt.field->name.toUpper())
.arg(options[m].toUpper().replace(QRegExp(ENUM_SPECIAL_CHARS), ""))
.arg(m);
}
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, " } :fieldNameOptions;\n");
}
// Generate element names (only if field has more than one element)
if (fieldCtxt.field->numElements > 1 && !fieldCtxt.field->defaultElementNames) {
QStringList elemNames = fieldCtxt.field->elementNames;
ctxt.fieldsInfo += " typedef enum { ";
for (int m = 0; m < elemNames.length(); ++m) {
if (m > 0) {
ctxt.fieldsInfo.append(", ");
}
ctxt.fieldsInfo += QString("%1_%2=%3")
.arg(fieldCtxt.field->name.toUpper())
.arg(elemNames[m].toUpper())
.arg(m);
}
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, " } :fieldNameElem;\n");
}
// Generate array information
if (fieldCtxt.field->numElements > 1) {
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, " static const quint32 %1_NUMELEM = :elementCount;\n")
.arg(fieldCtxt.field->name.toUpper());
}
}
void generateFieldInit(Context &ctxt, FieldContext &fieldCtxt)
{
ctxt.fieldsInit += generate(ctxt, fieldCtxt, " // :fieldName\n");
// Setup element names
ctxt.fieldsInit += generate(ctxt, fieldCtxt, " QStringList :fieldNameElemNames;\n");
QStringList elemNames = fieldCtxt.field->elementNames;
ctxt.fieldsInit += generate(ctxt, fieldCtxt, " :fieldNameElemNames");
for (int m = 0; m < elemNames.length(); ++m) {
ctxt.fieldsInit += QString(" << \"%1\"").arg(elemNames[m]);
}
ctxt.fieldsInit += ";\n";
if (fieldCtxt.field->type == FIELDTYPE_ENUM) {
ctxt.fieldsInit += generate(ctxt, fieldCtxt, " QStringList :fieldNameEnumOptions;\n");
QStringList options = fieldCtxt.field->options;
ctxt.fieldsInit += generate(ctxt, fieldCtxt, " :fieldNameEnumOptions");
for (int m = 0; m < options.length(); ++m) {
ctxt.fieldsInit += QString(" << \"%1\"").arg(options[m]);
}
ctxt.fieldsInit += ";\n";
ctxt.fieldsInit += generate(ctxt, fieldCtxt,
" fields.append(new UAVObjectField(\":fieldName\", tr(\":fieldDesc\"), \":fieldUnits\", UAVObjectField::ENUM, :fieldNameElemNames, :fieldNameEnumOptions, \":fieldLimitValues\"));\n");
} else {
ctxt.fieldsInit += generate(ctxt, fieldCtxt,
" fields.append(new UAVObjectField(\":fieldName\", tr(\":fieldDesc\"), \":fieldUnits\", UAVObjectField::%1, :fieldNameElemNames, QStringList(), \":fieldLimitValues\"));\n")
.arg(fieldTypeStrCPPClass(fieldCtxt.field->type));
}
}
void generateFieldDefault(Context &ctxt, FieldContext &fieldCtxt)
{
if (!fieldCtxt.field->defaultValues.isEmpty()) {
// For non-array fields
if (fieldCtxt.field->numElements == 1) {
ctxt.fieldsDefault += generate(ctxt, fieldCtxt, " // :fieldName\n");
if (fieldCtxt.field->type == FIELDTYPE_ENUM) {
ctxt.fieldsDefault += generate(ctxt, fieldCtxt, " data_.:fieldName = %1;\n")
.arg(fieldCtxt.field->options.indexOf(fieldCtxt.field->defaultValues[0]));
} else if (fieldCtxt.field->type == FIELDTYPE_FLOAT32) {
ctxt.fieldsDefault += generate(ctxt, fieldCtxt, " data_.:fieldName = %1;\n")
.arg(fieldCtxt.field->defaultValues[0].toFloat());
} else {
ctxt.fieldsDefault += generate(ctxt, fieldCtxt, " data_.:fieldName = %1;\n")
.arg(fieldCtxt.field->defaultValues[0].toInt());
}
} else {
// Initialize all fields in the array
ctxt.fieldsDefault += generate(ctxt, fieldCtxt, " // :fieldName\n");
for (int idx = 0; idx < fieldCtxt.field->numElements; ++idx) {
if (fieldCtxt.field->type == FIELDTYPE_ENUM) {
ctxt.fieldsDefault += generate(ctxt, fieldCtxt, " data_.:fieldName[%1] = %2;\n")
.arg(idx)
.arg(fieldCtxt.field->options.indexOf(fieldCtxt.field->defaultValues[idx]));
} else if (fieldCtxt.field->type == FIELDTYPE_FLOAT32) {
ctxt.fieldsDefault += generate(ctxt, fieldCtxt, " data_.:fieldName[%1] = %2;\n")
.arg(idx)
.arg(fieldCtxt.field->defaultValues[idx].toFloat());
} else {
ctxt.fieldsDefault += generate(ctxt, fieldCtxt, " data_.:fieldName[%1] = %2;\n")
.arg(idx)
.arg(fieldCtxt.field->defaultValues[idx].toInt());
}
}
}
}
}
void generateField(Context &ctxt, FieldContext &fieldCtxt)
{
if (fieldCtxt.field->numElements > 1) {
ctxt.fields += generate(ctxt, fieldCtxt, " :fieldType :fieldName[:elementCount];\n");
} else {
ctxt.fields += generate(ctxt, fieldCtxt, " :fieldType :fieldName;\n");
}
generateFieldInfo(ctxt, fieldCtxt);
generateFieldInit(ctxt, fieldCtxt);
generateFieldDefault(ctxt, fieldCtxt);
}
void generateEnum(Context &ctxt, FieldContext &fieldCtxt)
{
Q_ASSERT(fieldCtxt.field->type == FIELDTYPE_ENUM);
QString enumStringList = toEnumStringList(ctxt.object, fieldCtxt.field);
ctxt.enums += generate(ctxt, fieldCtxt,
"class :ClassName_:PropName : public QObject {\n"
" Q_OBJECT\n"
"public:\n"
" enum Enum { %1 };\n"
" Q_ENUMS(Enum) // TODO switch to Q_ENUM once on Qt 5.5\n"
"};\n\n").arg(enumStringList);
ctxt.registerImpl += generate(ctxt, fieldCtxt,
" qmlRegisterType<:ClassName_:PropName>(\"%1.:ClassName\", 1, 0, \":PropName\");\n").arg("UAVTalk");
}
void generateBaseProperty(Context &ctxt, FieldContext &fieldCtxt)
{
ctxt.properties += generate(ctxt, fieldCtxt,
" Q_PROPERTY(:propType :propName READ :propName WRITE set:PropName NOTIFY :propNameChanged)\n");
ctxt.getters += generate(ctxt, fieldCtxt, " :propType :propName() const;\n");
ctxt.setters += generate(ctxt, fieldCtxt, " void set:PropName(const :propRefType value);\n");
ctxt.notifications += generate(ctxt, fieldCtxt, " void :propNameChanged(const :propRefType value);\n");
ctxt.notificationsImpl += generate(ctxt, fieldCtxt, " emit :propNameChanged(:propName());\n");
if (DEPRECATED) {
// generate deprecated property for retro compatibility
if (fieldCtxt.hasDeprecatedProperty) {
ctxt.deprecatedProperties += generate(ctxt, fieldCtxt,
" /*DEPRECATED*/ Q_PROPERTY(:fieldType :fieldName READ get:fieldName WRITE set:fieldName NOTIFY :fieldNameChanged);\n");
}
if (fieldCtxt.hasDeprecatedGetter) {
ctxt.getters += generate(ctxt, fieldCtxt,
" /*DEPRECATED*/ Q_INVOKABLE :fieldType get:fieldName() const { return static_cast<:fieldType>(:propName()); }\n");
}
if (fieldCtxt.hasDeprecatedSetter) {
ctxt.setters += generate(ctxt, fieldCtxt,
" /*DEPRECATED*/ void set:fieldName(:fieldType value) { set:fieldName(static_cast<:propType>(value)); }\n");
}
if (fieldCtxt.hasDeprecatedNotification) {
ctxt.notifications += generate(ctxt, fieldCtxt,
" /*DEPRECATED*/ void :fieldNameChanged(:fieldType value);\n");
ctxt.notificationsImpl += generate(ctxt, fieldCtxt,
" /*DEPRECATED*/ emit :fieldNameChanged(get:fieldName());\n");
}
}
}
void generateSimpleProperty(Context &ctxt, FieldContext &fieldCtxt)
{
if (fieldCtxt.field->type == FIELDTYPE_ENUM) {
generateEnum(ctxt, fieldCtxt);
}
generateBaseProperty(ctxt, fieldCtxt);
// getter implementation
ctxt.propertiesImpl += generate(ctxt, fieldCtxt,
":propType :ClassName:::propName() const\n"
"{\n"
" QMutexLocker locker(mutex);\n"
" return static_cast<:propType>(data_.:fieldName);\n"
"}\n");
// emitters
QString emitters = generate(ctxt, fieldCtxt, "emit :propNameChanged(value);");
if (fieldCtxt.hasDeprecatedNotification) {
emitters += " ";
emitters += generate(ctxt, fieldCtxt, "emit :fieldNameChanged(static_cast<:fieldType>(value));");
}
// setter implementation
ctxt.propertiesImpl += generate(ctxt, fieldCtxt,
"void :ClassName::set:PropName(const :propRefType value)\n"
"{\n"
" mutex->lock();\n"
" bool changed = (data_.:fieldName != static_cast<:fieldType>(value));\n"
" data_.:fieldName = static_cast<:fieldType>(value);\n"
" mutex->unlock();\n"
" if (changed) { %1 }\n"
"}\n\n").arg(emitters);
}
void generateIndexedProperty(Context &ctxt, FieldContext &fieldCtxt)
{
if (fieldCtxt.field->type == FIELDTYPE_ENUM) {
generateEnum(ctxt, fieldCtxt);
}
// indexed getter/setter
ctxt.getters += generate(ctxt, fieldCtxt, " Q_INVOKABLE :propType :propName(quint32 index) const;\n");
ctxt.setters += generate(ctxt, fieldCtxt, " Q_INVOKABLE void set:PropName(quint32 index, const :propRefType value);\n");
// getter implementation
ctxt.propertiesImpl += generate(ctxt, fieldCtxt,
":propType :ClassName:::propName(quint32 index) const\n"
"{\n"
" QMutexLocker locker(mutex);\n"
" return static_cast<:propType>(data_.:fieldName[index]);\n"
"}\n");
// emitters
QString emitters = generate(ctxt, fieldCtxt, "emit :propNameChanged(index, value);");
if (fieldCtxt.hasDeprecatedNotification) {
emitters += " ";
emitters += generate(ctxt, fieldCtxt, "emit :fieldNameChanged(index, static_cast<:fieldType>(value));");
}
// setter implementation
ctxt.propertiesImpl += generate(ctxt, fieldCtxt,
"void :ClassName::set:PropName(quint32 index, const :propRefType value)\n"
"{\n"
" mutex->lock();\n"
" bool changed = (data_.:fieldName[index] != static_cast<:fieldType>(value));\n"
" data_.:fieldName[index] = static_cast<:fieldType>(value);\n"
" mutex->unlock();\n"
" if (changed) { %1 }\n"
"}\n\n").arg(emitters);
ctxt.notifications += generate(ctxt, fieldCtxt, " void :propNameChanged(quint32 index, const :propRefType value);\n");
if (DEPRECATED) {
// backward compatibility
if (fieldCtxt.hasDeprecatedGetter) {
ctxt.getters += generate(ctxt, fieldCtxt,
" /*DEPRECATED*/ Q_INVOKABLE :fieldType get:fieldName(quint32 index) const { return static_cast<:fieldType>(:propName(index)); }\n");
}
if (fieldCtxt.hasDeprecatedSetter) {
ctxt.setters += generate(ctxt, fieldCtxt,
" /*DEPRECATED*/ void set:fieldName(quint32 index, :fieldType value) { set:fieldName(index, static_cast<:propType>(value)); }\n");
}
if (fieldCtxt.hasDeprecatedNotification) {
ctxt.notifications += generate(ctxt, fieldCtxt,
" /*DEPRECATED*/ void :fieldNameChanged(quint32 index, :fieldType value);\n");
}
}
for (int elementIndex = 0; elementIndex < fieldCtxt.field->numElements; elementIndex++) {
QString elementName = fieldCtxt.field->elementNames[elementIndex];
FieldContext elementCtxt;
elementCtxt.field = fieldCtxt.field;
elementCtxt.fieldName = fieldCtxt.fieldName + "_" + elementName;
elementCtxt.fieldType = fieldCtxt.fieldType;
elementCtxt.propName = fieldCtxt.propName + elementName;
elementCtxt.ucPropName = fieldCtxt.ucPropName + elementName;
elementCtxt.propType = fieldCtxt.propType;
elementCtxt.propRefType = fieldCtxt.propRefType;
// deprecation
elementCtxt.hasDeprecatedProperty = (elementCtxt.fieldName != elementCtxt.propName) && DEPRECATED;
elementCtxt.hasDeprecatedGetter = DEPRECATED;
elementCtxt.hasDeprecatedSetter = ((elementCtxt.fieldName != elementCtxt.ucPropName) || (elementCtxt.fieldType != elementCtxt.propType)) && DEPRECATED;
elementCtxt.hasDeprecatedNotification = ((elementCtxt.fieldName != elementCtxt.propName) || (elementCtxt.fieldType != elementCtxt.propType)) && DEPRECATED;
generateBaseProperty(ctxt, elementCtxt);
ctxt.propertiesImpl += generate(ctxt, elementCtxt,
":propType :ClassName:::propName() const { return %1(%2); }\n").arg(fieldCtxt.propName).arg(elementIndex);
ctxt.propertiesImpl += generate(ctxt, elementCtxt,
"void :ClassName::set:PropName(const :propRefType value) { set%1(%2, value); }\n").arg(fieldCtxt.ucPropName).arg(elementIndex);
}
}
void generateProperty(Context &ctxt, FieldContext &fieldCtxt)
{
// do some checks
QString fieldName = fieldCtxt.fieldName;
if (fieldName[0].isLower()) {
info(ctxt.object, "Field \"" + fieldName + "\" does not start with an upper case letter.");
}
// generate all properties
if (fieldCtxt.field->numElements > 1) {
generateIndexedProperty(ctxt, fieldCtxt);
} else {
generateSimpleProperty(ctxt, fieldCtxt);
}
}
bool UAVObjectGeneratorGCS::generate(UAVObjectParser *parser, QString templatepath, QString outputpath)
{
gcsCodePath = QDir(templatepath + QString(GCS_CODE_DIR));
gcsOutputPath = QDir(outputpath);
gcsOutputPath.mkpath(gcsOutputPath.absolutePath());
gcsCodeTemplate = readFile(gcsCodePath.absoluteFilePath("uavobject.cpp.template"));
gcsIncludeTemplate = readFile(gcsCodePath.absoluteFilePath("uavobject.h.template"));
QString gcsInitTemplate = readFile(gcsCodePath.absoluteFilePath("uavobjectsinit.cpp.template"));
if (gcsCodeTemplate.isEmpty() || gcsIncludeTemplate.isEmpty() || gcsInitTemplate.isEmpty()) {
error("Error: Failed to read gcs code templates.");
return false;
}
QString objInc;
QString gcsObjInit;
for (int objidx = 0; objidx < parser->getNumObjects(); ++objidx) {
ObjectInfo *object = parser->getObjectByIndex(objidx);
process_object(object);
Context ctxt;
ctxt.object = object;
objInc.append(QString("#include \"%1.h\"\n").arg(object->namelc));
gcsObjInit += ::generate(ctxt, " objMngr->registerObject( new :ClassName() );\n");
gcsObjInit += ::generate(ctxt, " :ClassName::registerQMLTypes();\n");
}
// Write the gcs object initialization files
gcsInitTemplate.replace("$(OBJINC)", objInc);
gcsInitTemplate.replace("$(OBJINIT)", gcsObjInit);
bool res = writeFileIfDifferent(gcsOutputPath.absolutePath() + "/uavobjectsinit.cpp", gcsInitTemplate);
if (!res) {
error("Error: Could not write output files");
return false;
}
return true;
}
/**
* Generate the GCS object files
*
* TODO add getter to get enum names
*
* TODO handle "char" unit
* TODO handle "bool" unit
* TODO handle "hex" unit
* TODO handle Vector
*/
bool UAVObjectGeneratorGCS::process_object(ObjectInfo *object)
{
if (info == NULL) {
return false;
}
// Prepare output strings
QString outInclude = gcsIncludeTemplate;
QString outCode = gcsCodeTemplate;
// Replace common tags
replaceCommonTags(outInclude, object);
replaceCommonTags(outCode, object);
// to avoid name conflicts
QStringList reservedProperties;
reservedProperties << "Description" << "Metadata";
Context ctxt;
ctxt.object = object;
ctxt.registerImpl += ::generate(ctxt,
" qmlRegisterType<:ClassName>(\"%1.:ClassName\", 1, 0, \":ClassName\");\n").arg("UAVTalk");
for (int n = 0; n < object->fields.length(); ++n) {
FieldInfo *field = object->fields[n];
// field context
FieldContext fieldCtxt;
fieldCtxt.field = field;
// field properties
fieldCtxt.fieldName = field->name;
fieldCtxt.fieldType = fieldTypeStrCPP(field->type);
fieldCtxt.ucPropName = toPropertyName(field->name);
fieldCtxt.propName = toLowerCamelCase(fieldCtxt.ucPropName);
fieldCtxt.propType = fieldCtxt.fieldType;
fieldCtxt.propRefType = fieldCtxt.fieldType;
if (field->type == FIELDTYPE_ENUM) {
QString enumClassName = object->name + "_" + fieldCtxt.ucPropName;
fieldCtxt.propType = enumClassName + "::Enum";
fieldCtxt.propRefType = fieldCtxt.propType;
}
// deprecation
fieldCtxt.hasDeprecatedProperty = (fieldCtxt.fieldName != fieldCtxt.propName) && DEPRECATED;
fieldCtxt.hasDeprecatedGetter = DEPRECATED;
fieldCtxt.hasDeprecatedSetter = ((fieldCtxt.fieldName != fieldCtxt.ucPropName) || (fieldCtxt.fieldType != fieldCtxt.propType)) && DEPRECATED;
fieldCtxt.hasDeprecatedNotification = ((fieldCtxt.fieldName != fieldCtxt.propName) || (fieldCtxt.fieldType != fieldCtxt.propType)) && DEPRECATED;
generateField(ctxt, fieldCtxt);
if (reservedProperties.contains(field->name)) {
warning(object, "Ignoring reserved property " + field->name + ".");
continue;
}
generateProperty(ctxt, fieldCtxt);
}
outInclude.replace("$(ENUMS)", ctxt.enums);
outInclude.replace("$(DATAFIELDS)", ctxt.fields);
outInclude.replace("$(DATAFIELDINFO)", ctxt.fieldsInfo);
outInclude.replace("$(PROPERTIES)", ctxt.properties);
outInclude.replace("$(DEPRECATED_PROPERTIES)", ctxt.deprecatedProperties);
outInclude.replace("$(PROPERTY_GETTERS)", ctxt.getters);
outInclude.replace("$(PROPERTY_SETTERS)", ctxt.setters);
outInclude.replace("$(PROPERTY_NOTIFICATIONS)", ctxt.notifications);
outCode.replace("$(FIELDSINIT)", ctxt.fieldsInit);
outCode.replace("$(FIELDSDEFAULT)", ctxt.fieldsDefault);
outCode.replace("$(PROPERTIES_IMPL)", ctxt.propertiesImpl);
outCode.replace("$(NOTIFY_PROPERTIES_CHANGED)", ctxt.notificationsImpl);
outCode.replace("$(REGISTER_QML_TYPES)", ctxt.registerImpl);
// Write the GCS code
bool res = writeFileIfDifferent(gcsOutputPath.absolutePath() + "/" + object->namelc + ".cpp", outCode);
if (!res) {
error("Error: Could not write gcs output files");
return false;
}
res = writeFileIfDifferent(gcsOutputPath.absolutePath() + "/" + object->namelc + ".h", outInclude);
if (!res) {
error("Error: Could not write gcs output files");
return false;
}
return true;
}