##// END OF EJS Templates
Remove QPieSeries::replace(). The function does not really make sense with the pie.
Jani Honkonen -
r1013:bd5d49d1f7af
parent child
Show More
@@ -1,697 +1,687
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2012 Digia Plc
3 ** Copyright (C) 2012 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "qpieseries.h"
21 #include "qpieseries.h"
22 #include "qpieseries_p.h"
22 #include "qpieseries_p.h"
23 #include "qpieslice.h"
23 #include "qpieslice.h"
24 #include "pieslicedata_p.h"
24 #include "pieslicedata_p.h"
25 #include "chartdataset_p.h"
25 #include "chartdataset_p.h"
26 #include "charttheme_p.h"
26 #include "charttheme_p.h"
27 #include "chartanimator_p.h"
27 #include "chartanimator_p.h"
28 #include "legendmarker_p.h"
28 #include "legendmarker_p.h"
29 #include <QAbstractItemModel>
29 #include <QAbstractItemModel>
30
30
31 QTCOMMERCIALCHART_BEGIN_NAMESPACE
31 QTCOMMERCIALCHART_BEGIN_NAMESPACE
32
32
33 /*!
33 /*!
34 \class QPieSeries
34 \class QPieSeries
35 \brief Pie series API for QtCommercial Charts
35 \brief Pie series API for QtCommercial Charts
36
36
37 The pie series defines a pie chart which consists of pie slices which are defined as QPieSlice objects.
37 The pie series defines a pie chart which consists of pie slices which are defined as QPieSlice objects.
38 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
38 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
39 The actual slice size is determined by that relative value.
39 The actual slice size is determined by that relative value.
40
40
41 Pie size and position on the chart is controlled by using relative values which range from 0.0 to 1.0
41 Pie size and position on the chart is controlled by using relative values which range from 0.0 to 1.0
42 These relate to the actual chart rectangle.
42 These relate to the actual chart rectangle.
43
43
44 By default the pie is defined as a full pie but it can also be a partial pie.
44 By default the pie is defined as a full pie but it can also be a partial pie.
45 This can be done by setting a starting angle and angle span to the series.
45 This can be done by setting a starting angle and angle span to the series.
46 Full pie is 360 degrees where 0 is at 12 a'clock.
46 Full pie is 360 degrees where 0 is at 12 a'clock.
47
47
48 See the \l {PieChart Example} {pie chart example} to learn how to create a simple pie chart.
48 See the \l {PieChart Example} {pie chart example} to learn how to create a simple pie chart.
49 \image examples_piechart.png
49 \image examples_piechart.png
50 */
50 */
51
51
52 /*!
52 /*!
53 \property QPieSeries::horizontalPosition
53 \property QPieSeries::horizontalPosition
54 \brief Defines the horizontal position of the pie.
54 \brief Defines the horizontal position of the pie.
55
55
56 The value is a relative value to the chart rectangle where:
56 The value is a relative value to the chart rectangle where:
57
57
58 \list
58 \list
59 \o 0.0 is the absolute left.
59 \o 0.0 is the absolute left.
60 \o 1.0 is the absolute right.
60 \o 1.0 is the absolute right.
61 \endlist
61 \endlist
62
62
63 Default value is 0.5 (center).
63 Default value is 0.5 (center).
64 */
64 */
65
65
66 /*!
66 /*!
67 \property QPieSeries::verticalPosition
67 \property QPieSeries::verticalPosition
68 \brief Defines the vertical position of the pie.
68 \brief Defines the vertical position of the pie.
69
69
70 The value is a relative value to the chart rectangle where:
70 The value is a relative value to the chart rectangle where:
71
71
72 \list
72 \list
73 \o 0.0 is the absolute top.
73 \o 0.0 is the absolute top.
74 \o 1.0 is the absolute bottom.
74 \o 1.0 is the absolute bottom.
75 \endlist
75 \endlist
76
76
77 Default value is 0.5 (center).
77 Default value is 0.5 (center).
78 */
78 */
79
79
80 /*!
80 /*!
81 \property QPieSeries::size
81 \property QPieSeries::size
82 \brief Defines the pie size.
82 \brief Defines the pie size.
83
83
84 The value is a relative value to the chart rectangle where:
84 The value is a relative value to the chart rectangle where:
85
85
86 \list
86 \list
87 \o 0.0 is the minimum size (pie not drawn).
87 \o 0.0 is the minimum size (pie not drawn).
88 \o 1.0 is the maximum size that can fit the chart.
88 \o 1.0 is the maximum size that can fit the chart.
89 \endlist
89 \endlist
90
90
91 Default value is 0.7.
91 Default value is 0.7.
92 */
92 */
93
93
94 /*!
94 /*!
95 \property QPieSeries::startAngle
95 \property QPieSeries::startAngle
96 \brief Defines the starting angle of the pie.
96 \brief Defines the starting angle of the pie.
97
97
98 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
98 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
99
99
100 Default is value is 0.
100 Default is value is 0.
101 */
101 */
102
102
103 /*!
103 /*!
104 \property QPieSeries::endAngle
104 \property QPieSeries::endAngle
105 \brief Defines the ending angle of the pie.
105 \brief Defines the ending angle of the pie.
106
106
107 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
107 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
108
108
109 Default is value is 360.
109 Default is value is 360.
110 */
110 */
111
111
112
112
113 /*!
113 /*!
114 Constructs a series object which is a child of \a parent.
114 Constructs a series object which is a child of \a parent.
115 */
115 */
116 QPieSeries::QPieSeries(QObject *parent) :
116 QPieSeries::QPieSeries(QObject *parent) :
117 QAbstractSeries(*new QPieSeriesPrivate(this),parent)
117 QAbstractSeries(*new QPieSeriesPrivate(this),parent)
118 {
118 {
119
119
120 }
120 }
121
121
122 /*!
122 /*!
123 Destroys the series and its slices.
123 Destroys the series and its slices.
124 */
124 */
125 QPieSeries::~QPieSeries()
125 QPieSeries::~QPieSeries()
126 {
126 {
127 // NOTE: d_prt destroyed by QObject
127 // NOTE: d_prt destroyed by QObject
128 }
128 }
129
129
130 /*!
130 /*!
131 Returns QChartSeries::SeriesTypePie.
131 Returns QChartSeries::SeriesTypePie.
132 */
132 */
133 QAbstractSeries::QSeriesType QPieSeries::type() const
133 QAbstractSeries::QSeriesType QPieSeries::type() const
134 {
134 {
135 return QAbstractSeries::SeriesTypePie;
135 return QAbstractSeries::SeriesTypePie;
136 }
136 }
137
137
138 /*!
138 /*!
139 Sets an array of \a slices to the series replacing the existing slices.
140 Slice ownership is passed to the series.
141 */
142 void QPieSeries::replace(QList<QPieSlice*> slices)
143 {
144 clear();
145 append(slices);
146 }
147
148 /*!
149 Appends an array of \a slices to the series.
139 Appends an array of \a slices to the series.
150 Slice ownership is passed to the series.
140 Slice ownership is passed to the series.
151 */
141 */
152 void QPieSeries::append(QList<QPieSlice*> slices)
142 void QPieSeries::append(QList<QPieSlice*> slices)
153 {
143 {
154 Q_D(QPieSeries);
144 Q_D(QPieSeries);
155
145
156 foreach (QPieSlice* s, slices) {
146 foreach (QPieSlice* s, slices) {
157 s->setParent(this);
147 s->setParent(this);
158 d->m_slices << s;
148 d->m_slices << s;
159 }
149 }
160
150
161 d->updateDerivativeData();
151 d->updateDerivativeData();
162
152
163 foreach (QPieSlice* s, slices) {
153 foreach (QPieSlice* s, slices) {
164 connect(s, SIGNAL(changed()), d, SLOT(sliceChanged()));
154 connect(s, SIGNAL(changed()), d, SLOT(sliceChanged()));
165 connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
155 connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
166 connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
156 connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
167 }
157 }
168
158
169 emit d->added(slices);
159 emit d->added(slices);
170 }
160 }
171
161
172 /*!
162 /*!
173 Appends a single \a slice to the series.
163 Appends a single \a slice to the series.
174 Slice ownership is passed to the series.
164 Slice ownership is passed to the series.
175 */
165 */
176 void QPieSeries::append(QPieSlice* slice)
166 void QPieSeries::append(QPieSlice* slice)
177 {
167 {
178 append(QList<QPieSlice*>() << slice);
168 append(QList<QPieSlice*>() << slice);
179 }
169 }
180
170
181 /*!
171 /*!
182 Appends a single \a slice to the series and returns a reference to the series.
172 Appends a single \a slice to the series and returns a reference to the series.
183 Slice ownership is passed to the series.
173 Slice ownership is passed to the series.
184 */
174 */
185 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
175 QPieSeries& QPieSeries::operator << (QPieSlice* slice)
186 {
176 {
187 append(slice);
177 append(slice);
188 return *this;
178 return *this;
189 }
179 }
190
180
191
181
192 /*!
182 /*!
193 Appends a single slice to the series with give \a value and \a name.
183 Appends a single slice to the series with give \a value and \a name.
194 Slice ownership is passed to the series.
184 Slice ownership is passed to the series.
195 */
185 */
196 QPieSlice* QPieSeries::append(qreal value, QString name)
186 QPieSlice* QPieSeries::append(qreal value, QString name)
197 {
187 {
198 QPieSlice* slice = new QPieSlice(value, name);
188 QPieSlice* slice = new QPieSlice(value, name);
199 append(slice);
189 append(slice);
200 return slice;
190 return slice;
201 }
191 }
202
192
203 /*!
193 /*!
204 Inserts a single \a slice to the series before the slice at \a index position.
194 Inserts a single \a slice to the series before the slice at \a index position.
205 Slice ownership is passed to the series.
195 Slice ownership is passed to the series.
206 */
196 */
207 void QPieSeries::insert(int index, QPieSlice* slice)
197 void QPieSeries::insert(int index, QPieSlice* slice)
208 {
198 {
209 Q_D(QPieSeries);
199 Q_D(QPieSeries);
210 Q_ASSERT(index <= d->m_slices.count());
200 Q_ASSERT(index <= d->m_slices.count());
211 slice->setParent(this);
201 slice->setParent(this);
212 d->m_slices.insert(index, slice);
202 d->m_slices.insert(index, slice);
213
203
214 d->updateDerivativeData();
204 d->updateDerivativeData();
215
205
216 connect(slice, SIGNAL(changed()), d, SLOT(sliceChanged()));
206 connect(slice, SIGNAL(changed()), d, SLOT(sliceChanged()));
217 connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
207 connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
218 connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
208 connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
219
209
220 emit d->added(QList<QPieSlice*>() << slice);
210 emit d->added(QList<QPieSlice*>() << slice);
221 }
211 }
222
212
223 /*!
213 /*!
224 Removes a single \a slice from the series and deletes the slice.
214 Removes a single \a slice from the series and deletes the slice.
225
215
226 Do not reference the pointer after this call.
216 Do not reference the pointer after this call.
227 */
217 */
228 void QPieSeries::remove(QPieSlice* slice)
218 void QPieSeries::remove(QPieSlice* slice)
229 {
219 {
230 Q_D(QPieSeries);
220 Q_D(QPieSeries);
231 if (!d->m_slices.removeOne(slice)) {
221 if (!d->m_slices.removeOne(slice)) {
232 Q_ASSERT(0); // TODO: how should this be reported?
222 Q_ASSERT(0); // TODO: how should this be reported?
233 return;
223 return;
234 }
224 }
235
225
236 d->updateDerivativeData();
226 d->updateDerivativeData();
237
227
238 emit d->removed(QList<QPieSlice*>() << slice);
228 emit d->removed(QList<QPieSlice*>() << slice);
239
229
240 delete slice;
230 delete slice;
241 slice = 0;
231 slice = 0;
242 }
232 }
243
233
244 /*!
234 /*!
245 Clears all slices from the series.
235 Clears all slices from the series.
246 */
236 */
247 void QPieSeries::clear()
237 void QPieSeries::clear()
248 {
238 {
249 Q_D(QPieSeries);
239 Q_D(QPieSeries);
250 if (d->m_slices.count() == 0)
240 if (d->m_slices.count() == 0)
251 return;
241 return;
252
242
253 QList<QPieSlice*> slices = d->m_slices;
243 QList<QPieSlice*> slices = d->m_slices;
254 foreach (QPieSlice* s, d->m_slices) {
244 foreach (QPieSlice* s, d->m_slices) {
255 d->m_slices.removeOne(s);
245 d->m_slices.removeOne(s);
256 delete s;
246 delete s;
257 }
247 }
258
248
259 d->updateDerivativeData();
249 d->updateDerivativeData();
260
250
261 emit d->removed(slices);
251 emit d->removed(slices);
262 }
252 }
263
253
264 /*!
254 /*!
265 returns the number of the slices in this series.
255 returns the number of the slices in this series.
266 */
256 */
267 int QPieSeries::count() const
257 int QPieSeries::count() const
268 {
258 {
269 Q_D(const QPieSeries);
259 Q_D(const QPieSeries);
270 return d->m_slices.count();
260 return d->m_slices.count();
271 }
261 }
272
262
273 /*!
263 /*!
274 Returns true is the series is empty.
264 Returns true is the series is empty.
275 */
265 */
276 bool QPieSeries::isEmpty() const
266 bool QPieSeries::isEmpty() const
277 {
267 {
278 Q_D(const QPieSeries);
268 Q_D(const QPieSeries);
279 return d->m_slices.isEmpty();
269 return d->m_slices.isEmpty();
280 }
270 }
281
271
282 /*!
272 /*!
283 Returns a list of slices that belong to this series.
273 Returns a list of slices that belong to this series.
284 */
274 */
285 QList<QPieSlice*> QPieSeries::slices() const
275 QList<QPieSlice*> QPieSeries::slices() const
286 {
276 {
287 Q_D(const QPieSeries);
277 Q_D(const QPieSeries);
288 return d->m_slices;
278 return d->m_slices;
289 }
279 }
290
280
291 void QPieSeries::setHorizontalPosition(qreal relativePosition)
281 void QPieSeries::setHorizontalPosition(qreal relativePosition)
292 {
282 {
293 Q_D(QPieSeries);
283 Q_D(QPieSeries);
294 if (d->setRealValue(d->m_pieRelativeHorPos, relativePosition, 1.0))
284 if (d->setRealValue(d->m_pieRelativeHorPos, relativePosition, 1.0))
295 emit d->piePositionChanged();
285 emit d->piePositionChanged();
296 }
286 }
297
287
298 void QPieSeries::setVerticalPosition(qreal relativePosition)
288 void QPieSeries::setVerticalPosition(qreal relativePosition)
299 {
289 {
300 Q_D(QPieSeries);
290 Q_D(QPieSeries);
301 if (d->setRealValue(d->m_pieRelativeVerPos, relativePosition, 1.0))
291 if (d->setRealValue(d->m_pieRelativeVerPos, relativePosition, 1.0))
302 emit d->piePositionChanged();
292 emit d->piePositionChanged();
303 }
293 }
304
294
305 qreal QPieSeries::horizontalPosition() const
295 qreal QPieSeries::horizontalPosition() const
306 {
296 {
307 Q_D(const QPieSeries);
297 Q_D(const QPieSeries);
308 return d->m_pieRelativeHorPos;
298 return d->m_pieRelativeHorPos;
309 }
299 }
310
300
311 qreal QPieSeries::verticalPosition() const
301 qreal QPieSeries::verticalPosition() const
312 {
302 {
313 Q_D(const QPieSeries);
303 Q_D(const QPieSeries);
314 return d->m_pieRelativeVerPos;
304 return d->m_pieRelativeVerPos;
315 }
305 }
316
306
317 void QPieSeries::setPieSize(qreal relativeSize)
307 void QPieSeries::setPieSize(qreal relativeSize)
318 {
308 {
319 Q_D(QPieSeries);
309 Q_D(QPieSeries);
320 if (d->setRealValue(d->m_pieRelativeSize, relativeSize, 1.0))
310 if (d->setRealValue(d->m_pieRelativeSize, relativeSize, 1.0))
321 emit d->pieSizeChanged();
311 emit d->pieSizeChanged();
322 }
312 }
323
313
324 qreal QPieSeries::pieSize() const
314 qreal QPieSeries::pieSize() const
325 {
315 {
326 Q_D(const QPieSeries);
316 Q_D(const QPieSeries);
327 return d->m_pieRelativeSize;
317 return d->m_pieRelativeSize;
328 }
318 }
329
319
330
320
331 void QPieSeries::setPieStartAngle(qreal angle)
321 void QPieSeries::setPieStartAngle(qreal angle)
332 {
322 {
333 Q_D(QPieSeries);
323 Q_D(QPieSeries);
334 if (d->setRealValue(d->m_pieStartAngle, angle, d->m_pieEndAngle))
324 if (d->setRealValue(d->m_pieStartAngle, angle, d->m_pieEndAngle))
335 d->updateDerivativeData();
325 d->updateDerivativeData();
336 }
326 }
337
327
338 qreal QPieSeries::pieStartAngle() const
328 qreal QPieSeries::pieStartAngle() const
339 {
329 {
340 Q_D(const QPieSeries);
330 Q_D(const QPieSeries);
341 return d->m_pieStartAngle;
331 return d->m_pieStartAngle;
342 }
332 }
343
333
344 /*!
334 /*!
345 Sets the end angle of the pie.
335 Sets the end angle of the pie.
346
336
347 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
337 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
348
338
349 \a angle must be greater than start angle.
339 \a angle must be greater than start angle.
350
340
351 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
341 \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
352 */
342 */
353 void QPieSeries::setPieEndAngle(qreal angle)
343 void QPieSeries::setPieEndAngle(qreal angle)
354 {
344 {
355 Q_D(QPieSeries);
345 Q_D(QPieSeries);
356
346
357 if (d->setRealValue(d->m_pieEndAngle, angle, 360.0, d->m_pieStartAngle))
347 if (d->setRealValue(d->m_pieEndAngle, angle, 360.0, d->m_pieStartAngle))
358 d->updateDerivativeData();
348 d->updateDerivativeData();
359 }
349 }
360
350
361 /*!
351 /*!
362 Returns the end angle of the pie.
352 Returns the end angle of the pie.
363
353
364 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
354 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
365
355
366 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
356 \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
367 */
357 */
368 qreal QPieSeries::pieEndAngle() const
358 qreal QPieSeries::pieEndAngle() const
369 {
359 {
370 Q_D(const QPieSeries);
360 Q_D(const QPieSeries);
371 return d->m_pieEndAngle;
361 return d->m_pieEndAngle;
372 }
362 }
373
363
374 /*!
364 /*!
375 Sets the all the slice labels \a visible or invisible.
365 Sets the all the slice labels \a visible or invisible.
376
366
377 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
367 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
378 */
368 */
379 void QPieSeries::setLabelsVisible(bool visible)
369 void QPieSeries::setLabelsVisible(bool visible)
380 {
370 {
381 Q_D(QPieSeries);
371 Q_D(QPieSeries);
382 foreach (QPieSlice* s, d->m_slices)
372 foreach (QPieSlice* s, d->m_slices)
383 s->setLabelVisible(visible);
373 s->setLabelVisible(visible);
384 }
374 }
385
375
386 /*!
376 /*!
387 Returns the sum of all slice values in this series.
377 Returns the sum of all slice values in this series.
388
378
389 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
379 \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
390 */
380 */
391 qreal QPieSeries::sum() const
381 qreal QPieSeries::sum() const
392 {
382 {
393 Q_D(const QPieSeries);
383 Q_D(const QPieSeries);
394 return d->m_sum;
384 return d->m_sum;
395 }
385 }
396
386
397 /*!
387 /*!
398 \fn void QPieSeries::clicked(QPieSlice* slice)
388 \fn void QPieSeries::clicked(QPieSlice* slice)
399
389
400 This signal is emitted when a \a slice has been clicked.
390 This signal is emitted when a \a slice has been clicked.
401
391
402 \sa QPieSlice::clicked()
392 \sa QPieSlice::clicked()
403 */
393 */
404
394
405 /*!
395 /*!
406 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
396 \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
407
397
408 This signal is emitted when user has hovered over or away from the \a slice.
398 This signal is emitted when user has hovered over or away from the \a slice.
409
399
410 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
400 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
411
401
412 \sa QPieSlice::hovered()
402 \sa QPieSlice::hovered()
413 */
403 */
414
404
415 /*!
405 /*!
416 \fn bool QPieSeries::setModel(QAbstractItemModel *model)
406 \fn bool QPieSeries::setModel(QAbstractItemModel *model)
417 Sets the \a model to be used as a data source
407 Sets the \a model to be used as a data source
418 */
408 */
419 bool QPieSeries::setModel(QAbstractItemModel* model)
409 bool QPieSeries::setModel(QAbstractItemModel* model)
420 {
410 {
421 Q_D(QPieSeries);
411 Q_D(QPieSeries);
422 // disconnect signals from old model
412 // disconnect signals from old model
423 if(d->m_model)
413 if(d->m_model)
424 {
414 {
425 disconnect(d->m_model, 0, this, 0);
415 disconnect(d->m_model, 0, this, 0);
426 d->m_mapValues = -1;
416 d->m_mapValues = -1;
427 d->m_mapLabels = -1;
417 d->m_mapLabels = -1;
428 d->m_mapOrientation = Qt::Vertical;
418 d->m_mapOrientation = Qt::Vertical;
429 }
419 }
430
420
431 // set new model
421 // set new model
432 if(model)
422 if(model)
433 {
423 {
434 d->m_model = model;
424 d->m_model = model;
435 return true;
425 return true;
436 }
426 }
437 else
427 else
438 {
428 {
439 d->m_model = 0;
429 d->m_model = 0;
440 return false;
430 return false;
441 }
431 }
442 }
432 }
443
433
444 /*!
434 /*!
445 \fn bool QPieSeries::setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation)
435 \fn bool QPieSeries::setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation)
446 Sets column/row specified by \a modelValuesLine to be used as a list of pie slice values for the pie.
436 Sets column/row specified by \a modelValuesLine to be used as a list of pie slice values for the pie.
447 Parameter \a modelValuesLine indicates the column/row where the values for the pie slices are located in the model.
437 Parameter \a modelValuesLine indicates the column/row where the values for the pie slices are located in the model.
448 Parameter \a modelLabelsLine indicates the column/row where the labels for the pie slices are located in the model.
438 Parameter \a modelLabelsLine indicates the column/row where the labels for the pie slices are located in the model.
449 The \a orientation parameter specifies whether the data is in columns or in rows.
439 The \a orientation parameter specifies whether the data is in columns or in rows.
450 */
440 */
451 void QPieSeries::setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation)
441 void QPieSeries::setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation)
452 {
442 {
453 Q_D(QPieSeries);
443 Q_D(QPieSeries);
454
444
455 if (d->m_model == 0)
445 if (d->m_model == 0)
456 return;
446 return;
457
447
458 d->m_mapValues = modelValuesLine;
448 d->m_mapValues = modelValuesLine;
459 d->m_mapLabels = modelLabelsLine;
449 d->m_mapLabels = modelLabelsLine;
460 d->m_mapOrientation = orientation;
450 d->m_mapOrientation = orientation;
461
451
462 // connect the signals
452 // connect the signals
463 if (d->m_mapOrientation == Qt::Vertical) {
453 if (d->m_mapOrientation == Qt::Vertical) {
464 connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
454 connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
465 connect(d->m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), d, SLOT(modelDataAdded(QModelIndex,int,int)));
455 connect(d->m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), d, SLOT(modelDataAdded(QModelIndex,int,int)));
466 connect(d->m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), d, SLOT(modelDataRemoved(QModelIndex,int,int)));
456 connect(d->m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), d, SLOT(modelDataRemoved(QModelIndex,int,int)));
467 } else {
457 } else {
468 connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
458 connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
469 connect(d->m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, SLOT(modelDataAdded(QModelIndex,int,int)));
459 connect(d->m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, SLOT(modelDataAdded(QModelIndex,int,int)));
470 connect(d->m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, SLOT(modelDataRemoved(QModelIndex,int,int)));
460 connect(d->m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, SLOT(modelDataRemoved(QModelIndex,int,int)));
471 }
461 }
472
462
473 // create the initial slices set
463 // create the initial slices set
474 if (d->m_mapOrientation == Qt::Vertical) {
464 if (d->m_mapOrientation == Qt::Vertical) {
475 for (int i = 0; i < d->m_model->rowCount(); i++)
465 for (int i = 0; i < d->m_model->rowCount(); i++)
476 append(d->m_model->data(d->m_model->index(i, d->m_mapValues), Qt::DisplayRole).toDouble(), d->m_model->data(d->m_model->index(i, d->m_mapLabels), Qt::DisplayRole).toString());
466 append(d->m_model->data(d->m_model->index(i, d->m_mapValues), Qt::DisplayRole).toDouble(), d->m_model->data(d->m_model->index(i, d->m_mapLabels), Qt::DisplayRole).toString());
477 } else {
467 } else {
478 for (int i = 0; i < d->m_model->columnCount(); i++)
468 for (int i = 0; i < d->m_model->columnCount(); i++)
479 append(d->m_model->data(d->m_model->index(d->m_mapValues, i), Qt::DisplayRole).toDouble(), d->m_model->data(d->m_model->index(d->m_mapLabels, i), Qt::DisplayRole).toString());
469 append(d->m_model->data(d->m_model->index(d->m_mapValues, i), Qt::DisplayRole).toDouble(), d->m_model->data(d->m_model->index(d->m_mapLabels, i), Qt::DisplayRole).toString());
480 }
470 }
481 }
471 }
482
472
483 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
473 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
484
474
485
475
486 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
476 QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
487 QAbstractSeriesPrivate(parent),
477 QAbstractSeriesPrivate(parent),
488 m_pieRelativeHorPos(0.5),
478 m_pieRelativeHorPos(0.5),
489 m_pieRelativeVerPos(0.5),
479 m_pieRelativeVerPos(0.5),
490 m_pieRelativeSize(0.7),
480 m_pieRelativeSize(0.7),
491 m_pieStartAngle(0),
481 m_pieStartAngle(0),
492 m_pieEndAngle(360),
482 m_pieEndAngle(360),
493 m_sum(0),
483 m_sum(0),
494 m_mapValues(0),
484 m_mapValues(0),
495 m_mapLabels(0),
485 m_mapLabels(0),
496 m_mapOrientation(Qt::Horizontal)
486 m_mapOrientation(Qt::Horizontal)
497 {
487 {
498
488
499 }
489 }
500
490
501 QPieSeriesPrivate::~QPieSeriesPrivate()
491 QPieSeriesPrivate::~QPieSeriesPrivate()
502 {
492 {
503
493
504 }
494 }
505
495
506 void QPieSeriesPrivate::updateDerivativeData()
496 void QPieSeriesPrivate::updateDerivativeData()
507 {
497 {
508 m_sum = 0;
498 m_sum = 0;
509
499
510 // nothing to do?
500 // nothing to do?
511 if (m_slices.count() == 0)
501 if (m_slices.count() == 0)
512 return;
502 return;
513
503
514 // calculate sum of all slices
504 // calculate sum of all slices
515 foreach (QPieSlice* s, m_slices)
505 foreach (QPieSlice* s, m_slices)
516 m_sum += s->value();
506 m_sum += s->value();
517
507
518 // nothing to show..
508 // nothing to show..
519 if (qFuzzyIsNull(m_sum))
509 if (qFuzzyIsNull(m_sum))
520 return;
510 return;
521
511
522 // update slice attributes
512 // update slice attributes
523 qreal sliceAngle = m_pieStartAngle;
513 qreal sliceAngle = m_pieStartAngle;
524 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
514 qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
525 QVector<QPieSlice*> changed;
515 QVector<QPieSlice*> changed;
526 foreach (QPieSlice* s, m_slices) {
516 foreach (QPieSlice* s, m_slices) {
527
517
528 PieSliceData data = PieSliceData::data(s);
518 PieSliceData data = PieSliceData::data(s);
529 data.m_percentage = s->value() / m_sum;
519 data.m_percentage = s->value() / m_sum;
530 data.m_angleSpan = pieSpan * data.m_percentage;
520 data.m_angleSpan = pieSpan * data.m_percentage;
531 data.m_startAngle = sliceAngle;
521 data.m_startAngle = sliceAngle;
532 sliceAngle += data.m_angleSpan;
522 sliceAngle += data.m_angleSpan;
533
523
534 if (PieSliceData::data(s) != data) {
524 if (PieSliceData::data(s) != data) {
535 PieSliceData::data(s) = data;
525 PieSliceData::data(s) = data;
536 changed << s;
526 changed << s;
537 }
527 }
538 }
528 }
539
529
540 // emit signals
530 // emit signals
541 foreach (QPieSlice* s, changed)
531 foreach (QPieSlice* s, changed)
542 PieSliceData::data(s).emitChangedSignal(s);
532 PieSliceData::data(s).emitChangedSignal(s);
543 }
533 }
544
534
545 QPieSeriesPrivate* QPieSeriesPrivate::seriesData(QPieSeries &series)
535 QPieSeriesPrivate* QPieSeriesPrivate::seriesData(QPieSeries &series)
546 {
536 {
547 return series.d_func();
537 return series.d_func();
548 }
538 }
549
539
550 void QPieSeriesPrivate::sliceChanged()
540 void QPieSeriesPrivate::sliceChanged()
551 {
541 {
552 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
542 Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
553 updateDerivativeData();
543 updateDerivativeData();
554 }
544 }
555
545
556 void QPieSeriesPrivate::sliceClicked()
546 void QPieSeriesPrivate::sliceClicked()
557 {
547 {
558 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
548 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
559 Q_ASSERT(m_slices.contains(slice));
549 Q_ASSERT(m_slices.contains(slice));
560 Q_Q(QPieSeries);
550 Q_Q(QPieSeries);
561 emit q->clicked(slice);
551 emit q->clicked(slice);
562 }
552 }
563
553
564 void QPieSeriesPrivate::sliceHovered(bool state)
554 void QPieSeriesPrivate::sliceHovered(bool state)
565 {
555 {
566 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
556 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
567 Q_ASSERT(m_slices.contains(slice));
557 Q_ASSERT(m_slices.contains(slice));
568 Q_Q(QPieSeries);
558 Q_Q(QPieSeries);
569 emit q->hovered(slice, state);
559 emit q->hovered(slice, state);
570 }
560 }
571
561
572 void QPieSeriesPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
562 void QPieSeriesPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
573 {
563 {
574 Q_UNUSED(bottomRight)
564 Q_UNUSED(bottomRight)
575
565
576 if (m_mapOrientation == Qt::Vertical)
566 if (m_mapOrientation == Qt::Vertical)
577 {
567 {
578 if (topLeft.column() == m_mapValues)
568 if (topLeft.column() == m_mapValues)
579 if (m_mapValues == m_mapLabels)
569 if (m_mapValues == m_mapLabels)
580 {
570 {
581 m_slices.at(topLeft.row())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
571 m_slices.at(topLeft.row())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
582 m_slices.at(topLeft.row())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
572 m_slices.at(topLeft.row())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
583 }
573 }
584 else
574 else
585 {
575 {
586 m_slices.at(topLeft.row())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
576 m_slices.at(topLeft.row())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
587 }
577 }
588 else if (topLeft.column() == m_mapLabels)
578 else if (topLeft.column() == m_mapLabels)
589 m_slices.at(topLeft.row())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
579 m_slices.at(topLeft.row())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
590 }
580 }
591 else
581 else
592 {
582 {
593 if (topLeft.row() == m_mapValues)
583 if (topLeft.row() == m_mapValues)
594 if (m_mapValues == m_mapLabels)
584 if (m_mapValues == m_mapLabels)
595 {
585 {
596 m_slices.at(topLeft.column())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
586 m_slices.at(topLeft.column())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
597 m_slices.at(topLeft.column())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
587 m_slices.at(topLeft.column())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
598 }
588 }
599 else
589 else
600 {
590 {
601 m_slices.at(topLeft.column())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
591 m_slices.at(topLeft.column())->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble());
602 }
592 }
603 else if (topLeft.row() == m_mapLabels)
593 else if (topLeft.row() == m_mapLabels)
604 m_slices.at(topLeft.column())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
594 m_slices.at(topLeft.column())->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString());
605 }
595 }
606 }
596 }
607
597
608 void QPieSeriesPrivate::modelDataAdded(QModelIndex parent, int start, int end)
598 void QPieSeriesPrivate::modelDataAdded(QModelIndex parent, int start, int end)
609 {
599 {
610 Q_UNUSED(parent)
600 Q_UNUSED(parent)
611 Q_UNUSED(end)
601 Q_UNUSED(end)
612 Q_Q(QPieSeries);
602 Q_Q(QPieSeries);
613
603
614 QPieSlice* newSlice = new QPieSlice;
604 QPieSlice* newSlice = new QPieSlice;
615 newSlice->setLabelVisible(true);
605 newSlice->setLabelVisible(true);
616 if (m_mapOrientation == Qt::Vertical)
606 if (m_mapOrientation == Qt::Vertical)
617 {
607 {
618 newSlice->setValue(m_model->data(m_model->index(start, m_mapValues), Qt::DisplayRole).toDouble());
608 newSlice->setValue(m_model->data(m_model->index(start, m_mapValues), Qt::DisplayRole).toDouble());
619 newSlice->setLabel(m_model->data(m_model->index(start, m_mapLabels), Qt::DisplayRole).toString());
609 newSlice->setLabel(m_model->data(m_model->index(start, m_mapLabels), Qt::DisplayRole).toString());
620 }
610 }
621 else
611 else
622 {
612 {
623 newSlice->setValue(m_model->data(m_model->index(m_mapValues, start), Qt::DisplayRole).toDouble());
613 newSlice->setValue(m_model->data(m_model->index(m_mapValues, start), Qt::DisplayRole).toDouble());
624 newSlice->setLabel(m_model->data(m_model->index(m_mapLabels, start), Qt::DisplayRole).toString());
614 newSlice->setLabel(m_model->data(m_model->index(m_mapLabels, start), Qt::DisplayRole).toString());
625 }
615 }
626
616
627 q->insert(start, newSlice);
617 q->insert(start, newSlice);
628 }
618 }
629
619
630 void QPieSeriesPrivate::modelDataRemoved(QModelIndex parent, int start, int end)
620 void QPieSeriesPrivate::modelDataRemoved(QModelIndex parent, int start, int end)
631 {
621 {
632 Q_UNUSED(parent)
622 Q_UNUSED(parent)
633 Q_UNUSED(end)
623 Q_UNUSED(end)
634 Q_Q(QPieSeries);
624 Q_Q(QPieSeries);
635 q->remove(m_slices.at(start));
625 q->remove(m_slices.at(start));
636 }
626 }
637
627
638 bool QPieSeriesPrivate::setRealValue(qreal &value, qreal newValue, qreal max, qreal min)
628 bool QPieSeriesPrivate::setRealValue(qreal &value, qreal newValue, qreal max, qreal min)
639 {
629 {
640 // Remove rounding errors
630 // Remove rounding errors
641 qreal roundedValue = newValue;
631 qreal roundedValue = newValue;
642 if (qFuzzyIsNull(min) && qFuzzyIsNull(newValue))
632 if (qFuzzyIsNull(min) && qFuzzyIsNull(newValue))
643 roundedValue = 0.0;
633 roundedValue = 0.0;
644 else if (qFuzzyCompare(newValue, max))
634 else if (qFuzzyCompare(newValue, max))
645 roundedValue = max;
635 roundedValue = max;
646 else if (qFuzzyCompare(newValue, min))
636 else if (qFuzzyCompare(newValue, min))
647 roundedValue = min;
637 roundedValue = min;
648
638
649 // Check if the position is valid after removing the rounding errors
639 // Check if the position is valid after removing the rounding errors
650 if (roundedValue < min || roundedValue > max) {
640 if (roundedValue < min || roundedValue > max) {
651 qWarning("QPieSeries: Illegal value");
641 qWarning("QPieSeries: Illegal value");
652 return false;
642 return false;
653 }
643 }
654
644
655 if (!qFuzzyIsNull(value - roundedValue)) {
645 if (!qFuzzyIsNull(value - roundedValue)) {
656 value = roundedValue;
646 value = roundedValue;
657 return true;
647 return true;
658 }
648 }
659
649
660 // The change was so small it is considered a rounding error
650 // The change was so small it is considered a rounding error
661 return false;
651 return false;
662 }
652 }
663
653
664 void QPieSeriesPrivate::scaleDomain(Domain& domain)
654 void QPieSeriesPrivate::scaleDomain(Domain& domain)
665 {
655 {
666 Q_UNUSED(domain);
656 Q_UNUSED(domain);
667 #ifndef QT_NO_DEBUG
657 #ifndef QT_NO_DEBUG
668 qWarning() << __FILE__<<__FUNCTION__<<"not implemented";
658 qWarning() << __FILE__<<__FUNCTION__<<"not implemented";
669 #endif
659 #endif
670 }
660 }
671
661
672 Chart* QPieSeriesPrivate::createGraphics(ChartPresenter* presenter)
662 Chart* QPieSeriesPrivate::createGraphics(ChartPresenter* presenter)
673 {
663 {
674 Q_Q(QPieSeries);
664 Q_Q(QPieSeries);
675 PieChartItem* pie = new PieChartItem(q,presenter);
665 PieChartItem* pie = new PieChartItem(q,presenter);
676 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
666 if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) {
677 presenter->animator()->addAnimation(pie);
667 presenter->animator()->addAnimation(pie);
678 }
668 }
679 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
669 presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q));
680 return pie;
670 return pie;
681 }
671 }
682
672
683 QList<LegendMarker*> QPieSeriesPrivate::createLegendMarker(QLegend* legend)
673 QList<LegendMarker*> QPieSeriesPrivate::createLegendMarker(QLegend* legend)
684 {
674 {
685 Q_Q(QPieSeries);
675 Q_Q(QPieSeries);
686 QList<LegendMarker*> markers;
676 QList<LegendMarker*> markers;
687 foreach(QPieSlice* slice, q->slices()) {
677 foreach(QPieSlice* slice, q->slices()) {
688 PieLegendMarker* marker = new PieLegendMarker(q,slice,legend);
678 PieLegendMarker* marker = new PieLegendMarker(q,slice,legend);
689 markers << marker;
679 markers << marker;
690 }
680 }
691 return markers;
681 return markers;
692 }
682 }
693
683
694 #include "moc_qpieseries.cpp"
684 #include "moc_qpieseries.cpp"
695 #include "moc_qpieseries_p.cpp"
685 #include "moc_qpieseries_p.cpp"
696
686
697 QTCOMMERCIALCHART_END_NAMESPACE
687 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,89 +1,88
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2012 Digia Plc
3 ** Copyright (C) 2012 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #ifndef PIESERIES_H
21 #ifndef PIESERIES_H
22 #define PIESERIES_H
22 #define PIESERIES_H
23
23
24 #include <qabstractseries.h>
24 #include <qabstractseries.h>
25
25
26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 class QPieSeriesPrivate;
27 class QPieSeriesPrivate;
28 class QPieSlice;
28 class QPieSlice;
29
29
30 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QAbstractSeries
30 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QAbstractSeries
31 {
31 {
32 Q_OBJECT
32 Q_OBJECT
33 Q_PROPERTY(qreal horizontalPosition READ horizontalPosition WRITE setHorizontalPosition)
33 Q_PROPERTY(qreal horizontalPosition READ horizontalPosition WRITE setHorizontalPosition)
34 Q_PROPERTY(qreal verticalPosition READ verticalPosition WRITE setVerticalPosition)
34 Q_PROPERTY(qreal verticalPosition READ verticalPosition WRITE setVerticalPosition)
35 Q_PROPERTY(qreal size READ pieSize WRITE setPieSize)
35 Q_PROPERTY(qreal size READ pieSize WRITE setPieSize)
36 Q_PROPERTY(qreal startAngle READ pieStartAngle WRITE setPieStartAngle)
36 Q_PROPERTY(qreal startAngle READ pieStartAngle WRITE setPieStartAngle)
37 Q_PROPERTY(qreal endAngle READ pieEndAngle WRITE setPieEndAngle)
37 Q_PROPERTY(qreal endAngle READ pieEndAngle WRITE setPieEndAngle)
38
38
39 public:
39 public:
40 explicit QPieSeries(QObject *parent = 0);
40 explicit QPieSeries(QObject *parent = 0);
41 virtual ~QPieSeries();
41 virtual ~QPieSeries();
42
42
43 QSeriesType type() const;
43 QSeriesType type() const;
44
44
45 void append(QPieSlice* slice);
45 void append(QPieSlice* slice);
46 void append(QList<QPieSlice*> slices);
46 void append(QList<QPieSlice*> slices);
47 QPieSeries& operator << (QPieSlice* slice);
47 QPieSeries& operator << (QPieSlice* slice);
48 QPieSlice* append(qreal value, QString name);
48 QPieSlice* append(qreal value, QString name);
49 void insert(int index, QPieSlice* slice);
49 void insert(int index, QPieSlice* slice);
50 void replace(QList<QPieSlice*> slices);
51 void remove(QPieSlice* slice);
50 void remove(QPieSlice* slice);
52 void clear();
51 void clear();
53
52
54 QList<QPieSlice*> slices() const;
53 QList<QPieSlice*> slices() const;
55 int count() const;
54 int count() const;
56 bool isEmpty() const;
55 bool isEmpty() const;
57
56
58 qreal sum() const;
57 qreal sum() const;
59
58
60 void setHorizontalPosition(qreal relativePosition);
59 void setHorizontalPosition(qreal relativePosition);
61 qreal horizontalPosition() const;
60 qreal horizontalPosition() const;
62 void setVerticalPosition(qreal relativePosition);
61 void setVerticalPosition(qreal relativePosition);
63 qreal verticalPosition() const;
62 qreal verticalPosition() const;
64
63
65 void setPieSize(qreal relativeSize);
64 void setPieSize(qreal relativeSize);
66 qreal pieSize() const;
65 qreal pieSize() const;
67
66
68 void setPieStartAngle(qreal startAngle);
67 void setPieStartAngle(qreal startAngle);
69 qreal pieStartAngle() const;
68 qreal pieStartAngle() const;
70 void setPieEndAngle(qreal endAngle);
69 void setPieEndAngle(qreal endAngle);
71 qreal pieEndAngle() const;
70 qreal pieEndAngle() const;
72
71
73 void setLabelsVisible(bool visible = true);
72 void setLabelsVisible(bool visible = true);
74
73
75 bool setModel(QAbstractItemModel* model);
74 bool setModel(QAbstractItemModel* model);
76 void setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation = Qt::Vertical);
75 void setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation = Qt::Vertical);
77
76
78 Q_SIGNALS:
77 Q_SIGNALS:
79 void clicked(QPieSlice* slice);
78 void clicked(QPieSlice* slice);
80 void hovered(QPieSlice* slice, bool state);
79 void hovered(QPieSlice* slice, bool state);
81
80
82 private:
81 private:
83 Q_DECLARE_PRIVATE(QPieSeries)
82 Q_DECLARE_PRIVATE(QPieSeries)
84 Q_DISABLE_COPY(QPieSeries)
83 Q_DISABLE_COPY(QPieSeries)
85 };
84 };
86
85
87 QTCOMMERCIALCHART_END_NAMESPACE
86 QTCOMMERCIALCHART_END_NAMESPACE
88
87
89 #endif // PIESERIES_H
88 #endif // PIESERIES_H
@@ -1,410 +1,410
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2012 Digia Plc
3 ** Copyright (C) 2012 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "qpieslice.h"
21 #include "qpieslice.h"
22 #include "pieslicedata_p.h"
22 #include "pieslicedata_p.h"
23
23
24 QTCOMMERCIALCHART_BEGIN_NAMESPACE
24 QTCOMMERCIALCHART_BEGIN_NAMESPACE
25
25
26 /*!
26 /*!
27 \class QPieSlice
27 \class QPieSlice
28 \brief Defines a slice in pie series.
28 \brief Defines a slice in pie series.
29
29
30 This object defines the properties of a single slice in a QPieSeries.
30 This object defines the properties of a single slice in a QPieSeries.
31
31
32 In addition to the obvious value and label properties the user can also control
32 In addition to the obvious value and label properties the user can also control
33 the visual appearance of a slice. By modifying the visual appearance also means that
33 the visual appearance of a slice. By modifying the visual appearance also means that
34 the user is overriding the default appearance set by the theme. Even if the theme is
34 the user is overriding the default appearance set by the theme. Even if the theme is
35 changed users settings will persist.
35 changed users settings will persist.
36
36
37 To enable user interaction customization with the slices some basic signals
37 To enable user interaction customization with the slices some basic signals
38 are provided about clicking and hovering.
38 are provided about clicking and hovering.
39 */
39 */
40
40
41 /*!
41 /*!
42 \property QPieSlice::label
42 \property QPieSlice::label
43
43
44 Label of the slice.
44 Label of the slice.
45 */
45 */
46
46
47 /*!
47 /*!
48 \property QPieSlice::value
48 \property QPieSlice::value
49
49
50 Value of the slice.
50 Value of the slice.
51
51
52 \sa percentage(), QPieSeries::sum()
52 \sa percentage(), QPieSeries::sum()
53 */
53 */
54
54
55 /*!
55 /*!
56 Constructs an empty slice with a \a parent.
56 Constructs an empty slice with a \a parent.
57
57
58 \sa QPieSeries::append(), QPieSeries::insert(), QPieSeries::replace()
58 \sa QPieSeries::append(), QPieSeries::insert()
59 */
59 */
60 QPieSlice::QPieSlice(QObject *parent)
60 QPieSlice::QPieSlice(QObject *parent)
61 :QObject(parent),
61 :QObject(parent),
62 d(new PieSliceData())
62 d(new PieSliceData())
63 {
63 {
64
64
65 }
65 }
66
66
67 /*!
67 /*!
68 Constructs an empty slice with given \a value, \a label and a \a parent.
68 Constructs an empty slice with given \a value, \a label and a \a parent.
69 \sa QPieSeries::append(), QPieSeries::insert(), QPieSeries::replace()
69 \sa QPieSeries::append(), QPieSeries::insert()
70 */
70 */
71 QPieSlice::QPieSlice(qreal value, QString label, QObject *parent)
71 QPieSlice::QPieSlice(qreal value, QString label, QObject *parent)
72 :QObject(parent),
72 :QObject(parent),
73 d(new PieSliceData())
73 d(new PieSliceData())
74 {
74 {
75 d->m_value = value;
75 d->m_value = value;
76 d->m_labelText = label;
76 d->m_labelText = label;
77 }
77 }
78
78
79 /*!
79 /*!
80 Destroys the slice.
80 Destroys the slice.
81 User should not delete the slice if it has been added to the series.
81 User should not delete the slice if it has been added to the series.
82 */
82 */
83 QPieSlice::~QPieSlice()
83 QPieSlice::~QPieSlice()
84 {
84 {
85 delete d;
85 delete d;
86 }
86 }
87
87
88 /*!
88 /*!
89 Gets the value of the slice.
89 Gets the value of the slice.
90 Note that all values in the series
90 Note that all values in the series
91 \sa setValue()
91 \sa setValue()
92 */
92 */
93 qreal QPieSlice::value() const
93 qreal QPieSlice::value() const
94 {
94 {
95 return d->m_value;
95 return d->m_value;
96 }
96 }
97
97
98 /*!
98 /*!
99 Gets the label of the slice.
99 Gets the label of the slice.
100 \sa setLabel()
100 \sa setLabel()
101 */
101 */
102 QString QPieSlice::label() const
102 QString QPieSlice::label() const
103 {
103 {
104 return d->m_labelText;
104 return d->m_labelText;
105 }
105 }
106
106
107 /*!
107 /*!
108 Returns true if label is set as visible.
108 Returns true if label is set as visible.
109 \sa setLabelVisible()
109 \sa setLabelVisible()
110 */
110 */
111 bool QPieSlice::isLabelVisible() const
111 bool QPieSlice::isLabelVisible() const
112 {
112 {
113 return d->m_isLabelVisible;
113 return d->m_isLabelVisible;
114 }
114 }
115
115
116 /*!
116 /*!
117 Returns true if slice is exloded from the pie.
117 Returns true if slice is exloded from the pie.
118 \sa setExploded(), explodeDistanceFactor(), setExplodeDistanceFactor()
118 \sa setExploded(), explodeDistanceFactor(), setExplodeDistanceFactor()
119 */
119 */
120 bool QPieSlice::isExploded() const
120 bool QPieSlice::isExploded() const
121 {
121 {
122 return d->m_isExploded;
122 return d->m_isExploded;
123 }
123 }
124
124
125 /*!
125 /*!
126 Returns the explode distance factor.
126 Returns the explode distance factor.
127
127
128 The factor is relative to pie radius. For example:
128 The factor is relative to pie radius. For example:
129 1.0 means the distance is the same as the radius.
129 1.0 means the distance is the same as the radius.
130 0.5 means the distance is half of the radius.
130 0.5 means the distance is half of the radius.
131
131
132 Default value is 0.15.
132 Default value is 0.15.
133
133
134 \sa setExplodeDistanceFactor(), isExploded(), setExploded()
134 \sa setExplodeDistanceFactor(), isExploded(), setExploded()
135 */
135 */
136 qreal QPieSlice::explodeDistanceFactor() const
136 qreal QPieSlice::explodeDistanceFactor() const
137 {
137 {
138 return d->m_explodeDistanceFactor;
138 return d->m_explodeDistanceFactor;
139 }
139 }
140
140
141 /*!
141 /*!
142 Returns the percentage of this slice compared to the sum of all slices in the same series.
142 Returns the percentage of this slice compared to the sum of all slices in the same series.
143 The returned value ranges from 0 to 1.0.
143 The returned value ranges from 0 to 1.0.
144
144
145 Updated internally after the slice is added to the series.
145 Updated internally after the slice is added to the series.
146
146
147 \sa QPieSeries::sum()
147 \sa QPieSeries::sum()
148 */
148 */
149 qreal QPieSlice::percentage() const
149 qreal QPieSlice::percentage() const
150 {
150 {
151 return d->m_percentage;
151 return d->m_percentage;
152 }
152 }
153
153
154 /*!
154 /*!
155 Returns the starting angle of this slice in the series it belongs to.
155 Returns the starting angle of this slice in the series it belongs to.
156
156
157 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
157 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
158
158
159 Updated internally after the slice is added to the series.
159 Updated internally after the slice is added to the series.
160 */
160 */
161 qreal QPieSlice::startAngle() const
161 qreal QPieSlice::startAngle() const
162 {
162 {
163 return d->m_startAngle;
163 return d->m_startAngle;
164 }
164 }
165
165
166 /*!
166 /*!
167 Returns the end angle of this slice in the series it belongs to.
167 Returns the end angle of this slice in the series it belongs to.
168
168
169 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
169 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
170
170
171 Updated internally after the slice is added to the series.
171 Updated internally after the slice is added to the series.
172 */
172 */
173 qreal QPieSlice::endAngle() const
173 qreal QPieSlice::endAngle() const
174 {
174 {
175 return d->m_startAngle + d->m_angleSpan;
175 return d->m_startAngle + d->m_angleSpan;
176 }
176 }
177
177
178 /*!
178 /*!
179 Returns the pen used to draw this slice.
179 Returns the pen used to draw this slice.
180 \sa setPen()
180 \sa setPen()
181 */
181 */
182 QPen QPieSlice::pen() const
182 QPen QPieSlice::pen() const
183 {
183 {
184 return d->m_slicePen;
184 return d->m_slicePen;
185 }
185 }
186
186
187 /*!
187 /*!
188 Returns the brush used to draw this slice.
188 Returns the brush used to draw this slice.
189 \sa setBrush()
189 \sa setBrush()
190 */
190 */
191 QBrush QPieSlice::brush() const
191 QBrush QPieSlice::brush() const
192 {
192 {
193 return d->m_sliceBrush;
193 return d->m_sliceBrush;
194 }
194 }
195
195
196 /*!
196 /*!
197 Returns the pen used to draw the label in this slice.
197 Returns the pen used to draw the label in this slice.
198 \sa setLabelPen()
198 \sa setLabelPen()
199 */
199 */
200 QPen QPieSlice::labelPen() const
200 QPen QPieSlice::labelPen() const
201 {
201 {
202 return d->m_labelPen;
202 return d->m_labelPen;
203 }
203 }
204
204
205 /*!
205 /*!
206 Returns the font used to draw label in this slice.
206 Returns the font used to draw label in this slice.
207 \sa setLabelFont()
207 \sa setLabelFont()
208 */
208 */
209 QFont QPieSlice::labelFont() const
209 QFont QPieSlice::labelFont() const
210 {
210 {
211 return d->m_labelFont;
211 return d->m_labelFont;
212 }
212 }
213
213
214 /*!
214 /*!
215 Gets the label arm length factor.
215 Gets the label arm length factor.
216
216
217 The factor is relative to pie radius. For example:
217 The factor is relative to pie radius. For example:
218 1.0 means the length is the same as the radius.
218 1.0 means the length is the same as the radius.
219 0.5 means the length is half of the radius.
219 0.5 means the length is half of the radius.
220
220
221 Default value is 0.15
221 Default value is 0.15
222
222
223 \sa setLabelArmLengthFactor()
223 \sa setLabelArmLengthFactor()
224 */
224 */
225 qreal QPieSlice::labelArmLengthFactor() const
225 qreal QPieSlice::labelArmLengthFactor() const
226 {
226 {
227 return d->m_labelArmLengthFactor;
227 return d->m_labelArmLengthFactor;
228 }
228 }
229
229
230 /*!
230 /*!
231 \fn void QPieSlice::clicked()
231 \fn void QPieSlice::clicked()
232
232
233 This signal is emitted when user has clicked the slice.
233 This signal is emitted when user has clicked the slice.
234
234
235 \sa QPieSeries::clicked()
235 \sa QPieSeries::clicked()
236 */
236 */
237
237
238 /*!
238 /*!
239 \fn void QPieSlice::hovered(bool state)
239 \fn void QPieSlice::hovered(bool state)
240
240
241 This signal is emitted when user has hovered over or away from the slice.
241 This signal is emitted when user has hovered over or away from the slice.
242
242
243 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
243 \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
244
244
245 \sa QPieSeries::hovered()
245 \sa QPieSeries::hovered()
246 */
246 */
247
247
248 /*!
248 /*!
249 \fn void QPieSlice::changed()
249 \fn void QPieSlice::changed()
250
250
251 This signal emitted when something has changed in the slice.
251 This signal emitted when something has changed in the slice.
252 */
252 */
253
253
254 /*!
254 /*!
255 Sets the \a value of this slice.
255 Sets the \a value of this slice.
256 \sa value()
256 \sa value()
257 */
257 */
258 void QPieSlice::setValue(qreal value)
258 void QPieSlice::setValue(qreal value)
259 {
259 {
260 if (!qFuzzyIsNull(d->m_value - value)) {
260 if (!qFuzzyIsNull(d->m_value - value)) {
261 d->m_value = value;
261 d->m_value = value;
262 emit changed();
262 emit changed();
263 }
263 }
264 }
264 }
265
265
266 /*!
266 /*!
267 Sets the \a label of the slice.
267 Sets the \a label of the slice.
268 \sa label()
268 \sa label()
269 */
269 */
270 void QPieSlice::setLabel(QString label)
270 void QPieSlice::setLabel(QString label)
271 {
271 {
272 if (d->m_labelText != label) {
272 if (d->m_labelText != label) {
273 d->m_labelText = label;
273 d->m_labelText = label;
274 emit changed();
274 emit changed();
275 }
275 }
276 }
276 }
277
277
278 /*!
278 /*!
279 Sets the label \a visible in this slice.
279 Sets the label \a visible in this slice.
280 \sa isLabelVisible(), QPieSeries::setLabelsVisible()
280 \sa isLabelVisible(), QPieSeries::setLabelsVisible()
281 */
281 */
282 void QPieSlice::setLabelVisible(bool visible)
282 void QPieSlice::setLabelVisible(bool visible)
283 {
283 {
284 if (d->m_isLabelVisible != visible) {
284 if (d->m_isLabelVisible != visible) {
285 d->m_isLabelVisible = visible;
285 d->m_isLabelVisible = visible;
286 emit changed();
286 emit changed();
287 }
287 }
288 }
288 }
289
289
290 /*!
290 /*!
291 Sets this slices \a exploded state.
291 Sets this slices \a exploded state.
292
292
293 If the slice is exploded it is moved away from the pie center. The distance is defined by the explode distance factor.
293 If the slice is exploded it is moved away from the pie center. The distance is defined by the explode distance factor.
294
294
295 \sa isExploded(), explodeDistanceFactor(), setExplodeDistanceFactor()
295 \sa isExploded(), explodeDistanceFactor(), setExplodeDistanceFactor()
296 */
296 */
297 void QPieSlice::setExploded(bool exploded)
297 void QPieSlice::setExploded(bool exploded)
298 {
298 {
299 if (d->m_isExploded != exploded) {
299 if (d->m_isExploded != exploded) {
300 d->m_isExploded = exploded;
300 d->m_isExploded = exploded;
301 emit changed();
301 emit changed();
302 }
302 }
303 }
303 }
304
304
305 /*!
305 /*!
306 Sets the explode distance \a factor.
306 Sets the explode distance \a factor.
307
307
308 The factor is relative to pie radius. For example:
308 The factor is relative to pie radius. For example:
309 1.0 means the distance is the same as the radius.
309 1.0 means the distance is the same as the radius.
310 0.5 means the distance is half of the radius.
310 0.5 means the distance is half of the radius.
311
311
312 Default value is 0.15
312 Default value is 0.15
313
313
314 \sa explodeDistanceFactor(), isExploded(), setExploded()
314 \sa explodeDistanceFactor(), isExploded(), setExploded()
315 */
315 */
316 void QPieSlice::setExplodeDistanceFactor(qreal factor)
316 void QPieSlice::setExplodeDistanceFactor(qreal factor)
317 {
317 {
318 if (!qFuzzyIsNull(d->m_explodeDistanceFactor - factor)) {
318 if (!qFuzzyIsNull(d->m_explodeDistanceFactor - factor)) {
319 d->m_explodeDistanceFactor = factor;
319 d->m_explodeDistanceFactor = factor;
320 emit changed();
320 emit changed();
321 }
321 }
322 }
322 }
323
323
324 /*!
324 /*!
325 Sets the \a pen used to draw this slice.
325 Sets the \a pen used to draw this slice.
326
326
327 Overrides the pen set by the theme.
327 Overrides the pen set by the theme.
328
328
329 \sa pen()
329 \sa pen()
330 */
330 */
331 void QPieSlice::setPen(const QPen &pen)
331 void QPieSlice::setPen(const QPen &pen)
332 {
332 {
333 if (d->m_slicePen != pen) {
333 if (d->m_slicePen != pen) {
334 d->m_slicePen = pen;
334 d->m_slicePen = pen;
335 d->m_slicePen.setThemed(false);
335 d->m_slicePen.setThemed(false);
336 emit changed();
336 emit changed();
337 }
337 }
338 }
338 }
339
339
340 /*!
340 /*!
341 Sets the \a brush used to draw this slice.
341 Sets the \a brush used to draw this slice.
342
342
343 Overrides the brush set by the theme.
343 Overrides the brush set by the theme.
344
344
345 \sa brush()
345 \sa brush()
346 */
346 */
347 void QPieSlice::setBrush(const QBrush &brush)
347 void QPieSlice::setBrush(const QBrush &brush)
348 {
348 {
349 if (d->m_sliceBrush != brush) {
349 if (d->m_sliceBrush != brush) {
350 d->m_sliceBrush = brush;
350 d->m_sliceBrush = brush;
351 d->m_sliceBrush.setThemed(false);
351 d->m_sliceBrush.setThemed(false);
352 emit changed();
352 emit changed();
353 }
353 }
354 }
354 }
355
355
356 /*!
356 /*!
357 Sets the \a pen used to draw the label in this slice.
357 Sets the \a pen used to draw the label in this slice.
358
358
359 Overrides the pen set by the theme.
359 Overrides the pen set by the theme.
360
360
361 \sa labelPen()
361 \sa labelPen()
362 */
362 */
363 void QPieSlice::setLabelPen(const QPen &pen)
363 void QPieSlice::setLabelPen(const QPen &pen)
364 {
364 {
365 if (d->m_labelPen != pen) {
365 if (d->m_labelPen != pen) {
366 d->m_labelPen = pen;
366 d->m_labelPen = pen;
367 d->m_labelPen.setThemed(false);
367 d->m_labelPen.setThemed(false);
368 emit changed();
368 emit changed();
369 }
369 }
370 }
370 }
371
371
372 /*!
372 /*!
373 Sets the \a font used to draw the label in this slice.
373 Sets the \a font used to draw the label in this slice.
374
374
375 Overrides the font set by the theme.
375 Overrides the font set by the theme.
376
376
377 \sa labelFont()
377 \sa labelFont()
378 */
378 */
379 void QPieSlice::setLabelFont(const QFont &font)
379 void QPieSlice::setLabelFont(const QFont &font)
380 {
380 {
381 if (d->m_labelFont != font) {
381 if (d->m_labelFont != font) {
382 d->m_labelFont = font;
382 d->m_labelFont = font;
383 d->m_labelFont.setThemed(false);
383 d->m_labelFont.setThemed(false);
384 emit changed();
384 emit changed();
385 }
385 }
386 }
386 }
387
387
388 /*!
388 /*!
389 Sets the label arm length \a factor.
389 Sets the label arm length \a factor.
390
390
391 The factor is relative to pie radius. For example:
391 The factor is relative to pie radius. For example:
392 1.0 means the length is the same as the radius.
392 1.0 means the length is the same as the radius.
393 0.5 means the length is half of the radius.
393 0.5 means the length is half of the radius.
394
394
395 Default value is 0.15
395 Default value is 0.15
396
396
397 \sa labelArmLengthFactor()
397 \sa labelArmLengthFactor()
398 */
398 */
399 void QPieSlice::setLabelArmLengthFactor(qreal factor)
399 void QPieSlice::setLabelArmLengthFactor(qreal factor)
400 {
400 {
401 if (!qFuzzyIsNull(d->m_labelArmLengthFactor - factor)) {
401 if (!qFuzzyIsNull(d->m_labelArmLengthFactor - factor)) {
402 d->m_labelArmLengthFactor = factor;
402 d->m_labelArmLengthFactor = factor;
403 emit changed();
403 emit changed();
404 }
404 }
405 }
405 }
406
406
407 QTCOMMERCIALCHART_END_NAMESPACE
407 QTCOMMERCIALCHART_END_NAMESPACE
408
408
409 QTCOMMERCIALCHART_USE_NAMESPACE
409 QTCOMMERCIALCHART_USE_NAMESPACE
410 #include "moc_qpieslice.cpp"
410 #include "moc_qpieslice.cpp"
General Comments 0
You need to be logged in to leave comments. Login now