qpieseries.cpp
562 lines
| 12.9 KiB
| text/x-c
|
CppLexer
Jani Honkonen
|
r142 | #include "qpieseries.h" | ||
Jani Honkonen
|
r203 | #include "qpieslice.h" | ||
Jani Honkonen
|
r142 | #include <QDebug> | ||
QTCOMMERCIALCHART_BEGIN_NAMESPACE | ||||
Jani Honkonen
|
r320 | |||
Jani Honkonen
|
r314 | /*! | ||
Jani Honkonen
|
r320 | \class QPieSeries::ChangeSet | ||
\brief Defines the changes in the series. | ||||
Jani Honkonen
|
r314 | |||
Jani Honkonen
|
r320 | Contains the changes that have occurred in the series. Lists of added, changed and removed slices. | ||
Jani Honkonen
|
r314 | |||
Jani Honkonen
|
r320 | \sa QPieSeries::changed() | ||
Jani Honkonen
|
r314 | */ | ||
/*! | ||||
Jani Honkonen
|
r320 | \internal | ||
Jani Honkonen
|
r314 | */ | ||
Jani Honkonen
|
r203 | void QPieSeries::ChangeSet::appendAdded(QPieSlice* slice) | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r203 | if (!m_added.contains(slice)) | ||
m_added << slice; | ||||
Jani Honkonen
|
r142 | } | ||
Jani Honkonen
|
r320 | /*! | ||
\internal | ||||
*/ | ||||
Jani Honkonen
|
r289 | void QPieSeries::ChangeSet::appendAdded(QList<QPieSlice*> slices) | ||
{ | ||||
foreach (QPieSlice* s, slices) | ||||
appendAdded(s); | ||||
} | ||||
Jani Honkonen
|
r320 | /*! | ||
\internal | ||||
*/ | ||||
Jani Honkonen
|
r203 | void QPieSeries::ChangeSet::appendChanged(QPieSlice* slice) | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r203 | if (!m_changed.contains(slice)) | ||
m_changed << slice; | ||||
} | ||||
Jani Honkonen
|
r142 | |||
Jani Honkonen
|
r320 | /*! | ||
\internal | ||||
*/ | ||||
Jani Honkonen
|
r203 | void QPieSeries::ChangeSet::appendRemoved(QPieSlice* slice) | ||
{ | ||||
if (!m_removed.contains(slice)) | ||||
m_removed << slice; | ||||
Jani Honkonen
|
r142 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Returns a list of slices that have been added to the series. | ||||
\sa QPieSeries::changed() | ||||
*/ | ||||
Jani Honkonen
|
r203 | QList<QPieSlice*> QPieSeries::ChangeSet::added() const | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r203 | return m_added; | ||
Jani Honkonen
|
r163 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Returns a list of slices that have been changed in the series. | ||||
\sa QPieSeries::changed() | ||||
*/ | ||||
Jani Honkonen
|
r203 | QList<QPieSlice*> QPieSeries::ChangeSet::changed() const | ||
Jani Honkonen
|
r163 | { | ||
Jani Honkonen
|
r203 | return m_changed; | ||
} | ||||
Jani Honkonen
|
r163 | |||
Jani Honkonen
|
r314 | /*! | ||
Returns a list of slices that have been removed from the series. | ||||
\sa QPieSeries::changed() | ||||
*/ | ||||
Jani Honkonen
|
r203 | QList<QPieSlice*> QPieSeries::ChangeSet::removed() const | ||
{ | ||||
return m_removed; | ||||
} | ||||
Jani Honkonen
|
r157 | |||
Jani Honkonen
|
r314 | |||
/*! | ||||
Returns true if there are no added/changed or removed slices in the change set. | ||||
*/ | ||||
Jani Honkonen
|
r203 | bool QPieSeries::ChangeSet::isEmpty() const | ||
{ | ||||
if (m_added.count() || m_changed.count() || m_removed.count()) | ||||
return false; | ||||
return true; | ||||
} | ||||
Jani Honkonen
|
r157 | |||
Jani Honkonen
|
r320 | /*! | ||
\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. | ||||
Jani Honkonen
|
r386 | The actual slice size is determined by that relative value. | ||
Jani Honkonen
|
r320 | |||
Jani Honkonen
|
r386 | By default the pie is defined as a full pie but it can be a partial pie. | ||
Jani Honkonen
|
r320 | This can be done by setting a starting angle and angle span to the series. | ||
*/ | ||||
Jani Honkonen
|
r314 | /*! | ||
Constructs a series object which is a child of \a parent. | ||||
*/ | ||||
Jani Honkonen
|
r203 | QPieSeries::QPieSeries(QObject *parent) : | ||
Michal Klocek
|
r360 | QSeries(parent), | ||
Jani Honkonen
|
r454 | m_hPositionFactor(0.5), | ||
m_vPositionFactor(0.5), | ||||
m_pieSizeFactor(0.7), | ||||
Jani Honkonen
|
r203 | m_pieStartAngle(0), | ||
Jani Honkonen
|
r454 | m_pieEndAngle(360), | ||
m_total(0) | ||||
Jani Honkonen
|
r203 | { | ||
Jani Honkonen
|
r157 | |||
Jani Honkonen
|
r203 | } | ||
Jani Honkonen
|
r174 | |||
Jani Honkonen
|
r314 | /*! | ||
Destroys the object. Note that adding series to QChart transfers the ownership to the chart. | ||||
*/ | ||||
Jani Honkonen
|
r203 | QPieSeries::~QPieSeries() | ||
{ | ||||
Jani Honkonen
|
r204 | |||
Jani Honkonen
|
r203 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Jani Honkonen
|
r320 | Returns QChartSeries::SeriesTypePie. | ||
Jani Honkonen
|
r314 | */ | ||
Michal Klocek
|
r360 | QSeries::QSeriesType QPieSeries::type() const | ||
Jani Honkonen
|
r314 | { | ||
Michal Klocek
|
r360 | return QSeries::SeriesTypePie; | ||
Jani Honkonen
|
r314 | } | ||
/*! | ||||
Jani Honkonen
|
r354 | Sets an array of \a slices to the series replacing the existing slices. | ||
Jani Honkonen
|
r314 | Slice ownership is passed to the series. | ||
*/ | ||||
Jani Honkonen
|
r354 | void QPieSeries::replace(QList<QPieSlice*> slices) | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r203 | clear(); | ||
add(slices); | ||||
} | ||||
Jani Honkonen
|
r163 | |||
Jani Honkonen
|
r314 | /*! | ||
Jani Honkonen
|
r345 | Adds an array of \a slices to the series. | ||
Jani Honkonen
|
r314 | Slice ownership is passed to the series. | ||
*/ | ||||
Jani Honkonen
|
r203 | void QPieSeries::add(QList<QPieSlice*> slices) | ||
{ | ||||
Jani Honkonen
|
r174 | ChangeSet changeSet; | ||
Jani Honkonen
|
r203 | foreach (QPieSlice* s, slices) { | ||
s->setParent(this); | ||||
m_slices << s; | ||||
changeSet.appendAdded(s); | ||||
Jani Honkonen
|
r174 | } | ||
Jani Honkonen
|
r157 | |||
Jani Honkonen
|
r174 | updateDerivativeData(); | ||
Jani Honkonen
|
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); | ||||
Jani Honkonen
|
r142 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Adds a single \a slice to the series. | ||||
Slice ownership is passed to the series. | ||||
*/ | ||||
Jani Honkonen
|
r203 | void QPieSeries::add(QPieSlice* slice) | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r203 | add(QList<QPieSlice*>() << slice); | ||
Jani Honkonen
|
r142 | } | ||
Jani Honkonen
|
r415 | /*! | ||
Adds a single \a slice to the series and returns a reference to the series. | ||||
Slice ownership is passed to the series. | ||||
*/ | ||||
Jani Honkonen
|
r406 | QPieSeries& QPieSeries::operator << (QPieSlice* slice) | ||
{ | ||||
add(slice); | ||||
return *this; | ||||
} | ||||
Jani Honkonen
|
r314 | |||
/*! | ||||
Adds a single slice to the series with give \a value and \a name. | ||||
Slice ownership is passed to the series. | ||||
*/ | ||||
Jani Honkonen
|
r203 | QPieSlice* QPieSeries::add(qreal value, QString name) | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r203 | QPieSlice* slice = new QPieSlice(value, name); | ||
add(slice); | ||||
return slice; | ||||
} | ||||
Jani Honkonen
|
r174 | |||
Jani Honkonen
|
r314 | /*! | ||
Removes a single \a slice from the series and deletes the slice. | ||||
Jani Honkonen
|
r320 | |||
Jani Honkonen
|
r314 | Do not reference this pointer after this call. | ||
*/ | ||||
Jani Honkonen
|
r203 | void QPieSeries::remove(QPieSlice* slice) | ||
{ | ||||
if (!m_slices.removeOne(slice)) { | ||||
Jani Honkonen
|
r289 | Q_ASSERT(0); // TODO: how should this be reported? | ||
Jani Honkonen
|
r203 | return; | ||
} | ||||
Jani Honkonen
|
r174 | |||
ChangeSet changeSet; | ||||
Jani Honkonen
|
r203 | changeSet.appendRemoved(slice); | ||
Jani Honkonen
|
r174 | emit changed(changeSet); | ||
Jani Honkonen
|
r203 | delete slice; | ||
slice = NULL; | ||||
updateDerivativeData(); | ||||
Jani Honkonen
|
r142 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Clears all slices from the series. | ||||
*/ | ||||
Jani Honkonen
|
r203 | void QPieSeries::clear() | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r203 | if (m_slices.count() == 0) | ||
return; | ||||
Jani Honkonen
|
r174 | |||
ChangeSet changeSet; | ||||
Jani Honkonen
|
r203 | foreach (QPieSlice* s, m_slices) { | ||
changeSet.appendRemoved(s); | ||||
m_slices.removeOne(s); | ||||
delete s; | ||||
} | ||||
Jani Honkonen
|
r174 | emit changed(changeSet); | ||
Jani Honkonen
|
r203 | updateDerivativeData(); | ||
Jani Honkonen
|
r142 | } | ||
Jani Honkonen
|
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; | ||||
} | ||||
/*! | ||||
Jani Honkonen
|
r454 | Sets the center position of the pie by \a horizontalFactor and \a verticalFactor. | ||
The factors are relative to the chart rectangle where: | ||||
\a horizontalFactor 0.0 means the absolute left. | ||||
\a horizontalFactor 1.0 means the absolute right. | ||||
\a verticalFactor 0.0 means the absolute top. | ||||
\a verticalFactor 1.0 means the absolute bottom. | ||||
By default \a horizontalFactor and \a verticalFactor are 0.5 which puts the pie in the middle of the chart rectangle. | ||||
\sa horizontalPositionFactor(), verticalPositionFactor(), setSizeFactor() | ||||
Jani Honkonen
|
r314 | */ | ||
Jani Honkonen
|
r454 | void QPieSeries::setPositionFactors(qreal horizontalFactor, qreal verticalFactor) | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r454 | if (horizontalFactor < 0.0 || horizontalFactor > 1.0 || verticalFactor < 0.0 || verticalFactor > 1.0) | ||
Jani Honkonen
|
r163 | return; | ||
Jani Honkonen
|
r454 | if (m_hPositionFactor != horizontalFactor || m_vPositionFactor != verticalFactor) { | ||
m_hPositionFactor = horizontalFactor; | ||||
m_vPositionFactor = verticalFactor; | ||||
emit positionChanged(); | ||||
Jani Honkonen
|
r163 | } | ||
Jani Honkonen
|
r142 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Jani Honkonen
|
r454 | Gets the horizontal position factor of the pie. | ||
Jani Honkonen
|
r314 | |||
Jani Honkonen
|
r454 | The factors are relative to the chart rectangle where: | ||
Horizontal factor 0.0 means the absolute left. | ||||
Horizontal factor 1.0 means the absolute right. | ||||
By default horizontal factor is 0.5 which puts the pie in the horizontal middle of the chart rectangle. | ||||
\sa setPositionFactors(), verticalPositionFactor(), setSizeFactor() | ||||
Jani Honkonen
|
r314 | */ | ||
Jani Honkonen
|
r454 | qreal QPieSeries::horizontalPositionFactor() const | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r454 | return m_hPositionFactor; | ||
Jani Honkonen
|
r142 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Jani Honkonen
|
r454 | Gets the vertical position factor of the pie. | ||
The factors are relative to the chart rectangle where: | ||||
Vertical factor 0.0 means the absolute top. | ||||
Vertical factor 1.0 means the absolute bottom. | ||||
By default vertical factor is 0.5 which puts the pie in the vertical middle of the chart rectangle. | ||||
\sa setPositionFactors(), horizontalPositionFactor(), setSizeFactor() | ||||
Jani Honkonen
|
r314 | */ | ||
Jani Honkonen
|
r454 | qreal QPieSeries::verticalPositionFactor() const | ||
Jani Honkonen
|
r314 | { | ||
Jani Honkonen
|
r454 | return m_vPositionFactor; | ||
Jani Honkonen
|
r314 | } | ||
/*! | ||||
Jani Honkonen
|
r454 | Sets the size \a sizeFactor of the pie. | ||
The size factor is defined so that the 1.0 is the maximum that can fit the given chart rectangle. | ||||
Default value is 0.7. | ||||
\sa sizeFactor(), setPositionFactors(), verticalPositionFactor(), horizontalPositionFactor() | ||||
Jani Honkonen
|
r437 | */ | ||
Jani Honkonen
|
r454 | void QPieSeries::setSizeFactor(qreal sizeFactor) | ||
Jani Honkonen
|
r437 | { | ||
Jani Honkonen
|
r454 | if (sizeFactor < 0.0) | ||
return; | ||||
if (m_pieSizeFactor != sizeFactor) { | ||||
m_pieSizeFactor = sizeFactor; | ||||
emit sizeFactorChanged(); | ||||
Jani Honkonen
|
r437 | } | ||
} | ||||
Jani Honkonen
|
r314 | |||
Jani Honkonen
|
r437 | /*! | ||
Jani Honkonen
|
r454 | Gets the size factor of the pie. | ||
The size factor is defined so that the 1.0 is the maximum that can fit the given chart rectangle. | ||||
Default value is 0.7. | ||||
\sa setSizeFactor(), setPositionFactors(), verticalPositionFactor(), horizontalPositionFactor() | ||||
Jani Honkonen
|
r314 | */ | ||
Jani Honkonen
|
r454 | qreal QPieSeries::sizeFactor() const | ||
Jani Honkonen
|
r203 | { | ||
Jani Honkonen
|
r454 | return m_pieSizeFactor; | ||
Jani Honkonen
|
r437 | } | ||
Jani Honkonen
|
r454 | /*! | ||
Sets the end angle of the pie. | ||||
Full pie is 360 degrees where 0 degrees is at 12 a'clock. | ||||
\a startAngle must be less than end angle. Default value is 0. | ||||
\sa startAngle(), endAngle(), setEndAngle() | ||||
*/ | ||||
Jani Honkonen
|
r437 | void QPieSeries::setStartAngle(qreal startAngle) | ||
{ | ||||
if (startAngle >= 0 && startAngle <= 360 && startAngle != m_pieStartAngle && startAngle <= m_pieEndAngle) { | ||||
Jani Honkonen
|
r203 | m_pieStartAngle = startAngle; | ||
updateDerivativeData(); | ||||
} | ||||
} | ||||
Jani Honkonen
|
r454 | /*! | ||
Gets the start angle of the pie. | ||||
Full pie is 360 degrees where 0 degrees is at 12 a'clock. Default value is 360. | ||||
\sa setStartAngle(), endAngle(), setEndAngle() | ||||
*/ | ||||
Jani Honkonen
|
r437 | qreal QPieSeries::startAngle() const | ||
{ | ||||
return m_pieStartAngle; | ||||
} | ||||
Jani Honkonen
|
r454 | /*! | ||
Sets the end angle of the pie. | ||||
Full pie is 360 degrees where 0 degrees is at 12 a'clock. | ||||
\a endAngle must be greater than start angle. | ||||
\sa endAngle(), startAngle(), setStartAngle() | ||||
*/ | ||||
Jani Honkonen
|
r437 | void QPieSeries::setEndAngle(qreal endAngle) | ||
{ | ||||
if (endAngle >= 0 && endAngle <= 360 && endAngle != m_pieEndAngle && endAngle >= m_pieStartAngle) { | ||||
m_pieEndAngle = endAngle; | ||||
updateDerivativeData(); | ||||
} | ||||
} | ||||
Jani Honkonen
|
r454 | /*! | ||
Returns the end angle of the pie. | ||||
Full pie is 360 degrees where 0 degrees is at 12 a'clock. | ||||
\sa setEndAngle(), startAngle(), setStartAngle() | ||||
*/ | ||||
Jani Honkonen
|
r437 | qreal QPieSeries::endAngle() const | ||
{ | ||||
return m_pieEndAngle; | ||||
} | ||||
Jani Honkonen
|
r314 | /*! | ||
Sets the all the slice labels \a visible or invisible. | ||||
\sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible() | ||||
*/ | ||||
Jani Honkonen
|
r203 | void QPieSeries::setLabelsVisible(bool visible) | ||
{ | ||||
foreach (QPieSlice* s, m_slices) | ||||
s->setLabelVisible(visible); | ||||
} | ||||
Jani Honkonen
|
r406 | /*! | ||
Returns the sum of all slice values in this series. | ||||
\sa QPieSlice::value(), QPieSlice::setValue() | ||||
*/ | ||||
qreal QPieSeries::total() const | ||||
{ | ||||
return m_total; | ||||
} | ||||
Jani Honkonen
|
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. | ||||
Jani Honkonen
|
r454 | \sa horizontalPositionFactor(), verticalPositionFactor(), setPositionFactors() | ||
Jani Honkonen
|
r314 | */ | ||
Jani Honkonen
|
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() | ||||
Jani Honkonen
|
r174 | { | ||
Jani Honkonen
|
r203 | QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); | ||
Q_ASSERT(m_slices.contains(slice)); | ||||
emit hoverLeave(slice); | ||||
} | ||||
Jani Honkonen
|
r174 | void QPieSeries::updateDerivativeData() | ||
{ | ||||
m_total = 0; | ||||
Jani Honkonen
|
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 | ||||
Jani Honkonen
|
r406 | if (m_total == 0) { | ||
qDebug() << "QPieSeries::updateDerivativeData() total == 0"; | ||||
Q_ASSERT(m_total > 0); // TODO: is this the correct way to handle this? | ||||
} | ||||
Jani Honkonen
|
r174 | |||
Jani Honkonen
|
r203 | // update slice attributes | ||
qreal sliceAngle = m_pieStartAngle; | ||||
Jani Honkonen
|
r437 | qreal pieSpan = m_pieEndAngle - m_pieStartAngle; | ||
Jani Honkonen
|
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; | ||||
} | ||||
Jani Honkonen
|
r437 | qreal sliceSpan = pieSpan * percentage; | ||
Jani Honkonen
|
r289 | if (s->m_angleSpan != sliceSpan) { | ||
s->m_angleSpan = sliceSpan; | ||||
Jani Honkonen
|
r203 | changed = true; | ||
} | ||||
Jani Honkonen
|
r355 | if (s->m_startAngle != sliceAngle) { | ||
s->m_startAngle = sliceAngle; | ||||
Jani Honkonen
|
r203 | changed = true; | ||
} | ||||
sliceAngle += sliceSpan; | ||||
if (changed) | ||||
emit s->changed(); | ||||
} | ||||
Jani Honkonen
|
r174 | } | ||
Jani Honkonen
|
r142 | #include "moc_qpieseries.cpp" | ||
QTCOMMERCIALCHART_END_NAMESPACE | ||||