##// END OF EJS Templates
Bugfix: remove restrictions from pie start & end angles...
Jani Honkonen -
r1207:614787b7b70d
parent child
Show More
@@ -1,331 +1,331
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20 #include "mainwidget.h"
21 21 #include "customslice.h"
22 22 #include "pentool.h"
23 23 #include "brushtool.h"
24 24 #include <QPushButton>
25 25 #include <QComboBox>
26 26 #include <QCheckBox>
27 27 #include <QLabel>
28 28 #include <QGroupBox>
29 29 #include <QDoubleSpinBox>
30 30 #include <QFormLayout>
31 31 #include <QFontDialog>
32 32 #include <QChartView>
33 33 #include <QPieSeries>
34 34
35 35 QTCOMMERCIALCHART_USE_NAMESPACE
36 36
37 37 MainWidget::MainWidget(QWidget* parent)
38 38 :QWidget(parent),
39 39 m_slice(0)
40 40 {
41 41 // create chart
42 42 QChart *chart = new QChart;
43 43 chart->setTitle("Piechart customization");
44 44 chart->setAnimationOptions(QChart::AllAnimations);
45 45
46 46 // create series
47 47 m_series = new QPieSeries();
48 48 *m_series << new CustomSlice("Slice 1", 10.0);
49 49 *m_series << new CustomSlice("Slice 2", 20.0);
50 50 *m_series << new CustomSlice("Slice 3", 30.0);
51 51 *m_series << new CustomSlice("Slice 4", 40.0);
52 52 *m_series << new CustomSlice("Slice 5", 50.0);
53 53 m_series->setLabelsVisible();
54 54 chart->addSeries(m_series);
55 55
56 56 connect(m_series, SIGNAL(clicked(QPieSlice*)), this, SLOT(handleSliceClicked(QPieSlice*)));
57 57
58 58 // chart settings
59 59 m_themeComboBox = new QComboBox();
60 60 m_themeComboBox->addItem("Light", QChart::ChartThemeLight);
61 61 m_themeComboBox->addItem("BlueCerulean", QChart::ChartThemeBlueCerulean);
62 62 m_themeComboBox->addItem("Dark", QChart::ChartThemeDark);
63 63 m_themeComboBox->addItem("BrownSand", QChart::ChartThemeBrownSand);
64 64 m_themeComboBox->addItem("BlueNcs", QChart::ChartThemeBlueNcs);
65 65 m_themeComboBox->addItem("High Contrast", QChart::ChartThemeHighContrast);
66 66 m_themeComboBox->addItem("Blue Icy", QChart::ChartThemeBlueIcy);
67 67
68 68 m_aaCheckBox = new QCheckBox();
69 69 m_animationsCheckBox = new QCheckBox();
70 70 m_animationsCheckBox->setCheckState(Qt::Checked);
71 71
72 72 m_legendCheckBox = new QCheckBox();
73 73
74 74 QFormLayout* chartSettingsLayout = new QFormLayout();
75 75 chartSettingsLayout->addRow("Theme", m_themeComboBox);
76 76 chartSettingsLayout->addRow("Antialiasing", m_aaCheckBox);
77 77 chartSettingsLayout->addRow("Animations", m_animationsCheckBox);
78 78 chartSettingsLayout->addRow("Legend", m_legendCheckBox);
79 79 QGroupBox* chartSettings = new QGroupBox("Chart");
80 80 chartSettings->setLayout(chartSettingsLayout);
81 81
82 82 connect(m_themeComboBox, SIGNAL(currentIndexChanged(int)), this ,SLOT(updateChartSettings()));
83 83 connect(m_aaCheckBox, SIGNAL(toggled(bool)), this ,SLOT(updateChartSettings()));
84 84 connect(m_animationsCheckBox, SIGNAL(toggled(bool)), this ,SLOT(updateChartSettings()));
85 85 connect(m_legendCheckBox, SIGNAL(toggled(bool)), this ,SLOT(updateChartSettings()));
86 86
87 87 // series settings
88 88 m_hPosition = new QDoubleSpinBox();
89 89 m_hPosition->setMinimum(0.0);
90 90 m_hPosition->setMaximum(1.0);
91 91 m_hPosition->setSingleStep(0.1);
92 92 m_hPosition->setValue(m_series->horizontalPosition());
93 93
94 94 m_vPosition = new QDoubleSpinBox();
95 95 m_vPosition->setMinimum(0.0);
96 96 m_vPosition->setMaximum(1.0);
97 97 m_vPosition->setSingleStep(0.1);
98 98 m_vPosition->setValue(m_series->verticalPosition());
99 99
100 100 m_sizeFactor = new QDoubleSpinBox();
101 101 m_sizeFactor->setMinimum(0.0);
102 102 m_sizeFactor->setMaximum(1.0);
103 103 m_sizeFactor->setSingleStep(0.1);
104 104 m_sizeFactor->setValue(m_series->pieSize());
105 105
106 106 m_startAngle = new QDoubleSpinBox();
107 m_startAngle->setMinimum(0.0);
108 m_startAngle->setMaximum(360);
107 m_startAngle->setMinimum(-720);
108 m_startAngle->setMaximum(720);
109 109 m_startAngle->setValue(m_series->pieStartAngle());
110 110 m_startAngle->setSingleStep(1);
111 111
112 112 m_endAngle = new QDoubleSpinBox();
113 m_endAngle->setMinimum(0.0);
114 m_endAngle->setMaximum(360);
113 m_endAngle->setMinimum(-720);
114 m_endAngle->setMaximum(720);
115 115 m_endAngle->setValue(m_series->pieEndAngle());
116 116 m_endAngle->setSingleStep(1);
117 117
118 118 QPushButton *appendSlice = new QPushButton("Append slice");
119 119 QPushButton *insertSlice = new QPushButton("Insert slice");
120 120
121 121 QFormLayout* seriesSettingsLayout = new QFormLayout();
122 122 seriesSettingsLayout->addRow("Horizontal position", m_hPosition);
123 123 seriesSettingsLayout->addRow("Vertical position", m_vPosition);
124 124 seriesSettingsLayout->addRow("Size factor", m_sizeFactor);
125 125 seriesSettingsLayout->addRow("Start angle", m_startAngle);
126 126 seriesSettingsLayout->addRow("End angle", m_endAngle);
127 127 seriesSettingsLayout->addRow(appendSlice);
128 128 seriesSettingsLayout->addRow(insertSlice);
129 129 QGroupBox* seriesSettings = new QGroupBox("Series");
130 130 seriesSettings->setLayout(seriesSettingsLayout);
131 131
132 132 connect(m_vPosition, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
133 133 connect(m_hPosition, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
134 134 connect(m_sizeFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
135 135 connect(m_startAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
136 136 connect(m_endAngle, SIGNAL(valueChanged(double)), this, SLOT(updateSerieSettings()));
137 137 connect(appendSlice, SIGNAL(clicked()), this, SLOT(appendSlice()));
138 138 connect(insertSlice, SIGNAL(clicked()), this, SLOT(insertSlice()));
139 139
140 140 // slice settings
141 141 m_sliceName = new QLabel("<click a slice>");
142 142 m_sliceValue = new QDoubleSpinBox();
143 143 m_sliceValue->setMaximum(1000);
144 144 m_sliceLabelVisible = new QCheckBox();
145 145 m_sliceLabelArmFactor = new QDoubleSpinBox();
146 146 m_sliceLabelArmFactor->setSingleStep(0.01);
147 147 m_sliceExploded = new QCheckBox();
148 148 m_sliceExplodedFactor = new QDoubleSpinBox();
149 149 m_sliceExplodedFactor->setSingleStep(0.01);
150 150 m_pen = new QPushButton();
151 151 m_penTool = new PenTool("Slice pen", this);
152 152 m_brush = new QPushButton();
153 153 m_brushTool = new BrushTool("Slice brush", this);
154 154 m_font = new QPushButton();
155 155 m_labelPen = new QPushButton();
156 156 m_labelPenTool = new PenTool("Label pen", this);
157 157 QPushButton *removeSlice = new QPushButton("Remove slice");
158 158
159 159 QFormLayout* sliceSettingsLayout = new QFormLayout();
160 160 sliceSettingsLayout->addRow("Selected", m_sliceName);
161 161 sliceSettingsLayout->addRow("Value", m_sliceValue);
162 162 sliceSettingsLayout->addRow("Pen", m_pen);
163 163 sliceSettingsLayout->addRow("Brush", m_brush);
164 164 sliceSettingsLayout->addRow("Label visible", m_sliceLabelVisible);
165 165 sliceSettingsLayout->addRow("Label font", m_font);
166 166 sliceSettingsLayout->addRow("Label pen", m_labelPen);
167 167 sliceSettingsLayout->addRow("Label arm length", m_sliceLabelArmFactor);
168 168 sliceSettingsLayout->addRow("Exploded", m_sliceExploded);
169 169 sliceSettingsLayout->addRow("Explode distance", m_sliceExplodedFactor);
170 170 sliceSettingsLayout->addRow(removeSlice);
171 171 QGroupBox* sliceSettings = new QGroupBox("Slice");
172 172 sliceSettings->setLayout(sliceSettingsLayout);
173 173
174 174 connect(m_sliceValue, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings()));
175 175 connect(m_pen, SIGNAL(clicked()), m_penTool, SLOT(show()));
176 176 connect(m_penTool, SIGNAL(changed()), this, SLOT(updateSliceSettings()));
177 177 connect(m_brush, SIGNAL(clicked()), m_brushTool, SLOT(show()));
178 178 connect(m_brushTool, SIGNAL(changed()), this, SLOT(updateSliceSettings()));
179 179 connect(m_font, SIGNAL(clicked()), this, SLOT(showFontDialog()));
180 180 connect(m_labelPen, SIGNAL(clicked()), m_labelPenTool, SLOT(show()));
181 181 connect(m_labelPenTool, SIGNAL(changed()), this, SLOT(updateSliceSettings()));
182 182 connect(m_sliceLabelVisible, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings()));
183 183 connect(m_sliceLabelVisible, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings()));
184 184 connect(m_sliceLabelArmFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings()));
185 185 connect(m_sliceExploded, SIGNAL(toggled(bool)), this, SLOT(updateSliceSettings()));
186 186 connect(m_sliceExplodedFactor, SIGNAL(valueChanged(double)), this, SLOT(updateSliceSettings()));
187 187 connect(removeSlice, SIGNAL(clicked()), this, SLOT(removeSlice()));
188 188
189 189 // create chart view
190 190 m_chartView = new QChartView(chart);
191 191
192 192 // create main layout
193 193 QVBoxLayout *settingsLayout = new QVBoxLayout();
194 194 settingsLayout->addWidget(chartSettings);
195 195 settingsLayout->addWidget(seriesSettings);
196 196 settingsLayout->addWidget(sliceSettings);
197 197 settingsLayout->addStretch();
198 198
199 199 QGridLayout* baseLayout = new QGridLayout();
200 200 baseLayout->addLayout(settingsLayout, 0, 0);
201 201 baseLayout->addWidget(m_chartView, 0, 1);
202 202 setLayout(baseLayout);
203 203
204 204 updateSerieSettings();
205 205 }
206 206
207 207
208 208 void MainWidget::updateChartSettings()
209 209 {
210 210 QChart::ChartTheme theme = (QChart::ChartTheme) m_themeComboBox->itemData(m_themeComboBox->currentIndex()).toInt();
211 211 m_chartView->chart()->setTheme(theme);
212 212 m_chartView->setRenderHint(QPainter::Antialiasing, m_aaCheckBox->isChecked());
213 213
214 214 if (m_animationsCheckBox->checkState() == Qt::Checked)
215 215 m_chartView->chart()->setAnimationOptions(QChart::AllAnimations);
216 216 else
217 217 m_chartView->chart()->setAnimationOptions(QChart::NoAnimation);
218 218
219 219 if (m_legendCheckBox->checkState() == Qt::Checked)
220 220 m_chartView->chart()->legend()->show();
221 221 else
222 222 m_chartView->chart()->legend()->hide();
223 223 }
224 224
225 225 void MainWidget::updateSerieSettings()
226 226 {
227 227 m_series->setHorizontalPosition(m_hPosition->value());
228 228 m_series->setVerticalPosition(m_vPosition->value());
229 229 m_series->setPieSize(m_sizeFactor->value());
230 230 m_series->setPieStartAngle(m_startAngle->value());
231 231 m_series->setPieEndAngle(m_endAngle->value());
232 232 }
233 233
234 234 void MainWidget::updateSliceSettings()
235 235 {
236 236 if (!m_slice)
237 237 return;
238 238
239 239 m_slice->setValue(m_sliceValue->value());
240 240
241 241 m_slice->setPen(m_penTool->pen());
242 242 m_slice->setBrush(m_brushTool->brush());
243 243
244 244 m_slice->setLabelPen(m_labelPenTool->pen());
245 245 m_slice->setLabelVisible(m_sliceLabelVisible->isChecked());
246 246 m_slice->setLabelArmLengthFactor(m_sliceLabelArmFactor->value());
247 247
248 248 m_slice->setExploded(m_sliceExploded->isChecked());
249 249 m_slice->setExplodeDistanceFactor(m_sliceExplodedFactor->value());
250 250 }
251 251
252 252 void MainWidget::handleSliceClicked(QPieSlice* slice)
253 253 {
254 254 m_slice = static_cast<CustomSlice*>(slice);
255 255
256 256 // name
257 257 m_sliceName->setText(slice->label());
258 258
259 259 // value
260 260 m_sliceValue->blockSignals(true);
261 261 m_sliceValue->setValue(slice->value());
262 262 m_sliceValue->blockSignals(false);
263 263
264 264 // pen
265 265 m_pen->setText(PenTool::name(m_slice->pen()));
266 266 m_penTool->setPen(m_slice->pen());
267 267
268 268 // brush
269 269 m_brush->setText(m_slice->originalBrush().color().name());
270 270 m_brushTool->setBrush(m_slice->originalBrush());
271 271
272 272 // label
273 273 m_labelPen->setText(PenTool::name(m_slice->labelPen()));
274 274 m_labelPenTool->setPen(m_slice->labelPen());
275 275 m_font->setText(slice->labelFont().toString());
276 276 m_sliceLabelVisible->blockSignals(true);
277 277 m_sliceLabelVisible->setChecked(slice->isLabelVisible());
278 278 m_sliceLabelVisible->blockSignals(false);
279 279 m_sliceLabelArmFactor->blockSignals(true);
280 280 m_sliceLabelArmFactor->setValue(slice->labelArmLengthFactor());
281 281 m_sliceLabelArmFactor->blockSignals(false);
282 282
283 283 // exploded
284 284 m_sliceExploded->blockSignals(true);
285 285 m_sliceExploded->setChecked(slice->isExploded());
286 286 m_sliceExploded->blockSignals(false);
287 287 m_sliceExplodedFactor->blockSignals(true);
288 288 m_sliceExplodedFactor->setValue(slice->explodeDistanceFactor());
289 289 m_sliceExplodedFactor->blockSignals(false);
290 290 }
291 291
292 292 void MainWidget::showFontDialog()
293 293 {
294 294 if (!m_slice)
295 295 return;
296 296
297 297 QFontDialog dialog(m_slice->labelFont());
298 298 dialog.show();
299 299 dialog.exec();
300 300
301 301 m_slice->setLabelFont(dialog.currentFont());
302 302 m_font->setText(dialog.currentFont().toString());
303 303 }
304 304
305 305 void MainWidget::appendSlice()
306 306 {
307 307 *m_series << new CustomSlice("Slice " + QString::number(m_series->count()+1), 10.0);
308 308 }
309 309
310 310 void MainWidget::insertSlice()
311 311 {
312 312 if (!m_slice)
313 313 return;
314 314
315 315 int i = m_series->slices().indexOf(m_slice);
316 316
317 317 m_series->insert(i, new CustomSlice("Slice " + QString::number(m_series->count()+1), 10.0));
318 318 }
319 319
320 320 void MainWidget::removeSlice()
321 321 {
322 322 if (!m_slice)
323 323 return;
324 324
325 325 m_sliceName->setText("<click a slice>");
326 326
327 327 m_series->remove(m_slice);
328 328 m_slice = 0;
329 329 }
330 330
331 331 #include "moc_mainwidget.cpp"
@@ -1,813 +1,816
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "qpieseries.h"
22 22 #include "qpieseries_p.h"
23 23 #include "qpieslice.h"
24 24 #include "pieslicedata_p.h"
25 25 #include "chartdataset_p.h"
26 26 #include "charttheme_p.h"
27 27 #include "chartanimator_p.h"
28 28 #include "legendmarker_p.h"
29 29 #include <QAbstractItemModel>
30 30 #include "qpiemodelmapper.h"
31 31
32 32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 33
34 34 /*!
35 35 \class QPieSeries
36 36 \brief Pie series API for QtCommercial Charts
37 37
38 38 The pie series defines a pie chart which consists of pie slices which are defined as QPieSlice objects.
39 39 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
40 40 The actual slice size is determined by that relative value.
41 41
42 42 Pie size and position on the chart is controlled by using relative values which range from 0.0 to 1.0
43 43 These relate to the actual chart rectangle.
44 44
45 45 By default the pie is defined as a full pie but it can also be a partial pie.
46 46 This can be done by setting a starting angle and angle span to the series.
47 47 Full pie is 360 degrees where 0 is at 12 a'clock.
48 48
49 49 See the \l {PieChart Example} {pie chart example} to learn how to create a simple pie chart.
50 50 \image examples_piechart.png
51 51 */
52 52
53 53 /*!
54 54 \property QPieSeries::horizontalPosition
55 55 \brief Defines the horizontal position of the pie.
56 56
57 57 The value is a relative value to the chart rectangle where:
58 58
59 59 \list
60 60 \o 0.0 is the absolute left.
61 61 \o 1.0 is the absolute right.
62 62 \endlist
63 63
64 64 Default value is 0.5 (center).
65 65 */
66 66
67 67 /*!
68 68 \property QPieSeries::verticalPosition
69 69 \brief Defines the vertical position of the pie.
70 70
71 71 The value is a relative value to the chart rectangle where:
72 72
73 73 \list
74 74 \o 0.0 is the absolute top.
75 75 \o 1.0 is the absolute bottom.
76 76 \endlist
77 77
78 78 Default value is 0.5 (center).
79 79 */
80 80
81 81 /*!
82 82 \property QPieSeries::size
83 83 \brief Defines the pie size.
84 84
85 85 The value is a relative value to the chart rectangle where:
86 86
87 87 \list
88 88 \o 0.0 is the minimum size (pie not drawn).
89 89 \o 1.0 is the maximum size that can fit the chart.
90 90 \endlist
91 91
92 92 Default value is 0.7.
93 93 */
94 94
95 95 /*!
96 96 \property QPieSeries::startAngle
97 97 \brief Defines the starting angle of the pie.
98 98
99 99 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
100 100
101 101 Default is value is 0.
102 102 */
103 103
104 104 /*!
105 105 \property QPieSeries::endAngle
106 106 \brief Defines the ending angle of the pie.
107 107
108 108 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
109 109
110 110 Default is value is 360.
111 111 */
112 112
113 113
114 114 /*!
115 115 Constructs a series object which is a child of \a parent.
116 116 */
117 117 QPieSeries::QPieSeries(QObject *parent) :
118 118 QAbstractSeries(*new QPieSeriesPrivate(this),parent)
119 119 {
120 120
121 121 }
122 122
123 123 /*!
124 124 Destroys the series and its slices.
125 125 */
126 126 QPieSeries::~QPieSeries()
127 127 {
128 128 // NOTE: d_prt destroyed by QObject
129 129 }
130 130
131 131 /*!
132 132 Returns QChartSeries::SeriesTypePie.
133 133 */
134 134 QAbstractSeries::SeriesType QPieSeries::type() const
135 135 {
136 136 return QAbstractSeries::SeriesTypePie;
137 137 }
138 138
139 139 /*!
140 140 Appends an array of \a slices to the series.
141 141 Slice ownership is passed to the series.
142 142 */
143 143 bool QPieSeries::append(QList<QPieSlice*> slices)
144 144 {
145 145 Q_D(QPieSeries);
146 146
147 147 if (slices.count() == 0)
148 148 return false;
149 149
150 150 foreach (QPieSlice* s, slices) {
151 151 if (!s || d->m_slices.contains(s))
152 152 return false;
153 153 }
154 154
155 155 foreach (QPieSlice* s, slices) {
156 156 s->setParent(this);
157 157 d->m_slices << s;
158 158 }
159 159
160 160 d->updateDerivativeData();
161 161
162 162 foreach (QPieSlice* s, slices) {
163 163 connect(s, SIGNAL(changed()), d, SLOT(sliceChanged()));
164 164 connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
165 165 connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
166 166 }
167 167
168 168 emit d->added(slices);
169 169
170 170 return true;
171 171 }
172 172
173 173 /*!
174 174 Appends a single \a slice to the series.
175 175 Slice ownership is passed to the series.
176 176 */
177 177 bool QPieSeries::append(QPieSlice* slice)
178 178 {
179 179 return append(QList<QPieSlice*>() << slice);
180 180 }
181 181
182 182 /*!
183 183 Appends a single \a slice to the series and returns a reference to the series.
184 184 Slice ownership is passed to the series.
185 185 */
186 186 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
187 187 {
188 188 append(slice);
189 189 return *this;
190 190 }
191 191
192 192
193 193 /*!
194 194 Appends a single slice to the series with give \a value and \a label.
195 195 Slice ownership is passed to the series.
196 196 */
197 197 QPieSlice* QPieSeries::append(QString label, qreal value)
198 198 {
199 199 QPieSlice* slice = new QPieSlice(label, value);
200 200 append(slice);
201 201 return slice;
202 202 }
203 203
204 204 /*!
205 205 Inserts a single \a slice to the series before the slice at \a index position.
206 206 Slice ownership is passed to the series.
207 207 */
208 208 bool QPieSeries::insert(int index, QPieSlice* slice)
209 209 {
210 210 Q_D(QPieSeries);
211 211
212 212 if (index < 0 || index > d->m_slices.count())
213 213 return false;
214 214
215 215 if (!slice || d->m_slices.contains(slice))
216 216 return false;
217 217
218 218 slice->setParent(this);
219 219 d->m_slices.insert(index, slice);
220 220
221 221 d->updateDerivativeData();
222 222
223 223 connect(slice, SIGNAL(changed()), d, SLOT(sliceChanged()));
224 224 connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
225 225 connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
226 226
227 227 emit d->added(QList<QPieSlice*>() << slice);
228 228
229 229 return true;
230 230 }
231 231
232 232 /*!
233 233 Removes a single \a slice from the series and deletes the slice.
234 234
235 235 Do not reference the pointer after this call.
236 236 */
237 237 bool QPieSeries::remove(QPieSlice* slice)
238 238 {
239 239 Q_D(QPieSeries);
240 240
241 241 if (!d->m_slices.removeOne(slice))
242 242 return false;
243 243
244 244 d->updateDerivativeData();
245 245
246 246 emit d->removed(QList<QPieSlice*>() << slice);
247 247
248 248 delete slice;
249 249 slice = 0;
250 250
251 251 return true;
252 252 }
253 253
254 254 /*!
255 255 Clears all slices from the series.
256 256 */
257 257 void QPieSeries::clear()
258 258 {
259 259 Q_D(QPieSeries);
260 260 if (d->m_slices.count() == 0)
261 261 return;
262 262
263 263 QList<QPieSlice*> slices = d->m_slices;
264 264 foreach (QPieSlice* s, d->m_slices) {
265 265 d->m_slices.removeOne(s);
266 266 delete s;
267 267 }
268 268
269 269 d->updateDerivativeData();
270 270
271 271 emit d->removed(slices);
272 272 }
273 273
274 274 /*!
275 275 returns the number of the slices in this series.
276 276 */
277 277 int QPieSeries::count() const
278 278 {
279 279 Q_D(const QPieSeries);
280 280 return d->m_slices.count();
281 281 }
282 282
283 283 /*!
284 284 Returns true is the series is empty.
285 285 */
286 286 bool QPieSeries::isEmpty() const
287 287 {
288 288 Q_D(const QPieSeries);
289 289 return d->m_slices.isEmpty();
290 290 }
291 291
292 292 /*!
293 293 Returns a list of slices that belong to this series.
294 294 */
295 295 QList<QPieSlice*> QPieSeries::slices() const
296 296 {
297 297 Q_D(const QPieSeries);
298 298 return d->m_slices;
299 299 }
300 300
301 301 void QPieSeries::setHorizontalPosition(qreal relativePosition)
302 302 {
303 303 Q_D(QPieSeries);
304 304 if (d->setRealValue(d->m_pieRelativeHorPos, relativePosition, 1.0))
305 305 emit d->piePositionChanged();
306 306 }
307 307
308 308 void QPieSeries::setVerticalPosition(qreal relativePosition)
309 309 {
310 310 Q_D(QPieSeries);
311 311 if (d->setRealValue(d->m_pieRelativeVerPos, relativePosition, 1.0))
312 312 emit d->piePositionChanged();
313 313 }
314 314
315 315 qreal QPieSeries::horizontalPosition() const
316 316 {
317 317 Q_D(const QPieSeries);
318 318 return d->m_pieRelativeHorPos;
319 319 }
320 320
321 321 qreal QPieSeries::verticalPosition() const
322 322 {
323 323 Q_D(const QPieSeries);
324 324 return d->m_pieRelativeVerPos;
325 325 }
326 326
327 327 void QPieSeries::setPieSize(qreal relativeSize)
328 328 {
329 329 Q_D(QPieSeries);
330 330 if (d->setRealValue(d->m_pieRelativeSize, relativeSize, 1.0))
331 331 emit d->pieSizeChanged();
332 332 }
333 333
334 334 qreal QPieSeries::pieSize() const
335 335 {
336 336 Q_D(const QPieSeries);
337 337 return d->m_pieRelativeSize;
338 338 }
339 339
340 340
341 341 void QPieSeries::setPieStartAngle(qreal angle)
342 342 {
343 343 Q_D(QPieSeries);
344 if (d->setRealValue(d->m_pieStartAngle, angle, d->m_pieEndAngle))
345 d->updateDerivativeData();
344 if (qFuzzyIsNull(d->m_pieStartAngle - angle))
345 return;
346 d->m_pieStartAngle = angle;
347 d->updateDerivativeData();
346 348 }
347 349
348 350 qreal QPieSeries::pieStartAngle() const
349 351 {
350 352 Q_D(const QPieSeries);
351 353 return d->m_pieStartAngle;
352 354 }
353 355
354 356 /*!
355 357 Sets the end angle of the pie.
356 358
357 359 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
358 360
359 361 \a angle must be greater than start angle.
360 362
361 363 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
362 364 */
363 365 void QPieSeries::setPieEndAngle(qreal angle)
364 366 {
365 367 Q_D(QPieSeries);
366
367 if (d->setRealValue(d->m_pieEndAngle, angle, 360.0, d->m_pieStartAngle))
368 d->updateDerivativeData();
368 if (qFuzzyIsNull(d->m_pieEndAngle - angle))
369 return;
370 d->m_pieEndAngle = angle;
371 d->updateDerivativeData();
369 372 }
370 373
371 374 /*!
372 375 Returns the end angle of the pie.
373 376
374 377 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
375 378
376 379 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
377 380 */
378 381 qreal QPieSeries::pieEndAngle() const
379 382 {
380 383 Q_D(const QPieSeries);
381 384 return d->m_pieEndAngle;
382 385 }
383 386
384 387 /*!
385 388 Sets the all the slice labels \a visible or invisible.
386 389
387 390 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
388 391 */
389 392 void QPieSeries::setLabelsVisible(bool visible)
390 393 {
391 394 Q_D(QPieSeries);
392 395 foreach (QPieSlice* s, d->m_slices)
393 396 s->setLabelVisible(visible);
394 397 }
395 398
396 399 /*!
397 400 Returns the sum of all slice values in this series.
398 401
399 402 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
400 403 */
401 404 qreal QPieSeries::sum() const
402 405 {
403 406 Q_D(const QPieSeries);
404 407 return d->m_sum;
405 408 }
406 409
407 410 /*!
408 411 \fn void QPieSeries::clicked(QPieSlice* slice)
409 412
410 413 This signal is emitted when a \a slice has been clicked.
411 414
412 415 \sa QPieSlice::clicked()
413 416 */
414 417
415 418 /*!
416 419 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
417 420
418 421 This signal is emitted when user has hovered over or away from the \a slice.
419 422
420 423 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
421 424
422 425 \sa QPieSlice::hovered()
423 426 */
424 427
425 428 /*!
426 429 \fn bool QPieSeries::setModel(QAbstractItemModel *model)
427 430 Sets the \a model to be used as a data source
428 431 */
429 432 void QPieSeries::setModel(QAbstractItemModel* model)
430 433 {
431 434 Q_D(QPieSeries);
432 435 // disconnect signals from old model
433 436 if(d->m_model)
434 437 {
435 438 disconnect(d->m_model, 0, this, 0);
436 439 }
437 440
438 441 // set new model
439 442 if(model)
440 443 {
441 444 d->m_model = model;
442 445 // connect signals from the model
443 446 connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
444 447 connect(d->m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), d, SLOT(modelRowsAdded(QModelIndex,int,int)));
445 448 connect(d->m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), d, SLOT(modelRowsRemoved(QModelIndex,int,int)));
446 449 connect(d->m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, SLOT(modelColumnsAdded(QModelIndex,int,int)));
447 450 connect(d->m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, SLOT(modelColumnsRemoved(QModelIndex,int,int)));
448 451
449 452 if (d->m_mapper)
450 453 d->initializePieFromModel();
451 454 }
452 455 else
453 456 {
454 457 d->m_model = 0;
455 458 }
456 459 }
457 460
458 461 void QPieSeries::setModelMapper(QPieModelMapper *mapper)
459 462 {
460 463 Q_D(QPieSeries);
461 464 // disconnect signals from old mapper
462 465 if (d->m_mapper) {
463 466 QObject::disconnect(d->m_mapper, 0, this, 0);
464 467 }
465 468
466 469 if (mapper) {
467 470 d->m_mapper = mapper;
468 471 // connect the signal from the mapper
469 472 connect(d->m_mapper, SIGNAL(updated()), d, SLOT(initializePieFromModel()));
470 473
471 474 if (d->m_model)
472 475 d->initializePieFromModel();
473 476 } else {
474 477 d->m_mapper = 0;
475 478 }
476 479 }
477 480
478 481 QPieModelMapper* QPieSeries::modelMapper() const
479 482 {
480 483 Q_D(const QPieSeries);
481 484 return d->m_mapper;
482 485 }
483 486
484 487 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
485 488
486 489
487 490 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
488 491 QAbstractSeriesPrivate(parent),
489 492 m_pieRelativeHorPos(0.5),
490 493 m_pieRelativeVerPos(0.5),
491 494 m_pieRelativeSize(0.7),
492 495 m_pieStartAngle(0),
493 496 m_pieEndAngle(360),
494 497 m_sum(0),
495 498 m_mapper(0)
496 499 {
497 500
498 501 }
499 502
500 503 QPieSeriesPrivate::~QPieSeriesPrivate()
501 504 {
502 505
503 506 }
504 507
505 508 void QPieSeriesPrivate::updateDerivativeData()
506 509 {
507 510 m_sum = 0;
508 511
509 512 // nothing to do?
510 513 if (m_slices.count() == 0)
511 514 return;
512 515
513 516 // calculate sum of all slices
514 517 foreach (QPieSlice* s, m_slices)
515 518 m_sum += s->value();
516 519
517 520 // nothing to show..
518 521 if (qFuzzyIsNull(m_sum))
519 522 return;
520 523
521 524 // update slice attributes
522 525 qreal sliceAngle = m_pieStartAngle;
523 526 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
524 527 QVector<QPieSlice*> changed;
525 528 foreach (QPieSlice* s, m_slices) {
526 529
527 530 PieSliceData data = PieSliceData::data(s);
528 531 data.m_percentage = s->value() / m_sum;
529 532 data.m_angleSpan = pieSpan * data.m_percentage;
530 533 data.m_startAngle = sliceAngle;
531 534 sliceAngle += data.m_angleSpan;
532 535
533 536 if (PieSliceData::data(s) != data) {
534 537 PieSliceData::data(s) = data;
535 538 changed << s;
536 539 }
537 540 }
538 541
539 542 // emit signals
540 543 foreach (QPieSlice* s, changed)
541 544 PieSliceData::data(s).emitChangedSignal(s);
542 545 }
543 546
544 547 QPieSeriesPrivate* QPieSeriesPrivate::seriesData(QPieSeries &series)
545 548 {
546 549 return series.d_func();
547 550 }
548 551
549 552 void QPieSeriesPrivate::sliceChanged()
550 553 {
551 554 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
552 555 updateDerivativeData();
553 556 }
554 557
555 558 void QPieSeriesPrivate::sliceClicked()
556 559 {
557 560 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
558 561 Q_ASSERT(m_slices.contains(slice));
559 562 Q_Q(QPieSeries);
560 563 emit q->clicked(slice);
561 564 }
562 565
563 566 void QPieSeriesPrivate::sliceHovered(bool state)
564 567 {
565 568 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
566 569 Q_ASSERT(m_slices.contains(slice));
567 570 Q_Q(QPieSeries);
568 571 emit q->hovered(slice, state);
569 572 }
570 573
571 574 void QPieSeriesPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
572 575 {
573 576 if (m_mapper) {
574 577 for (int row = topLeft.row(); row <= bottomRight.row(); row++) {
575 578 for (int column = topLeft.column(); column <= bottomRight.column(); column++) {
576 579 if (m_mapper->orientation() == Qt::Vertical)
577 580 {
578 581 if ( topLeft.row() >= m_mapper->first() && (m_mapper->count() == - 1 || topLeft.row() < m_mapper->first() + m_mapper->count())) {
579 582 if (topLeft.column() == m_mapper->mapValues())
580 583 m_slices.at(topLeft.row() - m_mapper->first())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
581 584 if (topLeft.column() == m_mapper->mapLabels())
582 585 m_slices.at(topLeft.row() - m_mapper->first())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
583 586 }
584 587 }
585 588 else
586 589 {
587 590 if (topLeft.column() >= m_mapper->first() && (m_mapper->count() == - 1 || topLeft.column() < m_mapper->first() + m_mapper->count())) {
588 591 if (topLeft.row() == m_mapper->mapValues())
589 592 m_slices.at(topLeft.column() - m_mapper->first())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
590 593 if (topLeft.row() == m_mapper->mapLabels())
591 594 m_slices.at(topLeft.column() - m_mapper->first())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
592 595 }
593 596 }
594 597 }
595 598 }
596 599 }
597 600 }
598 601
599 602
600 603 void QPieSeriesPrivate::modelRowsAdded(QModelIndex parent, int start, int end)
601 604 {
602 605 Q_UNUSED(parent);
603 606 if (m_mapper) {
604 607 if (m_mapper->orientation() == Qt::Vertical)
605 608 insertData(start, end);
606 609 else if (start <= m_mapper->mapValues() || start <= m_mapper->mapLabels()) // if the changes affect the map - reinitialize the pie
607 610 initializePieFromModel();
608 611 }
609 612 }
610 613
611 614 void QPieSeriesPrivate::modelRowsRemoved(QModelIndex parent, int start, int end)
612 615 {
613 616 Q_UNUSED(parent);
614 617 if (m_mapper) {
615 618 if (m_mapper->orientation() == Qt::Vertical)
616 619 removeData(start, end);
617 620 else if (start <= m_mapper->mapValues() || start <= m_mapper->mapLabels()) // if the changes affect the map - reinitialize the pie
618 621 initializePieFromModel();
619 622 }
620 623 }
621 624
622 625 void QPieSeriesPrivate::modelColumnsAdded(QModelIndex parent, int start, int end)
623 626 {
624 627 Q_UNUSED(parent);
625 628 if (m_mapper) {
626 629 if (m_mapper->orientation() == Qt::Horizontal)
627 630 insertData(start, end);
628 631 else if (start <= m_mapper->mapValues() || start <= m_mapper->mapLabels()) // if the changes affect the map - reinitialize the pie
629 632 initializePieFromModel();
630 633 }
631 634 }
632 635
633 636 void QPieSeriesPrivate::modelColumnsRemoved(QModelIndex parent, int start, int end)
634 637 {
635 638 Q_UNUSED(parent);
636 639 if (m_mapper) {
637 640 if (m_mapper->orientation() == Qt::Horizontal)
638 641 removeData(start, end);
639 642 else if (start <= m_mapper->mapValues() || start <= m_mapper->mapLabels()) // if the changes affect the map - reinitialize the pie
640 643 initializePieFromModel();
641 644 }
642 645 }
643 646
644 647 void QPieSeriesPrivate::insertData(int start, int end)
645 648 {
646 649 Q_Q(QPieSeries);
647 650 if (m_mapper) {
648 651 if (m_mapper->count() != -1 && start >= m_mapper->first() + m_mapper->count()) {
649 652 return;
650 653 } else {
651 654 int addedCount = end - start + 1;
652 655 if (m_mapper->count() != -1 && addedCount > m_mapper->count())
653 656 addedCount = m_mapper->count();
654 657 int first = qMax(start, m_mapper->first());
655 658 int last = qMin(first + addedCount - 1, m_mapper->orientation() == Qt::Vertical ? m_model->rowCount() - 1 : m_model->columnCount() - 1);
656 659 for (int i = first; i <= last; i++) {
657 660 QPieSlice *slice = new QPieSlice;
658 661 if (m_mapper->orientation() == Qt::Vertical) {
659 662 slice->setValue(m_model->data(m_model->index(i, m_mapper->mapValues()), Qt::DisplayRole).toDouble());
660 663 slice->setLabel(m_model->data(m_model->index(i, m_mapper->mapLabels()), Qt::DisplayRole).toString());
661 664 } else {
662 665 slice->setValue(m_model->data(m_model->index(m_mapper->mapValues(), i), Qt::DisplayRole).toDouble());
663 666 slice->setLabel(m_model->data(m_model->index(m_mapper->mapLabels(), i), Qt::DisplayRole).toString());
664 667 }
665 668 slice->setLabelVisible();
666 669 q->insert(i - m_mapper->first(), slice);
667 670 }
668 671 if (m_mapper->count() != -1 && m_slices.size() > m_mapper->count())
669 672 for (int i = m_slices.size() - 1; i >= m_mapper->count(); i--)
670 673 q->remove(q->slices().at(i));
671 674 }
672 675 }
673 676 }
674 677
675 678 void QPieSeriesPrivate::removeData(int start, int end)
676 679 {
677 680 Q_Q(QPieSeries);
678 681 if (m_mapper) {
679 682 int removedCount = end - start + 1;
680 683 if (m_mapper->count() != -1 && start >= m_mapper->first() + m_mapper->count()) {
681 684 return;
682 685 } else {
683 686 int toRemove = qMin(m_slices.size(), removedCount); // first find how many items can actually be removed
684 687 int first = qMax(start, m_mapper->first()); // get the index of the first item that will be removed.
685 688 int last = qMin(first + toRemove - 1, m_slices.size() + m_mapper->first() - 1); // get the index of the last item that will be removed.
686 689 for (int i = last; i >= first; i--)
687 690 q->remove(q->slices().at(i - m_mapper->first()));
688 691
689 692 if (m_mapper->count() != -1) {
690 693 int itemsAvailable; // check how many are available to be added
691 694 if (m_mapper->orientation() == Qt::Vertical)
692 695 itemsAvailable = m_model->rowCount() - m_mapper->first() - m_slices.size();
693 696 else
694 697 itemsAvailable = m_model->columnCount() - m_mapper->first() - m_slices.size();
695 698 int toBeAdded = qMin(itemsAvailable, m_mapper->count() - m_slices.size()); // add not more items than there is space left to be filled.
696 699 int currentSize = m_slices.size();
697 700 if (toBeAdded > 0)
698 701 for (int i = m_slices.size(); i < currentSize + toBeAdded; i++) {
699 702 QPieSlice *slice = new QPieSlice;
700 703 if (m_mapper->orientation() == Qt::Vertical) {
701 704 slice->setValue(m_model->data(m_model->index(i + m_mapper->first(), m_mapper->mapValues()), Qt::DisplayRole).toDouble());
702 705 slice->setLabel(m_model->data(m_model->index(i + m_mapper->first(), m_mapper->mapLabels()), Qt::DisplayRole).toString());
703 706 } else {
704 707 slice->setValue(m_model->data(m_model->index(m_mapper->mapValues(), i + m_mapper->first()), Qt::DisplayRole).toDouble());
705 708 slice->setLabel(m_model->data(m_model->index(m_mapper->mapLabels(), i + m_mapper->first()), Qt::DisplayRole).toString());
706 709 }
707 710 slice->setLabelVisible();
708 711 q->insert(i, slice);
709 712 }
710 713 }
711 714 }
712 715 }
713 716 }
714 717
715 718 void QPieSeriesPrivate::initializePieFromModel()
716 719 {
717 720 Q_Q(QPieSeries);
718 721
719 722 // clear current content
720 723 q->clear();
721 724
722 725 if (m_model == 0 || m_mapper == 0)
723 726 return;
724 727
725 728 // check if mappings are set
726 729 if (m_mapper->mapValues() == -1 || m_mapper->mapLabels() == -1)
727 730 return;
728 731
729 732 // create the initial slices set
730 733 if (m_mapper->orientation() == Qt::Vertical) {
731 734 if (m_mapper->mapValues() >= m_model->columnCount() || m_mapper->mapLabels() >= m_model->columnCount())
732 735 return; // mapped columns are not existing
733 736
734 737 int sliceCount = 0;
735 738 if(m_mapper->count() == -1)
736 739 sliceCount = m_model->rowCount() - m_mapper->first();
737 740 else
738 741 sliceCount = qMin(m_mapper->count(), m_model->rowCount() - m_mapper->first());
739 742 for (int i = m_mapper->first(); i < m_mapper->first() + sliceCount; i++)
740 743 q->append(m_model->data(m_model->index(i, m_mapper->mapLabels()), Qt::DisplayRole).toString(), m_model->data(m_model->index(i, m_mapper->mapValues()), Qt::DisplayRole).toDouble());
741 744 } else {
742 745 if (m_mapper->mapValues() >= m_model->rowCount() || m_mapper->mapLabels() >= m_model->rowCount())
743 746 return; // mapped columns are not existing
744 747
745 748 int sliceCount = 0;
746 749 if(m_mapper->count() == -1)
747 750 sliceCount = m_model->columnCount() - m_mapper->first();
748 751 else
749 752 sliceCount = qMin(m_mapper->count(), m_model->columnCount() - m_mapper->first());
750 753 for (int i = m_mapper->first(); i < m_mapper->first() + sliceCount; i++)
751 754 q->append(m_model->data(m_model->index(m_mapper->mapLabels(), i), Qt::DisplayRole).toString(), m_model->data(m_model->index(m_mapper->mapValues(), i), Qt::DisplayRole).toDouble());
752 755 }
753 756 q->setLabelsVisible(true);
754 757 }
755 758
756 759 bool QPieSeriesPrivate::setRealValue(qreal &value, qreal newValue, qreal max, qreal min)
757 760 {
758 761 // Remove rounding errors
759 762 qreal roundedValue = newValue;
760 763 if (qFuzzyIsNull(min) && qFuzzyIsNull(newValue))
761 764 roundedValue = 0.0;
762 765 else if (qFuzzyCompare(newValue, max))
763 766 roundedValue = max;
764 767 else if (qFuzzyCompare(newValue, min))
765 768 roundedValue = min;
766 769
767 770 // Check if the position is valid after removing the rounding errors
768 771 if (roundedValue < min || roundedValue > max) {
769 772 qWarning("QPieSeries: Illegal value");
770 773 return false;
771 774 }
772 775
773 776 if (!qFuzzyIsNull(value - roundedValue)) {
774 777 value = roundedValue;
775 778 return true;
776 779 }
777 780
778 781 // The change was so small it is considered a rounding error
779 782 return false;
780 783 }
781 784
782 785 void QPieSeriesPrivate::scaleDomain(Domain& domain)
783 786 {
784 787 Q_UNUSED(domain);
785 788 // does not apply to pie
786 789 }
787 790
788 791 Chart* QPieSeriesPrivate::createGraphics(ChartPresenter* presenter)
789 792 {
790 793 Q_Q(QPieSeries);
791 794 PieChartItem* pie = new PieChartItem(q,presenter);
792 795 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
793 796 presenter->animator()->addAnimation(pie);
794 797 }
795 798 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
796 799 return pie;
797 800 }
798 801
799 802 QList<LegendMarker*> QPieSeriesPrivate::createLegendMarker(QLegend* legend)
800 803 {
801 804 Q_Q(QPieSeries);
802 805 QList<LegendMarker*> markers;
803 806 foreach(QPieSlice* slice, q->slices()) {
804 807 PieLegendMarker* marker = new PieLegendMarker(q,slice,legend);
805 808 markers << marker;
806 809 }
807 810 return markers;
808 811 }
809 812
810 813 #include "moc_qpieseries.cpp"
811 814 #include "moc_qpieseries_p.cpp"
812 815
813 816 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,484 +1,491
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2012 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include <QtTest/QtTest>
22 22 #include <qchartview.h>
23 23 #include <qchart.h>
24 24 #include <qpieseries.h>
25 25 #include <qpieslice.h>
26 26 #include <qpiemodelmapper.h>
27 27 #include <QStandardItemModel>
28 28 #include <tst_definitions.h>
29 29
30 30 QTCOMMERCIALCHART_USE_NAMESPACE
31 31
32 32 Q_DECLARE_METATYPE(QPieSlice*)
33 33
34 34 class tst_qpieseries : public QObject
35 35 {
36 36 Q_OBJECT
37 37
38 38 public slots:
39 39 void initTestCase();
40 40 void cleanupTestCase();
41 41 void init();
42 42 void cleanup();
43 43
44 44 private slots:
45 45 void construction();
46 46 void append();
47 47 void insert();
48 48 void remove();
49 49 void calculatedValues();
50 50 void clickedSignal();
51 51 void hoverSignal();
52 52 void model();
53 53 void modelCustomMap();
54 54 void modelUpdate();
55 55
56 56 private:
57 57 void verifyCalculatedData(const QPieSeries &series, bool *ok);
58 58
59 59 private:
60 60
61 61 };
62 62
63 63 void tst_qpieseries::initTestCase()
64 64 {
65 65 qRegisterMetaType<QPieSlice*>("QPieSlice*");
66 66 }
67 67
68 68 void tst_qpieseries::cleanupTestCase()
69 69 {
70 70 }
71 71
72 72 void tst_qpieseries::init()
73 73 {
74 74
75 75 }
76 76
77 77 void tst_qpieseries::cleanup()
78 78 {
79 79
80 80 }
81 81
82 82 void tst_qpieseries::construction()
83 83 {
84 84 // verify default values
85 85 QPieSeries s;
86 86 QVERIFY(s.type() == QAbstractSeries::SeriesTypePie);
87 87 QVERIFY(s.count() == 0);
88 88 QVERIFY(s.isEmpty());
89 89 QCOMPARE(s.sum(), 0.0);
90 90 QCOMPARE(s.horizontalPosition(), 0.5);
91 91 QCOMPARE(s.verticalPosition(), 0.5);
92 92 QCOMPARE(s.pieSize(), 0.7);
93 93 QCOMPARE(s.pieStartAngle(), 0.0);
94 94 QCOMPARE(s.pieEndAngle(), 360.0);
95 95 }
96 96
97 97 void tst_qpieseries::append()
98 98 {
99 99 QPieSeries s;
100 100
101 101 // append pointer
102 102 QPieSlice *slice1 = 0;
103 103 QVERIFY(!s.append(slice1));
104 104 slice1 = new QPieSlice("slice 1", 1);
105 105 QVERIFY(s.append(slice1));
106 106 QVERIFY(!s.append(slice1));
107 107 QCOMPARE(s.count(), 1);
108 108
109 109 // append pointer list
110 110 QList<QPieSlice *> list;
111 111 QVERIFY(!s.append(list));
112 112 list << (QPieSlice *) 0;
113 113 QVERIFY(!s.append(list));
114 114 list.clear();
115 115 list << new QPieSlice("slice 2", 2);
116 116 list << new QPieSlice("slice 3", 3);
117 117 QVERIFY(s.append(list));
118 118 QVERIFY(!s.append(list));
119 119 QCOMPARE(s.count(), 3);
120 120
121 121 // append operator
122 122 s << new QPieSlice("slice 4", 4);
123 123 s << slice1; // fails because already added
124 124 QCOMPARE(s.count(), 4);
125 125
126 126 // append with params
127 127 QPieSlice *slice5 = s.append("slice 5", 5);
128 128 QVERIFY(slice5 != 0);
129 129 QCOMPARE(slice5->value(), 5.0);
130 130 QCOMPARE(slice5->label(), QString("slice 5"));
131 131 QCOMPARE(s.count(), 5);
132 132
133 133 // check slices
134 134 QVERIFY(!s.isEmpty());
135 135 for (int i=0; i<s.count(); i++) {
136 136 QCOMPARE(s.slices().at(i)->value(), (qreal) i+1);
137 137 QCOMPARE(s.slices().at(i)->label(), QString("slice ") + QString::number(i+1));
138 138 }
139 139 }
140 140
141 141 void tst_qpieseries::insert()
142 142 {
143 143 QPieSeries s;
144 144
145 145 // insert one slice
146 146 QPieSlice *slice1 = 0;
147 147 QVERIFY(!s.insert(0, slice1));
148 148 slice1 = new QPieSlice("slice 1", 1);
149 149 QVERIFY(!s.insert(-1, slice1));
150 150 QVERIFY(!s.insert(5, slice1));
151 151 QVERIFY(s.insert(0, slice1));
152 152 QVERIFY(!s.insert(0, slice1));
153 153 QCOMPARE(s.count(), 1);
154 154
155 155 // add some more slices
156 156 s.append("slice 2", 2);
157 157 s.append("slice 4", 4);
158 158 QCOMPARE(s.count(), 3);
159 159
160 160 // insert between slices
161 161 s.insert(2, new QPieSlice("slice 3", 3));
162 162 QCOMPARE(s.count(), 4);
163 163
164 164 // check slices
165 165 for (int i=0; i<s.count(); i++) {
166 166 QCOMPARE(s.slices().at(i)->value(), (qreal) i+1);
167 167 QCOMPARE(s.slices().at(i)->label(), QString("slice ") + QString::number(i+1));
168 168 }
169 169 }
170 170
171 171 void tst_qpieseries::remove()
172 172 {
173 173 QPieSeries s;
174 174
175 175 // add some slices
176 176 QPieSlice *slice1 = s.append("slice 1", 1);
177 177 QPieSlice *slice2 = s.append("slice 2", 2);
178 178 QPieSlice *slice3 = s.append("slice 3", 3);
179 179 QSignalSpy spy1(slice1, SIGNAL(destroyed()));
180 180 QSignalSpy spy2(slice2, SIGNAL(destroyed()));
181 181 QSignalSpy spy3(slice3, SIGNAL(destroyed()));
182 182 QCOMPARE(s.count(), 3);
183 183
184 184 // null pointer remove
185 185 QVERIFY(!s.remove(0));
186 186
187 187 // remove first
188 188 QVERIFY(s.remove(slice1));
189 189 QVERIFY(!s.remove(slice1));
190 190 QCOMPARE(s.count(), 2);
191 191 QCOMPARE(s.slices().at(0)->label(), slice2->label());
192 192
193 193 // remove all
194 194 s.clear();
195 195 QVERIFY(s.isEmpty());
196 196 QVERIFY(s.slices().isEmpty());
197 197 QCOMPARE(s.count(), 0);
198 198
199 199 // check that slices were actually destroyed
200 200 TRY_COMPARE(spy1.count(), 1);
201 201 TRY_COMPARE(spy2.count(), 1);
202 202 TRY_COMPARE(spy3.count(), 1);
203 203 }
204 204
205 205 void tst_qpieseries::calculatedValues()
206 206 {
207 207 bool ok;
208 208 QPieSeries s;
209 209
210 210 // add a slice
211 211 QPieSlice *slice1 = s.append("slice 1", 1);
212 212 verifyCalculatedData(s, &ok);
213 213 if (!ok)
214 214 return;
215 215
216 216 // add some more slices
217 217 QList<QPieSlice *> list;
218 218 list << new QPieSlice("slice 2", 2);
219 219 list << new QPieSlice("slice 3", 3);
220 220 s.append(list);
221 221 verifyCalculatedData(s, &ok);
222 222 if (!ok)
223 223 return;
224 224
225 225 // remove a slice
226 226 s.remove(slice1);
227 227 verifyCalculatedData(s, &ok);
228 228 if (!ok)
229 229 return;
230 230
231 231 // insert a slice
232 232 s.insert(0, new QPieSlice("Slice 4", 4));
233 233 verifyCalculatedData(s, &ok);
234 234 if (!ok)
235 235 return;
236 236
237 // modify pie angles
238 s.setPieStartAngle(-90);
239 s.setPieEndAngle(90);
240 verifyCalculatedData(s, &ok);
241 if (!ok)
242 return;
243
237 244 // clear all
238 245 s.clear();
239 246 verifyCalculatedData(s, &ok);
240 247 }
241 248
242 249 void tst_qpieseries::verifyCalculatedData(const QPieSeries &series, bool *ok)
243 250 {
244 251 *ok = false;
245 252
246 253 qreal sum = 0;
247 254 foreach (const QPieSlice *slice, series.slices())
248 255 sum += slice->value();
249 256 QCOMPARE(series.sum(), sum);
250 257
251 258 qreal startAngle = series.pieStartAngle();
252 259 qreal pieAngleSpan = series.pieEndAngle() - series.pieStartAngle();
253 260 foreach (const QPieSlice *slice, series.slices()) {
254 261 qreal ratio = slice->value() / sum;
255 262 qreal sliceSpan = pieAngleSpan * ratio;
256 263 QCOMPARE(slice->startAngle(), startAngle);
257 264 QCOMPARE(slice->endAngle(), startAngle + sliceSpan);
258 265 QCOMPARE(slice->percentage(), ratio);
259 266 startAngle += sliceSpan;
260 267 }
261 268
262 269 if (!series.isEmpty())
263 270 QCOMPARE(series.slices().last()->endAngle(), series.pieEndAngle());
264 271
265 272 *ok = true;
266 273 }
267 274
268 275
269 276 void tst_qpieseries::clickedSignal()
270 277 {
271 278 // create a pie series
272 279 QPieSeries *series = new QPieSeries();
273 280 series->setPieSize(1.0);
274 281 QPieSlice *s1 = series->append("slice 1", 1);
275 282 series->append("slice 2", 2);
276 283 series->append("slice 3", 3);
277 284 QSignalSpy clickSpy1(series, SIGNAL(clicked(QPieSlice*)));
278 285
279 286 // add series to the chart
280 287 QChartView view(new QChart());
281 288 view.chart()->legend()->setVisible(false);
282 289 view.resize(200, 200);
283 290 view.chart()->addSeries(series);
284 291 view.show();
285 292 QTest::qWaitForWindowShown(&view);
286 293
287 294 // simulate clicks
288 295 // pie rectangle: QRectF(60,60 121x121)
289 296 QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, QPoint(146, 90)); // inside slice 1
290 297 TRY_COMPARE(clickSpy1.count(), 1);
291 298 QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy1.at(0).at(0)), s1);
292 299 }
293 300
294 301 void tst_qpieseries::hoverSignal()
295 302 {
296 303 // create a pie series
297 304 QPieSeries *series = new QPieSeries();
298 305 series->setPieSize(1.0);
299 306 QPieSlice *s1 = series->append("slice 1", 1);
300 307 series->append("slice 2", 2);
301 308 series->append("slice 3", 3);
302 309
303 310 // add series to the chart
304 311 QChartView view(new QChart());
305 312 view.chart()->legend()->setVisible(false);
306 313 view.resize(200, 200);
307 314 view.chart()->addSeries(series);
308 315 view.show();
309 316 QTest::qWaitForWindowShown(&view);
310 317
311 318 // first move to right top corner
312 319 QTest::mouseMove(view.viewport(), QPoint(200, 0));
313 320 QCoreApplication::processEvents(QEventLoop::AllEvents, 1000);
314 321
315 322 // move inside the slice
316 323 // pie rectangle: QRectF(60,60 121x121)
317 324 QSignalSpy hoverSpy(series, SIGNAL(hovered(QPieSlice*,bool)));
318 325 QTest::mouseMove(view.viewport(), QPoint(139, 85));
319 326 TRY_COMPARE(hoverSpy.count(), 1);
320 327 QCOMPARE(qvariant_cast<QPieSlice*>(hoverSpy.at(0).at(0)), s1);
321 328 QCOMPARE(qvariant_cast<bool>(hoverSpy.at(0).at(1)), true);
322 329
323 330 // move outside the slice
324 331 QTest::mouseMove(view.viewport(), QPoint(200, 0));
325 332 TRY_COMPARE(hoverSpy.count(), 2);
326 333 QCOMPARE(qvariant_cast<QPieSlice*>(hoverSpy.at(1).at(0)), s1);
327 334 QCOMPARE(qvariant_cast<bool>(hoverSpy.at(1).at(1)), false);
328 335 }
329 336
330 337 void tst_qpieseries::model()
331 338 {
332 339 QSKIP("Needs to be checked again. Model implementation changed", SkipAll);
333 340
334 341 QPieSeries *series = new QPieSeries;
335 342 QChart *chart = new QChart;
336 343 chart->addSeries(series);
337 344 QChartView *chartView = new QChartView(chart);
338 345 chartView->show();
339 346
340 347 QStandardItemModel *stdModel = new QStandardItemModel(0, 2);
341 348 series->setModel(stdModel);
342 349
343 350 int rowCount = 3;
344 351 for (int row = 0; row < rowCount; ++row) {
345 352 for (int column = 0; column < 2; column++) {
346 353 QStandardItem *item = new QStandardItem(row * column);
347 354 stdModel->setItem(row, column, item);
348 355 }
349 356 }
350 357
351 358 // data has been added to the model, but mapper is not set the number of slices should still be 0
352 359 QVERIFY2(series->slices().count() == 0, "Mapper has not been set, so the number of slices should be 0");
353 360
354 361 // set the mapper
355 362 QPieModelMapper *mapper = series->modelMapper();//new QPieModelMapper;
356 363 mapper->setMapValues(0);
357 364 mapper->setMapLabels(0);
358 365 // series->setModelMapper(mapper); // this should cause the Pie to get initialized from the model, since there is now both the model and the mapper defined
359 366 QCOMPARE(series->slices().count(), rowCount);
360 367
361 368 // set the mappings to be outside of the model
362 369 mapper->setMapLabels(5);
363 370 mapper->setMapValues(4);
364 371 QCOMPARE(series->slices().count(), 0); // Mappings are invalid, so the number of slices should be 0
365 372
366 373 // set back to correct ones
367 374 mapper->setMapValues(0);
368 375 mapper->setMapLabels(0);
369 376 QCOMPARE(series->slices().count(), rowCount);
370 377
371 378 // reset the mappings
372 379 mapper->reset();
373 380 QCOMPARE(series->slices().count(), 0); // Mappings have been reset and are invalid, so the number of slices should be 0
374 381
375 382 // unset the model and the mapper
376 383 series->setModel(0);
377 384 // series->setModelMapper(0);
378 385 QVERIFY(series->model() == 0); // Model should be unset
379 386 // QVERIFY(series->modelMapper() == 0); // Model mapper should be unset
380 387 }
381 388
382 389 void tst_qpieseries::modelCustomMap()
383 390 {
384 391 QSKIP("Needs to be checked again. Model implementation changed", SkipAll);
385 392
386 393 int rowCount = 12;
387 394 int columnCount = 3;
388 395 QStandardItemModel *stdModel = new QStandardItemModel(0, 3);
389 396 for (int row = 0; row < rowCount; ++row) {
390 397 for (int column = 0; column < 2; column++) {
391 398 QStandardItem *item = new QStandardItem(row * column);
392 399 stdModel->setItem(row, column, item);
393 400 }
394 401 }
395 402
396 403 QPieSeries *series = new QPieSeries;
397 404 QChart *chart = new QChart;
398 405 chart->addSeries(series);
399 406 QChartView *chartView = new QChartView(chart);
400 407 chartView->show();
401 408 series->setModel(stdModel);
402 409
403 410 QPieModelMapper *mapper = series->modelMapper();//new QPieModelMapper;
404 411 mapper->setMapValues(0);
405 412 mapper->setMapLabels(0);
406 413 // series->setModelMapper(mapper);
407 414 QCOMPARE(series->slices().count(), rowCount);
408 415
409 416 // lets change the orientation to horizontal
410 417 mapper->setOrientation(Qt::Horizontal);
411 418 QCOMPARE(series->slices().count(), columnCount);
412 419
413 420 // change it back to vertical
414 421 mapper->setOrientation(Qt::Vertical);
415 422 QCOMPARE(series->slices().count(), rowCount);
416 423
417 424 // lets customize the mapping
418 425 int first = 3;
419 426 mapper->setFirst(first);
420 427 QCOMPARE(series->slices().count(), rowCount - first);
421 428 int count = 7;
422 429 mapper->setCount(count);
423 430 QCOMPARE(series->slices().count(), count);
424 431 first = 9;
425 432 mapper->setFirst(first);
426 433 QCOMPARE(series->slices().count(), qMin(count, rowCount - first));
427 434 }
428 435
429 436 void tst_qpieseries::modelUpdate()
430 437 {
431 438 QSKIP("Needs to be checked again. Model implementation changed", SkipAll);
432 439
433 440 int rowCount = 12;
434 441 int columnCount = 7;
435 442 QStandardItemModel *stdModel = new QStandardItemModel(rowCount, columnCount);
436 443 for (int row = 0; row < rowCount; ++row) {
437 444 for (int column = 0; column < columnCount; column++) {
438 445 QStandardItem *item = new QStandardItem(row * column);
439 446 stdModel->setItem(row, column, item);
440 447 }
441 448 }
442 449
443 450 QPieSeries *series = new QPieSeries;
444 451 QChart *chart = new QChart;
445 452 chart->addSeries(series);
446 453 QChartView *chartView = new QChartView(chart);
447 454 chartView->show();
448 455 series->setModel(stdModel);
449 456
450 457 QPieModelMapper *mapper = series->modelMapper();//new QPieModelMapper;
451 458 mapper->setMapValues(0);
452 459 mapper->setMapLabels(0);
453 460 // series->setModelMapper(mapper);
454 461
455 462 stdModel->insertRows(3, 5);
456 463 QCOMPARE(series->slices().count(), rowCount + 5);
457 464
458 465 stdModel->removeRows(10, 5);
459 466 QCOMPARE(series->slices().count(), rowCount);
460 467
461 468 // limit the number of slices taken from the model to 12
462 469 mapper->setCount(rowCount);
463 470 stdModel->insertRows(3, 5);
464 471 QCOMPARE(series->slices().count(), rowCount);
465 472
466 473 stdModel->removeRows(0, 10);
467 474 QCOMPARE(series->slices().count(), rowCount - 5);
468 475
469 476 // change the orientation to horizontal
470 477 mapper->setOrientation(Qt::Horizontal);
471 478 QCOMPARE(series->slices().count(), columnCount);
472 479
473 480 stdModel->insertColumns(3, 10);
474 481 QCOMPARE(series->slices().count(), rowCount); // count is limited to rowCount (12)
475 482
476 483 stdModel->removeColumns(5, 10);
477 484 QCOMPARE(series->slices().count(), columnCount);
478 485
479 486 }
480 487
481 488 QTEST_MAIN(tst_qpieseries)
482 489
483 490 #include "tst_qpieseries.moc"
484 491
General Comments 0
You need to be logged in to leave comments. Login now