qpieseries.cpp
517 lines
| 11.0 KiB
| text/x-c
|
CppLexer
|
r142 | #include "qpieseries.h" | ||
|
r203 | #include "qpieslice.h" | ||
|
r142 | #include <QDebug> | ||
QTCOMMERCIALCHART_BEGIN_NAMESPACE | ||||
|
r320 | |||
|
r314 | /*! | ||
|
r320 | \class QPieSeries::ChangeSet | ||
\brief Defines the changes in the series. | ||||
|
r314 | |||
|
r320 | Contains the changes that have occurred in the series. Lists of added, changed and removed slices. | ||
|
r314 | |||
|
r320 | \sa QPieSeries::changed() | ||
|
r314 | */ | ||
/*! | ||||
|
r320 | \internal | ||
|
r314 | */ | ||
|
r203 | void QPieSeries::ChangeSet::appendAdded(QPieSlice* slice) | ||
|
r142 | { | ||
|
r203 | if (!m_added.contains(slice)) | ||
m_added << slice; | ||||
|
r142 | } | ||
|
r320 | /*! | ||
\internal | ||||
*/ | ||||
|
r289 | void QPieSeries::ChangeSet::appendAdded(QList<QPieSlice*> slices) | ||
{ | ||||
foreach (QPieSlice* s, slices) | ||||
appendAdded(s); | ||||
} | ||||
|
r320 | /*! | ||
\internal | ||||
*/ | ||||
|
r203 | void QPieSeries::ChangeSet::appendChanged(QPieSlice* slice) | ||
|
r142 | { | ||
|
r203 | if (!m_changed.contains(slice)) | ||
m_changed << slice; | ||||
} | ||||
|
r142 | |||
|
r320 | /*! | ||
\internal | ||||
*/ | ||||
|
r203 | void QPieSeries::ChangeSet::appendRemoved(QPieSlice* slice) | ||
{ | ||||
if (!m_removed.contains(slice)) | ||||
m_removed << slice; | ||||
|
r142 | } | ||
|
r314 | /*! | ||
Returns a list of slices that have been added to the series. | ||||
\sa QPieSeries::changed() | ||||
*/ | ||||
|
r203 | QList<QPieSlice*> QPieSeries::ChangeSet::added() const | ||
|
r142 | { | ||
|
r203 | return m_added; | ||
|
r163 | } | ||
|
r314 | /*! | ||
Returns a list of slices that have been changed in the series. | ||||
\sa QPieSeries::changed() | ||||
*/ | ||||
|
r203 | QList<QPieSlice*> QPieSeries::ChangeSet::changed() const | ||
|
r163 | { | ||
|
r203 | return m_changed; | ||
} | ||||
|
r163 | |||
|
r314 | /*! | ||
Returns a list of slices that have been removed from the series. | ||||
\sa QPieSeries::changed() | ||||
*/ | ||||
|
r203 | QList<QPieSlice*> QPieSeries::ChangeSet::removed() const | ||
{ | ||||
return m_removed; | ||||
} | ||||
|
r157 | |||
|
r314 | |||
/*! | ||||
Returns true if there are no added/changed or removed slices in the change set. | ||||
*/ | ||||
|
r203 | bool QPieSeries::ChangeSet::isEmpty() const | ||
{ | ||||
if (m_added.count() || m_changed.count() || m_removed.count()) | ||||
return false; | ||||
return true; | ||||
} | ||||
|
r157 | |||
|
r320 | /*! | ||
\enum QPieSeries::PiePosition | ||||
This enum describes pie position within its bounding rectangle | ||||
\value PiePositionMaximized | ||||
\value PiePositionTopLeft | ||||
\value PiePositionTopRight | ||||
\value PiePositionBottomLeft | ||||
\value PiePositionBottomRight | ||||
*/ | ||||
/*! | ||||
\class QPieSeries | ||||
\brief Pie series API for QtCommercial Charts | ||||
The pie series defines a pie chart which consists of pie slices which are QPieSlice objects. | ||||
The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices. | ||||
|
r386 | The actual slice size is determined by that relative value. | ||
|
r320 | |||
|
r386 | By default the pie is defined as a full pie but it can be a partial pie. | ||
|
r320 | This can be done by setting a starting angle and angle span to the series. | ||
*/ | ||||
|
r314 | /*! | ||
Constructs a series object which is a child of \a parent. | ||||
*/ | ||||
|
r203 | QPieSeries::QPieSeries(QObject *parent) : | ||
|
r360 | QSeries(parent), | ||
|
r203 | m_sizeFactor(1.0), | ||
|
r437 | m_position(PiePositionCenter), | ||
m_sizePolicy(PieSizePolicyMaximized), | ||||
|
r203 | m_pieStartAngle(0), | ||
|
r437 | m_pieEndAngle(360) | ||
|
r203 | { | ||
|
r157 | |||
|
r203 | } | ||
|
r174 | |||
|
r314 | /*! | ||
Destroys the object. Note that adding series to QChart transfers the ownership to the chart. | ||||
*/ | ||||
|
r203 | QPieSeries::~QPieSeries() | ||
{ | ||||
|
r204 | |||
|
r203 | } | ||
|
r314 | /*! | ||
|
r320 | Returns QChartSeries::SeriesTypePie. | ||
|
r314 | */ | ||
|
r360 | QSeries::QSeriesType QPieSeries::type() const | ||
|
r314 | { | ||
|
r360 | return QSeries::SeriesTypePie; | ||
|
r314 | } | ||
/*! | ||||
|
r354 | Sets an array of \a slices to the series replacing the existing slices. | ||
|
r314 | Slice ownership is passed to the series. | ||
*/ | ||||
|
r354 | void QPieSeries::replace(QList<QPieSlice*> slices) | ||
|
r142 | { | ||
|
r203 | clear(); | ||
add(slices); | ||||
} | ||||
|
r163 | |||
|
r314 | /*! | ||
|
r345 | Adds an array of \a slices to the series. | ||
|
r314 | Slice ownership is passed to the series. | ||
*/ | ||||
|
r203 | void QPieSeries::add(QList<QPieSlice*> slices) | ||
{ | ||||
|
r174 | ChangeSet changeSet; | ||
|
r203 | foreach (QPieSlice* s, slices) { | ||
s->setParent(this); | ||||
m_slices << s; | ||||
changeSet.appendAdded(s); | ||||
|
r174 | } | ||
|
r157 | |||
|
r174 | updateDerivativeData(); | ||
|
r203 | foreach (QPieSlice* s, slices) { | ||
connect(s, SIGNAL(changed()), this, SLOT(sliceChanged())); | ||||
connect(s, SIGNAL(clicked()), this, SLOT(sliceClicked())); | ||||
connect(s, SIGNAL(hoverEnter()), this, SLOT(sliceHoverEnter())); | ||||
connect(s, SIGNAL(hoverLeave()), this, SLOT(sliceHoverLeave())); | ||||
} | ||||
emit changed(changeSet); | ||||
|
r142 | } | ||
|
r314 | /*! | ||
Adds a single \a slice to the series. | ||||
Slice ownership is passed to the series. | ||||
*/ | ||||
|
r203 | void QPieSeries::add(QPieSlice* slice) | ||
|
r142 | { | ||
|
r203 | add(QList<QPieSlice*>() << slice); | ||
|
r142 | } | ||
|
r415 | /*! | ||
Adds a single \a slice to the series and returns a reference to the series. | ||||
Slice ownership is passed to the series. | ||||
*/ | ||||
|
r406 | QPieSeries& QPieSeries::operator << (QPieSlice* slice) | ||
{ | ||||
add(slice); | ||||
return *this; | ||||
} | ||||
|
r314 | |||
/*! | ||||
Adds a single slice to the series with give \a value and \a name. | ||||
Slice ownership is passed to the series. | ||||
*/ | ||||
|
r203 | QPieSlice* QPieSeries::add(qreal value, QString name) | ||
|
r142 | { | ||
|
r203 | QPieSlice* slice = new QPieSlice(value, name); | ||
add(slice); | ||||
return slice; | ||||
} | ||||
|
r174 | |||
|
r314 | /*! | ||
Removes a single \a slice from the series and deletes the slice. | ||||
|
r320 | |||
|
r314 | Do not reference this pointer after this call. | ||
*/ | ||||
|
r203 | void QPieSeries::remove(QPieSlice* slice) | ||
{ | ||||
if (!m_slices.removeOne(slice)) { | ||||
|
r289 | Q_ASSERT(0); // TODO: how should this be reported? | ||
|
r203 | return; | ||
} | ||||
|
r174 | |||
ChangeSet changeSet; | ||||
|
r203 | changeSet.appendRemoved(slice); | ||
|
r174 | emit changed(changeSet); | ||
|
r203 | delete slice; | ||
slice = NULL; | ||||
updateDerivativeData(); | ||||
|
r142 | } | ||
|
r314 | /*! | ||
Clears all slices from the series. | ||||
*/ | ||||
|
r203 | void QPieSeries::clear() | ||
|
r142 | { | ||
|
r203 | if (m_slices.count() == 0) | ||
return; | ||||
|
r174 | |||
ChangeSet changeSet; | ||||
|
r203 | foreach (QPieSlice* s, m_slices) { | ||
changeSet.appendRemoved(s); | ||||
m_slices.removeOne(s); | ||||
delete s; | ||||
} | ||||
|
r174 | emit changed(changeSet); | ||
|
r203 | updateDerivativeData(); | ||
|
r142 | } | ||
|
r314 | /*! | ||
Counts the number of the slices in this series. | ||||
*/ | ||||
int QPieSeries::count() const | ||||
{ | ||||
return m_slices.count(); | ||||
} | ||||
/*! | ||||
Returns a list of slices that belong to this series. | ||||
*/ | ||||
QList<QPieSlice*> QPieSeries::slices() const | ||||
{ | ||||
return m_slices; | ||||
} | ||||
/*! | ||||
Sets the size \a factor of the pie. 1.0 is the default value. | ||||
Note that the pie will not grow beyond its absolute maximum size. | ||||
In practice its use is to make the pie appear smaller. | ||||
\sa sizeFactor() | ||||
*/ | ||||
|
r142 | void QPieSeries::setSizeFactor(qreal factor) | ||
{ | ||||
|
r163 | if (factor < 0.0) | ||
return; | ||||
if (m_sizeFactor != factor) { | ||||
|
r142 | m_sizeFactor = factor; | ||
|
r163 | emit sizeFactorChanged(); | ||
} | ||||
|
r142 | } | ||
|
r314 | /*! | ||
Gets the size factor of the pie. | ||||
\sa setSizeFactor() | ||||
*/ | ||||
qreal QPieSeries::sizeFactor() const | ||||
{ | ||||
return m_sizeFactor; | ||||
} | ||||
/*! | ||||
Sets the \a position of the pie within its bounding rectangle. | ||||
\sa PiePosition, position() | ||||
*/ | ||||
|
r142 | void QPieSeries::setPosition(PiePosition position) | ||
{ | ||||
|
r437 | // TODO: sanity check | ||
|
r163 | if (m_position != position) { | ||
m_position = position; | ||||
emit positionChanged(); | ||||
} | ||||
|
r142 | } | ||
|
r314 | /*! | ||
Gets the position of the pie within its bounding rectangle. | ||||
\sa PiePosition, setPosition() | ||||
*/ | ||||
QPieSeries::PiePosition QPieSeries::position() const | ||||
{ | ||||
return m_position; | ||||
} | ||||
/*! | ||||
|
r437 | Sets the \a sizePolicy of the pie. | ||
\sa PieSizePolicy, sizePolicy() | ||||
*/ | ||||
void QPieSeries::setSizePolicy(PieSizePolicy sizePolicy) | ||||
{ | ||||
// TODO: sanity check | ||||
if (m_sizePolicy != sizePolicy) { | ||||
m_sizePolicy = sizePolicy; | ||||
emit sizePolicyChanged(); | ||||
} | ||||
} | ||||
|
r314 | |||
|
r437 | /*! | ||
Gets the size policy of the pie. | ||||
\sa PieSizePolicy, setSizePolicy() | ||||
|
r314 | */ | ||
|
r437 | QPieSeries::PieSizePolicy QPieSeries::sizePolicy() const | ||
|
r203 | { | ||
|
r437 | return m_sizePolicy; | ||
} | ||||
void QPieSeries::setStartAngle(qreal startAngle) | ||||
{ | ||||
if (startAngle >= 0 && startAngle <= 360 && startAngle != m_pieStartAngle && startAngle <= m_pieEndAngle) { | ||||
|
r203 | m_pieStartAngle = startAngle; | ||
updateDerivativeData(); | ||||
} | ||||
} | ||||
|
r437 | qreal QPieSeries::startAngle() const | ||
{ | ||||
return m_pieStartAngle; | ||||
} | ||||
void QPieSeries::setEndAngle(qreal endAngle) | ||||
{ | ||||
if (endAngle >= 0 && endAngle <= 360 && endAngle != m_pieEndAngle && endAngle >= m_pieStartAngle) { | ||||
m_pieEndAngle = endAngle; | ||||
updateDerivativeData(); | ||||
} | ||||
} | ||||
qreal QPieSeries::endAngle() const | ||||
{ | ||||
return m_pieEndAngle; | ||||
} | ||||
|
r314 | /*! | ||
Sets the all the slice labels \a visible or invisible. | ||||
\sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible() | ||||
*/ | ||||
|
r203 | void QPieSeries::setLabelsVisible(bool visible) | ||
{ | ||||
foreach (QPieSlice* s, m_slices) | ||||
s->setLabelVisible(visible); | ||||
} | ||||
|
r406 | /*! | ||
Returns the sum of all slice values in this series. | ||||
\sa QPieSlice::value(), QPieSlice::setValue() | ||||
*/ | ||||
qreal QPieSeries::total() const | ||||
{ | ||||
return m_total; | ||||
} | ||||
|
r314 | /*! | ||
\fn void QPieSeries::changed(const QPieSeries::ChangeSet& changeSet) | ||||
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() | ||||
*/ | ||||
/*! | ||||
\fn void QPieSeries::clicked(QPieSlice* slice) | ||||
This signal is emitted when a \a slice has been clicked. | ||||
\sa QPieSlice::clicked() | ||||
*/ | ||||
/*! | ||||
\fn void QPieSeries::hoverEnter(QPieSlice* slice) | ||||
This signal is emitted when user has hovered over a \a slice. | ||||
\sa QPieSlice::hoverEnter() | ||||
*/ | ||||
/*! | ||||
\fn void QPieSeries::hoverLeave(QPieSlice* slice) | ||||
This signal is emitted when user has hovered away from a \a slice. | ||||
\sa QPieSlice::hoverLeave() | ||||
*/ | ||||
/*! | ||||
\fn void QPieSeries::sizeFactorChanged() | ||||
This signal is emitted when size factor has been changed. | ||||
\sa sizeFactor(), setSizeFactor() | ||||
*/ | ||||
/*! | ||||
\fn void QPieSeries::positionChanged() | ||||
This signal is emitted when position of the pie has been changed. | ||||
\sa position(), setPosition() | ||||
*/ | ||||
|
r203 | void QPieSeries::sliceChanged() | ||
{ | ||||
QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); | ||||
Q_ASSERT(m_slices.contains(slice)); | ||||
ChangeSet changeSet; | ||||
changeSet.appendChanged(slice); | ||||
emit changed(changeSet); | ||||
updateDerivativeData(); | ||||
} | ||||
void QPieSeries::sliceClicked() | ||||
{ | ||||
QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); | ||||
Q_ASSERT(m_slices.contains(slice)); | ||||
emit clicked(slice); | ||||
} | ||||
void QPieSeries::sliceHoverEnter() | ||||
{ | ||||
QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); | ||||
Q_ASSERT(m_slices.contains(slice)); | ||||
emit hoverEnter(slice); | ||||
} | ||||
void QPieSeries::sliceHoverLeave() | ||||
|
r174 | { | ||
|
r203 | QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); | ||
Q_ASSERT(m_slices.contains(slice)); | ||||
emit hoverLeave(slice); | ||||
} | ||||
|
r174 | void QPieSeries::updateDerivativeData() | ||
{ | ||||
m_total = 0; | ||||
|
r203 | // nothing to do? | ||
if (m_slices.count() == 0) | ||||
return; | ||||
// calculate total | ||||
foreach (QPieSlice* s, m_slices) | ||||
m_total += s->value(); | ||||
// we must have some values | ||||
|
r406 | if (m_total == 0) { | ||
qDebug() << "QPieSeries::updateDerivativeData() total == 0"; | ||||
Q_ASSERT(m_total > 0); // TODO: is this the correct way to handle this? | ||||
} | ||||
|
r174 | |||
|
r203 | // update slice attributes | ||
qreal sliceAngle = m_pieStartAngle; | ||||
|
r437 | qreal pieSpan = m_pieEndAngle - m_pieStartAngle; | ||
|
r203 | foreach (QPieSlice* s, m_slices) { | ||
bool changed = false; | ||||
qreal percentage = s->value() / m_total; | ||||
if (s->m_percentage != percentage) { | ||||
s->m_percentage = percentage; | ||||
changed = true; | ||||
} | ||||
|
r437 | qreal sliceSpan = pieSpan * percentage; | ||
|
r289 | if (s->m_angleSpan != sliceSpan) { | ||
s->m_angleSpan = sliceSpan; | ||||
|
r203 | changed = true; | ||
} | ||||
|
r355 | if (s->m_startAngle != sliceAngle) { | ||
s->m_startAngle = sliceAngle; | ||||
|
r203 | changed = true; | ||
} | ||||
sliceAngle += sliceSpan; | ||||
if (changed) | ||||
emit s->changed(); | ||||
} | ||||
|
r174 | } | ||
|
r142 | #include "moc_qpieseries.cpp" | ||
QTCOMMERCIALCHART_END_NAMESPACE | ||||