diff --git a/src/piechart/piepresenter.cpp b/src/piechart/piepresenter.cpp index 286bc2c..2ebde05 100644 --- a/src/piechart/piepresenter.cpp +++ b/src/piechart/piepresenter.cpp @@ -14,15 +14,7 @@ PiePresenter::PiePresenter(QGraphicsItem *parent, QPieSeries *series) m_series(series) { Q_ASSERT(series); - connect(series, SIGNAL(changed(const QPieSeries::ChangeSet&)), this, SLOT(handleSeriesChanged(const QPieSeries::ChangeSet&))); - connect(series, SIGNAL(piePositionChanged()), this, SLOT(updateGeometry())); - connect(series, SIGNAL(pieSizeChanged()), this, SLOT(updateGeometry())); - - if (m_series->count()) { - QPieSeries::ChangeSet changeSet; - changeSet.appendAdded(m_series->m_slices); - handleSeriesChanged(changeSet); - } + connect(series, SIGNAL(changed()), this, SLOT(handleSeriesChanged())); // Note: the following does not affect as long as the item does not have anything to paint setZValue(ChartPresenter::PieSeriesZValue); @@ -41,43 +33,38 @@ void PiePresenter::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QW //painter->drawRect(m_debugRect); } -void PiePresenter::handleSeriesChanged(const QPieSeries::ChangeSet& changeSet) +void PiePresenter::handleSeriesChanged() { - //qDebug() << "PiePresenter::handleSeriesChanged()"; - //qDebug() << " added : " << changeSet.added(); - //qDebug() << " changed: " << changeSet.changed(); - //qDebug() << " removed: " << changeSet.removed(); - - foreach (QPieSlice* s, changeSet.added()) - addSlice(s); - - foreach (QPieSlice* s, changeSet.changed()) - updateSlice(s); - - foreach (QPieSlice* s, changeSet.removed()) - deleteSlice(s); + QVector sliceLayout = calculateLayout(); + applyLayout(sliceLayout); + update(); +} - // every change possibly changes the actual pie size - updateGeometry(); +void PiePresenter::handleSliceChanged() +{ + // TODO: optimize don't need to handle all slices + QVector sliceLayout = calculateLayout(); + applyLayout(sliceLayout); + update(); } -void PiePresenter::handleDomainChanged(const Domain& domain) +void PiePresenter::handleDomainChanged(qreal, qreal, qreal, qreal) { // TODO } void PiePresenter::handleGeometryChanged(const QRectF& rect) { - m_rect = rect; prepareGeometryChange(); - updateGeometry(); + m_rect = rect; + QVector sliceLayout = calculateLayout(); + applyLayout(sliceLayout); + update(); } -void PiePresenter::updateGeometry() -{ - if (!m_rect.isValid() || m_rect.isEmpty()) - return; +QVector PiePresenter::calculateLayout() +{ // find pie center coordinates QPointF center; center.setX(m_rect.left() + (m_rect.width() * m_series->pieHorizontalPosition())); @@ -91,66 +78,64 @@ void PiePresenter::updateGeometry() // apply size factor radius *= m_series->pieSize(); - // update slices - if (m_pieCenter != center || m_pieRadius != radius) { - m_pieCenter = center; - m_pieRadius = radius; - //qDebug() << "PiePresenter::updateGeometry()" << m_rect << m_pieCenter << m_pieRadius; - foreach (PieSlice* s, m_slices.values()) { - s->setPieCenterAndRadius(center, radius); - s->updateGeometry(); - s->update(); - } + QVector layout; + foreach (QPieSlice* s, m_series->slices()) { + PieSliceLayout sliceLayout; + sliceLayout.m_data = s; + sliceLayout.m_center = PieSlice::sliceCenter(center, radius, s); + sliceLayout.m_radius = radius; + sliceLayout.m_startAngle = s->startAngle(); + sliceLayout.m_angleSpan = s->m_angleSpan; + layout << sliceLayout; } - update(); + return layout; } -void PiePresenter::addSlice(QPieSlice* sliceData) +void PiePresenter::applyLayout(const QVector &layout) { - //qDebug() << "PiePresenter::addSlice()" << sliceData; - - if (m_slices.keys().contains(sliceData)) { - Q_ASSERT(0); // TODO: how to handle this nicely? - return; - } - - // create slice - PieSlice *slice = new PieSlice(this); - slice->setPieCenterAndRadius(m_pieCenter, m_pieRadius); - slice->updateData(sliceData); - slice->updateGeometry(); - slice->update(); - m_slices.insert(sliceData, slice); - - // connect signals - connect(slice, SIGNAL(clicked()), sliceData, SIGNAL(clicked())); - connect(slice, SIGNAL(hoverEnter()), sliceData, SIGNAL(hoverEnter())); - connect(slice, SIGNAL(hoverLeave()), sliceData, SIGNAL(hoverLeave())); + //if(m_animator) + // m_animator->applyLayout(this,points); + //else + setLayout(layout); } -void PiePresenter::updateSlice(QPieSlice* sliceData) +void PiePresenter::setLayout(const QVector &layout) { - //qDebug() << "PiePresenter::updateSlice()" << sliceData; + foreach (PieSliceLayout l, layout) { + + // find slice + PieSlice *slice = m_slices.value(l.m_data); + if (!slice) { + // add a new slice + slice = new PieSlice(this); + m_slices.insert(l.m_data, slice); + + // connect signals + connect(l.m_data, SIGNAL(changed()), this, SLOT(handleSliceChanged())); + connect(slice, SIGNAL(clicked()), l.m_data, SIGNAL(clicked())); + connect(slice, SIGNAL(hoverEnter()), l.m_data, SIGNAL(hoverEnter())); + connect(slice, SIGNAL(hoverLeave()), l.m_data, SIGNAL(hoverLeave())); + } - if (!m_slices.contains(sliceData)) { - Q_ASSERT(0); // TODO: how to handle this nicely? - return; + // update + slice->setLayout(l); + slice->updateGeometry(); + slice->update(); } - m_slices[sliceData]->updateData(sliceData); -} + // delete slices + foreach (QPieSlice *s, m_slices.keys()) { -void PiePresenter::deleteSlice(QPieSlice* sliceData) -{ - //qDebug() << "PiePresenter::deleteSlice()" << sliceData; + bool found = false; + foreach (PieSliceLayout l, layout) { + if (l.m_data == s) + found = true; + } - if (!m_slices.contains(sliceData)) { - Q_ASSERT(0); // TODO: how to handle this nicely? - return; + if (!found) + delete m_slices.take(s); } - - delete m_slices.take(sliceData); } #include "moc_piepresenter_p.cpp" diff --git a/src/piechart/piepresenter_p.h b/src/piechart/piepresenter_p.h index 5671e3a..082544c 100644 --- a/src/piechart/piepresenter_p.h +++ b/src/piechart/piepresenter_p.h @@ -1,13 +1,13 @@ #ifndef PIEPRESENTER_H #define PIEPRESENTER_H -#include "chartitem_p.h" #include "qpieseries.h" -#include +#include "chartitem_p.h" +#include "pieslice_p.h" class QGraphicsItem; QTCOMMERCIALCHART_BEGIN_NAMESPACE -class PieSlice; +class QPieSlice; class PiePresenter : public QObject, public ChartItem { @@ -23,15 +23,15 @@ public: // from QGraphicsItem void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); public Q_SLOTS: - void handleSeriesChanged(const QPieSeries::ChangeSet& changeSet); - void handleDomainChanged(const Domain& domain); + void handleSeriesChanged(); + void handleSliceChanged(); + void handleDomainChanged(qreal, qreal, qreal, qreal); void handleGeometryChanged(const QRectF& rect); - void updateGeometry(); private: - void addSlice(QPieSlice* sliceData); - void updateSlice(QPieSlice* sliceData); - void deleteSlice(QPieSlice* sliceData); + QVector calculateLayout(); + void applyLayout(const QVector &layout); + void setLayout(const QVector &layout); private: friend class PieSlice; diff --git a/src/piechart/pieslice.cpp b/src/piechart/pieslice.cpp index 7634f59..35b9577 100644 --- a/src/piechart/pieslice.cpp +++ b/src/piechart/pieslice.cpp @@ -22,7 +22,6 @@ QPointF offset(qreal angle, qreal length) PieSlice::PieSlice(QGraphicsItem* parent) :QGraphicsObject(parent), - m_pieRadius(0), m_startAngle(0), m_angleSpan(0), m_isExploded(false), @@ -88,15 +87,15 @@ void PieSlice::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/) emit clicked(); } -void PieSlice::setPieCenterAndRadius(QPointF center, qreal radius) +void PieSlice::setLayout(PieSliceLayout layout) { - m_pieCenter = center; - m_pieRadius = radius; + m_layout = layout; + updateData(layout.m_data); } void PieSlice::updateGeometry() { - if (m_pieRadius <= 0) + if (m_layout.m_radius <= 0) return; prepareGeometryChange(); @@ -104,14 +103,14 @@ void PieSlice::updateGeometry() // update slice path qreal centerAngle; QPointF armStart; - m_slicePath = slicePath(m_pieCenter, m_pieRadius, m_startAngle, m_angleSpan, m_isExploded, m_pieRadius * m_explodeDistanceFactor, ¢erAngle, &armStart); + m_slicePath = slicePath(m_layout.m_center, m_layout.m_radius, m_startAngle, m_angleSpan, ¢erAngle, &armStart); // update text rect m_labelTextRect = labelTextRect(m_labelFont, m_labelText); // update label arm path QPointF labelTextStart; - m_labelArmPath = labelArmPath(armStart, centerAngle, m_pieRadius * m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart); + m_labelArmPath = labelArmPath(armStart, centerAngle, m_layout.m_radius * m_labelArmLengthFactor, m_labelTextRect.width(), &labelTextStart); // update text position m_labelTextRect.moveBottomLeft(labelTextStart); @@ -135,12 +134,21 @@ void PieSlice::updateData(const QPieSlice* sliceData) m_labelFont = sliceData->labelFont(); m_labelArmLengthFactor = sliceData->labelArmLengthFactor(); m_labelArmPen = sliceData->labelArmPen(); +} - updateGeometry(); - update(); +QPointF PieSlice::sliceCenter(QPointF point, qreal radius, QPieSlice *slice) +{ + if (slice->isExploded()) { + qreal centerAngle = slice->startAngle() + (slice->m_angleSpan/2); + qreal len = radius * slice->explodeDistanceFactor(); + qreal dx = qSin(centerAngle*(PI/180)) * len; + qreal dy = -qCos(centerAngle*(PI/180)) * len; + point += QPointF(dx, dy); + } + return point; } -QPainterPath PieSlice::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, bool exploded, qreal explodeDistance, qreal* centerAngle, QPointF* armStart) +QPainterPath PieSlice::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart) { // calculate center angle *centerAngle = startAngle + (angleSpan/2); @@ -148,13 +156,6 @@ QPainterPath PieSlice::slicePath(QPointF center, qreal radius, qreal startAngle, // calculate slice rectangle QRectF rect(center.x()-radius, center.y()-radius, radius*2, radius*2); - // adjust rect for exploding - if (exploded) { - qreal dx = qSin(*centerAngle*(PI/180)) * explodeDistance; - qreal dy = -qCos(*centerAngle*(PI/180)) * explodeDistance; - rect.translate(dx, dy); - } - // slice path // TODO: draw the shape so that it might have a hole in the center QPainterPath path; @@ -164,10 +165,7 @@ QPainterPath PieSlice::slicePath(QPointF center, qreal radius, qreal startAngle, // calculate label arm start point *armStart = center; - if (exploded) - *armStart += offset(*centerAngle, explodeDistance + radius + PIESLICE_LABEL_GAP); - else - *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP); + *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP); return path; } diff --git a/src/piechart/pieslice_p.h b/src/piechart/pieslice_p.h index 760c8c7..783e9ff 100644 --- a/src/piechart/pieslice_p.h +++ b/src/piechart/pieslice_p.h @@ -16,6 +16,16 @@ class PiePresenter; class PieSliceLabel; class QPieSlice; +class PieSliceLayout +{ +public: + QPieSlice* m_data; + QPointF m_center; + qreal m_radius; + qreal m_startAngle; + qreal m_angleSpan; +}; + class PieSlice : public QGraphicsObject { Q_OBJECT @@ -37,19 +47,17 @@ Q_SIGNALS: void hoverEnter(); void hoverLeave(); -public Q_SLOTS: - void setPieCenterAndRadius(QPointF center, qreal radius); +public: + void setLayout(PieSliceLayout layout); void updateGeometry(); void updateData(const QPieSlice *sliceData); - -public: - static QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, bool exploded, qreal explodeDistance, qreal* centerAngle, QPointF* armStart); + static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice); + static QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal* centerAngle, QPointF* armStart); static QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF* textStart); static QRectF labelTextRect(QFont font, QString text); private: - QPointF m_pieCenter; - qreal m_pieRadius; + PieSliceLayout m_layout; QPainterPath m_slicePath; qreal m_startAngle; diff --git a/src/piechart/qpieseries.cpp b/src/piechart/qpieseries.cpp index d2ef8c7..c0f311a 100644 --- a/src/piechart/qpieseries.cpp +++ b/src/piechart/qpieseries.cpp @@ -147,11 +147,9 @@ void QPieSeries::replace(QList slices) */ void QPieSeries::add(QList slices) { - ChangeSet changeSet; foreach (QPieSlice* s, slices) { s->setParent(this); m_slices << s; - changeSet.appendAdded(s); } updateDerivativeData(); @@ -163,7 +161,7 @@ void QPieSeries::add(QList slices) connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave())); } - emit changed(changeSet); + emit changed(); } /*! @@ -208,15 +206,12 @@ void QPieSeries::remove(QPieSlice* slice) Q_ASSERT(0); // TODO: how should this be reported? return; } + emit changed(); - ChangeSet changeSet; - changeSet.appendRemoved(slice); - emit changed(changeSet); + updateDerivativeData(); delete slice; slice = NULL; - - updateDerivativeData(); } /*! @@ -227,13 +222,13 @@ void QPieSeries::clear() if (m_slices.count() == 0) return; - ChangeSet changeSet; foreach (QPieSlice* s, m_slices) { - changeSet.appendRemoved(s); m_slices.removeOne(s); delete s; } - emit changed(changeSet); + + emit changed(); + updateDerivativeData(); } @@ -276,7 +271,7 @@ void QPieSeries::setPiePosition(qreal relativeHorizontalPosition, qreal relative if (m_pieRelativeHorPos != relativeHorizontalPosition || m_pieRelativeVerPos != relativeVerticalPosition) { m_pieRelativeHorPos = relativeHorizontalPosition; m_pieRelativeVerPos = relativeVerticalPosition; - emit piePositionChanged(); + emit changed(); } } @@ -330,7 +325,7 @@ void QPieSeries::setPieSize(qreal relativeSize) if (m_pieRelativeSize != relativeSize) { m_pieRelativeSize = relativeSize; - emit pieSizeChanged(); + emit changed(); } } @@ -429,10 +424,9 @@ qreal QPieSeries::total() const } /*! - \fn void QPieSeries::changed(const QPieSeries::ChangeSet& changeSet) + \fn void QPieSeries::changed() This signal emitted when something has changed in the series. - The \a changeSet contains the details of which slices have been added, changed or removed. \sa QPieSeries::ChangeSet, QPieSlice::changed() */ @@ -461,31 +455,10 @@ qreal QPieSeries::total() const \sa QPieSlice::hoverLeave() */ -/*! - \fn void QPieSeries::pieSizeChanged() - - This signal is emitted when size factor has been changed. - - \sa pieSize(), setPieSize() -*/ - -/*! - \fn void QPieSeries::piePositionChanged() - - This signal is emitted when position of the pie has been changed. - - \sa pieHorizontalPosition(), pieVerticalPosition(), setPiePosition() -*/ - void QPieSeries::sliceChanged() { QPieSlice* slice = qobject_cast(sender()); Q_ASSERT(m_slices.contains(slice)); - - ChangeSet changeSet; - changeSet.appendChanged(slice); - emit changed(changeSet); - updateDerivativeData(); } diff --git a/src/piechart/qpieseries.h b/src/piechart/qpieseries.h index a2f3c5e..5bfb805 100644 --- a/src/piechart/qpieseries.h +++ b/src/piechart/qpieseries.h @@ -97,11 +97,7 @@ Q_SIGNALS: void clicked(QPieSlice* slice); void hoverEnter(QPieSlice* slice); void hoverLeave(QPieSlice* slice); - - void pieSizeChanged(); - void piePositionChanged(); - - void changed(const QPieSeries::ChangeSet& changeSet); // TODO: hide this in PIMPL + void changed(); // TODO: hide this in PIMPL private Q_SLOTS: // TODO: should be private and not visible in the interface at all void sliceChanged();