##// END OF EJS Templates
pie: make slice added/removed signals public (again)
Jani Honkonen -
r1213:7e0a0b1297ee
parent child
Show More
@@ -1,461 +1,459
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 "qlegend.h"
22 22 #include "qlegend_p.h"
23 23 #include "qabstractseries.h"
24 24 #include "qabstractseries_p.h"
25 25 #include "qchart_p.h"
26 26
27 27 #include "legendmarker_p.h"
28 28 #include "qxyseries.h"
29 29 #include "qlineseries.h"
30 30 #include "qareaseries.h"
31 31 #include "qscatterseries.h"
32 32 #include "qsplineseries.h"
33 33 #include "qbarseries.h"
34 34 #include "qstackedbarseries.h"
35 35 #include "qpercentbarseries.h"
36 36 #include "qbarset.h"
37 37 #include "qpieseries.h"
38 38 #include "qpieseries_p.h"
39 39 #include "qpieslice.h"
40 40 #include "chartpresenter_p.h"
41 41 #include <QPainter>
42 42 #include <QPen>
43 43 #include <QTimer>
44 44
45 45 #include <QGraphicsSceneEvent>
46 46
47 47 QTCOMMERCIALCHART_BEGIN_NAMESPACE
48 48
49 49 /*!
50 50 \class QLegend
51 51 \brief part of QtCommercial chart API.
52 52 \mainclass
53 53
54 54 QLegend is a graphical object, whics displays legend of the chart. Legend state is updated by QChart, when
55 55 series have been changed. By default, legend is drawn by QChart, but user can set a new parent to legend and
56 56 handle the drawing manually.
57 57 User isn't supposed to create or delete legend objects, but can reference it via QChart class.
58 58
59 59 \image examples_percentbarchart_legend.png
60 60
61 61 \sa QChart
62 62 */
63 63
64 64 /*!
65 65 \enum QLegend::Alignment
66 66
67 67 This enum describes the possible position for legend inside chart.
68 68
69 69 \value AlignmentTop
70 70 \value AlignmentBottom
71 71 \value AlignmentLeft
72 72 \value AlignmentRight
73 73 */
74 74
75 75 /*!
76 76 \fn qreal QLegend::minWidth() const
77 77 Returns minimum width of the legend
78 78 */
79 79
80 80 /*!
81 81 \fn qreal QLegend::minHeight() const
82 82 Returns minimum height of the legend
83 83 */
84 84
85 85 /*!
86 86 Constructs the legend object and sets the parent to \a parent
87 87 */
88 88
89 89 QLegend::QLegend(QChart *chart):QGraphicsWidget(chart),
90 90 d_ptr(new QLegendPrivate(chart->d_ptr->m_presenter,this))
91 91 {
92 92 setZValue(ChartPresenter::LegendZValue);
93 93 setFlags(QGraphicsItem::ItemClipsChildrenToShape);
94 94 QObject::connect(chart->d_ptr->m_dataset,SIGNAL(seriesAdded(QAbstractSeries*,Domain*)),d_ptr.data(),SLOT(handleSeriesAdded(QAbstractSeries*,Domain*)));
95 95 QObject::connect(chart->d_ptr->m_dataset,SIGNAL(seriesRemoved(QAbstractSeries*)),d_ptr.data(),SLOT(handleSeriesRemoved(QAbstractSeries*)));
96 96 }
97 97
98 98 /*!
99 99 Destroys the legend object. Legend is always owned by a QChart, so an application should never call this.
100 100 */
101 101 QLegend::~QLegend()
102 102 {
103 103 }
104 104
105 105 /*!
106 106 Paints the legend to given \a painter. Paremeters \a option and \a widget arent used.
107 107 */
108 108
109 109 void QLegend::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
110 110 {
111 111 Q_UNUSED(option)
112 112 Q_UNUSED(widget)
113 113 if(!d_ptr->m_backgroundVisible) return;
114 114
115 115 painter->setOpacity(opacity());
116 116 painter->setPen(d_ptr->m_pen);
117 117 painter->setBrush(d_ptr->m_brush);
118 118 painter->drawRect(boundingRect());
119 119 }
120 120
121 121 /*!
122 122 Bounding rect of legend.
123 123 */
124 124
125 125 QRectF QLegend::boundingRect() const
126 126 {
127 127 return d_ptr->m_rect;
128 128 }
129 129
130 130 /*!
131 131 Sets the \a brush of legend. Brush affects the background of legend.
132 132 */
133 133 void QLegend::setBrush(const QBrush &brush)
134 134 {
135 135 if (d_ptr->m_brush != brush) {
136 136 d_ptr->m_brush = brush;
137 137 update();
138 138 }
139 139 }
140 140
141 141 /*!
142 142 Returns the brush used by legend.
143 143 */
144 144 QBrush QLegend::brush() const
145 145 {
146 146 return d_ptr->m_brush;
147 147 }
148 148
149 149 /*!
150 150 Sets the \a pen of legend. Pen affects the legend borders.
151 151 */
152 152 void QLegend::setPen(const QPen &pen)
153 153 {
154 154 if (d_ptr->m_pen != pen) {
155 155 d_ptr->m_pen = pen;
156 156 update();
157 157 }
158 158 }
159 159
160 160 /*!
161 161 Returns the pen used by legend
162 162 */
163 163
164 164 QPen QLegend::pen() const
165 165 {
166 166 return d_ptr->m_pen;
167 167 }
168 168
169 169 /*!
170 170 Sets the \a alignment for legend. Legend tries to paint itself on the defined position in chart.
171 171 \sa QLegend::Alignment
172 172 */
173 173 void QLegend::setAlignment(QLegend::Alignments alignment)
174 174 {
175 175 if(d_ptr->m_alignment!=alignment && d_ptr->m_attachedToChart) {
176 176 d_ptr->m_alignment = alignment;
177 177 d_ptr->updateLayout();
178 178 }
179 179 }
180 180
181 181 /*!
182 182 Returns the preferred layout for legend
183 183 */
184 184 QLegend::Alignments QLegend::alignment() const
185 185 {
186 186 return d_ptr->m_alignment;
187 187 }
188 188
189 189 /*!
190 190 Detaches the legend from chart. Chart won't change layout of the legend.
191 191 */
192 192 void QLegend::detachFromChart()
193 193 {
194 194 d_ptr->m_attachedToChart = false;
195 195 }
196 196
197 197 /*!
198 198 Attaches the legend to chart. Chart may change layout of the legend.
199 199 */
200 200 void QLegend::attachToChart()
201 201 {
202 202 d_ptr->m_attachedToChart = true;
203 203 }
204 204
205 205 /*!
206 206 Returns true, if legend is attached to chart.
207 207 */
208 208 bool QLegend::isAttachedToChart()
209 209 {
210 210 return d_ptr->m_attachedToChart;
211 211 }
212 212
213 213 /*!
214 214 Sets the legend's scrolling offset to value defined by \a point.
215 215 */
216 216 void QLegend::setOffset(const QPointF& point)
217 217 {
218 218 d_ptr->setOffset(point.x(),point.y());
219 219 }
220 220
221 221 /*!
222 222 Returns the legend's scrolling offset.
223 223 */
224 224 QPointF QLegend::offset() const
225 225 {
226 226 return QPointF(d_ptr->m_offsetX,d_ptr->m_offsetY);
227 227 }
228 228
229 229 /*!
230 230 Sets the visibility of legend background to \a visible
231 231 */
232 232 void QLegend::setBackgroundVisible(bool visible)
233 233 {
234 234 if(d_ptr->m_backgroundVisible!=visible)
235 235 {
236 236 d_ptr->m_backgroundVisible=visible;
237 237 update();
238 238 }
239 239 }
240 240
241 241 /*!
242 242 Returns the visibility of legend background
243 243 */
244 244 bool QLegend::isBackgroundVisible() const
245 245 {
246 246 return d_ptr->m_backgroundVisible;
247 247 }
248 248
249 249 /*!
250 250 \internal \a event see QGraphicsWidget for details
251 251 */
252 252 void QLegend::resizeEvent(QGraphicsSceneResizeEvent *event)
253 253 {
254 254 const QRectF& rect = QRectF(QPoint(0,0),event->newSize());
255 255 QGraphicsWidget::resizeEvent(event);
256 256 if(d_ptr->m_rect != rect) {
257 257 d_ptr->m_rect = rect;
258 258 d_ptr->updateLayout();
259 259 }
260 260 }
261 261
262 262 /*!
263 263 \internal \a event see QGraphicsWidget for details
264 264 */
265 265 void QLegend::hideEvent(QHideEvent *event)
266 266 {
267 267 QGraphicsWidget::hideEvent(event);
268 268 setEnabled(false);
269 269 d_ptr->updateLayout();
270 270 }
271 271
272 272 /*!
273 273 \internal \a event see QGraphicsWidget for details
274 274 */
275 275 void QLegend::showEvent(QShowEvent *event)
276 276 {
277 277 QGraphicsWidget::showEvent(event);
278 278 setEnabled(true);
279 279 d_ptr->updateLayout();
280 280 }
281 281
282 282 qreal QLegend::minWidth() const
283 283 {
284 284 return d_ptr->m_minWidth;
285 285 }
286 286
287 287 qreal QLegend::minHeight() const
288 288 {
289 289 return d_ptr->m_minHeight;
290 290 }
291 291
292 292 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
293 293
294 294 QLegendPrivate::QLegendPrivate(ChartPresenter* presenter,QLegend *q):
295 295 q_ptr(q),
296 296 m_presenter(presenter),
297 297 m_markers(new QGraphicsItemGroup(q)),
298 298 m_alignment(QLegend::AlignmentTop),
299 299 m_offsetX(0),
300 300 m_offsetY(0),
301 301 m_minWidth(0),
302 302 m_minHeight(0),
303 303 m_width(0),
304 304 m_height(0),
305 305 m_attachedToChart(true),
306 306 m_backgroundVisible(false)
307 307 {
308 308
309 309 }
310 310
311 311 QLegendPrivate::~QLegendPrivate()
312 312 {
313 313
314 314 }
315 315
316 316 void QLegendPrivate::setOffset(qreal x, qreal y)
317 317 {
318 318
319 319 switch(m_alignment) {
320 320
321 321 case QLegend::AlignmentTop:
322 322 case QLegend::AlignmentBottom: {
323 323 if(m_width<=m_rect.width()) return;
324 324
325 325 if (x != m_offsetX) {
326 326 m_offsetX = qBound(qreal(0), x, m_width - m_rect.width());
327 327 m_markers->setPos(-m_offsetX,m_rect.top());
328 328 }
329 329 break;
330 330 }
331 331 case QLegend::AlignmentLeft:
332 332 case QLegend::AlignmentRight: {
333 333
334 334 if(m_height<=m_rect.height()) return;
335 335
336 336 if (y != m_offsetY) {
337 337 m_offsetY = qBound(qreal(0), y, m_height - m_rect.height());
338 338 m_markers->setPos(m_rect.left(),-m_offsetY);
339 339 }
340 340 break;
341 341 }
342 342 }
343 343 }
344 344
345 345
346 346 void QLegendPrivate::updateLayout()
347 347 {
348 348 m_offsetX=0;
349 349 QList<QGraphicsItem *> items = m_markers->childItems();
350 350
351 351 if(items.isEmpty()) return;
352 352
353 353 m_minWidth=0;
354 354 m_minHeight=0;
355 355
356 356 switch(m_alignment) {
357 357
358 358 case QLegend::AlignmentTop:
359 359 case QLegend::AlignmentBottom: {
360 360 QPointF point = m_rect.topLeft();
361 361 m_width = 0;
362 362 foreach (QGraphicsItem *item, items) {
363 363 item->setPos(point.x(),m_rect.height()/2 -item->boundingRect().height()/2);
364 364 const QRectF& rect = item->boundingRect();
365 365 qreal w = rect.width();
366 366 m_minWidth=qMax(m_minWidth,w);
367 367 m_minHeight=qMax(m_minHeight,rect.height());
368 368 m_width+=w;
369 369 point.setX(point.x() + w);
370 370 }
371 371 if(m_width<m_rect.width()) {
372 372 m_markers->setPos(m_rect.width()/2-m_width/2,m_rect.top());
373 373 }
374 374 else {
375 375 m_markers->setPos(m_rect.topLeft());
376 376 }
377 377 m_height=m_minHeight;
378 378 }
379 379 break;
380 380 case QLegend::AlignmentLeft:
381 381 case QLegend::AlignmentRight: {
382 382 QPointF point = m_rect.topLeft();
383 383 m_height = 0;
384 384 foreach (QGraphicsItem *item, items) {
385 385 item->setPos(point);
386 386 const QRectF& rect = item->boundingRect();
387 387 qreal h = rect.height();
388 388 m_minWidth=qMax(m_minWidth,rect.width());
389 389 m_minHeight=qMax(m_minHeight,h);
390 390 m_height+=h;
391 391 point.setY(point.y() + h);
392 392 }
393 393 if(m_height<m_rect.height()) {
394 394 m_markers->setPos(m_rect.left(),m_rect.height()/2-m_height/2);
395 395 }
396 396 else {
397 397 m_markers->setPos(m_rect.topLeft());
398 398 }
399 399 m_width=m_minWidth;
400 400 }
401 401 break;
402 402 }
403 403
404 404 m_presenter->updateLayout();
405 405 }
406 406
407 407 void QLegendPrivate::handleSeriesAdded(QAbstractSeries *series, Domain *domain)
408 408 {
409 409 Q_UNUSED(domain)
410 410
411 411 QList<LegendMarker*> markers = series->d_ptr->createLegendMarker(q_ptr);
412 412 foreach(LegendMarker* marker , markers)
413 413 m_markers->addToGroup(marker);
414 414
415 415 if(series->type() == QAbstractSeries::SeriesTypePie)
416 416 {
417 417 QPieSeries *pieSeries = static_cast<QPieSeries *>(series);
418 QPieSeriesPrivate *d = QPieSeriesPrivate::seriesData(*pieSeries);
419 QObject::connect(d, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
420 QObject::connect(d, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
418 QObject::connect(pieSeries, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
419 QObject::connect(pieSeries, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
421 420 }
422 421
423 422 updateLayout();
424 423 }
425 424
426 425 void QLegendPrivate::handleSeriesRemoved(QAbstractSeries *series)
427 426 {
428 427
429 428 QList<QGraphicsItem *> items = m_markers->childItems();
430 429
431 430 foreach (QGraphicsItem *markers, items) {
432 431 LegendMarker *marker = static_cast<LegendMarker*>(markers);
433 432 if (marker->series() == series) {
434 433 delete marker;
435 434 }
436 435 }
437 436
438 437 if(series->type() == QAbstractSeries::SeriesTypePie)
439 438 {
440 439 QPieSeries *pieSeries = static_cast<QPieSeries *>(series);
441 QPieSeriesPrivate *d = QPieSeriesPrivate::seriesData(*pieSeries);
442 QObject::disconnect(d, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
443 QObject::disconnect(d, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
440 QObject::disconnect(pieSeries, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
441 QObject::disconnect(pieSeries, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleUpdatePieSeries()));
444 442 }
445 443
446 444 updateLayout();
447 445 }
448 446
449 447 void QLegendPrivate::handleUpdatePieSeries()
450 448 {
451 449 //TODO: reimplement to be optimal
452 QPieSeriesPrivate* d = qobject_cast<QPieSeriesPrivate *> (sender());
453 Q_ASSERT(d->q_func());
454 handleSeriesRemoved(d->q_func());
455 handleSeriesAdded(d->q_func(), 0);
450 QPieSeries* series = qobject_cast<QPieSeries *> (sender());
451 Q_ASSERT(series);
452 handleSeriesRemoved(series);
453 handleSeriesAdded(series, 0);
456 454 }
457 455
458 456 #include "moc_qlegend.cpp"
459 457 #include "moc_qlegend_p.cpp"
460 458
461 459 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,185 +1,185
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 "qpieseries_p.h"
26 26 #include "chartpresenter_p.h"
27 27 #include "chartdataset_p.h"
28 28 #include "chartanimator_p.h"
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
40 connect(series, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
41 connect(series, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
40 42 QPieSeriesPrivate *d = QPieSeriesPrivate::seriesData(*series);
41 connect(d, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
42 connect(d, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
43 43 connect(d, SIGNAL(piePositionChanged()), this, SLOT(updateLayout()));
44 44 connect(d, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout()));
45 45
46 46 QTimer::singleShot(0, this, SLOT(initialize())); // TODO: get rid of this
47 47
48 48 // Note: the following does not affect as long as the item does not have anything to paint
49 49 setZValue(ChartPresenter::PieSeriesZValue);
50 50 }
51 51
52 52 PieChartItem::~PieChartItem()
53 53 {
54 54 // slices deleted automatically through QGraphicsItem
55 55 }
56 56
57 57 void PieChartItem::handleGeometryChanged(const QRectF& rect)
58 58 {
59 59 prepareGeometryChange();
60 60 m_rect = rect;
61 61 updateLayout();
62 62 }
63 63
64 64 void PieChartItem::handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY)
65 65 {
66 66 Q_UNUSED(minX);
67 67 Q_UNUSED(maxX);
68 68 Q_UNUSED(minY);
69 69 Q_UNUSED(maxY);
70 70 // does not apply to pie
71 71 }
72 72
73 73 void PieChartItem::rangeXChanged(qreal min, qreal max, int tickXCount)
74 74 {
75 75 Q_UNUSED(min);
76 76 Q_UNUSED(max);
77 77 Q_UNUSED(tickXCount);
78 78 // does not apply to pie
79 79 }
80 80
81 81 void PieChartItem::rangeYChanged(qreal min, qreal max, int tickYCount)
82 82 {
83 83 Q_UNUSED(min);
84 84 Q_UNUSED(max);
85 85 Q_UNUSED(tickYCount);
86 86 // does not apply to pie
87 87 }
88 88
89 89 void PieChartItem::initialize()
90 90 {
91 91 handleSlicesAdded(m_series->slices());
92 92 }
93 93
94 94 void PieChartItem::updateLayout()
95 95 {
96 96 // find pie center coordinates
97 97 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
98 98 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
99 99
100 100 // find maximum radius for pie
101 101 m_pieRadius = m_rect.height() / 2;
102 102 if (m_rect.width() < m_rect.height())
103 103 m_pieRadius = m_rect.width() / 2;
104 104
105 105 // apply size factor
106 106 m_pieRadius *= m_series->pieSize();
107 107
108 108 // set layouts for existing slice items
109 109 foreach (QPieSlice* slice, m_series->slices()) {
110 110 PieSliceItem *sliceItem = m_sliceItems.value(slice);
111 111 if (sliceItem) {
112 112 PieSliceData sliceData = updateSliceGeometry(slice);
113 113 if (animator())
114 114 animator()->updateAnimation(this, sliceItem, sliceData);
115 115 else
116 116 sliceItem->setLayout(sliceData);
117 117 }
118 118 }
119 119
120 120 update();
121 121 }
122 122
123 123 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
124 124 {
125 125 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
126 126
127 127 bool startupAnimation = m_sliceItems.isEmpty();
128 128
129 129 foreach (QPieSlice *slice, slices) {
130 130 PieSliceItem* sliceItem = new PieSliceItem(this);
131 131 m_sliceItems.insert(slice, sliceItem);
132 132 connect(slice, SIGNAL(changed()), this, SLOT(handleSliceChanged()));
133 133 connect(sliceItem, SIGNAL(clicked(Qt::MouseButtons)), slice, SIGNAL(clicked()));
134 134 connect(sliceItem, SIGNAL(hovered(bool)), slice, SIGNAL(hovered(bool)));
135 135
136 136 PieSliceData sliceData = updateSliceGeometry(slice);
137 137 if (animator())
138 138 animator()->addAnimation(this, sliceItem, sliceData, startupAnimation);
139 139 else
140 140 sliceItem->setLayout(sliceData);
141 141 }
142 142 }
143 143
144 144 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
145 145 {
146 146 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
147 147
148 148 foreach (QPieSlice *slice, slices) {
149 149 PieSliceItem *sliceItem = m_sliceItems.value(slice);
150 150 Q_ASSERT(sliceItem);
151 151 m_sliceItems.remove(slice);
152 152
153 153 if (animator())
154 154 animator()->removeAnimation(this, sliceItem); // animator deletes the PieSliceItem
155 155 else
156 156 delete sliceItem;
157 157 }
158 158 }
159 159
160 160 void PieChartItem::handleSliceChanged()
161 161 {
162 162 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
163 163 Q_ASSERT(m_sliceItems.contains(slice));
164 164
165 165 PieSliceItem *sliceItem = m_sliceItems.value(slice);
166 166 PieSliceData sliceData = updateSliceGeometry(slice);
167 167 if (animator())
168 168 animator()->updateAnimation(this, sliceItem, sliceData);
169 169 else
170 170 sliceItem->setLayout(sliceData);
171 171
172 172 update();
173 173 }
174 174
175 175 PieSliceData PieChartItem::updateSliceGeometry(QPieSlice *slice)
176 176 {
177 177 PieSliceData &sliceData = PieSliceData::data(slice);
178 178 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
179 179 sliceData.m_radius = m_pieRadius;
180 180 return sliceData;
181 181 }
182 182
183 183 #include "moc_piechartitem_p.cpp"
184 184
185 185 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,816 +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 emit d->added(slices);
168 emit 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 emit d->added(QList<QPieSlice*>() << slice);
227 emit 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 emit d->removed(QList<QPieSlice*>() << slice);
246 emit 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 emit d->removed(slices);
271 emit 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 344 if (qFuzzyIsNull(d->m_pieStartAngle - angle))
345 345 return;
346 346 d->m_pieStartAngle = angle;
347 347 d->updateDerivativeData();
348 348 }
349 349
350 350 qreal QPieSeries::pieStartAngle() const
351 351 {
352 352 Q_D(const QPieSeries);
353 353 return d->m_pieStartAngle;
354 354 }
355 355
356 356 /*!
357 357 Sets the end angle of the pie.
358 358
359 359 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
360 360
361 361 \a angle must be greater than start angle.
362 362
363 363 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
364 364 */
365 365 void QPieSeries::setPieEndAngle(qreal angle)
366 366 {
367 367 Q_D(QPieSeries);
368 368 if (qFuzzyIsNull(d->m_pieEndAngle - angle))
369 369 return;
370 370 d->m_pieEndAngle = angle;
371 371 d->updateDerivativeData();
372 372 }
373 373
374 374 /*!
375 375 Returns the end angle of the pie.
376 376
377 377 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
378 378
379 379 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
380 380 */
381 381 qreal QPieSeries::pieEndAngle() const
382 382 {
383 383 Q_D(const QPieSeries);
384 384 return d->m_pieEndAngle;
385 385 }
386 386
387 387 /*!
388 388 Sets the all the slice labels \a visible or invisible.
389 389
390 390 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
391 391 */
392 392 void QPieSeries::setLabelsVisible(bool visible)
393 393 {
394 394 Q_D(QPieSeries);
395 395 foreach (QPieSlice* s, d->m_slices)
396 396 s->setLabelVisible(visible);
397 397 }
398 398
399 399 /*!
400 400 Returns the sum of all slice values in this series.
401 401
402 402 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
403 403 */
404 404 qreal QPieSeries::sum() const
405 405 {
406 406 Q_D(const QPieSeries);
407 407 return d->m_sum;
408 408 }
409 409
410 410 /*!
411 411 \fn void QPieSeries::clicked(QPieSlice* slice)
412 412
413 413 This signal is emitted when a \a slice has been clicked.
414 414
415 415 \sa QPieSlice::clicked()
416 416 */
417 417
418 418 /*!
419 419 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
420 420
421 421 This signal is emitted when user has hovered over or away from the \a slice.
422 422
423 423 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
424 424
425 425 \sa QPieSlice::hovered()
426 426 */
427 427
428 428 /*!
429 429 \fn bool QPieSeries::setModel(QAbstractItemModel *model)
430 430 Sets the \a model to be used as a data source
431 431 */
432 432 void QPieSeries::setModel(QAbstractItemModel* model)
433 433 {
434 434 Q_D(QPieSeries);
435 435 // disconnect signals from old model
436 436 if(d->m_model)
437 437 {
438 438 disconnect(d->m_model, 0, this, 0);
439 439 }
440 440
441 441 // set new model
442 442 if(model)
443 443 {
444 444 d->m_model = model;
445 445 // connect signals from the model
446 446 connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
447 447 connect(d->m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), d, SLOT(modelRowsAdded(QModelIndex,int,int)));
448 448 connect(d->m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), d, SLOT(modelRowsRemoved(QModelIndex,int,int)));
449 449 connect(d->m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, SLOT(modelColumnsAdded(QModelIndex,int,int)));
450 450 connect(d->m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, SLOT(modelColumnsRemoved(QModelIndex,int,int)));
451 451
452 452 if (d->m_mapper)
453 453 d->initializePieFromModel();
454 454 }
455 455 else
456 456 {
457 457 d->m_model = 0;
458 458 }
459 459 }
460 460
461 461 void QPieSeries::setModelMapper(QPieModelMapper *mapper)
462 462 {
463 463 Q_D(QPieSeries);
464 464 // disconnect signals from old mapper
465 465 if (d->m_mapper) {
466 466 QObject::disconnect(d->m_mapper, 0, this, 0);
467 467 }
468 468
469 469 if (mapper) {
470 470 d->m_mapper = mapper;
471 471 // connect the signal from the mapper
472 472 connect(d->m_mapper, SIGNAL(updated()), d, SLOT(initializePieFromModel()));
473 473
474 474 if (d->m_model)
475 475 d->initializePieFromModel();
476 476 } else {
477 477 d->m_mapper = 0;
478 478 }
479 479 }
480 480
481 481 QPieModelMapper* QPieSeries::modelMapper() const
482 482 {
483 483 Q_D(const QPieSeries);
484 484 return d->m_mapper;
485 485 }
486 486
487 487 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
488 488
489 489
490 490 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
491 491 QAbstractSeriesPrivate(parent),
492 492 m_pieRelativeHorPos(0.5),
493 493 m_pieRelativeVerPos(0.5),
494 494 m_pieRelativeSize(0.7),
495 495 m_pieStartAngle(0),
496 496 m_pieEndAngle(360),
497 497 m_sum(0),
498 498 m_mapper(0)
499 499 {
500 500
501 501 }
502 502
503 503 QPieSeriesPrivate::~QPieSeriesPrivate()
504 504 {
505 505
506 506 }
507 507
508 508 void QPieSeriesPrivate::updateDerivativeData()
509 509 {
510 510 m_sum = 0;
511 511
512 512 // nothing to do?
513 513 if (m_slices.count() == 0)
514 514 return;
515 515
516 516 // calculate sum of all slices
517 517 foreach (QPieSlice* s, m_slices)
518 518 m_sum += s->value();
519 519
520 520 // nothing to show..
521 521 if (qFuzzyIsNull(m_sum))
522 522 return;
523 523
524 524 // update slice attributes
525 525 qreal sliceAngle = m_pieStartAngle;
526 526 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
527 527 QVector<QPieSlice*> changed;
528 528 foreach (QPieSlice* s, m_slices) {
529 529
530 530 PieSliceData data = PieSliceData::data(s);
531 531 data.m_percentage = s->value() / m_sum;
532 532 data.m_angleSpan = pieSpan * data.m_percentage;
533 533 data.m_startAngle = sliceAngle;
534 534 sliceAngle += data.m_angleSpan;
535 535
536 536 if (PieSliceData::data(s) != data) {
537 537 PieSliceData::data(s) = data;
538 538 changed << s;
539 539 }
540 540 }
541 541
542 542 // emit signals
543 543 foreach (QPieSlice* s, changed)
544 544 PieSliceData::data(s).emitChangedSignal(s);
545 545 }
546 546
547 547 QPieSeriesPrivate* QPieSeriesPrivate::seriesData(QPieSeries &series)
548 548 {
549 549 return series.d_func();
550 550 }
551 551
552 552 void QPieSeriesPrivate::sliceChanged()
553 553 {
554 554 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
555 555 updateDerivativeData();
556 556 }
557 557
558 558 void QPieSeriesPrivate::sliceClicked()
559 559 {
560 560 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
561 561 Q_ASSERT(m_slices.contains(slice));
562 562 Q_Q(QPieSeries);
563 563 emit q->clicked(slice);
564 564 }
565 565
566 566 void QPieSeriesPrivate::sliceHovered(bool state)
567 567 {
568 568 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
569 569 Q_ASSERT(m_slices.contains(slice));
570 570 Q_Q(QPieSeries);
571 571 emit q->hovered(slice, state);
572 572 }
573 573
574 574 void QPieSeriesPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
575 575 {
576 576 if (m_mapper) {
577 577 for (int row = topLeft.row(); row <= bottomRight.row(); row++) {
578 578 for (int column = topLeft.column(); column <= bottomRight.column(); column++) {
579 579 if (m_mapper->orientation() == Qt::Vertical)
580 580 {
581 581 if ( topLeft.row() >= m_mapper->first() && (m_mapper->count() == - 1 || topLeft.row() < m_mapper->first() + m_mapper->count())) {
582 582 if (topLeft.column() == m_mapper->mapValues())
583 583 m_slices.at(topLeft.row() - m_mapper->first())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
584 584 if (topLeft.column() == m_mapper->mapLabels())
585 585 m_slices.at(topLeft.row() - m_mapper->first())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
586 586 }
587 587 }
588 588 else
589 589 {
590 590 if (topLeft.column() >= m_mapper->first() && (m_mapper->count() == - 1 || topLeft.column() < m_mapper->first() + m_mapper->count())) {
591 591 if (topLeft.row() == m_mapper->mapValues())
592 592 m_slices.at(topLeft.column() - m_mapper->first())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
593 593 if (topLeft.row() == m_mapper->mapLabels())
594 594 m_slices.at(topLeft.column() - m_mapper->first())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
595 595 }
596 596 }
597 597 }
598 598 }
599 599 }
600 600 }
601 601
602 602
603 603 void QPieSeriesPrivate::modelRowsAdded(QModelIndex parent, int start, int end)
604 604 {
605 605 Q_UNUSED(parent);
606 606 if (m_mapper) {
607 607 if (m_mapper->orientation() == Qt::Vertical)
608 608 insertData(start, end);
609 609 else if (start <= m_mapper->mapValues() || start <= m_mapper->mapLabels()) // if the changes affect the map - reinitialize the pie
610 610 initializePieFromModel();
611 611 }
612 612 }
613 613
614 614 void QPieSeriesPrivate::modelRowsRemoved(QModelIndex parent, int start, int end)
615 615 {
616 616 Q_UNUSED(parent);
617 617 if (m_mapper) {
618 618 if (m_mapper->orientation() == Qt::Vertical)
619 619 removeData(start, end);
620 620 else if (start <= m_mapper->mapValues() || start <= m_mapper->mapLabels()) // if the changes affect the map - reinitialize the pie
621 621 initializePieFromModel();
622 622 }
623 623 }
624 624
625 625 void QPieSeriesPrivate::modelColumnsAdded(QModelIndex parent, int start, int end)
626 626 {
627 627 Q_UNUSED(parent);
628 628 if (m_mapper) {
629 629 if (m_mapper->orientation() == Qt::Horizontal)
630 630 insertData(start, end);
631 631 else if (start <= m_mapper->mapValues() || start <= m_mapper->mapLabels()) // if the changes affect the map - reinitialize the pie
632 632 initializePieFromModel();
633 633 }
634 634 }
635 635
636 636 void QPieSeriesPrivate::modelColumnsRemoved(QModelIndex parent, int start, int end)
637 637 {
638 638 Q_UNUSED(parent);
639 639 if (m_mapper) {
640 640 if (m_mapper->orientation() == Qt::Horizontal)
641 641 removeData(start, end);
642 642 else if (start <= m_mapper->mapValues() || start <= m_mapper->mapLabels()) // if the changes affect the map - reinitialize the pie
643 643 initializePieFromModel();
644 644 }
645 645 }
646 646
647 647 void QPieSeriesPrivate::insertData(int start, int end)
648 648 {
649 649 Q_Q(QPieSeries);
650 650 if (m_mapper) {
651 651 if (m_mapper->count() != -1 && start >= m_mapper->first() + m_mapper->count()) {
652 652 return;
653 653 } else {
654 654 int addedCount = end - start + 1;
655 655 if (m_mapper->count() != -1 && addedCount > m_mapper->count())
656 656 addedCount = m_mapper->count();
657 657 int first = qMax(start, m_mapper->first());
658 658 int last = qMin(first + addedCount - 1, m_mapper->orientation() == Qt::Vertical ? m_model->rowCount() - 1 : m_model->columnCount() - 1);
659 659 for (int i = first; i <= last; i++) {
660 660 QPieSlice *slice = new QPieSlice;
661 661 if (m_mapper->orientation() == Qt::Vertical) {
662 662 slice->setValue(m_model->data(m_model->index(i, m_mapper->mapValues()), Qt::DisplayRole).toDouble());
663 663 slice->setLabel(m_model->data(m_model->index(i, m_mapper->mapLabels()), Qt::DisplayRole).toString());
664 664 } else {
665 665 slice->setValue(m_model->data(m_model->index(m_mapper->mapValues(), i), Qt::DisplayRole).toDouble());
666 666 slice->setLabel(m_model->data(m_model->index(m_mapper->mapLabels(), i), Qt::DisplayRole).toString());
667 667 }
668 668 slice->setLabelVisible();
669 669 q->insert(i - m_mapper->first(), slice);
670 670 }
671 671 if (m_mapper->count() != -1 && m_slices.size() > m_mapper->count())
672 672 for (int i = m_slices.size() - 1; i >= m_mapper->count(); i--)
673 673 q->remove(q->slices().at(i));
674 674 }
675 675 }
676 676 }
677 677
678 678 void QPieSeriesPrivate::removeData(int start, int end)
679 679 {
680 680 Q_Q(QPieSeries);
681 681 if (m_mapper) {
682 682 int removedCount = end - start + 1;
683 683 if (m_mapper->count() != -1 && start >= m_mapper->first() + m_mapper->count()) {
684 684 return;
685 685 } else {
686 686 int toRemove = qMin(m_slices.size(), removedCount); // first find how many items can actually be removed
687 687 int first = qMax(start, m_mapper->first()); // get the index of the first item that will be removed.
688 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.
689 689 for (int i = last; i >= first; i--)
690 690 q->remove(q->slices().at(i - m_mapper->first()));
691 691
692 692 if (m_mapper->count() != -1) {
693 693 int itemsAvailable; // check how many are available to be added
694 694 if (m_mapper->orientation() == Qt::Vertical)
695 695 itemsAvailable = m_model->rowCount() - m_mapper->first() - m_slices.size();
696 696 else
697 697 itemsAvailable = m_model->columnCount() - m_mapper->first() - m_slices.size();
698 698 int toBeAdded = qMin(itemsAvailable, m_mapper->count() - m_slices.size()); // add not more items than there is space left to be filled.
699 699 int currentSize = m_slices.size();
700 700 if (toBeAdded > 0)
701 701 for (int i = m_slices.size(); i < currentSize + toBeAdded; i++) {
702 702 QPieSlice *slice = new QPieSlice;
703 703 if (m_mapper->orientation() == Qt::Vertical) {
704 704 slice->setValue(m_model->data(m_model->index(i + m_mapper->first(), m_mapper->mapValues()), Qt::DisplayRole).toDouble());
705 705 slice->setLabel(m_model->data(m_model->index(i + m_mapper->first(), m_mapper->mapLabels()), Qt::DisplayRole).toString());
706 706 } else {
707 707 slice->setValue(m_model->data(m_model->index(m_mapper->mapValues(), i + m_mapper->first()), Qt::DisplayRole).toDouble());
708 708 slice->setLabel(m_model->data(m_model->index(m_mapper->mapLabels(), i + m_mapper->first()), Qt::DisplayRole).toString());
709 709 }
710 710 slice->setLabelVisible();
711 711 q->insert(i, slice);
712 712 }
713 713 }
714 714 }
715 715 }
716 716 }
717 717
718 718 void QPieSeriesPrivate::initializePieFromModel()
719 719 {
720 720 Q_Q(QPieSeries);
721 721
722 722 // clear current content
723 723 q->clear();
724 724
725 725 if (m_model == 0 || m_mapper == 0)
726 726 return;
727 727
728 728 // check if mappings are set
729 729 if (m_mapper->mapValues() == -1 || m_mapper->mapLabels() == -1)
730 730 return;
731 731
732 732 // create the initial slices set
733 733 if (m_mapper->orientation() == Qt::Vertical) {
734 734 if (m_mapper->mapValues() >= m_model->columnCount() || m_mapper->mapLabels() >= m_model->columnCount())
735 735 return; // mapped columns are not existing
736 736
737 737 int sliceCount = 0;
738 738 if(m_mapper->count() == -1)
739 739 sliceCount = m_model->rowCount() - m_mapper->first();
740 740 else
741 741 sliceCount = qMin(m_mapper->count(), m_model->rowCount() - m_mapper->first());
742 742 for (int i = m_mapper->first(); i < m_mapper->first() + sliceCount; i++)
743 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());
744 744 } else {
745 745 if (m_mapper->mapValues() >= m_model->rowCount() || m_mapper->mapLabels() >= m_model->rowCount())
746 746 return; // mapped columns are not existing
747 747
748 748 int sliceCount = 0;
749 749 if(m_mapper->count() == -1)
750 750 sliceCount = m_model->columnCount() - m_mapper->first();
751 751 else
752 752 sliceCount = qMin(m_mapper->count(), m_model->columnCount() - m_mapper->first());
753 753 for (int i = m_mapper->first(); i < m_mapper->first() + sliceCount; i++)
754 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());
755 755 }
756 756 q->setLabelsVisible(true);
757 757 }
758 758
759 759 bool QPieSeriesPrivate::setRealValue(qreal &value, qreal newValue, qreal max, qreal min)
760 760 {
761 761 // Remove rounding errors
762 762 qreal roundedValue = newValue;
763 763 if (qFuzzyIsNull(min) && qFuzzyIsNull(newValue))
764 764 roundedValue = 0.0;
765 765 else if (qFuzzyCompare(newValue, max))
766 766 roundedValue = max;
767 767 else if (qFuzzyCompare(newValue, min))
768 768 roundedValue = min;
769 769
770 770 // Check if the position is valid after removing the rounding errors
771 771 if (roundedValue < min || roundedValue > max) {
772 772 qWarning("QPieSeries: Illegal value");
773 773 return false;
774 774 }
775 775
776 776 if (!qFuzzyIsNull(value - roundedValue)) {
777 777 value = roundedValue;
778 778 return true;
779 779 }
780 780
781 781 // The change was so small it is considered a rounding error
782 782 return false;
783 783 }
784 784
785 785 void QPieSeriesPrivate::scaleDomain(Domain& domain)
786 786 {
787 787 Q_UNUSED(domain);
788 788 // does not apply to pie
789 789 }
790 790
791 791 Chart* QPieSeriesPrivate::createGraphics(ChartPresenter* presenter)
792 792 {
793 793 Q_Q(QPieSeries);
794 794 PieChartItem* pie = new PieChartItem(q,presenter);
795 795 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
796 796 presenter->animator()->addAnimation(pie);
797 797 }
798 798 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
799 799 return pie;
800 800 }
801 801
802 802 QList<LegendMarker*> QPieSeriesPrivate::createLegendMarker(QLegend* legend)
803 803 {
804 804 Q_Q(QPieSeries);
805 805 QList<LegendMarker*> markers;
806 806 foreach(QPieSlice* slice, q->slices()) {
807 807 PieLegendMarker* marker = new PieLegendMarker(q,slice,legend);
808 808 markers << marker;
809 809 }
810 810 return markers;
811 811 }
812 812
813 813 #include "moc_qpieseries.cpp"
814 814 #include "moc_qpieseries_p.cpp"
815 815
816 816 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,92 +1,94
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 PIESERIES_H
22 22 #define PIESERIES_H
23 23
24 24 #include <qabstractseries.h>
25 25
26 26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 27 class QPieSeriesPrivate;
28 28 class QPieSlice;
29 29 class QPieModelMapper;
30 30
31 31 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QAbstractSeries
32 32 {
33 33 Q_OBJECT
34 34 Q_PROPERTY(qreal horizontalPosition READ horizontalPosition WRITE setHorizontalPosition)
35 35 Q_PROPERTY(qreal verticalPosition READ verticalPosition WRITE setVerticalPosition)
36 36 Q_PROPERTY(qreal size READ pieSize WRITE setPieSize)
37 37 Q_PROPERTY(qreal startAngle READ pieStartAngle WRITE setPieStartAngle)
38 38 Q_PROPERTY(qreal endAngle READ pieEndAngle WRITE setPieEndAngle)
39 39 Q_PROPERTY(int count READ count)
40 40 Q_PROPERTY(QPieModelMapper *modelMapper READ modelMapper)
41 41
42 42 public:
43 43 explicit QPieSeries(QObject *parent = 0);
44 44 virtual ~QPieSeries();
45 45
46 46 QAbstractSeries::SeriesType type() const;
47 47
48 48 bool append(QPieSlice* slice);
49 49 bool append(QList<QPieSlice*> slices);
50 50 QPieSeries& operator << (QPieSlice* slice);
51 51 QPieSlice* append(QString label, qreal value);
52 52 bool insert(int index, QPieSlice* slice);
53 53 bool remove(QPieSlice* slice);
54 54 void clear();
55 55
56 56 QList<QPieSlice*> slices() const;
57 57 int count() const;
58 58 bool isEmpty() const;
59 59
60 60 qreal sum() const;
61 61
62 62 void setHorizontalPosition(qreal relativePosition);
63 63 qreal horizontalPosition() const;
64 64 void setVerticalPosition(qreal relativePosition);
65 65 qreal verticalPosition() const;
66 66
67 67 void setPieSize(qreal relativeSize);
68 68 qreal pieSize() const;
69 69
70 70 void setPieStartAngle(qreal startAngle);
71 71 qreal pieStartAngle() const;
72 72 void setPieEndAngle(qreal endAngle);
73 73 qreal pieEndAngle() const;
74 74
75 75 void setLabelsVisible(bool visible = true);
76 76
77 77 void setModel(QAbstractItemModel* model);
78 78 void setModelMapper(QPieModelMapper *mapper);
79 79 QPieModelMapper* modelMapper() const;
80 80
81 81 Q_SIGNALS:
82 void added(QList<QPieSlice*> slices);
83 void removed(QList<QPieSlice*> slices);
82 84 void clicked(QPieSlice* slice);
83 85 void hovered(QPieSlice* slice, bool state);
84 86
85 87 private:
86 88 Q_DECLARE_PRIVATE(QPieSeries)
87 89 Q_DISABLE_COPY(QPieSeries)
88 90 };
89 91
90 92 QTCOMMERCIALCHART_END_NAMESPACE
91 93
92 94 #endif // PIESERIES_H
@@ -1,94 +1,92
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 QPIESERIES_P_H
22 22 #define QPIESERIES_P_H
23 23
24 24 #include "qpieseries.h"
25 25 #include "qabstractseries_p.h"
26 26
27 27 class QModelIndex;
28 28
29 29 QTCOMMERCIALCHART_BEGIN_NAMESPACE
30 30 class QLegendPrivate;
31 31 class QPieModelMapper;
32 32
33 33 class QPieSeriesPrivate : public QAbstractSeriesPrivate
34 34 {
35 35 Q_OBJECT
36 36
37 37 public:
38 38 QPieSeriesPrivate(QPieSeries *parent);
39 39 ~QPieSeriesPrivate();
40 40
41 41 void scaleDomain(Domain& domain);
42 42 Chart* createGraphics(ChartPresenter *presenter);
43 43 QList<LegendMarker*> createLegendMarker(QLegend *legend);
44 44
45 45 void updateDerivativeData();
46 46
47 47 static QPieSeriesPrivate* seriesData(QPieSeries &series);
48 48
49 49 Q_SIGNALS:
50 void added(QList<QPieSlice*> slices);
51 void removed(QList<QPieSlice*> slices);
52 50 void piePositionChanged();
53 51 void pieSizeChanged();
54 52
55 53 public Q_SLOTS:
56 54 void sliceChanged();
57 55 void sliceClicked();
58 56 void sliceHovered(bool state);
59 57 void initializePieFromModel();
60 58 void modelUpdated(QModelIndex topLeft, QModelIndex bottomRight);
61 59 void modelRowsAdded(QModelIndex parent, int start, int end);
62 60 void modelRowsRemoved(QModelIndex parent, int start, int end);
63 61 void modelColumnsAdded(QModelIndex parent, int start, int end);
64 62 void modelColumnsRemoved(QModelIndex parent, int start, int end);
65 63 bool setRealValue(qreal &value, qreal newValue, qreal max, qreal min = 0.0);
66 64
67 65 private:
68 66 void doClear();
69 67 void doRemove(QPieSlice* slice);
70 68 void doInsert(int index, QPieSlice* slice);
71 69 void insertData(int start, int end);
72 70 void removeData(int start, int end);
73 71
74 72 public:
75 73 QList<QPieSlice*> m_slices;
76 74 qreal m_pieRelativeHorPos;
77 75 qreal m_pieRelativeVerPos;
78 76 qreal m_pieRelativeSize;
79 77 qreal m_pieStartAngle;
80 78 qreal m_pieEndAngle;
81 79 qreal m_sum;
82 80
83 81 // model
84 82 QAbstractItemModel *m_model;
85 83 QPieModelMapper *m_mapper;
86 84
87 85 private:
88 86 friend class QLegendPrivate;
89 87 Q_DECLARE_PUBLIC(QPieSeries)
90 88 };
91 89
92 90 QTCOMMERCIALCHART_END_NAMESPACE
93 91
94 92 #endif // QPIESERIES_P_H
General Comments 0
You need to be logged in to leave comments. Login now