##// END OF EJS Templates
Refactoring piechart API (and internals)
Jani Honkonen -
r174:0d781305aa75
parent child
Show More
@@ -0,0 +1,76
1 #include "pieslicelabel.h"
2 #include <QPainter>
3 #include <qmath.h>
4
5 QTCOMMERCIALCHART_BEGIN_NAMESPACE
6
7 #define PI 3.14159265
8
9 PieSliceLabel::PieSliceLabel(QGraphicsItem* parent)
10 :QGraphicsItem(parent)
11 {
12 m_pen = QPen(Qt::black);
13 }
14
15 PieSliceLabel::~PieSliceLabel()
16 {
17
18 }
19
20 QRectF PieSliceLabel::boundingRect() const
21 {
22 return m_rect;
23 }
24
25 QPainterPath PieSliceLabel::shape() const
26 {
27 return m_path;
28 }
29
30 void PieSliceLabel::paint(QPainter *painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
31 {
32 painter->setRenderHint(QPainter::Antialiasing);
33 painter->setPen(m_pen);
34 painter->drawPath(m_path);
35 }
36
37 void PieSliceLabel::updateGeometry(const QPointF& startPoint, qreal armAngle, qreal armLength)
38 {
39 prepareGeometryChange();
40
41 QPainterPath path;
42 path.moveTo(startPoint);
43
44 // draw arm
45 qreal dx = qSin(armAngle*(PI/180)) * armLength;
46 qreal dy = -qCos(armAngle*(PI/180)) * armLength;
47 QPointF p1 = startPoint + QPointF(dx, dy);
48 path.lineTo(p1);
49
50 QPointF p2 = p1;
51 QPointF pt = p1;
52 if (armAngle < 180) {
53 p2 += QPointF(50, 0);
54 } else {
55 p2 += QPointF(-50,0);
56 pt = p2;
57 }
58 path.lineTo(p2);
59
60 QFont font;
61 pt += QPointF(0,-2);
62 path.addText(pt, font, m_label);
63
64 m_path = path;
65 m_rect = path.boundingRect();
66 }
67
68 void PieSliceLabel::setLabel(QString label)
69 {
70 m_label = label;
71 // TODO: animation?
72 }
73
74
75
76 QTCOMMERCIALCHART_END_NAMESPACE
@@ -0,0 +1,36
1 #ifndef PIELABEL_H
2 #define PIELABEL_H
3
4 #include "qchartglobal.h"
5 #include <QGraphicsItem>
6 #include <QPen>
7
8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9
10 class PieSliceLabel : public QGraphicsItem
11 {
12 public:
13 PieSliceLabel(QGraphicsItem* parent = 0);
14 ~PieSliceLabel();
15
16 public: // from QGraphicsItem
17 QRectF boundingRect() const;
18 QPainterPath shape() const;
19 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
20
21 public:
22 void updateGeometry(const QPointF& startPoint, qreal armAngle, qreal armLength);
23 void setLabel(QString label);
24 QString label() const {return m_label;}
25 void setPen(QPen pen);
26
27 private:
28 QString m_label;
29 QPainterPath m_path;
30 QRectF m_rect;
31 QPen m_pen;
32 };
33
34 QTCOMMERCIALCHART_END_NAMESPACE
35
36 #endif // PIELABEL_H
@@ -17,11 +17,11 int main(int argc, char *argv[])
17 Q_ASSERT(series);
17 Q_ASSERT(series);
18
18
19 // Add test data to the series
19 // Add test data to the series
20 series->add(QPieSlice(1, "test1", Qt::red, true));
20 series->add(QPieSlice(1, "test1", true, true, QPen(Qt::red, 2), QBrush(Qt::red)));
21 series->add(QPieSlice(2, "test2", Qt::green));
21 series->add(QPieSlice(2, "test2"));
22 series->add(QPieSlice(3, "test3", Qt::blue));
22 series->add(QPieSlice(3, "test3"));
23 series->add(QPieSlice(4, "test4", Qt::darkRed, true));
23 series->add(QPieSlice(4, "test4"));
24 series->add(QPieSlice(5, "test5", Qt::darkGreen));
24 series->add(QPieSlice(5, "test5"));
25
25
26 // Use the chart widget as the central widget
26 // Use the chart widget as the central widget
27 QMainWindow w;
27 QMainWindow w;
@@ -198,14 +198,12 void ChartTheme::decorate(PiePresenter* item, QPieSeries* series, int /*count*/)
198 }
198 }
199
199
200 // finally update colors
200 // finally update colors
201 QList<QPieSlice> slices;
201 foreach (QPieSliceId id, series->ids()) {
202 for (int i=0; i<series->count(); i++) {
202 QPieSlice s = series->slice(id);
203 QPieSlice slice = series->slice(i);
203 s.setPen(QPen(Qt::black)); // TODO: get from theme
204 slice.m_color = colors.at(i);
204 s.setBrush(colors.takeFirst());
205 slices << slice;
205 series->update(s);
206 }
206 }
207
208 series->set(slices);
209 }
207 }
210
208
211
209
@@ -4,11 +4,13 DEPENDPATH += $$PWD
4 SOURCES += \
4 SOURCES += \
5 $$PWD/qpieseries.cpp \
5 $$PWD/qpieseries.cpp \
6 $$PWD/pieslice.cpp \
6 $$PWD/pieslice.cpp \
7 $$PWD/piepresenter.cpp
7 $$PWD/piepresenter.cpp \
8 $$PWD/pieslicelabel.cpp
8
9
9 PRIVATE_HEADERS += \
10 PRIVATE_HEADERS += \
10 $$PWD/piepresenter.h \
11 $$PWD/piepresenter.h \
11 $$PWD/pieslice.h
12 $$PWD/pieslice.h \
13 $$PWD/pieslicelabel.h
12
14
13 PUBLIC_HEADERS += \
15 PUBLIC_HEADERS += \
14 $$PWD/qpieseries.h
16 $$PWD/qpieseries.h
@@ -6,57 +6,50
6
6
7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
7 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8
8
9 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series) :
9 PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series)
10 ChartItem(parent),
10 :ChartItem(parent),
11 m_pieSeries(series)
11 m_series(series)
12 {
12 {
13 Q_ASSERT(parent);
14 Q_ASSERT(series);
13 Q_ASSERT(series);
15
14 connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&)));
16 m_rect = parentItem()->boundingRect();
17 setAcceptHoverEvents(true);
18 qsrand(QTime::currentTime().msec()); // for random color generation
19
20 connect(series, SIGNAL(changed(const PieChangeSet&)), this, SLOT(handleSeriesChanged(const PieChangeSet&)));
21 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
15 connect(series, SIGNAL(sizeFactorChanged()), this, SLOT(updateGeometry()));
22 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
16 connect(series, SIGNAL(positionChanged()), this, SLOT(updateGeometry()));
23 }
17 }
24
18
25 PiePresenter::~PiePresenter()
19 PiePresenter::~PiePresenter()
26 {
20 {
27 while (m_slices.count())
21 // slices deleted automatically through QGraphicsItem
28 delete m_slices.takeLast();
29 }
22 }
30
23
31 void PiePresenter::handleSeriesChanged(const PieChangeSet& /*changeSet*/)
24 void PiePresenter::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
32 {
25 {
33 const qreal fullPie = 360;
26 // TODO: paint shadows for all components
34 qreal total = 0;
27 // - get paths from items & merge & offset and draw with shadow color?
35
36 // calculate total and set random color if there is no color
37 for (int i=0; i<m_pieSeries->count(); i++) {
38 QPieSlice& slice = m_pieSeries->m_slices[i];
39 total += slice.m_value;
40 if (slice.m_color == QColor::Invalid) {
41 slice.m_color.setRed(qrand() % 255);
42 slice.m_color.setGreen(qrand() % 255);
43 slice.m_color.setBlue(qrand() % 255);
44 }
28 }
29
30 void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet)
31 {
32 qDebug() << "PiePresenter::handleSeriesChanged()";
33 qDebug() << " added : " << changeSet.m_added;
34 qDebug() << " changed: " << changeSet.m_changed;
35 qDebug() << " removed: " << changeSet.m_removed;
36
37 // ignore changeset when there are no visual slices
38 // changeset might not be valid about the added slices
39 if (m_slices.count() == 0) {
40 foreach (QPieSliceId id, m_series->m_slices.keys())
41 addSlice(id);
42 return;
45 }
43 }
46
44
47 // TODO: no need to create new slices in case size changed; we should re-use the existing ones
45 foreach (QPieSliceId id, changeSet.m_removed)
48 while (m_slices.count())
46 deleteSlice(id);
49 delete m_slices.takeLast();
50
47
51 // create slices
48 foreach (QPieSliceId id, changeSet.m_changed)
52 qreal angle = 0;
49 updateSlice(id);
53 for (int i=0; i<m_pieSeries->count(); i++) {
50
54 QPieSlice sliceData = m_pieSeries->slice(i);
51 foreach (QPieSliceId id, changeSet.m_added)
55 qreal span = sliceData.m_value / total * fullPie;
52 addSlice(id);
56 PieSlice *slice = new PieSlice(this, i, angle, span);
57 m_slices.append(slice);
58 angle += span;
59 }
60 }
53 }
61
54
62 void PiePresenter::updateGeometry()
55 void PiePresenter::updateGeometry()
@@ -66,16 +59,16 void PiePresenter::updateGeometry()
66 m_pieRect = m_rect;
59 m_pieRect = m_rect;
67
60
68 if (m_pieRect.width() < m_pieRect.height()) {
61 if (m_pieRect.width() < m_pieRect.height()) {
69 m_pieRect.setWidth(m_pieRect.width() * m_pieSeries->sizeFactor());
62 m_pieRect.setWidth(m_pieRect.width() * m_series->sizeFactor());
70 m_pieRect.setHeight(m_pieRect.width());
63 m_pieRect.setHeight(m_pieRect.width());
71 m_pieRect.moveCenter(m_rect.center());
64 m_pieRect.moveCenter(m_rect.center());
72 } else {
65 } else {
73 m_pieRect.setHeight(m_pieRect.height() * m_pieSeries->sizeFactor());
66 m_pieRect.setHeight(m_pieRect.height() * m_series->sizeFactor());
74 m_pieRect.setWidth(m_pieRect.height());
67 m_pieRect.setWidth(m_pieRect.height());
75 m_pieRect.moveCenter(m_rect.center());
68 m_pieRect.moveCenter(m_rect.center());
76 }
69 }
77
70
78 switch (m_pieSeries->position()) {
71 switch (m_series->position()) {
79 case QPieSeries::PiePositionTopLeft: {
72 case QPieSeries::PiePositionTopLeft: {
80 m_pieRect.setHeight(m_pieRect.height() / 2);
73 m_pieRect.setHeight(m_pieRect.height() / 2);
81 m_pieRect.setWidth(m_pieRect.height());
74 m_pieRect.setWidth(m_pieRect.height());
@@ -104,10 +97,16 void PiePresenter::updateGeometry()
104 break;
97 break;
105 }
98 }
106
99
107 qDebug() << "presentation rect:" << m_rect;
100 // update slice geometry
108 qDebug() << "pie rect:" << m_pieRect;
101 const qreal fullPie = 360;
109 foreach (PieSlice *slice, m_slices)
102 qreal angle = 0;
110 slice->updateGeometry();
103 foreach (QPieSliceId id, m_slices.keys()) {
104 qreal span = fullPie * m_series->slice(id).percentage();
105 m_slices[id]->updateGeometry(m_pieRect, angle, span);
106 angle += span;
107 }
108
109 //qDebug() << "PiePresenter::updateGeometry" << m_rect << m_pieRect;
111 }
110 }
112
111
113 void PiePresenter::handleDomainChanged(const Domain& domain)
112 void PiePresenter::handleDomainChanged(const Domain& domain)
@@ -119,7 +118,51 void PiePresenter::handleGeometryChanged(const QRectF& rect)
119 {
118 {
120 m_rect = rect;
119 m_rect = rect;
121 updateGeometry();
120 updateGeometry();
121 }
122
123 void PiePresenter::addSlice(QPieSliceId id)
124 {
125 qDebug() << "PiePresenter::addSlice()" << id;
126
127 if (m_slices.contains(id)) {
128 qWarning() << "PiePresenter::addSlice(): slice already exists!" << id;
129 updateSlice(id);
130 return;
131 }
132
133 // create slice
134 PieSlice *slice = new PieSlice(id, m_series, this);
135 m_slices.insert(id, slice);
136
137 updateGeometry();
138 }
122
139
140 void PiePresenter::updateSlice(QPieSliceId id)
141 {
142 qDebug() << "PiePresenter::updateSlice()" << id;
143
144 // TODO: animation
145 if (m_slices.contains(id))
146 m_slices.value(id)->updateData();
147 else {
148 qWarning() << "PiePresenter::updateSlice(): slice does not exist!" << id;
149 addSlice(id);
150 }
151
152 updateGeometry();
153 }
154
155 void PiePresenter::deleteSlice(QPieSliceId id)
156 {
157 qDebug() << "PiePresenter::deleteSlice()" << id;
158
159 // TODO: animation
160 if (m_slices.contains(id))
161 delete m_slices.take(id);
162 else
163 qWarning() << "PiePresenter::deleteSlice(): slice does not exist!" << id;
164
165 updateGeometry();
123 }
166 }
124
167
125 #include "moc_piepresenter.cpp"
168 #include "moc_piepresenter.cpp"
@@ -3,6 +3,7
3
3
4 #include "chartitem_p.h"
4 #include "chartitem_p.h"
5 #include "qpieseries.h"
5 #include "qpieseries.h"
6 #include <QSignalMapper>
6
7
7 class QGraphicsItem;
8 class QGraphicsItem;
8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
@@ -19,21 +20,26 public:
19
20
20 public: // from QGraphicsItem
21 public: // from QGraphicsItem
21 QRectF boundingRect() const { return m_rect; }
22 QRectF boundingRect() const { return m_rect; }
22 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
23 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
23
24
24 public:
25 public:
25 QRectF pieRect() const { return m_pieRect; }
26 QRectF pieRect() const { return m_pieRect; }
26
27
27 public Q_SLOTS:
28 public Q_SLOTS:
28 void handleSeriesChanged(const PieChangeSet& changeSet);
29 void handleSeriesChanged(const QPieSeries::ChangeSet& changeSet);
29 void handleDomainChanged(const Domain& domain);
30 void handleDomainChanged(const Domain& domain);
30 void handleGeometryChanged(const QRectF& rect);
31 void handleGeometryChanged(const QRectF& rect);
31 void updateGeometry();
32 void updateGeometry();
32
33
33 private:
34 private:
35 void addSlice(QPieSliceId id);
36 void updateSlice(QPieSliceId id);
37 void deleteSlice(QPieSliceId id);
38
39 private:
34 friend class PieSlice;
40 friend class PieSlice;
35 QList<PieSlice*> m_slices;
41 QHash<QPieSliceId, PieSlice*> m_slices;
36 QPieSeries *m_pieSeries;
42 QPieSeries *m_series;
37 QRectF m_rect;
43 QRectF m_rect;
38 QRectF m_pieRect;
44 QRectF m_pieRect;
39 };
45 };
@@ -1,10 +1,12
1 #include "pieslice.h"
1 #include "pieslice.h"
2 #include "pieslicelabel.h"
2 #include "piepresenter.h"
3 #include "piepresenter.h"
3 #include "qpieseries.h"
4 #include "qpieseries.h"
4 #include <QPainter>
5 #include <QPainter>
5 #include <QDebug>
6 #include <QDebug>
6 #include <qmath.h>
7 #include <qmath.h>
7 #include <QGraphicsSceneEvent>
8 #include <QGraphicsSceneEvent>
9 #include <QTime>
8
10
9 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 QTCOMMERCIALCHART_BEGIN_NAMESPACE
10
12
@@ -18,25 +20,22 QPointF offset(qreal angle, qreal length)
18 return QPointF(dx, -dy);
20 return QPointF(dx, -dy);
19 }
21 }
20
22
21 PieSlice::PieSlice(PiePresenter *presenter, int seriesIndex, qreal startAngle, qreal span)
23 PieSlice::PieSlice(QPieSliceId id, QPieSeries *series, QGraphicsItem* parent)
22 :QGraphicsItem(presenter),
24 :QGraphicsObject(parent),
23 m_label(new QGraphicsTextItem(this)),
25 m_id(id),
24 m_seriesIndex(seriesIndex),
26 m_series(series),
25 m_startAngle(startAngle),
27 m_slicelabel(new PieSliceLabel(this)),
26 m_span(span)
28 m_isHovering(false)
27 {
29 {
28 Q_ASSERT(presenter);
30 Q_ASSERT(series);
29 setAcceptHoverEvents(true);
31 setAcceptHoverEvents(true);
30 setAcceptedMouseButtons(Qt::LeftButton);
32 setAcceptedMouseButtons(Qt::LeftButton);
31 updateGeometry();
33 updateData();
32
33 // TODO: use themes
34 m_pen = QPen(Qt::black);
35 m_brush = QBrush(sliceData().m_color);
36 }
34 }
37
35
38 PieSlice::~PieSlice()
36 PieSlice::~PieSlice()
39 {
37 {
38 qDebug() << "~PieSlice()" << m_id;
40 }
39 }
41
40
42 QRectF PieSlice::boundingRect() const
41 QRectF PieSlice::boundingRect() const
@@ -51,72 +50,86 QPainterPath PieSlice::shape() const
51
50
52 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
51 void PieSlice::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget* /*widget*/)
53 {
52 {
54 painter->setRenderHint(QPainter::Antialiasing);
53 // set hover brush
54 // TODO: what if we are using gradients...
55 QBrush brush = m_data.brush();
56 if (m_isHovering)
57 brush.setColor(brush.color().lighter());
55
58
56 // TODO: themes
59 painter->setRenderHint(QPainter::Antialiasing);
57 painter->setPen(m_pen);
60 painter->setPen(m_data.pen());
58 painter->setBrush(m_brush);
61 painter->setBrush(brush);
59 painter->drawPath(m_path);
62 painter->drawPath(m_path);
60
61 // Draw the label
62 // TODO: do this better
63 //QTextItem text;
64 painter->drawText(m_center, sliceData().m_label);
65 }
63 }
66
64
67 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
65 void PieSlice::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/)
68 {
66 {
69 m_brush = QBrush(sliceData().m_color.lighter());
67 m_isHovering = true;
70 update();
68 update();
69 // TODO: emit hoverEnter()
71 }
70 }
72
71
73 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
72 void PieSlice::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/)
74 {
73 {
75 m_brush = QBrush(sliceData().m_color);
74 m_isHovering = false;
76 update();
75 update();
76 // TODO: emit hoverLeave()
77 }
77 }
78
78
79 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
79 void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/)
80 {
80 {
81 QPieSlice data = sliceData();
81 // TODO: emit clicked
82 data.m_isExploded = !data.m_isExploded;
82 // TODO: should we let the user decide if this can be exploded?
83 (static_cast<PiePresenter*>(parentItem()))->m_pieSeries->update(m_seriesIndex, data);
83 m_data.setExploded(!m_data.isExploded());
84 m_series->update(m_data);
84 }
85 }
85
86
86 void PieSlice::updateGeometry()
87 void PieSlice::updateGeometry(QRectF rect, qreal startAngle, qreal span)
87 {
88 {
88 prepareGeometryChange();
89 prepareGeometryChange();
89
90
90 PiePresenter *presenter = static_cast<PiePresenter*>(parentItem());
91 // calculate center angle
91 QRectF rect = presenter->pieRect();
92 qreal centerAngle = startAngle + (span/2);
92 rect.adjust(EXPLODE_OFFSET, EXPLODE_OFFSET, -EXPLODE_OFFSET ,-EXPLODE_OFFSET);
93
93
94 qreal centerAngle = m_startAngle + (m_span/2);
94 // adjust rect for exploding
95
95 rect.adjust(EXPLODE_OFFSET, EXPLODE_OFFSET, -EXPLODE_OFFSET ,-EXPLODE_OFFSET);
96 if (presenter->m_pieSeries->slice(m_seriesIndex).m_isExploded) {
96 if (m_data.isExploded()) {
97 QPointF d = offset((centerAngle), EXPLODE_OFFSET);
97 QPointF d = offset((centerAngle), EXPLODE_OFFSET);
98 rect.translate(d.x(), d.y());
98 rect.translate(d.x(), d.y());
99 }
99 }
100
100
101 qreal angle = (-m_startAngle) + (90);
101 // update slice path
102 qreal span = -m_span;
102 // TODO: draw the shape so that it might have a hole in the center
103
104 QPainterPath path;
103 QPainterPath path;
105 path.moveTo(rect.center());
104 path.moveTo(rect.center());
106 path.arcTo(rect, angle, span);
105 path.arcTo(rect, -startAngle + 90, -span);
107
108 // TODO: draw the shape so that it might have a hole in the center
109
110 m_path = path;
106 m_path = path;
111 m_rect = path.boundingRect();
107 m_rect = path.boundingRect();
112
108
109 // update label position
113 qreal radius = rect.height() / 2;
110 qreal radius = rect.height() / 2;
114 m_center = rect.center() + offset(centerAngle, radius / 2);
111 QPointF edgeCenter = rect.center() + offset(centerAngle, radius + 5);
112 m_slicelabel->updateGeometry(edgeCenter, centerAngle, 50);
113
114 //qDebug() << "PieSlice::updateGeometry" << m_rect;
115 }
115 }
116
116
117 QPieSlice PieSlice::sliceData()
117 void PieSlice::updateData()
118 {
118 {
119 return (static_cast<PiePresenter*>(parentItem()))->m_pieSeries->slice(m_seriesIndex);
119 if (!m_series->m_slices.contains(m_id))
120 qWarning() << "PieSlice::updateData(): cannot find slice data!" << m_id;
121
122 QPieSlice data = m_series->slice(m_id);
123 // TODO: find out what has changed and trigger some animation
124 m_data = data;
125
126 update();
127
128 m_slicelabel->setLabel(m_data.label());
129 m_slicelabel->setVisible(m_data.isLabelVisible());
130 m_slicelabel->update();
120 }
131 }
121
132
133 #include "moc_pieslice.cpp"
134
122 QTCOMMERCIALCHART_END_NAMESPACE
135 QTCOMMERCIALCHART_END_NAMESPACE
@@ -11,11 +11,14
11
11
12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
13 class PiePresenter;
13 class PiePresenter;
14 class PieSliceLabel;
14
15
15 class PieSlice : public QGraphicsItem
16 class PieSlice : public QGraphicsObject
16 {
17 {
18 Q_OBJECT
19
17 public:
20 public:
18 PieSlice(PiePresenter *piePresenter, int seriesIndex, qreal startAngle, qreal span);
21 PieSlice(QPieSliceId id, QPieSeries *series, QGraphicsItem* parent = 0);
19 ~PieSlice();
22 ~PieSlice();
20
23
21 public: // from QGraphicsItem
24 public: // from QGraphicsItem
@@ -26,22 +29,21 public: // from QGraphicsItem
26 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
29 void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
27 void mousePressEvent(QGraphicsSceneMouseEvent *event);
30 void mousePressEvent(QGraphicsSceneMouseEvent *event);
28
31
29 public:
32 Q_SIGNALS:
30 void updateGeometry();
33 void clicked();
31
34
32 private:
35 public:
33 QPieSlice sliceData();
36 void updateGeometry(QRectF rect, qreal startAngle, qreal span);
37 void updateData();
34
38
35 private:
39 private:
36 QGraphicsTextItem* m_label;
40 QPieSliceId m_id;
37 int m_seriesIndex;
41 QPieSeries* m_series;
38 qreal m_startAngle;
42 QPieSlice m_data;
39 qreal m_span;
43 PieSliceLabel* m_slicelabel;
40 QPainterPath m_path;
44 QPainterPath m_path;
41 QRectF m_rect;
45 QRectF m_rect;
42 QPointF m_center;
46 bool m_isHovering;
43 QPen m_pen;
44 QBrush m_brush;
45 };
47 };
46
48
47 QTCOMMERCIALCHART_END_NAMESPACE
49 QTCOMMERCIALCHART_END_NAMESPACE
@@ -8,7 +8,8 QTCOMMERCIALCHART_BEGIN_NAMESPACE
8 QPieSeries::QPieSeries(QObject *parent) :
8 QPieSeries::QPieSeries(QObject *parent) :
9 QChartSeries(parent),
9 QChartSeries(parent),
10 m_sizeFactor(1.0),
10 m_sizeFactor(1.0),
11 m_position(PiePositionMaximized)
11 m_position(PiePositionMaximized),
12 m_sliceIdSeed(0)
12 {
13 {
13 }
14 }
14
15
@@ -19,70 +20,93 QPieSeries::~QPieSeries()
19
20
20 bool QPieSeries::setData(QList<qreal> data)
21 bool QPieSeries::setData(QList<qreal> data)
21 {
22 {
23 // TODO: remove this function
22 QList<QPieSlice> slices;
24 QList<QPieSlice> slices;
23 foreach (int value, data)
25 foreach (int value, data)
24 slices << QPieSlice(value, QString::number(value));
26 slices << QPieSlice(value, QString::number(value));
25 return set(slices);
27 return set(slices);
26 }
28 }
27
29
28 bool QPieSeries::set(QList<QPieSlice> slices)
30 bool QPieSeries::set(const QList<QPieSlice>& slices)
29 {
31 {
30 if (!slices.count())
32 if (!slices.count())
31 return false;
33 return false;
32
34
33 PieChangeSet changeSet;
35 ChangeSet changeSet;
34
36
35 for (int i=slices.count(); i<m_slices.count(); i++)
37 foreach (QPieSlice s, m_slices.values())
36 changeSet.m_removed << i;
38 changeSet.m_removed << s.id();
37
39
38 for (int i=0; i<slices.count(); i++) {
40 m_slices.clear();
39 if (i < m_slices.count())
41
40 changeSet.m_changed << i;
42 foreach (QPieSlice s, slices) {
41 else
43 s.m_id = generateSliceId();
42 changeSet.m_added << i;
44 m_slices.insert(s.id(), s);
45 changeSet.m_added << s.id();
43 }
46 }
44
47
45 m_slices = slices;
48 updateDerivativeData();
46 emit changed(changeSet);
49 emit changed(changeSet);
50
47 return true;
51 return true;
48 }
52 }
49
53
50 bool QPieSeries::add(QList<QPieSlice> slices)
54 bool QPieSeries::add(const QList<QPieSlice>& slices)
51 {
55 {
52 if (!slices.count())
56 if (!slices.count())
53 return false;
57 return false;
54
58
55 PieChangeSet changeSet;
59 ChangeSet changeSet;
56 for (int i=0; i<slices.count(); i++)
60 foreach (QPieSlice s, slices) {
57 changeSet.m_added << m_slices.count() + i;
61 s.m_id = generateSliceId();
62 m_slices.insert(s.id(), s);
63 changeSet.m_added << s.id();
64 }
58
65
59 m_slices += slices;
66 updateDerivativeData();
60 emit changed(changeSet);
67 emit changed(changeSet);
68
61 return true;
69 return true;
62 }
70 }
63
71
64 bool QPieSeries::add(QPieSlice slice)
72 bool QPieSeries::add(const QPieSlice& slice)
65 {
73 {
66 return add(QList<QPieSlice>() << slice);
74 return add(QList<QPieSlice>() << slice);
67 }
75 }
68
76
69 QPieSlice QPieSeries::slice(int index) const
77 bool QPieSeries::update(const QPieSlice& slice)
70 {
78 {
71 if ((index >= 0) && (index < m_slices.count()))
79 if (!m_slices.contains(slice.id()))
72 return m_slices.at(index);
80 return false; // series does not contain this slice
73 return QPieSlice();
81
82 m_slices[slice.id()] = slice;
83
84 ChangeSet changeSet;
85 changeSet.m_changed << slice.id();
86 updateDerivativeData();
87 emit changed(changeSet);
88
89 return true;
74 }
90 }
75
91
76 bool QPieSeries::update(int index, QPieSlice slice)
92 bool QPieSeries::remove(QPieSliceId id)
77 {
93 {
78 if ((index >= 0) && (index < m_slices.count())) {
94 if (!m_slices.contains(id))
79 m_slices[index] = slice;
95 return false; // series does not contain this slice
80 PieChangeSet changeSet;
96
81 changeSet.m_changed << index;
97 m_slices.remove(id);
98
99 ChangeSet changeSet;
100 changeSet.m_removed << id;
101 updateDerivativeData();
82 emit changed(changeSet);
102 emit changed(changeSet);
103
83 return true;
104 return true;
84 }
105 }
85 return false;
106
107 QPieSlice QPieSeries::slice(QPieSliceId id) const
108 {
109 return m_slices.value(id);
86 }
110 }
87
111
88 void QPieSeries::setSizeFactor(qreal factor)
112 void QPieSeries::setSizeFactor(qreal factor)
@@ -104,6 +128,25 void QPieSeries::setPosition(PiePosition position)
104 }
128 }
105 }
129 }
106
130
131 QPieSliceId QPieSeries::generateSliceId()
132 {
133 // Id is quint64 so it should be enough for us.
134 // Note that id is not unique between pie series.
135 return m_sliceIdSeed++;
136 }
137
138 void QPieSeries::updateDerivativeData()
139 {
140 m_total = 0;
141 foreach (const QPieSlice& s, m_slices.values())
142 m_total += s.value();
143
144 Q_ASSERT(m_total > 0); // TODO: remove this before release
145
146 foreach (QPieSliceId id, m_slices.keys())
147 m_slices[id].m_percentage = m_slices.value(id).value() / m_total;
148 }
149
107 #include "moc_qpieseries.cpp"
150 #include "moc_qpieseries.cpp"
108
151
109 QTCOMMERCIALCHART_END_NAMESPACE
152 QTCOMMERCIALCHART_END_NAMESPACE
@@ -5,33 +5,62
5 #include <QObject>
5 #include <QObject>
6 #include <QRectF>
6 #include <QRectF>
7 #include <QColor>
7 #include <QColor>
8 #include <QPen>
9 #include <QBrush>
8
10
9 class QGraphicsObject;
11 class QGraphicsObject;
10 QTCOMMERCIALCHART_BEGIN_NAMESPACE
12 QTCOMMERCIALCHART_BEGIN_NAMESPACE
11 class PiePresenter;
13 class PiePresenter;
12 class PieSlice;
14 class PieSlice;
13
15
16 typedef quint64 QPieSliceId;
17
14 class QPieSlice
18 class QPieSlice
15 {
19 {
16 public:
20 public:
17 QPieSlice()
21 QPieSlice()
18 :m_value(0), m_label("<empty>"), m_color(QColor::Invalid), m_isExploded(false) {}
22 :m_id(-1), m_value(0), m_isLabelVisible(true), m_isExploded(false), m_percentage(0) {}
19
23
20 QPieSlice(qreal value, QString label = "<empty>", QColor color = QColor::Invalid, bool exploded = false)
24 QPieSlice(qreal value, QString label = QString(), bool labelVisible = true, bool exploded = false, QPen pen = QPen(), QBrush brush = QBrush())
21 :m_value(value), m_label(label), m_color(color), m_isExploded(exploded) {}
25 :m_id(-1), m_value(value), m_label(label), m_isLabelVisible(labelVisible), m_isExploded(exploded), m_pen(pen), m_brush(brush), m_percentage(0) {}
22 public:
26
27 QPieSliceId id() const { return m_id; }
28
29 void setValue(qreal value) { m_value = value; }
30 qreal value() const { return m_value; }
31
32 void setLabel(QString label) { m_label = label; }
33 QString label() const { return m_label; }
34
35 void setLabelVisible(bool visible) { m_isLabelVisible = visible; }
36 bool isLabelVisible() const { return m_isLabelVisible; }
37
38 void setExploded(bool exploded) { m_isExploded = exploded; }
39 bool isExploded() const { return m_isExploded; }
40
41 void setPen(QPen pen) { m_pen = pen; }
42 QPen pen() const { return m_pen; }
43
44 void setBrush(QBrush brush) { m_brush = brush; }
45 QBrush brush() const { return m_brush; }
46
47 qreal percentage() const { return m_percentage; }
48
49 private:
50
51 // TODO: use private class
52 friend class QPieSeries;
53
54 QPieSliceId m_id;
23 qreal m_value;
55 qreal m_value;
24 QString m_label;
56 QString m_label;
25 QColor m_color; // TODO: should we even define color here?
57 bool m_isLabelVisible;
26 bool m_isExploded;
58 bool m_isExploded;
27 };
28
59
29 class PieChangeSet
60 QPen m_pen;
30 {
61 QBrush m_brush;
31 public:
62
32 QList<int> m_added;
63 qreal m_percentage; // generated content
33 QList<int> m_removed;
34 QList<int> m_changed;
35 };
64 };
36
65
37 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries
66 class QTCOMMERCIALCHART_EXPORT QPieSeries : public QChartSeries
@@ -47,24 +76,38 public:
47 PiePositionBottomRight
76 PiePositionBottomRight
48 };
77 };
49
78
79 class ChangeSet
80 {
81 public:
82 QList<QPieSliceId> m_added;
83 QList<QPieSliceId> m_removed;
84 QList<QPieSliceId> m_changed;
85 };
86
50 public:
87 public:
51 QPieSeries(QObject *parent = 0);
88 QPieSeries(QObject *parent = 0);
52 ~QPieSeries();
89 ~QPieSeries();
53
90
54 public: // from QChartSeries
91 public: // from QChartSeries
55 QChartSeriesType type() const { return QChartSeries::SeriesTypePie; }
92 QChartSeriesType type() const { return QChartSeries::SeriesTypePie; }
56 virtual bool setData(QList<qreal> data);
93 virtual bool setData(QList<qreal> data); // TODO: remove this
57
94
58 public:
95 public:
59 bool set(QList<QPieSlice> slices);
96 // TODO: should we return id/bool or what?
60 bool add(QList<QPieSlice> slices);
97 // TODO: should we prefer passing a modifiable reference?
61 bool add(QPieSlice slice);
98 bool set(const QList<QPieSlice>& slices);
99 bool add(const QList<QPieSlice>& slices);
100 bool add(const QPieSlice& slice);
101 bool update(const QPieSlice& slice);
102 bool remove(QPieSliceId id);
62
103
63 int count() const { return m_slices.count(); }
104 int count() const { return m_slices.count(); }
64
105
65 QList<QPieSlice> slices() const { return m_slices; }
106 QList<QPieSlice> slices() const { return m_slices.values(); }
66 QPieSlice slice(int index) const;
107 QList<QPieSliceId> ids() const { return m_slices.keys(); }
67 bool update(int index, QPieSlice slice);
108 QPieSlice slice(QPieSliceId id) const;
109
110 // TODO: sorting?
68
111
69 // TODO: convenience functions
112 // TODO: convenience functions
70 //void updateValue(int sliceIndex, qreal value);
113 //void updateValue(int sliceIndex, qreal value);
@@ -72,6 +115,11 public:
72 //void updateColor(int sliceIndex, QColor color);
115 //void updateColor(int sliceIndex, QColor color);
73 //void updateExploded(int slizeIndex, bool exploded);
116 //void updateExploded(int slizeIndex, bool exploded);
74
117
118 // TODO: customization
119 // set/get pen/brush
120 // - for label
121 // - for whole pie/slice
122
75 void setSizeFactor(qreal sizeFactor);
123 void setSizeFactor(qreal sizeFactor);
76 qreal sizeFactor() const { return m_sizeFactor; }
124 qreal sizeFactor() const { return m_sizeFactor; }
77
125
@@ -79,17 +127,29 public:
79 PiePosition position() const { return m_position; }
127 PiePosition position() const { return m_position; }
80
128
81 Q_SIGNALS:
129 Q_SIGNALS:
82 void changed(const PieChangeSet& changeSet);
130 void changed(const QPieSeries::ChangeSet& changeSet);
83 void sizeFactorChanged();
131 void sizeFactorChanged();
84 void positionChanged();
132 void positionChanged();
133 //void sliceClicked(QPieSliceId id);
134 //void sliceHoverEnter(QPieSliceId id);
135 //void sliceHoverLeave(QPieSliceId id);
136
137 private:
138 QPieSliceId generateSliceId();
139 void updateDerivativeData();
85
140
86 private:
141 private:
87 Q_DISABLE_COPY(QPieSeries)
142 Q_DISABLE_COPY(QPieSeries)
88 friend class PiePresenter;
143
89 // TODO: use PIML
144 // TODO: use PIML
90 QList<QPieSlice> m_slices;
145 friend class PiePresenter;
146 friend class PieSlice;
147
148 QHash<QPieSliceId, QPieSlice> m_slices;
91 qreal m_sizeFactor;
149 qreal m_sizeFactor;
92 PiePosition m_position;
150 PiePosition m_position;
151 qreal m_total;
152 QPieSliceId m_sliceIdSeed;
93 };
153 };
94
154
95 QTCOMMERCIALCHART_END_NAMESPACE
155 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now