##// END OF EJS Templates
Add _p to pie internal headers
Jani Honkonen -
r353:e5ed5bdfafc1
parent child
Show More
@@ -1,283 +1,283
1 1 #include "qchart.h"
2 2 #include "qchartaxis.h"
3 3 #include "chartpresenter_p.h"
4 4 #include "chartdataset_p.h"
5 5 #include "charttheme_p.h"
6 6 //series
7 7 #include "qbarseries.h"
8 8 #include "qstackedbarseries.h"
9 9 #include "qpercentbarseries.h"
10 10 #include "qlineseries.h"
11 11 #include "qpieseries.h"
12 12 #include "qscatterseries.h"
13 13 //items
14 14 #include "axisitem_p.h"
15 15 #include "axisanimationitem_p.h"
16 16 #include "barpresenter.h"
17 17 #include "stackedbarpresenter.h"
18 18 #include "linechartitem_p.h"
19 19 #include "percentbarpresenter.h"
20 20 #include "linechartanimationitem_p.h"
21 #include "piepresenter.h"
21 #include "piepresenter_p.h"
22 22 #include "scatterpresenter_p.h"
23 23
24 24 QTCOMMERCIALCHART_BEGIN_NAMESPACE
25 25
26 26 ChartPresenter::ChartPresenter(QChart* chart,ChartDataSet* dataset):QObject(chart),
27 27 m_chart(chart),
28 28 m_dataset(dataset),
29 29 m_chartTheme(0),
30 30 m_marginSize(0),
31 31 m_rect(QRectF(QPoint(0,0),m_chart->size())),
32 32 m_options(0)
33 33 {
34 34 createConnections();
35 35 setChartTheme(QChart::ChartThemeDefault);
36 36
37 37 }
38 38
39 39 ChartPresenter::~ChartPresenter()
40 40 {
41 41 }
42 42
43 43 void ChartPresenter::createConnections()
44 44 {
45 45 QObject::connect(m_chart,SIGNAL(geometryChanged()),this,SLOT(handleGeometryChanged()));
46 46 QObject::connect(m_dataset,SIGNAL(seriesAdded(QChartSeries*)),this,SLOT(handleSeriesAdded(QChartSeries*)));
47 47 QObject::connect(m_dataset,SIGNAL(seriesRemoved(QChartSeries*)),this,SLOT(handleSeriesRemoved(QChartSeries*)));
48 48 QObject::connect(m_dataset,SIGNAL(axisAdded(QChartAxis*)),this,SLOT(handleAxisAdded(QChartAxis*)));
49 49 QObject::connect(m_dataset,SIGNAL(axisRemoved(QChartAxis*)),this,SLOT(handleAxisRemoved(QChartAxis*)));
50 50 QObject::connect(m_dataset,SIGNAL(seriesDomainChanged(QChartSeries*,const Domain&)),this,SLOT(handleSeriesDomainChanged(QChartSeries*,const Domain&)));
51 51 QObject::connect(m_dataset,SIGNAL(axisLabelsChanged(QChartAxis*,const QStringList&)),this,SLOT(handleAxisLabelsChanged(QChartAxis*,const QStringList&)));
52 52 }
53 53
54 54
55 55 QRectF ChartPresenter::geometry() const
56 56 {
57 57 return m_rect;
58 58 }
59 59
60 60 void ChartPresenter::handleGeometryChanged()
61 61 {
62 62 m_rect = QRectF(QPoint(0,0),m_chart->size());
63 63 m_rect.adjust(m_marginSize,m_marginSize, -m_marginSize, -m_marginSize);
64 64 Q_ASSERT(m_rect.isValid());
65 65 emit geometryChanged(m_rect);
66 66 }
67 67
68 68 int ChartPresenter::margin() const
69 69 {
70 70 return m_marginSize;
71 71 }
72 72
73 73 void ChartPresenter::setMargin(int margin)
74 74 {
75 75 m_marginSize = margin;
76 76 }
77 77
78 78 void ChartPresenter::handleAxisAdded(QChartAxis* axis)
79 79 {
80 80
81 81 AxisItem* item ;
82 82
83 83 if(!m_options.testFlag(QChart::GridAxisAnimations))
84 84 {
85 85 item = new AxisItem(axis==m_dataset->axisX()?AxisItem::X_AXIS : AxisItem::Y_AXIS,m_chart);
86 86 }else{
87 87 item = new AxisAnimationItem(axis==m_dataset->axisX()?AxisItem::X_AXIS : AxisItem::Y_AXIS,m_chart);
88 88 }
89 89
90 90 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
91 91 QObject::connect(axis,SIGNAL(update(QChartAxis*)),item,SLOT(handleAxisUpdate(QChartAxis*)));
92 92
93 93 item->handleAxisUpdate(axis);
94 94 item->handleGeometryChanged(m_rect);
95 95 m_chartTheme->decorate(axis,item);
96 96 m_axisItems.insert(axis,item);
97 97 }
98 98
99 99 void ChartPresenter::handleAxisRemoved(QChartAxis* axis)
100 100 {
101 101 AxisItem* item = m_axisItems.take(axis);
102 102 Q_ASSERT(item);
103 103 delete item;
104 104 }
105 105
106 106
107 107 void ChartPresenter::handleSeriesAdded(QChartSeries* series)
108 108 {
109 109 switch(series->type())
110 110 {
111 111 case QChartSeries::SeriesTypeLine: {
112 112 QLineSeries* lineSeries = static_cast<QLineSeries*>(series);
113 113 LineChartItem* item;
114 114 if(m_options.testFlag(QChart::SeriesAnimations)){
115 115 item = new LineChartAnimationItem(this,lineSeries,m_chart);
116 116 }else{
117 117 item = new LineChartItem(this,lineSeries,m_chart);
118 118 }
119 119 m_chartTheme->decorate(item,lineSeries,m_chartItems.count());
120 120 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
121 121 QObject::connect(lineSeries,SIGNAL(changed(int)),item,SLOT(handleModelChanged(int)));
122 122 m_chartItems.insert(series,item);
123 123 break;
124 124 }
125 125
126 126 case QChartSeries::SeriesTypeBar: {
127 127 QBarSeries* barSeries = static_cast<QBarSeries*>(series);
128 128 BarPresenter* item = new BarPresenter(barSeries,m_chart);
129 129 m_chartTheme->decorate(item,barSeries,m_chartItems.count());
130 130 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
131 131 QObject::connect(barSeries,SIGNAL(changed(int)),item,SLOT(handleModelChanged(int)));
132 132 m_chartItems.insert(series,item);
133 133 // m_axisXItem->setVisible(false);
134 134 break;
135 135 }
136 136
137 137 case QChartSeries::SeriesTypeStackedBar: {
138 138
139 139 QStackedBarSeries* stackedBarSeries = static_cast<QStackedBarSeries*>(series);
140 140 StackedBarPresenter* item = new StackedBarPresenter(stackedBarSeries,m_chart);
141 141 m_chartTheme->decorate(item,stackedBarSeries,m_chartItems.count());
142 142 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
143 143 QObject::connect(stackedBarSeries,SIGNAL(changed(int)),item,SLOT(handleModelChanged(int)));
144 144 m_chartItems.insert(series,item);
145 145 break;
146 146 }
147 147
148 148 case QChartSeries::SeriesTypePercentBar: {
149 149
150 150 QPercentBarSeries* percentBarSeries = static_cast<QPercentBarSeries*>(series);
151 151 PercentBarPresenter* item = new PercentBarPresenter(percentBarSeries,m_chart);
152 152 m_chartTheme->decorate(item,percentBarSeries ,m_chartItems.count());
153 153 QObject::connect(this,SIGNAL(geometryChanged(const QRectF&)),item,SLOT(handleGeometryChanged(const QRectF&)));
154 154 QObject::connect(percentBarSeries,SIGNAL(changed(int)),item,SLOT(handleModelChanged(int)));
155 155 m_chartItems.insert(series,item);
156 156 break;
157 157 }
158 158 case QChartSeries::SeriesTypeScatter: {
159 159 QScatterSeries *scatterSeries = qobject_cast<QScatterSeries *>(series);
160 160 ScatterPresenter *scatterPresenter = new ScatterPresenter(scatterSeries, m_chart);
161 161 QObject::connect(scatterPresenter, SIGNAL(clicked()), scatterSeries, SIGNAL(clicked()));
162 162 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)),
163 163 scatterPresenter, SLOT(handleGeometryChanged(const QRectF&)));
164 164 m_chartTheme->decorate(scatterPresenter, scatterSeries, m_chartItems.count());
165 165 m_chartItems.insert(scatterSeries, scatterPresenter);
166 166 break;
167 167 }
168 168 case QChartSeries::SeriesTypePie: {
169 169 QPieSeries *s = qobject_cast<QPieSeries *>(series);
170 170 PiePresenter* pie = new PiePresenter(m_chart, s);
171 171 m_chartTheme->decorate(pie, s, m_chartItems.count());
172 172 QObject::connect(this, SIGNAL(geometryChanged(const QRectF&)), pie, SLOT(handleGeometryChanged(const QRectF&)));
173 173
174 174 // Hide all from background when there is only piechart
175 175 // TODO: refactor this ugly code... should be one setting for this
176 176 if (m_chartItems.count() == 0) {
177 177 m_chart->axisX()->setAxisVisible(false);
178 178 m_chart->axisY()->setAxisVisible(false);
179 179 m_chart->axisX()->setGridVisible(false);
180 180 m_chart->axisY()->setGridVisible(false);
181 181 m_chart->axisX()->setLabelsVisible(false);
182 182 m_chart->axisY()->setLabelsVisible(false);
183 183 m_chart->axisX()->setShadesVisible(false);
184 184 m_chart->axisY()->setShadesVisible(false);
185 185 m_chart->setChartBackgroundBrush(Qt::transparent);
186 186 }
187 187
188 188 m_chartItems.insert(series, pie);
189 189 break;
190 190 }
191 191 default: {
192 192 qDebug()<< "Series type" << series->type() << "not implemented.";
193 193 break;
194 194 }
195 195 }
196 196
197 197 if(m_rect.isValid()) emit geometryChanged(m_rect);
198 198 }
199 199
200 200 void ChartPresenter::handleSeriesRemoved(QChartSeries* series)
201 201 {
202 202 ChartItem* item = m_chartItems.take(series);
203 203 delete item;
204 204 }
205 205
206 206 void ChartPresenter::handleSeriesChanged(QChartSeries* series)
207 207 {
208 208 //TODO:
209 209 }
210 210
211 211 void ChartPresenter::handleSeriesDomainChanged(QChartSeries* series, const Domain& domain)
212 212 {
213 213 m_chartItems.value(series)->handleDomainChanged(domain);
214 214 }
215 215
216 216 void ChartPresenter::handleAxisLabelsChanged(QChartAxis* axis,const QStringList& labels)
217 217 {
218 218 m_axisItems.value(axis)->handleLabelsChanged(axis,labels);
219 219 }
220 220
221 221 void ChartPresenter::setChartTheme(QChart::ChartTheme theme)
222 222 {
223 223 delete m_chartTheme;
224 224
225 225 m_chartTheme = ChartTheme::createTheme(theme);
226 226
227 227 m_chartTheme->decorate(m_chart);
228 228 QMapIterator<QChartSeries*,ChartItem*> i(m_chartItems);
229 229
230 230 int index=0;
231 231 while (i.hasNext()) {
232 232 i.next();
233 233 m_chartTheme->decorate(i.value(),i.key(),index);
234 234 index++;
235 235 }
236 236
237 237 QMapIterator<QChartAxis*,AxisItem*> j(m_axisItems);
238 238 while (j.hasNext()) {
239 239 j.next();
240 240 m_chartTheme->decorate(j.key(),j.value());
241 241 }
242 242 }
243 243
244 244 QChart::ChartTheme ChartPresenter::chartTheme()
245 245 {
246 246 return m_chartTheme->id();
247 247 }
248 248
249 249 void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
250 250 {
251 251 if(m_options!=options) {
252 252
253 253 m_options=options;
254 254
255 255 //recreate elements
256 256
257 257 QList<QChartAxis*> axisList = m_axisItems.uniqueKeys();
258 258 QList<QChartSeries*> seriesList = m_chartItems.uniqueKeys();
259 259
260 260 foreach(QChartAxis* axis, axisList) {
261 261 handleAxisRemoved(axis);
262 262 handleAxisAdded(axis);
263 263 }
264 264 foreach(QChartSeries* series, seriesList) {
265 265 handleSeriesRemoved(series);
266 266 handleSeriesAdded(series);
267 267 }
268 268
269 269 //now reintialize view data
270 270 //TODO: make it more nice
271 271 m_dataset->setDomain(m_dataset->domainIndex());
272 272 }
273 273 }
274 274
275 275 QChart::AnimationOptions ChartPresenter::animationOptions() const
276 276 {
277 277 return m_options;
278 278 }
279 279
280 280
281 281 #include "moc_chartpresenter_p.cpp"
282 282
283 283 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,267 +1,267
1 1 #include "charttheme_p.h"
2 2 #include "qchart.h"
3 3 #include "qchartaxis.h"
4 4 #include <QTime>
5 5
6 6 //series
7 7 #include "qbarset.h"
8 8 #include "qbarseries.h"
9 9 #include "qstackedbarseries.h"
10 10 #include "qpercentbarseries.h"
11 11 #include "qlineseries.h"
12 12 #include "qscatterseries.h"
13 13 #include "qpieseries.h"
14 14 #include "qpieslice.h"
15 15
16 16 //items
17 17 #include "axisitem_p.h"
18 18 #include "barpresenter.h"
19 19 #include "stackedbarpresenter.h"
20 20 #include "linechartitem_p.h"
21 21 #include "percentbarpresenter.h"
22 22 #include "scatterpresenter_p.h"
23 #include "piepresenter.h"
23 #include "piepresenter_p.h"
24 24
25 25 //themes
26 26 #include "chartthemevanilla_p.h"
27 27 #include "chartthemeicy_p.h"
28 28 #include "chartthemegrayscale_p.h"
29 29 #include "chartthemescientific_p.h"
30 30
31 31
32 32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 33
34 34 /* TODO
35 35 case QChart::ChartThemeUnnamed1:
36 36 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xff3fa9f5)), 2));
37 37 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xff7AC943)), 2));
38 38 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xffFF931E)), 2));
39 39 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xffFF1D25)), 2));
40 40 m_seriesThemes.append(SeriesTheme(QColor(QRgb(0xffFF7BAC)), 2));
41 41
42 42 m_gradientStartColor = QColor(QRgb(0xfff3dc9e));
43 43 m_gradientEndColor = QColor(QRgb(0xffafafaf));
44 44 */
45 45
46 46 ChartTheme::ChartTheme(QChart::ChartTheme id)
47 47 {
48 48 m_id = id;
49 49 m_seriesColor.append(QRgb(0xff000000));
50 50 m_seriesColor.append(QRgb(0xff707070));
51 51 m_gradientStartColor = QColor(QRgb(0xffffffff));
52 52 m_gradientEndColor = QColor(QRgb(0xffafafaf));
53 53
54 54 qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
55 55 }
56 56
57 57
58 58 ChartTheme* ChartTheme::createTheme(QChart::ChartTheme theme)
59 59 {
60 60 switch(theme) {
61 61 case QChart::ChartThemeDefault:
62 62 return new ChartThemeIcy();
63 63 case QChart::ChartThemeVanilla:
64 64 return new ChartThemeVanilla();
65 65 case QChart::ChartThemeIcy:
66 66 return new ChartThemeIcy();
67 67 case QChart::ChartThemeGrayscale:
68 68 return new ChartThemeGrayscale();
69 69 case QChart::ChartThemeScientific:
70 70 return new ChartThemeScientific();
71 71 }
72 72 }
73 73
74 74 void ChartTheme::decorate(QChart* chart)
75 75 {
76 76 QLinearGradient backgroundGradient;
77 77 backgroundGradient.setColorAt(0.0, m_gradientStartColor);
78 78 backgroundGradient.setColorAt(1.0, m_gradientEndColor);
79 79 backgroundGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
80 80 chart->setChartBackgroundBrush(backgroundGradient);
81 81 }
82 82 //TODO helper to by removed later
83 83 void ChartTheme::decorate(ChartItem* item, QChartSeries* series,int count)
84 84 {
85 85 switch(series->type())
86 86 {
87 87 case QChartSeries::SeriesTypeLine: {
88 88 QLineSeries* s = static_cast<QLineSeries*>(series);
89 89 LineChartItem* i = static_cast<LineChartItem*>(item);
90 90 decorate(i,s,count);
91 91 break;
92 92 }
93 93 case QChartSeries::SeriesTypeBar: {
94 94 QBarSeries* b = static_cast<QBarSeries*>(series);
95 95 BarPresenter* i = static_cast<BarPresenter*>(item);
96 96 decorate(i,b,count);
97 97 break;
98 98 }
99 99 case QChartSeries::SeriesTypeStackedBar: {
100 100 QStackedBarSeries* s = static_cast<QStackedBarSeries*>(series);
101 101 StackedBarPresenter* i = static_cast<StackedBarPresenter*>(item);
102 102 decorate(i,s,count);
103 103 break;
104 104 }
105 105 case QChartSeries::SeriesTypePercentBar: {
106 106 QPercentBarSeries* s = static_cast<QPercentBarSeries*>(series);
107 107 PercentBarPresenter* i = static_cast<PercentBarPresenter*>(item);
108 108 decorate(i,s,count);
109 109 break;
110 110 }
111 111 case QChartSeries::SeriesTypeScatter: {
112 112 QScatterSeries* s = qobject_cast<QScatterSeries*>(series);
113 113 Q_ASSERT(s);
114 114 ScatterPresenter* i = static_cast<ScatterPresenter*>(item);
115 115 Q_ASSERT(i);
116 116 decorate(i, s, count);
117 117 break;
118 118 }
119 119 case QChartSeries::SeriesTypePie: {
120 120 QPieSeries* s = static_cast<QPieSeries*>(series);
121 121 PiePresenter* i = static_cast<PiePresenter*>(item);
122 122 decorate(i,s,count);
123 123 break;
124 124 }
125 125 default:
126 126 qDebug()<<"Wrong item to be decorated by theme";
127 127 break;
128 128 }
129 129
130 130 }
131 131
132 132 void ChartTheme::decorate(LineChartItem* item, QLineSeries* series,int count)
133 133 {
134 134 QPen pen;
135 135 if(pen != series->pen()){
136 136 item->setPen(series->pen());
137 137 return;
138 138 }
139 139 pen.setColor(m_seriesColor.at(count%m_seriesColor.size()));
140 140 pen.setWidthF(2);
141 141 item->setPen(pen);
142 142 }
143 143
144 144 void ChartTheme::decorate(BarPresenter* item, QBarSeries* series,int count)
145 145 {
146 146 for (int i=0; i<series->countSets(); i++) {
147 147 series->nextSet(0==i)->setBrush(QBrush(m_seriesColor.at(i%m_seriesColor.count())));
148 148 }
149 149 }
150 150
151 151 void ChartTheme::decorate(StackedBarPresenter* item, QStackedBarSeries* series,int count)
152 152 {
153 153 for (int i=0; i<series->countSets(); i++) {
154 154 series->nextSet(0==i)->setBrush(QBrush(m_seriesColor.at(i%m_seriesColor.count())));
155 155 }
156 156 }
157 157
158 158 void ChartTheme::decorate(PercentBarPresenter* item, QPercentBarSeries* series,int count)
159 159 {
160 160 for (int i=0; i<series->countSets(); i++) {
161 161 series->nextSet(0==i)->setBrush(QBrush(m_seriesColor.at(i%m_seriesColor.count())));
162 162 }
163 163 }
164 164
165 165 void ChartTheme::decorate(ScatterPresenter* presenter, QScatterSeries* series, int count)
166 166 {
167 167 Q_ASSERT(presenter);
168 168 Q_ASSERT(series);
169 169
170 170 QColor color = m_seriesColor.at(count % m_seriesColor.size());
171 171 // TODO: define alpha in the theme? or in the series?
172 172 //color.setAlpha(120);
173 173
174 174 QBrush brush(color, Qt::SolidPattern);
175 175 presenter->m_markerBrush = brush;
176 176
177 177 QPen pen(brush, 3);
178 178 pen.setColor(color);
179 179 presenter->m_markerPen = pen;
180 180 }
181 181
182 182 void ChartTheme::decorate(PiePresenter* item, QPieSeries* series, int /*count*/)
183 183 {
184 184 // create a list of slice colors based on current theme
185 185 int i = 0;
186 186 QList<QColor> colors;
187 187 while (colors.count() < series->count()) {
188 188
189 189 // get base color
190 190 QColor c = m_seriesColor[i++];
191 191 i = i % m_seriesColor.count();
192 192
193 193 // dont use black colors... looks bad
194 194 if (c == Qt::black)
195 195 continue;
196 196
197 197 // by default use the "raw" theme color
198 198 if (!colors.contains(c)) {
199 199 colors << c;
200 200 continue;
201 201 }
202 202 // ...ok we need to generate something that looks like the same color
203 203 // but different lightness
204 204
205 205 int tryCount = 0;
206 206 while (tryCount++ < 100) {
207 207
208 208 // find maximum value we can raise the lightness
209 209 int lMax = 255;
210 210 if (lMax > 255 - c.red())
211 211 lMax = 255 - c.red();
212 212 if (lMax > 255 - c.green())
213 213 lMax = 255 - c.green();
214 214 if (lMax > 255 - c.blue())
215 215 lMax = 255 - c.blue();
216 216
217 217 // find maximum value we can make it darker
218 218 int dMax = 255;
219 219 if (dMax > c.red())
220 220 dMax = c.red();
221 221 if (dMax > c.green())
222 222 dMax = c.green();
223 223 if (dMax > c.blue())
224 224 dMax = c.blue();
225 225
226 226 int max = dMax + lMax;
227 227 if (max == 0) {
228 228 // no room to make color lighter or darker...
229 229 qDebug() << "cannot generate a color for pie!";
230 230 break;
231 231 }
232 232
233 233 // generate random color
234 234 int r = c.red() - dMax;
235 235 int g = c.green() - dMax;
236 236 int b = c.blue() - dMax;
237 237 int d = qrand() % max;
238 238 c.setRgb(r+d, g+d, b+d);
239 239
240 240 // found a unique color?
241 241 if (!colors.contains(c))
242 242 break;
243 243 }
244 244
245 245 qDebug() << "generated a color for pie" << c;
246 246 colors << c;
247 247 }
248 248
249 249 // finally update colors
250 250 foreach (QPieSlice* s, series->slices()) {
251 251 QColor c = colors.takeFirst();
252 252 s->setPen(c);
253 253 s->setBrush(c);
254 254 }
255 255 }
256 256
257 257
258 258 void ChartTheme::decorate(QChartAxis* axis,AxisItem* item)
259 259 {
260 260 //TODO: dummy defults for now
261 261 axis->setLabelsBrush(Qt::black);
262 262 axis->setLabelsPen(Qt::NoPen);
263 263 axis->setShadesPen(Qt::NoPen);
264 264 axis->setShadesOpacity(0.5);
265 265 }
266 266
267 267 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,18 +1,18
1 1 INCLUDEPATH += $$PWD
2 2 DEPENDPATH += $$PWD
3 3
4 4 SOURCES += \
5 5 $$PWD/qpieseries.cpp \
6 6 $$PWD/pieslice.cpp \
7 7 $$PWD/piepresenter.cpp \
8 8 $$PWD/pieslicelabel.cpp \
9 9 $$PWD/qpieslice.cpp
10 10
11 11 PRIVATE_HEADERS += \
12 $$PWD/piepresenter.h \
13 $$PWD/pieslice.h \
14 $$PWD/pieslicelabel.h
12 $$PWD/piepresenter_p.h \
13 $$PWD/pieslice_p.h \
14 $$PWD/pieslicelabel_p.h
15 15
16 16 PUBLIC_HEADERS += \
17 17 $$PWD/qpieseries.h \
18 18 $$PWD/qpieslice.h
@@ -1,210 +1,210
1 1
2 #include "piepresenter.h"
3 #include "pieslice.h"
2 #include "piepresenter_p.h"
3 #include "pieslice_p.h"
4 4 #include "qpieslice.h"
5 #include "pieslicelabel.h"
5 #include "pieslicelabel_p.h"
6 6 #include "qpieseries.h"
7 7 #include <qmath.h>
8 8 #include <QDebug>
9 9 #include <QFontMetrics>
10 10
11 11
12 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 13
14 14 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
15 15 :ChartItem(parent),
16 16 m_series(series)
17 17 {
18 18 Q_ASSERT(series);
19 19 connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&)));
20 20 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
21 21 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
22 22
23 23 if (m_series->count()) {
24 24 QPieSeries::ChangeSet changeSet;
25 25 changeSet.appendAdded(m_series->m_slices);
26 26 handleSeriesChanged(changeSet);
27 27 }
28 28 }
29 29
30 30 PiePresenter::~PiePresenter()
31 31 {
32 32 // slices deleted automatically through QGraphicsItem
33 33 }
34 34
35 35 void PiePresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
36 36 {
37 37 // TODO: paint shadows for all components
38 38 // - get paths from items & merge & offset and draw with shadow color?
39 39 }
40 40
41 41 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
42 42 {
43 43 //qDebug() << "PiePresenter::handleSeriesChanged()";
44 44 //qDebug() << " added : " << changeSet.added();
45 45 //qDebug() << " changed: " << changeSet.changed();
46 46 //qDebug() << " removed: " << changeSet.removed();
47 47
48 48 foreach (QPieSlice* s, changeSet.added())
49 49 addSlice(s);
50 50
51 51 foreach (QPieSlice* s, changeSet.changed())
52 52 updateSlice(s);
53 53
54 54 foreach (QPieSlice* s, changeSet.removed())
55 55 deleteSlice(s);
56 56
57 57 // every change possibly changes the actual pie size
58 58 updateGeometry();
59 59 }
60 60
61 61 void PiePresenter::handleDomainChanged(const Domain& domain)
62 62 {
63 63 // TODO
64 64 }
65 65
66 66 void PiePresenter::handleGeometryChanged(const QRectF& rect)
67 67 {
68 68 m_rect = rect;
69 69 prepareGeometryChange();
70 70 updateGeometry();
71 71 }
72 72
73 73 void PiePresenter::updateGeometry()
74 74 {
75 75 if (!m_rect.isValid() || m_rect.isEmpty())
76 76 return;
77 77
78 78 // calculate maximum rectangle for pie
79 79 QRectF pieRect = m_rect;
80 80 if (pieRect.width() < pieRect.height()) {
81 81 pieRect.setWidth(pieRect.width() * m_series->sizeFactor());
82 82 pieRect.setHeight(pieRect.width());
83 83 pieRect.moveCenter(m_rect.center());
84 84 } else {
85 85 pieRect.setHeight(pieRect.height() * m_series->sizeFactor());
86 86 pieRect.setWidth(pieRect.height());
87 87 pieRect.moveCenter(m_rect.center());
88 88 }
89 89
90 90 // position the pie rectangle
91 91 switch (m_series->position()) {
92 92 case QPieSeries::PiePositionTopLeft: {
93 93 pieRect.setHeight(pieRect.height() / 2);
94 94 pieRect.setWidth(pieRect.height());
95 95 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, m_rect.center().y() / 2));
96 96 break;
97 97 }
98 98 case QPieSeries::PiePositionTopRight: {
99 99 pieRect.setHeight(pieRect.height() / 2);
100 100 pieRect.setWidth(pieRect.height());
101 101 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, m_rect.center().y() / 2));
102 102 break;
103 103 }
104 104 case QPieSeries::PiePositionBottomLeft: {
105 105 pieRect.setHeight(pieRect.height() / 2);
106 106 pieRect.setWidth(pieRect.height());
107 107 pieRect.moveCenter(QPointF(m_rect.center().x() / 2, (m_rect.center().y() / 2) * 3));
108 108 break;
109 109 }
110 110 case QPieSeries::PiePositionBottomRight: {
111 111 pieRect.setHeight(pieRect.height() / 2);
112 112 pieRect.setWidth(pieRect.height());
113 113 pieRect.moveCenter(QPointF((m_rect.center().x() / 2) * 3, (m_rect.center().y() / 2) * 3));
114 114 break;
115 115 }
116 116 default:
117 117 break;
118 118 }
119 119
120 120 // calculate how much space we need around the pie rectangle (labels & exploding)
121 121 qreal delta = 0;
122 122 qreal pieRadius = pieRect.height() / 2;
123 123 foreach (QPieSlice* s, m_series->m_slices) {
124 124
125 125 // calculate the farthest point in the slice from the pie center
126 126 qreal centerAngle = s->angle() + (s->angleSpan() / 2);
127 127 qreal len = pieRadius + s->labelArmLength() + s->explodeDistance();
128 128 QPointF dp(qSin(centerAngle*(PI/180)) * len, -qCos(centerAngle*(PI/180)) * len);
129 129 QPointF p = pieRect.center() + dp;
130 130
131 131 // TODO: consider the label text
132 132
133 133 // calculate how much the radius must get smaller to fit that point in the base rectangle
134 134 qreal dt = m_rect.top() - p.y();
135 135 if (dt > delta) delta = dt;
136 136 qreal dl = m_rect.left() - p.x();
137 137 if (dl > delta) delta = dl;
138 138 qreal dr = p.x() - m_rect.right();
139 139 if (dr > delta) delta = dr;
140 140 qreal db = p.y() - m_rect.bottom();
141 141 if (db > delta) delta = db;
142 142
143 143 //if (!m_rect.contains(p)) qDebug() << s->label() << dt << dl << dr << db << "delta" << delta;
144 144 }
145 145
146 146 // shrink the pie rectangle so that everything outside it fits the base rectangle
147 147 pieRect.adjust(delta, delta, -delta, -delta);
148 148
149 149 // update slices
150 150 if (m_pieRect != pieRect) {
151 151 m_pieRect = pieRect;
152 152 //qDebug() << "PiePresenter::updateGeometry()" << m_rect << m_pieRect;
153 153 foreach (PieSlice* s, m_slices.values()) {
154 154 s->setPieRect(m_pieRect);
155 155 s->updateGeometry();
156 156 s->update();
157 157 }
158 158 }
159 159 }
160 160
161 161 void PiePresenter::addSlice(QPieSlice* sliceData)
162 162 {
163 163 //qDebug() << "PiePresenter::addSlice()" << sliceData;
164 164
165 165 if (m_slices.keys().contains(sliceData)) {
166 166 Q_ASSERT(0); // TODO: how to handle this nicely?
167 167 return;
168 168 }
169 169
170 170 // create slice
171 171 PieSlice *slice = new PieSlice(this);
172 172 slice->setPieRect(m_pieRect);
173 173 slice->updateData(sliceData);
174 174 slice->updateGeometry();
175 175 slice->update();
176 176 m_slices.insert(sliceData, slice);
177 177
178 178 // connect signals
179 179 connect(slice, SIGNAL(clicked()), sliceData, SIGNAL(clicked()));
180 180 connect(slice, SIGNAL(hoverEnter()), sliceData, SIGNAL(hoverEnter()));
181 181 connect(slice, SIGNAL(hoverLeave()), sliceData, SIGNAL(hoverLeave()));
182 182 }
183 183
184 184 void PiePresenter::updateSlice(QPieSlice* sliceData)
185 185 {
186 186 //qDebug() << "PiePresenter::updateSlice()" << sliceData;
187 187
188 188 if (!m_slices.contains(sliceData)) {
189 189 Q_ASSERT(0); // TODO: how to handle this nicely?
190 190 return;
191 191 }
192 192
193 193 m_slices[sliceData]->updateData(sliceData);
194 194 }
195 195
196 196 void PiePresenter::deleteSlice(QPieSlice* sliceData)
197 197 {
198 198 //qDebug() << "PiePresenter::deleteSlice()" << sliceData;
199 199
200 200 if (!m_slices.contains(sliceData)) {
201 201 Q_ASSERT(0); // TODO: how to handle this nicely?
202 202 return;
203 203 }
204 204
205 205 delete m_slices.take(sliceData);
206 206 }
207 207
208 #include "moc_piepresenter.cpp"
208 #include "moc_piepresenter_p.cpp"
209 209
210 210 QTCOMMERCIALCHART_END_NAMESPACE
1 NO CONTENT: file renamed from src/piechart/piepresenter.h to src/piechart/piepresenter_p.h
@@ -1,135 +1,135
1 #include "pieslice.h"
2 #include "pieslicelabel.h"
3 #include "piepresenter.h"
1 #include "pieslice_p.h"
2 #include "pieslicelabel_p.h"
3 #include "piepresenter_p.h"
4 4 #include "qpieseries.h"
5 5 #include "qpieslice.h"
6 6 #include <QPainter>
7 7 #include <QDebug>
8 8 #include <qmath.h>
9 9 #include <QGraphicsSceneEvent>
10 10 #include <QTime>
11 11
12 12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 13
14 14 QPointF offset(qreal angle, qreal length)
15 15 {
16 16 qreal dx = qSin(angle*(PI/180)) * length;
17 17 qreal dy = qCos(angle*(PI/180)) * length;
18 18 return QPointF(dx, -dy);
19 19 }
20 20
21 21 PieSlice::PieSlice(QGraphicsItem* parent)
22 22 :QGraphicsObject(parent),
23 23 m_slicelabel(new PieSliceLabel(this)),
24 24 m_angle(0),
25 25 m_angleSpan(0),
26 26 m_isExploded(false),
27 27 m_explodeDistance(0)
28 28 {
29 29 setAcceptHoverEvents(true);
30 30 setAcceptedMouseButtons(Qt::LeftButton);
31 31 }
32 32
33 33 PieSlice::~PieSlice()
34 34 {
35 35
36 36 }
37 37
38 38 QRectF PieSlice::boundingRect() const
39 39 {
40 40 return m_path.boundingRect();
41 41 }
42 42
43 43 QPainterPath PieSlice::shape() const
44 44 {
45 45 return m_path;
46 46 }
47 47
48 48 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
49 49 {
50 50 painter->setPen(m_pen);
51 51 painter->setBrush(m_brush);
52 52 painter->drawPath(m_path);
53 53 }
54 54
55 55 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
56 56 {
57 57 emit hoverEnter();
58 58 }
59 59
60 60 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
61 61 {
62 62 emit hoverLeave();
63 63 }
64 64
65 65 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
66 66 {
67 67 emit clicked();
68 68 }
69 69
70 70 void PieSlice::setPieRect(QRectF rect)
71 71 {
72 72 m_pieRect = rect;
73 73 }
74 74
75 75 void PieSlice::updateGeometry()
76 76 {
77 77 if (!m_pieRect.isValid() || m_pieRect.isEmpty())
78 78 return;
79 79
80 80 prepareGeometryChange();
81 81
82 82 // calculate center angle
83 83 qreal centerAngle = m_angle + (m_angleSpan/2);
84 84
85 85 // adjust rect for exploding
86 86 QRectF rect = m_pieRect;
87 87 if (m_isExploded) {
88 88 qreal dx = qSin(centerAngle*(PI/180)) * m_explodeDistance;
89 89 qreal dy = -qCos(centerAngle*(PI/180)) * m_explodeDistance;
90 90 rect.translate(dx, dy);
91 91 }
92 92
93 93 // update slice path
94 94 // TODO: draw the shape so that it might have a hole in the center
95 95 QPainterPath path;
96 96 path.moveTo(rect.center());
97 97 path.arcTo(rect, -m_angle + 90, -m_angleSpan);
98 98 path.closeSubpath();
99 99 m_path = path;
100 100
101 101 // update label position
102 102 qreal radius = rect.height() / 2;
103 103 QPointF edgeCenter = rect.center() + offset(centerAngle, radius + 5);
104 104 m_slicelabel->setArmStartPoint(edgeCenter);
105 105 m_slicelabel->setArmAngle(centerAngle);
106 106 m_slicelabel->updateGeometry();
107 107 m_slicelabel->update();
108 108
109 109 //qDebug() << "PieSlice::updateGeometry" << m_slicelabel->text() << boundingRect() << m_angle << m_span;
110 110 }
111 111
112 112 void PieSlice::updateData(const QPieSlice* sliceData)
113 113 {
114 114 // TODO: compare what has changes to avoid unneccesary geometry updates
115 115
116 116 m_angle = sliceData->angle();
117 117 m_angleSpan = sliceData->angleSpan();
118 118 m_isExploded = sliceData->isExploded();
119 119 m_explodeDistance = sliceData->explodeDistance(); // TODO: expose to public API
120 120 m_pen = sliceData->pen();
121 121 m_brush = sliceData->brush();
122 122
123 123 m_slicelabel->setVisible(sliceData->isLabelVisible());
124 124 m_slicelabel->setText(sliceData->label());
125 125 m_slicelabel->setPen(sliceData->labelPen());
126 126 m_slicelabel->setFont(sliceData->labelFont());
127 127 m_slicelabel->setArmLength(sliceData->labelArmLength());
128 128
129 129 updateGeometry();
130 130 update();
131 131 }
132 132
133 #include "moc_pieslice.cpp"
133 #include "moc_pieslice_p.cpp"
134 134
135 135 QTCOMMERCIALCHART_END_NAMESPACE
1 NO CONTENT: file renamed from src/piechart/pieslice.h to src/piechart/pieslice_p.h
@@ -1,72 +1,72
1 #include "pieslicelabel.h"
1 #include "pieslicelabel_p.h"
2 2 #include <QPainter>
3 3 #include <qmath.h>
4 4 #include <QGraphicsTextItem>
5 5 #include <QDebug>
6 6
7 7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8 8
9 9 #define PI 3.14159265
10 10
11 11 PieSliceLabel::PieSliceLabel(QGraphicsItem* parent)
12 12 :QGraphicsItem(parent),
13 13 m_armAngle(0),
14 14 m_armLength(0)
15 15 {
16 16
17 17 }
18 18
19 19 void PieSliceLabel::paint(QPainter *painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
20 20 {
21 21 painter->setPen(m_pen);
22 22 painter->drawPath(m_armPath);
23 23
24 24 // TODO: do we need a pen for text?
25 25 painter->setFont(m_font);
26 26 painter->drawText(m_textRect.bottomLeft(), m_text);
27 27
28 28 //qDebug() << "PieSliceLabel::paint" << m_text << m_textRect;
29 29 }
30 30
31 31 void PieSliceLabel::updateGeometry()
32 32 {
33 33 prepareGeometryChange();
34 34
35 35 // calculate text size
36 36 QFontMetricsF fm(m_font);
37 37 QRectF textRect = fm.boundingRect(m_text);
38 38
39 39 // calculate path for arm and text start point
40 40 qreal dx = qSin(m_armAngle*(PI/180)) * m_armLength;
41 41 qreal dy = -qCos(m_armAngle*(PI/180)) * m_armLength;
42 42 QPointF parm1 = m_armStartPoint + QPointF(dx, dy);
43 43
44 44 // calculate horizontal arm and text position
45 45 QPointF parm2 = parm1;
46 46 textRect.moveBottomLeft(parm1);
47 47 if (m_armAngle < 180) { // arm swings the other way on the left side
48 48 parm2 += QPointF(m_textRect.width(), 0);
49 49 } else {
50 50 parm2 += QPointF(-m_textRect.width(),0);
51 51 textRect.moveBottomLeft(parm2);
52 52 }
53 53
54 54 // add a little offset to text so that it does not touch the arm
55 55 qreal yOffset = m_pen.widthF() ? m_pen.widthF() : 2;
56 56 textRect.translate(0, -yOffset);
57 57
58 58 // update arm path
59 59 QPainterPath path;
60 60 path.moveTo(m_armStartPoint);
61 61 path.lineTo(parm1);
62 62 path.lineTo(parm2);
63 63
64 64 // update paths & rects
65 65 m_armPath = path;
66 66 m_textRect = textRect;
67 67 m_rect = path.boundingRect().united(m_textRect);
68 68
69 69 //qDebug() << "PieSliceLabel::updateGeometry" << m_text << m_armStartPoint << m_armLength << m_armAngle << m_textRect;
70 70 }
71 71
72 72 QTCOMMERCIALCHART_END_NAMESPACE
1 NO CONTENT: file renamed from src/piechart/pieslicelabel.h to src/piechart/pieslicelabel_p.h
@@ -1,537 +1,534
1 1 #include "qpieseries.h"
2 2 #include "qpieslice.h"
3 #include "piepresenter.h"
4 #include "pieslice.h"
5 #include <QFontMetrics>
6 3 #include <QDebug>
7 4
8 5 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 6
10 7
11 8 /*!
12 9 \class QPieSeries::ChangeSet
13 10 \brief Defines the changes in the series.
14 11
15 12 Contains the changes that have occurred in the series. Lists of added, changed and removed slices.
16 13
17 14 \sa QPieSeries::changed()
18 15 */
19 16
20 17 /*!
21 18 \internal
22 19 */
23 20 void QPieSeries::ChangeSet::appendAdded(QPieSlice* slice)
24 21 {
25 22 if (!m_added.contains(slice))
26 23 m_added << slice;
27 24 }
28 25
29 26 /*!
30 27 \internal
31 28 */
32 29 void QPieSeries::ChangeSet::appendAdded(QList<QPieSlice*> slices)
33 30 {
34 31 foreach (QPieSlice* s, slices)
35 32 appendAdded(s);
36 33 }
37 34
38 35 /*!
39 36 \internal
40 37 */
41 38 void QPieSeries::ChangeSet::appendChanged(QPieSlice* slice)
42 39 {
43 40 if (!m_changed.contains(slice))
44 41 m_changed << slice;
45 42 }
46 43
47 44 /*!
48 45 \internal
49 46 */
50 47 void QPieSeries::ChangeSet::appendRemoved(QPieSlice* slice)
51 48 {
52 49 if (!m_removed.contains(slice))
53 50 m_removed << slice;
54 51 }
55 52
56 53 /*!
57 54 Returns a list of slices that have been added to the series.
58 55 \sa QPieSeries::changed()
59 56 */
60 57 QList<QPieSlice*> QPieSeries::ChangeSet::added() const
61 58 {
62 59 return m_added;
63 60 }
64 61
65 62 /*!
66 63 Returns a list of slices that have been changed in the series.
67 64 \sa QPieSeries::changed()
68 65 */
69 66 QList<QPieSlice*> QPieSeries::ChangeSet::changed() const
70 67 {
71 68 return m_changed;
72 69 }
73 70
74 71 /*!
75 72 Returns a list of slices that have been removed from the series.
76 73 \sa QPieSeries::changed()
77 74 */
78 75 QList<QPieSlice*> QPieSeries::ChangeSet::removed() const
79 76 {
80 77 return m_removed;
81 78 }
82 79
83 80
84 81 /*!
85 82 Returns true if there are no added/changed or removed slices in the change set.
86 83 */
87 84 bool QPieSeries::ChangeSet::isEmpty() const
88 85 {
89 86 if (m_added.count() || m_changed.count() || m_removed.count())
90 87 return false;
91 88 return true;
92 89 }
93 90
94 91 /*!
95 92 \enum QPieSeries::PiePosition
96 93
97 94 This enum describes pie position within its bounding rectangle
98 95
99 96 \value PiePositionMaximized
100 97 \value PiePositionTopLeft
101 98 \value PiePositionTopRight
102 99 \value PiePositionBottomLeft
103 100 \value PiePositionBottomRight
104 101 */
105 102
106 103 /*!
107 104 \class QPieSeries
108 105 \brief Pie series API for QtCommercial Charts
109 106
110 107 The pie series defines a pie chart which consists of pie slices which are QPieSlice objects.
111 108 The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
112 109 The actual slice size (span) is determined by that relative value.
113 110
114 111 By default the pie is defined as full but it can be a partial pie.
115 112 This can be done by setting a starting angle and angle span to the series.
116 113
117 114 Example on how to create a chart with pie series:
118 115 \snippet ../example/piechart/main.cpp 1
119 116
120 117 To help with the most common user intercation scenarions there some convenience functions. Specifically
121 118 exploding and higlighting:
122 119 \snippet ../example/piechart/main.cpp 2
123 120
124 121 */
125 122
126 123 /*!
127 124 Constructs a series object which is a child of \a parent.
128 125 */
129 126 QPieSeries::QPieSeries(QObject *parent) :
130 127 QChartSeries(parent),
131 128 m_sizeFactor(1.0),
132 129 m_position(PiePositionMaximized),
133 130 m_pieStartAngle(0),
134 131 m_pieAngleSpan(360)
135 132 {
136 133
137 134 }
138 135
139 136 /*!
140 137 Destroys the object. Note that adding series to QChart transfers the ownership to the chart.
141 138 */
142 139 QPieSeries::~QPieSeries()
143 140 {
144 141
145 142 }
146 143
147 144 /*!
148 145 Returns QChartSeries::SeriesTypePie.
149 146 */
150 147 QChartSeries::QChartSeriesType QPieSeries::type() const
151 148 {
152 149 return QChartSeries::SeriesTypePie;
153 150 }
154 151
155 152 /*!
156 153 \internal \a data
157 154 */
158 155 bool QPieSeries::setData(QList<qreal> data)
159 156 {
160 157 // TODO: remove this function
161 158 QList<QPieSlice*> slices;
162 159 foreach (qreal value, data)
163 160 slices << new QPieSlice(value, QString::number(value));
164 161 set(slices);
165 162 return true;
166 163 }
167 164
168 165 /*!
169 166 Sets an array of \a slices to the series.
170 167 Slice ownership is passed to the series.
171 168 */
172 169 void QPieSeries::set(QList<QPieSlice*> slices)
173 170 {
174 171 clear();
175 172 add(slices);
176 173 }
177 174
178 175 /*!
179 176 Adds an array of \a slices to the series.
180 177 Slice ownership is passed to the series.
181 178 */
182 179 void QPieSeries::add(QList<QPieSlice*> slices)
183 180 {
184 181 ChangeSet changeSet;
185 182 foreach (QPieSlice* s, slices) {
186 183 s->setParent(this);
187 184 m_slices << s;
188 185 changeSet.appendAdded(s);
189 186 }
190 187
191 188 updateDerivativeData();
192 189
193 190 foreach (QPieSlice* s, slices) {
194 191 connect(s, SIGNAL(changed()), this, SLOT(sliceChanged()));
195 192 connect(s, SIGNAL(clicked()), this, SLOT(sliceClicked()));
196 193 connect(s, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter()));
197 194 connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave()));
198 195 }
199 196
200 197 emit changed(changeSet);
201 198 }
202 199
203 200 /*!
204 201 Adds a single \a slice to the series.
205 202 Slice ownership is passed to the series.
206 203 */
207 204 void QPieSeries::add(QPieSlice* slice)
208 205 {
209 206 add(QList<QPieSlice*>() << slice);
210 207 }
211 208
212 209
213 210 /*!
214 211 Adds a single slice to the series with give \a value and \a name.
215 212 Slice ownership is passed to the series.
216 213 */
217 214 QPieSlice* QPieSeries::add(qreal value, QString name)
218 215 {
219 216 QPieSlice* slice = new QPieSlice(value, name);
220 217 add(slice);
221 218 return slice;
222 219 }
223 220
224 221 /*!
225 222 Removes a single \a slice from the series and deletes the slice.
226 223
227 224 Do not reference this pointer after this call.
228 225 */
229 226 void QPieSeries::remove(QPieSlice* slice)
230 227 {
231 228 if (!m_slices.removeOne(slice)) {
232 229 Q_ASSERT(0); // TODO: how should this be reported?
233 230 return;
234 231 }
235 232
236 233 ChangeSet changeSet;
237 234 changeSet.appendRemoved(slice);
238 235 emit changed(changeSet);
239 236
240 237 delete slice;
241 238 slice = NULL;
242 239
243 240 updateDerivativeData();
244 241 }
245 242
246 243 /*!
247 244 Clears all slices from the series.
248 245 */
249 246 void QPieSeries::clear()
250 247 {
251 248 if (m_slices.count() == 0)
252 249 return;
253 250
254 251 ChangeSet changeSet;
255 252 foreach (QPieSlice* s, m_slices) {
256 253 changeSet.appendRemoved(s);
257 254 m_slices.removeOne(s);
258 255 delete s;
259 256 }
260 257 emit changed(changeSet);
261 258 updateDerivativeData();
262 259 }
263 260
264 261 /*!
265 262 Counts the number of the slices in this series.
266 263 */
267 264 int QPieSeries::count() const
268 265 {
269 266 return m_slices.count();
270 267 }
271 268
272 269 /*!
273 270 Returns a list of slices that belong to this series.
274 271 */
275 272 QList<QPieSlice*> QPieSeries::slices() const
276 273 {
277 274 return m_slices;
278 275 }
279 276
280 277 /*!
281 278 Sets the size \a factor of the pie. 1.0 is the default value.
282 279 Note that the pie will not grow beyond its absolute maximum size.
283 280 In practice its use is to make the pie appear smaller.
284 281 \sa sizeFactor()
285 282 */
286 283 void QPieSeries::setSizeFactor(qreal factor)
287 284 {
288 285 if (factor < 0.0)
289 286 return;
290 287
291 288 if (m_sizeFactor != factor) {
292 289 m_sizeFactor = factor;
293 290 emit sizeFactorChanged();
294 291 }
295 292 }
296 293
297 294 /*!
298 295 Gets the size factor of the pie.
299 296 \sa setSizeFactor()
300 297 */
301 298 qreal QPieSeries::sizeFactor() const
302 299 {
303 300 return m_sizeFactor;
304 301 }
305 302
306 303 /*!
307 304 Sets the \a position of the pie within its bounding rectangle.
308 305 \sa PiePosition, position()
309 306 */
310 307 void QPieSeries::setPosition(PiePosition position)
311 308 {
312 309 if (m_position != position) {
313 310 m_position = position;
314 311 emit positionChanged();
315 312 }
316 313 }
317 314
318 315 /*!
319 316 Gets the position of the pie within its bounding rectangle.
320 317 \sa PiePosition, setPosition()
321 318 */
322 319 QPieSeries::PiePosition QPieSeries::position() const
323 320 {
324 321 return m_position;
325 322 }
326 323
327 324
328 325 /*!
329 326 Sets the \a startAngle and \a angleSpan of this series.
330 327
331 328 Full pie is 360 degrees where 0 degrees is at 12 a'clock.
332 329 */
333 330 void QPieSeries::setSpan(qreal startAngle, qreal angleSpan)
334 331 {
335 332 if (startAngle >= 0 && startAngle < 360 &&
336 333 angleSpan > 0 && angleSpan <= 360) {
337 334 m_pieStartAngle = startAngle;
338 335 m_pieAngleSpan = angleSpan;
339 336 updateDerivativeData();
340 337 }
341 338 }
342 339
343 340 /*!
344 341 Sets the all the slice labels \a visible or invisible.
345 342
346 343 \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
347 344 */
348 345 void QPieSeries::setLabelsVisible(bool visible)
349 346 {
350 347 foreach (QPieSlice* s, m_slices)
351 348 s->setLabelVisible(visible);
352 349 }
353 350
354 351 /*!
355 352 Convenience method for exploding a slice when user clicks the pie. Set \a enable to true to
356 353 explode slices by clicking.
357 354
358 355 \sa QPieSlice::isExploded(), QPieSlice::setExploded(), QPieSlice::setExplodeDistance()
359 356 */
360 357 void QPieSeries::enableClickExplodes(bool enable)
361 358 {
362 359 if (enable)
363 360 connect(this, SIGNAL(clicked(QPieSlice*)), this, SLOT(toggleExploded(QPieSlice*)));
364 361 else
365 362 disconnect(this, SLOT(toggleExploded(QPieSlice*)));
366 363 }
367 364
368 365 /*!
369 366 Convenience method for highlighting a slice when user hovers over the slice.
370 367 It changes the slice color to be lighter and shows the label of the slice.
371 368 Set \a enable to true to highlight a slice when user hovers on top of it.
372 369
373 370 \sa QPieSlice::isExploded(), QPieSlice::setExploded()
374 371 */
375 372
376 373 void QPieSeries::enableHoverHighlight(bool enable)
377 374 {
378 375 if (enable) {
379 376 connect(this, SIGNAL(hoverEnter(QPieSlice*)), this, SLOT(highlightOn(QPieSlice*)));
380 377 connect(this, SIGNAL(hoverLeave(QPieSlice*)), this, SLOT(highlightOff(QPieSlice*)));
381 378 } else {
382 379 disconnect(this, SLOT(hoverEnter(QPieSlice*)));
383 380 disconnect(this, SLOT(hoverLeave(QPieSlice*)));
384 381 }
385 382 }
386 383
387 384 /*!
388 385 \fn void QPieSeries::changed(const QPieSeries::ChangeSet& changeSet)
389 386
390 387 This signal emitted when something has changed in the series.
391 388 The \a changeSet contains the details of which slices have been added, changed or removed.
392 389
393 390 \sa QPieSeries::ChangeSet, QPieSlice::changed()
394 391 */
395 392
396 393 /*!
397 394 \fn void QPieSeries::clicked(QPieSlice* slice)
398 395
399 396 This signal is emitted when a \a slice has been clicked.
400 397
401 398 \sa QPieSlice::clicked()
402 399 */
403 400
404 401 /*!
405 402 \fn void QPieSeries::hoverEnter(QPieSlice* slice)
406 403
407 404 This signal is emitted when user has hovered over a \a slice.
408 405
409 406 \sa QPieSlice::hoverEnter()
410 407 */
411 408
412 409 /*!
413 410 \fn void QPieSeries::hoverLeave(QPieSlice* slice)
414 411
415 412 This signal is emitted when user has hovered away from a \a slice.
416 413
417 414 \sa QPieSlice::hoverLeave()
418 415 */
419 416
420 417 /*!
421 418 \fn void QPieSeries::sizeFactorChanged()
422 419
423 420 This signal is emitted when size factor has been changed.
424 421
425 422 \sa sizeFactor(), setSizeFactor()
426 423 */
427 424
428 425 /*!
429 426 \fn void QPieSeries::positionChanged()
430 427
431 428 This signal is emitted when position of the pie has been changed.
432 429
433 430 \sa position(), setPosition()
434 431 */
435 432
436 433 void QPieSeries::sliceChanged()
437 434 {
438 435 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
439 436 Q_ASSERT(m_slices.contains(slice));
440 437
441 438 ChangeSet changeSet;
442 439 changeSet.appendChanged(slice);
443 440 emit changed(changeSet);
444 441
445 442 updateDerivativeData();
446 443 }
447 444
448 445 void QPieSeries::sliceClicked()
449 446 {
450 447 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
451 448 Q_ASSERT(m_slices.contains(slice));
452 449 emit clicked(slice);
453 450 }
454 451
455 452 void QPieSeries::sliceHoverEnter()
456 453 {
457 454 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
458 455 Q_ASSERT(m_slices.contains(slice));
459 456 emit hoverEnter(slice);
460 457 }
461 458
462 459 void QPieSeries::sliceHoverLeave()
463 460 {
464 461 QPieSlice* slice = qobject_cast<QPieSlice *>(sender());
465 462 Q_ASSERT(m_slices.contains(slice));
466 463 emit hoverLeave(slice);
467 464 }
468 465
469 466 void QPieSeries::toggleExploded(QPieSlice* slice)
470 467 {
471 468 Q_ASSERT(slice);
472 469 slice->setExploded(!slice->isExploded());
473 470 }
474 471
475 472 void QPieSeries::highlightOn(QPieSlice* slice)
476 473 {
477 474 Q_ASSERT(slice);
478 475 QColor c = slice->brush().color().lighter();
479 476 slice->setBrush(c);
480 477 slice->setLabelVisible(true);
481 478 }
482 479
483 480 void QPieSeries::highlightOff(QPieSlice* slice)
484 481 {
485 482 Q_ASSERT(slice);
486 483 QColor c = slice->brush().color().darker(150);
487 484 slice->setBrush(c);
488 485 slice->setLabelVisible(false);
489 486 }
490 487
491 488 void QPieSeries::updateDerivativeData()
492 489 {
493 490 m_total = 0;
494 491
495 492 // nothing to do?
496 493 if (m_slices.count() == 0)
497 494 return;
498 495
499 496 // calculate total
500 497 foreach (QPieSlice* s, m_slices)
501 498 m_total += s->value();
502 499
503 500 // we must have some values
504 501 Q_ASSERT(m_total > 0); // TODO: is this the correct way to handle this?
505 502
506 503 // update slice attributes
507 504 qreal sliceAngle = m_pieStartAngle;
508 505 foreach (QPieSlice* s, m_slices) {
509 506
510 507 bool changed = false;
511 508
512 509 qreal percentage = s->value() / m_total;
513 510 if (s->m_percentage != percentage) {
514 511 s->m_percentage = percentage;
515 512 changed = true;
516 513 }
517 514
518 515 qreal sliceSpan = m_pieAngleSpan * percentage;
519 516 if (s->m_angleSpan != sliceSpan) {
520 517 s->m_angleSpan = sliceSpan;
521 518 changed = true;
522 519 }
523 520
524 521 if (s->m_angle != sliceAngle) {
525 522 s->m_angle = sliceAngle;
526 523 changed = true;
527 524 }
528 525 sliceAngle += sliceSpan;
529 526
530 527 if (changed)
531 528 emit s->changed();
532 529 }
533 530 }
534 531
535 532 #include "moc_qpieseries.cpp"
536 533
537 534 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now