##// END OF EJS Templates
Fix crash when signals connected to deleted PieChartItem are emitted...
Miikka Heikkinen -
r2423:5eb5ce9ed083
parent child
Show More
@@ -1,220 +1,228
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 "piechartitem_p.h"
21 #include "piechartitem_p.h"
22 #include "piesliceitem_p.h"
22 #include "piesliceitem_p.h"
23 #include "qpieslice.h"
23 #include "qpieslice.h"
24 #include "qpieslice_p.h"
24 #include "qpieslice_p.h"
25 #include "qpieseries.h"
25 #include "qpieseries.h"
26 #include "qpieseries_p.h"
26 #include "qpieseries_p.h"
27 #include "chartpresenter_p.h"
27 #include "chartpresenter_p.h"
28 #include "chartdataset_p.h"
28 #include "chartdataset_p.h"
29 #include "pieanimation_p.h"
29 #include "pieanimation_p.h"
30 #include <QPainter>
30 #include <QPainter>
31 #include <QTimer>
31 #include <QTimer>
32
32
33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
34
34
35 PieChartItem::PieChartItem(QPieSeries *series, QGraphicsItem* item)
35 PieChartItem::PieChartItem(QPieSeries *series, QGraphicsItem* item)
36 : ChartItem(series->d_func(),item),
36 : ChartItem(series->d_func(),item),
37 m_series(series),
37 m_series(series),
38 m_animation(0)
38 m_animation(0)
39 {
39 {
40 Q_ASSERT(series);
40 Q_ASSERT(series);
41
41
42 QPieSeriesPrivate *p = QPieSeriesPrivate::fromSeries(series);
42 QPieSeriesPrivate *p = QPieSeriesPrivate::fromSeries(series);
43 connect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
43 connect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
44 connect(series, SIGNAL(opacityChanged()), this, SLOT(handleOpacityChanged()));
44 connect(series, SIGNAL(opacityChanged()), this, SLOT(handleOpacityChanged()));
45 connect(series, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
45 connect(series, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
46 connect(series, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
46 connect(series, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
47 connect(p, SIGNAL(horizontalPositionChanged()), this, SLOT(updateLayout()));
47 connect(p, SIGNAL(horizontalPositionChanged()), this, SLOT(updateLayout()));
48 connect(p, SIGNAL(verticalPositionChanged()), this, SLOT(updateLayout()));
48 connect(p, SIGNAL(verticalPositionChanged()), this, SLOT(updateLayout()));
49 connect(p, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout()));
49 connect(p, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout()));
50 connect(p, SIGNAL(calculatedDataChanged()), this, SLOT(updateLayout()));
50 connect(p, SIGNAL(calculatedDataChanged()), this, SLOT(updateLayout()));
51
51
52 // Note: the following does not affect as long as the item does not have anything to paint
52 // Note: the following does not affect as long as the item does not have anything to paint
53 setZValue(ChartPresenter::PieSeriesZValue);
53 setZValue(ChartPresenter::PieSeriesZValue);
54
54
55 // Note: will not create slice items until we have a proper rectangle to draw on.
55 // Note: will not create slice items until we have a proper rectangle to draw on.
56 }
56 }
57
57
58 PieChartItem::~PieChartItem()
58 PieChartItem::~PieChartItem()
59 {
59 {
60 // slices deleted automatically through QGraphicsItem
60 // slices deleted automatically through QGraphicsItem
61 if (m_series) {
62 m_series->disconnect(this);
63 QPieSeriesPrivate::fromSeries(m_series)->disconnect(this);
64 }
65 foreach (QPieSlice *slice, m_sliceItems.keys()) {
66 slice->disconnect(this);
67 QPieSlicePrivate::fromSlice(slice)->disconnect(this);
68 }
61 }
69 }
62
70
63 void PieChartItem::setAnimation(PieAnimation *animation)
71 void PieChartItem::setAnimation(PieAnimation *animation)
64 {
72 {
65 m_animation = animation;
73 m_animation = animation;
66 }
74 }
67
75
68 ChartAnimation *PieChartItem::animation() const
76 ChartAnimation *PieChartItem::animation() const
69 {
77 {
70 return m_animation;
78 return m_animation;
71 }
79 }
72
80
73 void PieChartItem::handleDomainUpdated()
81 void PieChartItem::handleDomainUpdated()
74 {
82 {
75 QRectF rect(QPointF(0,0),domain()->size());
83 QRectF rect(QPointF(0,0),domain()->size());
76 if(m_rect!=rect){
84 if(m_rect!=rect){
77 prepareGeometryChange();
85 prepareGeometryChange();
78 m_rect = rect;
86 m_rect = rect;
79 updateLayout();
87 updateLayout();
80
88
81 if (m_sliceItems.isEmpty())
89 if (m_sliceItems.isEmpty())
82 handleSlicesAdded(m_series->slices());
90 handleSlicesAdded(m_series->slices());
83 }
91 }
84 }
92 }
85
93
86 void PieChartItem::updateLayout()
94 void PieChartItem::updateLayout()
87 {
95 {
88 // find pie center coordinates
96 // find pie center coordinates
89 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
97 m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
90 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
98 m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
91
99
92 // find maximum radius for pie
100 // find maximum radius for pie
93 m_pieRadius = m_rect.height() / 2;
101 m_pieRadius = m_rect.height() / 2;
94 if (m_rect.width() < m_rect.height())
102 if (m_rect.width() < m_rect.height())
95 m_pieRadius = m_rect.width() / 2;
103 m_pieRadius = m_rect.width() / 2;
96
104
97 m_holeSize = m_pieRadius;
105 m_holeSize = m_pieRadius;
98 // apply size factor
106 // apply size factor
99 m_pieRadius *= m_series->pieSize();
107 m_pieRadius *= m_series->pieSize();
100 m_holeSize *= m_series->holeSize();
108 m_holeSize *= m_series->holeSize();
101
109
102 // set layouts for existing slice items
110 // set layouts for existing slice items
103 foreach (QPieSlice *slice, m_series->slices()) {
111 foreach (QPieSlice *slice, m_series->slices()) {
104 PieSliceItem *sliceItem = m_sliceItems.value(slice);
112 PieSliceItem *sliceItem = m_sliceItems.value(slice);
105 if (sliceItem) {
113 if (sliceItem) {
106 PieSliceData sliceData = updateSliceGeometry(slice);
114 PieSliceData sliceData = updateSliceGeometry(slice);
107 if (m_animation)
115 if (m_animation)
108 presenter()->startAnimation(m_animation->updateValue(sliceItem, sliceData));
116 presenter()->startAnimation(m_animation->updateValue(sliceItem, sliceData));
109 else
117 else
110 sliceItem->setLayout(sliceData);
118 sliceItem->setLayout(sliceData);
111 }
119 }
112 }
120 }
113
121
114 update();
122 update();
115 }
123 }
116
124
117 void PieChartItem::handleSlicesAdded(QList<QPieSlice *> slices)
125 void PieChartItem::handleSlicesAdded(QList<QPieSlice *> slices)
118 {
126 {
119 // delay creating slice items until there is a proper rectangle
127 // delay creating slice items until there is a proper rectangle
120 if (!m_rect.isValid() && m_sliceItems.isEmpty())
128 if (!m_rect.isValid() && m_sliceItems.isEmpty())
121 return;
129 return;
122
130
123 themeManager()->updateSeries(m_series);
131 themeManager()->updateSeries(m_series);
124
132
125 bool startupAnimation = m_sliceItems.isEmpty();
133 bool startupAnimation = m_sliceItems.isEmpty();
126
134
127 foreach(QPieSlice * slice, slices) {
135 foreach(QPieSlice * slice, slices) {
128 PieSliceItem *sliceItem = new PieSliceItem(this);
136 PieSliceItem *sliceItem = new PieSliceItem(this);
129 m_sliceItems.insert(slice, sliceItem);
137 m_sliceItems.insert(slice, sliceItem);
130
138
131 // Note: no need to connect to slice valueChanged() etc.
139 // Note: no need to connect to slice valueChanged() etc.
132 // This is handled through calculatedDataChanged signal.
140 // This is handled through calculatedDataChanged signal.
133 connect(slice, SIGNAL(labelChanged()), this, SLOT(handleSliceChanged()));
141 connect(slice, SIGNAL(labelChanged()), this, SLOT(handleSliceChanged()));
134 connect(slice, SIGNAL(labelVisibleChanged()), this, SLOT(handleSliceChanged()));
142 connect(slice, SIGNAL(labelVisibleChanged()), this, SLOT(handleSliceChanged()));
135 connect(slice, SIGNAL(penChanged()), this, SLOT(handleSliceChanged()));
143 connect(slice, SIGNAL(penChanged()), this, SLOT(handleSliceChanged()));
136 connect(slice, SIGNAL(brushChanged()), this, SLOT(handleSliceChanged()));
144 connect(slice, SIGNAL(brushChanged()), this, SLOT(handleSliceChanged()));
137 connect(slice, SIGNAL(labelBrushChanged()), this, SLOT(handleSliceChanged()));
145 connect(slice, SIGNAL(labelBrushChanged()), this, SLOT(handleSliceChanged()));
138 connect(slice, SIGNAL(labelFontChanged()), this, SLOT(handleSliceChanged()));
146 connect(slice, SIGNAL(labelFontChanged()), this, SLOT(handleSliceChanged()));
139
147
140 QPieSlicePrivate *p = QPieSlicePrivate::fromSlice(slice);
148 QPieSlicePrivate *p = QPieSlicePrivate::fromSlice(slice);
141 connect(p, SIGNAL(labelPositionChanged()), this, SLOT(handleSliceChanged()));
149 connect(p, SIGNAL(labelPositionChanged()), this, SLOT(handleSliceChanged()));
142 connect(p, SIGNAL(explodedChanged()), this, SLOT(handleSliceChanged()));
150 connect(p, SIGNAL(explodedChanged()), this, SLOT(handleSliceChanged()));
143 connect(p, SIGNAL(labelArmLengthFactorChanged()), this, SLOT(handleSliceChanged()));
151 connect(p, SIGNAL(labelArmLengthFactorChanged()), this, SLOT(handleSliceChanged()));
144 connect(p, SIGNAL(explodeDistanceFactorChanged()), this, SLOT(handleSliceChanged()));
152 connect(p, SIGNAL(explodeDistanceFactorChanged()), this, SLOT(handleSliceChanged()));
145
153
146 connect(sliceItem, SIGNAL(clicked(Qt::MouseButtons)), slice, SIGNAL(clicked()));
154 connect(sliceItem, SIGNAL(clicked(Qt::MouseButtons)), slice, SIGNAL(clicked()));
147 connect(sliceItem, SIGNAL(hovered(bool)), slice, SIGNAL(hovered(bool)));
155 connect(sliceItem, SIGNAL(hovered(bool)), slice, SIGNAL(hovered(bool)));
148
156
149 PieSliceData sliceData = updateSliceGeometry(slice);
157 PieSliceData sliceData = updateSliceGeometry(slice);
150 if (m_animation)
158 if (m_animation)
151 presenter()->startAnimation(m_animation->addSlice(sliceItem, sliceData, startupAnimation));
159 presenter()->startAnimation(m_animation->addSlice(sliceItem, sliceData, startupAnimation));
152 else
160 else
153 sliceItem->setLayout(sliceData);
161 sliceItem->setLayout(sliceData);
154 }
162 }
155 }
163 }
156
164
157 void PieChartItem::handleSlicesRemoved(QList<QPieSlice *> slices)
165 void PieChartItem::handleSlicesRemoved(QList<QPieSlice *> slices)
158 {
166 {
159 themeManager()->updateSeries(m_series);
167 themeManager()->updateSeries(m_series);
160
168
161 foreach (QPieSlice *slice, slices) {
169 foreach (QPieSlice *slice, slices) {
162
170
163 PieSliceItem *sliceItem = m_sliceItems.value(slice);
171 PieSliceItem *sliceItem = m_sliceItems.value(slice);
164
172
165 // this can happen if you call append() & remove() in a row so that PieSliceItem is not even created
173 // this can happen if you call append() & remove() in a row so that PieSliceItem is not even created
166 if (!sliceItem)
174 if (!sliceItem)
167 continue;
175 continue;
168
176
169 m_sliceItems.remove(slice);
177 m_sliceItems.remove(slice);
170 slice->disconnect(this);
178 slice->disconnect(this);
171 QPieSlicePrivate::fromSlice(slice)->disconnect(this);
179 QPieSlicePrivate::fromSlice(slice)->disconnect(this);
172
180
173 if (m_animation)
181 if (m_animation)
174 presenter()->startAnimation(m_animation->removeSlice(sliceItem)); // animator deletes the PieSliceItem
182 presenter()->startAnimation(m_animation->removeSlice(sliceItem)); // animator deletes the PieSliceItem
175 else
183 else
176 delete sliceItem;
184 delete sliceItem;
177 }
185 }
178 }
186 }
179
187
180 void PieChartItem::handleSliceChanged()
188 void PieChartItem::handleSliceChanged()
181 {
189 {
182 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
190 QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
183 if (!slice) {
191 if (!slice) {
184 QPieSlicePrivate *slicep = qobject_cast<QPieSlicePrivate *>(sender());
192 QPieSlicePrivate *slicep = qobject_cast<QPieSlicePrivate *>(sender());
185 slice = slicep->q_ptr;
193 slice = slicep->q_ptr;
186 }
194 }
187 Q_ASSERT(m_sliceItems.contains(slice));
195 Q_ASSERT(m_sliceItems.contains(slice));
188
196
189 PieSliceItem *sliceItem = m_sliceItems.value(slice);
197 PieSliceItem *sliceItem = m_sliceItems.value(slice);
190 PieSliceData sliceData = updateSliceGeometry(slice);
198 PieSliceData sliceData = updateSliceGeometry(slice);
191 if (m_animation)
199 if (m_animation)
192 presenter()->startAnimation(m_animation->updateValue(sliceItem, sliceData));
200 presenter()->startAnimation(m_animation->updateValue(sliceItem, sliceData));
193 else
201 else
194 sliceItem->setLayout(sliceData);
202 sliceItem->setLayout(sliceData);
195
203
196 update();
204 update();
197 }
205 }
198
206
199 void PieChartItem::handleSeriesVisibleChanged()
207 void PieChartItem::handleSeriesVisibleChanged()
200 {
208 {
201 setVisible(m_series->isVisible());
209 setVisible(m_series->isVisible());
202 }
210 }
203
211
204 void PieChartItem::handleOpacityChanged()
212 void PieChartItem::handleOpacityChanged()
205 {
213 {
206 setOpacity(m_series->opacity());
214 setOpacity(m_series->opacity());
207 }
215 }
208
216
209 PieSliceData PieChartItem::updateSliceGeometry(QPieSlice *slice)
217 PieSliceData PieChartItem::updateSliceGeometry(QPieSlice *slice)
210 {
218 {
211 PieSliceData &sliceData = QPieSlicePrivate::fromSlice(slice)->m_data;
219 PieSliceData &sliceData = QPieSlicePrivate::fromSlice(slice)->m_data;
212 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
220 sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
213 sliceData.m_radius = m_pieRadius;
221 sliceData.m_radius = m_pieRadius;
214 sliceData.m_holeRadius = m_holeSize;
222 sliceData.m_holeRadius = m_holeSize;
215 return sliceData;
223 return sliceData;
216 }
224 }
217
225
218 #include "moc_piechartitem_p.cpp"
226 #include "moc_piechartitem_p.cpp"
219
227
220 QTCOMMERCIALCHART_END_NAMESPACE
228 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now