##// END OF EJS Templates
bugfix: pie does not disconnect signals when a slice is taken (not deleted)
Jani Honkonen -
r2084:8911fa47051b
parent child
Show More
@@ -1,248 +1,250
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 "qpieslice_p.h"
25 25 #include "qpieseries.h"
26 26 #include "qpieseries_p.h"
27 27 #include "chartpresenter_p.h"
28 28 #include "chartdataset_p.h"
29 29 #include "pieanimation_p.h"
30 30 #include <QPainter>
31 31 #include <QTimer>
32 32
33 33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
34 34
35 35 PieChartItem::PieChartItem(QPieSeries *series, ChartPresenter* presenter)
36 36 :ChartItem(presenter),
37 37 m_series(series),
38 38 m_animation(0)
39 39 {
40 40 Q_ASSERT(series);
41 41
42 42 QPieSeriesPrivate *p = QPieSeriesPrivate::fromSeries(series);
43 43 connect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
44 44 connect(series, SIGNAL(opacityChanged()), this, SLOT(handleOpacityChanged()));
45 45 connect(series, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
46 46 connect(series, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
47 47 connect(p, SIGNAL(horizontalPositionChanged()), this, SLOT(updateLayout()));
48 48 connect(p, SIGNAL(verticalPositionChanged()), this, SLOT(updateLayout()));
49 49 connect(p, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout()));
50 50 connect(p, SIGNAL(calculatedDataChanged()), this, SLOT(updateLayout()));
51 51
52 52 // Note: the following does not affect as long as the item does not have anything to paint
53 53 setZValue(ChartPresenter::PieSeriesZValue);
54 54
55 55 // Note: will not create slice items until we have a proper rectangle to draw on.
56 56 }
57 57
58 58 PieChartItem::~PieChartItem()
59 59 {
60 60 // slices deleted automatically through QGraphicsItem
61 61 }
62 62
63 63 void PieChartItem::setAnimation(PieAnimation* animation)
64 64 {
65 65 m_animation=animation;
66 66 }
67 67
68 68 ChartAnimation* PieChartItem::animation() const
69 69 {
70 70 return m_animation;
71 71 }
72 72
73 73 void PieChartItem::handleGeometryChanged(const QRectF& rect)
74 74 {
75 75 prepareGeometryChange();
76 76 m_rect = rect;
77 77 updateLayout();
78 78
79 79 // This is for delayed initialization of the slice items during startup.
80 80 // It ensures that startup animation originates from the correct position.
81 81 if (m_sliceItems.isEmpty())
82 82 handleSlicesAdded(m_series->slices());
83 83 }
84 84
85 85 void PieChartItem::handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY)
86 86 {
87 87 Q_UNUSED(minX);
88 88 Q_UNUSED(maxX);
89 89 Q_UNUSED(minY);
90 90 Q_UNUSED(maxY);
91 91 // does not apply to pie
92 92 }
93 93
94 94 void PieChartItem::handleDomainUpdated()
95 95 {
96 96 // does not apply to pie
97 97 }
98 98
99 99 void PieChartItem::rangeXChanged(qreal min, qreal max, int tickXCount)
100 100 {
101 101 Q_UNUSED(min);
102 102 Q_UNUSED(max);
103 103 Q_UNUSED(tickXCount);
104 104 // does not apply to pie
105 105 }
106 106
107 107 void PieChartItem::rangeYChanged(qreal min, qreal max, int tickYCount)
108 108 {
109 109 Q_UNUSED(min);
110 110 Q_UNUSED(max);
111 111 Q_UNUSED(tickYCount);
112 112 // does not apply to pie
113 113 }
114 114
115 115 void PieChartItem::updateLayout()
116 116 {
117 117 // find pie center coordinates
118 118 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
119 119 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
120 120
121 121 // find maximum radius for pie
122 122 m_pieRadius = m_rect.height() / 2;
123 123 if (m_rect.width() < m_rect.height())
124 124 m_pieRadius = m_rect.width() / 2;
125 125
126 126 m_holeSize = m_pieRadius;
127 127 // apply size factor
128 128 m_pieRadius *= m_series->pieSize();
129 129 m_holeSize *= m_series->holeSize();
130 130
131 131 // set layouts for existing slice items
132 132 foreach (QPieSlice* slice, m_series->slices()) {
133 133 PieSliceItem *sliceItem = m_sliceItems.value(slice);
134 134 if (sliceItem) {
135 135 PieSliceData sliceData = updateSliceGeometry(slice);
136 136 if (m_animation){
137 137 presenter()->startAnimation(m_animation->updateValue(sliceItem, sliceData));
138 138 }
139 139 else
140 140 sliceItem->setLayout(sliceData);
141 141 }
142 142 }
143 143
144 144 update();
145 145 }
146 146
147 147 void PieChartItem::handleSlicesAdded(QList<QPieSlice*> slices)
148 148 {
149 149 // delay creating slice items until there is a proper rectangle
150 150 if (!m_rect.isValid() && m_sliceItems.isEmpty())
151 151 return;
152 152
153 153 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
154 154
155 155 bool startupAnimation = m_sliceItems.isEmpty();
156 156
157 157 foreach (QPieSlice *slice, slices) {
158 158 PieSliceItem* sliceItem = new PieSliceItem(this);
159 159 m_sliceItems.insert(slice, sliceItem);
160 160
161 161 // Note: no need to connect to slice valueChanged() etc.
162 162 // This is handled through calculatedDataChanged signal.
163 163 connect(slice, SIGNAL(labelChanged()), this, SLOT(handleSliceChanged()));
164 164 connect(slice, SIGNAL(labelVisibleChanged()), this, SLOT(handleSliceChanged()));
165 165 connect(slice, SIGNAL(penChanged()), this, SLOT(handleSliceChanged()));
166 166 connect(slice, SIGNAL(brushChanged()), this, SLOT(handleSliceChanged()));
167 167 connect(slice, SIGNAL(labelBrushChanged()), this, SLOT(handleSliceChanged()));
168 168 connect(slice, SIGNAL(labelFontChanged()), this, SLOT(handleSliceChanged()));
169 169
170 170 QPieSlicePrivate *p = QPieSlicePrivate::fromSlice(slice);
171 171 connect(p, SIGNAL(labelPositionChanged()), this, SLOT(handleSliceChanged()));
172 172 connect(p, SIGNAL(explodedChanged()), this, SLOT(handleSliceChanged()));
173 173 connect(p, SIGNAL(labelArmLengthFactorChanged()), this, SLOT(handleSliceChanged()));
174 174 connect(p, SIGNAL(explodeDistanceFactorChanged()), this, SLOT(handleSliceChanged()));
175 175
176 176 connect(sliceItem, SIGNAL(clicked(Qt::MouseButtons)), slice, SIGNAL(clicked()));
177 177 connect(sliceItem, SIGNAL(hovered(bool)), slice, SIGNAL(hovered(bool)));
178 178
179 179 PieSliceData sliceData = updateSliceGeometry(slice);
180 180 if (m_animation)
181 181 presenter()->startAnimation(m_animation->addSlice(sliceItem, sliceData, startupAnimation));
182 182 else
183 183 sliceItem->setLayout(sliceData);
184 184 }
185 185 }
186 186
187 187 void PieChartItem::handleSlicesRemoved(QList<QPieSlice*> slices)
188 188 {
189 189 presenter()->chartTheme()->decorate(m_series, presenter()->dataSet()->seriesIndex(m_series));
190 190
191 191 foreach (QPieSlice *slice, slices) {
192 192
193 193 PieSliceItem *sliceItem = m_sliceItems.value(slice);
194 194
195 195 // this can happen if you call append() & remove() in a row so that PieSliceItem is not even created
196 196 if (!sliceItem)
197 197 continue;
198 198
199 199 m_sliceItems.remove(slice);
200 slice->disconnect(this);
201 QPieSlicePrivate::fromSlice(slice)->disconnect(this);
200 202
201 203 if (m_animation)
202 204 presenter()->startAnimation(m_animation->removeSlice(sliceItem)); // animator deletes the PieSliceItem
203 205 else
204 206 delete sliceItem;
205 207 }
206 208 }
207 209
208 210 void PieChartItem::handleSliceChanged()
209 211 {
210 212 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
211 213 if (!slice) {
212 214 QPieSlicePrivate* slicep = qobject_cast<QPieSlicePrivate *>(sender());
213 215 slice = slicep->q_ptr;
214 216 }
215 217 Q_ASSERT(m_sliceItems.contains(slice));
216 218
217 219 PieSliceItem *sliceItem = m_sliceItems.value(slice);
218 220 PieSliceData sliceData = updateSliceGeometry(slice);
219 221 if (m_animation)
220 222 presenter()->startAnimation(m_animation->updateValue(sliceItem, sliceData));
221 223 else
222 224 sliceItem->setLayout(sliceData);
223 225
224 226 update();
225 227 }
226 228
227 229 void PieChartItem::handleSeriesVisibleChanged()
228 230 {
229 231 setVisible(m_series->isVisible());
230 232 }
231 233
232 234 void PieChartItem::handleOpacityChanged()
233 235 {
234 236 setOpacity(m_series->opacity());
235 237 }
236 238
237 239 PieSliceData PieChartItem::updateSliceGeometry(QPieSlice *slice)
238 240 {
239 241 PieSliceData &sliceData = QPieSlicePrivate::fromSlice(slice)->m_data;
240 242 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
241 243 sliceData.m_radius = m_pieRadius;
242 244 sliceData.m_holeRadius = m_holeSize;
243 245 return sliceData;
244 246 }
245 247
246 248 #include "moc_piechartitem_p.cpp"
247 249
248 250 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,896 +1,898
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 "qpieslice_p.h"
25 25 #include "pieslicedata_p.h"
26 26 #include "chartdataset_p.h"
27 27 #include "charttheme_p.h"
28 28 #include "legendmarker_p.h"
29 29 #include "qabstractaxis.h"
30 30 #include "pieanimation_p.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} or \l {DonutChart Example} {donut chart example} to learn how to use QPieSeries.
50 50 \table 100%
51 51 \row
52 52 \o \image examples_piechart.png
53 53 \o \image examples_donut.png
54 54 \endtable
55 55 */
56 56 /*!
57 57 \qmlclass PieSeries QPieSeries
58 58 \inherits AbstractSeries
59 59
60 60 The following QML shows how to create a simple pie chart.
61 61
62 62 \snippet ../demos/qmlchart/qml/qmlchart/View1.qml 1
63 63
64 64 \beginfloatleft
65 65 \image demos_qmlchart1.png
66 66 \endfloat
67 67 \clearfloat
68 68 */
69 69
70 70 /*!
71 71 \property QPieSeries::horizontalPosition
72 72 \brief Defines the horizontal position of the pie.
73 73
74 74 The value is a relative value to the chart rectangle where:
75 75
76 76 \list
77 77 \o 0.0 is the absolute left.
78 78 \o 1.0 is the absolute right.
79 79 \endlist
80 80 Default value is 0.5 (center).
81 81 \sa verticalPosition
82 82 */
83 83
84 84 /*!
85 85 \qmlproperty real PieSeries::horizontalPosition
86 86
87 87 Defines the horizontal position of the pie.
88 88
89 89 The value is a relative value to the chart rectangle where:
90 90
91 91 \list
92 92 \o 0.0 is the absolute left.
93 93 \o 1.0 is the absolute right.
94 94 \endlist
95 95 Default value is 0.5 (center).
96 96 \sa verticalPosition
97 97 */
98 98
99 99 /*!
100 100 \property QPieSeries::verticalPosition
101 101 \brief Defines the vertical position of the pie.
102 102
103 103 The value is a relative value to the chart rectangle where:
104 104
105 105 \list
106 106 \o 0.0 is the absolute top.
107 107 \o 1.0 is the absolute bottom.
108 108 \endlist
109 109 Default value is 0.5 (center).
110 110 \sa horizontalPosition
111 111 */
112 112
113 113 /*!
114 114 \qmlproperty real PieSeries::verticalPosition
115 115
116 116 Defines the vertical position of the pie.
117 117
118 118 The value is a relative value to the chart rectangle where:
119 119
120 120 \list
121 121 \o 0.0 is the absolute top.
122 122 \o 1.0 is the absolute bottom.
123 123 \endlist
124 124 Default value is 0.5 (center).
125 125 \sa horizontalPosition
126 126 */
127 127
128 128 /*!
129 129 \property QPieSeries::size
130 130 \brief Defines the pie size.
131 131
132 132 The value is a relative value to the chart rectangle where:
133 133
134 134 \list
135 135 \o 0.0 is the minimum size (pie not drawn).
136 136 \o 1.0 is the maximum size that can fit the chart.
137 137 \endlist
138 138
139 139 When setting this property the holeSize property is adjusted if necessary, to ensure that the hole size is not greater than the outer size.
140 140
141 141 Default value is 0.7.
142 142 */
143 143
144 144 /*!
145 145 \qmlproperty real PieSeries::size
146 146
147 147 Defines the pie size.
148 148
149 149 The value is a relative value to the chart rectangle where:
150 150
151 151 \list
152 152 \o 0.0 is the minimum size (pie not drawn).
153 153 \o 1.0 is the maximum size that can fit the chart.
154 154 \endlist
155 155
156 156 Default value is 0.7.
157 157 */
158 158
159 159 /*!
160 160 \property QPieSeries::holeSize
161 161 \brief Defines the donut hole size.
162 162
163 163 The value is a relative value to the chart rectangle where:
164 164
165 165 \list
166 166 \o 0.0 is the minimum size (full pie drawn, without any hole inside).
167 167 \o 1.0 is the maximum size that can fit the chart. (donut has no width)
168 168 \endlist
169 169
170 170 The value is never greater then size property.
171 171 Default value is 0.0.
172 172 */
173 173
174 174 /*!
175 175 \qmlproperty real PieSeries::holeSize
176 176
177 177 Defines the donut hole size.
178 178
179 179 The value is a relative value to the chart rectangle where:
180 180
181 181 \list
182 182 \o 0.0 is the minimum size (full pie drawn, without any hole inside).
183 183 \o 1.0 is the maximum size that can fit the chart. (donut has no width)
184 184 \endlist
185 185
186 186 When setting this property the size property is adjusted if necessary, to ensure that the inner size is not greater than the outer size.
187 187
188 188 Default value is 0.0.
189 189 */
190 190
191 191 /*!
192 192 \property QPieSeries::startAngle
193 193 \brief Defines the starting angle of the pie.
194 194
195 195 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
196 196
197 197 Default is value is 0.
198 198 */
199 199
200 200 /*!
201 201 \qmlproperty real PieSeries::startAngle
202 202
203 203 Defines the starting angle of the pie.
204 204
205 205 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
206 206
207 207 Default is value is 0.
208 208 */
209 209
210 210 /*!
211 211 \property QPieSeries::endAngle
212 212 \brief Defines the ending angle of the pie.
213 213
214 214 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
215 215
216 216 Default is value is 360.
217 217 */
218 218
219 219 /*!
220 220 \qmlproperty real PieSeries::endAngle
221 221
222 222 Defines the ending angle of the pie.
223 223
224 224 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
225 225
226 226 Default is value is 360.
227 227 */
228 228
229 229 /*!
230 230 \property QPieSeries::count
231 231
232 232 Number of slices in the series.
233 233 */
234 234
235 235 /*!
236 236 \qmlproperty int PieSeries::count
237 237
238 238 Number of slices in the series.
239 239 */
240 240
241 241 /*!
242 242 \fn void QPieSeries::countChanged()
243 243 Emitted when the slice count has changed.
244 244 \sa count
245 245 */
246 246 /*!
247 247 \qmlsignal PieSeries::onCountChanged()
248 248 Emitted when the slice count has changed.
249 249 */
250 250
251 251 /*!
252 252 \property QPieSeries::sum
253 253
254 254 Sum of all slices.
255 255
256 256 The series keeps track of the sum of all slices it holds.
257 257 */
258 258
259 259 /*!
260 260 \qmlproperty real PieSeries::sum
261 261
262 262 Sum of all slices.
263 263
264 264 The series keeps track of the sum of all slices it holds.
265 265 */
266 266
267 267 /*!
268 268 \fn void QPieSeries::sumChanged()
269 269 Emitted when the sum of all slices has changed.
270 270 \sa sum
271 271 */
272 272 /*!
273 273 \qmlsignal PieSeries::onSumChanged()
274 274 Emitted when the sum of all slices has changed. This may happen for example if you add or remove slices, or if you
275 275 change value of a slice.
276 276 */
277 277
278 278 /*!
279 279 \fn void QPieSeries::added(QList<QPieSlice*> slices)
280 280
281 281 This signal is emitted when \a slices have been added to the series.
282 282
283 283 \sa append(), insert()
284 284 */
285 285 /*!
286 286 \qmlsignal PieSeries::onAdded(PieSlice slice)
287 287 Emitted when \a slice has been added to the series.
288 288 */
289 289
290 290 /*!
291 291 \fn void QPieSeries::removed(QList<QPieSlice*> slices)
292 292 This signal is emitted when \a slices have been removed from the series.
293 293 \sa remove()
294 294 */
295 295 /*!
296 296 \qmlsignal PieSeries::onRemoved(PieSlice slice)
297 297 Emitted when \a slice has been removed from the series.
298 298 */
299 299
300 300 /*!
301 301 \fn void QPieSeries::clicked(QPieSlice* slice)
302 302 This signal is emitted when a \a slice has been clicked.
303 303 \sa QPieSlice::clicked()
304 304 */
305 305 /*!
306 306 \qmlsignal PieSeries::onClicked(PieSlice slice)
307 307 This signal is emitted when a \a slice has been clicked.
308 308 */
309 309
310 310 /*!
311 311 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
312 312 This signal is emitted when user has hovered over or away from the \a slice.
313 313 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
314 314 \sa QPieSlice::hovered()
315 315 */
316 316 /*!
317 317 \qmlsignal PieSeries::onHovered(PieSlice slice, bool state)
318 318 This signal is emitted when user has hovered over or away from the \a slice. \a state is true when user has hovered
319 319 over the slice and false when hover has moved away from the slice.
320 320 */
321 321
322 322 /*!
323 323 \qmlmethod PieSlice PieSeries::at(int index)
324 324 Returns slice at \a index. Returns null if the index is not valid.
325 325 */
326 326
327 327 /*!
328 328 \qmlmethod PieSlice PieSeries::find(string label)
329 329 Returns the first slice with \a label. Returns null if the index is not valid.
330 330 */
331 331
332 332 /*!
333 333 \qmlmethod PieSlice PieSeries::append(string label, real value)
334 334 Adds a new slice with \a label and \a value to the pie.
335 335 */
336 336
337 337 /*!
338 338 \qmlmethod bool PieSeries::remove(PieSlice slice)
339 339 Removes the \a slice from the pie. Returns true if the removal was successful, false otherwise.
340 340 */
341 341
342 342 /*!
343 343 \qmlmethod PieSeries::clear()
344 344 Removes all slices from the pie.
345 345 */
346 346
347 347 /*!
348 348 Constructs a series object which is a child of \a parent.
349 349 */
350 350 QPieSeries::QPieSeries(QObject *parent) :
351 351 QAbstractSeries(*new QPieSeriesPrivate(this),parent)
352 352 {
353 353
354 354 }
355 355
356 356 /*!
357 357 Destroys the series and its slices.
358 358 */
359 359 QPieSeries::~QPieSeries()
360 360 {
361 361 // NOTE: d_prt destroyed by QObject
362 362 }
363 363
364 364 /*!
365 365 Returns QChartSeries::SeriesTypePie.
366 366 */
367 367 QAbstractSeries::SeriesType QPieSeries::type() const
368 368 {
369 369 return QAbstractSeries::SeriesTypePie;
370 370 }
371 371
372 372 /*!
373 373 Appends a single \a slice to the series.
374 374 Slice ownership is passed to the series.
375 375
376 376 Returns true if append was succesfull.
377 377 */
378 378 bool QPieSeries::append(QPieSlice* slice)
379 379 {
380 380 return append(QList<QPieSlice*>() << slice);
381 381 }
382 382
383 383 /*!
384 384 Appends an array of \a slices to the series.
385 385 Slice ownership is passed to the series.
386 386
387 387 Returns true if append was successful.
388 388 */
389 389 bool QPieSeries::append(QList<QPieSlice*> slices)
390 390 {
391 391 Q_D(QPieSeries);
392 392
393 393 if (slices.count() == 0)
394 394 return false;
395 395
396 396 foreach (QPieSlice* s, slices) {
397 397 if (!s || d->m_slices.contains(s))
398 398 return false;
399 399 if (s->series()) // already added to some series
400 400 return false;
401 401 }
402 402
403 403 foreach (QPieSlice* s, slices) {
404 404 s->setParent(this);
405 405 QPieSlicePrivate::fromSlice(s)->m_series = this;
406 406 d->m_slices << s;
407 407 }
408 408
409 409 d->updateDerivativeData();
410 410
411 411 foreach (QPieSlice* s, slices) {
412 412 connect(s, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
413 413 connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
414 414 connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
415 415
416 416 connect(s, SIGNAL(labelChanged()), d, SLOT(updateLegendProperties()));
417 417 connect(s, SIGNAL(penChanged()), d, SLOT(updateLegendProperties()));
418 418 connect(s, SIGNAL(brushChanged()), d, SLOT(updateLegendProperties()));
419 419 connect(s, SIGNAL(labelBrushChanged()), d, SLOT(updateLegendProperties()));
420 420 connect(s, SIGNAL(labelFontChanged()), d, SLOT(updateLegendProperties()));
421 421 connect(s, SIGNAL(labelFontChanged()), d, SLOT(updateLegendProperties()));
422 422 }
423 423
424 424 emit added(slices);
425 425 emit countChanged();
426 426
427 427 return true;
428 428 }
429 429
430 430 /*!
431 431 Appends a single \a slice to the series and returns a reference to the series.
432 432 Slice ownership is passed to the series.
433 433 */
434 434 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
435 435 {
436 436 append(slice);
437 437 return *this;
438 438 }
439 439
440 440
441 441 /*!
442 442 Appends a single slice to the series with give \a value and \a label.
443 443 Slice ownership is passed to the series.
444 444 */
445 445 QPieSlice* QPieSeries::append(QString label, qreal value)
446 446 {
447 447 QPieSlice* slice = new QPieSlice(label, value);
448 448 append(slice);
449 449 return slice;
450 450 }
451 451
452 452 /*!
453 453 Inserts a single \a slice to the series before the slice at \a index position.
454 454 Slice ownership is passed to the series.
455 455
456 456 Returns true if insert was successful.
457 457 */
458 458 bool QPieSeries::insert(int index, QPieSlice* slice)
459 459 {
460 460 Q_D(QPieSeries);
461 461
462 462 if (index < 0 || index > d->m_slices.count())
463 463 return false;
464 464
465 465 if (!slice || d->m_slices.contains(slice))
466 466 return false;
467 467
468 468 if (slice->series()) // already added to some series
469 469 return false;
470 470
471 471 slice->setParent(this);
472 472 QPieSlicePrivate::fromSlice(slice)->m_series = this;
473 473 d->m_slices.insert(index, slice);
474 474
475 475 d->updateDerivativeData();
476 476
477 477 connect(slice, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
478 478 connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
479 479 connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
480 480
481 481 connect(slice, SIGNAL(labelChanged()), d, SLOT(updateLegendProperties()));
482 482 connect(slice, SIGNAL(penChanged()), d, SLOT(updateLegendProperties()));
483 483 connect(slice, SIGNAL(brushChanged()), d, SLOT(updateLegendProperties()));
484 484 connect(slice, SIGNAL(labelBrushChanged()), d, SLOT(updateLegendProperties()));
485 485 connect(slice, SIGNAL(labelFontChanged()), d, SLOT(updateLegendProperties()));
486 486 connect(slice, SIGNAL(labelFontChanged()), d, SLOT(updateLegendProperties()));
487 487
488 488 emit added(QList<QPieSlice*>() << slice);
489 489 emit countChanged();
490 490
491 491 return true;
492 492 }
493 493
494 494 /*!
495 495 Removes a single \a slice from the series and deletes the slice.
496 496
497 497 Do not reference the pointer after this call.
498 498
499 499 Returns true if remove was successful.
500 500 */
501 501 bool QPieSeries::remove(QPieSlice* slice)
502 502 {
503 503 Q_D(QPieSeries);
504 504
505 505 if (!d->m_slices.removeOne(slice))
506 506 return false;
507 507
508 508 d->updateDerivativeData();
509 509
510 510 emit removed(QList<QPieSlice*>() << slice);
511 511 emit countChanged();
512 512
513 513 delete slice;
514 514 slice = 0;
515 515
516 516 return true;
517 517 }
518 518
519 519 /*!
520 520 Takes a single \a slice from the series. Does not destroy the slice object.
521 521
522 522 NOTE: The series remains as the slice's parent object. You must set the
523 523 parent object to take full ownership.
524 524
525 525 Returns true if take was successful.
526 526 */
527 527 bool QPieSeries::take(QPieSlice* slice)
528 528 {
529 529 Q_D(QPieSeries);
530 530
531 531 if (!d->m_slices.removeOne(slice))
532 532 return false;
533 533
534 534 QPieSlicePrivate::fromSlice(slice)->m_series = 0;
535 slice->disconnect(d);
535 536
536 537 d->updateDerivativeData();
537 538
538 539 emit removed(QList<QPieSlice*>() << slice);
539 540 emit countChanged();
540 541
541 542 return true;
542 543 }
543 544
544 545 /*!
545 546 Clears all slices from the series.
546 547 */
547 548 void QPieSeries::clear()
548 549 {
549 550 Q_D(QPieSeries);
550 551 if (d->m_slices.count() == 0)
551 552 return;
552 553
553 554 QList<QPieSlice*> slices = d->m_slices;
554 foreach (QPieSlice* s, d->m_slices) {
555 foreach (QPieSlice* s, d->m_slices)
555 556 d->m_slices.removeOne(s);
556 delete s;
557 }
558 557
559 558 d->updateDerivativeData();
560 559
561 560 emit removed(slices);
562 561 emit countChanged();
562
563 foreach (QPieSlice* s, slices)
564 delete s;
563 565 }
564 566
565 567 /*!
566 568 Returns a list of slices that belong to this series.
567 569 */
568 570 QList<QPieSlice*> QPieSeries::slices() const
569 571 {
570 572 Q_D(const QPieSeries);
571 573 return d->m_slices;
572 574 }
573 575
574 576 /*!
575 577 returns the number of the slices in this series.
576 578 */
577 579 int QPieSeries::count() const
578 580 {
579 581 Q_D(const QPieSeries);
580 582 return d->m_slices.count();
581 583 }
582 584
583 585 /*!
584 586 Returns true is the series is empty.
585 587 */
586 588 bool QPieSeries::isEmpty() const
587 589 {
588 590 Q_D(const QPieSeries);
589 591 return d->m_slices.isEmpty();
590 592 }
591 593
592 594 /*!
593 595 Returns the sum of all slice values in this series.
594 596
595 597 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
596 598 */
597 599 qreal QPieSeries::sum() const
598 600 {
599 601 Q_D(const QPieSeries);
600 602 return d->m_sum;
601 603 }
602 604
603 605 void QPieSeries::setHoleSize(qreal holeSize)
604 606 {
605 607 Q_D(QPieSeries);
606 608 holeSize = qBound((qreal)0.0, holeSize, (qreal)1.0);
607 609 d->setSizes(holeSize, qMax(d->m_pieRelativeSize, holeSize));
608 610 }
609 611
610 612 qreal QPieSeries::holeSize() const
611 613 {
612 614 Q_D(const QPieSeries);
613 615 return d->m_holeRelativeSize;
614 616 }
615 617
616 618 void QPieSeries::setHorizontalPosition(qreal relativePosition)
617 619 {
618 620 Q_D(QPieSeries);
619 621
620 622 if (relativePosition < 0.0)
621 623 relativePosition = 0.0;
622 624 if (relativePosition > 1.0)
623 625 relativePosition = 1.0;
624 626
625 627 if (!qFuzzyIsNull(d->m_pieRelativeHorPos - relativePosition)) {
626 628 d->m_pieRelativeHorPos = relativePosition;
627 629 emit d->horizontalPositionChanged();
628 630 }
629 631 }
630 632
631 633 qreal QPieSeries::horizontalPosition() const
632 634 {
633 635 Q_D(const QPieSeries);
634 636 return d->m_pieRelativeHorPos;
635 637 }
636 638
637 639 void QPieSeries::setVerticalPosition(qreal relativePosition)
638 640 {
639 641 Q_D(QPieSeries);
640 642
641 643 if (relativePosition < 0.0)
642 644 relativePosition = 0.0;
643 645 if (relativePosition > 1.0)
644 646 relativePosition = 1.0;
645 647
646 648 if (!qFuzzyIsNull(d->m_pieRelativeVerPos - relativePosition)) {
647 649 d->m_pieRelativeVerPos = relativePosition;
648 650 emit d->verticalPositionChanged();
649 651 }
650 652 }
651 653
652 654 qreal QPieSeries::verticalPosition() const
653 655 {
654 656 Q_D(const QPieSeries);
655 657 return d->m_pieRelativeVerPos;
656 658 }
657 659
658 660 void QPieSeries::setPieSize(qreal relativeSize)
659 661 {
660 662 Q_D(QPieSeries);
661 663 relativeSize = qBound((qreal)0.0, relativeSize, (qreal)1.0);
662 664 d->setSizes(qMin(d->m_holeRelativeSize, relativeSize), relativeSize);
663 665
664 666 }
665 667
666 668 qreal QPieSeries::pieSize() const
667 669 {
668 670 Q_D(const QPieSeries);
669 671 return d->m_pieRelativeSize;
670 672 }
671 673
672 674
673 675 void QPieSeries::setPieStartAngle(qreal angle)
674 676 {
675 677 Q_D(QPieSeries);
676 678 if (qFuzzyIsNull(d->m_pieStartAngle - angle))
677 679 return;
678 680 d->m_pieStartAngle = angle;
679 681 d->updateDerivativeData();
680 682 emit d->pieStartAngleChanged();
681 683 }
682 684
683 685 qreal QPieSeries::pieStartAngle() const
684 686 {
685 687 Q_D(const QPieSeries);
686 688 return d->m_pieStartAngle;
687 689 }
688 690
689 691 /*!
690 692 Sets the end angle of the pie.
691 693
692 694 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
693 695
694 696 \a angle must be greater than start angle.
695 697
696 698 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
697 699 */
698 700 void QPieSeries::setPieEndAngle(qreal angle)
699 701 {
700 702 Q_D(QPieSeries);
701 703 if (qFuzzyIsNull(d->m_pieEndAngle - angle))
702 704 return;
703 705 d->m_pieEndAngle = angle;
704 706 d->updateDerivativeData();
705 707 emit d->pieEndAngleChanged();
706 708 }
707 709
708 710 /*!
709 711 Returns the end angle of the pie.
710 712
711 713 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
712 714
713 715 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
714 716 */
715 717 qreal QPieSeries::pieEndAngle() const
716 718 {
717 719 Q_D(const QPieSeries);
718 720 return d->m_pieEndAngle;
719 721 }
720 722
721 723 /*!
722 724 Sets the all the slice labels \a visible or invisible.
723 725
724 726 Note that this affects only the current slices in the series.
725 727 If user adds a new slice the default label visibility is false.
726 728
727 729 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
728 730 */
729 731 void QPieSeries::setLabelsVisible(bool visible)
730 732 {
731 733 Q_D(QPieSeries);
732 734 foreach (QPieSlice* s, d->m_slices)
733 735 s->setLabelVisible(visible);
734 736 }
735 737
736 738 /*!
737 739 Sets the all the slice labels \a position
738 740
739 741 Note that this affects only the current slices in the series.
740 742 If user adds a new slice the default label position is LabelOutside
741 743
742 744 \sa QPieSlice::labelPosition(), QPieSlice::setLabelPosition()
743 745 */
744 746 void QPieSeries::setLabelsPosition(QPieSlice::LabelPosition position)
745 747 {
746 748 Q_D(QPieSeries);
747 749 foreach (QPieSlice* s, d->m_slices)
748 750 s->setLabelPosition(position);
749 751 }
750 752
751 753 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
752 754
753 755
754 756 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
755 757 QAbstractSeriesPrivate(parent),
756 758 m_pieRelativeHorPos(0.5),
757 759 m_pieRelativeVerPos(0.5),
758 760 m_pieRelativeSize(0.7),
759 761 m_pieStartAngle(0),
760 762 m_pieEndAngle(360),
761 763 m_sum(0),
762 764 m_holeRelativeSize(0.0)
763 765 {
764 766 }
765 767
766 768 QPieSeriesPrivate::~QPieSeriesPrivate()
767 769 {
768 770 }
769 771
770 772 void QPieSeriesPrivate::updateDerivativeData()
771 773 {
772 774 // calculate sum of all slices
773 775 qreal sum = 0;
774 776 foreach (QPieSlice* s, m_slices)
775 777 sum += s->value();
776 778
777 779 if (!qFuzzyIsNull(m_sum - sum)) {
778 780 m_sum = sum;
779 781 emit q_func()->sumChanged();
780 782 }
781 783
782 784 // nothing to show..
783 785 if (qFuzzyIsNull(m_sum))
784 786 return;
785 787
786 788 // update slice attributes
787 789 qreal sliceAngle = m_pieStartAngle;
788 790 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
789 791 QVector<QPieSlice*> changed;
790 792 foreach (QPieSlice* s, m_slices) {
791 793 QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
792 794 d->setPercentage(s->value() / m_sum);
793 795 d->setStartAngle(sliceAngle);
794 796 d->setAngleSpan(pieSpan * s->percentage());
795 797 sliceAngle += s->angleSpan();
796 798 }
797 799
798 800
799 801 emit calculatedDataChanged();
800 802 }
801 803
802 804 void QPieSeriesPrivate::setSizes(qreal innerSize, qreal outerSize)
803 805 {
804 806 bool changed = false;
805 807
806 808 if (!qFuzzyIsNull(m_holeRelativeSize - innerSize)) {
807 809 m_holeRelativeSize = innerSize;
808 810 changed = true;
809 811 }
810 812
811 813 if (!qFuzzyIsNull(m_pieRelativeSize - outerSize)) {
812 814 m_pieRelativeSize = outerSize;
813 815 changed = true;
814 816 }
815 817
816 818 if (changed)
817 819 emit pieSizeChanged();
818 820 }
819 821
820 822 QPieSeriesPrivate* QPieSeriesPrivate::fromSeries(QPieSeries *series)
821 823 {
822 824 return series->d_func();
823 825 }
824 826
825 827 void QPieSeriesPrivate::sliceValueChanged()
826 828 {
827 829 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
828 830 updateDerivativeData();
829 831 }
830 832
831 833 void QPieSeriesPrivate::sliceClicked()
832 834 {
833 835 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
834 836 Q_ASSERT(m_slices.contains(slice));
835 837 Q_Q(QPieSeries);
836 838 emit q->clicked(slice);
837 839 }
838 840
839 841 void QPieSeriesPrivate::sliceHovered(bool state)
840 842 {
841 843 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
842 844 Q_ASSERT(m_slices.contains(slice));
843 845 Q_Q(QPieSeries);
844 846 emit q->hovered(slice, state);
845 847 }
846 848
847 849 void QPieSeriesPrivate::updateLegendProperties()
848 850 {
849 851 // This slot listens to all properties of slices, which may interest legend and signals it.
850 852 Q_Q(QPieSeries);
851 853 emit legendPropertiesUpdated(q);
852 854 }
853 855
854 856 void QPieSeriesPrivate::scaleDomain(Domain& domain)
855 857 {
856 858 Q_UNUSED(domain);
857 859 // does not apply to pie
858 860 }
859 861
860 862 ChartElement* QPieSeriesPrivate::createGraphics(ChartPresenter* presenter)
861 863 {
862 864 Q_Q(QPieSeries);
863 865 PieChartItem* pie = new PieChartItem(q,presenter);
864 866 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
865 867 pie->setAnimation(new PieAnimation(pie));
866 868 }
867 869 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
868 870 return pie;
869 871 }
870 872
871 873 QList<LegendMarker*> QPieSeriesPrivate::createLegendMarker(QLegend* legend)
872 874 {
873 875 Q_Q(QPieSeries);
874 876 QList<LegendMarker*> markers;
875 877 foreach(QPieSlice* slice, q->slices()) {
876 878 PieLegendMarker* marker = new PieLegendMarker(q,slice,legend);
877 879 markers << marker;
878 880 }
879 881 return markers;
880 882 }
881 883
882 884 void QPieSeriesPrivate::initializeAxis(QAbstractAxis* axis)
883 885 {
884 886 Q_UNUSED(axis);
885 887 }
886 888
887 889 QAbstractAxis::AxisType QPieSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
888 890 {
889 891 Q_UNUSED(orientation);
890 892 return QAbstractAxis::AxisTypeNoAxis;
891 893 }
892 894
893 895 #include "moc_qpieseries.cpp"
894 896 #include "moc_qpieseries_p.cpp"
895 897
896 898 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now