bool UiExtractor::checkProperty(QObject *obj, const QString &prop) const { const QMetaObject *mo = obj->metaObject(); const QMetaProperty mp = mo->property(mo->indexOfProperty(prop.toLatin1())); // TODO come up with some more aggressive filtering if (mp.isValid() && mp.isDesignable(obj) && mp.isStored(obj) && mp.isWritable()) { const QVariant value = mp.read(obj); // try to figure out the default by resetting to it if (mp.isResettable()) { mp.reset(obj); if (mp.read(obj) == value) { return false; } mp.write(obj, value); return true; } // some guessing for non-resettable properties if (value.isNull() || !value.isValid()) { return false; } if (value.type() == QVariant::String) { return !value.toString().isEmpty(); } else if (value.type() == QVariant::Locale) { return value.value<QLocale>() != QLocale::system(); } return true; } return false; }
QT_BEGIN_NAMESPACE QDeclarativePropertyCache::Data::Flags QDeclarativePropertyCache::Data::flagsForProperty(const QMetaProperty &p, QDeclarativeEngine *engine) { int propType = p.userType(); Flags flags; if (p.isConstant()) flags |= Data::IsConstant; if (p.isWritable()) flags |= Data::IsWritable; if (p.isResettable()) flags |= Data::IsResettable; if (propType == qMetaTypeId<QDeclarativeBinding *>()) { flags |= Data::IsQmlBinding; } else if (propType == qMetaTypeId<QScriptValue>()) { flags |= Data::IsQScriptValue; } else if (p.isEnumType()) { flags |= Data::IsEnumType; } else { QDeclarativeMetaType::TypeCategory cat = engine ? QDeclarativeEnginePrivate::get(engine)->typeCategory(propType) : QDeclarativeMetaType::typeCategory(propType); if (cat == QDeclarativeMetaType::Object) flags |= Data::IsQObjectDerived; else if (cat == QDeclarativeMetaType::List) flags |= Data::IsQList; } return flags; }
void AbstractParam::resetValue() { const QMetaObject *mo = metaObject(); int i = mo->indexOfProperty("value"); if (i >= 0) { QMetaProperty mp = mo->property(i); if (mp.isResettable()) { mp.reset(this); } } }
QVariant ObjectStaticPropertyModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || !m_obj || index.row() < 0 || index.row() >= m_obj.data()->metaObject()->propertyCount()) { return QVariant(); } const QMetaProperty prop = m_obj.data()->metaObject()->property(index.row()); if (role == Qt::DisplayRole) { if (index.column() == 0) { return prop.name(); } else if (index.column() == 1) { // QMetaProperty::read sets QVariant::typeName to int for enums, // so we need to handle that separately here const QVariant value = prop.read(m_obj.data()); const QString enumStr = Util::enumToString(value, prop.typeName(), m_obj.data()); if (!enumStr.isEmpty()) { return enumStr; } return VariantHandler::displayString(value); } else if (index.column() == 2) { return prop.typeName(); } else if (index.column() == 3) { const QMetaObject *mo = m_obj.data()->metaObject(); while (mo->propertyOffset() > index.row()) { mo = mo->superClass(); } return mo->className(); } } else if (role == Qt::DecorationRole) { if (index.column() == 1) { return VariantHandler::decoration(prop.read(m_obj.data())); } } else if (role == Qt::EditRole) { if (index.column() == 1) { return prop.read(m_obj.data()); } } else if (role == Qt::ToolTipRole) { const QString toolTip = tr("Constant: %1\nDesignable: %2\nFinal: %3\nResetable: %4\n" "Has notification: %5\nScriptable: %6\nStored: %7\nUser: %8\nWritable: %9"). arg(translateBool(prop.isConstant())). arg(translateBool(prop.isDesignable(m_obj.data()))). arg(translateBool(prop.isFinal())). arg(translateBool(prop.isResettable())). arg(translateBool(prop.hasNotifySignal())). arg(translateBool(prop.isScriptable(m_obj.data()))). arg(translateBool(prop.isStored(m_obj.data()))). arg(translateBool(prop.isUser(m_obj.data()))). arg(translateBool(prop.isWritable())); return toolTip; } return QVariant(); }
void MetaInfoPrivate::parseProperties(NodeMetaInfo &nodeMetaInfo, const QMetaObject *qMetaObject) const { Q_ASSERT_X(qMetaObject, Q_FUNC_INFO, "invalid QMetaObject"); Q_ASSERT_X(nodeMetaInfo.isValid(), Q_FUNC_INFO, "invalid NodeMetaInfo"); for (int i = qMetaObject->propertyOffset(); i < qMetaObject->propertyCount(); ++i) { QMetaProperty qProperty = qMetaObject->property(i); PropertyMetaInfo propertyInfo; propertyInfo.setName(QLatin1String(qProperty.name())); QString typeName(qProperty.typeName()); QString noStar = typeName; bool star = false; while (noStar.contains('*')) {//strip star noStar.chop(1); star = true; } if (m_QtTypesToQmlTypes.contains(noStar)) { typeName = star ? m_QtTypesToQmlTypes.value(noStar) + '*' : m_QtTypesToQmlTypes.value(noStar); //### versions } propertyInfo.setType(typeName); propertyInfo.setValid(true); propertyInfo.setReadable(qProperty.isReadable()); propertyInfo.setWritable(qProperty.isWritable()); propertyInfo.setResettable(qProperty.isResettable()); propertyInfo.setEnumType(qProperty.isEnumType()); propertyInfo.setFlagType(qProperty.isFlagType()); if (propertyInfo.isEnumType()) { EnumeratorMetaInfo enumerator; QMetaEnum qEnumerator = qProperty.enumerator(); enumerator.setValid(qEnumerator.isValid()); enumerator.setIsFlagType(qEnumerator.isFlag()); enumerator.setScope(qEnumerator.scope()); enumerator.setName(qEnumerator.name()); for (int i = 0 ;i < qEnumerator.keyCount(); i++) { enumerator.addElement(qEnumerator.valueToKey(i), i); } propertyInfo.setEnumerator(enumerator); } nodeMetaInfo.addProperty(propertyInfo); } }
QVariant ObjectStaticPropertyModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || !m_obj || index.row() < 0 || index.row() >= m_obj.data()->metaObject()->propertyCount()) { return QVariant(); } const QMetaProperty prop = m_obj.data()->metaObject()->property(index.row()); if (role == Qt::DisplayRole) { if (index.column() == 0) { return prop.name(); } else if (index.column() == 1) { return Util::variantToString(prop.read(m_obj.data())); } else if (index.column() == 2) { return prop.typeName(); } else if (index.column() == 3) { const QMetaObject *mo = m_obj.data()->metaObject(); while (mo->propertyOffset() > index.row()) { mo = mo->superClass(); } return mo->className(); } } else if (role == Qt::EditRole) { if (index.column() == 1) { return prop.read(m_obj.data()); } } else if (role == Qt::ToolTipRole) { const QString toolTip = tr("Constant: %1\nDesignable: %2\nFinal: %3\nResetable: %4\n" "Has notification: %5\nScriptable: %6\nStored: %7\nUser: %8\nWritable: %9"). arg(translateBool(prop.isConstant())). arg(translateBool(prop.isDesignable(m_obj.data()))). arg(translateBool(prop.isFinal())). arg(translateBool(prop.isResettable())). arg(translateBool(prop.hasNotifySignal())). arg(translateBool(prop.isScriptable(m_obj.data()))). arg(translateBool(prop.isStored(m_obj.data()))). arg(translateBool(prop.isUser(m_obj.data()))). arg(translateBool(prop.isWritable())); return toolTip; } return QVariant(); }
QT_BEGIN_NAMESPACE // Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick // to load static QDeclarativePropertyCache::Data::Flags fastFlagsForProperty(const QMetaProperty &p) { QDeclarativePropertyCache::Data::Flags flags; if (p.isConstant()) flags |= QDeclarativePropertyCache::Data::IsConstant; if (p.isWritable()) flags |= QDeclarativePropertyCache::Data::IsWritable; if (p.isResettable()) flags |= QDeclarativePropertyCache::Data::IsResettable; if (p.isFinal()) flags |= QDeclarativePropertyCache::Data::IsFinal; if (p.isEnumType()) flags |= QDeclarativePropertyCache::Data::IsEnumType; return flags; }
QString ObjectStaticPropertyModel::detailString(const QMetaProperty& prop) const { QStringList s; s << tr("Constant: %1").arg(translateBool(prop.isConstant())); s << tr("Designable: %1").arg(translateBool(prop.isDesignable(m_obj.data()))); s << tr("Final: %1").arg(translateBool(prop.isFinal())); if (prop.hasNotifySignal()) { s << tr("Notification: %1").arg(Util::prettyMethodSignature(prop.notifySignal())); } else { s << tr("Notification: no"); } s << tr("Resetable: %1").arg(translateBool(prop.isResettable())); #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) s << tr("Revision: %1").arg(prop.revision()); #endif s << tr("Scriptable: %1").arg(translateBool(prop.isScriptable(m_obj.data()))); s << tr("Stored: %1").arg(translateBool(prop.isStored(m_obj.data()))); s << tr("User: %1").arg(translateBool(prop.isUser(m_obj.data()))); s << tr("Writable: %1").arg(translateBool(prop.isWritable())); return s.join("\n"); }
QString QMetaPropertyAdaptor::detailString(const QMetaProperty &prop) const { QObject *obj = object().qtObject(); QStringList s; s << tr("Constant: %1").arg(translateBool(prop.isConstant())); s << tr("Designable: %1").arg(translateBool(prop.isDesignable(obj))); s << tr("Final: %1").arg(translateBool(prop.isFinal())); if (prop.hasNotifySignal()) s << tr("Notification: %1").arg(Util::prettyMethodSignature(prop.notifySignal())); else s << tr("Notification: no"); s << tr("Resetable: %1").arg(translateBool(prop.isResettable())); #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0) s << tr("Revision: %1").arg(prop.revision()); #endif s << tr("Scriptable: %1").arg(translateBool(prop.isScriptable(obj))); s << tr("Stored: %1").arg(translateBool(prop.isStored(obj))); s << tr("User: %1").arg(translateBool(prop.isUser(obj))); s << tr("Writable: %1").arg(translateBool(prop.isWritable())); return s.join(QStringLiteral("\n")); }
QVariant ObjectStaticPropertyModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || !m_obj || index.row() < 0 || index.row() >= m_obj.data()->metaObject()->propertyCount()) { return QVariant(); } const QMetaProperty prop = m_obj.data()->metaObject()->property(index.row()); const QVariant value = prop.read(m_obj.data()); if (role == Qt::DisplayRole) { if (index.column() == 0) { return prop.name(); } else if (index.column() == 1) { // QMetaProperty::read sets QVariant::typeName to int for enums, // so we need to handle that separately here const QString enumStr = Util::enumToString(value, prop.typeName(), m_obj.data()); if (!enumStr.isEmpty()) { return enumStr; } return VariantHandler::displayString(value); } else if (index.column() == 2) { return prop.typeName(); } else if (index.column() == 3) { const QMetaObject *mo = m_obj.data()->metaObject(); while (mo->propertyOffset() > index.row()) { mo = mo->superClass(); } return mo->className(); } } else if (role == Qt::DecorationRole) { if (index.column() == 1) { return VariantHandler::decoration(value); } } else if (role == Qt::EditRole) { if (index.column() == 1 && prop.isWritable()) { return value; } } else if (role == Qt::ToolTipRole) { return detailString(prop); } else if (role == PropertyModel::ActionRole) { return (prop.isResettable() ? PropertyModel::Reset : PropertyModel::NoAction) | ((MetaObjectRepository::instance()->metaObject(value.typeName()) && *reinterpret_cast<void* const*>(value.data())) || value.value<QObject*>() ? PropertyModel::NavigateTo : PropertyModel::NoAction); } else if (role == PropertyModel::ValueRole) { return value; } else if (role == PropertyModel::AppropriateToolRole) { ToolModel *toolModel = Probe::instance()->toolModel(); ToolFactory *factory; if (value.canConvert<QObject*>()) factory = toolModel->data(toolModel->toolForObject(value.value<QObject*>()), ToolModelRole::ToolFactory).value<ToolFactory*>(); else factory = toolModel->data(toolModel->toolForObject(*reinterpret_cast<void* const*>(value.data()), value.typeName()), ToolModelRole::ToolFactory).value<ToolFactory*>(); if (factory) { return factory->name(); } return QVariant(); } return QVariant(); }
void tst_QQmlMetaObject::property() { QFETCH(QString, testFile); QFETCH(QByteArray, cppTypeName); QFETCH(int, cppType); QFETCH(bool, isDefault); QFETCH(QVariant, expectedValue); QFETCH(bool, isWritable); QFETCH(QVariant, newValue); QQmlEngine engine; QQmlComponent component(&engine, testFileUrl(testFile)); QObject *object = component.create(); QVERIFY(object != 0); const QMetaObject *mo = object->metaObject(); QVERIFY(mo->superClass() != 0); QVERIFY(QByteArray(mo->className()).contains("_QML_")); QCOMPARE(mo->propertyOffset(), mo->superClass()->propertyCount()); QCOMPARE(mo->propertyCount(), mo->superClass()->propertyCount() + 1); QMetaProperty prop = mo->property(mo->propertyOffset()); QCOMPARE(prop.name(), "test"); QCOMPARE(QByteArray(prop.typeName()), cppTypeName); if (prop.userType() < QMetaType::User) QCOMPARE(prop.type(), QVariant::Type(cppType)); else QCOMPARE(prop.type(), QVariant::UserType); QCOMPARE(prop.userType(), cppType); QVERIFY(!prop.isConstant()); QVERIFY(!prop.isDesignable()); QVERIFY(!prop.isEnumType()); QVERIFY(!prop.isFinal()); QVERIFY(!prop.isFlagType()); QVERIFY(prop.isReadable()); QVERIFY(!prop.isResettable()); QVERIFY(prop.isScriptable()); QVERIFY(!prop.isStored()); QVERIFY(!prop.isUser()); QVERIFY(prop.isValid()); QCOMPARE(prop.isWritable(), isWritable); QCOMPARE(mo->classInfoOffset(), mo->superClass()->classInfoCount()); QCOMPARE(mo->classInfoCount(), mo->superClass()->classInfoCount() + (isDefault ? 1 : 0)); if (isDefault) { QMetaClassInfo info = mo->classInfo(mo->classInfoOffset()); QCOMPARE(info.name(), "DefaultProperty"); QCOMPARE(info.value(), "test"); } QCOMPARE(mo->methodOffset(), mo->superClass()->methodCount()); QCOMPARE(mo->methodCount(), mo->superClass()->methodCount() + 1); // the signal QVERIFY(prop.notifySignalIndex() != -1); QMetaMethod signal = prop.notifySignal(); QCOMPARE(signal.methodType(), QMetaMethod::Signal); QCOMPARE(signal.name(), QByteArray("testChanged")); QCOMPARE(signal.methodSignature(), QByteArray("testChanged()")); QCOMPARE(signal.access(), QMetaMethod::Public); QCOMPARE(signal.parameterCount(), 0); QCOMPARE(signal.parameterTypes(), QList<QByteArray>()); QCOMPARE(signal.parameterNames(), QList<QByteArray>()); QCOMPARE(signal.tag(), ""); QCOMPARE(signal.typeName(), "void"); QCOMPARE(signal.returnType(), int(QMetaType::Void)); QSignalSpy changedSpy(object, SIGNAL(testChanged())); QObject::connect(object, SIGNAL(testChanged()), object, SLOT(deleteLater())); if (expectedValue.isValid()) QCOMPARE(prop.read(object), expectedValue); else QVERIFY(prop.read(object).isValid()); QCOMPARE(changedSpy.count(), 0); if (isWritable) { QVERIFY(prop.write(object, newValue)); QCOMPARE(changedSpy.count(), 1); QCOMPARE(prop.read(object), newValue); } else { QVERIFY(!prop.write(object, prop.read(object))); QCOMPARE(changedSpy.count(), 0); } delete object; }