Remove usage of deprecated qWaitForWindowShown(QWidget *) method.
[profile/ivi/qtbase.git] / tests / auto / widgets / styles / qstylesheetstyle / tst_qstylesheetstyle.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <QtCore>
42 #include <QtGui>
43 #include <QtWidgets>
44 #include <QtTest/QtTest>
45 #include <QtDebug>
46 #include <QMetaObject>
47
48 #include <private/qstylesheetstyle_p.h>
49 #include "../../../platformquirks.h"
50
51 class tst_QStyleSheetStyle : public QObject
52 {
53     Q_OBJECT
54 public:
55     tst_QStyleSheetStyle();
56     ~tst_QStyleSheetStyle();
57
58 private slots:
59     void repolish();
60     void numinstances();
61     void widgetsBeforeAppStyleSheet();
62     void widgetsAfterAppStyleSheet();
63     void applicationStyleSheet();
64     void windowStyleSheet();
65     void widgetStyleSheet();
66     void reparentWithNoChildStyleSheet();
67     void reparentWithChildStyleSheet();
68     void dynamicProperty();
69     // NB! Invoking this slot after layoutSpacing crashes on Mac.
70     void namespaces();
71 #ifdef Q_OS_MAC
72     void layoutSpacing();
73 #endif
74     void qproperty();
75     void palettePropagation();
76     void fontPropagation();
77     void onWidgetDestroyed();
78     void fontPrecedence();
79     void focusColors();
80     void hoverColors();
81     void background();
82     void tabAlignement();
83     void attributesList();
84     void minmaxSizes();
85     void task206238_twice();
86     void transparent();
87     void proxyStyle();
88     void dialogButtonBox();
89     void emptyStyleSheet();
90     void toolTip();
91     void embeddedFonts();
92     void opaquePaintEvent_data();
93     void opaquePaintEvent();
94     void complexWidgetFocus();
95     void task188195_baseBackground();
96     void task232085_spinBoxLineEditBg();
97     void changeStyleInChangeEvent();
98     void QTBUG15910_crashNullWidget();
99
100     //at the end because it mess with the style.
101     void widgetStyle();
102     void appStyle();
103     void QTBUG11658_cachecrash();
104 private:
105     QColor COLOR(const QWidget& w) {
106         w.ensurePolished();
107         return w.palette().color(w.foregroundRole());
108     }
109     QColor APPCOLOR(const QWidget& w) {
110         w.ensurePolished();
111         return qApp->palette(&w).color(w.foregroundRole());
112     }
113     QColor BACKGROUND(const QWidget& w) {
114         w.ensurePolished();
115         return w.palette().color(w.backgroundRole());
116     }
117     QColor APPBACKGROUND(const QWidget& w) {
118         w.ensurePolished();
119         return qApp->palette(&w).color(w.backgroundRole());
120     }
121     int FONTSIZE(const QWidget &w) {
122         w.ensurePolished();
123         return w.font().pointSize();
124     }
125     int APPFONTSIZE(const QWidget &w) {
126         return qApp->font(&w).pointSize();
127     }
128 };
129
130 tst_QStyleSheetStyle::tst_QStyleSheetStyle()
131 {
132 }
133
134 tst_QStyleSheetStyle::~tst_QStyleSheetStyle()
135 {
136 }
137
138 void tst_QStyleSheetStyle::numinstances()
139 {
140     QWidget w;
141     QCommonStyle *style = new QCommonStyle;
142     style->setParent(&w);
143     QWidget c(&w);
144     w.show();
145
146     // set and unset application stylesheet
147     QCOMPARE(QStyleSheetStyle::numinstances, 0);
148     qApp->setStyleSheet("* { color: red; }");
149     QCOMPARE(QStyleSheetStyle::numinstances, 1);
150     qApp->setStyleSheet("");
151     QCOMPARE(QStyleSheetStyle::numinstances, 0);
152
153     // set and unset application stylesheet+widget
154     qApp->setStyleSheet("* { color: red; }");
155     w.setStyleSheet("color: red;");
156     QCOMPARE(QStyleSheetStyle::numinstances, 2);
157     w.setStyle(style);
158     QCOMPARE(QStyleSheetStyle::numinstances, 2);
159     qApp->setStyleSheet("");
160     QCOMPARE(QStyleSheetStyle::numinstances, 1);
161     w.setStyleSheet("");
162     QCOMPARE(QStyleSheetStyle::numinstances, 0);
163
164     // set and unset widget stylesheet
165     w.setStyle(0);
166     w.setStyleSheet("color: red");
167     QCOMPARE(QStyleSheetStyle::numinstances, 1);
168     c.setStyle(style);
169     QCOMPARE(QStyleSheetStyle::numinstances, 2);
170     w.setStyleSheet("");
171     QCOMPARE(QStyleSheetStyle::numinstances, 0);
172 }
173
174 void tst_QStyleSheetStyle::widgetsBeforeAppStyleSheet()
175 {
176     QPushButton w1; // widget with no stylesheet
177     qApp->setStyleSheet("* { color: red; }");
178     QVERIFY(COLOR(w1) == QColor("red"));
179     w1.setStyleSheet("color: white");
180     QVERIFY(COLOR(w1) == QColor("white"));
181     qApp->setStyleSheet("");
182     QVERIFY(COLOR(w1) == QColor("white"));
183     w1.setStyleSheet("");
184     QVERIFY(COLOR(w1) == APPCOLOR(w1));
185 }
186
187 class FriendlySpinBox : public QSpinBox { friend class tst_QStyleSheetStyle; };
188
189 void tst_QStyleSheetStyle::widgetsAfterAppStyleSheet()
190 {
191     qApp->setStyleSheet("* { color: red; font-size: 32pt; }");
192     QPushButton w1;
193     FriendlySpinBox spin;
194     QVERIFY(COLOR(w1) == QColor("red"));
195     QVERIFY(COLOR(spin) == QColor("red"));
196     QVERIFY(COLOR(*spin.lineEdit()) == QColor("red"));
197     QCOMPARE(FONTSIZE(w1), 32);
198     QCOMPARE(FONTSIZE(spin), 32);
199     QCOMPARE(FONTSIZE(*spin.lineEdit()), 32);
200     w1.setStyleSheet("color: white");
201     QVERIFY(COLOR(w1) == QColor("white"));
202     QVERIFY(COLOR(spin) == QColor("red"));
203     QVERIFY(COLOR(*spin.lineEdit()) == QColor("red"));
204     w1.setStyleSheet("");
205     QVERIFY(COLOR(w1) == QColor("red"));
206     QVERIFY(COLOR(spin) == QColor("red"));
207     QVERIFY(COLOR(*spin.lineEdit()) == QColor("red"));
208     w1.setStyleSheet("color: white");
209     QVERIFY(COLOR(w1) == QColor("white"));
210     qApp->setStyleSheet("");
211     QVERIFY(COLOR(w1) == QColor("white"));
212     QVERIFY(COLOR(spin) == APPCOLOR(spin));
213     QVERIFY(COLOR(*spin.lineEdit()) == APPCOLOR(*spin.lineEdit()));
214     w1.setStyleSheet("");
215     QVERIFY(COLOR(w1) == APPCOLOR(w1));
216     // QCOMPARE(FONTSIZE(w1), APPFONTSIZE(w1));  //### task 244261
217     QCOMPARE(FONTSIZE(spin), APPFONTSIZE(spin));
218     //QCOMPARE(FONTSIZE(*spin.lineEdit()), APPFONTSIZE(*spin.lineEdit())); //### task 244261
219 }
220
221 void tst_QStyleSheetStyle::applicationStyleSheet()
222 {
223     QPushButton w1;
224     qApp->setStyleSheet("* { color: red; }");
225     QVERIFY(COLOR(w1) == QColor("red"));
226     qApp->setStyleSheet("* { color: white; }");
227     QVERIFY(COLOR(w1) == QColor("white"));
228     qApp->setStyleSheet("");
229     QVERIFY(COLOR(w1) == APPCOLOR(w1));
230     qApp->setStyleSheet("* { color: red }");
231     QVERIFY(COLOR(w1) == QColor("red"));
232 }
233
234 void tst_QStyleSheetStyle::windowStyleSheet()
235 {
236     QPushButton w1;
237     qApp->setStyleSheet("");
238     w1.setStyleSheet("* { color: red; }");
239     QVERIFY(COLOR(w1) == QColor("red"));
240     w1.setStyleSheet("* { color: white; }");
241     QVERIFY(COLOR(w1) == QColor("white"));
242     w1.setStyleSheet("");
243     QVERIFY(COLOR(w1) == APPCOLOR(w1));
244     w1.setStyleSheet("* { color: red }");
245     QVERIFY(COLOR(w1) == QColor("red"));
246
247     qApp->setStyleSheet("* { color: green }");
248     QVERIFY(COLOR(w1) == QColor("red"));
249     w1.setStyleSheet("");
250     QVERIFY(COLOR(w1) == QColor("green"));
251     qApp->setStyleSheet("");
252     QVERIFY(COLOR(w1) == APPCOLOR(w1));
253 }
254
255 void tst_QStyleSheetStyle::widgetStyleSheet()
256 {
257     QPushButton w1;
258     QPushButton *pb = new QPushButton(&w1);
259     QPushButton &w2 = *pb;
260
261     qApp->setStyleSheet("");
262     w1.setStyleSheet("* { color: red }");
263     QVERIFY(COLOR(w1) == QColor("red"));
264     QVERIFY(COLOR(w2) == QColor("red"));
265
266     w2.setStyleSheet("* { color: white }");
267     QVERIFY(COLOR(w2) == QColor("white"));
268
269     w1.setStyleSheet("* { color: blue }");
270     QVERIFY(COLOR(w1) == QColor("blue"));
271     QVERIFY(COLOR(w2) == QColor("white"));
272
273     w1.setStyleSheet("");
274     QVERIFY(COLOR(w1) == APPCOLOR(w1));
275     QVERIFY(COLOR(w2) == QColor("white"));
276
277     w2.setStyleSheet("");
278     QVERIFY(COLOR(w1) == APPCOLOR(w1));
279     QVERIFY(COLOR(w2) == APPCOLOR(w2));
280 }
281
282 void tst_QStyleSheetStyle::reparentWithNoChildStyleSheet()
283 {
284     QPushButton p1, p2;
285     QPushButton *pb = new QPushButton(&p1);
286     QPushButton &c1 = *pb; // child with no stylesheet
287
288     qApp->setStyleSheet("");
289     p1.setStyleSheet("* { color: red }");
290     QVERIFY(COLOR(c1) == QColor("red"));
291     c1.setParent(&p2);
292     QVERIFY(COLOR(c1) == APPCOLOR(c1));
293
294     p2.setStyleSheet("* { color: white }");
295     QVERIFY(COLOR(c1) == QColor("white"));
296
297     c1.setParent(&p1);
298     QVERIFY(COLOR(c1) == QColor("red"));
299
300     qApp->setStyleSheet("* { color: blue }");
301     c1.setParent(0);
302     QVERIFY(COLOR(c1) == QColor("blue"));
303     delete pb;
304 }
305
306 void tst_QStyleSheetStyle::reparentWithChildStyleSheet()
307 {
308     qApp->setStyleSheet("");
309     QPushButton p1, p2;
310     QPushButton *pb = new QPushButton(&p1);
311     QPushButton &c1 = *pb;
312
313     c1.setStyleSheet("background: gray");
314     QVERIFY(BACKGROUND(c1) == QColor("gray"));
315     c1.setParent(&p2);
316     QVERIFY(BACKGROUND(c1) == QColor("gray"));
317
318     qApp->setStyleSheet("* { color: white }");
319     c1.setParent(&p1);
320     QVERIFY(BACKGROUND(c1) == QColor("gray"));
321     QVERIFY(COLOR(c1) == QColor("white"));
322 }
323
324 void tst_QStyleSheetStyle::repolish()
325 {
326     qApp->setStyleSheet("");
327     QPushButton p1;
328     p1.setStyleSheet("color: red; background: white");
329     QVERIFY(BACKGROUND(p1) == QColor("white"));
330     p1.setStyleSheet("background: white");
331     QVERIFY(COLOR(p1) == APPCOLOR(p1));
332     p1.setStyleSheet("color: red");
333     QVERIFY(COLOR(p1) == QColor("red"));
334     QVERIFY(BACKGROUND(p1) == APPBACKGROUND(p1));
335     p1.setStyleSheet("");
336     QVERIFY(COLOR(p1) == APPCOLOR(p1));
337     QVERIFY(BACKGROUND(p1) == APPBACKGROUND(p1));
338 }
339
340 void tst_QStyleSheetStyle::widgetStyle()
341 {
342     qApp->setStyleSheet("");
343
344     QWidget *window1 = new QWidget;
345     window1->setObjectName("window1");
346     QWidget *widget1 = new QWidget(window1);
347     widget1->setObjectName("widget1");
348     QWidget *widget2 = new QWidget;
349     widget2->setObjectName("widget2");
350     QWidget *window2 = new QWidget;
351     window2->setObjectName("window2");
352     window1->ensurePolished();
353     window2->ensurePolished();
354     widget1->ensurePolished();
355     widget2->ensurePolished();
356
357     QWindowsStyle style1, style2;
358     QPointer<QStyle> pstyle1 = &style1;
359     QPointer<QStyle> pstyle2 = &style2;
360
361     QStyle *appStyle = qApp->style();
362
363     // Sanity: By default, a window inherits the application style
364     QCOMPARE(appStyle, window1->style());
365
366     // Setting a custom style on a widget
367     window1->setStyle(&style1);
368     QCOMPARE(static_cast<QStyle *>(&style1), window1->style());
369
370     // Setting another style must not delete the older style
371     window1->setStyle(&style2);
372     QCOMPARE(static_cast<QStyle *>(&style2), window1->style());
373     QVERIFY(!pstyle1.isNull()); // case we have not already crashed
374
375     // Setting null style must make it follow the qApp style
376     window1->setStyle(0);
377     QCOMPARE(window1->style(), appStyle);
378     QVERIFY(!pstyle2.isNull()); // case we have not already crashed
379     QVERIFY(!pstyle2.isNull()); // case we have not already crashed
380
381     // Sanity: Set the stylesheet
382     window1->setStyleSheet(":x { }");
383
384     QPointer<QStyleSheetStyle> proxy = (QStyleSheetStyle *)window1->style();
385     QVERIFY(!proxy.isNull());
386     QCOMPARE(proxy->metaObject()->className(), "QStyleSheetStyle"); // must be our proxy
387     QVERIFY(proxy->base == 0); // and follows the application
388
389     // Set the stylesheet
390     window1->setStyle(&style1);
391     QVERIFY(proxy.isNull()); // we create a new one each time
392     proxy = (QStyleSheetStyle *)window1->style();
393     QCOMPARE(proxy->metaObject()->className(), "QStyleSheetStyle"); // it is a proxy
394     QCOMPARE(proxy->baseStyle(), static_cast<QStyle *>(&style1)); // must have been replaced with the new one
395
396     // Update the stylesheet and check nothing changes
397     window1->setStyleSheet(":y { }");
398     QCOMPARE(window1->style()->metaObject()->className(), "QStyleSheetStyle"); // it is a proxy
399     QCOMPARE(proxy->baseStyle(), static_cast<QStyle *>(&style1)); // the same guy
400
401     // Remove the stylesheet
402     proxy = (QStyleSheetStyle *)window1->style();
403     window1->setStyleSheet("");
404     QVERIFY(proxy.isNull()); // should have disappeared
405     QCOMPARE(window1->style(), static_cast<QStyle *>(&style1)); // its restored
406
407     // Style Sheet existing children propagation
408     window1->setStyleSheet(":z { }");
409     proxy = (QStyleSheetStyle *)window1->style();
410     QCOMPARE(proxy->metaObject()->className(), "QStyleSheetStyle");
411     QCOMPARE(window1->style(), widget1->style()); // proxy must have propagated
412     QCOMPARE(widget2->style(), appStyle); // widget2 is following the app style
413
414     // Style Sheet automatic propagation to new children
415     widget2->setParent(window1); // reparent in!
416     QCOMPARE(window1->style(), widget2->style()); // proxy must have propagated
417
418     // Style Sheet automatic removal from children who abandoned their parents
419     window2->setStyle(&style2);
420     widget2->setParent(window2); // reparent
421     QCOMPARE(widget2->style(), appStyle); // widget2 is following the app style
422
423     // Style Sheet propagation on a child widget with a custom style
424     widget2->setStyle(&style1);
425     window2->setStyleSheet(":x { }");
426     proxy = (QStyleSheetStyle *)widget2->style();
427     QCOMPARE(proxy->metaObject()->className(), "QStyleSheetStyle");
428     QCOMPARE(proxy->baseStyle(), static_cast<QStyle *>(&style1));
429
430     // Style Sheet propagation on a child widget with a custom style already set
431     window2->setStyleSheet("");
432     QCOMPARE(window2->style(), static_cast<QStyle *>(&style2));
433     QCOMPARE(widget2->style(), static_cast<QStyle *>(&style1));
434     widget2->setStyle(0);
435     window2->setStyleSheet(":x { }");
436     widget2->setStyle(&style1);
437     proxy = (QStyleSheetStyle *)widget2->style();
438     QCOMPARE(proxy->metaObject()->className(), "QStyleSheetStyle");
439
440     // QApplication, QWidget both having a style sheet
441
442     // clean everything out
443     window1->setStyle(0);
444     window1->setStyleSheet("");
445     window2->setStyle(0);
446     window2->setStyleSheet("");
447     qApp->setStyle(0);
448
449     qApp->setStyleSheet("may_insanity_prevail { }"); // app has stylesheet
450     QCOMPARE(window1->style(), qApp->style());
451     QCOMPARE(window1->style()->metaObject()->className(), "QStyleSheetStyle");
452     QCOMPARE(widget1->style()->metaObject()->className(), "QStyleSheetStyle"); // check the child
453     window1->setStyleSheet("may_more_insanity_prevail { }"); // window has stylesheet
454     QCOMPARE(window1->style()->metaObject()->className(), "QStyleSheetStyle"); // a new one
455     QCOMPARE(widget1->style(), window1->style()); // child follows...
456     proxy = (QStyleSheetStyle *) window1->style();
457     QWindowsStyle *newStyle = new QWindowsStyle;
458     qApp->setStyle(newStyle); // set a custom style on app
459     proxy = (QStyleSheetStyle *) window1->style();
460     QCOMPARE(proxy->baseStyle(), static_cast<QStyle *>(newStyle)); // magic ;) the widget still follows the application
461     QCOMPARE(static_cast<QStyle *>(proxy), widget1->style()); // child still follows...
462
463     window1->setStyleSheet(""); // remove stylesheet
464     QCOMPARE(window1->style(), qApp->style()); // is this cool or what
465     QCOMPARE(widget1->style(), qApp->style()); // annoying child follows...
466     QWindowsStyle wndStyle;
467     window1->setStyle(&wndStyle);
468     QCOMPARE(window1->style()->metaObject()->className(), "QStyleSheetStyle"); // auto wraps it
469     QCOMPARE(widget1->style(), window1->style()); // and auto propagates to child
470     qApp->setStyleSheet(""); // remove the app stylesheet
471     QCOMPARE(window1->style(), static_cast<QStyle *>(&wndStyle)); // auto dewrap
472     QCOMPARE(widget1->style(), qApp->style()); // and child state is restored
473     window1->setStyle(0); // let sanity prevail
474     qApp->setStyle(0);
475
476     delete window1;
477     delete widget2;
478     delete window2;
479 }
480
481 void tst_QStyleSheetStyle::appStyle()
482 {
483     qApp->setStyleSheet("");
484     // qApp style can never be 0
485     QVERIFY(QApplication::style() != 0);
486     QPointer<QStyle> style1 = new QWindowsStyle;
487     QPointer<QStyle> style2 = new QWindowsStyle;
488     qApp->setStyle(style1);
489     // Basic sanity
490     QVERIFY(qApp->style() == style1);
491     qApp->setStyle(style2);
492     QVERIFY(style1.isNull()); // qApp must have taken ownership and deleted it
493     // Setting null should not crash
494     qApp->setStyle(0);
495     QVERIFY(qApp->style() == style2);
496
497     // Set the stylesheet
498     qApp->setStyleSheet("whatever");
499     QPointer<QStyleSheetStyle> sss = (QStyleSheetStyle *)qApp->style();
500     QVERIFY(!sss.isNull());
501     QCOMPARE(sss->metaObject()->className(), "QStyleSheetStyle"); // must be our proxy now
502     QVERIFY(!style2.isNull()); // this should exist as it is the base of the proxy
503     QVERIFY(sss->baseStyle() == style2);
504     style1 = new QWindowsStyle;
505     qApp->setStyle(style1);
506     QVERIFY(style2.isNull()); // should disappear automatically
507     QVERIFY(sss.isNull()); // should disappear automatically
508
509     // Update the stylesheet and check nothing changes
510     sss = (QStyleSheetStyle *)qApp->style();
511     qApp->setStyleSheet("whatever2");
512     QVERIFY(qApp->style() == sss);
513     QVERIFY(sss->baseStyle() == style1);
514
515     // Revert the stylesheet
516     qApp->setStyleSheet("");
517     QVERIFY(sss.isNull()); // should have disappeared
518     QVERIFY(qApp->style() == style1);
519
520     qApp->setStyleSheet("");
521     QVERIFY(qApp->style() == style1);
522 }
523
524 void tst_QStyleSheetStyle::dynamicProperty()
525 {
526     qApp->setStyleSheet(QString());
527
528     QString appStyle = qApp->style()->metaObject()->className();
529     QPushButton pb1, pb2;
530     pb1.setProperty("type", "critical");
531     qApp->setStyleSheet("*[class~=\"QPushButton\"] { color: red; } *[type=\"critical\"] { background: white; }");
532     QVERIFY(COLOR(pb1) == Qt::red);
533     QVERIFY(BACKGROUND(pb1) == Qt::white);
534
535     pb2.setProperty("class", "critical"); // dynamic class
536     pb2.setStyleSheet(QLatin1String(".critical[style~=\"") + appStyle + "\"] { color: blue }");
537     pb2.show();
538
539     QVERIFY(COLOR(pb2) == Qt::blue);
540 }
541
542 #ifdef Q_OS_MAC
543 void tst_QStyleSheetStyle::layoutSpacing()
544 {
545     qApp->setStyleSheet("* { color: red }");
546     QCheckBox ck1;
547     QCheckBox ck2;
548     QWidget window;
549     int spacing_widgetstyle = window.style()->layoutSpacing(ck1.sizePolicy().controlType(), ck2.sizePolicy().controlType(), Qt::Vertical);
550     int spacing_style = window.style()->layoutSpacing(ck1.sizePolicy().controlType(), ck2.sizePolicy().controlType(), Qt::Vertical);
551     QCOMPARE(spacing_widgetstyle, spacing_style);
552 }
553 #endif
554
555 void tst_QStyleSheetStyle::qproperty()
556 {
557     QPushButton pb;
558     pb.setStyleSheet("QPushButton { qproperty-text: hello; qproperty-checkable: 1; qproperty-checked: false}");
559     pb.ensurePolished();
560     QCOMPARE(pb.text(), QString("hello"));
561     QCOMPARE(pb.isCheckable(), true);
562     QCOMPARE(pb.isChecked(), false);
563 }
564
565 namespace ns {
566     class PushButton1 : public QPushButton {
567         Q_OBJECT
568     public:
569         PushButton1() { }
570     };
571     class PushButton2 : public PushButton1 {
572         Q_OBJECT
573     public:
574         PushButton2() { setProperty("class", "PushButtonTwo PushButtonDuo"); }
575     };
576 }
577
578 void tst_QStyleSheetStyle::namespaces()
579 {
580     ns::PushButton1 pb1;
581     qApp->setStyleSheet("ns--PushButton1 { background: white }");
582     QVERIFY(BACKGROUND(pb1) == QColor("white"));
583     qApp->setStyleSheet(".ns--PushButton1 { background: red }");
584     QVERIFY(BACKGROUND(pb1) == QColor("red"));
585
586     ns::PushButton2 pb2;
587     qApp->setStyleSheet("ns--PushButton1 { background: blue}");
588     QVERIFY(BACKGROUND(pb2) == QColor("blue"));
589     qApp->setStyleSheet("ns--PushButton2 { background: magenta }");
590     QVERIFY(BACKGROUND(pb2) == QColor("magenta"));
591     qApp->setStyleSheet(".PushButtonTwo { background: white; }");
592     QVERIFY(BACKGROUND(pb2) == QColor("white"));
593     qApp->setStyleSheet(".PushButtonDuo { background: red; }");
594     QVERIFY(BACKGROUND(pb2) == QColor("red"));
595 }
596
597 void tst_QStyleSheetStyle::palettePropagation()
598 {
599     qApp->setStyleSheet("");
600     QGroupBox gb;
601     QPushButton *push = new QPushButton(&gb);
602     QPushButton &pb = *push;
603     push->setText("AsdF");
604
605     gb.setStyleSheet("QGroupBox { color: red }");
606     QVERIFY(COLOR(gb) == Qt::red);
607     QVERIFY(COLOR(pb) == APPCOLOR(pb)); // palette shouldn't propagate
608     gb.setStyleSheet("QGroupBox * { color: red }");
609
610     QVERIFY(COLOR(pb) == Qt::red);
611     QVERIFY(COLOR(gb) == APPCOLOR(gb));
612
613     QWidget window;
614     window.setStyleSheet("* { color: white; }");
615     pb.setParent(&window);
616     QVERIFY(COLOR(pb) == Qt::white);
617 }
618
619 void tst_QStyleSheetStyle::fontPropagation()
620 {
621     qApp->setStyleSheet("");
622     QComboBox cb;
623     cb.addItem("item1");
624     cb.addItem("item2");
625
626     QAbstractItemView *popup = cb.view();
627     int viewFontSize = FONTSIZE(*popup);
628
629     cb.setStyleSheet("QComboBox { font-size: 20pt; }");
630     QVERIFY(FONTSIZE(cb) == 20);
631     QVERIFY(FONTSIZE(*popup) == viewFontSize);
632     QGroupBox gb;
633     QPushButton *push = new QPushButton(&gb);
634     QPushButton &pb = *push;
635     int buttonFontSize = FONTSIZE(pb);
636     int gbFontSize = FONTSIZE(gb);
637
638     gb.setStyleSheet("QGroupBox { font-size: 20pt }");
639     QVERIFY(FONTSIZE(gb) == 20);
640     QVERIFY(FONTSIZE(pb) == buttonFontSize); // font does not propagate
641     gb.setStyleSheet("QGroupBox * { font-size: 20pt; }");
642     QVERIFY(FONTSIZE(gb) == gbFontSize);
643     QVERIFY(FONTSIZE(pb) == 20);
644
645     QWidget window;
646     window.setStyleSheet("* { font-size: 10pt }");
647     pb.setParent(&window);
648     QCOMPARE(FONTSIZE(pb), 10);
649     window.setStyleSheet("");
650     QVERIFY(FONTSIZE(pb) == buttonFontSize);
651
652     QTabWidget tw;
653     tw.setStyleSheet("QTabWidget { font-size: 20pt; }");
654     QVERIFY(FONTSIZE(tw) == 20);
655     QWidget *child = qFindChild<QWidget *>(&tw, "qt_tabwidget_tabbar");
656     QVERIFY2(child, "QTabWidget did not contain a widget named \"qt_tabwidget_tabbar\"");
657     QVERIFY(FONTSIZE(*child) == 20);
658 }
659
660 void tst_QStyleSheetStyle::onWidgetDestroyed()
661 {
662     qApp->setStyleSheet("");
663     QLabel *l = new QLabel;
664     l->setStyleSheet("QLabel { color: red }");
665     QPointer<QStyleSheetStyle> ss = (QStyleSheetStyle *) l->style();
666     delete l;
667     QVERIFY(ss.isNull());
668 }
669
670 void tst_QStyleSheetStyle::fontPrecedence()
671 {
672     QLineEdit edit;
673     edit.show();
674     QFont font;
675     QVERIFY(FONTSIZE(edit) != 22); // Sanity check to make sure this test makes sense.
676     edit.setStyleSheet("QLineEdit { font-size: 22pt; }");
677     QCOMPARE(FONTSIZE(edit), 22);
678     font.setPointSize(16);
679     edit.setFont(font);
680     QCOMPARE(FONTSIZE(edit), 22);
681     edit.setStyleSheet("");
682     QCOMPARE(FONTSIZE(edit), 16);
683     font.setPointSize(18);
684     edit.setFont(font);
685     QCOMPARE(FONTSIZE(edit), 18);
686     edit.setStyleSheet("QLineEdit { font-size: 20pt; }");
687     QCOMPARE(FONTSIZE(edit), 20);
688     edit.setStyleSheet("");
689     QCOMPARE(FONTSIZE(edit), 18);
690     edit.hide();
691
692     QLineEdit edit2;
693     edit2.setReadOnly(true);
694     edit2.setStyleSheet("QLineEdit { font-size: 24pt; } QLineEdit:read-only { font-size: 26pt; }");
695     QCOMPARE(FONTSIZE(edit2), 26);
696 }
697
698 // Ensure primary will only return true if the color covers more than 50% of pixels
699 static bool testForColors(const QImage& image, const QColor& color, bool ensurePrimary=false)
700 {
701     int count = 0;
702     QRgb rgb = color.rgba();
703     int totalCount = image.height()*image.width();
704     for (int y = 0; y < image.height(); ++y) {
705         for (int x = 0; x < image.width(); ++x) {
706             // Because of antialiasing we allow a certain range of errors here.
707             QRgb pixel = image.pixel(x, y);
708
709             if (qAbs((int)(pixel & 0xff) - (int)(rgb & 0xff)) +
710                     qAbs((int)((pixel & 0xff00) >> 8) - (int)((rgb & 0xff00) >> 8)) +
711                     qAbs((int)((pixel & 0xff0000) >> 16) - (int)((rgb & 0xff0000) >> 16)) <= 50) {
712                 count++;
713                 if (!ensurePrimary && count >=10 )
714                     return true;
715                 else if (count > totalCount/2)
716                     return true;
717             }
718         }
719     }
720
721     return false;
722 }
723
724 void tst_QStyleSheetStyle::focusColors()
725 {
726     // Tests if colors can be changed by altering the focus of the widget.
727     // To avoid messy pixel-by-pixel comparison, we assume that the goal
728     // is reached if at least ten pixels of the right color can be found in
729     // the image.
730     // For this reason, we use unusual and extremely ugly colors! :-)
731     // Note that in case of anti-aliased text, ensuring that we have at least
732     // ten pixels of the right color requires quite a many characters, as the
733     // majority of the pixels will have slightly different colors due to the
734     // anti-aliasing effect.
735 #if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) && !(defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(Q_CC_INTEL))
736     QSKIP("This is a fragile test which fails on many esoteric platforms because of focus problems. "
737           "That doesn't mean that the feature doesn't work in practice.");
738 #endif
739     QList<QWidget *> widgets;
740     widgets << new QPushButton("TESTING TESTING");
741     widgets << new QLineEdit("TESTING TESTING");
742     widgets << new QLabel("TESTING TESTING");
743     QSpinBox *spinbox = new QSpinBox;
744     spinbox->setMaximum(1000000000);
745     spinbox->setValue(123456789);
746     widgets << spinbox;
747     QComboBox *combobox = new QComboBox;
748     combobox->setEditable(true);
749     combobox->addItems(QStringList() << "TESTING TESTING");
750     widgets << combobox;
751     widgets << new QLabel("TESTING TESTING");
752
753 #ifdef Q_WS_QWS
754     // QWS has its own special focus logic which is slightly different
755     // and I don't dare change it at this point, because someone will
756     // be relying on it. It means that setFocus() on a NoFocus widget (i.e.
757     // a QLabel) will not work before the window is activated.
758     widgets[2]->setFocusPolicy(Qt::StrongFocus);
759 #endif
760
761     foreach (QWidget *widget, widgets) {
762         QDialog frame;
763         QLayout* layout = new QGridLayout;
764
765         QLineEdit* dummy = new QLineEdit; // Avoids initial focus.
766
767         widget->setStyleSheet("*:focus { border:none; background: #e8ff66; color: #ff0084 }");
768
769         layout->addWidget(dummy);
770         layout->addWidget(widget);
771         frame.setLayout(layout);
772
773         frame.show();
774         QApplication::setActiveWindow(&frame);
775         QVERIFY(QTest::qWaitForWindowActive(&frame));
776         widget->setFocus();
777         QApplication::processEvents();
778
779         QImage image(frame.width(), frame.height(), QImage::Format_ARGB32);
780         frame.render(&image);
781         if (image.depth() < 24)
782             QSKIP("Test doesn't support color depth < 24");
783
784         QVERIFY2(testForColors(image, QColor(0xe8, 0xff, 0x66)),
785                 (QString::fromLatin1(widget->metaObject()->className())
786                 + " did not contain background color #e8ff66, using style "
787                 + QString::fromLatin1(qApp->style()->metaObject()->className()))
788                 .toLocal8Bit().constData());
789         QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)),
790                 (QString::fromLatin1(widget->metaObject()->className())
791                 + " did not contain text color #ff0084, using style "
792                 + QString::fromLatin1(qApp->style()->metaObject()->className()))
793                 .toLocal8Bit().constData());
794     }
795 }
796
797 void tst_QStyleSheetStyle::hoverColors()
798 {
799     if (!PlatformQuirks::haveMouseCursor())
800         QSKIP("No mouse Cursor on this platform");
801     QList<QWidget *> widgets;
802     widgets << new QPushButton("TESTING TESTING");
803     widgets << new QLineEdit("TESTING TESTING");
804     widgets << new QLabel("TESTING TESTING");
805     QSpinBox *spinbox = new QSpinBox;
806     spinbox->setMaximum(1000000000);
807     spinbox->setValue(123456789);
808     widgets << spinbox;
809     QComboBox *combobox = new QComboBox;
810     combobox->setEditable(true);
811     combobox->addItems(QStringList() << "TESTING TESTING");
812     widgets << combobox;
813     widgets << new QLabel("<b>TESTING TESTING</b>");
814
815     foreach (QWidget *widget, widgets) {
816         //without Qt::X11BypassWindowManagerHint the window manager may move the window after we moved the cursor
817         QDialog frame(0, Qt::X11BypassWindowManagerHint);
818         QLayout* layout = new QGridLayout;
819
820         QLineEdit* dummy = new QLineEdit;
821
822         widget->setStyleSheet("*:hover { border:none; background: #e8ff66; color: #ff0084 }");
823
824         layout->addWidget(dummy);
825         layout->addWidget(widget);
826         frame.setLayout(layout);
827
828         frame.show();
829 #ifdef Q_WS_QWS
830 //QWS does not implement enter/leave when windows are shown underneath the cursor
831         QCursor::setPos(QPoint(0,0));
832 #endif
833
834         QApplication::setActiveWindow(&frame);
835         QVERIFY(QTest::qWaitForWindowActive(&frame));
836         //move the mouse inside the widget, it should be colored
837         QTest::mouseMove ( widget, QPoint(6,6));
838         QTest::qWait(60);
839
840 #ifdef Q_OS_MAC
841     QEXPECT_FAIL("", "Numerous failures related to Qt::WA_UnderMouse, see QTBUGT-23685", Continue);
842 #endif
843         QVERIFY(widget->testAttribute(Qt::WA_UnderMouse));
844
845         QImage image(frame.width(), frame.height(), QImage::Format_ARGB32);
846         frame.render(&image);
847
848 #ifdef Q_OS_MAC
849     QEXPECT_FAIL("", "Numerous failures related to Qt::WA_UnderMouse, see QTBUGT-23685", Continue);
850 #endif
851         QVERIFY2(testForColors(image, QColor(0xe8, 0xff, 0x66)),
852                   (QString::fromLatin1(widget->metaObject()->className())
853                   + " did not contain background color #e8ff66").toLocal8Bit().constData());
854 #ifdef Q_OS_MAC
855     QEXPECT_FAIL("", "Numerous failures related to Qt::WA_UnderMouse, see QTBUGT-23685", Continue);
856 #endif
857         QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)),
858                  (QString::fromLatin1(widget->metaObject()->className())
859                   + " did not contain text color #ff0084").toLocal8Bit().constData());
860
861         //move the mouse outside the widget, it should NOT be colored
862         QTest::mouseMove ( dummy, QPoint(5,5));
863         QTest::qWait(60);
864
865         frame.render(&image);
866
867         QVERIFY2(!testForColors(image, QColor(0xe8, 0xff, 0x66)),
868                   (QString::fromLatin1(widget->metaObject()->className())
869                   + " did contain background color #e8ff66").toLocal8Bit().constData());
870         QVERIFY2(!testForColors(image, QColor(0xff, 0x00, 0x84)),
871                  (QString::fromLatin1(widget->metaObject()->className())
872                   + " did contain text color #ff0084").toLocal8Bit().constData());
873
874         //move the mouse again inside the widget, it should be colored
875         QTest::mouseMove (widget, QPoint(5,5));
876         QTest::qWait(60);
877
878         QVERIFY(widget->testAttribute(Qt::WA_UnderMouse));
879
880         frame.render(&image);
881
882         QVERIFY2(testForColors(image, QColor(0xe8, 0xff, 0x66)),
883                  (QString::fromLatin1(widget->metaObject()->className())
884                  + " did not contain background color #e8ff66").toLocal8Bit().constData());
885 #ifdef Q_OS_MAC
886         if (qobject_cast<QComboBox *>(widget))
887             QEXPECT_FAIL("", "Failure only for QPushButton and QComboBox, see QTBUG-23686", Continue);
888 #endif
889         QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)),
890                 (QString::fromLatin1(widget->metaObject()->className())
891                 + " did not contain text color #ff0084").toLocal8Bit().constData());
892     }
893
894 }
895
896 class SingleInheritanceDialog : public QDialog
897 {
898     Q_OBJECT
899 public:
900     SingleInheritanceDialog(QWidget *w = 0) :
901         QDialog(w)
902     {
903     }
904 };
905
906 class DoubleInheritanceDialog : public SingleInheritanceDialog
907 {
908     Q_OBJECT
909 public:
910     DoubleInheritanceDialog(QWidget *w = 0) :
911         SingleInheritanceDialog(w)
912     {
913     }
914 };
915
916 void tst_QStyleSheetStyle::background()
917 {
918     const int number = 4;
919     QWidget* widgets[number];
920     // Testing inheritance styling of QDialog.
921     widgets[0] = new SingleInheritanceDialog;
922     widgets[0]->setStyleSheet("* { background-color: #e8ff66; }");
923     widgets[1] = new DoubleInheritanceDialog;
924     widgets[1]->setStyleSheet("* { background-color: #e8ff66; }");
925
926     // Testing gradients in QComboBox.
927     QLayout* layout;
928     QComboBox* cb;
929     // First color
930     widgets[2] = new QDialog;
931     layout = new QGridLayout;
932     cb = new QComboBox;
933     cb->setStyleSheet("* { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop:0 #e8ff66, stop:1 #000000); }");
934     layout->addWidget(cb);
935     widgets[2]->setLayout(layout);
936     // Second color
937     widgets[3] = new QDialog;
938     layout = new QGridLayout;
939     cb = new QComboBox;
940     cb->setStyleSheet("* { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop:0 #e8ff66, stop:1 #000000); }");
941     layout->addWidget(cb);
942     widgets[3]->setLayout(layout);
943
944     for (int c = 0; c < number; ++c) {
945         QWidget* widget = widgets[c];
946
947         widget->show();
948         QVERIFY(QTest::qWaitForWindowExposed(widget));
949
950         QImage image(widget->width(), widget->height(), QImage::Format_ARGB32);
951         widget->render(&image);
952         if (image.depth() < 24)
953             QSKIP("Test doesn't support color depth < 24");
954
955         QVERIFY2(testForColors(image, QColor(0xe8, 0xff, 0x66)),
956                 (QString::fromLatin1(widget->metaObject()->className())
957                 + " did not contain background image with color #e8ff66")
958                 .toLocal8Bit().constData());
959
960         delete widget;
961     }
962 }
963
964 void tst_QStyleSheetStyle::tabAlignement()
965 {
966     QWidget topLevel;
967     QTabWidget tabWidget(&topLevel);
968     tabWidget.addTab(new QLabel("tab1"),"tab1");
969     tabWidget.resize(QSize(400,400));
970     topLevel.show();
971     QVERIFY(QTest::qWaitForWindowExposed(&topLevel));
972     QTabBar *bar = qFindChild<QTabBar*>(&tabWidget);
973     QVERIFY(bar);
974     //check the tab is on the right
975     tabWidget.setStyleSheet("QTabWidget::tab-bar { alignment: right ; }");
976     qApp->processEvents();
977     QVERIFY(bar->geometry().right() > 380);
978     QVERIFY(bar->geometry().left() > 200);
979     //check the tab is on the middle
980     tabWidget.setStyleSheet("QTabWidget::tab-bar { alignment: center ; }");
981     QVERIFY(bar->geometry().right() < 300);
982     QVERIFY(bar->geometry().left() > 100);
983     //check the tab is on the left
984     tabWidget.setStyleSheet("QTabWidget::tab-bar { alignment: left ; }");
985     QVERIFY(bar->geometry().left() < 20);
986     QVERIFY(bar->geometry().right() < 200);
987
988     tabWidget.setTabPosition(QTabWidget::West);
989     //check the tab is on the top
990     QVERIFY(bar->geometry().top() < 20);
991     QVERIFY(bar->geometry().bottom() < 200);
992     //check the tab is on the bottom
993     tabWidget.setStyleSheet("QTabWidget::tab-bar { alignment: right ; }");
994     QVERIFY(bar->geometry().bottom() > 380);
995     QVERIFY(bar->geometry().top() > 200);
996     //check the tab is on the middle
997     tabWidget.setStyleSheet("QTabWidget::tab-bar { alignment: center ; }");
998     QVERIFY(bar->geometry().bottom() < 300);
999     QVERIFY(bar->geometry().top() > 100);
1000 }
1001
1002 void tst_QStyleSheetStyle::attributesList()
1003 {
1004     QWidget w;
1005     QPushButton *p1=new QPushButton(&w);
1006     QPushButton *p2=new QPushButton(&w);
1007     QPushButton *p3=new QPushButton(&w);
1008     QPushButton *p4=new QPushButton(&w);
1009     p1->setProperty("prop", QStringList() << "red");
1010     p2->setProperty("prop", QStringList() << "foo" << "red");
1011     p3->setProperty("prop", QStringList() << "foo" << "bar");
1012
1013     w.setStyleSheet(" QPushButton{ background-color:blue; }  QPushButton[prop~=red] { background-color:red; }");
1014     QCOMPARE(BACKGROUND(*p1) , QColor("red"));
1015     QCOMPARE(BACKGROUND(*p2) , QColor("red"));
1016     QCOMPARE(BACKGROUND(*p3) , QColor("blue"));
1017     QCOMPARE(BACKGROUND(*p4) , QColor("blue"));
1018 }
1019
1020 void tst_QStyleSheetStyle::minmaxSizes()
1021 {
1022     QTabWidget tabWidget;
1023     tabWidget.setObjectName("tabWidget");
1024     int index1 = tabWidget.addTab(new QLabel("Tab1"),"a");
1025
1026     QWidget *page2=new QLabel("page2");
1027     page2->setObjectName("page2");
1028     page2->setStyleSheet("* {background-color: white; min-width: 250px; max-width:500px }");
1029     tabWidget.addTab(page2,"Tab2");
1030     QWidget *page3=new QLabel("plop");
1031     page3->setObjectName("Page3");
1032     page3->setStyleSheet("* {background-color: yellow; min-height: 250px; max-height:500px }");
1033     int index3 = tabWidget.addTab(page3,"very_long_long_long_long_caption");
1034
1035     tabWidget.setStyleSheet("QTabBar::tab { min-width:100px; max-width:130px; }");
1036
1037     tabWidget.show();
1038     QTest::qWait(50);
1039     //i allow 4px additional border from the native style (hence the -2, <=2)
1040     QVERIFY(qAbs(page2->maximumSize().width() - 500 - 2) <= 2);
1041     QVERIFY(qAbs(page2->minimumSize().width() - 250 - 2) <= 2);
1042     QVERIFY(qAbs(page3->maximumSize().height() - 500 - 2) <= 2);
1043     QVERIFY(qAbs(page3->minimumSize().height() - 250 - 2) <= 2);
1044     QVERIFY(qAbs(page3->minimumSize().height() - 250 - 2) <= 2);
1045     QTabBar *bar = qFindChild<QTabBar*>(&tabWidget);
1046     QVERIFY(bar);
1047 #ifdef Q_OS_MAC
1048     QEXPECT_FAIL("", "QTBUG-23686", Continue);
1049 #endif
1050     QVERIFY(qAbs(bar->tabRect(index1).width() - 100 - 2) <= 2);
1051 #ifdef Q_OS_MAC
1052     QEXPECT_FAIL("", "QTBUG-23686", Continue);
1053 #endif
1054     QVERIFY(qAbs(bar->tabRect(index3).width() - 130 - 2) <= 2);
1055 }
1056
1057 void tst_QStyleSheetStyle::task206238_twice()
1058 {
1059     QMainWindow w;
1060     QTabWidget* tw = new QTabWidget;
1061     tw->addTab(new QLabel("foo"), "test");
1062     w.setCentralWidget(tw);
1063     w.setStyleSheet("background: red;");
1064     w.show();
1065     QTest::qWait(20);
1066     QCOMPARE(BACKGROUND(w) , QColor("red"));
1067     QCOMPARE(BACKGROUND(*tw), QColor("red"));
1068     w.setStyleSheet("background: red;");
1069     QTest::qWait(20);
1070     QCOMPARE(BACKGROUND(w) , QColor("red"));
1071     QCOMPARE(BACKGROUND(*tw), QColor("red"));
1072 }
1073
1074 void tst_QStyleSheetStyle::transparent()
1075 {
1076     QWidget w;
1077     QPushButton *p1=new QPushButton(&w);
1078     QPushButton *p2=new QPushButton(&w);
1079     QPushButton *p3=new QPushButton(&w);
1080     p1->setStyleSheet("background:transparent");
1081     p2->setStyleSheet("background-color:transparent");
1082     p3->setStyleSheet("background:rgb(0,0,0,0)");
1083     QCOMPARE(BACKGROUND(*p1) , QColor(0,0,0,0));
1084     QCOMPARE(BACKGROUND(*p2) , QColor(0,0,0,0));
1085     QCOMPARE(BACKGROUND(*p3) , QColor(0,0,0,0));
1086 }
1087
1088
1089
1090 class ProxyStyle : public QStyle
1091 {
1092     public:
1093         ProxyStyle(QStyle *s)
1094         {
1095             style = s;
1096         }
1097
1098         void drawControl(ControlElement ce, const QStyleOption *opt,
1099                          QPainter *painter, const QWidget *widget = 0) const;
1100
1101         void drawPrimitive(QStyle::PrimitiveElement pe,
1102                            const QStyleOption* opt,
1103                            QPainter* p ,
1104                            const QWidget* w) const
1105         {
1106             style->drawPrimitive(pe, opt, p, w);
1107         }
1108
1109         QRect subElementRect(QStyle::SubElement se,
1110                              const QStyleOption* opt,
1111                              const QWidget* w) const
1112         {
1113             Q_UNUSED(se);
1114             Q_UNUSED(opt);
1115             Q_UNUSED(w);
1116             return QRect(0, 0, 3, 3);
1117         }
1118
1119         void drawComplexControl(QStyle::ComplexControl cc,
1120                                 const QStyleOptionComplex* opt,
1121                                 QPainter* p,
1122                                 const QWidget* w) const
1123         {
1124             style->drawComplexControl(cc, opt, p, w);
1125         }
1126
1127
1128         SubControl hitTestComplexControl(QStyle::ComplexControl cc,
1129                                          const QStyleOptionComplex* opt,
1130                                          const QPoint& pt,
1131                                          const QWidget* w) const
1132         {
1133             return style->hitTestComplexControl(cc, opt, pt, w);
1134         }
1135
1136         QRect subControlRect(QStyle::ComplexControl cc,
1137                              const QStyleOptionComplex* opt,
1138                              QStyle::SubControl sc,
1139                              const QWidget* w) const
1140         {
1141             return style->subControlRect(cc, opt, sc, w);
1142         }
1143
1144         int pixelMetric(QStyle::PixelMetric pm,
1145                         const QStyleOption* opt,
1146                         const QWidget* w) const
1147         {
1148             return style->pixelMetric(pm, opt, w);
1149         }
1150
1151
1152         QSize sizeFromContents(QStyle::ContentsType ct,
1153                                const QStyleOption* opt,
1154                                const QSize& size,
1155                                const QWidget* w) const
1156         {
1157             return style->sizeFromContents(ct, opt, size, w);
1158         }
1159
1160         int styleHint(QStyle::StyleHint sh,
1161                       const QStyleOption* opt,
1162                       const QWidget* w,
1163                       QStyleHintReturn* shr) const
1164         {
1165             return style->styleHint(sh, opt, w, shr);
1166         }
1167
1168         QPixmap standardPixmap(QStyle::StandardPixmap spix,
1169                                const QStyleOption* opt,
1170                                const QWidget* w) const
1171         {
1172             return style->standardPixmap(spix, opt, w);
1173         }
1174
1175         QPixmap generatedIconPixmap(QIcon::Mode mode,
1176                                     const QPixmap& pix,
1177                                     const QStyleOption* opt) const
1178         {
1179             return style->generatedIconPixmap(mode, pix, opt);
1180         }
1181
1182     private:
1183         QStyle *style;
1184 };
1185
1186 void ProxyStyle::drawControl(ControlElement ce, const QStyleOption *opt,
1187                              QPainter *painter, const QWidget *widget) const
1188 {
1189     if(ce == CE_PushButton)
1190     {
1191         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt))
1192         {
1193             QRect r = btn->rect;
1194             painter->fillRect(r, Qt::green);
1195
1196             if(btn->state & QStyle::State_HasFocus)
1197                 painter->fillRect(r.adjusted(5, 5, -5, -5), Qt::yellow);
1198
1199
1200             painter->drawText(r, Qt::AlignCenter, btn->text);
1201         }
1202     }
1203     else
1204     {
1205         style->drawControl(ce, opt, painter, widget);
1206     }
1207 }
1208
1209 void tst_QStyleSheetStyle::proxyStyle()
1210 {
1211     //Should not crash;   task 158984
1212
1213     ProxyStyle *proxy = new ProxyStyle(qApp->style());
1214     QString styleSheet("QPushButton {background-color: red; }");
1215
1216     QWidget *w = new QWidget;
1217     QVBoxLayout *layout = new QVBoxLayout(w);
1218
1219     QPushButton *pb1 = new QPushButton(qApp->style()->objectName(), w);
1220     layout->addWidget(pb1);
1221
1222     QPushButton *pb2 = new QPushButton("ProxyStyle", w);
1223     pb2->setStyle(proxy);
1224     layout->addWidget(pb2);
1225
1226     QPushButton *pb3 = new QPushButton("StyleSheet", w);
1227     pb3->setStyleSheet(styleSheet);
1228     layout->addWidget(pb3);
1229
1230     QPushButton *pb4 = new QPushButton("StyleSheet then ProxyStyle ", w);
1231     pb4->setStyleSheet(styleSheet);
1232
1233     // We are creating our Proxy based on current style...
1234     // In this case it would be the QStyleSheetStyle that is deleted
1235     // later on. We need to get access to the "real" QStyle to be able to
1236     // draw correctly.
1237     ProxyStyle* newProxy = new ProxyStyle(qApp->style());
1238     pb4->setStyle(newProxy);
1239
1240     layout->addWidget(pb4);
1241
1242     QPushButton *pb5 = new QPushButton("ProxyStyle then StyleSheet ", w);
1243     pb5->setStyle(proxy);
1244     pb5->setStyleSheet(styleSheet);
1245     layout->addWidget(pb5);
1246
1247     w->show();
1248
1249     QTest::qWait(100);
1250
1251     // Test for QTBUG-7198 - style sheet overrides custom element size
1252     QStyleOptionViewItemV4 opt;
1253     opt.initFrom(w);
1254     opt.features |= QStyleOptionViewItemV2::HasCheckIndicator;
1255     QVERIFY(pb5->style()->subElementRect(QStyle::SE_ItemViewItemCheckIndicator,
1256             &opt, pb5).width() == 3);
1257     delete w;
1258     delete proxy;
1259     delete newProxy;
1260 }
1261
1262 void tst_QStyleSheetStyle::dialogButtonBox()
1263 {
1264     QDialogButtonBox box;
1265     box.addButton(QDialogButtonBox::Ok);
1266     box.addButton(QDialogButtonBox::Cancel);
1267     box.setStyleSheet("/** */ ");
1268     box.setStyleSheet(QString()); //should not crash
1269 }
1270
1271 void tst_QStyleSheetStyle::emptyStyleSheet()
1272 {
1273     //empty stylesheet should not change anything
1274     qApp->setStyleSheet(QString());
1275     QWidget w;
1276     QHBoxLayout layout(&w);
1277     w.setLayout(&layout);
1278     layout.addWidget(new QPushButton("push", &w));
1279     layout.addWidget(new QToolButton(&w));
1280     QLabel label("toto", &w);
1281     label.setFrameShape(QLabel::Panel);
1282     label.setFrameShadow(QLabel::Sunken);
1283     layout.addWidget(&label); //task 231137
1284     layout.addWidget(new QTableWidget(200,200, &w));
1285     layout.addWidget(new QProgressBar(&w));
1286     layout.addWidget(new QLineEdit(&w));
1287     layout.addWidget(new QSpinBox(&w));
1288     layout.addWidget(new QComboBox(&w));
1289     layout.addWidget(new QDateEdit(&w));
1290     layout.addWidget(new QGroupBox("some text", &w));
1291
1292     w.show();
1293     QVERIFY(QTest::qWaitForWindowExposed(&w));
1294     //workaround the fact that the label sizehint is one pixel different the first time.
1295     label.setIndent(0); //force to recompute the sizeHint:
1296     w.setFocus();
1297     QTest::qWait(100);
1298
1299     QImage img1(w.size(), QImage::Format_ARGB32);
1300     w.render(&img1);
1301
1302     w.setStyleSheet("/* */");
1303     QTest::qWait(100);
1304
1305     QImage img2(w.size(), QImage::Format_ARGB32);
1306     w.render(&img2);
1307
1308     if(img1 != img2) {
1309         img1.save("emptyStyleSheet_img1.png");
1310         img2.save("emptyStyleSheet_img2.png");
1311     }
1312
1313     QCOMPARE(img1,img2);
1314 }
1315
1316 void tst_QStyleSheetStyle::toolTip()
1317 {
1318     qApp->setStyleSheet(QString());
1319     QWidget w;
1320     QHBoxLayout layout(&w);
1321     w.setLayout(&layout);
1322
1323     QWidget *wid1 = new QGroupBox(&w);
1324     layout.addWidget(wid1);
1325     wid1->setStyleSheet("QToolTip { background: #ae2; }   #wid3 > QToolTip { background: #0b8; } ");
1326     QVBoxLayout *layout1 = new QVBoxLayout(wid1);
1327     wid1->setLayout(layout1);
1328     wid1->setToolTip("this is wid1");
1329     wid1->setObjectName("wid1");
1330
1331     QWidget *wid2 = new QPushButton("wid2", wid1);
1332     layout1->addWidget(wid2);
1333     wid2->setStyleSheet("QToolTip { background: #f81; } ");
1334     wid2->setToolTip("this is wid2");
1335     wid2->setObjectName("wid2");
1336
1337     QWidget *wid3 = new QPushButton("wid3", wid1);
1338     layout1->addWidget(wid3);
1339     wid3->setToolTip("this is wid3");
1340     wid3->setObjectName("wid3");
1341
1342     QWidget *wid4 = new QPushButton("wid4", &w);
1343     layout.addWidget(wid4);
1344     wid4->setToolTip("this is wid4");
1345     wid4->setObjectName("wid4");
1346
1347     w.show();
1348     qApp->setActiveWindow(&w);
1349     QVERIFY(QTest::qWaitForWindowActive(&w));
1350
1351     QColor normalToolTip = qApp->palette().toolTipBase().color();
1352     QList<QWidget *> widgets;
1353     QList<QColor> colors;
1354
1355
1356     //tooltip on the widget without stylesheet, then to othes widget, including one without stylesheet
1357     //(the tooltip will be reused but his colour must change)
1358     widgets << wid4          << wid1   << wid2   << wid3   << wid4;
1359     colors  << normalToolTip << "#ae2" << "#f81" << "#0b8" << normalToolTip;
1360
1361     for (int i = 0; i < widgets.count() ; i++)
1362     {
1363         QWidget *wid = widgets.at(i);
1364         QColor col = colors.at(i);
1365
1366         QToolTip::showText( QPoint(0,0) , "This is " + wid->objectName(), wid);
1367
1368         QWidget *tooltip = 0;
1369         foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1370             if (widget->inherits("QTipLabel") && widget->isVisible()) {
1371                 tooltip = widget;
1372                 break;
1373             }
1374         }
1375         QVERIFY(tooltip);
1376         QCOMPARE(tooltip->palette().color(tooltip->backgroundRole()), col);
1377     }
1378
1379     QToolTip::showText( QPoint(0,0) , "This is " + wid3->objectName(), wid3);
1380     QTest::qWait(100);
1381     delete wid3; //should not crash;
1382     QTest::qWait(10);
1383     foreach (QWidget *widget, QApplication::topLevelWidgets()) {
1384         widget->update(); //should not crash either
1385     }
1386 }
1387
1388 void tst_QStyleSheetStyle::embeddedFonts()
1389 {
1390     //task 235622 and 210551
1391     QSpinBox spin;
1392     spin.show();
1393     spin.setStyleSheet("QSpinBox { font-size: 32px; }");
1394     QTest::qWait(20);
1395     QLineEdit *embedded = spin.findChild<QLineEdit *>();
1396     QVERIFY(embedded);
1397     QCOMPARE(spin.font().pixelSize(), 32);
1398     QCOMPARE(embedded->font().pixelSize(), 32);
1399
1400     QMenu *menu = embedded->createStandardContextMenu();
1401     menu->show();
1402     QTest::qWait(20);
1403     QVERIFY(menu);
1404     QVERIFY(menu->font().pixelSize() != 32);
1405     QCOMPARE(menu->font().pixelSize(), qApp->font(menu).pixelSize());
1406
1407     //task 242556
1408     QComboBox box;
1409     box.setEditable(true);
1410     box.addItems(QStringList() << "First" << "Second" << "Third");
1411     box.setStyleSheet("QComboBox { font-size: 32px; }");
1412     box.show();
1413     embedded = box.findChild<QLineEdit *>();
1414     QVERIFY(embedded);
1415     QTest::qWait(20);
1416     QCOMPARE(box.font().pixelSize(), 32);
1417     QCOMPARE(embedded->font().pixelSize(), 32);
1418 }
1419
1420 void tst_QStyleSheetStyle::opaquePaintEvent_data()
1421 {
1422     QTest::addColumn<QString>("stylesheet");
1423     QTest::addColumn<bool>("transparent");
1424     QTest::addColumn<bool>("styled");
1425
1426     QTest::newRow("none") << QString::fromLatin1("/* */") << false << false;
1427     QTest::newRow("background black ") << QString::fromLatin1("background: black;") << false << true;
1428     QTest::newRow("background qrgba") << QString::fromLatin1("background: rgba(125,0,0,125);") << true << true;
1429     QTest::newRow("background transparent") << QString::fromLatin1("background: transparent;") << true << true;
1430     QTest::newRow("border native") << QString::fromLatin1("border: native;") << false << false;
1431     QTest::newRow("border solid") << QString::fromLatin1("border: 2px solid black;") << true << true;
1432     QTest::newRow("border transparent") << QString::fromLatin1("background: black; border: 2px solid rgba(125,0,0,125);") << true << true;
1433     QTest::newRow("margin") << QString::fromLatin1("margin: 25px;") << true << true;
1434     QTest::newRow("focus") << QString::fromLatin1("*:focus { background: rgba(125,0,0,125) }") << true << true;
1435 }
1436
1437 void tst_QStyleSheetStyle::opaquePaintEvent()
1438 {
1439     QFETCH(QString, stylesheet);
1440     QFETCH(bool, transparent);
1441     QFETCH(bool, styled);
1442
1443     QWidget tl;
1444     QWidget cl(&tl);
1445     cl.setAttribute(Qt::WA_OpaquePaintEvent, true);
1446     cl.setAutoFillBackground(true);
1447     cl.setStyleSheet(stylesheet);
1448     cl.ensurePolished();
1449     QCOMPARE(cl.testAttribute(Qt::WA_OpaquePaintEvent), !transparent);
1450     QCOMPARE(cl.testAttribute(Qt::WA_StyledBackground), styled);
1451     QCOMPARE(cl.autoFillBackground(), !styled );
1452 }
1453
1454 void tst_QStyleSheetStyle::complexWidgetFocus()
1455 {
1456     // This test is a simplified version of the focusColors() test above.
1457
1458     // Tests if colors can be changed by altering the focus of the widget.
1459     // To avoid messy pixel-by-pixel comparison, we assume that the goal
1460     // is reached if at least ten pixels of the right color can be found in
1461     // the image.
1462     // For this reason, we use unusual and extremely ugly colors! :-)
1463
1464     QDialog frame;
1465     frame.setStyleSheet("*:focus { background: black; color: black } "
1466                         "QSpinBox::up-arrow:focus, QSpinBox::down-arrow:focus { width: 7px; height: 7px; background: #ff0084 } "
1467                         "QComboBox::down-arrow:focus { width: 7px; height: 7px; background: #ff0084 }"
1468                         "QSlider::handle:horizontal:focus { width: 7px; height: 7px; background: #ff0084 } ");
1469
1470     QList<QWidget *> widgets;
1471     widgets << new QSpinBox;
1472     widgets << new QComboBox;
1473     widgets << new QSlider(Qt::Horizontal);
1474
1475     QLayout* layout = new QGridLayout;
1476     layout->addWidget(new QLineEdit); // Avoids initial focus.
1477     foreach (QWidget *widget, widgets)
1478         layout->addWidget(widget);
1479     frame.setLayout(layout);
1480
1481     frame.show();
1482     QApplication::setActiveWindow(&frame);
1483     QVERIFY(QTest::qWaitForWindowActive(&frame));
1484     foreach (QWidget *widget, widgets) {
1485         widget->setFocus();
1486         QApplication::processEvents();
1487
1488         QImage image(frame.width(), frame.height(), QImage::Format_ARGB32);
1489         frame.render(&image);
1490         if (image.depth() < 24)
1491             QSKIP("Test doesn't support color depth < 24");
1492
1493         QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)),
1494                 (QString::fromLatin1(widget->metaObject()->className())
1495                 + " did not contain text color #ff0084, using style "
1496                 + QString::fromLatin1(qApp->style()->metaObject()->className()))
1497                 .toLocal8Bit().constData());
1498     }
1499 }
1500
1501 void tst_QStyleSheetStyle::task188195_baseBackground()
1502 {
1503     QTreeView tree;
1504     tree.setStyleSheet( "QTreeView:disabled { background-color:#ab1251; }" );
1505     tree.show();
1506     QTest::qWait(20);
1507     QImage image(tree.width(), tree.height(), QImage::Format_ARGB32);
1508
1509     tree.render(&image);
1510     QVERIFY(testForColors(image, tree.palette().base().color()));
1511     QVERIFY(!testForColors(image, QColor(0xab, 0x12, 0x51)));
1512
1513     tree.setEnabled(false);
1514     tree.render(&image);
1515     QVERIFY(testForColors(image, QColor(0xab, 0x12, 0x51)));
1516
1517     tree.setEnabled(true);
1518     tree.render(&image);
1519     QVERIFY(testForColors(image, tree.palette().base().color()));
1520     QVERIFY(!testForColors(image, QColor(0xab, 0x12, 0x51)));
1521
1522     QTableWidget table(12, 12);
1523     table.setItem(0, 0, new QTableWidgetItem());
1524     table.setStyleSheet( "QTableView {background-color: #ff0000}" );
1525     table.show();
1526     QTest::qWait(20);
1527     image = QImage(table.width(), table.height(), QImage::Format_ARGB32);
1528     table.render(&image);
1529     QVERIFY(testForColors(image, Qt::red, true));
1530 }
1531
1532 void tst_QStyleSheetStyle::task232085_spinBoxLineEditBg()
1533 {
1534     // This test is a simplified version of the focusColors() test above.
1535
1536     // Tests if colors can be changed by altering the focus of the widget.
1537     // To avoid messy pixel-by-pixel comparison, we assume that the goal
1538     // is reached if at least ten pixels of the right color can be found in
1539     // the image.
1540     // For this reason, we use unusual and extremely ugly colors! :-)
1541
1542     QSpinBox *spinbox = new QSpinBox;
1543     spinbox->setValue(8888);
1544
1545     QDialog frame;
1546     QLayout* layout = new QGridLayout;
1547
1548     QLineEdit* dummy = new QLineEdit; // Avoids initial focus.
1549
1550     // We only want to test the line edit colors.
1551     spinbox->setStyleSheet("QSpinBox:focus { background: #e8ff66; color: #ff0084 } "
1552                            "QSpinBox::up-button, QSpinBox::down-button { background: black; }");
1553
1554     layout->addWidget(dummy);
1555     layout->addWidget(spinbox);
1556     frame.setLayout(layout);
1557
1558     frame.show();
1559     QApplication::setActiveWindow(&frame);
1560     spinbox->setFocus();
1561     QVERIFY(QTest::qWaitForWindowActive(&frame));
1562
1563     QImage image(frame.width(), frame.height(), QImage::Format_ARGB32);
1564     frame.render(&image);
1565     if (image.depth() < 24)
1566         QSKIP("Test doesn't support color depth < 24");
1567
1568     QVERIFY2(testForColors(image, QColor(0xe8, 0xff, 0x66)),
1569             (QString::fromLatin1(spinbox->metaObject()->className())
1570             + " did not contain background color #e8ff66, using style "
1571             + QString::fromLatin1(qApp->style()->metaObject()->className()))
1572             .toLocal8Bit().constData());
1573     QVERIFY2(testForColors(image, QColor(0xff, 0x00, 0x84)),
1574             (QString::fromLatin1(spinbox->metaObject()->className())
1575             + " did not contain text color #ff0084, using style "
1576             + QString::fromLatin1(qApp->style()->metaObject()->className()))
1577             .toLocal8Bit().constData());
1578 }
1579
1580 class ChangeEventWidget : public QWidget
1581 { public:
1582     void changeEvent(QEvent * event)
1583     {
1584         if(event->type() == QEvent::StyleChange) {
1585             static bool recurse = false;
1586             if (!recurse) {
1587                 recurse = true;
1588                 QStyle *style = new QMotifStyle;
1589                 style->setParent(this);
1590                 setStyle(style);
1591                 recurse = false;
1592             }
1593         }
1594         QWidget::changeEvent(event);
1595     }
1596 };
1597
1598 void tst_QStyleSheetStyle::changeStyleInChangeEvent()
1599 {   //must not crash;
1600     ChangeEventWidget wid;
1601     wid.ensurePolished();
1602     wid.setStyleSheet(" /* */ ");
1603     wid.ensurePolished();
1604     wid.setStyleSheet(" /* ** */ ");
1605     wid.ensurePolished();
1606 }
1607
1608 void tst_QStyleSheetStyle::QTBUG11658_cachecrash()
1609 {
1610     //should not crash
1611     class Widget : public QWidget
1612     {
1613     public:
1614         Widget(QWidget *parent = 0)
1615         : QWidget(parent)
1616         {
1617             QVBoxLayout* pLayout = new QVBoxLayout(this);
1618             QCheckBox* pCheckBox = new QCheckBox(this);
1619             pLayout->addWidget(pCheckBox);
1620             setLayout(pLayout);
1621
1622             QString szStyleSheet = QLatin1String("* { color: red; }");
1623             qApp->setStyleSheet(szStyleSheet);
1624             qApp->setStyle(QStyleFactory::create(QLatin1String("Windows")));
1625         }
1626     };
1627
1628     Widget *w = new Widget();
1629     delete w;
1630     w = new Widget();
1631     w->show();
1632
1633     QVERIFY(QTest::qWaitForWindowExposed(w));
1634     delete w;
1635     qApp->setStyleSheet(QString());
1636 }
1637
1638 void tst_QStyleSheetStyle::QTBUG15910_crashNullWidget()
1639 {
1640     struct Widget : QWidget {
1641         virtual void paintEvent(QPaintEvent* ) {
1642             QStyleOption opt;
1643             opt.init(this);
1644             QPainter p(this);
1645             style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, 0);
1646             style()->drawPrimitive(QStyle::PE_Frame, &opt, &p, 0);
1647             style()->drawControl(QStyle::CE_PushButton, &opt, &p, 0);
1648         }
1649     } w;
1650     w.setStyleSheet("* { background-color: white; color:black; border 3px solid yellow }");
1651     w.show();
1652     QVERIFY(QTest::qWaitForWindowExposed(&w));
1653 }
1654
1655
1656 QTEST_MAIN(tst_QStyleSheetStyle)
1657 #include "tst_qstylesheetstyle.moc"
1658