/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** 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, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.0, 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. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #ifdef QT3_SUPPORT #include #endif #include //TESTED_CLASS= //TESTED_FILES= 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(); 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 task188195_baseBackground(); //at the end because it mess with the style. void widgetStyle(); void appStyle(); 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 pstyle1 = &style1; QPointer 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(&style1), window1->style()); // Setting another style must not delete the older style window1->setStyle(&style2); QCOMPARE(static_cast(&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 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(&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(&style1)); // the same guy // Remove the stylesheet proxy = (QStyleSheetStyle *)window1->style(); window1->setStyleSheet(""); QVERIFY(proxy.isNull()); // should have disappeared QCOMPARE(window1->style(), static_cast(&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(&style1)); // Style Sheet propagation on a child widget with a custom style already set window2->setStyleSheet(""); QCOMPARE(window2->style(), static_cast(&style2)); QCOMPARE(widget2->style(), static_cast(&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 styleshet 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(newStyle)); // magic ;) the widget still follows the application QCOMPARE(static_cast(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(&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 style1 = new QWindowsStyle; QPointer 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 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 #include 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: true; qproperty-checked: 1}"); pb.ensurePolished(); QCOMPARE(pb.text(), QString("hello")); QCOMPARE(pb.isCheckable(), true); QCOMPARE(pb.isChecked(), true); } 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(pb)); 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(&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 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); } static bool testForColors(const QImage& image, const QColor& color) { int count = 0; QRgb rgb = color.rgba(); 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) { if (++count >= 10) { 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! :-) #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.", SkipAll); #endif /* Disabled changing style in order not to mess with the application style #ifdef Q_OS_MAC int styleCount = 3; QStyle *styles[3]; #else int styleCount = 2; QStyle *styles[2]; #endif styles[0] = new QPlastiqueStyle; styles[1] = new QWindowsStyle; #ifdef Q_OS_MAC styles[2] = new QMacStyle; #endif for (int i = 0; i < styleCount; ++i) { qApp->setStyle(styles[i]); */ QList widgets; widgets << new QPushButton("TESTING"); widgets << new QLineEdit("TESTING"); widgets << new QLabel("TESTING"); QSpinBox *spinbox = new QSpinBox; spinbox->setValue(8888); widgets << spinbox; QComboBox *combobox = new QComboBox; combobox->setEditable(true); combobox->addItems(QStringList() << "TESTING"); widgets << combobox; #ifdef Q_WS_QWS // QWS has its own special focus logic which is slightly different // and I don't dare change it at this point, because someone will // be relying on it. It means that setFocus() on a NoFocus widget (i.e. // a QLabel) will not work before the window is activated. widgets[2]->setFocusPolicy(Qt::StrongFocus); #endif 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(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&frame); #endif QApplication::setActiveWindow(&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", SkipAll); } 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()); } // } } 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(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(widget); #endif QImage image(widget->width(), widget->height(), QImage::Format_ARGB32); widget->render(&image); if (image.depth() < 24) { QSKIP("Test doesn't support color depth < 24", SkipAll); } 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() { QTabWidget tabWidget; tabWidget.show(); QTest::qWait(50); tabWidget.addTab(new QLabel("tab1"),"tab1"); tabWidget.resize(QSize(400,400)); QTabBar *bar = qFindChild(&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(&tabWidget); QVERIFY(bar); QVERIFY(qAbs(bar->tabRect(index1).width() - 100 - 2) <= 2); 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 { return style->subElementRect(se, opt, w); } 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); } 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(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 delete // 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); delete w; delete proxy; } 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); #ifdef QT3_SUPPORT layout.addWidget(new Q3ProgressBar(&w)); //task 231137 #endif 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(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&w); #endif //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(); QTest::qWait(100); QColor normalToolTip = qApp->palette().toolTipBase().color(); QList widgets; QList 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(); 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(); QVERIFY(embedded); QTest::qWait(20); QCOMPARE(box.font().pixelSize(), 32); QCOMPARE(embedded->font().pixelSize(), 32); } void tst_QStyleSheetStyle::opaquePaintEvent_data() { QTest::addColumn("stylesheet"); QTest::addColumn("transparent"); QTest::addColumn("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::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))); } QTEST_MAIN(tst_QStyleSheetStyle) #include "tst_qstylesheetstyle.moc"