From 734324c37cb9d8417aa86f76fc81dadc21be2156 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 18 Oct 2012 15:55:45 +0200 Subject: QStyleSheetStyle: QObject-based style & render rules The goal is to cut as many QWidget dependencies as possible and make stylesheets eventually work for the desktop components. Change-Id: Ib4aa47af07379fc39fd6df1961e113d03df6df35 Reviewed-by: J-P Nurmi Reviewed-by: Olivier Goffart --- src/widgets/styles/qstylesheetstyle.cpp | 178 ++++++++++++++++---------------- src/widgets/styles/qstylesheetstyle_p.h | 20 ++-- 2 files changed, 101 insertions(+), 97 deletions(-) (limited to 'src/widgets') diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index d73d25a1af..857750b466 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -468,7 +468,7 @@ class QRenderRule { public: QRenderRule() : features(0), hasFont(false), pal(0), b(0), bg(0), bd(0), ou(0), geo(0), p(0), img(0), clipset(0) { } - QRenderRule(const QVector &, const QWidget *); + QRenderRule(const QVector &, const QObject *); ~QRenderRule() { } QRect borderRect(const QRect &r) const; @@ -859,7 +859,7 @@ static QStyle::StandardPixmap subControlIcon(int pe) return QStyle::SP_CustomBase; } -QRenderRule::QRenderRule(const QVector &declarations, const QWidget *widget) +QRenderRule::QRenderRule(const QVector &declarations, const QObject *object) : features(0), hasFont(false), pal(0), b(0), bg(0), bd(0), ou(0), geo(0), p(0), img(0), clipset(0) { QPalette palette = QApplication::palette(); // ###: ideally widget's palette @@ -928,7 +928,7 @@ QRenderRule::QRenderRule(const QVector &declarations, const QWidget hasFont = v.extractFont(&font, &adj); #ifndef QT_NO_TOOLTIP - if (widget && qstrcmp(widget->metaObject()->className(), "QTipLabel") == 0) + if (object && qstrcmp(object->metaObject()->className(), "QTipLabel") == 0) palette = QToolTip::palette(); #endif @@ -997,12 +997,15 @@ QRenderRule::QRenderRule(const QVector &declarations, const QWidget } } - if (widget) { + if (object) { QStyleSheetStyle *style = const_cast(globalStyleSheetStyle); - if (!style) - style = qobject_cast(widget->style()); - if (style) - fixupBorder(style->nativeFrameWidth(widget)); + if (!style) { + if (const QWidget *widget = qobject_cast(object)) { + style = qobject_cast(widget->style()); + if (style) + fixupBorder(style->nativeFrameWidth(widget)); + } + } } if (hasBorder() && border()->hasBorderImage()) @@ -1407,14 +1410,14 @@ void QRenderRule::configurePalette(QPalette *p, QPalette::ColorGroup cg, const Q // Style rules #define WIDGET(x) (static_cast(x.ptr)) -static inline QWidget *parentWidget(const QWidget *w) +static inline QObject *parentObject(const QObject *obj) { - if(qobject_cast(w) && qstrcmp(w->metaObject()->className(), "QTipLabel") == 0) { - QWidget *p = qvariant_cast(w->property("_q_stylesheet_parent")); + if (qobject_cast(obj) && qstrcmp(obj->metaObject()->className(), "QTipLabel") == 0) { + QObject *p = qvariant_cast(obj->property("_q_stylesheet_parent")); if (p) return p; } - return w->parentWidget(); + return obj->parent(); } class QStyleSheetStyleSelector : public StyleSelector @@ -1503,7 +1506,7 @@ public: bool isNullNode(NodePtr node) const { return node.ptr == 0; } NodePtr parentNode(NodePtr node) const - { NodePtr n; n.ptr = isNullNode(node) ? 0 : parentWidget(WIDGET(node)); return n; } + { NodePtr n; n.ptr = isNullNode(node) ? 0 : parentObject(WIDGET(node)); return n; } NodePtr previousSiblingNode(NodePtr) const { NodePtr n; n.ptr = 0; return n; } NodePtr duplicateNode(NodePtr node) const @@ -1515,13 +1518,13 @@ private: mutable QHash > m_attributeCache; }; -QVector QStyleSheetStyle::styleRules(const QWidget *w) const +QVector QStyleSheetStyle::styleRules(const QObject *obj) const { - QHash >::const_iterator cacheIt = styleSheetCaches->styleRulesCache.constFind(w); + QHash >::const_iterator cacheIt = styleSheetCaches->styleRulesCache.constFind(obj); if (cacheIt != styleSheetCaches->styleRulesCache.constEnd()) return cacheIt.value(); - if (!initWidget(w)) { + if (!initObject(obj)) { return QVector(); } @@ -1558,36 +1561,37 @@ QVector QStyleSheetStyle::styleRules(const QWidget *w) const styleSelector.styleSheets += appSs; } - QVector widgetSs; - for (const QWidget *wid = w; wid; wid = parentWidget(wid)) { - if (wid->styleSheet().isEmpty()) + QVector objectSs; + for (const QObject *o = obj; o; o = parentObject(o)) { + QString styleSheet = o->property("styleSheet").toString(); + if (styleSheet.isEmpty()) continue; StyleSheet ss; - QHash::const_iterator widCacheIt = styleSheetCaches->styleSheetCache.constFind(wid); - if (widCacheIt == styleSheetCaches->styleSheetCache.constEnd()) { - parser.init(wid->styleSheet()); + QHash::const_iterator objCacheIt = styleSheetCaches->styleSheetCache.constFind(o); + if (objCacheIt == styleSheetCaches->styleSheetCache.constEnd()) { + parser.init(styleSheet); if (!parser.parse(&ss)) { - parser.init(QLatin1String("* {") + wid->styleSheet() + QLatin1Char('}')); + parser.init(QLatin1String("* {") + styleSheet + QLatin1Char('}')); if (!parser.parse(&ss)) - qWarning("Could not parse stylesheet of widget %p", wid); + qWarning("Could not parse stylesheet of object %p", o); } ss.origin = StyleSheetOrigin_Inline; - styleSheetCaches->styleSheetCache.insert(wid, ss); + styleSheetCaches->styleSheetCache.insert(o, ss); } else { - ss = widCacheIt.value(); + ss = objCacheIt.value(); } - widgetSs.append(ss); + objectSs.append(ss); } - for (int i = 0; i < widgetSs.count(); i++) - widgetSs[i].depth = widgetSs.count() - i + 2; + for (int i = 0; i < objectSs.count(); i++) + objectSs[i].depth = objectSs.count() - i + 2; - styleSelector.styleSheets += widgetSs; + styleSelector.styleSheets += objectSs; StyleSelector::NodePtr n; - n.ptr = (void *)w; + n.ptr = (void *)obj; QVector rules = styleSelector.styleRulesForNode(n); - styleSheetCaches->styleRulesCache.insert(w, rules); + styleSheetCaches->styleRulesCache.insert(obj, rules); return rules; } @@ -1696,36 +1700,36 @@ static quint64 pseudoClass(QStyle::State state) return pc; } -static void qt_check_if_internal_widget(const QWidget **w, int *element) +static void qt_check_if_internal_object(const QObject **obj, int *element) { #ifdef QT_NO_DOCKWIDGET - Q_UNUSED(w); + Q_UNUSED(obj); Q_UNUSED(element); #else - if (*w && qstrcmp((*w)->metaObject()->className(), "QDockWidgetTitleButton") == 0) { - if ((*w)->objectName() == QLatin1String("qt_dockwidget_closebutton")) { + if (*obj && qstrcmp((*obj)->metaObject()->className(), "QDockWidgetTitleButton") == 0) { + if ((*obj)->objectName() == QLatin1String("qt_dockwidget_closebutton")) { *element = PseudoElement_DockWidgetCloseButton; - } else if ((*w)->objectName() == QLatin1String("qt_dockwidget_floatbutton")) { + } else if ((*obj)->objectName() == QLatin1String("qt_dockwidget_floatbutton")) { *element = PseudoElement_DockWidgetFloatButton; } - *w = (*w)->parentWidget(); + *obj = (*obj)->parent(); } #endif } -QRenderRule QStyleSheetStyle::renderRule(const QWidget *w, int element, quint64 state) const +QRenderRule QStyleSheetStyle::renderRule(const QObject *obj, int element, quint64 state) const { - qt_check_if_internal_widget(&w, &element); - QHash &cache = styleSheetCaches->renderRulesCache[w][element]; + qt_check_if_internal_object(&obj, &element); + QHash &cache = styleSheetCaches->renderRulesCache[obj][element]; QHash::const_iterator cacheIt = cache.constFind(state); if (cacheIt != cache.constEnd()) return cacheIt.value(); - if (!initWidget(w)) + if (!initObject(obj)) return QRenderRule(); quint64 stateMask = 0; - const QVector rules = styleRules(w); + const QVector rules = styleRules(obj); for (int i = 0; i < rules.count(); i++) { const Selector& selector = rules.at(i).selectors.at(0); quint64 negated = 0; @@ -1743,14 +1747,14 @@ QRenderRule QStyleSheetStyle::renderRule(const QWidget *w, int element, quint64 const QString part = QLatin1String(knownPseudoElements[element].name); QVector decls = declarations(rules, part, state); - QRenderRule newRule(decls, w); + QRenderRule newRule(decls, obj); cache[state] = newRule; if ((state & stateMask) != state) cache[state&stateMask] = newRule; return newRule; } -QRenderRule QStyleSheetStyle::renderRule(const QWidget *w, const QStyleOption *opt, int pseudoElement) const +QRenderRule QStyleSheetStyle::renderRule(const QObject *obj, const QStyleOption *opt, int pseudoElement) const { quint64 extraClass = 0; QStyle::State state = opt ? opt->state : QStyle::State(QStyle::State_None); @@ -2006,7 +2010,7 @@ QRenderRule QStyleSheetStyle::renderRule(const QWidget *w, const QStyleOption *o #endif #ifndef QT_NO_LINEEDIT // LineEdit sets Sunken flag to indicate Sunken frame (argh) - if (const QLineEdit *lineEdit = qobject_cast(w)) { + if (const QLineEdit *lineEdit = qobject_cast(obj)) { state &= ~QStyle::State_Sunken; if (lineEdit->hasFrame()) { extraClass &= ~PseudoClass_Frameless; @@ -2015,29 +2019,29 @@ QRenderRule QStyleSheetStyle::renderRule(const QWidget *w, const QStyleOption *o } } else #endif - if (const QFrame *frm = qobject_cast(w)) { + if (const QFrame *frm = qobject_cast(obj)) { if (frm->lineWidth() == 0) extraClass |= PseudoClass_Frameless; } } - return renderRule(w, pseudoElement, pseudoClass(state) | extraClass); + return renderRule(obj, pseudoElement, pseudoClass(state) | extraClass); } -bool QStyleSheetStyle::hasStyleRule(const QWidget *w, int part) const +bool QStyleSheetStyle::hasStyleRule(const QObject *obj, int part) const { - QHash &cache = styleSheetCaches->hasStyleRuleCache[w]; + QHash &cache = styleSheetCaches->hasStyleRuleCache[obj]; QHash::const_iterator cacheIt = cache.constFind(part); if (cacheIt != cache.constEnd()) return cacheIt.value(); - if (!initWidget(w)) + if (!initObject(obj)) return false; - const QVector &rules = styleRules(w); + const QVector &rules = styleRules(obj); if (part == PseudoElement_None) { - bool result = w && !rules.isEmpty(); + bool result = obj && !rules.isEmpty(); cache[part] = result; return result; } @@ -2594,25 +2598,24 @@ void QStyleSheetStyle::unsetPalette(QWidget *w) } } -static void updateWidgets(const QList& widgets) +static void updateObjects(const QList& objects) { if (!styleSheetCaches->styleRulesCache.isEmpty() || !styleSheetCaches->hasStyleRuleCache.isEmpty() || !styleSheetCaches->renderRulesCache.isEmpty()) { - for (int i = 0; i < widgets.size(); ++i) { - const QWidget *widget = widgets.at(i); - styleSheetCaches->styleRulesCache.remove(widget); - styleSheetCaches->hasStyleRuleCache.remove(widget); - styleSheetCaches->renderRulesCache.remove(widget); + for (int i = 0; i < objects.size(); ++i) { + const QObject *object = objects.at(i); + styleSheetCaches->styleRulesCache.remove(object); + styleSheetCaches->hasStyleRuleCache.remove(object); + styleSheetCaches->renderRulesCache.remove(object); } } - for (int i = 0; i < widgets.size(); ++i) { - QWidget *widget = const_cast(widgets.at(i)); - if (widget == 0) + for (int i = 0; i < objects.size(); ++i) { + QObject *object = const_cast(objects.at(i)); + if (object == 0) continue; - widget->style()->polish(widget); + if (QWidget *widget = qobject_cast(object)) + widget->style()->polish(widget); QEvent event(QEvent::StyleChange); - QApplication::sendEvent(widget, &event); - widget->update(); - widget->updateGeometry(); + QApplication::sendEvent(object, &event); } } @@ -2645,13 +2648,13 @@ QStyle *QStyleSheetStyle::baseStyle() const return QApplication::style(); } -void QStyleSheetStyleCaches::widgetDestroyed(QObject *o) +void QStyleSheetStyleCaches::objectDestroyed(QObject *o) { - styleRulesCache.remove((const QWidget *)o); - hasStyleRuleCache.remove((const QWidget *)o); - renderRulesCache.remove((const QWidget *)o); + styleRulesCache.remove(o); + hasStyleRuleCache.remove(o); + renderRulesCache.remove(o); customPaletteWidgets.remove((const QWidget *)o); - styleSheetCache.remove((const QWidget *)o); + styleSheetCache.remove(o); autoFillDisabledWidgets.remove((const QWidget *)o); } @@ -2664,18 +2667,19 @@ void QStyleSheetStyleCaches::styleDestroyed(QObject *o) * Make sure that the cache will be clean by connecting destroyed if needed. * return false if the widget is not stylable; */ -bool QStyleSheetStyle::initWidget(const QWidget *w) const +bool QStyleSheetStyle::initObject(const QObject *obj) const { - if (!w) - return false; - if(w->testAttribute(Qt::WA_StyleSheet)) - return true; - - if(unstylable(w)) + if (!obj) return false; + if (const QWidget *w = qobject_cast(obj)) { + if (w->testAttribute(Qt::WA_StyleSheet)) + return true; + if (unstylable(w)) + return false; + const_cast(w)->setAttribute(Qt::WA_StyleSheet, true); + } - const_cast(w)->setAttribute(Qt::WA_StyleSheet, true); - QObject::connect(w, SIGNAL(destroyed(QObject*)), styleSheetCaches, SLOT(widgetDestroyed(QObject*)), Qt::UniqueConnection); + QObject::connect(obj, SIGNAL(destroyed(QObject*)), styleSheetCaches, SLOT(objectDestroyed(QObject*)), Qt::UniqueConnection); return true; } @@ -2684,7 +2688,7 @@ void QStyleSheetStyle::polish(QWidget *w) baseStyle()->polish(w); RECURSION_GUARD(return) - if (!initWidget(w)) + if (!initObject(w)) return; if (styleSheetCaches->styleRulesCache.contains(w)) { @@ -2776,21 +2780,21 @@ void QStyleSheetStyle::polish(QPalette &pal) void QStyleSheetStyle::repolish(QWidget *w) { - QList children = w->findChildren(QString()); + QList children = w->findChildren(QString()); children.append(w); styleSheetCaches->styleSheetCache.remove(w); - updateWidgets(children); + updateObjects(children); } void QStyleSheetStyle::repolish(QApplication *app) { Q_UNUSED(app); - const QList allWidgets = styleSheetCaches->styleRulesCache.keys(); + const QList allObjects = styleSheetCaches->styleRulesCache.keys(); styleSheetCaches->styleSheetCache.remove(qApp); styleSheetCaches->styleRulesCache.clear(); styleSheetCaches->hasStyleRuleCache.clear(); styleSheetCaches->renderRulesCache.clear(); - updateWidgets(allWidgets); + updateObjects(allObjects); } void QStyleSheetStyle::unpolish(QWidget *w) @@ -5870,9 +5874,9 @@ Qt::Alignment QStyleSheetStyle::resolveAlignment(Qt::LayoutDirection layDir, Qt: // This does not mean that any QTabBar which is a child of QTabWidget will // match, only the one that was created by the QTabWidget initialization // (and hence has the correct object name). -bool QStyleSheetStyle::isNaturalChild(const QWidget *w) +bool QStyleSheetStyle::isNaturalChild(const QObject *obj) { - if (w->objectName().startsWith(QLatin1String("qt_"))) + if (obj->objectName().startsWith(QLatin1String("qt_"))) return true; return false; diff --git a/src/widgets/styles/qstylesheetstyle_p.h b/src/widgets/styles/qstylesheetstyle_p.h index 93bb4441bb..f42c0e9b20 100644 --- a/src/widgets/styles/qstylesheetstyle_p.h +++ b/src/widgets/styles/qstylesheetstyle_p.h @@ -143,8 +143,8 @@ private: friend class QRenderRule; int nativeFrameWidth(const QWidget *); - QRenderRule renderRule(const QWidget *, int, quint64 = 0) const; - QRenderRule renderRule(const QWidget *, const QStyleOption *, int = 0) const; + QRenderRule renderRule(const QObject *, int, quint64 = 0) const; + QRenderRule renderRule(const QObject *, const QStyleOption *, int = 0) const; QSize defaultSize(const QWidget *, QSize, const QRect&, int) const; QRect positionRect(const QWidget *, const QRenderRule&, const QRenderRule&, int, const QRect&, Qt::LayoutDirection) const; @@ -157,16 +157,16 @@ private: void unsetPalette(QWidget *); void setProperties(QWidget *); void setGeometry(QWidget *); - QVector styleRules(const QWidget *w) const; - bool hasStyleRule(const QWidget *w, int part) const; + QVector styleRules(const QObject *obj) const; + bool hasStyleRule(const QObject *obj, int part) const; QHash titleBarLayout(const QWidget *w, const QStyleOptionTitleBar *tb) const; QCss::StyleSheet getDefaultStyleSheet() const; static Qt::Alignment resolveAlignment(Qt::LayoutDirection, Qt::Alignment); - static bool isNaturalChild(const QWidget *w); - bool initWidget(const QWidget *w) const; + static bool isNaturalChild(const QObject *obj); + bool initObject(const QObject *obj) const; public: static int numinstances; @@ -179,13 +179,13 @@ class QStyleSheetStyleCaches : public QObject { Q_OBJECT public Q_SLOTS: - void widgetDestroyed(QObject *); + void objectDestroyed(QObject *); void styleDestroyed(QObject *); public: - QHash > styleRulesCache; - QHash > hasStyleRuleCache; + QHash > styleRulesCache; + QHash > hasStyleRuleCache; typedef QHash > QRenderRules; - QHash renderRulesCache; + QHash renderRulesCache; QHash customPaletteWidgets; // widgets whose palette we tampered QHash styleSheetCache; // parsed style sheets QSet autoFillDisabledWidgets; -- cgit v1.2.3