qpieseries.cpp
863 lines
| 26.9 KiB
| text/x-c
|
CppLexer
Jani Honkonen
|
r794 | /**************************************************************************** | ||
** | ||||
** Copyright (C) 2012 Digia Plc | ||||
** All rights reserved. | ||||
** For any questions to Digia, please use contact form at http://qt.digia.com | ||||
** | ||||
** This file is part of the Qt Commercial Charts Add-on. | ||||
** | ||||
** $QT_BEGIN_LICENSE$ | ||||
** Licensees holding valid Qt Commercial licenses may use this file in | ||||
** accordance with the Qt Commercial License Agreement provided with the | ||||
** Software or, alternatively, in accordance with the terms contained in | ||||
** a written agreement between you and Digia. | ||||
** | ||||
** If you have questions regarding the use of this file, please use | ||||
** contact form at http://qt.digia.com | ||||
** $QT_END_LICENSE$ | ||||
** | ||||
****************************************************************************/ | ||||
Jani Honkonen
|
r142 | #include "qpieseries.h" | ||
Michal Klocek
|
r938 | #include "qpieseries_p.h" | ||
Jani Honkonen
|
r818 | #include "qpieslice.h" | ||
#include "pieslicedata_p.h" | ||||
Michal Klocek
|
r943 | #include "chartdataset_p.h" | ||
#include "charttheme_p.h" | ||||
#include "chartanimator_p.h" | ||||
Michal Klocek
|
r950 | #include "legendmarker_p.h" | ||
Marek Rosa
|
r862 | #include <QAbstractItemModel> | ||
Jani Honkonen
|
r142 | |||
QTCOMMERCIALCHART_BEGIN_NAMESPACE | ||||
Jani Honkonen
|
r320 | /*! | ||
\class QPieSeries | ||||
\brief Pie series API for QtCommercial Charts | ||||
Jani Honkonen
|
r952 | The pie series defines a pie chart which consists of pie slices which are defined as QPieSlice objects. | ||
Jani Honkonen
|
r320 | 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
|
r952 | Pie size and position on the chart is controlled by using relative values which range from 0.0 to 1.0 | ||
These relate to the actual chart rectangle. | ||||
By default the pie is defined as a full pie but it can also be a partial pie. | ||||
Jani Honkonen
|
r320 | This can be done by setting a starting angle and angle span to the series. | ||
Jani Honkonen
|
r952 | Full pie is 360 degrees where 0 is at 12 a'clock. | ||
Tero Ahola
|
r995 | |||
See the \l {PieChart Example} {pie chart example} to learn how to create a simple pie chart. | ||||
\image examples_piechart.png | ||||
Jani Honkonen
|
r320 | */ | ||
Marek Rosa
|
r924 | /*! | ||
Jani Honkonen
|
r928 | \property QPieSeries::horizontalPosition | ||
Jani Honkonen
|
r932 | \brief Defines the horizontal position of the pie. | ||
Marek Rosa
|
r924 | |||
Jani Honkonen
|
r932 | The value is a relative value to the chart rectangle where: | ||
\list | ||||
\o 0.0 is the absolute left. | ||||
\o 1.0 is the absolute right. | ||||
\endlist | ||||
Default value is 0.5 (center). | ||||
Marek Rosa
|
r924 | */ | ||
Jani Honkonen
|
r928 | /*! | ||
\property QPieSeries::verticalPosition | ||||
Jani Honkonen
|
r932 | \brief Defines the vertical position of the pie. | ||
The value is a relative value to the chart rectangle where: | ||||
\list | ||||
\o 0.0 is the absolute top. | ||||
\o 1.0 is the absolute bottom. | ||||
\endlist | ||||
Jani Honkonen
|
r928 | |||
Jani Honkonen
|
r932 | Default value is 0.5 (center). | ||
Jani Honkonen
|
r928 | */ | ||
/*! | ||||
\property QPieSeries::size | ||||
Jani Honkonen
|
r932 | \brief Defines the pie size. | ||
Jani Honkonen
|
r928 | |||
Jani Honkonen
|
r932 | The value is a relative value to the chart rectangle where: | ||
\list | ||||
Michal Klocek
|
r974 | \o 0.0 is the minimum size (pie not drawn). | ||
Jani Honkonen
|
r932 | \o 1.0 is the maximum size that can fit the chart. | ||
\endlist | ||||
Default value is 0.7. | ||||
Jani Honkonen
|
r928 | */ | ||
/*! | ||||
\property QPieSeries::startAngle | ||||
Jani Honkonen
|
r932 | \brief Defines the starting angle of the pie. | ||
Jani Honkonen
|
r928 | |||
Jani Honkonen
|
r932 | Full pie is 360 degrees where 0 degrees is at 12 a'clock. | ||
Jani Honkonen
|
r928 | |||
Jani Honkonen
|
r932 | Default is value is 0. | ||
*/ | ||||
Jani Honkonen
|
r928 | |||
/*! | ||||
\property QPieSeries::endAngle | ||||
Jani Honkonen
|
r932 | \brief Defines the ending angle of the pie. | ||
Jani Honkonen
|
r928 | |||
Jani Honkonen
|
r932 | Full pie is 360 degrees where 0 degrees is at 12 a'clock. | ||
Jani Honkonen
|
r928 | |||
Jani Honkonen
|
r932 | Default is value is 360. | ||
*/ | ||||
Jani Honkonen
|
r928 | |||
Marek Rosa
|
r924 | |||
Jani Honkonen
|
r314 | /*! | ||
Constructs a series object which is a child of \a parent. | ||||
*/ | ||||
Jani Honkonen
|
r203 | QPieSeries::QPieSeries(QObject *parent) : | ||
Tero Ahola
|
r988 | QAbstractSeries(*new QPieSeriesPrivate(this),parent) | ||
Jani Honkonen
|
r203 | { | ||
Jani Honkonen
|
r157 | |||
Jani Honkonen
|
r203 | } | ||
Jani Honkonen
|
r174 | |||
Jani Honkonen
|
r314 | /*! | ||
Jani Honkonen
|
r933 | Destroys the series and its slices. | ||
Jani Honkonen
|
r314 | */ | ||
Jani Honkonen
|
r203 | QPieSeries::~QPieSeries() | ||
{ | ||||
Jani Honkonen
|
r669 | // NOTE: d_prt destroyed by QObject | ||
Jani Honkonen
|
r203 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Jani Honkonen
|
r320 | Returns QChartSeries::SeriesTypePie. | ||
Jani Honkonen
|
r314 | */ | ||
Tero Ahola
|
r988 | QAbstractSeries::QSeriesType QPieSeries::type() const | ||
Jani Honkonen
|
r314 | { | ||
Tero Ahola
|
r988 | return QAbstractSeries::SeriesTypePie; | ||
Jani Honkonen
|
r314 | } | ||
/*! | ||||
Jani Honkonen
|
r933 | Appends an array of \a slices to the series. | ||
Jani Honkonen
|
r314 | Slice ownership is passed to the series. | ||
*/ | ||||
Jani Honkonen
|
r796 | void QPieSeries::append(QList<QPieSlice*> slices) | ||
Jani Honkonen
|
r203 | { | ||
Jani Honkonen
|
r669 | Q_D(QPieSeries); | ||
Jani Honkonen
|
r203 | foreach (QPieSlice* s, slices) { | ||
s->setParent(this); | ||||
Jani Honkonen
|
r669 | d->m_slices << s; | ||
Jani Honkonen
|
r174 | } | ||
Jani Honkonen
|
r157 | |||
Jani Honkonen
|
r669 | d->updateDerivativeData(); | ||
Jani Honkonen
|
r174 | |||
Jani Honkonen
|
r203 | foreach (QPieSlice* s, slices) { | ||
Jani Honkonen
|
r669 | connect(s, SIGNAL(changed()), d, SLOT(sliceChanged())); | ||
Jani Honkonen
|
r1009 | connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked())); | ||
connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool))); | ||||
Jani Honkonen
|
r203 | } | ||
Jani Honkonen
|
r1009 | emit d->added(slices); | ||
Jani Honkonen
|
r142 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Jani Honkonen
|
r933 | Appends a single \a slice to the series. | ||
Jani Honkonen
|
r314 | Slice ownership is passed to the series. | ||
*/ | ||||
Jani Honkonen
|
r796 | void QPieSeries::append(QPieSlice* slice) | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r796 | append(QList<QPieSlice*>() << slice); | ||
Jani Honkonen
|
r142 | } | ||
Jani Honkonen
|
r415 | /*! | ||
Jani Honkonen
|
r933 | Appends a single \a slice to the series and returns a reference to the series. | ||
Jani Honkonen
|
r415 | Slice ownership is passed to the series. | ||
*/ | ||||
Jani Honkonen
|
r406 | QPieSeries& QPieSeries::operator << (QPieSlice* slice) | ||
{ | ||||
Jani Honkonen
|
r796 | append(slice); | ||
Jani Honkonen
|
r406 | return *this; | ||
} | ||||
Jani Honkonen
|
r314 | |||
/*! | ||||
Jani Honkonen
|
r809 | Appends a single slice to the series with give \a value and \a name. | ||
Jani Honkonen
|
r314 | Slice ownership is passed to the series. | ||
*/ | ||||
Jani Honkonen
|
r796 | QPieSlice* QPieSeries::append(qreal value, QString name) | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r203 | QPieSlice* slice = new QPieSlice(value, name); | ||
Jani Honkonen
|
r796 | append(slice); | ||
Jani Honkonen
|
r203 | return slice; | ||
} | ||||
Jani Honkonen
|
r174 | |||
Jani Honkonen
|
r809 | /*! | ||
Inserts a single \a slice to the series before the slice at \a index position. | ||||
Slice ownership is passed to the series. | ||||
*/ | ||||
void QPieSeries::insert(int index, QPieSlice* slice) | ||||
Marek Rosa
|
r604 | { | ||
Jani Honkonen
|
r669 | Q_D(QPieSeries); | ||
Jani Honkonen
|
r809 | Q_ASSERT(index <= d->m_slices.count()); | ||
Marek Rosa
|
r604 | slice->setParent(this); | ||
Jani Honkonen
|
r809 | d->m_slices.insert(index, slice); | ||
Marek Rosa
|
r604 | |||
Jani Honkonen
|
r669 | d->updateDerivativeData(); | ||
Marek Rosa
|
r604 | |||
Jani Honkonen
|
r669 | connect(slice, SIGNAL(changed()), d, SLOT(sliceChanged())); | ||
Jani Honkonen
|
r1009 | connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked())); | ||
connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool))); | ||||
Marek Rosa
|
r604 | |||
Jani Honkonen
|
r1009 | emit d->added(QList<QPieSlice*>() << slice); | ||
Marek Rosa
|
r604 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Removes a single \a slice from the series and deletes the slice. | ||||
Jani Honkonen
|
r320 | |||
Jani Honkonen
|
r952 | Do not reference the pointer after this call. | ||
Jani Honkonen
|
r314 | */ | ||
Jani Honkonen
|
r203 | void QPieSeries::remove(QPieSlice* slice) | ||
{ | ||||
Jani Honkonen
|
r669 | Q_D(QPieSeries); | ||
if (!d->m_slices.removeOne(slice)) { | ||||
Jani Honkonen
|
r289 | Q_ASSERT(0); // TODO: how should this be reported? | ||
Jani Honkonen
|
r203 | return; | ||
} | ||||
Jani Honkonen
|
r174 | |||
Jani Honkonen
|
r669 | d->updateDerivativeData(); | ||
Jani Honkonen
|
r174 | |||
Jani Honkonen
|
r1009 | emit d->removed(QList<QPieSlice*>() << slice); | ||
Jani Honkonen
|
r621 | |||
Jani Honkonen
|
r203 | delete slice; | ||
Jani Honkonen
|
r823 | slice = 0; | ||
Jani Honkonen
|
r142 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Clears all slices from the series. | ||||
*/ | ||||
Jani Honkonen
|
r203 | void QPieSeries::clear() | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r669 | Q_D(QPieSeries); | ||
if (d->m_slices.count() == 0) | ||||
Jani Honkonen
|
r203 | return; | ||
Jani Honkonen
|
r174 | |||
Jani Honkonen
|
r669 | QList<QPieSlice*> slices = d->m_slices; | ||
foreach (QPieSlice* s, d->m_slices) { | ||||
d->m_slices.removeOne(s); | ||||
Jani Honkonen
|
r203 | delete s; | ||
} | ||||
Jani Honkonen
|
r566 | |||
Jani Honkonen
|
r669 | d->updateDerivativeData(); | ||
Jani Honkonen
|
r621 | |||
Jani Honkonen
|
r1009 | emit d->removed(slices); | ||
Jani Honkonen
|
r142 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Jani Honkonen
|
r933 | returns the number of the slices in this series. | ||
Jani Honkonen
|
r314 | */ | ||
int QPieSeries::count() const | ||||
{ | ||||
Jani Honkonen
|
r669 | Q_D(const QPieSeries); | ||
return d->m_slices.count(); | ||||
Jani Honkonen
|
r314 | } | ||
Jani Honkonen
|
r621 | /*! | ||
Returns true is the series is empty. | ||||
*/ | ||||
bool QPieSeries::isEmpty() const | ||||
{ | ||||
Jani Honkonen
|
r669 | Q_D(const QPieSeries); | ||
return d->m_slices.isEmpty(); | ||||
Jani Honkonen
|
r621 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Returns a list of slices that belong to this series. | ||||
*/ | ||||
QList<QPieSlice*> QPieSeries::slices() const | ||||
{ | ||||
Jani Honkonen
|
r669 | Q_D(const QPieSeries); | ||
return d->m_slices; | ||||
Jani Honkonen
|
r314 | } | ||
Tero Ahola
|
r884 | void QPieSeries::setHorizontalPosition(qreal relativePosition) | ||
{ | ||||
Q_D(QPieSeries); | ||||
if (d->setRealValue(d->m_pieRelativeHorPos, relativePosition, 1.0)) | ||||
Jani Honkonen
|
r1009 | emit d->piePositionChanged(); | ||
Tero Ahola
|
r884 | } | ||
Jani Honkonen
|
r454 | |||
Tero Ahola
|
r884 | void QPieSeries::setVerticalPosition(qreal relativePosition) | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r669 | Q_D(QPieSeries); | ||
Tero Ahola
|
r884 | if (d->setRealValue(d->m_pieRelativeVerPos, relativePosition, 1.0)) | ||
Jani Honkonen
|
r1009 | emit d->piePositionChanged(); | ||
Jani Honkonen
|
r142 | } | ||
Tero Ahola
|
r884 | qreal QPieSeries::horizontalPosition() const | ||
Jani Honkonen
|
r142 | { | ||
Jani Honkonen
|
r669 | Q_D(const QPieSeries); | ||
return d->m_pieRelativeHorPos; | ||||
Jani Honkonen
|
r142 | } | ||
Tero Ahola
|
r884 | qreal QPieSeries::verticalPosition() const | ||
Jani Honkonen
|
r314 | { | ||
Jani Honkonen
|
r669 | Q_D(const QPieSeries); | ||
return d->m_pieRelativeVerPos; | ||||
Jani Honkonen
|
r314 | } | ||
Jani Honkonen
|
r498 | void QPieSeries::setPieSize(qreal relativeSize) | ||
Jani Honkonen
|
r437 | { | ||
Jani Honkonen
|
r669 | Q_D(QPieSeries); | ||
Tero Ahola
|
r884 | if (d->setRealValue(d->m_pieRelativeSize, relativeSize, 1.0)) | ||
Jani Honkonen
|
r1009 | emit d->pieSizeChanged(); | ||
Jani Honkonen
|
r437 | } | ||
Jani Honkonen
|
r314 | |||
Jani Honkonen
|
r498 | qreal QPieSeries::pieSize() const | ||
Jani Honkonen
|
r203 | { | ||
Jani Honkonen
|
r669 | Q_D(const QPieSeries); | ||
return d->m_pieRelativeSize; | ||||
Jani Honkonen
|
r437 | } | ||
Jani Honkonen
|
r498 | void QPieSeries::setPieStartAngle(qreal angle) | ||
Jani Honkonen
|
r437 | { | ||
Jani Honkonen
|
r669 | Q_D(QPieSeries); | ||
Tero Ahola
|
r884 | if (d->setRealValue(d->m_pieStartAngle, angle, d->m_pieEndAngle)) | ||
Jani Honkonen
|
r669 | d->updateDerivativeData(); | ||
Jani Honkonen
|
r203 | } | ||
Jani Honkonen
|
r498 | qreal QPieSeries::pieStartAngle() const | ||
Jani Honkonen
|
r437 | { | ||
Jani Honkonen
|
r669 | Q_D(const QPieSeries); | ||
return d->m_pieStartAngle; | ||||
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. | ||||
Jani Honkonen
|
r498 | \a angle must be greater than start angle. | ||
Jani Honkonen
|
r454 | |||
Jani Honkonen
|
r498 | \sa pieEndAngle(), pieStartAngle(), setPieStartAngle() | ||
Jani Honkonen
|
r454 | */ | ||
Jani Honkonen
|
r498 | void QPieSeries::setPieEndAngle(qreal angle) | ||
Jani Honkonen
|
r437 | { | ||
Jani Honkonen
|
r669 | Q_D(QPieSeries); | ||
Jani Honkonen
|
r765 | |||
Tero Ahola
|
r884 | if (d->setRealValue(d->m_pieEndAngle, angle, 360.0, d->m_pieStartAngle)) | ||
Jani Honkonen
|
r669 | d->updateDerivativeData(); | ||
Jani Honkonen
|
r437 | } | ||
Jani Honkonen
|
r454 | /*! | ||
Returns the end angle of the pie. | ||||
Full pie is 360 degrees where 0 degrees is at 12 a'clock. | ||||
Jani Honkonen
|
r498 | \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle() | ||
Jani Honkonen
|
r454 | */ | ||
Jani Honkonen
|
r498 | qreal QPieSeries::pieEndAngle() const | ||
Jani Honkonen
|
r437 | { | ||
Jani Honkonen
|
r669 | Q_D(const QPieSeries); | ||
return d->m_pieEndAngle; | ||||
Jani Honkonen
|
r437 | } | ||
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) | ||
{ | ||||
Jani Honkonen
|
r669 | Q_D(QPieSeries); | ||
foreach (QPieSlice* s, d->m_slices) | ||||
Jani Honkonen
|
r203 | s->setLabelVisible(visible); | ||
} | ||||
Jani Honkonen
|
r406 | /*! | ||
Returns the sum of all slice values in this series. | ||||
Jani Honkonen
|
r952 | \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage() | ||
Jani Honkonen
|
r406 | */ | ||
Jani Honkonen
|
r939 | qreal QPieSeries::sum() const | ||
Jani Honkonen
|
r406 | { | ||
Jani Honkonen
|
r669 | Q_D(const QPieSeries); | ||
Jani Honkonen
|
r939 | return d->m_sum; | ||
Jani Honkonen
|
r406 | } | ||
Jani Honkonen
|
r314 | /*! | ||
Jani Honkonen
|
r1009 | \fn void QPieSeries::clicked(QPieSlice* slice) | ||
Jani Honkonen
|
r314 | |||
Jani Honkonen
|
r1009 | This signal is emitted when a \a slice has been clicked. | ||
Jani Honkonen
|
r314 | |||
\sa QPieSlice::clicked() | ||||
*/ | ||||
/*! | ||||
Jani Honkonen
|
r1009 | \fn void QPieSeries::hovered(QPieSlice* slice, bool state) | ||
Jani Honkonen
|
r314 | |||
Jani Honkonen
|
r1009 | This signal is emitted when user has hovered over or away from the \a slice. | ||
Jani Honkonen
|
r314 | |||
Jani Honkonen
|
r1009 | \a state is true when user has hovered over the slice and false when hover has moved away from the slice. | ||
Jani Honkonen
|
r809 | |||
Jani Honkonen
|
r1009 | \sa QPieSlice::hovered() | ||
Jani Honkonen
|
r809 | */ | ||
Jani Honkonen
|
r174 | |||
Marek Rosa
|
r879 | /*! | ||
\fn bool QPieSeries::setModel(QAbstractItemModel *model) | ||||
Sets the \a model to be used as a data source | ||||
*/ | ||||
Marek Rosa
|
r597 | bool QPieSeries::setModel(QAbstractItemModel* model) | ||
{ | ||||
Jani Honkonen
|
r669 | Q_D(QPieSeries); | ||
Marek Rosa
|
r597 | // disconnect signals from old model | ||
Michal Klocek
|
r938 | if(d->m_model) | ||
Marek Rosa
|
r597 | { | ||
Michal Klocek
|
r938 | disconnect(d->m_model, 0, this, 0); | ||
Jani Honkonen
|
r669 | d->m_mapValues = -1; | ||
d->m_mapLabels = -1; | ||||
d->m_mapOrientation = Qt::Vertical; | ||||
Marek Rosa
|
r597 | } | ||
Marek Rosa
|
r630 | // set new model | ||
Marek Rosa
|
r597 | if(model) | ||
{ | ||||
Michal Klocek
|
r938 | d->m_model = model; | ||
Marek Rosa
|
r630 | return true; | ||
} | ||||
else | ||||
{ | ||||
Michal Klocek
|
r938 | d->m_model = 0; | ||
Marek Rosa
|
r630 | return false; | ||
Marek Rosa
|
r597 | } | ||
} | ||||
Marek Rosa
|
r900 | /*! | ||
\fn bool QPieSeries::setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation) | ||||
Sets column/row specified by \a modelValuesLine to be used as a list of pie slice values for the pie. | ||||
Parameter \a modelValuesLine indicates the column/row where the values for the pie slices are located in the model. | ||||
Parameter \a modelLabelsLine indicates the column/row where the labels for the pie slices are located in the model. | ||||
Michal Klocek
|
r974 | The \a orientation parameter specifies whether the data is in columns or in rows. | ||
Marek Rosa
|
r900 | */ | ||
Marek Rosa
|
r597 | void QPieSeries::setModelMapping(int modelValuesLine, int modelLabelsLine, Qt::Orientation orientation) | ||
{ | ||||
Jani Honkonen
|
r669 | Q_D(QPieSeries); | ||
Michal Klocek
|
r938 | if (d->m_model == 0) | ||
Marek Rosa
|
r630 | return; | ||
Jani Honkonen
|
r669 | |||
d->m_mapValues = modelValuesLine; | ||||
d->m_mapLabels = modelLabelsLine; | ||||
d->m_mapOrientation = orientation; | ||||
Marek Rosa
|
r597 | |||
Marek Rosa
|
r1056 | d->initializePieFromModel(); | ||
// // connect the signals | ||||
// connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex))); | ||||
Marek Rosa
|
r1018 | |||
Marek Rosa
|
r597 | |||
Marek Rosa
|
r1056 | // // create the initial slices set | ||
// if (d->m_mapOrientation == Qt::Vertical) { | ||||
// for (int i = 0; i < d->m_model->rowCount(); i++) | ||||
// append(d->m_model->data(d->m_model->index(i, d->m_mapValues), Qt::DisplayRole).toDouble(), d->m_model->data(d->m_model->index(i, d->m_mapLabels), Qt::DisplayRole).toString()); | ||||
// } else { | ||||
// for (int i = 0; i < d->m_model->columnCount(); i++) | ||||
// append(d->m_model->data(d->m_model->index(d->m_mapValues, i), Qt::DisplayRole).toDouble(), d->m_model->data(d->m_model->index(d->m_mapLabels, i), Qt::DisplayRole).toString()); | ||||
// } | ||||
} | ||||
void QPieSeries::setModelMappingRange(int first, int count) | ||||
{ | ||||
Q_D(QPieSeries); | ||||
d->m_mapFirst = first; | ||||
d->m_mapCount = count; | ||||
Marek Rosa
|
r597 | } | ||
Michal Klocek
|
r938 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
Tero Ahola
|
r988 | QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) : | ||
QAbstractSeriesPrivate(parent), | ||||
Michal Klocek
|
r938 | m_pieRelativeHorPos(0.5), | ||
m_pieRelativeVerPos(0.5), | ||||
m_pieRelativeSize(0.7), | ||||
m_pieStartAngle(0), | ||||
m_pieEndAngle(360), | ||||
Jani Honkonen
|
r939 | m_sum(0), | ||
Michal Klocek
|
r938 | m_mapValues(0), | ||
Marek Rosa
|
r1055 | m_mapLabels(0) | ||
Michal Klocek
|
r938 | { | ||
} | ||||
QPieSeriesPrivate::~QPieSeriesPrivate() | ||||
{ | ||||
} | ||||
void QPieSeriesPrivate::updateDerivativeData() | ||||
{ | ||||
Jani Honkonen
|
r939 | m_sum = 0; | ||
Michal Klocek
|
r938 | |||
// nothing to do? | ||||
if (m_slices.count() == 0) | ||||
return; | ||||
Jani Honkonen
|
r939 | // calculate sum of all slices | ||
Michal Klocek
|
r938 | foreach (QPieSlice* s, m_slices) | ||
Jani Honkonen
|
r939 | m_sum += s->value(); | ||
Michal Klocek
|
r938 | |||
// nothing to show.. | ||||
Jani Honkonen
|
r939 | if (qFuzzyIsNull(m_sum)) | ||
Michal Klocek
|
r938 | return; | ||
// update slice attributes | ||||
qreal sliceAngle = m_pieStartAngle; | ||||
qreal pieSpan = m_pieEndAngle - m_pieStartAngle; | ||||
QVector<QPieSlice*> changed; | ||||
foreach (QPieSlice* s, m_slices) { | ||||
PieSliceData data = PieSliceData::data(s); | ||||
Jani Honkonen
|
r939 | data.m_percentage = s->value() / m_sum; | ||
Michal Klocek
|
r938 | data.m_angleSpan = pieSpan * data.m_percentage; | ||
data.m_startAngle = sliceAngle; | ||||
sliceAngle += data.m_angleSpan; | ||||
if (PieSliceData::data(s) != data) { | ||||
PieSliceData::data(s) = data; | ||||
changed << s; | ||||
} | ||||
} | ||||
// emit signals | ||||
foreach (QPieSlice* s, changed) | ||||
PieSliceData::data(s).emitChangedSignal(s); | ||||
} | ||||
Jani Honkonen
|
r1009 | QPieSeriesPrivate* QPieSeriesPrivate::seriesData(QPieSeries &series) | ||
Michal Klocek
|
r938 | { | ||
Jani Honkonen
|
r1009 | return series.d_func(); | ||
Michal Klocek
|
r938 | } | ||
Jani Honkonen
|
r1009 | void QPieSeriesPrivate::sliceChanged() | ||
Michal Klocek
|
r938 | { | ||
Jani Honkonen
|
r1009 | Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender()))); | ||
updateDerivativeData(); | ||||
Michal Klocek
|
r938 | } | ||
Jani Honkonen
|
r1009 | void QPieSeriesPrivate::sliceClicked() | ||
Michal Klocek
|
r938 | { | ||
QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); | ||||
Q_ASSERT(m_slices.contains(slice)); | ||||
Q_Q(QPieSeries); | ||||
Jani Honkonen
|
r1009 | emit q->clicked(slice); | ||
Michal Klocek
|
r938 | } | ||
Jani Honkonen
|
r1009 | void QPieSeriesPrivate::sliceHovered(bool state) | ||
Michal Klocek
|
r938 | { | ||
QPieSlice* slice = qobject_cast<QPieSlice *>(sender()); | ||||
Q_ASSERT(m_slices.contains(slice)); | ||||
Q_Q(QPieSeries); | ||||
Jani Honkonen
|
r1009 | emit q->hovered(slice, state); | ||
Michal Klocek
|
r938 | } | ||
void QPieSeriesPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight) | ||||
{ | ||||
Marek Rosa
|
r1056 | for (int row = topLeft.row(); row <= bottomRight.row(); row++) { | ||
for (int column = topLeft.column(); column <= bottomRight.column(); column++) { | ||||
if (m_mapOrientation == Qt::Vertical) | ||||
Michal Klocek
|
r938 | { | ||
Marek Rosa
|
r1056 | if ( topLeft.row() >= m_mapFirst && (m_mapCount == - 1 || topLeft.row() < m_mapFirst + m_mapCount)) { | ||
if (topLeft.column() == m_mapValues) | ||||
m_slices.at(topLeft.row() - m_mapFirst)->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble()); | ||||
if (topLeft.column() == m_mapLabels) | ||||
m_slices.at(topLeft.row() - m_mapFirst)->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString()); | ||||
} | ||||
Michal Klocek
|
r938 | } | ||
else | ||||
{ | ||||
Marek Rosa
|
r1056 | if (topLeft.column() >= m_mapFirst && (m_mapCount == - 1 || topLeft.column() < m_mapFirst + m_mapCount)) { | ||
if (topLeft.row() == m_mapValues) | ||||
m_slices.at(topLeft.column() - m_mapFirst)->setValue(m_model->data(topLeft, Qt::DisplayRole).toDouble()); | ||||
if (topLeft.row() == m_mapLabels) | ||||
m_slices.at(topLeft.column() - m_mapFirst)->setLabel(m_model->data(topLeft, Qt::DisplayRole).toString()); | ||||
} | ||||
Michal Klocek
|
r938 | } | ||
Marek Rosa
|
r1056 | } | ||
Michal Klocek
|
r938 | } | ||
Marek Rosa
|
r1056 | } | ||
void QPieSeriesPrivate::modelDataAdded(QModelIndex parent, int start, int end) | ||||
{ | ||||
Q_UNUSED(parent); | ||||
Q_Q(QPieSeries); | ||||
// series uses model as a data sourceupda | ||||
int addedCount = end - start + 1; | ||||
if (m_mapCount != -1 && start >= m_mapFirst + m_mapCount) { | ||||
return; | ||||
} else { | ||||
int first = qMax(start, m_mapFirst); | ||||
int last = qMin(first + addedCount - 1, end); | ||||
for (int i = first; i <= last; i++) { | ||||
QPieSlice *slice = new QPieSlice; | ||||
if (m_mapOrientation == Qt::Vertical) { | ||||
slice->setValue(m_model->data(m_model->index(i, m_mapValues), Qt::DisplayRole).toDouble()); | ||||
slice->setLabel(m_model->data(m_model->index(i, m_mapLabels), Qt::DisplayRole).toString()); | ||||
} else { | ||||
slice->setValue(m_model->data(m_model->index(m_mapValues, i), Qt::DisplayRole).toDouble()); | ||||
slice->setLabel(m_model->data(m_model->index(m_mapLabels, i), Qt::DisplayRole).toString()); | ||||
Michal Klocek
|
r938 | } | ||
Marek Rosa
|
r1056 | slice->setLabelVisible(); | ||
q->insert(i - m_mapFirst, slice); | ||||
} | ||||
if (m_mapCount != -1 && m_slices.size() > m_mapCount) | ||||
for (int i = m_slices.size() - 1; i >= m_mapCount; i--) | ||||
q->remove(q->slices().at(i)); | ||||
} | ||||
// // adding items to unlimited map | ||||
// else if (m_mapCount == -1 && start >= m_mapFirst) { | ||||
// for (int i = start; i <= end; i++) { | ||||
// QPieSlice *slice = new QPieSlice; | ||||
// slice->setValue(m_model->data(m_model->index(i, m_mapValues), Qt::DisplayRole).toDouble()); | ||||
// slice->setLabel(m_model->data(m_model->index(i, m_mapLabels), Qt::DisplayRole).toString()); | ||||
// slice->setLabelVisible(true); | ||||
// q->insert(i - m_mapFirst, slice); | ||||
// // handlePointAdded(i - first); | ||||
// } | ||||
// } else if (m_mapCount == - 1 && start < m_mapFirst) { | ||||
// // not all newly added items | ||||
// for (int i = m_mapFirst; i < m_mapFirst + addedCount; i++) { | ||||
// QPieSlice *slice = new QPieSlice; | ||||
// slice->setValue(m_model->data(m_model->index(i, m_mapValues), Qt::DisplayRole).toDouble()); | ||||
// slice->setLabel(m_model->data(m_model->index(i, m_mapLabels), Qt::DisplayRole).toString()); | ||||
// slice->setLabelVisible(true); | ||||
// q->insert(i - m_mapFirst, slice); | ||||
// // handlePointAdded(i - first); | ||||
// } | ||||
// } | ||||
// // adding items to limited map | ||||
// else if (start >= m_mapFirst) { | ||||
// // remove the items that will no longer fit into the map | ||||
// // int toRemove = addedCount - (count - points().size()); | ||||
// for (int i = start; i <= end; i++) { | ||||
// QPieSlice *slice = new QPieSlice; | ||||
// slice->setValue(m_model->data(m_model->index(i, m_mapValues), Qt::DisplayRole).toDouble()); | ||||
// slice->setLabel(m_model->data(m_model->index(i, m_mapLabels), Qt::DisplayRole).toString()); | ||||
// slice->setLabelVisible(true); | ||||
// q->insert(i - m_mapFirst, slice); | ||||
// } | ||||
// if (m_slices.size() > m_mapCount) | ||||
// for (int i = m_slices.size() - 1; i >= m_mapCount; i--) | ||||
// q->remove(q->slices().at(i)); | ||||
// // handlePointRemoved(i); | ||||
// // update(); | ||||
// } else { | ||||
// // | ||||
// for (int i = m_mapFirst; i < m_mapFirst + addedCount; i++) { | ||||
// QPieSlice *slice = new QPieSlice; | ||||
// slice->setValue(m_model->data(m_model->index(i, m_mapValues), Qt::DisplayRole).toDouble()); | ||||
// slice->setLabel(m_model->data(m_model->index(i, m_mapLabels), Qt::DisplayRole).toString()); | ||||
// slice->setLabelVisible(true); | ||||
// q->insert(i - m_mapFirst, slice); | ||||
// // handlePointAdded(i - first); | ||||
// } | ||||
// if (m_slices.size() > m_mapCount) | ||||
// for (int i = m_slices.size() - 1; i >= m_mapCount; i--) | ||||
// q->remove(q->slices().at(i)); | ||||
// // handlePointRemoved(i); | ||||
// } | ||||
} | ||||
void QPieSeriesPrivate::modelDataRemoved(QModelIndex parent, int start, int end) | ||||
{ | ||||
Q_UNUSED(parent); | ||||
Q_Q(QPieSeries); | ||||
int removedCount = end - start + 1; | ||||
if (m_mapCount != -1 && start >= m_mapFirst + m_mapCount) { | ||||
return; | ||||
} | ||||
// else if (m_mapCount == -1) { | ||||
// int first = qMax(start, m_mapFirst); | ||||
// int last = qMax(end, m_mapFirst + removedCount - 1); | ||||
// for (int i = last; i >= first; i--) | ||||
// q->remove(q->slices().at(i - m_mapFirst)); | ||||
// } | ||||
// else { | ||||
// int toRemove = qMin(m_slices.size() - 1, removedCount); | ||||
// int first = qMax(start, m_mapFirst); | ||||
// int last = qMax(end, m_mapFirst + toRemove - 1); | ||||
// } | ||||
// removing items from unlimited map | ||||
else if (m_mapCount == -1 && start >= m_mapFirst) { | ||||
for (int i = end; i >= start; i--) | ||||
q->remove(q->slices().at(i - m_mapFirst)); | ||||
// handlePointRemoved(i - m_mapFirst); | ||||
} else if (m_mapCount == - 1 && start < m_mapFirst) { | ||||
// not all removed items | ||||
for (int i = m_mapFirst + removedCount - 1; i >= m_mapFirst; i--) | ||||
q->remove(q->slices().at(i - m_mapFirst)); | ||||
// handlePointRemoved(i - m_mapFirst); | ||||
} | ||||
// removing items from limited map | ||||
else if (start >= m_mapFirst) { | ||||
// | ||||
// int sizeAfter = m_slices.size(); | ||||
int lastExisting = qMin(m_mapFirst + m_slices.size() - 1, end); | ||||
for (int i = lastExisting; i >= start; i--) { | ||||
q->remove(q->slices().at(i - m_mapFirst)); | ||||
// sizeAfter--; | ||||
// handlePointRemoved(i - m_mapFirst); | ||||
} | ||||
// the map is limited, so after removing the items some new items may have fall within the mapped area | ||||
int itemsAvailable; | ||||
if (m_mapOrientation == Qt::Vertical) | ||||
itemsAvailable = m_model->rowCount() - m_mapFirst - m_slices.size(); | ||||
else | ||||
itemsAvailable = m_model->columnCount() - m_mapFirst - m_slices.size(); | ||||
int toBeAdded = qMin(itemsAvailable, m_mapCount - m_slices.size()); | ||||
int currentSize = m_slices.size(); | ||||
if (itemsAvailable > 0) | ||||
for (int i = m_slices.size() + m_mapFirst; i < currentSize + toBeAdded + m_mapFirst; i++) { | ||||
// handlePointAdded(i); | ||||
QPieSlice *slice = new QPieSlice; | ||||
slice->setValue(m_model->data(m_model->index(i, m_mapValues), Qt::DisplayRole).toDouble()); | ||||
slice->setLabel(m_model->data(m_model->index(i, m_mapLabels), Qt::DisplayRole).toString()); | ||||
slice->setLabelVisible(true); | ||||
q->insert(i - m_mapFirst, slice); | ||||
} | ||||
// for (int i = lastExisting; i >= start; i--) { | ||||
// q->remove(q->slices().at(i - m_mapFirst)); | ||||
//// sizeAfter--; | ||||
//// handlePointRemoved(i - m_mapFirst); | ||||
// } | ||||
} else { | ||||
// first remove item lays before the mapped area | ||||
int toRemove = qMin(m_slices.size(), removedCount); | ||||
for (int i = m_mapFirst; i < m_mapFirst + toRemove; i++) | ||||
q->remove(q->slices().at(0)); | ||||
// handlePointRemoved(0); | ||||
// the map is limited, so after removing the items some new items may have fall into the map | ||||
int itemsAvailable; | ||||
if (m_mapOrientation == Qt::Vertical) | ||||
itemsAvailable = m_model->rowCount() - m_mapFirst - m_slices.size(); | ||||
else | ||||
itemsAvailable = m_model->columnCount() - m_mapFirst - m_slices.size(); | ||||
int toBeAdded = qMin(itemsAvailable, m_mapCount - m_slices.size()); | ||||
int currentSize = m_slices.size(); | ||||
if (itemsAvailable > 0) | ||||
for (int i = m_slices.size(); i < currentSize + toBeAdded; i++) { | ||||
QPieSlice *slice = new QPieSlice; | ||||
slice->setValue(m_model->data(m_model->index(i + m_mapFirst, m_mapValues), Qt::DisplayRole).toDouble()); | ||||
slice->setLabel(m_model->data(m_model->index(i + m_mapFirst, m_mapLabels), Qt::DisplayRole).toString()); | ||||
slice->setLabelVisible(true); | ||||
q->insert(i, slice); | ||||
// handlePointAdded(i); | ||||
Michal Klocek
|
r938 | } | ||
Marek Rosa
|
r1056 | } | ||
} | ||||
void QPieSeriesPrivate::initializePieFromModel() | ||||
{ | ||||
Q_Q(QPieSeries); | ||||
// clear current content | ||||
q->clear(); | ||||
// connect the signals | ||||
connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(modelUpdated(QModelIndex,QModelIndex))); | ||||
if (m_mapOrientation == Qt::Vertical) { | ||||
connect(m_model,SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(modelDataAdded(QModelIndex,int,int))); | ||||
connect(m_model,SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(modelDataRemoved(QModelIndex,int,int))); | ||||
} else { | ||||
connect(m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), this, SLOT(modelDataAdded(QModelIndex,int,int))); | ||||
connect(m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), this, SLOT(modelDataRemoved(QModelIndex,int,int))); | ||||
} | ||||
// create the initial slices set | ||||
if (m_mapOrientation == Qt::Vertical) { | ||||
int sliceCount = 0; | ||||
if(m_mapCount == -1) | ||||
sliceCount = m_model->rowCount() - m_mapFirst; | ||||
else | ||||
sliceCount = qMin(m_mapCount, m_model->rowCount() - m_mapFirst); | ||||
for (int i = m_mapFirst; i < m_mapFirst + sliceCount; i++) | ||||
q->append(m_model->data(m_model->index(i, m_mapValues), Qt::DisplayRole).toDouble(), m_model->data(m_model->index(i, m_mapLabels), Qt::DisplayRole).toString()); | ||||
} else { | ||||
int sliceCount = 0; | ||||
if(m_mapCount == -1) | ||||
sliceCount = m_model->columnCount() - m_mapFirst; | ||||
else | ||||
sliceCount = qMin(m_mapCount, m_model->columnCount() - m_mapFirst); | ||||
for (int i = m_mapFirst; i < m_mapFirst + sliceCount; i++) | ||||
q->append(m_model->data(m_model->index(m_mapValues, i), Qt::DisplayRole).toDouble(), m_model->data(m_model->index(m_mapLabels, i), Qt::DisplayRole).toString()); | ||||
Michal Klocek
|
r938 | } | ||
} | ||||
bool QPieSeriesPrivate::setRealValue(qreal &value, qreal newValue, qreal max, qreal min) | ||||
{ | ||||
// Remove rounding errors | ||||
qreal roundedValue = newValue; | ||||
if (qFuzzyIsNull(min) && qFuzzyIsNull(newValue)) | ||||
roundedValue = 0.0; | ||||
else if (qFuzzyCompare(newValue, max)) | ||||
roundedValue = max; | ||||
else if (qFuzzyCompare(newValue, min)) | ||||
roundedValue = min; | ||||
// Check if the position is valid after removing the rounding errors | ||||
if (roundedValue < min || roundedValue > max) { | ||||
qWarning("QPieSeries: Illegal value"); | ||||
return false; | ||||
} | ||||
if (!qFuzzyIsNull(value - roundedValue)) { | ||||
value = roundedValue; | ||||
return true; | ||||
} | ||||
// The change was so small it is considered a rounding error | ||||
return false; | ||||
} | ||||
Michal Klocek
|
r943 | void QPieSeriesPrivate::scaleDomain(Domain& domain) | ||
{ | ||||
Q_UNUSED(domain); | ||||
#ifndef QT_NO_DEBUG | ||||
qWarning() << __FILE__<<__FUNCTION__<<"not implemented"; | ||||
#endif | ||||
} | ||||
Chart* QPieSeriesPrivate::createGraphics(ChartPresenter* presenter) | ||||
{ | ||||
Q_Q(QPieSeries); | ||||
PieChartItem* pie = new PieChartItem(q,presenter); | ||||
if(presenter->animationOptions().testFlag(QChart::SeriesAnimations)) { | ||||
presenter->animator()->addAnimation(pie); | ||||
} | ||||
presenter->chartTheme()->decorate(q, presenter->dataSet()->seriesIndex(q)); | ||||
return pie; | ||||
} | ||||
Michal Klocek
|
r938 | |||
Michal Klocek
|
r950 | QList<LegendMarker*> QPieSeriesPrivate::createLegendMarker(QLegend* legend) | ||
{ | ||||
Q_Q(QPieSeries); | ||||
QList<LegendMarker*> markers; | ||||
foreach(QPieSlice* slice, q->slices()) { | ||||
PieLegendMarker* marker = new PieLegendMarker(q,slice,legend); | ||||
markers << marker; | ||||
} | ||||
return markers; | ||||
} | ||||
Jani Honkonen
|
r142 | #include "moc_qpieseries.cpp" | ||
Michal Klocek
|
r938 | #include "moc_qpieseries_p.cpp" | ||
Jani Honkonen
|
r142 | |||
QTCOMMERCIALCHART_END_NAMESPACE | ||||