diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index da3de4d651..283c3d346d 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -1988,7 +1988,7 @@ bool StyleSelector::nodeNameEquals(NodePtr node, const QString& nodeName) const QStringList StyleSelector::nodeIds(NodePtr node) const { - return QStringList(attribute(node, QLatin1String("id"))); + return QStringList(attributeValue(node, QCss::AttributeSelector{QLatin1String("id"), {}, AttributeSelector::NoMatch})); } bool StyleSelector::selectorMatches(const Selector &selector, NodePtr node) @@ -2060,7 +2060,7 @@ bool StyleSelector::basicSelectorMatches(const BasicSelector &sel, NodePtr node) for (int i = 0; i < sel.attributeSelectors.count(); ++i) { const QCss::AttributeSelector &a = sel.attributeSelectors.at(i); - const QString attrValue = attribute(node, a.name); + const QString attrValue = attributeValue(node, a); if (attrValue.isNull()) return false; diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h index 56af5c8bb2..dc982018b9 100644 --- a/src/gui/text/qcssparser_p.h +++ b/src/gui/text/qcssparser_p.h @@ -557,11 +557,10 @@ struct AttributeSelector MatchEndsWith, MatchContains }; - inline AttributeSelector() : valueMatchCriterium(NoMatch) {} QString name; QString value; - ValueMatchType valueMatchCriterium; + ValueMatchType valueMatchCriterium = NoMatch; }; QT_CSS_DECLARE_TYPEINFO(AttributeSelector, Q_RELOCATABLE_TYPE) @@ -666,7 +665,10 @@ public: QList declarationsForNode(NodePtr node, const char *extraPseudo = nullptr); virtual bool nodeNameEquals(NodePtr node, const QString& nodeName) const; - virtual QString attribute(NodePtr node, const QString &name) const = 0; + // ### TODO keep until QtSvg is updated with new qtbase and has overridden attributeValue + virtual QString attribute(NodePtr, const QString &) const { return QString(); } + virtual QString attributeValue(NodePtr node, const QCss::AttributeSelector &aSelector) const + { return attribute(node, aSelector.name); } virtual bool hasAttributes(NodePtr node) const = 0; virtual QStringList nodeIds(NodePtr node) const; virtual QStringList nodeNames(NodePtr node) const = 0; diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index f97b8a672a..2494fa472c 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -1848,14 +1848,14 @@ public: inline QTextHtmlStyleSelector(const QTextHtmlParser *parser) : parser(parser) { nameCaseSensitivity = Qt::CaseInsensitive; } - virtual QStringList nodeNames(NodePtr node) const override; - virtual QString attribute(NodePtr node, const QString &name) const override; - virtual bool hasAttributes(NodePtr node) const override; - virtual bool isNullNode(NodePtr node) const override; - virtual NodePtr parentNode(NodePtr node) const override; - virtual NodePtr previousSiblingNode(NodePtr node) const override; - virtual NodePtr duplicateNode(NodePtr node) const override; - virtual void freeNode(NodePtr node) const override; + QStringList nodeNames(NodePtr node) const override; + QString attributeValue(NodePtr node, const QCss::AttributeSelector &aSelector) const override; + bool hasAttributes(NodePtr node) const override; + bool isNullNode(NodePtr node) const override; + NodePtr parentNode(NodePtr node) const override; + NodePtr previousSiblingNode(NodePtr node) const override; + NodePtr duplicateNode(NodePtr node) const override; + void freeNode(NodePtr node) const override; private: const QTextHtmlParser *parser; @@ -1879,10 +1879,10 @@ static inline int findAttribute(const QStringList &attributes, const QString &na return idx; } -QString QTextHtmlStyleSelector::attribute(NodePtr node, const QString &name) const +QString QTextHtmlStyleSelector::attributeValue(NodePtr node, const QCss::AttributeSelector &aSelector) const { const QStringList &attributes = parser->at(node.id).attributes; - const int idx = findAttribute(attributes, name); + const int idx = findAttribute(attributes, aSelector.name); if (idx == -1) return QString(); return attributes.at(idx + 1); diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 1449def8c5..b799948933 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -1570,39 +1570,53 @@ public: } while (metaObject != nullptr); return result; } - QString attribute(NodePtr node, const QString& name) const override + QString attributeValue(NodePtr node, const QCss::AttributeSelector& aSelector) const override { if (isNullNode(node)) return QString(); + const QString &name = aSelector.name; QHash &cache = m_attributeCache[OBJECT_PTR(node)]; QHash::const_iterator cacheIt = cache.constFind(name); if (cacheIt != cache.constEnd()) return cacheIt.value(); + QVariant value; + QString valueStr; QObject *obj = OBJECT_PTR(node); - QVariant value = obj->property(name.toLatin1()); - if (!value.isValid()) { - if (name == QLatin1String("class")) { - QString className = QString::fromLatin1(obj->metaObject()->className()); - if (className.contains(QLatin1Char(':'))) - className.replace(QLatin1Char(':'), QLatin1Char('-')); - cache[name] = className; - return className; - } else if (name == QLatin1String("style")) { - QWidget *w = qobject_cast(obj); - QStyleSheetStyle *proxy = w ? qt_styleSheet(w->style()) : nullptr; - if (proxy) { - QString styleName = QString::fromLatin1(proxy->baseStyle()->metaObject()->className()); - cache[name] = styleName; - return styleName; + const int propertyIndex = obj->metaObject()->indexOfProperty(name.toLatin1()); + if (propertyIndex == -1) { + value = obj->property(name.toLatin1()); // might be a dynamic property + if (!value.isValid()) { + if (name == u"class"_qs) { + QString className = QString::fromLatin1(obj->metaObject()->className()); + if (className.contains(QLatin1Char(':'))) + className.replace(QLatin1Char(':'), QLatin1Char('-')); + valueStr = className; + } else if (name == u"style"_qs) { + QWidget *w = qobject_cast(obj); + QStyleSheetStyle *proxy = w ? qt_styleSheet(w->style()) : nullptr; + if (proxy) + valueStr = QString::fromLatin1(proxy->baseStyle()->metaObject()->className()); } } + } else { + const QMetaProperty property = obj->metaObject()->property(propertyIndex); + value = property.read(obj); + // support Qt 5 selector syntax, which required the integer enum value + if (property.isEnumType()) { + bool isNumber; + aSelector.value.toInt(&isNumber); + if (isNumber) + value.convert(QMetaType::fromType()); + } + } + if (value.isValid()) { + valueStr = (value.userType() == QMetaType::QStringList + || value.userType() == QMetaType::QVariantList) + ? value.toStringList().join(QLatin1Char(' ')) + : value.toString(); } - QString valueStr = (value.userType() == QMetaType::QStringList - || value.userType() == QMetaType::QVariantList) - ? value.toStringList().join(QLatin1Char(' ')) - : value.toString(); cache[name] = valueStr; return valueStr; } diff --git a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp index f51c0eab20..7c16f4aa76 100644 --- a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp +++ b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp @@ -886,32 +886,34 @@ public: styleSheets.append(sheet); } - virtual QStringList nodeNames(NodePtr node) const override { return QStringList(reinterpret_cast(node.ptr)->tagName()); } - virtual QString attribute(NodePtr node, const QString &name) const override { return reinterpret_cast(node.ptr)->attribute(name); } - virtual bool hasAttribute(NodePtr node, const QString &name) const { return reinterpret_cast(node.ptr)->hasAttribute(name); } - virtual bool hasAttributes(NodePtr node) const override { return reinterpret_cast(node.ptr)->hasAttributes(); } + QStringList nodeNames(NodePtr node) const override + { return QStringList(reinterpret_cast(node.ptr)->tagName()); } + QString attributeValue(NodePtr node, const QCss::AttributeSelector &aSel) const override + { return reinterpret_cast(node.ptr)->attribute(aSel.name); } + bool hasAttribute(NodePtr node, const QString &name) const + { return reinterpret_cast(node.ptr)->hasAttribute(name); } + bool hasAttributes(NodePtr node) const override + { return reinterpret_cast(node.ptr)->hasAttributes(); } - virtual bool isNullNode(NodePtr node) const override { - return reinterpret_cast(node.ptr)->isNull(); - } - virtual NodePtr parentNode(NodePtr node) const override { + bool isNullNode(NodePtr node) const override + { return reinterpret_cast(node.ptr)->isNull(); } + NodePtr parentNode(NodePtr node) const override { NodePtr parent; parent.ptr = new QDomElement(reinterpret_cast(node.ptr)->parentNode().toElement()); return parent; } - virtual NodePtr duplicateNode(NodePtr node) const override { + NodePtr duplicateNode(NodePtr node) const override { NodePtr n; n.ptr = new QDomElement(*reinterpret_cast(node.ptr)); return n; } - virtual NodePtr previousSiblingNode(NodePtr node) const override { + NodePtr previousSiblingNode(NodePtr node) const override { NodePtr sibling; sibling.ptr = new QDomElement(reinterpret_cast(node.ptr)->previousSiblingElement()); return sibling; } - virtual void freeNode(NodePtr node) const override { - delete reinterpret_cast(node.ptr); - } + void freeNode(NodePtr node) const override + { delete reinterpret_cast(node.ptr); } private: QDomDocument doc; diff --git a/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp index 6409a669fe..492b206019 100644 --- a/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp +++ b/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp @@ -2371,8 +2371,6 @@ void tst_QStyleSheetStyle::enumPropertySelector() #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QEXPECT_FAIL("Enum value", "In Qt 5, style sheet selectors have to use integer enum values", Continue); -#else - QEXPECT_FAIL("Int value", "In Qt 6, style sheet selectors must use the enum value name", Continue); #endif QVERIFY(styledSizeHint.width() > unstyledSizeHint.width());