##// END OF EJS Templates
Polish QPieSlice API by removing the DataPtr stuff
Jani Honkonen -
r822:924499b21823
parent child
Show More
@@ -1,393 +1,393
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 "charttheme_p.h"
22 22 #include "qchart.h"
23 23 #include "qchartview.h"
24 24 #include "qlegend.h"
25 25 #include "qchartaxis.h"
26 26 #include <QTime>
27 27
28 28 //series
29 29 #include "qbarset.h"
30 30 #include "qbarseries.h"
31 31 #include "qstackedbarseries.h"
32 32 #include "qpercentbarseries.h"
33 33 #include "qlineseries.h"
34 34 #include "qareaseries.h"
35 35 #include "qscatterseries.h"
36 36 #include "qpieseries.h"
37 37 #include "qpieslice.h"
38 38 #include "qsplineseries.h"
39 39
40 40 //items
41 41 #include "axisitem_p.h"
42 42 #include "barchartitem_p.h"
43 43 #include "stackedbarchartitem_p.h"
44 44 #include "percentbarchartitem_p.h"
45 45 #include "linechartitem_p.h"
46 46 #include "areachartitem_p.h"
47 47 #include "scatterchartitem_p.h"
48 48 #include "piechartitem_p.h"
49 49 #include "splinechartitem_p.h"
50 50
51 51 //themes
52 52 #include "chartthemedefault_p.h"
53 53 #include "chartthemelight_p.h"
54 54 #include "chartthemebluecerulean_p.h"
55 55 #include "chartthemedark_p.h"
56 56 #include "chartthemebrownsand_p.h"
57 57 #include "chartthemebluencs_p.h"
58 58 #include "chartthemehighcontrast_p.h"
59 59 #include "chartthemeblueicy_p.h"
60 60
61 61 QTCOMMERCIALCHART_BEGIN_NAMESPACE
62 62
63 63 ChartTheme::ChartTheme(QChart::ChartTheme id) :
64 64 m_masterFont(QFont("arial", 12)),
65 65 m_labelFont(QFont("arial", 10)),
66 66 m_titleBrush(QColor(QRgb(0x000000))),
67 67 m_axisLinePen(QPen(QRgb(0x000000))),
68 68 m_axisLabelBrush(QColor(QRgb(0x000000))),
69 69 m_backgroundShadesPen(Qt::NoPen),
70 70 m_backgroundShadesBrush(Qt::NoBrush),
71 71 m_backgroundShades(BackgroundShadesNone),
72 72 m_gridLinePen(QPen(QRgb(0x000000)))
73 73 {
74 74 m_id = id;
75 75 qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
76 76 }
77 77
78 78
79 79 ChartTheme* ChartTheme::createTheme(QChart::ChartTheme theme)
80 80 {
81 81 switch(theme) {
82 82 case QChart::ChartThemeLight:
83 83 return new ChartThemeLight();
84 84 case QChart::ChartThemeBlueCerulean:
85 85 return new ChartThemeBlueCerulean();
86 86 case QChart::ChartThemeDark:
87 87 return new ChartThemeDark();
88 88 case QChart::ChartThemeBrownSand:
89 89 return new ChartThemeBrownSand();
90 90 case QChart::ChartThemeBlueNcs:
91 91 return new ChartThemeBlueNcs();
92 92 case QChart::ChartThemeHighContrast:
93 93 return new ChartThemeHighContrast();
94 94 case QChart::ChartThemeBlueIcy:
95 95 return new ChartThemeBlueIcy();
96 96 default:
97 97 return new ChartThemeDefault();
98 98 }
99 99 }
100 100
101 101 void ChartTheme::decorate(QChart* chart,bool force)
102 102 {
103 103 QBrush brush;
104 104
105 105 if(brush == chart->backgroundBrush() || force)
106 106 chart->setBackgroundBrush(m_chartBackgroundGradient);
107 107 chart->setTitleFont(m_masterFont);
108 108 chart->setTitleBrush(m_titleBrush);
109 109 }
110 110
111 111 void ChartTheme::decorate(QLegend* legend,bool force)
112 112 {
113 113 QPen pen;
114 114 QBrush brush;
115 115
116 116 if (pen == legend->pen() || force){
117 117 legend->setPen(Qt::NoPen);
118 118 }
119 119
120 120
121 121 if (brush == legend->brush() || force) {
122 122 legend->setBrush(m_chartBackgroundGradient);
123 123 }
124 124 }
125 125
126 126 void ChartTheme::decorate(QAreaSeries* series, int index,bool force)
127 127 {
128 128 QPen pen;
129 129 QBrush brush;
130 130
131 131 if (pen == series->pen() || force){
132 132 pen.setColor(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0.0));
133 133 pen.setWidthF(2);
134 134 series->setPen(pen);
135 135 }
136 136
137 137 if (brush == series->brush() || force) {
138 138 QBrush brush(m_seriesColors.at(index % m_seriesColors.size()));
139 139 series->setBrush(brush);
140 140 }
141 141 }
142 142
143 143
144 144 void ChartTheme::decorate(QLineSeries* series,int index,bool force)
145 145 {
146 146 QPen pen;
147 147 if(pen == series->pen() || force ){
148 148 pen.setColor(m_seriesColors.at(index%m_seriesColors.size()));
149 149 pen.setWidthF(2);
150 150 series->setPen(pen);
151 151 }
152 152 }
153 153
154 154 void ChartTheme::decorate(QBarSeries* series, int index, bool force)
155 155 {
156 156 QBrush brush;
157 157 QPen pen;
158 158 QList<QBarSet*> sets = series->barSets();
159 159
160 160 qreal takeAtPos = 0.5;
161 161 qreal step = 0.2;
162 162 if (sets.count() > 1 ) {
163 163 step = 1.0 / (qreal) sets.count();
164 164 if (sets.count() % m_seriesGradients.count())
165 165 step *= m_seriesGradients.count();
166 166 else
167 167 step *= (m_seriesGradients.count() - 1);
168 168 }
169 169
170 170 for (int i(0); i < sets.count(); i++) {
171 171 int colorIndex = (index + i) % m_seriesGradients.count();
172 172 if (i > 0 && i % m_seriesGradients.count() == 0) {
173 173 // There is no dedicated base color for each sets, generate more colors
174 174 takeAtPos += step;
175 175 if (takeAtPos == 1.0)
176 176 takeAtPos += step;
177 177 takeAtPos -= (int) takeAtPos;
178 178 }
179 179 qDebug() << "pos:" << takeAtPos;
180 180 if (brush == sets.at(i)->brush() || force )
181 181 sets.at(i)->setBrush(colorAt(m_seriesGradients.at(colorIndex), takeAtPos));
182 182
183 183 // Pick label color from the opposite end of the gradient.
184 184 // 0.3 as a boundary seems to work well.
185 185 if (takeAtPos < 0.3)
186 186 sets.at(i)->setLabelBrush(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 1));
187 187 else
188 188 sets.at(i)->setLabelBrush(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0));
189 189
190 190 if (pen == sets.at(i)->pen() || force) {
191 191 QColor c = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0.0);
192 192 sets.at(i)->setPen(c);
193 193 }
194 194 }
195 195 }
196 196
197 197 void ChartTheme::decorate(QScatterSeries* series, int index,bool force)
198 198 {
199 199 QPen pen;
200 200 QBrush brush;
201 201
202 202 if (pen == series->pen() || force) {
203 203 pen.setColor(colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0.0));
204 204 pen.setWidthF(2);
205 205 series->setPen(pen);
206 206 }
207 207
208 208 if (brush == series->brush() || force) {
209 209 QBrush brush(m_seriesColors.at(index % m_seriesColors.size()));
210 210 series->setBrush(brush);
211 211 }
212 212 }
213 213
214 214 void ChartTheme::decorate(QPieSeries* series, int index, bool force)
215 215 {
216 216
217 217 for (int i(0); i < series->slices().count(); i++) {
218 218
219 219 QColor penColor = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), 0.0);
220 220
221 221 // Get color for a slice from a gradient linearly, beginning from the start of the gradient
222 222 qreal pos = (qreal) (i + 1) / (qreal) series->count();
223 223 QColor brushColor = colorAt(m_seriesGradients.at(index % m_seriesGradients.size()), pos);
224 224
225 225 QPieSlice *s = series->slices().at(i);
226 PieSliceData data = *s->data_ptr();
226 PieSliceData data = PieSliceData::data(s);
227 227
228 228 if (data.m_slicePen.isThemed() || force) {
229 229 data.m_slicePen = penColor;
230 230 data.m_slicePen.setThemed(true);
231 231 }
232 232
233 233 if (data.m_sliceBrush.isThemed() || force) {
234 234 data.m_sliceBrush = brushColor;
235 235 data.m_sliceBrush.setThemed(true);
236 236 }
237 237
238 238 if (data.m_labelPen.isThemed() || force) {
239 239 data.m_labelPen = QPen(m_titleBrush.color());
240 240 data.m_labelPen.setThemed(true);
241 241 }
242 242
243 243 if (data.m_labelFont.isThemed() || force) {
244 244 data.m_labelFont = m_labelFont;
245 245 data.m_labelFont.setThemed(true);
246 246 }
247 247
248 if (*s->data_ptr() != data) {
249 *s->data_ptr() = data;
250 emit s->data_ptr()->emitChangedSignal(s);
248 if (PieSliceData::data(s) != data) {
249 PieSliceData::data(s) = data;
250 emit PieSliceData::data(s).emitChangedSignal(s);
251 251 }
252 252 }
253 253 }
254 254
255 255 void ChartTheme::decorate(QSplineSeries* series, int index, bool force)
256 256 {
257 257 QPen pen;
258 258 if(pen == series->pen() || force){
259 259 pen.setColor(m_seriesColors.at(index%m_seriesColors.size()));
260 260 pen.setWidthF(2);
261 261 series->setPen(pen);
262 262 }
263 263 }
264 264
265 265 void ChartTheme::decorate(QChartAxis* axis,bool axisX, bool force)
266 266 {
267 267 QPen pen;
268 268 QBrush brush;
269 269 QFont font;
270 270
271 271 if (axis->isAxisVisible()) {
272 272
273 273 if(brush == axis->labelsBrush() || force){
274 274 axis->setLabelsBrush(m_axisLabelBrush);
275 275 }
276 276 if(pen == axis->labelsPen() || force){
277 277 axis->setLabelsPen(Qt::NoPen); // NoPen for performance reasons
278 278 }
279 279
280 280
281 281 if (axis->shadesVisible() || force) {
282 282
283 283 if(brush == axis->shadesBrush() || force){
284 284 axis->setShadesBrush(m_backgroundShadesBrush);
285 285 }
286 286
287 287 if(pen == axis->shadesPen() || force){
288 288 axis->setShadesPen(m_backgroundShadesPen);
289 289 }
290 290
291 291 if(force && (m_backgroundShades == BackgroundShadesBoth
292 292 || (m_backgroundShades == BackgroundShadesVertical && axisX)
293 293 || (m_backgroundShades == BackgroundShadesHorizontal && !axisX))){
294 294 axis->setShadesVisible(true);
295 295
296 296 }
297 297 }
298 298
299 299 if(pen == axis->axisPen() || force){
300 300 axis->setAxisPen(m_axisLinePen);
301 301 }
302 302
303 303 if(pen == axis->gridLinePen() || force){
304 304 axis->setGridLinePen(m_gridLinePen);
305 305 }
306 306
307 307 if(font == axis->labelsFont() || force){
308 308 axis->setLabelsFont(m_labelFont);
309 309 }
310 310 }
311 311 }
312 312
313 313 void ChartTheme::generateSeriesGradients()
314 314 {
315 315 // Generate gradients in HSV color space
316 316 foreach (QColor color, m_seriesColors) {
317 317 QLinearGradient g;
318 318 qreal h = color.hsvHueF();
319 319 qreal s = color.hsvSaturationF();
320 320
321 321 // TODO: tune the algorithm to give nice results with most base colors defined in
322 322 // most themes. The rest of the gradients we can define manually in theme specific
323 323 // implementation.
324 324 QColor start = color;
325 325 start.setHsvF(h, 0.0, 1.0);
326 326 g.setColorAt(0.0, start);
327 327
328 328 g.setColorAt(0.5, color);
329 329
330 330 QColor end = color;
331 331 end.setHsvF(h, s, 0.25);
332 332 g.setColorAt(1.0, end);
333 333
334 334 m_seriesGradients << g;
335 335 }
336 336 }
337 337
338 338
339 339 QColor ChartTheme::colorAt(const QColor &start, const QColor &end, qreal pos)
340 340 {
341 341 Q_ASSERT(pos >=0.0 && pos <= 1.0);
342 342 qreal r = start.redF() + ((end.redF() - start.redF()) * pos);
343 343 qreal g = start.greenF() + ((end.greenF() - start.greenF()) * pos);
344 344 qreal b = start.blueF() + ((end.blueF() - start.blueF()) * pos);
345 345 QColor c;
346 346 c.setRgbF(r, g, b);
347 347 return c;
348 348 }
349 349
350 350 QColor ChartTheme::colorAt(const QGradient &gradient, qreal pos)
351 351 {
352 352 Q_ASSERT(pos >=0 && pos <= 1.0);
353 353
354 354 // another possibility:
355 355 // http://stackoverflow.com/questions/3306786/get-intermediate-color-from-a-gradient
356 356
357 357 QGradientStops stops = gradient.stops();
358 358 int count = stops.count();
359 359
360 360 // find previous stop relative to position
361 361 QGradientStop prev = stops.first();
362 362 for (int i=0; i<count; i++) {
363 363 QGradientStop stop = stops.at(i);
364 364 if (pos > stop.first)
365 365 prev = stop;
366 366
367 367 // given position is actually a stop position?
368 368 if (pos == stop.first) {
369 369 //qDebug() << "stop color" << pos;
370 370 return stop.second;
371 371 }
372 372 }
373 373
374 374 // find next stop relative to position
375 375 QGradientStop next = stops.last();
376 376 for (int i=count-1; i>=0; i--) {
377 377 QGradientStop stop = stops.at(i);
378 378 if (pos < stop.first)
379 379 next = stop;
380 380 }
381 381
382 382 //qDebug() << "prev" << prev.first << "pos" << pos << "next" << next.first;
383 383
384 384 qreal range = next.first - prev.first;
385 385 qreal posDelta = pos - prev.first;
386 386 qreal relativePos = posDelta / range;
387 387
388 388 //qDebug() << "range" << range << "posDelta" << posDelta << "relativePos" << relativePos;
389 389
390 390 return colorAt(prev.second, next.second, relativePos);
391 391 }
392 392
393 393 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,211 +1,211
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 "piechartitem_p.h"
22 22 #include "piesliceitem_p.h"
23 23 #include "qpieslice.h"
24 24 #include "qpieseries.h"
25 25 #include "chartpresenter_p.h"
26 26 #include "chartdataset_p.h"
27 27 #include "chartanimator_p.h"
28 28 #include <QDebug>
29 29 #include <QPainter>
30 30 #include <QTimer>
31 31
32 32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 33
34 34 PieChartItem::PieChartItem(QPieSeries *series, ChartPresenter* presenter)
35 35 :ChartItem(presenter),
36 36 m_series(series)
37 37 {
38 38 Q_ASSERT(series);
39 39 connect(series, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
40 40 connect(series, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
41 41 connect(series, SIGNAL(piePositionChanged()), this, SLOT(handlePieLayoutChanged()));
42 42 connect(series, SIGNAL(pieSizeChanged()), this, SLOT(handlePieLayoutChanged()));
43 43
44 44 QTimer::singleShot(0, this, SLOT(initialize()));
45 45
46 46 // Note: the following does not affect as long as the item does not have anything to paint
47 47 setZValue(ChartPresenter::PieSeriesZValue);
48 48 }
49 49
50 50 PieChartItem::~PieChartItem()
51 51 {
52 52 // slices deleted automatically through QGraphicsItem
53 53 }
54 54
55 55 void PieChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
56 56 {
57 57 Q_UNUSED(painter)
58 58 // TODO: paint shadows for all components
59 59 // - get paths from items & merge & offset and draw with shadow color?
60 60 //painter->setBrush(QBrush(Qt::red));
61 61 //painter->drawRect(m_debugRect);
62 62 }
63 63
64 64 void PieChartItem::initialize()
65 65 {
66 66 handleSlicesAdded(m_series->slices());
67 67 }
68 68
69 69 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
70 70 {
71 71 bool isEmpty = m_slices.isEmpty();
72 72
73 73 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series), false);
74 74
75 75 foreach (QPieSlice *s, slices) {
76 76 PieSliceItem* item = new PieSliceItem(this);
77 77 m_slices.insert(s, item);
78 78 connect(s, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
79 79 connect(item, SIGNAL(clicked(Qt::MouseButtons)), s, SIGNAL(clicked(Qt::MouseButtons)));
80 80 connect(item, SIGNAL(hoverEnter()), s, SIGNAL(hoverEnter()));
81 81 connect(item, SIGNAL(hoverLeave()), s, SIGNAL(hoverLeave()));
82 82
83 83 PieSliceData data = sliceData(s);
84 84
85 85 if (animator())
86 86 animator()->addAnimation(this, s, data, isEmpty);
87 87 else
88 88 setLayout(s, data);
89 89 }
90 90 }
91 91
92 92 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
93 93 {
94 94 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series), false);
95 95
96 96 foreach (QPieSlice *s, slices) {
97 97 if (animator())
98 98 animator()->removeAnimation(this, s);
99 99 else
100 100 destroySlice(s);
101 101 }
102 102 }
103 103
104 104 void PieChartItem::handlePieLayoutChanged()
105 105 {
106 106 PieLayout layout = calculateLayout();
107 107 applyLayout(layout);
108 108 update();
109 109 }
110 110
111 111 void PieChartItem::handleSliceChanged()
112 112 {
113 113 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
114 114 Q_ASSERT(m_slices.contains(slice));
115 115 PieSliceData data = sliceData(slice);
116 116 updateLayout(slice, data);
117 117 update();
118 118 }
119 119
120 120 void PieChartItem::handleDomainChanged(qreal, qreal, qreal, qreal)
121 121 {
122 122 // TODO
123 123 }
124 124
125 125 void PieChartItem::handleGeometryChanged(const QRectF& rect)
126 126 {
127 127 prepareGeometryChange();
128 128 m_rect = rect;
129 129 handlePieLayoutChanged();
130 130 }
131 131
132 132 void PieChartItem::calculatePieLayout()
133 133 {
134 134 // find pie center coordinates
135 135 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->pieHorizontalPosition()));
136 136 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->pieVerticalPosition()));
137 137
138 138 // find maximum radius for pie
139 139 m_pieRadius = m_rect.height() / 2;
140 140 if (m_rect.width() < m_rect.height())
141 141 m_pieRadius = m_rect.width() / 2;
142 142
143 143 // apply size factor
144 144 m_pieRadius *= m_series->pieSize();
145 145 }
146 146
147 147 PieSliceData PieChartItem::sliceData(QPieSlice *slice)
148 148 {
149 149 // TODO: This function is kid of useless now. Refactor.
150 PieSliceData sliceData = *slice->data_ptr();
150 PieSliceData sliceData = PieSliceData::data(slice);
151 151 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
152 152 sliceData.m_radius = m_pieRadius;
153 153 return sliceData;
154 154 }
155 155
156 156 PieLayout PieChartItem::calculateLayout()
157 157 {
158 158 calculatePieLayout();
159 159 PieLayout layout;
160 160 foreach (QPieSlice* s, m_series->slices()) {
161 161 if (m_slices.contains(s)) // calculate layout only for those slices that are already visible
162 162 layout.insert(s, sliceData(s));
163 163 }
164 164 return layout;
165 165 }
166 166
167 167 void PieChartItem::applyLayout(const PieLayout &layout)
168 168 {
169 169 if (animator())
170 170 animator()->updateLayout(this, layout);
171 171 else
172 172 setLayout(layout);
173 173 }
174 174
175 175 void PieChartItem::updateLayout(QPieSlice *slice, const PieSliceData &sliceData)
176 176 {
177 177 if (animator())
178 178 animator()->updateLayout(this, slice, sliceData);
179 179 else
180 180 setLayout(slice, sliceData);
181 181 }
182 182
183 183 void PieChartItem::setLayout(const PieLayout &layout)
184 184 {
185 185 foreach (QPieSlice *slice, layout.keys()) {
186 186 PieSliceItem *item = m_slices.value(slice);
187 187 Q_ASSERT(item);
188 188 item->setSliceData(layout.value(slice));
189 189 item->updateGeometry();
190 190 item->update();
191 191 }
192 192 }
193 193
194 194 void PieChartItem::setLayout(QPieSlice *slice, const PieSliceData &sliceData)
195 195 {
196 196 // find slice
197 197 PieSliceItem *item = m_slices.value(slice);
198 198 Q_ASSERT(item);
199 199 item->setSliceData(sliceData);
200 200 item->updateGeometry();
201 201 item->update();
202 202 }
203 203
204 204 void PieChartItem::destroySlice(QPieSlice *slice)
205 205 {
206 206 delete m_slices.take(slice);
207 207 }
208 208
209 209 #include "moc_piechartitem_p.cpp"
210 210
211 211 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,136 +1,142
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 #ifndef PIESLICEDATA_P_H
22 22 #define PIESLICEDATA_P_H
23 23
24 24 #include "qchartglobal.h"
25 25 #include "qpieslice.h"
26 26 #include <QPen>
27 27 #include <QBrush>
28 28 #include <QDebug>
29 29
30 30 QTCOMMERCIALCHART_BEGIN_NAMESPACE
31 31
32 32 template <class T>
33 33 class Themed : public T
34 34 {
35 35 public:
36 36 Themed():m_isThemed(true) {}
37 37
38 38 inline T &operator=(const T &other) { return T::operator =(other); }
39 39
40 40 inline bool operator!=(const T &other) const { return T::operator !=(other); }
41 41 inline bool operator!=(const Themed &other) const
42 42 {
43 43 if (T::operator !=(other))
44 44 return true;
45 45
46 46 if (m_isThemed != other.m_isThemed)
47 47 return true;
48 48
49 49 return false;
50 50 }
51 51
52 52 inline void setThemed(bool state) { m_isThemed = state; }
53 53 inline bool isThemed() const { return m_isThemed; }
54 54
55 55 private:
56 56 bool m_isThemed;
57 57 };
58 58
59 59 class PieSliceData
60 60 {
61 61 public:
62 62 PieSliceData()
63 63 {
64 64 m_value = 0;
65 65
66 66 m_isExploded = false;
67 67 m_explodeDistanceFactor = 0.15;
68 68
69 69 m_isLabelVisible = false;
70 70 m_labelArmLengthFactor = 0.15;
71 71
72 72 m_percentage = 0;
73 73 m_radius = 0;
74 74 m_startAngle = 0;
75 75 m_angleSpan = 0;
76 76 }
77 77
78 78 bool operator!=(const PieSliceData &other) const
79 79 {
80 80 if (!qFuzzyIsNull(m_value - other.m_value))
81 81 return true;
82 82
83 83 if (m_slicePen != other.m_slicePen ||
84 84 m_sliceBrush != other.m_sliceBrush)
85 85 return true;
86 86
87 87 if (m_isExploded != other.m_isExploded ||
88 88 !qFuzzyIsNull(m_explodeDistanceFactor - other.m_explodeDistanceFactor))
89 89 return true;
90 90
91 91 if (m_isLabelVisible != other.m_isLabelVisible ||
92 92 m_labelText != other.m_labelText ||
93 93 m_labelFont != other.m_labelFont ||
94 94 !qFuzzyIsNull(m_labelArmLengthFactor - other.m_labelArmLengthFactor) ||
95 95 m_labelPen != other.m_labelPen)
96 96 return true;
97 97
98 98 if (!qFuzzyIsNull(m_percentage - other.m_percentage) ||
99 99 m_center != other.m_center ||
100 100 !qFuzzyIsNull(m_radius - other.m_radius) ||
101 101 !qFuzzyIsNull(m_startAngle - other.m_startAngle) ||
102 102 !qFuzzyIsNull(m_angleSpan - other.m_angleSpan))
103 103 return true;
104 104
105 105 return false;
106 106 }
107 107
108 108 void emitChangedSignal(QPieSlice *s)
109 109 {
110 110 emit s->changed();
111 111 }
112 112
113 static PieSliceData &data(QPieSlice *slice)
114 {
115 Q_ASSERT(slice);
116 return *slice->d;
117 }
118
113 119 qreal m_value;
114 120
115 121 Themed<QPen> m_slicePen;
116 122 Themed<QBrush> m_sliceBrush;
117 123
118 124 bool m_isExploded;
119 125 qreal m_explodeDistanceFactor;
120 126
121 127 bool m_isLabelVisible;
122 128 QString m_labelText;
123 129 Themed<QFont> m_labelFont;
124 130 qreal m_labelArmLengthFactor;
125 131 Themed<QPen> m_labelPen;
126 132
127 133 qreal m_percentage;
128 134 QPointF m_center;
129 135 qreal m_radius;
130 136 qreal m_startAngle;
131 137 qreal m_angleSpan;
132 138 };
133 139
134 140 QTCOMMERCIALCHART_END_NAMESPACE
135 141
136 142 #endif // PIESLICEDATA_P_H
@@ -1,694 +1,694
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 "qpieseriesprivate_p.h"
23 23 #include "qpieslice.h"
24 24 #include "pieslicedata_p.h"
25 25 #include <QDebug>
26 26
27 27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 28
29 29 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent)
30 30 :QObject(parent),
31 31 q_ptr(parent),
32 32 m_pieRelativeHorPos(0.5),
33 33 m_pieRelativeVerPos(0.5),
34 34 m_pieRelativeSize(0.7),
35 35 m_pieStartAngle(0),
36 36 m_pieEndAngle(360),
37 37 m_total(0),
38 38 m_mapValues(0),
39 39 m_mapLabels(0),
40 40 m_mapOrientation(Qt::Horizontal)
41 41 {
42 42
43 43 }
44 44
45 45 QPieSeriesPrivate::~QPieSeriesPrivate()
46 46 {
47 47
48 48 }
49 49
50 50 void QPieSeriesPrivate::updateDerivativeData()
51 51 {
52 52 m_total = 0;
53 53
54 54 // nothing to do?
55 55 if (m_slices.count() == 0)
56 56 return;
57 57
58 58 // calculate total
59 59 foreach (QPieSlice* s, m_slices)
60 60 m_total += s->value();
61 61
62 62 // nothing to show..
63 63 if (qFuzzyIsNull(m_total))
64 64 return;
65 65
66 66 // update slice attributes
67 67 qreal sliceAngle = m_pieStartAngle;
68 68 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
69 69 QVector<QPieSlice*> changed;
70 70 foreach (QPieSlice* s, m_slices) {
71 71
72 PieSliceData data = *s->data_ptr();
72 PieSliceData data = PieSliceData::data(s);
73 73 data.m_percentage = s->value() / m_total;
74 74 data.m_angleSpan = pieSpan * data.m_percentage;
75 75 data.m_startAngle = sliceAngle;
76 76 sliceAngle += data.m_angleSpan;
77 77
78 if (*s->data_ptr() != data) {
79 *s->data_ptr() = data;
78 if (PieSliceData::data(s) != data) {
79 PieSliceData::data(s) = data;
80 80 changed << s;
81 81 }
82 82 }
83 83
84 84 // emit signals
85 85 foreach (QPieSlice* s, changed)
86 s->data_ptr()->emitChangedSignal(s);
86 PieSliceData::data(s).emitChangedSignal(s);
87 87 }
88 88
89 89 void QPieSeriesPrivate::sliceChanged()
90 90 {
91 91 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
92 92 updateDerivativeData();
93 93 }
94 94
95 95 void QPieSeriesPrivate::sliceClicked(Qt::MouseButtons buttons)
96 96 {
97 97 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
98 98 Q_ASSERT(m_slices.contains(slice));
99 99 Q_Q(QPieSeries);
100 100 emit q->clicked(slice, buttons);
101 101 }
102 102
103 103 void QPieSeriesPrivate::sliceHoverEnter()
104 104 {
105 105 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
106 106 Q_ASSERT(m_slices.contains(slice));
107 107 Q_Q(QPieSeries);
108 108 emit q->hoverEnter(slice);
109 109 }
110 110
111 111 void QPieSeriesPrivate::sliceHoverLeave()
112 112 {
113 113 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
114 114 Q_ASSERT(m_slices.contains(slice));
115 115 Q_Q(QPieSeries);
116 116 emit q->hoverLeave(slice);
117 117 }
118 118
119 119 void QPieSeriesPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
120 120 {
121 121 Q_UNUSED(bottomRight)
122 122 Q_Q(QPieSeries);
123 123
124 124 if (m_mapOrientation == Qt::Vertical)
125 125 {
126 126 // slices().at(topLeft.row())->setValue(m_model->data(m_model->index(topLeft.row(), topLeft.column()), Qt::DisplayRole).toDouble());
127 127 if (topLeft.column() == m_mapValues)
128 128 if (m_mapValues == m_mapLabels)
129 129 {
130 130 m_slices.at(topLeft.row())->setValue(q->m_model->data(topLeft, Qt::DisplayRole).toDouble());
131 131 m_slices.at(topLeft.row())->setLabel(q->m_model->data(topLeft, Qt::DisplayRole).toString());
132 132 }
133 133 else
134 134 {
135 135 m_slices.at(topLeft.row())->setValue(q->m_model->data(topLeft, Qt::DisplayRole).toDouble());
136 136 }
137 137 else if (topLeft.column() == m_mapLabels)
138 138 m_slices.at(topLeft.row())->setLabel(q->m_model->data(topLeft, Qt::DisplayRole).toString());
139 139 }
140 140 else
141 141 {
142 142 // slices().at(topLeft.column())->setValue(m_model->data(m_model->index(topLeft.row(), topLeft.column()), Qt::DisplayRole).toDouble());
143 143 if (topLeft.row() == m_mapValues)
144 144 if (m_mapValues == m_mapLabels)
145 145 {
146 146 m_slices.at(topLeft.column())->setValue(q->m_model->data(topLeft, Qt::DisplayRole).toDouble());
147 147 m_slices.at(topLeft.column())->setLabel(q->m_model->data(topLeft, Qt::DisplayRole).toString());
148 148 }
149 149 else
150 150 {
151 151 m_slices.at(topLeft.column())->setValue(q->m_model->data(topLeft, Qt::DisplayRole).toDouble());
152 152 }
153 153 else if (topLeft.row() == m_mapLabels)
154 154 m_slices.at(topLeft.column())->setLabel(q->m_model->data(topLeft, Qt::DisplayRole).toString());
155 155 }
156 156 }
157 157
158 158 void QPieSeriesPrivate::modelDataAdded(QModelIndex parent, int start, int end)
159 159 {
160 160 Q_UNUSED(parent)
161 161 Q_UNUSED(end)
162 162 Q_Q(QPieSeries);
163 163
164 164 QPieSlice* newSlice = new QPieSlice;
165 165 newSlice->setLabelVisible(true);
166 166 if (m_mapOrientation == Qt::Vertical)
167 167 {
168 168 newSlice->setValue(q->m_model->data(q->m_model->index(start, m_mapValues), Qt::DisplayRole).toDouble());
169 169 newSlice->setLabel(q->m_model->data(q->m_model->index(start, m_mapLabels), Qt::DisplayRole).toString());
170 170 }
171 171 else
172 172 {
173 173 newSlice->setValue(q->m_model->data(q->m_model->index(m_mapValues, start), Qt::DisplayRole).toDouble());
174 174 newSlice->setLabel(q->m_model->data(q->m_model->index(m_mapLabels, start), Qt::DisplayRole).toString());
175 175 }
176 176
177 177 q->insert(start, newSlice);
178 178 }
179 179
180 180 void QPieSeriesPrivate::modelDataRemoved(QModelIndex parent, int start, int end)
181 181 {
182 182 Q_UNUSED(parent)
183 183 Q_UNUSED(end)
184 184 Q_Q(QPieSeries);
185 185 q->remove(m_slices.at(start));
186 186 }
187 187
188 188
189 189
190 190 /*!
191 191 \class QPieSeries
192 192 \brief Pie series API for QtCommercial Charts
193 193
194 194 The pie series defines a pie chart which consists of pie slices which are QPieSlice objects.
195 195 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
196 196 The actual slice size is determined by that relative value.
197 197
198 198 By default the pie is defined as a full pie but it can be a partial pie.
199 199 This can be done by setting a starting angle and angle span to the series.
200 200 */
201 201
202 202 /*!
203 203 Constructs a series object which is a child of \a parent.
204 204 */
205 205 QPieSeries::QPieSeries(QObject *parent) :
206 206 QSeries(parent),
207 207 d_ptr(new QPieSeriesPrivate(this))
208 208 {
209 209
210 210 }
211 211
212 212 /*!
213 213 Destroys the object. Note that adding series to QChart transfers the ownership to the chart.
214 214 */
215 215 QPieSeries::~QPieSeries()
216 216 {
217 217 // NOTE: d_prt destroyed by QObject
218 218 }
219 219
220 220 /*!
221 221 Returns QChartSeries::SeriesTypePie.
222 222 */
223 223 QSeries::QSeriesType QPieSeries::type() const
224 224 {
225 225 return QSeries::SeriesTypePie;
226 226 }
227 227
228 228 /*!
229 229 Sets an array of \a slices to the series replacing the existing slices.
230 230 Slice ownership is passed to the series.
231 231 */
232 232 void QPieSeries::replace(QList<QPieSlice*> slices)
233 233 {
234 234 clear();
235 235 append(slices);
236 236 }
237 237
238 238 /*!
239 239 Adds an array of \a slices to the series.
240 240 Slice ownership is passed to the series.
241 241 */
242 242 void QPieSeries::append(QList<QPieSlice*> slices)
243 243 {
244 244 Q_D(QPieSeries);
245 245
246 246 foreach (QPieSlice* s, slices) {
247 247 s->setParent(this);
248 248 d->m_slices << s;
249 249 }
250 250
251 251 d->updateDerivativeData();
252 252
253 253 foreach (QPieSlice* s, slices) {
254 254 connect(s, SIGNAL(changed()), d, SLOT(sliceChanged()));
255 255 connect(s, SIGNAL(clicked(Qt::MouseButtons)), d, SLOT(sliceClicked(Qt::MouseButtons)));
256 256 connect(s, SIGNAL(hoverEnter()), d, SLOT(sliceHoverEnter()));
257 257 connect(s, SIGNAL(hoverLeave()), d, SLOT(sliceHoverLeave()));
258 258 }
259 259
260 260 emit added(slices);
261 261 }
262 262
263 263 /*!
264 264 Adds a single \a slice to the series.
265 265 Slice ownership is passed to the series.
266 266 */
267 267 void QPieSeries::append(QPieSlice* slice)
268 268 {
269 269 append(QList<QPieSlice*>() << slice);
270 270 }
271 271
272 272 /*!
273 273 Adds a single \a slice to the series and returns a reference to the series.
274 274 Slice ownership is passed to the series.
275 275 */
276 276 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
277 277 {
278 278 append(slice);
279 279 return *this;
280 280 }
281 281
282 282
283 283 /*!
284 284 Appends a single slice to the series with give \a value and \a name.
285 285 Slice ownership is passed to the series.
286 286 */
287 287 QPieSlice* QPieSeries::append(qreal value, QString name)
288 288 {
289 289 QPieSlice* slice = new QPieSlice(value, name);
290 290 append(slice);
291 291 return slice;
292 292 }
293 293
294 294 /*!
295 295 Inserts a single \a slice to the series before the slice at \a index position.
296 296 Slice ownership is passed to the series.
297 297 */
298 298 void QPieSeries::insert(int index, QPieSlice* slice)
299 299 {
300 300 Q_D(QPieSeries);
301 301 Q_ASSERT(index <= d->m_slices.count());
302 302 slice->setParent(this);
303 303 d->m_slices.insert(index, slice);
304 304
305 305 d->updateDerivativeData();
306 306
307 307 connect(slice, SIGNAL(changed()), d, SLOT(sliceChanged()));
308 308 connect(slice, SIGNAL(clicked(Qt::MouseButtons)), d, SLOT(sliceClicked(Qt::MouseButtons)));
309 309 connect(slice, SIGNAL(hoverEnter()), d, SLOT(sliceHoverEnter()));
310 310 connect(slice, SIGNAL(hoverLeave()), d, SLOT(sliceHoverLeave()));
311 311
312 312 emit added(QList<QPieSlice*>() << slice);
313 313 }
314 314
315 315 /*!
316 316 Removes a single \a slice from the series and deletes the slice.
317 317
318 318 Do not reference this pointer after this call.
319 319 */
320 320 void QPieSeries::remove(QPieSlice* slice)
321 321 {
322 322 Q_D(QPieSeries);
323 323 if (!d->m_slices.removeOne(slice)) {
324 324 Q_ASSERT(0); // TODO: how should this be reported?
325 325 return;
326 326 }
327 327
328 328 d->updateDerivativeData();
329 329
330 330 emit removed(QList<QPieSlice*>() << slice);
331 331
332 332 delete slice;
333 333 slice = NULL;
334 334 }
335 335
336 336 /*!
337 337 Clears all slices from the series.
338 338 */
339 339 void QPieSeries::clear()
340 340 {
341 341 Q_D(QPieSeries);
342 342 if (d->m_slices.count() == 0)
343 343 return;
344 344
345 345 QList<QPieSlice*> slices = d->m_slices;
346 346 foreach (QPieSlice* s, d->m_slices) {
347 347 d->m_slices.removeOne(s);
348 348 delete s;
349 349 }
350 350
351 351 d->updateDerivativeData();
352 352
353 353 emit removed(slices);
354 354 }
355 355
356 356 /*!
357 357 Counts the number of the slices in this series.
358 358 */
359 359 int QPieSeries::count() const
360 360 {
361 361 Q_D(const QPieSeries);
362 362 return d->m_slices.count();
363 363 }
364 364
365 365 /*!
366 366 Returns true is the series is empty.
367 367 */
368 368 bool QPieSeries::isEmpty() const
369 369 {
370 370 Q_D(const QPieSeries);
371 371 return d->m_slices.isEmpty();
372 372 }
373 373
374 374 /*!
375 375 Returns a list of slices that belong to this series.
376 376 */
377 377 QList<QPieSlice*> QPieSeries::slices() const
378 378 {
379 379 Q_D(const QPieSeries);
380 380 return d->m_slices;
381 381 }
382 382
383 383 /*!
384 384 Sets the center position of the pie by \a relativeHorizontalPosition and \a relativeVerticalPosition.
385 385
386 386 The factors are relative to the chart rectangle where:
387 387
388 388 \a relativeHorizontalPosition 0.0 means the absolute left.
389 389 \a relativeHorizontalPosition 1.0 means the absolute right.
390 390 \a relativeVerticalPosition 0.0 means the absolute top.
391 391 \a relativeVerticalPosition 1.0 means the absolute bottom.
392 392
393 393 By default both values are 0.5 which puts the pie in the middle of the chart rectangle.
394 394
395 395 \sa pieHorizontalPosition(), pieVerticalPosition(), setPieSize()
396 396 */
397 397 void QPieSeries::setPiePosition(qreal relativeHorizontalPosition, qreal relativeVerticalPosition)
398 398 {
399 399 Q_D(QPieSeries);
400 400 if (relativeHorizontalPosition < 0.0 || relativeHorizontalPosition > 1.0 ||
401 401 relativeVerticalPosition < 0.0 || relativeVerticalPosition > 1.0)
402 402 return;
403 403
404 404 if (!qFuzzyIsNull(d->m_pieRelativeHorPos - relativeHorizontalPosition) ||
405 405 !qFuzzyIsNull(d->m_pieRelativeVerPos - relativeVerticalPosition)) {
406 406 d->m_pieRelativeHorPos = relativeHorizontalPosition;
407 407 d->m_pieRelativeVerPos = relativeVerticalPosition;
408 408 emit piePositionChanged();
409 409 }
410 410 }
411 411
412 412 /*!
413 413 Gets the horizontal position of the pie.
414 414
415 415 The returned value is relative to the chart rectangle where:
416 416
417 417 0.0 means the absolute left.
418 418 1.0 means the absolute right.
419 419
420 420 By default it is 0.5 which puts the pie in the horizontal middle of the chart rectangle.
421 421
422 422 \sa setPiePosition(), pieVerticalPosition(), setPieSize()
423 423 */
424 424 qreal QPieSeries::pieHorizontalPosition() const
425 425 {
426 426 Q_D(const QPieSeries);
427 427 return d->m_pieRelativeHorPos;
428 428 }
429 429
430 430 /*!
431 431 Gets the vertical position position of the pie.
432 432
433 433 The returned value is relative to the chart rectangle where:
434 434
435 435 0.0 means the absolute top.
436 436 1.0 means the absolute bottom.
437 437
438 438 By default it is 0.5 which puts the pie in the vertical middle of the chart rectangle.
439 439
440 440 \sa setPiePosition(), pieHorizontalPosition(), setPieSize()
441 441 */
442 442 qreal QPieSeries::pieVerticalPosition() const
443 443 {
444 444 Q_D(const QPieSeries);
445 445 return d->m_pieRelativeVerPos;
446 446 }
447 447
448 448 /*!
449 449 Sets the relative size of the pie.
450 450
451 451 The \a relativeSize is defined so that the 1.0 is the maximum that can fit the given chart rectangle.
452 452
453 453 Default value is 0.7.
454 454
455 455 \sa pieSize(), setPiePosition(), pieVerticalPosition(), pieHorizontalPosition()
456 456 */
457 457 void QPieSeries::setPieSize(qreal relativeSize)
458 458 {
459 459 Q_D(QPieSeries);
460 460 if (relativeSize < 0.0 || relativeSize > 1.0)
461 461 return;
462 462
463 463 if (!qFuzzyIsNull(d->m_pieRelativeSize- relativeSize)) {
464 464 d->m_pieRelativeSize = relativeSize;
465 465 emit pieSizeChanged();
466 466 }
467 467 }
468 468
469 469 /*!
470 470 Gets the relative size of the pie.
471 471
472 472 The size is defined so that the 1.0 is the maximum that can fit the given chart rectangle.
473 473
474 474 Default value is 0.7.
475 475
476 476 \sa setPieSize(), setPiePosition(), pieVerticalPosition(), pieHorizontalPosition()
477 477 */
478 478 qreal QPieSeries::pieSize() const
479 479 {
480 480 Q_D(const QPieSeries);
481 481 return d->m_pieRelativeSize;
482 482 }
483 483
484 484
485 485 /*!
486 486 Sets the end angle of the pie.
487 487
488 488 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
489 489
490 490 \a angle must be less than pie end angle. Default value is 0.
491 491
492 492 \sa pieStartAngle(), pieEndAngle(), setPieEndAngle()
493 493 */
494 494 void QPieSeries::setPieStartAngle(qreal angle)
495 495 {
496 496 Q_D(QPieSeries);
497 497
498 498 if (angle < 0 || angle > 360 || angle > d->m_pieEndAngle)
499 499 return;
500 500
501 501 if (!qFuzzyIsNull(angle - d->m_pieStartAngle)) {
502 502 d->m_pieStartAngle = angle;
503 503 d->updateDerivativeData();
504 504 }
505 505 }
506 506
507 507 /*!
508 508 Gets the start angle of the pie.
509 509
510 510 Full pie is 360 degrees where 0 degrees is at 12 a'clock. Default value is 360.
511 511
512 512 \sa setPieStartAngle(), pieEndAngle(), setPieEndAngle()
513 513 */
514 514 qreal QPieSeries::pieStartAngle() const
515 515 {
516 516 Q_D(const QPieSeries);
517 517 return d->m_pieStartAngle;
518 518 }
519 519
520 520 /*!
521 521 Sets the end angle of the pie.
522 522
523 523 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
524 524
525 525 \a angle must be greater than start angle.
526 526
527 527 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
528 528 */
529 529 void QPieSeries::setPieEndAngle(qreal angle)
530 530 {
531 531 Q_D(QPieSeries);
532 532
533 533 if (angle < 0 || angle > 360 || angle < d->m_pieStartAngle)
534 534 return;
535 535
536 536 if (!qFuzzyIsNull(angle - d->m_pieEndAngle)) {
537 537 d->m_pieEndAngle = angle;
538 538 d->updateDerivativeData();
539 539 }
540 540 }
541 541
542 542 /*!
543 543 Returns the end angle of the pie.
544 544
545 545 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
546 546
547 547 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
548 548 */
549 549 qreal QPieSeries::pieEndAngle() const
550 550 {
551 551 Q_D(const QPieSeries);
552 552 return d->m_pieEndAngle;
553 553 }
554 554
555 555 /*!
556 556 Sets the all the slice labels \a visible or invisible.
557 557
558 558 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
559 559 */
560 560 void QPieSeries::setLabelsVisible(bool visible)
561 561 {
562 562 Q_D(QPieSeries);
563 563 foreach (QPieSlice* s, d->m_slices)
564 564 s->setLabelVisible(visible);
565 565 }
566 566
567 567 /*!
568 568 Returns the sum of all slice values in this series.
569 569
570 570 \sa QPieSlice::value(), QPieSlice::setValue()
571 571 */
572 572 qreal QPieSeries::total() const
573 573 {
574 574 Q_D(const QPieSeries);
575 575 return d->m_total;
576 576 }
577 577
578 578 /*!
579 579 \fn void QPieSeries::clicked(QPieSlice* slice, Qt::MouseButtons buttons)
580 580
581 581 This signal is emitted when a \a slice has been clicked with mouse \a buttons.
582 582
583 583 \sa QPieSlice::clicked()
584 584 */
585 585
586 586 /*!
587 587 \fn void QPieSeries::hoverEnter(QPieSlice* slice)
588 588
589 589 This signal is emitted when user has hovered over a \a slice.
590 590
591 591 \sa QPieSlice::hoverEnter()
592 592 */
593 593
594 594 /*!
595 595 \fn void QPieSeries::hoverLeave(QPieSlice* slice)
596 596
597 597 This signal is emitted when user has hovered away from a \a slice.
598 598
599 599 \sa QPieSlice::hoverLeave()
600 600 */
601 601
602 602 /*!
603 603 \fn void QPieSeries::added(QList<QPieSlice*> slices)
604 604
605 605 This signal is emitted when \a slices has been added to the series.
606 606
607 607 \sa append(), insert()
608 608 */
609 609
610 610 /*!
611 611 \fn void QPieSeries::removed(QList<QPieSlice*> slices)
612 612
613 613 This signal is emitted when \a slices has been removed from the series.
614 614
615 615 \sa remove(), clear()
616 616 */
617 617
618 618 /*!
619 619 \fn void QPieSeries::piePositionChanged()
620 620
621 621 This signal is emitted when pie position has changed.
622 622
623 623 \sa setPiePosition(), pieVerticalPosition(), pieHorizontalPosition()
624 624 */
625 625
626 626 /*!
627 627 \fn void QPieSeries::pieSizeChanged()
628 628
629 629 This signal is emitted when pie size has changed.
630 630
631 631 \sa pieSize(), setPieSize()
632 632 */
633 633
634 634 bool QPieSeries::setModel(QAbstractItemModel* model)
635 635 {
636 636 Q_D(QPieSeries);
637 637 // disconnect signals from old model
638 638 if(m_model)
639 639 {
640 640 disconnect(m_model, 0, this, 0);
641 641 d->m_mapValues = -1;
642 642 d->m_mapLabels = -1;
643 643 d->m_mapOrientation = Qt::Vertical;
644 644 }
645 645
646 646 // set new model
647 647 if(model)
648 648 {
649 649 m_model = model;
650 650 return true;
651 651 }
652 652 else
653 653 {
654 654 m_model = NULL;
655 655 return false;
656 656 }
657 657 }
658 658
659 659 void QPieSeries::setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation)
660 660 {
661 661 Q_D(QPieSeries);
662 662
663 663 if (m_model == NULL)
664 664 return;
665 665
666 666 d->m_mapValues = modelValuesLine;
667 667 d->m_mapLabels = modelLabelsLine;
668 668 d->m_mapOrientation = orientation;
669 669
670 670 // connect the signals
671 671 if (d->m_mapOrientation == Qt::Vertical) {
672 672 connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex, QModelIndex)));
673 673 connect(m_model, SIGNAL(rowsInserted(QModelIndex, int, int)), d, SLOT(modelDataAdded(QModelIndex,int,int)));
674 674 connect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), d, SLOT(modelDataRemoved(QModelIndex,int,int)));
675 675 } else {
676 676 connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex, QModelIndex)));
677 677 connect(m_model, SIGNAL(columnsInserted(QModelIndex, int, int)), d, SLOT(modelDataAdded(QModelIndex,int,int)));
678 678 connect(m_model, SIGNAL(columnsRemoved(QModelIndex, int, int)), d, SLOT(modelDataRemoved(QModelIndex,int,int)));
679 679 }
680 680
681 681 // create the initial slices set
682 682 if (d->m_mapOrientation == Qt::Vertical) {
683 683 for (int i = 0; i < m_model->rowCount(); i++)
684 684 append(m_model->data(m_model->index(i, d->m_mapValues), Qt::DisplayRole).toDouble(), m_model->data(m_model->index(i, d->m_mapLabels), Qt::DisplayRole).toString());
685 685 } else {
686 686 for (int i = 0; i < m_model->columnCount(); i++)
687 687 append(m_model->data(m_model->index(d->m_mapValues, i), Qt::DisplayRole).toDouble(), m_model->data(m_model->index(d->m_mapLabels, i), Qt::DisplayRole).toString());
688 688 }
689 689 }
690 690
691 691 #include "moc_qpieseries.cpp"
692 692 #include "moc_qpieseriesprivate_p.cpp"
693 693
694 694 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,91 +1,87
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 #ifndef QPIESLICE_H
22 22 #define QPIESLICE_H
23 23
24 24 #include <qchartglobal.h>
25 25 #include <QObject>
26 26 #include <QPen>
27 27 #include <QBrush>
28 28 #include <QFont>
29 29
30 30 QTCOMMERCIALCHART_BEGIN_NAMESPACE
31 31 class PieSliceData;
32 32
33 33 class QTCOMMERCIALCHART_EXPORT QPieSlice : public QObject
34 34 {
35 35 Q_OBJECT
36 36 Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY changed)
37 37 Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY changed)
38 38
39 39 public:
40 40 QPieSlice(QObject *parent = 0);
41 41 QPieSlice(qreal value, QString label, QObject *parent = 0);
42 42 virtual ~QPieSlice();
43 43
44 44 // data
45 45 void setValue(qreal value);
46 46 qreal value() const;
47 47 void setLabel(QString label);
48 48 QString label() const;
49 49 void setLabelVisible(bool visible = true);
50 50 bool isLabelVisible() const;
51 51 void setExploded(bool exploded = true);
52 52 bool isExploded() const;
53 53
54 54 // generated data
55 55 qreal percentage() const;
56 56 qreal startAngle() const;
57 57 qreal endAngle() const;
58 58
59 59 // customization
60 60 void setPen(const QPen &pen);
61 61 QPen pen() const;
62 62 void setBrush(const QBrush &brush);
63 63 QBrush brush() const;
64 64 void setLabelPen(const QPen &pen);
65 65 QPen labelPen() const;
66 66 void setLabelFont(const QFont &font);
67 67 QFont labelFont() const;
68 68 void setLabelArmLengthFactor(qreal factor);
69 69 qreal labelArmLengthFactor() const;
70 70 void setExplodeDistanceFactor(qreal factor);
71 71 qreal explodeDistanceFactor() const;
72 72
73 73 Q_SIGNALS:
74 74 void clicked(Qt::MouseButtons buttons);
75 75 void hoverEnter();
76 76 void hoverLeave();
77 77 void changed();
78 78
79 79 private:
80 80 friend class PieSliceData;
81 81 PieSliceData * const d;
82 82 Q_DISABLE_COPY(QPieSlice)
83
84 public:
85 typedef PieSliceData * const DataPtr;
86 inline DataPtr &data_ptr() { return d; }
87 83 };
88 84
89 85 QTCOMMERCIALCHART_END_NAMESPACE
90 86
91 87 #endif // QPIESLICE_H
General Comments 0
You need to be logged in to leave comments. Login now