Provide a way of exposing private QProperties with a fake API
The API reduces the amount of manual plumbing required to offer a conceptual property through the traditional setter/getter API as well as through QProperty<T> API. Since the latter would require inlining the type and thus making it impossible to add new properties without breaking binary compatibility, this patch introduces a fake API that behaves similar but does not contain the property by value. Change-Id: Ib9bccd867f0e4e36a520e5583ba348e728284253 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
b480acb372
commit
3d7265db90
@ -91,6 +91,34 @@ QT_BEGIN_NAMESPACE
|
||||
#define Q_INTERFACES(x) QT_ANNOTATE_CLASS(qt_interfaces, x)
|
||||
#define Q_PROPERTY(...) QT_ANNOTATE_CLASS(qt_property, __VA_ARGS__)
|
||||
#define Q_PRIVATE_PROPERTY(d, text) QT_ANNOTATE_CLASS2(qt_private_property, d, text)
|
||||
#define Q_PRIVATE_QPROPERTY(accessor, type, name, setter, ...) \
|
||||
struct _qt_property_api_##name { \
|
||||
type value() const; \
|
||||
type operator()() const { return value(); } \
|
||||
void setValue(type &&); \
|
||||
void setValue(const type &); \
|
||||
void operator=(const type &v) { setValue(v); } \
|
||||
void operator=(type &&v) { setValue(std::move(v)); } \
|
||||
QPropertyBinding<type> setBinding(const QPropertyBinding<type> &); \
|
||||
QPropertyBinding<type> setBinding(QPropertyBinding<type> &&); \
|
||||
QPropertyBinding<type> operator=(const QPropertyBinding<type> &b) { return setBinding(b); } \
|
||||
QPropertyBinding<type> operator=(QPropertyBinding<type> &&b) { return setBinding(std::move(b)); } \
|
||||
bool setBinding(const QUntypedPropertyBinding &); \
|
||||
template <typename Functor> \
|
||||
QPropertyBinding<type> setBinding(Functor f, \
|
||||
const QPropertyBindingSourceLocation &location = QT_PROPERTY_DEFAULT_BINDING_LOCATION) \
|
||||
{ \
|
||||
return setBinding(Qt::makePropertyBinding(f, location)); \
|
||||
} \
|
||||
bool hasBinding() const; \
|
||||
QPropertyBinding<type> binding() const; \
|
||||
QPropertyBinding<type> takeBinding(); \
|
||||
}; \
|
||||
void setter(const type &value);
|
||||
#define Q_PRIVATE_QPROPERTIES_BEGIN union {
|
||||
#define Q_PRIVATE_QPROPERTY_IMPL(name) \
|
||||
_qt_property_api_##name name;
|
||||
#define Q_PRIVATE_QPROPERTIES_END };
|
||||
#ifndef Q_REVISION
|
||||
# define Q_REVISION(...)
|
||||
#endif
|
||||
@ -211,6 +239,10 @@ private: \
|
||||
#define Q_INTERFACES(x) Q_INTERFACES(x)
|
||||
#define Q_PROPERTY(text) Q_PROPERTY(text)
|
||||
#define Q_PRIVATE_PROPERTY(d, text) Q_PRIVATE_PROPERTY(d, text)
|
||||
#define Q_PRIVATE_QPROPERTY(accessor, type, name, setter, ...) Q_PRIVATE_QPROPERTY(accessor, type, name, setter, __VA_ARGS__)
|
||||
#define Q_PRIVATE_QPROPERTIES_BEGIN
|
||||
#define Q_PRIVATE_QPROPERTY_IMPL(name)
|
||||
#define Q_PRIVATE_QPROPERTIES_END
|
||||
#define Q_REVISION(...) Q_REVISION(__VA_ARGS__)
|
||||
#define Q_OVERRIDE(text) Q_OVERRIDE(text)
|
||||
#define Q_ENUMS(x) Q_ENUMS(x)
|
||||
|
@ -615,6 +615,11 @@ void Generator::generateCode()
|
||||
for (int signalindex = 0; signalindex < cdef->signalList.size(); ++signalindex)
|
||||
generateSignal(&cdef->signalList[signalindex], signalindex);
|
||||
|
||||
//
|
||||
// Generate QProperty forwarding API
|
||||
//
|
||||
generateQPropertyApi();
|
||||
|
||||
//
|
||||
// Generate plugin meta data
|
||||
//
|
||||
@ -1621,6 +1626,106 @@ void Generator::generateSignal(FunctionDef *def,int index)
|
||||
fprintf(out, "}\n");
|
||||
}
|
||||
|
||||
void Generator::generateQPropertyApi()
|
||||
{
|
||||
for (const PrivateQPropertyDef &property: cdef->privateQProperties) {
|
||||
auto printAccessor = [this, property](bool constAccessor = false) {
|
||||
const char *constOrNot = constAccessor ? "const " : " ";
|
||||
fprintf(out, " const size_t propertyMemberOffset = reinterpret_cast<size_t>(&(static_cast<%s *>(nullptr)->%s));\n", cdef->qualified.constData(), property.name.constData());
|
||||
fprintf(out, " %sauto *thisPtr = reinterpret_cast<%s%s *>(reinterpret_cast<%schar *>(this) - propertyMemberOffset);\n", constOrNot, constOrNot, cdef->qualified.constData(), constOrNot);
|
||||
};
|
||||
|
||||
// property accessor
|
||||
fprintf(out, "\n%s %s::_qt_property_api_%s::value() const\n{\n",
|
||||
property.type.name.constData(),
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData());
|
||||
printAccessor(/*const*/true);
|
||||
fprintf(out, " return thisPtr->%s->%s.value();\n", property.accessor.constData(), property.name.constData());
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// property value setter
|
||||
fprintf(out, "\nvoid %s::_qt_property_api_%s::setValue(const %s &value)\n{\n",
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData(),
|
||||
property.type.name.constData());
|
||||
printAccessor();
|
||||
fprintf(out, " return thisPtr->%s->%s.setValue(value);\n", property.accessor.constData(), property.name.constData());
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// property value move setter
|
||||
fprintf(out, "\nvoid %s::_qt_property_api_%s::setValue(%s &&value)\n{\n",
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData(),
|
||||
property.type.name.constData());
|
||||
printAccessor();
|
||||
fprintf(out, " return thisPtr->%s->%s.setValue(std::move(value));\n", property.accessor.constData(), property.name.constData());
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// binding setter
|
||||
fprintf(out, "\nQPropertyBinding<%s> %s::_qt_property_api_%s::setBinding(const QPropertyBinding<%s> &binding)\n{\n",
|
||||
property.type.name.constData(),
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData(),
|
||||
property.type.name.constData());
|
||||
printAccessor();
|
||||
fprintf(out, " return thisPtr->%s->%s.setBinding(binding);\n", property.accessor.constData(), property.name.constData());
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// binding move setter
|
||||
fprintf(out, "\nQPropertyBinding<%s> %s::_qt_property_api_%s::setBinding(QPropertyBinding<%s> &&binding)\n{\n",
|
||||
property.type.name.constData(),
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData(),
|
||||
property.type.name.constData());
|
||||
printAccessor();
|
||||
fprintf(out, " return thisPtr->%s->%s.setBinding(std::move(binding));\n", property.accessor.constData(), property.name.constData());
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// untyped binding setter
|
||||
fprintf(out, "\nbool %s::_qt_property_api_%s::setBinding(const QUntypedPropertyBinding &binding)\n{\n",
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData());
|
||||
printAccessor();
|
||||
fprintf(out, " return thisPtr->%s->%s.setBinding(binding);\n", property.accessor.constData(), property.name.constData());
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// binding bool getter
|
||||
fprintf(out, "\nbool %s::_qt_property_api_%s::hasBinding() const\n{\n",
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData());
|
||||
printAccessor(/*const*/true);
|
||||
fprintf(out, " return thisPtr->%s->%s.hasBinding();\n", property.accessor.constData(), property.name.constData());
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// binding getter
|
||||
fprintf(out, "\nQPropertyBinding<%s> %s::_qt_property_api_%s::binding() const\n{\n",
|
||||
property.type.name.constData(),
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData());
|
||||
printAccessor(/*const*/true);
|
||||
fprintf(out, " return thisPtr->%s->%s.binding();\n", property.accessor.constData(), property.name.constData());
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// binding taker
|
||||
fprintf(out, "\nQPropertyBinding<%s> %s::_qt_property_api_%s::takeBinding()\n{\n",
|
||||
property.type.name.constData(),
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData());
|
||||
printAccessor();
|
||||
fprintf(out, " return thisPtr->%s->%s.takeBinding();\n", property.accessor.constData(), property.name.constData());
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// property setter function
|
||||
fprintf(out, "\nvoid %s::%s(const %s &value)\n{\n",
|
||||
cdef->qualified.constData(),
|
||||
property.setter.constData(),
|
||||
property.type.name.constData());
|
||||
fprintf(out, " %s->%s.setValue(value);\n", property.accessor.constData(), property.name.constData());
|
||||
fprintf(out, "}\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v);
|
||||
static CborError jsonObjectToCbor(CborEncoder *parent, const QJsonObject &o)
|
||||
{
|
||||
|
@ -58,6 +58,7 @@ private:
|
||||
void generateMetacall();
|
||||
void generateStaticMetacall();
|
||||
void generateSignal(FunctionDef *def, int index);
|
||||
void generateQPropertyApi();
|
||||
void generatePluginMetaData();
|
||||
QMultiMap<QByteArray, int> automaticPropertyMetaTypesHelper();
|
||||
QMap<int, QMultiMap<QByteArray, int> > methodsWithAutomaticTypesHelper(const QVector<FunctionDef> &methodList);
|
||||
|
@ -30,12 +30,12 @@
|
||||
// DO NOT EDIT.
|
||||
|
||||
static const short keyword_trans[][128] = {
|
||||
{0,0,0,0,0,0,0,0,0,579,576,0,0,0,0,0,
|
||||
{0,0,0,0,0,0,0,0,0,588,585,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
579,252,577,580,8,38,239,578,25,26,236,234,30,235,27,237,
|
||||
588,252,586,589,8,38,239,587,25,26,236,234,30,235,27,237,
|
||||
22,22,22,22,22,22,22,22,22,22,34,41,23,39,24,43,
|
||||
0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
|
||||
8,21,8,8,8,8,8,8,8,8,8,31,582,32,238,8,
|
||||
8,21,8,8,8,8,8,8,8,8,8,31,591,32,238,8,
|
||||
0,1,2,3,4,5,6,7,8,9,8,8,10,11,12,13,
|
||||
14,8,15,16,17,18,19,20,8,8,8,36,245,37,248,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
@ -177,7 +177,7 @@ static const short keyword_trans[][128] = {
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,42,0,0,0,28,0,
|
||||
585,585,585,585,585,585,585,585,585,585,0,0,0,0,0,0,
|
||||
594,594,594,594,594,594,594,594,594,594,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
@ -336,7 +336,7 @@ static const short keyword_trans[][128] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,584,0,0,0,0,583,
|
||||
0,0,0,0,0,0,0,0,0,0,593,0,0,0,0,592,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,258,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
@ -378,8 +378,8 @@ static const short keyword_trans[][128] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,475,424,408,416,380,0,484,0,0,0,565,364,358,
|
||||
386,0,557,472,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,475,424,408,416,380,0,484,0,0,0,574,364,358,
|
||||
386,0,566,472,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
@ -443,7 +443,7 @@ static const short keyword_trans[][128] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
549,0,0,517,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
549,557,0,517,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
|
||||
};
|
||||
@ -1013,30 +1013,39 @@ static const struct
|
||||
{CHARACTER, 0, 84, 555, CHARACTER},
|
||||
{CHARACTER, 0, 89, 556, CHARACTER},
|
||||
{Q_PRIVATE_PROPERTY_TOKEN, 0, 0, 0, CHARACTER},
|
||||
{CHARACTER, 0, 69, 558, CHARACTER},
|
||||
{CHARACTER, 0, 86, 559, CHARACTER},
|
||||
{CHARACTER, 0, 73, 560, CHARACTER},
|
||||
{CHARACTER, 0, 83, 561, CHARACTER},
|
||||
{CHARACTER, 0, 73, 562, CHARACTER},
|
||||
{CHARACTER, 0, 79, 563, CHARACTER},
|
||||
{CHARACTER, 0, 78, 564, CHARACTER},
|
||||
{Q_REVISION_TOKEN, 0, 0, 0, CHARACTER},
|
||||
{CHARACTER, 0, 79, 566, CHARACTER},
|
||||
{CHARACTER, 0, 67, 567, CHARACTER},
|
||||
{CHARACTER, 0, 95, 568, CHARACTER},
|
||||
{CHARACTER, 0, 80, 558, CHARACTER},
|
||||
{CHARACTER, 0, 82, 559, CHARACTER},
|
||||
{CHARACTER, 0, 79, 560, CHARACTER},
|
||||
{CHARACTER, 0, 80, 561, CHARACTER},
|
||||
{CHARACTER, 0, 69, 562, CHARACTER},
|
||||
{CHARACTER, 0, 82, 563, CHARACTER},
|
||||
{CHARACTER, 0, 84, 564, CHARACTER},
|
||||
{CHARACTER, 0, 89, 565, CHARACTER},
|
||||
{Q_PRIVATE_QPROPERTY_TOKEN, 0, 0, 0, CHARACTER},
|
||||
{CHARACTER, 0, 69, 567, CHARACTER},
|
||||
{CHARACTER, 0, 86, 568, CHARACTER},
|
||||
{CHARACTER, 0, 73, 569, CHARACTER},
|
||||
{CHARACTER, 0, 78, 570, CHARACTER},
|
||||
{CHARACTER, 0, 67, 571, CHARACTER},
|
||||
{CHARACTER, 0, 76, 572, CHARACTER},
|
||||
{CHARACTER, 0, 85, 573, CHARACTER},
|
||||
{CHARACTER, 0, 68, 574, CHARACTER},
|
||||
{CHARACTER, 0, 69, 575, CHARACTER},
|
||||
{CHARACTER, 0, 83, 570, CHARACTER},
|
||||
{CHARACTER, 0, 73, 571, CHARACTER},
|
||||
{CHARACTER, 0, 79, 572, CHARACTER},
|
||||
{CHARACTER, 0, 78, 573, CHARACTER},
|
||||
{Q_REVISION_TOKEN, 0, 0, 0, CHARACTER},
|
||||
{CHARACTER, 0, 79, 575, CHARACTER},
|
||||
{CHARACTER, 0, 67, 576, CHARACTER},
|
||||
{CHARACTER, 0, 95, 577, CHARACTER},
|
||||
{CHARACTER, 0, 73, 578, CHARACTER},
|
||||
{CHARACTER, 0, 78, 579, CHARACTER},
|
||||
{CHARACTER, 0, 67, 580, CHARACTER},
|
||||
{CHARACTER, 0, 76, 581, CHARACTER},
|
||||
{CHARACTER, 0, 85, 582, CHARACTER},
|
||||
{CHARACTER, 0, 68, 583, CHARACTER},
|
||||
{CHARACTER, 0, 69, 584, CHARACTER},
|
||||
{Q_MOC_INCLUDE_TOKEN, 0, 0, 0, CHARACTER},
|
||||
{NEWLINE, 0, 0, 0, NOTOKEN},
|
||||
{QUOTE, 0, 0, 0, NOTOKEN},
|
||||
{SINGLEQUOTE, 0, 0, 0, NOTOKEN},
|
||||
{WHITESPACE, 0, 0, 0, NOTOKEN},
|
||||
{HASH, 0, 35, 581, HASH},
|
||||
{HASH, 0, 35, 590, HASH},
|
||||
{PP_HASHHASH, 0, 0, 0, NOTOKEN},
|
||||
{BACKSLASH, 0, 0, 0, NOTOKEN},
|
||||
{CPP_COMMENT, 0, 0, 0, NOTOKEN},
|
||||
|
@ -878,6 +878,9 @@ void Moc::parse()
|
||||
case Q_PRIVATE_PROPERTY_TOKEN:
|
||||
parsePrivateProperty(&def);
|
||||
break;
|
||||
case Q_PRIVATE_QPROPERTY_TOKEN:
|
||||
parsePrivateQProperty(&def);
|
||||
break;
|
||||
case ENUM: {
|
||||
EnumDef enumDef;
|
||||
if (parseEnum(&enumDef))
|
||||
@ -1031,10 +1034,14 @@ static QByteArrayList requiredQtContainers(const QVector<ClassDef> &classes)
|
||||
QByteArrayList required;
|
||||
required.reserve(candidates.size());
|
||||
|
||||
bool needsQProperty = false;
|
||||
|
||||
for (const auto &candidate : candidates) {
|
||||
const QByteArray pattern = candidate + '<';
|
||||
|
||||
for (const auto &c : classes) {
|
||||
if (!c.privateQProperties.isEmpty())
|
||||
needsQProperty = true;
|
||||
if (any_type_contains(c.propertyList, pattern) ||
|
||||
any_arg_contains(c.slotList, pattern) ||
|
||||
any_arg_contains(c.signalList, pattern) ||
|
||||
@ -1045,6 +1052,9 @@ static QByteArrayList requiredQtContainers(const QVector<ClassDef> &classes)
|
||||
}
|
||||
}
|
||||
|
||||
if (needsQProperty)
|
||||
required.push_back("QProperty");
|
||||
|
||||
return required;
|
||||
}
|
||||
|
||||
@ -1268,6 +1278,14 @@ void Moc::createPropertyDef(PropertyDef &propDef)
|
||||
|
||||
propDef.type = type;
|
||||
|
||||
next();
|
||||
propDef.name = lexem();
|
||||
|
||||
parsePropertyAttributes(propDef);
|
||||
}
|
||||
|
||||
void Moc::parsePropertyAttributes(PropertyDef &propDef)
|
||||
{
|
||||
auto checkIsFunction = [&](const QByteArray &def, const char *name) {
|
||||
if (def.endsWith(')')) {
|
||||
QByteArray msg = "Providing a function for ";
|
||||
@ -1277,9 +1295,6 @@ void Moc::createPropertyDef(PropertyDef &propDef)
|
||||
}
|
||||
};
|
||||
|
||||
next();
|
||||
propDef.name = lexem();
|
||||
|
||||
while (test(IDENTIFIER)) {
|
||||
const QByteArray l = lexem();
|
||||
if (l[0] == 'C' && l == "CONSTANT") {
|
||||
@ -1459,23 +1474,30 @@ void Moc::parsePluginData(ClassDef *def)
|
||||
next(RPAREN);
|
||||
}
|
||||
|
||||
void Moc::parsePrivateProperty(ClassDef *def)
|
||||
QByteArray Moc::parsePropertyAccessor()
|
||||
{
|
||||
next(LPAREN);
|
||||
PropertyDef propDef;
|
||||
next(IDENTIFIER);
|
||||
propDef.inPrivateClass = lexem();
|
||||
QByteArray accessor = lexem();
|
||||
while (test(SCOPE)) {
|
||||
propDef.inPrivateClass += lexem();
|
||||
accessor += lexem();
|
||||
next(IDENTIFIER);
|
||||
propDef.inPrivateClass += lexem();
|
||||
accessor += lexem();
|
||||
}
|
||||
// also allow void functions
|
||||
if (test(LPAREN)) {
|
||||
next(RPAREN);
|
||||
propDef.inPrivateClass += "()";
|
||||
accessor += "()";
|
||||
}
|
||||
|
||||
return accessor;
|
||||
}
|
||||
|
||||
void Moc::parsePrivateProperty(ClassDef *def)
|
||||
{
|
||||
next(LPAREN);
|
||||
PropertyDef propDef;
|
||||
propDef.inPrivateClass = parsePropertyAccessor();
|
||||
|
||||
next(COMMA);
|
||||
|
||||
createPropertyDef(propDef);
|
||||
@ -1488,6 +1510,42 @@ void Moc::parsePrivateProperty(ClassDef *def)
|
||||
def->propertyList += propDef;
|
||||
}
|
||||
|
||||
void Moc::parsePrivateQProperty(ClassDef *def)
|
||||
{
|
||||
next(LPAREN);
|
||||
const QByteArray accessor = parsePropertyAccessor();
|
||||
next(COMMA);
|
||||
const Type type = parseType();
|
||||
next(COMMA);
|
||||
next(IDENTIFIER);
|
||||
const QByteArray name = lexem();
|
||||
next(COMMA);
|
||||
next(IDENTIFIER);
|
||||
const QByteArray setter = lexem();
|
||||
|
||||
def->privateQProperties += PrivateQPropertyDef{type, name, setter, accessor};
|
||||
|
||||
PropertyDef propDef;
|
||||
propDef.name = name;
|
||||
propDef.type = type.name;
|
||||
propDef.read = name + ".value";
|
||||
propDef.write = name + ".setValue";
|
||||
propDef.isQProperty = true;
|
||||
propDef.inPrivateClass = accessor;
|
||||
propDef.designable = propDef.scriptable = propDef.stored = "true";
|
||||
propDef.user = "false";
|
||||
|
||||
if (test(COMMA))
|
||||
parsePropertyAttributes(propDef);
|
||||
|
||||
next(RPAREN);
|
||||
|
||||
if (!propDef.notify.isEmpty())
|
||||
def->notifyableProperties++;
|
||||
|
||||
def->propertyList += propDef;
|
||||
}
|
||||
|
||||
void Moc::parseEnumOrFlag(BaseDef *def, bool isFlag)
|
||||
{
|
||||
next(LPAREN);
|
||||
|
@ -148,6 +148,14 @@ struct PropertyDef
|
||||
};
|
||||
Q_DECLARE_TYPEINFO(PropertyDef, Q_MOVABLE_TYPE);
|
||||
|
||||
struct PrivateQPropertyDef
|
||||
{
|
||||
Type type;
|
||||
QByteArray name;
|
||||
QByteArray setter;
|
||||
QByteArray accessor;
|
||||
};
|
||||
Q_DECLARE_TYPEINFO(PrivateQPropertyDef, Q_MOVABLE_TYPE);
|
||||
|
||||
struct ClassInfoDef
|
||||
{
|
||||
@ -191,6 +199,7 @@ struct ClassDef : BaseDef {
|
||||
QVector<FunctionDef> signalList, slotList, methodList, publicList;
|
||||
QVector<QByteArray> nonClassSignalList;
|
||||
QVector<PropertyDef> propertyList;
|
||||
QVector<PrivateQPropertyDef> privateQProperties;
|
||||
QSet<QByteArray> qPropertyMembers;
|
||||
int notifyableProperties = 0;
|
||||
int revisionedMethods = 0;
|
||||
@ -258,6 +267,7 @@ public:
|
||||
void parseProperty(ClassDef *def);
|
||||
void parsePluginData(ClassDef *def);
|
||||
void createPropertyDef(PropertyDef &def);
|
||||
void parsePropertyAttributes(PropertyDef &propDef);
|
||||
void parseEnumOrFlag(BaseDef *def, bool isFlag);
|
||||
void parseFlag(BaseDef *def);
|
||||
void parseClassInfo(BaseDef *def);
|
||||
@ -266,7 +276,9 @@ public:
|
||||
void parseDeclareMetatype();
|
||||
void parseMocInclude();
|
||||
void parseSlotInPrivate(ClassDef *def, FunctionDef::Access access);
|
||||
QByteArray parsePropertyAccessor();
|
||||
void parsePrivateProperty(ClassDef *def);
|
||||
void parsePrivateQProperty(ClassDef *def);
|
||||
|
||||
void parseFunctionArguments(FunctionDef *def);
|
||||
|
||||
|
@ -178,6 +178,7 @@ QT_BEGIN_NAMESPACE
|
||||
F(Q_INVOKABLE_TOKEN) \
|
||||
F(Q_SCRIPTABLE_TOKEN) \
|
||||
F(Q_PRIVATE_PROPERTY_TOKEN) \
|
||||
F(Q_PRIVATE_QPROPERTY_TOKEN) \
|
||||
F(Q_REVISION_TOKEN) \
|
||||
F(Q_MOC_INCLUDE_TOKEN) \
|
||||
F(SPECIAL_TREATMENT_MARK) \
|
||||
|
@ -242,6 +242,7 @@ static const Keyword keywords[] = {
|
||||
{ "Q_SLOT", "Q_SLOT_TOKEN" },
|
||||
{ "Q_SCRIPTABLE", "Q_SCRIPTABLE_TOKEN" },
|
||||
{ "Q_PRIVATE_PROPERTY", "Q_PRIVATE_PROPERTY_TOKEN" },
|
||||
{ "Q_PRIVATE_QPROPERTY", "Q_PRIVATE_QPROPERTY_TOKEN" },
|
||||
{ "Q_REVISION", "Q_REVISION_TOKEN" },
|
||||
{ "Q_MOC_INCLUDE", "Q_MOC_INCLUDE_TOKEN" },
|
||||
{ "\n", "NEWLINE" },
|
||||
|
@ -727,6 +727,7 @@ private slots:
|
||||
void qpropertyMembers();
|
||||
void observerMetaCall();
|
||||
void setQPRopertyBinding();
|
||||
void privateQPropertyShim();
|
||||
|
||||
signals:
|
||||
void sigWithUnsignedArg(unsigned foo);
|
||||
@ -4212,6 +4213,65 @@ void tst_Moc::setQPRopertyBinding()
|
||||
QVERIFY(bindingCalled); // but now it should've been called :)
|
||||
}
|
||||
|
||||
|
||||
class ClassWithPrivateQPropertyShim :public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_PRIVATE_QPROPERTY(d_func(), int, testProperty, setTestProperty, NOTIFY testPropertyChanged)
|
||||
|
||||
Q_PRIVATE_QPROPERTIES_BEGIN
|
||||
Q_PRIVATE_QPROPERTY_IMPL(testProperty)
|
||||
Q_PRIVATE_QPROPERTIES_END
|
||||
|
||||
signals:
|
||||
void testPropertyChanged();
|
||||
public:
|
||||
|
||||
struct Private {
|
||||
Private(ClassWithPrivateQPropertyShim *pub)
|
||||
: q(pub)
|
||||
{}
|
||||
|
||||
ClassWithPrivateQPropertyShim *q = nullptr;
|
||||
|
||||
QProperty<int> testProperty;
|
||||
void onTestPropertyChanged() { q->testPropertyChanged(); }
|
||||
QPropertyMemberChangeHandler<&Private::testProperty, &Private::onTestPropertyChanged> testChangeHandler{this};
|
||||
};
|
||||
Private priv{this};
|
||||
|
||||
Private *d_func() { return &priv; }
|
||||
const Private *d_func() const { return &priv; }
|
||||
};
|
||||
|
||||
|
||||
void tst_Moc::privateQPropertyShim()
|
||||
{
|
||||
ClassWithPrivateQPropertyShim testObject;
|
||||
|
||||
{
|
||||
auto metaObject = &ClassWithPrivateQPropertyShim::staticMetaObject;
|
||||
QMetaProperty prop = metaObject->property(metaObject->indexOfProperty("testProperty"));
|
||||
QVERIFY(prop.isValid());
|
||||
QVERIFY(prop.notifySignal().isValid());
|
||||
}
|
||||
|
||||
testObject.priv.testProperty.setValue(42);
|
||||
QCOMPARE(testObject.property("testProperty").toInt(), 42);
|
||||
|
||||
// Behave like a QProperty
|
||||
QVERIFY(!testObject.testProperty.hasBinding());
|
||||
testObject.testProperty.setBinding([]() { return 100; });
|
||||
QCOMPARE(testObject.testProperty.value(), 100);
|
||||
QVERIFY(testObject.testProperty.hasBinding());
|
||||
|
||||
// Old style setter getters
|
||||
testObject.setTestProperty(400);
|
||||
QVERIFY(!testObject.testProperty.hasBinding());
|
||||
QCOMPARE(testObject.testProperty(), 400);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_Moc)
|
||||
|
||||
// the generated code must compile with QT_NO_KEYWORDS
|
||||
|
Loading…
Reference in New Issue
Block a user