1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Charts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include <QtTest/QtTest>
31#include <tst_definitions.h>
32#include <QtCharts/QChartView>
33#include <QtCharts/QChart>
34#include <QtCharts/QLegend>
35#include <QtCharts/QLegendMarker>
36#include <QtCharts/QPieSlice>
37#include <QtCharts/QPieSeries>
38
39QT_CHARTS_USE_NAMESPACE
40
41class tst_qpieslice : public QObject
42{
43 Q_OBJECT
44
45public slots:
46 void initTestCase();
47 void cleanupTestCase();
48 void init();
49 void cleanup();
50
51private slots:
52 void construction();
53 void changedSignals();
54 void customize();
55 void clickedSignal();
56 void hoverSignal();
57 void pressedSignal();
58 void releasedSignal();
59 void doubleClickedSignal();
60
61private:
62 QList<QPoint> slicePoints(QRectF rect);
63
64private:
65
66};
67
68void tst_qpieslice::initTestCase()
69{
70}
71
72void tst_qpieslice::cleanupTestCase()
73{
74 QTest::qWait(ms: 1); // Allow final deleteLaters to run
75}
76
77void tst_qpieslice::init()
78{
79
80}
81
82void tst_qpieslice::cleanup()
83{
84
85}
86
87void tst_qpieslice::construction()
88{
89 // no params
90 QPieSlice slice1;
91 QCOMPARE(slice1.value(), 0.0);
92 QVERIFY(slice1.label().isEmpty());
93 QVERIFY(!slice1.isLabelVisible());
94 QVERIFY(!slice1.isExploded());
95 QCOMPARE(slice1.pen(), QPen());
96 QCOMPARE(slice1.brush(), QBrush());
97 QCOMPARE(slice1.labelBrush(), QBrush());
98 QCOMPARE(slice1.labelFont(), QFont());
99 QCOMPARE(slice1.labelArmLengthFactor(), 0.15); // default value
100 QCOMPARE(slice1.explodeDistanceFactor(), 0.15); // default value
101 QCOMPARE(slice1.percentage(), 0.0);
102 QCOMPARE(slice1.startAngle(), 0.0);
103 QCOMPARE(slice1.angleSpan(), 0.0);
104
105 // value and label params
106 QPieSlice slice2("foobar", 1.0);
107 QCOMPARE(slice2.value(), 1.0);
108 QCOMPARE(slice2.label(), QString("foobar"));
109 QVERIFY(!slice2.isLabelVisible());
110 QVERIFY(!slice2.isExploded());
111 QCOMPARE(slice2.pen(), QPen());
112 QCOMPARE(slice2.brush(), QBrush());
113 QCOMPARE(slice2.labelBrush(), QBrush());
114 QCOMPARE(slice2.labelFont(), QFont());
115 QCOMPARE(slice2.labelArmLengthFactor(), 0.15); // default value
116 QCOMPARE(slice2.explodeDistanceFactor(), 0.15); // default value
117 QCOMPARE(slice2.percentage(), 0.0);
118 QCOMPARE(slice2.startAngle(), 0.0);
119 QCOMPARE(slice2.angleSpan(), 0.0);
120}
121
122void tst_qpieslice::changedSignals()
123{
124 QPieSlice slice;
125
126 QSignalSpy valueSpy(&slice, SIGNAL(valueChanged()));
127 QSignalSpy labelSpy(&slice, SIGNAL(labelChanged()));
128 QSignalSpy penSpy(&slice, SIGNAL(penChanged()));
129 QSignalSpy brushSpy(&slice, SIGNAL(brushChanged()));
130 QSignalSpy labelBrushSpy(&slice, SIGNAL(labelBrushChanged()));
131 QSignalSpy labelFontSpy(&slice, SIGNAL(labelFontChanged()));
132 QSignalSpy colorSpy(&slice, SIGNAL(colorChanged()));
133 QSignalSpy borderColorSpy(&slice, SIGNAL(borderColorChanged()));
134 QSignalSpy borderWidthSpy(&slice, SIGNAL(borderWidthChanged()));
135 QSignalSpy labelColorSpy(&slice, SIGNAL(labelColorChanged()));
136
137 // percentageChanged(), startAngleChanged() and angleSpanChanged() signals tested at tst_qpieseries::calculatedValues()
138
139 // set everything twice to see we do not get unnecessary signals
140 slice.setValue(1.0);
141 slice.setValue(-1.0);
142 QCOMPARE(slice.value(), 1.0);
143 slice.setLabel("foobar");
144 slice.setLabel("foobar");
145 slice.setLabelVisible();
146 slice.setLabelVisible();
147 slice.setExploded();
148 slice.setExploded();
149 slice.setPen(QPen(Qt::red));
150 slice.setPen(QPen(QBrush(Qt::red), 3));
151 slice.setBrush(QBrush(Qt::red));
152 slice.setBrush(QBrush(Qt::red));
153 slice.setLabelBrush(QBrush(Qt::green));
154 slice.setLabelBrush(QBrush(Qt::green));
155 slice.setLabelFont(QFont("Tahoma"));
156 slice.setLabelFont(QFont("Tahoma"));
157 slice.setLabelPosition(QPieSlice::LabelInsideHorizontal);
158 slice.setLabelPosition(QPieSlice::LabelInsideHorizontal);
159 slice.setLabelArmLengthFactor(0.1);
160 slice.setLabelArmLengthFactor(0.1);
161 slice.setExplodeDistanceFactor(0.1);
162 slice.setExplodeDistanceFactor(0.1);
163
164 TRY_COMPARE(valueSpy.count(), 1);
165 TRY_COMPARE(labelSpy.count(), 1);
166 TRY_COMPARE(penSpy.count(), 2);
167 TRY_COMPARE(brushSpy.count(), 1);
168 TRY_COMPARE(labelBrushSpy.count(), 1);
169 TRY_COMPARE(labelFontSpy.count(), 1);
170 TRY_COMPARE(colorSpy.count(), 1);
171 TRY_COMPARE(borderColorSpy.count(), 1);
172 TRY_COMPARE(borderWidthSpy.count(), 1);
173 TRY_COMPARE(labelColorSpy.count(), 1);
174}
175
176void tst_qpieslice::customize()
177{
178 // create a pie series
179 QPieSeries *series = new QPieSeries();
180 QPieSlice *s1 = series->append(label: "slice 1", value: 1);
181 QPieSlice *s2 = series->append(label: "slice 2", value: 2);
182 series->append(label: "slice 3", value: 3);
183
184 // customize a slice
185 QPen p1(Qt::red);
186 s1->setPen(p1);
187 QBrush b1(Qt::red);
188 s1->setBrush(b1);
189 s1->setLabelBrush(b1);
190 QFont f1("Consolas");
191 s1->setLabelFont(f1);
192
193 // add series to the chart
194 QChartView view(new QChart());
195 view.resize(w: 200, h: 200);
196 view.chart()->addSeries(series);
197 view.show();
198 QVERIFY(QTest::qWaitForWindowExposed(&view));
199 //QTest::qWait(1000);
200
201 // check that customizations persist
202 QCOMPARE(s1->pen(), p1);
203 QCOMPARE(s1->brush(), b1);
204 QCOMPARE(s1->labelBrush(), b1);
205 QCOMPARE(s1->labelFont(), f1);
206
207 // remove a slice
208 series->remove(slice: s2);
209 QCOMPARE(s1->pen(), p1);
210 QCOMPARE(s1->brush(), b1);
211 QCOMPARE(s1->labelBrush(), b1);
212 QCOMPARE(s1->labelFont(), f1);
213
214 // add a slice
215 series->append(label: "slice 4", value: 4);
216 QCOMPARE(s1->pen(), p1);
217 QCOMPARE(s1->brush(), b1);
218 QCOMPARE(s1->labelBrush(), b1);
219 QCOMPARE(s1->labelFont(), f1);
220
221 // insert a slice
222 series->insert(index: 0, slice: new QPieSlice("slice 0", 5));
223 QCOMPARE(s1->pen(), p1);
224 QCOMPARE(s1->brush(), b1);
225 QCOMPARE(s1->labelBrush(), b1);
226 QCOMPARE(s1->labelFont(), f1);
227
228 // QTBUG-62082, verify correct insertion at 0.
229 const QStringList expectedLabels{"slice 0", "slice 1", "slice 3", "slice 4"};
230 const auto legendMarkers = view.chart()->legend()->markers();
231 const int legendMarkersSize = legendMarkers.size();
232 QCOMPARE(legendMarkersSize, expectedLabels.size());
233 for (int m = 0; m < legendMarkersSize; ++m)
234 QCOMPARE(legendMarkers.at(m)->label(), expectedLabels.at(m));
235
236 // change theme
237 // theme will overwrite customizations
238 view.chart()->setTheme(QChart::ChartThemeHighContrast);
239 QVERIFY(s1->pen() != p1);
240 QVERIFY(s1->brush() != b1);
241 QVERIFY(s1->labelBrush() != b1);
242 QVERIFY(s1->labelFont() != f1);
243}
244
245void tst_qpieslice::clickedSignal()
246{
247 // NOTE:
248 // This test is the same as tst_qpieseries::clickedSignal()
249 // Just for different signals.
250
251 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
252
253 // create a pie series
254 QPieSeries *series = new QPieSeries();
255 QPieSlice *s1 = series->append(label: "slice 1", value: 1);
256 QPieSlice *s2 = series->append(label: "slice 2", value: 1);
257 QPieSlice *s3 = series->append(label: "slice 3", value: 1);
258 QPieSlice *s4 = series->append(label: "slice 4", value: 1);
259 QSignalSpy clickSpy1(s1, SIGNAL(clicked()));
260 QSignalSpy clickSpy2(s2, SIGNAL(clicked()));
261 QSignalSpy clickSpy3(s3, SIGNAL(clicked()));
262 QSignalSpy clickSpy4(s4, SIGNAL(clicked()));
263
264 // add series to the chart
265 QChartView view;
266 view.resize(w: 200, h: 200);
267 view.chart()->legend()->setVisible(false);
268 view.chart()->addSeries(series);
269 view.show();
270 QVERIFY(QTest::qWaitForWindowExposed(&view));
271
272 // simulate clicks
273 series->setPieSize(1.0);
274 QRectF pieRect = view.chart()->plotArea();
275 QList<QPoint> points = slicePoints(rect: pieRect);
276 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 0));
277 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 1));
278 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 2));
279 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 3));
280 QCOMPARE(clickSpy1.count(), 1);
281 QCOMPARE(clickSpy2.count(), 1);
282 QCOMPARE(clickSpy3.count(), 1);
283 QCOMPARE(clickSpy4.count(), 1);
284}
285
286void tst_qpieslice::hoverSignal()
287{
288 // NOTE:
289 // This test is the same as tst_qpieseries::hoverSignal()
290 // Just for different signals.
291
292 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
293 SKIP_IF_FLAKY_MOUSE_MOVE();
294
295 // add some slices
296 QPieSeries *series = new QPieSeries();
297 QPieSlice *s1 = series->append(label: "slice 1", value: 1);
298 QPieSlice *s2 = series->append(label: "slice 2", value: 1);
299 QPieSlice *s3 = series->append(label: "slice 3", value: 1);
300 QPieSlice *s4 = series->append(label: "slice 4", value: 1);
301
302 // add series to the chart
303 QChartView view;
304 view.resize(w: 200, h: 200);
305 view.chart()->legend()->setVisible(false);
306 view.chart()->addSeries(series);
307 view.show();
308 QVERIFY(QTest::qWaitForWindowExposed(&view));
309
310 // try to ensure focus
311 QApplication::setActiveWindow(&view);
312 view.setFocus();
313 QApplication::processEvents();
314 QVERIFY(view.isActiveWindow());
315 QVERIFY(view.hasFocus());
316
317 // move inside the slices
318 series->setPieSize(1.0);
319 QRectF pieRect = view.chart()->plotArea();
320 QList<QPoint> points = slicePoints(rect: pieRect);
321 QTest::mouseMove(widget: view.viewport(), pos: pieRect.topRight().toPoint(), delay: 100);
322 QSignalSpy hoverSpy1(s1, SIGNAL(hovered(bool)));
323 QSignalSpy hoverSpy2(s2, SIGNAL(hovered(bool)));
324 QSignalSpy hoverSpy3(s3, SIGNAL(hovered(bool)));
325 QSignalSpy hoverSpy4(s4, SIGNAL(hovered(bool)));
326 QTest::mouseMove(widget: view.viewport(), pos: points.at(i: 0), delay: 100);
327 QTest::mouseMove(widget: view.viewport(), pos: points.at(i: 1), delay: 100);
328 QTest::mouseMove(widget: view.viewport(), pos: points.at(i: 2), delay: 100);
329 QTest::mouseMove(widget: view.viewport(), pos: points.at(i: 3), delay: 100);
330 QTest::mouseMove(widget: view.viewport(), pos: pieRect.topLeft().toPoint(), delay: 100);
331 // Final hoverevent can take few milliseconds to appear in some environments, so wait a bit
332 QTest::qWait(ms: 100);
333
334 // check
335 QCOMPARE(hoverSpy1.count(), 2);
336 QCOMPARE(qvariant_cast<bool>(hoverSpy1.at(0).at(0)), true);
337 QCOMPARE(qvariant_cast<bool>(hoverSpy1.at(1).at(0)), false);
338 QCOMPARE(hoverSpy2.count(), 2);
339 QCOMPARE(qvariant_cast<bool>(hoverSpy2.at(0).at(0)), true);
340 QCOMPARE(qvariant_cast<bool>(hoverSpy2.at(1).at(0)), false);
341 QCOMPARE(hoverSpy3.count(), 2);
342 QCOMPARE(qvariant_cast<bool>(hoverSpy3.at(0).at(0)), true);
343 QCOMPARE(qvariant_cast<bool>(hoverSpy3.at(1).at(0)), false);
344 QCOMPARE(hoverSpy4.count(), 2);
345 QCOMPARE(qvariant_cast<bool>(hoverSpy4.at(0).at(0)), true);
346 QCOMPARE(qvariant_cast<bool>(hoverSpy4.at(1).at(0)), false);
347}
348
349QList<QPoint> tst_qpieslice::slicePoints(QRectF rect)
350{
351 qreal x1 = rect.topLeft().x() + (rect.width() / 4);
352 qreal x2 = rect.topLeft().x() + (rect.width() / 4) * 3;
353 qreal y1 = rect.topLeft().y() + (rect.height() / 4);
354 qreal y2 = rect.topLeft().y() + (rect.height() / 4) * 3;
355 QList<QPoint> points;
356 points << QPoint(x2, y1);
357 points << QPoint(x2, y2);
358 points << QPoint(x1, y2);
359 points << QPoint(x1, y1);
360 return points;
361}
362
363void tst_qpieslice::pressedSignal()
364{
365 // NOTE:
366 // This test is the same as tst_qpieseries::pressedSignal()
367 // Just for different signals.
368
369 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
370
371 // create a pie series
372 QPieSeries *series = new QPieSeries();
373 QPieSlice *s1 = series->append(label: "slice 1", value: 1);
374 QPieSlice *s2 = series->append(label: "slice 2", value: 1);
375 QPieSlice *s3 = series->append(label: "slice 3", value: 1);
376 QPieSlice *s4 = series->append(label: "slice 4", value: 1);
377 QSignalSpy clickSpy1(s1, SIGNAL(pressed()));
378 QSignalSpy clickSpy2(s2, SIGNAL(pressed()));
379 QSignalSpy clickSpy3(s3, SIGNAL(pressed()));
380 QSignalSpy clickSpy4(s4, SIGNAL(pressed()));
381
382 // add series to the chart
383 QChartView view;
384 view.resize(w: 200, h: 200);
385 view.chart()->legend()->setVisible(false);
386 view.chart()->addSeries(series);
387 view.show();
388 QVERIFY(QTest::qWaitForWindowExposed(&view));
389
390 // simulate clicks
391 series->setPieSize(1.0);
392 QRectF pieRect = view.chart()->plotArea();
393 QList<QPoint> points = slicePoints(rect: pieRect);
394 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 0));
395 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 1));
396 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 2));
397 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 3));
398 QCOMPARE(clickSpy1.count(), 1);
399 QCOMPARE(clickSpy2.count(), 1);
400 QCOMPARE(clickSpy3.count(), 1);
401 QCOMPARE(clickSpy4.count(), 1);
402}
403
404void tst_qpieslice::releasedSignal()
405{
406 // NOTE:
407 // This test is the same as tst_qpieseries::releasedSignal()
408 // Just for different signals.
409
410 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
411
412 // create a pie series
413 QPieSeries *series = new QPieSeries();
414 QPieSlice *s1 = series->append(label: "slice 1", value: 1);
415 QPieSlice *s2 = series->append(label: "slice 2", value: 1);
416 QPieSlice *s3 = series->append(label: "slice 3", value: 1);
417 QPieSlice *s4 = series->append(label: "slice 4", value: 1);
418 QSignalSpy clickSpy1(s1, SIGNAL(released()));
419 QSignalSpy clickSpy2(s2, SIGNAL(released()));
420 QSignalSpy clickSpy3(s3, SIGNAL(released()));
421 QSignalSpy clickSpy4(s4, SIGNAL(released()));
422
423 // add series to the chart
424 QChartView view;
425 view.resize(w: 200, h: 200);
426 view.chart()->legend()->setVisible(false);
427 view.chart()->addSeries(series);
428 view.show();
429 QVERIFY(QTest::qWaitForWindowExposed(&view));
430
431 // simulate clicks
432 series->setPieSize(1.0);
433 QRectF pieRect = view.chart()->plotArea();
434 QList<QPoint> points = slicePoints(rect: pieRect);
435 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 0));
436 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 1));
437 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 2));
438 QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 3));
439 QCOMPARE(clickSpy1.count(), 1);
440 QCOMPARE(clickSpy2.count(), 1);
441 QCOMPARE(clickSpy3.count(), 1);
442 QCOMPARE(clickSpy4.count(), 1);
443}
444
445void tst_qpieslice::doubleClickedSignal()
446{
447 // NOTE:
448 // This test is the same as tst_qpieseries::doubleClickedSignal()
449 // Just for different signals.
450
451 SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
452
453 // create a pie series
454 QPieSeries *series = new QPieSeries();
455 QPieSlice *s1 = series->append(label: "slice 1", value: 1);
456 QSignalSpy clickSpy1(s1, SIGNAL(doubleClicked()));
457
458 // add series to the chart
459 QChartView view;
460 view.resize(w: 200, h: 200);
461 view.chart()->legend()->setVisible(false);
462 view.chart()->addSeries(series);
463 view.show();
464 QVERIFY(QTest::qWaitForWindowExposed(&view));
465
466 // simulate clicks
467 series->setPieSize(1.0);
468 QRectF pieRect = view.chart()->plotArea();
469 QList<QPoint> points = slicePoints(rect: pieRect);
470 QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton, stateKey: {}, pos: points.at(i: 0));
471 QCOMPARE(clickSpy1.count(), 1);
472}
473
474QTEST_MAIN(tst_qpieslice)
475
476#include "tst_qpieslice.moc"
477
478

source code of qtcharts/tests/auto/qpieslice/tst_qpieslice.cpp