qt5base-lts/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp
J-P Nurmi 9bc49b0bca Made QFusionStyle internal
We will take this opportynity to remove various QStyle specializations
from the public API in Qt5. This gives us much more freedom, for
example changing the inheritance hierarchy, pluginizing etc. without
worrying about BC.

=> Use QStyleFactory and/or QProxyStyle instead of creating an instance
or inheriting QFusionStyle directly.

Change-Id: I37d8acb13b6fd328a9cd53c74df971428bbbe443
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
2012-11-21 11:03:48 +01:00

1662 lines
57 KiB
C++

/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtCore>
#include <QtGui>
#include <QtWidgets>
#include <QtTest/QtTest>
#include <QtDebug>
#include <QMetaObject>
#include <private/qstylesheetstyle_p.h>
#include "../../../qtest-config.h"
class tst_QStyleSheetStyle : public QObject
{
Q_OBJECT
public:
tst_QStyleSheetStyle();
~tst_QStyleSheetStyle();
private slots:
void repolish();
void numinstances();
void widgetsBeforeAppStyleSheet();
void widgetsAfterAppStyleSheet();
void applicationStyleSheet();
void windowStyleSheet();
void widgetStyleSheet();
void reparentWithNoChildStyleSheet();
void reparentWithChildStyleSheet();
void dynamicProperty();
// NB! Invoking this slot after layoutSpacing crashes on Mac.
void namespaces();
#ifdef Q_OS_MAC
void layoutSpacing();
#endif
void qproperty();
void palettePropagation();
void fontPropagation();
void onWidgetDestroyed();
void fontPrecedence();
void focusColors();
#ifndef QTEST_NO_CURSOR
void hoverColors();
#endif
void background();
void tabAlignement();
void attributesList();
void minmaxSizes();
void task206238_twice();
void transparent();
void proxyStyle();
void dialogButtonBox();
void emptyStyleSheet();
void toolTip();
void embeddedFonts();
void opaquePaintEvent_data();
void opaquePaintEvent();
void complexWidgetFocus();
void task188195_baseBackground();
void task232085_spinBoxLineEditBg();
void changeStyleInChangeEvent();
void QTBUG15910_crashNullWidget();
//at the end because it mess with the style.
void widgetStyle();
void appStyle();
void QTBUG11658_cachecrash();
private:
QColor COLOR(const QWidget& w) {
w.ensurePolished();
return w.palette().color(w.foregroundRole());
}
QColor APPCOLOR(const QWidget& w) {
w.ensurePolished();
return qApp->palette(&w).color(w.foregroundRole());
}
QColor BACKGROUND(const QWidget& w) {
w.ensurePolished();
return w.palette().color(w.backgroundRole());
}
QColor APPBACKGROUND(const QWidget& w) {
w.ensurePolished();
return qApp->palette(&w).color(w.backgroundRole());
}
int FONTSIZE(const QWidget &w) {
w.ensurePolished();
return w.font().pointSize();
}
int APPFONTSIZE(const QWidget &w) {
return qApp->font(&w).pointSize();
}
};
tst_QStyleSheetStyle::tst_QStyleSheetStyle()
{
}
tst_QStyleSheetStyle::~tst_QStyleSheetStyle()
{
}
void tst_QStyleSheetStyle::numinstances()
{
QWidget w;
QCommonStyle *style = new QCommonStyle;
style->setParent(&w);
QWidget c(&w);
w.show();
// set and unset application stylesheet
QCOMPARE(QStyleSheetStyle::numinstances, 0);
qApp->setStyleSheet("* { color: red; }");
QCOMPARE(QStyleSheetStyle::numinstances, 1);
qApp->setStyleSheet("");
QCOMPARE(QStyleSheetStyle::numinstances, 0);
// set and unset application stylesheet+widget
qApp->setStyleSheet("* { color: red; }");
w.setStyleSheet("color: red;");
QCOMPARE(QStyleSheetStyle::numinstances, 2);
w.setStyle(style);
QCOMPARE(QStyleSheetStyle::numinstances, 2);
qApp->setStyleSheet("");
QCOMPARE(QStyleSheetStyle::numinstances, 1);
w.setStyleSheet("");
QCOMPARE(QStyleSheetStyle::numinstances, 0);
// set and unset widget stylesheet
w.setStyle(0);
w.setStyleSheet("color: red");
QCOMPARE(QStyleSheetStyle::numinstances, 1);
c.setStyle(style);
QCOMPARE(QStyleSheetStyle::numinstances, 2);
w.setStyleSheet("");
QCOMPARE(QStyleSheetStyle::numinstances, 0);
}
void tst_QStyleSheetStyle::widgetsBeforeAppStyleSheet()
{
QPushButton w1; // widget with no stylesheet
qApp->setStyleSheet("* { color: red; }");
QVERIFY(COLOR(w1) == QColor("red"));
w1.setStyleSheet("color: white");
QVERIFY(COLOR(w1) == QColor("white"));
qApp->setStyleSheet("");
QVERIFY(COLOR(w1) == QColor("white"));
w1.setStyleSheet("");
QVERIFY(COLOR(w1) == APPCOLOR(w1));
}
class FriendlySpinBox : public QSpinBox { friend class tst_QStyleSheetStyle; };
void tst_QStyleSheetStyle::widgetsAfterAppStyleSheet()
{
qApp->setStyleSheet("* { color: red; font-size: 32pt; }");
QPushButton w1;
FriendlySpinBox spin;
QVERIFY(COLOR(w1) == QColor("red"));
QVERIFY(COLOR(spin) == QColor("red"));
QVERIFY(COLOR(*spin.lineEdit()) == QColor("red"));
QCOMPARE(FONTSIZE(w1), 32);
QCOMPARE(FONTSIZE(spin), 32);
QCOMPARE(FONTSIZE(*spin.lineEdit()), 32);
w1.setStyleSheet("color: white");
QVERIFY(COLOR(w1) == QColor("white"));
QVERIFY(COLOR(spin) == QColor("red"));
QVERIFY(COLOR(*spin.lineEdit()) == QColor("red"));
w1.setStyleSheet("");
QVERIFY(COLOR(w1) == QColor("red"));
QVERIFY(COLOR(spin) == QColor("red"));
QVERIFY(COLOR(*spin.lineEdit()) == QColor("red"));
w1.setStyleSheet("color: white");
QVERIFY(COLOR(w1) == QColor("white"));
qApp->setStyleSheet("");
QVERIFY(COLOR(w1) == QColor("white"));
QVERIFY(COLOR(spin) == APPCOLOR(spin));
QVERIFY(COLOR(*spin.lineEdit()) == APPCOLOR(*spin.lineEdit()));
w1.setStyleSheet("");
QVERIFY(COLOR(w1) == APPCOLOR(w1));
// QCOMPARE(FONTSIZE(w1), APPFONTSIZE(w1)); //### task 244261
QCOMPARE(FONTSIZE(spin), APPFONTSIZE(spin));
//QCOMPARE(FONTSIZE(*spin.lineEdit()), APPFONTSIZE(*spin.lineEdit())); //### task 244261
}
void tst_QStyleSheetStyle::applicationStyleSheet()
{
QPushButton w1;
qApp->setStyleSheet("* { color: red; }");
QVERIFY(COLOR(w1) == QColor("red"));
qApp->setStyleSheet("* { color: white; }");
QVERIFY(COLOR(w1) == QColor("white"));
qApp->setStyleSheet("");
QVERIFY(COLOR(w1) == APPCOLOR(w1));
qApp->setStyleSheet("* { color: red }");
QVERIFY(COLOR(w1) == QColor("red"));
}
void tst_QStyleSheetStyle::windowStyleSheet()
{
QPushButton w1;
qApp->setStyleSheet("");
w1.setStyleSheet("* { color: red; }");
QVERIFY(COLOR(w1) == QColor("red"));
w1.setStyleSheet("* { color: white; }");
QVERIFY(COLOR(w1) == QColor("white"));
w1.setStyleSheet("");
QVERIFY(COLOR(w1) == APPCOLOR(w1));
w1.setStyleSheet("* { color: red }");
QVERIFY(COLOR(w1) == QColor("red"));
qApp->setStyleSheet("* { color: green }");
QVERIFY(COLOR(w1) == QColor("red"));
w1.setStyleSheet("");
QVERIFY(COLOR(w1) == QColor("green"));
qApp->setStyleSheet("");
QVERIFY(COLOR(w1) == APPCOLOR(w1));
}
void tst_QStyleSheetStyle::widgetStyleSheet()
{
QPushButton w1;
QPushButton *pb = new QPushButton(&w1);
QPushButton &w2 = *pb;
qApp->setStyleSheet("");
w1.setStyleSheet("* { color: red }");
QVERIFY(COLOR(w1) == QColor("red"));
QVERIFY(COLOR(w2) == QColor("red"));
w2.setStyleSheet("* { color: white }");
QVERIFY(COLOR(w2) == QColor("white"));
w1.setStyleSheet("* { color: blue }");
QVERIFY(COLOR(w1) == QColor("blue"));
QVERIFY(COLOR(w2) == QColor("white"));
w1.setStyleSheet("");
QVERIFY(COLOR(w1) == APPCOLOR(w1));
QVERIFY(COLOR(w2) == QColor("white"));
w2.setStyleSheet("");
QVERIFY(COLOR(w1) == APPCOLOR(w1));
QVERIFY(COLOR(w2) == APPCOLOR(w2));
}
void tst_QStyleSheetStyle::reparentWithNoChildStyleSheet()
{
QPushButton p1, p2;
QPushButton *pb = new QPushButton(&p1);
QPushButton &c1 = *pb; // child with no stylesheet
qApp->setStyleSheet("");
p1.setStyleSheet("* { color: red }");
QVERIFY(COLOR(c1) == QColor("red"));
c1.setParent(&p2);
QVERIFY(COLOR(c1) == APPCOLOR(c1));
p2.setStyleSheet("* { color: white }");
QVERIFY(COLOR(c1) == QColor("white"));
c1.setParent(&p1);
QVERIFY(COLOR(c1) == QColor("red"));
qApp->setStyleSheet("* { color: blue }");
c1.setParent(0);
QVERIFY(COLOR(c1) == QColor("blue"));
delete pb;
}
void tst_QStyleSheetStyle::reparentWithChildStyleSheet()
{
qApp->setStyleSheet("");
QPushButton p1, p2;
QPushButton *pb = new QPushButton(&p1);
QPushButton &c1 = *pb;
c1.setStyleSheet("background: gray");
QVERIFY(BACKGROUND(c1) == QColor("gray"));
c1.setParent(&p2);
QVERIFY(BACKGROUND(c1) == QColor("gray"));
qApp->setStyleSheet("* { color: white }");
c1.setParent(&p1);
QVERIFY(BACKGROUND(c1) == QColor("gray"));
QVERIFY(COLOR(c1) == QColor("white"));
}
void tst_QStyleSheetStyle::repolish()
{
qApp->setStyleSheet("");
QPushButton p1;
p1.setStyleSheet("color: red; background: white");
QVERIFY(BACKGROUND(p1) == QColor("white"));
p1.setStyleSheet("background: white");
QVERIFY(COLOR(p1) == APPCOLOR(p1));
p1.setStyleSheet("color: red");
QVERIFY(COLOR(p1) == QColor("red"));
QVERIFY(BACKGROUND(p1) == APPBACKGROUND(p1));
p1.setStyleSheet("");
QVERIFY(COLOR(p1) == APPCOLOR(p1));
QVERIFY(BACKGROUND(p1) == APPBACKGROUND(p1));
}
void tst_QStyleSheetStyle::widgetStyle()
{
qApp->setStyleSheet("");
QWidget *window1 = new QWidget;
window1->setObjectName("window1");
QWidget *widget1 = new QWidget(window1);
widget1->setObjectName("widget1");
QWidget *widget2 = new QWidget;
widget2->setObjectName("widget2");
QWidget *window2 = new QWidget;
window2->setObjectName("window2");
window1->ensurePolished();
window2->ensurePolished();
widget1->ensurePolished();
widget2->ensurePolished();
QWindowsStyle style1, style2;
QPointer<QStyle> pstyle1 = &style1;
QPointer<QStyle> pstyle2 = &style2;
QStyle *appStyle = qApp->style();
// Sanity: By default, a window inherits the application style
QCOMPARE(appStyle, window1->style());
// Setting a custom style on a widget
window1->setStyle(&style1);
QCOMPARE(static_cast<QStyle *>(&style1), window1->style());
// Setting another style must not delete the older style
window1->setStyle(&style2);
QCOMPARE(static_cast<QStyle *>(&style2), window1->style());
QVERIFY(!pstyle1.isNull()); // case we have not already crashed
// Setting null style must make it follow the qApp style
window1->setStyle(0);
QCOMPARE(window1->style(), appStyle);
QVERIFY(!pstyle2.isNull()); // case we have not already crashed
QVERIFY(!pstyle2.isNull()); // case we have not already crashed
// Sanity: Set the stylesheet
window1->setStyleSheet(":x { }");
QPointer<QStyleSheetStyle> proxy = (QStyleSheetStyle *)window1->style();
QVERIFY(!proxy.isNull());
QCOMPARE(proxy->metaObject()->className(), "QStyleSheetStyle"); // must be our proxy
QVERIFY(proxy->base == 0); // and follows the application
// Set the stylesheet
window1->setStyle(&style1);
QVERIFY(proxy.isNull()); // we create a new one each time
proxy = (QStyleSheetStyle *)window1->style();
QCOMPARE(proxy->metaObject()->className(), "QStyleSheetStyle"); // it is a proxy
QCOMPARE(proxy->baseStyle(), static_cast<QStyle *>(&style1)); // must have been replaced with the new one
// Update the stylesheet and check nothing changes
window1->setStyleSheet(":y { }");
QCOMPARE(window1->style()->metaObject()->className(), "QStyleSheetStyle"); // it is a proxy
QCOMPARE(proxy->baseStyle(), static_cast<QStyle *>(&style1)); // the same guy
// Remove the stylesheet
proxy = (QStyleSheetStyle *)window1->style();
window1->setStyleSheet("");
QVERIFY(proxy.isNull()); // should have disappeared
QCOMPARE(window1->style(), static_cast<QStyle *>(&style1)); // its restored
// Style Sheet existing children propagation
window1->setStyleSheet(":z { }");
proxy = (QStyleSheetStyle *)window1->style();
QCOMPARE(proxy->metaObject()->className(), "QStyleSheetStyle");
QCOMPARE(window1->style(), widget1->style()); // proxy must have propagated
QCOMPARE(widget2->style(), appStyle); // widget2 is following the app style
// Style Sheet automatic propagation to new children
widget2->setParent(window1); // reparent in!
QCOMPARE(window1->style(), widget2->style()); // proxy must have propagated
// Style Sheet automatic removal from children who abandoned their parents
window2->setStyle(&style2);
widget2->setParent(window2); // reparent
QCOMPARE(widget2->style(), appStyle); // widget2 is following the app style
// Style Sheet propagation on a child widget with a custom style
widget2->setStyle(&style1);
window2->setStyleSheet(":x { }");
proxy = (QStyleSheetStyle *)widget2->style();
QCOMPARE(proxy->metaObject()->className(), "QStyleSheetStyle");
QCOMPARE(proxy->baseStyle(), static_cast<QStyle *>(&style1));
// Style Sheet propagation on a child widget with a custom style already set
window2->setStyleSheet("");
QCOMPARE(window2->style(), static_cast<QStyle *>(&style2));
QCOMPARE(widget2->style(), static_cast<QStyle *>(&style1));
widget2->setStyle(0);
window2->setStyleSheet(":x { }");
widget2->setStyle(&style1);
proxy = (QStyleSheetStyle *)widget2->style();
QCOMPARE(proxy->metaObject()->className(), "QStyleSheetStyle");
// QApplication, QWidget both having a style sheet
// clean everything out
window1->setStyle(0);
window1->setStyleSheet("");
window2->setStyle(0);
window2->setStyleSheet("");
qApp->setStyle(0);
qApp->setStyleSheet("may_insanity_prevail { }"); // app has stylesheet
QCOMPARE(window1->style(), qApp->style());
QCOMPARE(window1->style()->metaObject()->className(), "QStyleSheetStyle");
QCOMPARE(widget1->style()->metaObject()->className(), "QStyleSheetStyle"); // check the child
window1->setStyleSheet("may_more_insanity_prevail { }"); // window has stylesheet
QCOMPARE(window1->style()->metaObject()->className(), "QStyleSheetStyle"); // a new one
QCOMPARE(widget1->style(), window1->style()); // child follows...
proxy = (QStyleSheetStyle *) window1->style();
QWindowsStyle *newStyle = new QWindowsStyle;
qApp->setStyle(newStyle); // set a custom style on app
proxy = (QStyleSheetStyle *) window1->style();
QCOMPARE(proxy->baseStyle(), static_cast<QStyle *>(newStyle)); // magic ;) the widget still follows the application
QCOMPARE(static_cast<QStyle *>(proxy), widget1->style()); // child still follows...
window1->setStyleSheet(""); // remove stylesheet
QCOMPARE(window1->style(), qApp->style()); // is this cool or what
QCOMPARE(widget1->style(), qApp->style()); // annoying child follows...
QWindowsStyle wndStyle;
window1->setStyle(&wndStyle);
QCOMPARE(window1->style()->metaObject()->className(), "QStyleSheetStyle"); // auto wraps it
QCOMPARE(widget1->style(), window1->style()); // and auto propagates to child
qApp->setStyleSheet(""); // remove the app stylesheet
QCOMPARE(window1->style(), static_cast<QStyle *>(&wndStyle)); // auto dewrap
QCOMPARE(widget1->style(), qApp->style()); // and child state is restored
window1->setStyle(0); // let sanity prevail
qApp->setStyle(0);
delete window1;
delete widget2;
delete window2;
}
void tst_QStyleSheetStyle::appStyle()
{
qApp->setStyleSheet("");
// qApp style can never be 0
QVERIFY(QApplication::style() != 0);
QPointer<QStyle> style1 = new QWindowsStyle;
QPointer<QStyle> style2 = new QWindowsStyle;
qApp->setStyle(style1);
// Basic sanity
QVERIFY(qApp->style() == style1);
qApp->setStyle(style2);
QVERIFY(style1.isNull()); // qApp must have taken ownership and deleted it
// Setting null should not crash
qApp->setStyle(0);
QVERIFY(qApp->style() == style2);
// Set the stylesheet
qApp->setStyleSheet("whatever");
QPointer<QStyleSheetStyle> sss = (QStyleSheetStyle *)qApp->style();
QVERIFY(!sss.isNull());
QCOMPARE(sss->metaObject()->className(), "QStyleSheetStyle"); // must be our proxy now
QVERIFY(!style2.isNull()); // this should exist as it is the base of the proxy
QVERIFY(sss->baseStyle() == style2);
style1 = new QWindowsStyle;
qApp->setStyle(style1);
QVERIFY(style2.isNull()); // should disappear automatically
QVERIFY(sss.isNull()); // should disappear automatically
// Update the stylesheet and check nothing changes
sss = (QStyleSheetStyle *)qApp->style();
qApp->setStyleSheet("whatever2");
QVERIFY(qApp->style() == sss);
QVERIFY(sss->baseStyle() == style1);
// Revert the stylesheet
qApp->setStyleSheet("");
QVERIFY(sss.isNull()); // should have disappeared
QVERIFY(qApp->style() == style1);
qApp->setStyleSheet("");
QVERIFY(qApp->style() == style1);
}
void tst_QStyleSheetStyle::dynamicProperty()
{
qApp->setStyleSheet(QString());
QString appStyle = qApp->style()->metaObject()->className();
QPushButton pb1, pb2;
pb1.setProperty("type", "critical");
qApp->setStyleSheet("*[class~=\"QPushButton\"] { color: red; } *[type=\"critical\"] { background: white; }");
QVERIFY(COLOR(pb1) == Qt::red);
QVERIFY(BACKGROUND(pb1) == Qt::white);
pb2.setProperty("class", "critical"); // dynamic class
pb2.setStyleSheet(QLatin1String(".critical[style~=\"") + appStyle + "\"] { color: blue }");
pb2.show();
QVERIFY(COLOR(pb2) == Qt::blue);
}
#ifdef Q_OS_MAC
void tst_QStyleSheetStyle::layoutSpacing()
{
qApp->setStyleSheet("* { color: red }");
QCheckBox ck1;
QCheckBox ck2;
QWidget window;
int spacing_widgetstyle = window.style()->layoutSpacing(ck1.sizePolicy().controlType(), ck2.sizePolicy().controlType(), Qt::Vertical);
int spacing_style = window.style()->layoutSpacing(ck1.sizePolicy().controlType(), ck2.sizePolicy().controlType(), Qt::Vertical);
QCOMPARE(spacing_widgetstyle, spacing_style);
}
#endif
void tst_QStyleSheetStyle::qproperty()
{
QPushButton pb;
pb.setStyleSheet("QPushButton { qproperty-text: hello; qproperty-checkable: 1; qproperty-checked: false}");
pb.ensurePolished();
QCOMPARE(pb.text(), QString("hello"));
QCOMPARE(pb.isCheckable(), true);
QCOMPARE(pb.isChecked(), false);
}
namespace ns {
class PushButton1 : public QPushButton {
Q_OBJECT
public:
PushButton1() { }
};
class PushButton2 : public PushButton1 {
Q_OBJECT
public:
PushButton2() { setProperty("class", "PushButtonTwo PushButtonDuo"); }
};
}
void tst_QStyleSheetStyle::namespaces()
{
ns::PushButton1 pb1;
qApp->setStyleSheet("ns--PushButton1 { background: white }");
QVERIFY(BACKGROUND(pb1) == QColor("white"));
qApp->setStyleSheet(".ns--PushButton1 { background: red }");
QVERIFY(BACKGROUND(pb1) == QColor("red"));
ns::PushButton2 pb2;
qApp->setStyleSheet("ns--PushButton1 { background: blue}");
QVERIFY(BACKGROUND(pb2) == QColor("blue"));
qApp->setStyleSheet("ns--PushButton2 { background: magenta }");
QVERIFY(BACKGROUND(pb2) == QColor("magenta"));
qApp->setStyleSheet(".PushButtonTwo { background: white; }");
QVERIFY(BACKGROUND(pb2) == QColor("white"));
qApp->setStyleSheet(".PushButtonDuo { background: red; }");
QVERIFY(BACKGROUND(pb2) == QColor("red"));
}
void tst_QStyleSheetStyle::palettePropagation()
{
qApp->setStyleSheet("");
QGroupBox gb;
QPushButton *push = new QPushButton(&gb);
QPushButton &pb = *push;
push->setText("AsdF");
gb.setStyleSheet("QGroupBox { color: red }");
QVERIFY(COLOR(gb) == Qt::red);
QVERIFY(COLOR(pb) == APPCOLOR(pb)); // palette shouldn't propagate
gb.setStyleSheet("QGroupBox * { color: red }");
QVERIFY(COLOR(pb) == Qt::red);
QVERIFY(COLOR(gb) == APPCOLOR(gb));
QWidget window;
window.setStyleSheet("* { color: white; }");
pb.setParent(&window);
QVERIFY(COLOR(pb) == Qt::white);
}
void tst_QStyleSheetStyle::fontPropagation()
{
qApp->setStyleSheet("");
QComboBox cb;
cb.addItem("item1");
cb.addItem("item2");
QAbstractItemView *popup = cb.view();
int viewFontSize = FONTSIZE(*popup);
cb.setStyleSheet("QComboBox { font-size: 20pt; }");
QVERIFY(FONTSIZE(cb) == 20);
QVERIFY(FONTSIZE(*popup) == viewFontSize);
QGroupBox gb;
QPushButton *push = new QPushButton(&gb);
QPushButton &pb = *push;
int buttonFontSize = FONTSIZE(pb);
int gbFontSize = FONTSIZE(gb);
gb.setStyleSheet("QGroupBox { font-size: 20pt }");
QVERIFY(FONTSIZE(gb) == 20);
QVERIFY(FONTSIZE(pb) == buttonFontSize); // font does not propagate
gb.setStyleSheet("QGroupBox * { font-size: 20pt; }");
QVERIFY(FONTSIZE(gb) == gbFontSize);
QVERIFY(FONTSIZE(pb) == 20);
QWidget window;
window.setStyleSheet("* { font-size: 10pt }");
pb.setParent(&window);
QCOMPARE(FONTSIZE(pb), 10);
window.setStyleSheet("");
QVERIFY(FONTSIZE(pb) == buttonFontSize);
QTabWidget tw;
tw.setStyleSheet("QTabWidget { font-size: 20pt; }");
QVERIFY(FONTSIZE(tw) == 20);
QWidget *child = qFindChild<QWidget *>(&tw, "qt_tabwidget_tabbar");
QVERIFY2(child, "QTabWidget did not contain a widget named \"qt_tabwidget_tabbar\"");
QVERIFY(FONTSIZE(*child) == 20);
}
void tst_QStyleSheetStyle::onWidgetDestroyed()
{
qApp->setStyleSheet("");
QLabel *l = new QLabel;
l->setStyleSheet("QLabel { color: red }");
QPointer<QStyleSheetStyle> ss = (QStyleSheetStyle *) l->style();
delete l;
QVERIFY(ss.isNull());
}
void tst_QStyleSheetStyle::fontPrecedence()
{
QLineEdit edit;
edit.show();
QFont font;
QVERIFY(FONTSIZE(edit) != 22); // Sanity check to make sure this test makes sense.
edit.setStyleSheet("QLineEdit { font-size: 22pt; }");
QCOMPARE(FONTSIZE(edit), 22);
font.setPointSize(16);
edit.setFont(font);
QCOMPARE(FONTSIZE(edit), 22);
edit.setStyleSheet("");
QCOMPARE(FONTSIZE(edit), 16);
font.setPointSize(18);
edit.setFont(font);
QCOMPARE(FONTSIZE(edit), 18);
edit.setStyleSheet("QLineEdit { font-size: 20pt; }");
QCOMPARE(FONTSIZE(edit), 20);
edit.setStyleSheet("");
QCOMPARE(FONTSIZE(edit), 18);
edit.hide();
QLineEdit edit2;
edit2.setReadOnly(true);
edit2.setStyleSheet("QLineEdit { font-size: 24pt; } QLineEdit:read-only { font-size: 26pt; }");
QCOMPARE(FONTSIZE(edit2), 26);
}
// Ensure primary will only return true if the color covers more than 50% of pixels
static bool testForColors(const QImage& image, const QColor& color, bool ensurePrimary=false)
{
int count = 0;
QRgb rgb = color.rgba();
int totalCount = image.height()*image.width();
for (int y = 0; y < image.height(); ++y) {
for (int x = 0; x < image.width(); ++x) {
// Because of antialiasing we allow a certain range of errors here.
QRgb pixel = image.pixel(x, y);
if (qAbs((int)(pixel & 0xff) - (int)(rgb & 0xff)) +
qAbs((int)((pixel & 0xff00) >> 8) - (int)((rgb & 0xff00) >> 8)) +
qAbs((int)((pixel & 0xff0000) >> 16) - (int)((rgb & 0xff0000) >> 16)) <= 50) {
count++;
if (!ensurePrimary && count >=10 )
return true;
else if (count > totalCount/2)
return true;
}
}
}
return false;
}
void tst_QStyleSheetStyle::focusColors()
{
// Tests if colors can be changed by altering the focus of the widget.
// To avoid messy pixel-by-pixel comparison, we assume that the goal
// is reached if at least ten pixels of the right color can be found in
// the image.
// For this reason, we use unusual and extremely ugly colors! :-)
// Note that in case of anti-aliased text, ensuring that we have at least
// ten pixels of the right color requires quite a many characters, as the
// majority of the pixels will have slightly different colors due to the
// anti-aliasing effect.
#if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) && !(defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(Q_CC_INTEL))
QSKIP("This is a fragile test which fails on many esoteric platforms because of focus problems. "
"That doesn't mean that the feature doesn't work in practice.");
#endif
QList<QWidget *> widgets;
widgets << new QPushButton("TESTING TESTING");
widgets << new QLineEdit("TESTING TESTING");
widgets << new QLabel("TESTING TESTING");
QSpinBox *spinbox = new QSpinBox;
spinbox->setMaximum(1000000000);
spinbox->setValue(123456789);
widgets << spinbox;
QComboBox *combobox = new QComboBox;
combobox->setEditable(true);
combobox->addItems(QStringList() << "TESTING TESTING");
widgets << combobox;
widgets << new QLabel("TESTING TESTING");
foreach (QWidget *widget, widgets) {
QDialog frame;
QLayout* layout = new QGridLayout;
QLineEdit* dummy = new QLineEdit; // Avoids initial focus.
widget->setStyleSheet("*:focus { border:none; background: #e8ff66; color: #ff0084 }");
layout->addWidget(dummy);
layout->addWidget(widget);
frame.setLayout(layout);
frame.show();
QApplication::setActiveWindow(&frame);
QVERIFY(QTest::qWaitForWindowActive(&frame));
widget->setFocus();
QApplication::processEvents();
QImage image(frame.width(), frame.height(), QImage::Format_ARGB32);
frame.render(&image);
if (image.depth() < 24)
QSKIP("Test doesn't support color depth < 24");
QVERIFY2(testForColors(image, QColor(0xe8, 0xff, 0x66)),
(QString::fromLatin1(widget->metaObject()->className())
+ " did not contain background color #e8ff66, using style "
+ QString::fromLatin1(qApp->style()->metaObject()->className()))
.toLocal8Bit().constData());
QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)),
(QString::fromLatin1(widget->metaObject()->className())
+ " did not contain text color #ff0084, using style "
+ QString::fromLatin1(qApp->style()->metaObject()->className()))
.toLocal8Bit().constData());
}
}
#ifndef QTEST_NO_CURSOR
void tst_QStyleSheetStyle::hoverColors()
{
QList<QWidget *> widgets;
widgets << new QPushButton("TESTING TESTING");
widgets << new QLineEdit("TESTING TESTING");
widgets << new QLabel("TESTING TESTING");
QSpinBox *spinbox = new QSpinBox;
spinbox->setMaximum(1000000000);
spinbox->setValue(123456789);
widgets << spinbox;
QComboBox *combobox = new QComboBox;
combobox->setEditable(true);
combobox->addItems(QStringList() << "TESTING TESTING");
widgets << combobox;
widgets << new QLabel("<b>TESTING TESTING</b>");
foreach (QWidget *widget, widgets) {
//without Qt::X11BypassWindowManagerHint the window manager may move the window after we moved the cursor
QDialog frame(0, Qt::X11BypassWindowManagerHint);
QLayout* layout = new QGridLayout;
QLineEdit* dummy = new QLineEdit;
widget->setStyleSheet("*:hover { border:none; background: #e8ff66; color: #ff0084 }");
layout->addWidget(dummy);
layout->addWidget(widget);
frame.setLayout(layout);
frame.show();
QApplication::setActiveWindow(&frame);
QVERIFY(QTest::qWaitForWindowActive(&frame));
//move the mouse inside the widget, it should be colored
QTest::mouseMove ( widget, QPoint(6,6));
QTest::qWait(60);
#ifdef Q_OS_MAC
QEXPECT_FAIL("", "Numerous failures related to Qt::WA_UnderMouse, see QTBUGT-23685", Continue);
#endif
QVERIFY(widget->testAttribute(Qt::WA_UnderMouse));
QImage image(frame.width(), frame.height(), QImage::Format_ARGB32);
frame.render(&image);
#ifdef Q_OS_MAC
QEXPECT_FAIL("", "Numerous failures related to Qt::WA_UnderMouse, see QTBUGT-23685", Continue);
#endif
QVERIFY2(testForColors(image, QColor(0xe8, 0xff, 0x66)),
(QString::fromLatin1(widget->metaObject()->className())
+ " did not contain background color #e8ff66").toLocal8Bit().constData());
#ifdef Q_OS_MAC
QEXPECT_FAIL("", "Numerous failures related to Qt::WA_UnderMouse, see QTBUGT-23685", Continue);
#endif
QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)),
(QString::fromLatin1(widget->metaObject()->className())
+ " did not contain text color #ff0084").toLocal8Bit().constData());
//move the mouse outside the widget, it should NOT be colored
QTest::mouseMove ( dummy, QPoint(5,5));
QTest::qWait(60);
frame.render(&image);
QVERIFY2(!testForColors(image, QColor(0xe8, 0xff, 0x66)),
(QString::fromLatin1(widget->metaObject()->className())
+ " did contain background color #e8ff66").toLocal8Bit().constData());
QVERIFY2(!testForColors(image, QColor(0xff, 0x00, 0x84)),
(QString::fromLatin1(widget->metaObject()->className())
+ " did contain text color #ff0084").toLocal8Bit().constData());
//move the mouse again inside the widget, it should be colored
QTest::mouseMove (widget, QPoint(5,5));
QTest::qWait(60);
QVERIFY(widget->testAttribute(Qt::WA_UnderMouse));
frame.render(&image);
QVERIFY2(testForColors(image, QColor(0xe8, 0xff, 0x66)),
(QString::fromLatin1(widget->metaObject()->className())
+ " did not contain background color #e8ff66").toLocal8Bit().constData());
QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)),
(QString::fromLatin1(widget->metaObject()->className())
+ " did not contain text color #ff0084").toLocal8Bit().constData());
}
}
#endif
class SingleInheritanceDialog : public QDialog
{
Q_OBJECT
public:
SingleInheritanceDialog(QWidget *w = 0) :
QDialog(w)
{
}
};
class DoubleInheritanceDialog : public SingleInheritanceDialog
{
Q_OBJECT
public:
DoubleInheritanceDialog(QWidget *w = 0) :
SingleInheritanceDialog(w)
{
}
};
void tst_QStyleSheetStyle::background()
{
const int number = 4;
QWidget* widgets[number];
// Testing inheritance styling of QDialog.
widgets[0] = new SingleInheritanceDialog;
widgets[0]->setStyleSheet("* { background-color: #e8ff66; }");
widgets[1] = new DoubleInheritanceDialog;
widgets[1]->setStyleSheet("* { background-color: #e8ff66; }");
// Testing gradients in QComboBox.
QLayout* layout;
QComboBox* cb;
// First color
widgets[2] = new QDialog;
layout = new QGridLayout;
cb = new QComboBox;
cb->setStyleSheet("* { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop:0 #e8ff66, stop:1 #000000); }");
layout->addWidget(cb);
widgets[2]->setLayout(layout);
// Second color
widgets[3] = new QDialog;
layout = new QGridLayout;
cb = new QComboBox;
cb->setStyleSheet("* { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop:0 #e8ff66, stop:1 #000000); }");
layout->addWidget(cb);
widgets[3]->setLayout(layout);
for (int c = 0; c < number; ++c) {
QWidget* widget = widgets[c];
widget->show();
QVERIFY(QTest::qWaitForWindowExposed(widget));
QImage image(widget->width(), widget->height(), QImage::Format_ARGB32);
widget->render(&image);
if (image.depth() < 24)
QSKIP("Test doesn't support color depth < 24");
QVERIFY2(testForColors(image, QColor(0xe8, 0xff, 0x66)),
(QString::fromLatin1(widget->metaObject()->className())
+ " did not contain background image with color #e8ff66")
.toLocal8Bit().constData());
delete widget;
}
}
void tst_QStyleSheetStyle::tabAlignement()
{
QWidget topLevel;
QTabWidget tabWidget(&topLevel);
tabWidget.addTab(new QLabel("tab1"),"tab1");
tabWidget.resize(QSize(400,400));
topLevel.show();
QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
QTabBar *bar = qFindChild<QTabBar*>(&tabWidget);
QVERIFY(bar);
//check the tab is on the right
tabWidget.setStyleSheet("QTabWidget::tab-bar { alignment: right ; }");
qApp->processEvents();
QVERIFY(bar->geometry().right() > 380);
QVERIFY(bar->geometry().left() > 200);
//check the tab is on the middle
tabWidget.setStyleSheet("QTabWidget::tab-bar { alignment: center ; }");
QVERIFY(bar->geometry().right() < 300);
QVERIFY(bar->geometry().left() > 100);
//check the tab is on the left
tabWidget.setStyleSheet("QTabWidget::tab-bar { alignment: left ; }");
QVERIFY(bar->geometry().left() < 20);
QVERIFY(bar->geometry().right() < 200);
tabWidget.setTabPosition(QTabWidget::West);
//check the tab is on the top
QVERIFY(bar->geometry().top() < 20);
QVERIFY(bar->geometry().bottom() < 200);
//check the tab is on the bottom
tabWidget.setStyleSheet("QTabWidget::tab-bar { alignment: right ; }");
QVERIFY(bar->geometry().bottom() > 380);
QVERIFY(bar->geometry().top() > 200);
//check the tab is on the middle
tabWidget.setStyleSheet("QTabWidget::tab-bar { alignment: center ; }");
QVERIFY(bar->geometry().bottom() < 300);
QVERIFY(bar->geometry().top() > 100);
}
void tst_QStyleSheetStyle::attributesList()
{
QWidget w;
QPushButton *p1=new QPushButton(&w);
QPushButton *p2=new QPushButton(&w);
QPushButton *p3=new QPushButton(&w);
QPushButton *p4=new QPushButton(&w);
p1->setProperty("prop", QStringList() << "red");
p2->setProperty("prop", QStringList() << "foo" << "red");
p3->setProperty("prop", QStringList() << "foo" << "bar");
w.setStyleSheet(" QPushButton{ background-color:blue; } QPushButton[prop~=red] { background-color:red; }");
QCOMPARE(BACKGROUND(*p1) , QColor("red"));
QCOMPARE(BACKGROUND(*p2) , QColor("red"));
QCOMPARE(BACKGROUND(*p3) , QColor("blue"));
QCOMPARE(BACKGROUND(*p4) , QColor("blue"));
}
void tst_QStyleSheetStyle::minmaxSizes()
{
QTabWidget tabWidget;
tabWidget.setObjectName("tabWidget");
int index1 = tabWidget.addTab(new QLabel("Tab1"),"a");
QWidget *page2=new QLabel("page2");
page2->setObjectName("page2");
page2->setStyleSheet("* {background-color: white; min-width: 250px; max-width:500px }");
tabWidget.addTab(page2,"Tab2");
QWidget *page3=new QLabel("plop");
page3->setObjectName("Page3");
page3->setStyleSheet("* {background-color: yellow; min-height: 250px; max-height:500px }");
int index3 = tabWidget.addTab(page3,"very_long_long_long_long_caption");
tabWidget.setStyleSheet("QTabBar::tab { min-width:100px; max-width:130px; }");
tabWidget.show();
QTest::qWait(50);
//i allow 4px additional border from the native style (hence the -2, <=2)
QVERIFY(qAbs(page2->maximumSize().width() - 500 - 2) <= 2);
QVERIFY(qAbs(page2->minimumSize().width() - 250 - 2) <= 2);
QVERIFY(qAbs(page3->maximumSize().height() - 500 - 2) <= 2);
QVERIFY(qAbs(page3->minimumSize().height() - 250 - 2) <= 2);
QVERIFY(qAbs(page3->minimumSize().height() - 250 - 2) <= 2);
QTabBar *bar = qFindChild<QTabBar*>(&tabWidget);
QVERIFY(bar);
#ifdef Q_OS_MAC
QEXPECT_FAIL("", "QTBUG-23686", Continue);
#endif
QVERIFY(qAbs(bar->tabRect(index1).width() - 100 - 2) <= 2);
#ifdef Q_OS_MAC
QEXPECT_FAIL("", "QTBUG-23686", Continue);
#endif
QVERIFY(qAbs(bar->tabRect(index3).width() - 130 - 2) <= 2);
}
void tst_QStyleSheetStyle::task206238_twice()
{
QMainWindow w;
QTabWidget* tw = new QTabWidget;
tw->addTab(new QLabel("foo"), "test");
w.setCentralWidget(tw);
w.setStyleSheet("background: red;");
w.show();
QTest::qWait(20);
QCOMPARE(BACKGROUND(w) , QColor("red"));
QCOMPARE(BACKGROUND(*tw), QColor("red"));
w.setStyleSheet("background: red;");
QTest::qWait(20);
QCOMPARE(BACKGROUND(w) , QColor("red"));
QCOMPARE(BACKGROUND(*tw), QColor("red"));
}
void tst_QStyleSheetStyle::transparent()
{
QWidget w;
QPushButton *p1=new QPushButton(&w);
QPushButton *p2=new QPushButton(&w);
QPushButton *p3=new QPushButton(&w);
p1->setStyleSheet("background:transparent");
p2->setStyleSheet("background-color:transparent");
p3->setStyleSheet("background:rgb(0,0,0,0)");
QCOMPARE(BACKGROUND(*p1) , QColor(0,0,0,0));
QCOMPARE(BACKGROUND(*p2) , QColor(0,0,0,0));
QCOMPARE(BACKGROUND(*p3) , QColor(0,0,0,0));
}
class ProxyStyle : public QStyle
{
public:
ProxyStyle(QStyle *s)
{
style = s;
}
void drawControl(ControlElement ce, const QStyleOption *opt,
QPainter *painter, const QWidget *widget = 0) const;
void drawPrimitive(QStyle::PrimitiveElement pe,
const QStyleOption* opt,
QPainter* p ,
const QWidget* w) const
{
style->drawPrimitive(pe, opt, p, w);
}
QRect subElementRect(QStyle::SubElement se,
const QStyleOption* opt,
const QWidget* w) const
{
Q_UNUSED(se);
Q_UNUSED(opt);
Q_UNUSED(w);
return QRect(0, 0, 3, 3);
}
void drawComplexControl(QStyle::ComplexControl cc,
const QStyleOptionComplex* opt,
QPainter* p,
const QWidget* w) const
{
style->drawComplexControl(cc, opt, p, w);
}
SubControl hitTestComplexControl(QStyle::ComplexControl cc,
const QStyleOptionComplex* opt,
const QPoint& pt,
const QWidget* w) const
{
return style->hitTestComplexControl(cc, opt, pt, w);
}
QRect subControlRect(QStyle::ComplexControl cc,
const QStyleOptionComplex* opt,
QStyle::SubControl sc,
const QWidget* w) const
{
return style->subControlRect(cc, opt, sc, w);
}
int pixelMetric(QStyle::PixelMetric pm,
const QStyleOption* opt,
const QWidget* w) const
{
return style->pixelMetric(pm, opt, w);
}
QSize sizeFromContents(QStyle::ContentsType ct,
const QStyleOption* opt,
const QSize& size,
const QWidget* w) const
{
return style->sizeFromContents(ct, opt, size, w);
}
int styleHint(QStyle::StyleHint sh,
const QStyleOption* opt,
const QWidget* w,
QStyleHintReturn* shr) const
{
return style->styleHint(sh, opt, w, shr);
}
QPixmap standardPixmap(QStyle::StandardPixmap spix,
const QStyleOption* opt,
const QWidget* w) const
{
return style->standardPixmap(spix, opt, w);
}
QPixmap generatedIconPixmap(QIcon::Mode mode,
const QPixmap& pix,
const QStyleOption* opt) const
{
return style->generatedIconPixmap(mode, pix, opt);
}
int layoutSpacing(QSizePolicy::ControlType c1,
QSizePolicy::ControlType c2,
Qt::Orientation ori,
const QStyleOption *opt,
const QWidget *w) const
{
return style->layoutSpacing(c1, c2, ori, opt, w);
}
QIcon standardIcon(StandardPixmap si,
const QStyleOption *opt,
const QWidget *w) const
{
return style->standardIcon(si, opt, w);
}
private:
QStyle *style;
};
void ProxyStyle::drawControl(ControlElement ce, const QStyleOption *opt,
QPainter *painter, const QWidget *widget) const
{
if(ce == CE_PushButton)
{
if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt))
{
QRect r = btn->rect;
painter->fillRect(r, Qt::green);
if(btn->state & QStyle::State_HasFocus)
painter->fillRect(r.adjusted(5, 5, -5, -5), Qt::yellow);
painter->drawText(r, Qt::AlignCenter, btn->text);
}
}
else
{
style->drawControl(ce, opt, painter, widget);
}
}
void tst_QStyleSheetStyle::proxyStyle()
{
//Should not crash; task 158984
ProxyStyle *proxy = new ProxyStyle(qApp->style());
QString styleSheet("QPushButton {background-color: red; }");
QWidget *w = new QWidget;
QVBoxLayout *layout = new QVBoxLayout(w);
QPushButton *pb1 = new QPushButton(qApp->style()->objectName(), w);
layout->addWidget(pb1);
QPushButton *pb2 = new QPushButton("ProxyStyle", w);
pb2->setStyle(proxy);
layout->addWidget(pb2);
QPushButton *pb3 = new QPushButton("StyleSheet", w);
pb3->setStyleSheet(styleSheet);
layout->addWidget(pb3);
QPushButton *pb4 = new QPushButton("StyleSheet then ProxyStyle ", w);
pb4->setStyleSheet(styleSheet);
// We are creating our Proxy based on current style...
// In this case it would be the QStyleSheetStyle that is deleted
// later on. We need to get access to the "real" QStyle to be able to
// draw correctly.
ProxyStyle* newProxy = new ProxyStyle(qApp->style());
pb4->setStyle(newProxy);
layout->addWidget(pb4);
QPushButton *pb5 = new QPushButton("ProxyStyle then StyleSheet ", w);
pb5->setStyle(proxy);
pb5->setStyleSheet(styleSheet);
layout->addWidget(pb5);
w->show();
QTest::qWait(100);
// Test for QTBUG-7198 - style sheet overrides custom element size
QStyleOptionViewItemV4 opt;
opt.initFrom(w);
opt.features |= QStyleOptionViewItemV2::HasCheckIndicator;
QVERIFY(pb5->style()->subElementRect(QStyle::SE_ItemViewItemCheckIndicator,
&opt, pb5).width() == 3);
delete w;
delete proxy;
delete newProxy;
}
void tst_QStyleSheetStyle::dialogButtonBox()
{
QDialogButtonBox box;
box.addButton(QDialogButtonBox::Ok);
box.addButton(QDialogButtonBox::Cancel);
box.setStyleSheet("/** */ ");
box.setStyleSheet(QString()); //should not crash
}
void tst_QStyleSheetStyle::emptyStyleSheet()
{
//empty stylesheet should not change anything
qApp->setStyleSheet(QString());
QWidget w;
QHBoxLayout layout(&w);
w.setLayout(&layout);
layout.addWidget(new QPushButton("push", &w));
layout.addWidget(new QToolButton(&w));
QLabel label("toto", &w);
label.setFrameShape(QLabel::Panel);
label.setFrameShadow(QLabel::Sunken);
layout.addWidget(&label); //task 231137
layout.addWidget(new QTableWidget(200,200, &w));
layout.addWidget(new QProgressBar(&w));
layout.addWidget(new QLineEdit(&w));
layout.addWidget(new QSpinBox(&w));
layout.addWidget(new QComboBox(&w));
layout.addWidget(new QDateEdit(&w));
layout.addWidget(new QGroupBox("some text", &w));
w.show();
QVERIFY(QTest::qWaitForWindowExposed(&w));
//workaround the fact that the label sizehint is one pixel different the first time.
label.setIndent(0); //force to recompute the sizeHint:
w.setFocus();
QTest::qWait(100);
QImage img1(w.size(), QImage::Format_ARGB32);
w.render(&img1);
w.setStyleSheet("/* */");
QTest::qWait(100);
QImage img2(w.size(), QImage::Format_ARGB32);
w.render(&img2);
if(img1 != img2) {
img1.save("emptyStyleSheet_img1.png");
img2.save("emptyStyleSheet_img2.png");
}
QCOMPARE(img1,img2);
}
void tst_QStyleSheetStyle::toolTip()
{
qApp->setStyleSheet(QString());
QWidget w;
QHBoxLayout layout(&w);
w.setLayout(&layout);
QWidget *wid1 = new QGroupBox(&w);
layout.addWidget(wid1);
wid1->setStyleSheet("QToolTip { background: #ae2; } #wid3 > QToolTip { background: #0b8; } ");
QVBoxLayout *layout1 = new QVBoxLayout(wid1);
wid1->setLayout(layout1);
wid1->setToolTip("this is wid1");
wid1->setObjectName("wid1");
QWidget *wid2 = new QPushButton("wid2", wid1);
layout1->addWidget(wid2);
wid2->setStyleSheet("QToolTip { background: #f81; } ");
wid2->setToolTip("this is wid2");
wid2->setObjectName("wid2");
QWidget *wid3 = new QPushButton("wid3", wid1);
layout1->addWidget(wid3);
wid3->setToolTip("this is wid3");
wid3->setObjectName("wid3");
QWidget *wid4 = new QPushButton("wid4", &w);
layout.addWidget(wid4);
wid4->setToolTip("this is wid4");
wid4->setObjectName("wid4");
w.show();
qApp->setActiveWindow(&w);
QVERIFY(QTest::qWaitForWindowActive(&w));
QColor normalToolTip = qApp->palette().toolTipBase().color();
QList<QWidget *> widgets;
QList<QColor> colors;
//tooltip on the widget without stylesheet, then to othes widget, including one without stylesheet
//(the tooltip will be reused but his colour must change)
widgets << wid4 << wid1 << wid2 << wid3 << wid4;
colors << normalToolTip << "#ae2" << "#f81" << "#0b8" << normalToolTip;
for (int i = 0; i < widgets.count() ; i++)
{
QWidget *wid = widgets.at(i);
QColor col = colors.at(i);
QToolTip::showText( QPoint(0,0) , "This is " + wid->objectName(), wid);
QWidget *tooltip = 0;
foreach (QWidget *widget, QApplication::topLevelWidgets()) {
if (widget->inherits("QTipLabel") && widget->isVisible()) {
tooltip = widget;
break;
}
}
QVERIFY(tooltip);
QCOMPARE(tooltip->palette().color(tooltip->backgroundRole()), col);
}
QToolTip::showText( QPoint(0,0) , "This is " + wid3->objectName(), wid3);
QTest::qWait(100);
delete wid3; //should not crash;
QTest::qWait(10);
foreach (QWidget *widget, QApplication::topLevelWidgets()) {
widget->update(); //should not crash either
}
}
void tst_QStyleSheetStyle::embeddedFonts()
{
//task 235622 and 210551
QSpinBox spin;
spin.show();
spin.setStyleSheet("QSpinBox { font-size: 32px; }");
QTest::qWait(20);
QLineEdit *embedded = spin.findChild<QLineEdit *>();
QVERIFY(embedded);
QCOMPARE(spin.font().pixelSize(), 32);
QCOMPARE(embedded->font().pixelSize(), 32);
QMenu *menu = embedded->createStandardContextMenu();
menu->show();
QTest::qWait(20);
QVERIFY(menu);
QVERIFY(menu->font().pixelSize() != 32);
QCOMPARE(menu->font().pixelSize(), qApp->font(menu).pixelSize());
//task 242556
QComboBox box;
box.setEditable(true);
box.addItems(QStringList() << "First" << "Second" << "Third");
box.setStyleSheet("QComboBox { font-size: 32px; }");
box.show();
embedded = box.findChild<QLineEdit *>();
QVERIFY(embedded);
QTest::qWait(20);
QCOMPARE(box.font().pixelSize(), 32);
QCOMPARE(embedded->font().pixelSize(), 32);
}
void tst_QStyleSheetStyle::opaquePaintEvent_data()
{
QTest::addColumn<QString>("stylesheet");
QTest::addColumn<bool>("transparent");
QTest::addColumn<bool>("styled");
QTest::newRow("none") << QString::fromLatin1("/* */") << false << false;
QTest::newRow("background black ") << QString::fromLatin1("background: black;") << false << true;
QTest::newRow("background qrgba") << QString::fromLatin1("background: rgba(125,0,0,125);") << true << true;
QTest::newRow("background transparent") << QString::fromLatin1("background: transparent;") << true << true;
QTest::newRow("border native") << QString::fromLatin1("border: native;") << false << false;
QTest::newRow("border solid") << QString::fromLatin1("border: 2px solid black;") << true << true;
QTest::newRow("border transparent") << QString::fromLatin1("background: black; border: 2px solid rgba(125,0,0,125);") << true << true;
QTest::newRow("margin") << QString::fromLatin1("margin: 25px;") << true << true;
QTest::newRow("focus") << QString::fromLatin1("*:focus { background: rgba(125,0,0,125) }") << true << true;
}
void tst_QStyleSheetStyle::opaquePaintEvent()
{
QFETCH(QString, stylesheet);
QFETCH(bool, transparent);
QFETCH(bool, styled);
QWidget tl;
QWidget cl(&tl);
cl.setAttribute(Qt::WA_OpaquePaintEvent, true);
cl.setAutoFillBackground(true);
cl.setStyleSheet(stylesheet);
cl.ensurePolished();
QCOMPARE(cl.testAttribute(Qt::WA_OpaquePaintEvent), !transparent);
QCOMPARE(cl.testAttribute(Qt::WA_StyledBackground), styled);
QCOMPARE(cl.autoFillBackground(), !styled );
}
void tst_QStyleSheetStyle::complexWidgetFocus()
{
// This test is a simplified version of the focusColors() test above.
// Tests if colors can be changed by altering the focus of the widget.
// To avoid messy pixel-by-pixel comparison, we assume that the goal
// is reached if at least ten pixels of the right color can be found in
// the image.
// For this reason, we use unusual and extremely ugly colors! :-)
QDialog frame;
frame.setStyleSheet("*:focus { background: black; color: black } "
"QSpinBox::up-arrow:focus, QSpinBox::down-arrow:focus { width: 7px; height: 7px; background: #ff0084 } "
"QComboBox::down-arrow:focus { width: 7px; height: 7px; background: #ff0084 }"
"QSlider::handle:horizontal:focus { width: 7px; height: 7px; background: #ff0084 } ");
QList<QWidget *> widgets;
widgets << new QSpinBox;
widgets << new QComboBox;
widgets << new QSlider(Qt::Horizontal);
QLayout* layout = new QGridLayout;
layout->addWidget(new QLineEdit); // Avoids initial focus.
foreach (QWidget *widget, widgets)
layout->addWidget(widget);
frame.setLayout(layout);
frame.show();
QApplication::setActiveWindow(&frame);
QVERIFY(QTest::qWaitForWindowActive(&frame));
foreach (QWidget *widget, widgets) {
widget->setFocus();
QApplication::processEvents();
QImage image(frame.width(), frame.height(), QImage::Format_ARGB32);
frame.render(&image);
if (image.depth() < 24)
QSKIP("Test doesn't support color depth < 24");
QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)),
(QString::fromLatin1(widget->metaObject()->className())
+ " did not contain text color #ff0084, using style "
+ QString::fromLatin1(qApp->style()->metaObject()->className()))
.toLocal8Bit().constData());
}
}
void tst_QStyleSheetStyle::task188195_baseBackground()
{
QTreeView tree;
tree.setStyleSheet( "QTreeView:disabled { background-color:#ab1251; }" );
tree.show();
QTest::qWait(20);
QImage image(tree.width(), tree.height(), QImage::Format_ARGB32);
tree.render(&image);
QVERIFY(testForColors(image, tree.palette().base().color()));
QVERIFY(!testForColors(image, QColor(0xab, 0x12, 0x51)));
tree.setEnabled(false);
tree.render(&image);
QVERIFY(testForColors(image, QColor(0xab, 0x12, 0x51)));
tree.setEnabled(true);
tree.render(&image);
QVERIFY(testForColors(image, tree.palette().base().color()));
QVERIFY(!testForColors(image, QColor(0xab, 0x12, 0x51)));
QTableWidget table(12, 12);
table.setItem(0, 0, new QTableWidgetItem());
table.setStyleSheet( "QTableView {background-color: #ff0000}" );
table.show();
QTest::qWait(20);
image = QImage(table.width(), table.height(), QImage::Format_ARGB32);
table.render(&image);
QVERIFY(testForColors(image, Qt::red, true));
}
void tst_QStyleSheetStyle::task232085_spinBoxLineEditBg()
{
// This test is a simplified version of the focusColors() test above.
// Tests if colors can be changed by altering the focus of the widget.
// To avoid messy pixel-by-pixel comparison, we assume that the goal
// is reached if at least ten pixels of the right color can be found in
// the image.
// For this reason, we use unusual and extremely ugly colors! :-)
QSpinBox *spinbox = new QSpinBox;
spinbox->setValue(8888);
QDialog frame;
QLayout* layout = new QGridLayout;
QLineEdit* dummy = new QLineEdit; // Avoids initial focus.
// We only want to test the line edit colors.
spinbox->setStyleSheet("QSpinBox:focus { background: #e8ff66; color: #ff0084 } "
"QSpinBox::up-button, QSpinBox::down-button { background: black; }");
layout->addWidget(dummy);
layout->addWidget(spinbox);
frame.setLayout(layout);
frame.show();
QApplication::setActiveWindow(&frame);
spinbox->setFocus();
QVERIFY(QTest::qWaitForWindowActive(&frame));
QImage image(frame.width(), frame.height(), QImage::Format_ARGB32);
frame.render(&image);
if (image.depth() < 24)
QSKIP("Test doesn't support color depth < 24");
QVERIFY2(testForColors(image, QColor(0xe8, 0xff, 0x66)),
(QString::fromLatin1(spinbox->metaObject()->className())
+ " did not contain background color #e8ff66, using style "
+ QString::fromLatin1(qApp->style()->metaObject()->className()))
.toLocal8Bit().constData());
QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)),
(QString::fromLatin1(spinbox->metaObject()->className())
+ " did not contain text color #ff0084, using style "
+ QString::fromLatin1(qApp->style()->metaObject()->className()))
.toLocal8Bit().constData());
}
class ChangeEventWidget : public QWidget
{ public:
void changeEvent(QEvent * event)
{
if(event->type() == QEvent::StyleChange) {
static bool recurse = false;
if (!recurse) {
recurse = true;
QStyle *style = QStyleFactory::create(QLatin1String("Fusion"));
style->setParent(this);
setStyle(style);
recurse = false;
}
}
QWidget::changeEvent(event);
}
};
void tst_QStyleSheetStyle::changeStyleInChangeEvent()
{ //must not crash;
ChangeEventWidget wid;
wid.ensurePolished();
wid.setStyleSheet(" /* */ ");
wid.ensurePolished();
wid.setStyleSheet(" /* ** */ ");
wid.ensurePolished();
}
void tst_QStyleSheetStyle::QTBUG11658_cachecrash()
{
//should not crash
class Widget : public QWidget
{
public:
Widget(QWidget *parent = 0)
: QWidget(parent)
{
QVBoxLayout* pLayout = new QVBoxLayout(this);
QCheckBox* pCheckBox = new QCheckBox(this);
pLayout->addWidget(pCheckBox);
setLayout(pLayout);
QString szStyleSheet = QLatin1String("* { color: red; }");
qApp->setStyleSheet(szStyleSheet);
qApp->setStyle(QStyleFactory::create(QLatin1String("Windows")));
}
};
Widget *w = new Widget();
delete w;
w = new Widget();
w->show();
QVERIFY(QTest::qWaitForWindowExposed(w));
delete w;
qApp->setStyleSheet(QString());
}
void tst_QStyleSheetStyle::QTBUG15910_crashNullWidget()
{
struct Widget : QWidget {
virtual void paintEvent(QPaintEvent* ) {
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, 0);
style()->drawPrimitive(QStyle::PE_Frame, &opt, &p, 0);
style()->drawControl(QStyle::CE_PushButton, &opt, &p, 0);
}
} w;
w.setStyleSheet("* { background-color: white; color:black; border 3px solid yellow }");
w.show();
QVERIFY(QTest::qWaitForWindowExposed(&w));
}
QTEST_MAIN(tst_QStyleSheetStyle)
#include "tst_qstylesheetstyle.moc"