##// END OF EJS Templates
Added BoxPlot tester to tests.pro...
Added BoxPlot tester to tests.pro Change-Id: Ic85b3572518f66b4ea4c9e61f2a9ac5ee96c51fb Reviewed-by: Mika Salmela <mika.salmela@digia.com>

File last commit:

r2432:53927f716a3d
r2466:58c13bf6bba4
Show More
chartdataset.cpp
534 lines | 14.1 KiB | text/x-c | CppLexer
/****************************************************************************
**
** Copyright (C) 2013 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$
**
****************************************************************************/
#include "chartdataset_p.h"
#include "chartpresenter_p.h"
#include "qchart.h"
#include "qchart_p.h"
#include "qvalueaxis.h"
#include "qbarcategoryaxis.h"
#include "qvalueaxis_p.h"
#include "qcategoryaxis.h"
#include "qabstractseries_p.h"
#include "qabstractbarseries.h"
#include "qstackedbarseries.h"
#include "qpercentbarseries.h"
#include "qpieseries.h"
#include "chartitem_p.h"
#include "xydomain_p.h"
#include "xlogydomain_p.h"
#include "logxydomain_p.h"
#include "logxlogydomain_p.h"
#ifndef QT_ON_ARM
#include "qdatetimeaxis.h"
#endif
QTCOMMERCIALCHART_BEGIN_NAMESPACE
ChartDataSet::ChartDataSet(QChart *chart)
: QObject(chart),
m_chart(chart)
{
}
ChartDataSet::~ChartDataSet()
{
deleteAllSeries();
deleteAllAxes();
}
/*
* This method adds series to chartdataset, series ownership is taken from caller.
*/
void ChartDataSet::addSeries(QAbstractSeries *series)
{
if (m_seriesList.contains(series)) {
qWarning() << QObject::tr("Can not add series. Series already on the chart.");
return;
}
series->d_ptr->initializeDomain();
m_seriesList.append(series);
series->setParent(this); // take ownership
series->d_ptr->m_chart = m_chart;
emit seriesAdded(series);
}
/*
* This method adds axis to chartdataset, axis ownership is taken from caller.
*/
void ChartDataSet::addAxis(QAbstractAxis *axis,Qt::Alignment aligment)
{
if (m_axisList.contains(axis)) {
qWarning() << QObject::tr("Can not add axis. Axis already on the chart.");
return;
}
axis->d_ptr->setAlignment(aligment);
if(!axis->alignment()) {
qWarning()<< QObject::tr("No alignment specified !");
return;
};
QSharedPointer<AbstractDomain> domain(new XYDomain());
axis->d_ptr->initializeDomain(domain.data());
axis->setParent(this);
axis->d_ptr->m_chart = m_chart;
m_axisList.append(axis);
emit axisAdded(axis);
}
/*
* This method removes series form chartdataset, series ownership is passed back to caller.
*/
void ChartDataSet::removeSeries(QAbstractSeries *series)
{
if (! m_seriesList.contains(series)) {
qWarning() << QObject::tr("Can not remove series. Series not found on the chart.");
return;
}
QList<QAbstractAxis*> axes = series->d_ptr->m_axes;
foreach(QAbstractAxis* axis, axes) {
detachAxis(series,axis);
}
emit seriesRemoved(series);
m_seriesList.removeAll(series);
series->setParent(0);
series->d_ptr->m_chart = 0;
}
/*
* This method removes axis form chartdataset, series ownership is passed back to caller.
*/
void ChartDataSet::removeAxis(QAbstractAxis *axis)
{
if (! m_axisList.contains(axis)) {
qWarning() << QObject::tr("Can not remove axis. Axis not found on the chart.");
return;
}
QList<QAbstractSeries*> series = axis->d_ptr->m_series;
foreach(QAbstractSeries* s, series) {
detachAxis(s,axis);
}
emit axisRemoved(axis);
m_axisList.removeAll(axis);
axis->setParent(0);
axis->d_ptr->m_chart = 0;
}
/*
* This method attaches axis to series, return true if success.
*/
bool ChartDataSet::attachAxis(QAbstractSeries* series,QAbstractAxis *axis)
{
Q_ASSERT(series);
Q_ASSERT(axis);
QList<QAbstractSeries* > attachedSeriesList = axis->d_ptr->m_series;
QList<QAbstractAxis* > attachedAxisList = series->d_ptr->m_axes;
if (!m_seriesList.contains(series)) {
qWarning() << QObject::tr("Can not find series on the chart.");
return false;
}
if (axis && !m_axisList.contains(axis)) {
qWarning() << QObject::tr("Can not find axis on the chart.");
return false;
}
if (attachedAxisList.contains(axis)) {
qWarning() << QObject::tr("Axis already attached to series.");
return false;
}
if (attachedSeriesList.contains(series)) {
qWarning() << QObject::tr("Axis already attached to series.");
return false;
}
AbstractDomain* domain = series->d_ptr->domain();
AbstractDomain::DomainType type = selectDomain(attachedAxisList<<axis);
if(type == AbstractDomain::UndefinedDomain) return false;
if(domain->type()!=type){
AbstractDomain *old = domain;
domain = createDomain(type);
domain->setRange(old->minX(), old->maxX(), old->minY(), old->maxY());
}
if(!domain) return false;
if(!domain->attachAxis(axis)) return false;
if(domain!=series->d_ptr->domain()){
foreach(QAbstractAxis* axis,series->d_ptr->m_axes){
series->d_ptr->domain()->detachAxis(axis);
domain->attachAxis(axis);
}
series->d_ptr->setDomain(domain);
series->d_ptr->initializeDomain();
}
series->d_ptr->m_axes<<axis;
axis->d_ptr->m_series<<series;
series->d_ptr->initializeAxes();
axis->d_ptr->initializeDomain(domain);
return true;
}
/*
* This method detaches axis to series, return true if success.
*/
bool ChartDataSet::detachAxis(QAbstractSeries* series,QAbstractAxis *axis)
{
Q_ASSERT(series);
Q_ASSERT(axis);
QList<QAbstractSeries* > attachedSeriesList = axis->d_ptr->m_series;
QList<QAbstractAxis* > attachedAxisList = series->d_ptr->m_axes;
AbstractDomain* domain = series->d_ptr->domain();
if (!m_seriesList.contains(series)) {
qWarning() << QObject::tr("Can not find series on the chart.");
return false;
}
if (axis && !m_axisList.contains(axis)) {
qWarning() << QObject::tr("Can not find axis on the chart.");
return false;
}
if (!attachedAxisList.contains(axis)) {
qWarning() << QObject::tr("Axis not attached to series.");
return false;
}
Q_ASSERT(axis->d_ptr->m_series.contains(series));
domain->detachAxis(axis);
series->d_ptr->m_axes.removeAll(axis);
axis->d_ptr->m_series.removeAll(series);
return true;
}
void ChartDataSet::createDefaultAxes()
{
if (m_seriesList.isEmpty())
return;
QAbstractAxis::AxisTypes typeX(0);
QAbstractAxis::AxisTypes typeY(0);
// Remove possibly existing axes
deleteAllAxes();
Q_ASSERT(m_axisList.isEmpty());
// Select the required axis x and axis y types based on the types of the current series
foreach(QAbstractSeries* s, m_seriesList) {
typeX |= s->d_ptr->defaultAxisType(Qt::Horizontal);
typeY |= s->d_ptr->defaultAxisType(Qt::Vertical);
}
// Create the axes of the types selected
createAxes(typeX, Qt::Horizontal);
createAxes(typeY, Qt::Vertical);
}
void ChartDataSet::createAxes(QAbstractAxis::AxisTypes type, Qt::Orientation orientation)
{
QAbstractAxis *axis = 0;
//decide what axis should be created
switch (type) {
case QAbstractAxis::AxisTypeValue:
axis = new QValueAxis(this);
break;
case QAbstractAxis::AxisTypeBarCategory:
axis = new QBarCategoryAxis(this);
break;
case QAbstractAxis::AxisTypeCategory:
axis = new QCategoryAxis(this);
break;
#ifndef Q_WS_QWS
case QAbstractAxis::AxisTypeDateTime:
axis = new QDateTimeAxis(this);
break;
#endif
default:
axis = 0;
break;
}
if (axis) {
//create one axis for all
addAxis(axis,orientation==Qt::Horizontal?Qt::AlignBottom:Qt::AlignLeft);
qreal min = 0;
qreal max = 0;
findMinMaxForSeries(m_seriesList,orientation,min,max);
foreach(QAbstractSeries *s, m_seriesList) {
attachAxis(s,axis);
}
axis->setRange(min,max);
}
else if (!type.testFlag(QAbstractAxis::AxisTypeNoAxis)) {
//create separate axis
foreach(QAbstractSeries *s, m_seriesList) {
QAbstractAxis *axis = s->d_ptr->createDefaultAxis(orientation);
if(axis) {
addAxis(axis,orientation==Qt::Horizontal?Qt::AlignBottom:Qt::AlignLeft);
attachAxis(s,axis);
}
}
}
}
void ChartDataSet::findMinMaxForSeries(QList<QAbstractSeries *> series,Qt::Orientations orientation, qreal &min, qreal &max)
{
Q_ASSERT(!series.isEmpty());
AbstractDomain* domain = series.first()->d_ptr->domain();
min = (orientation == Qt::Vertical) ? domain->minY() : domain->minX();
max = (orientation == Qt::Vertical) ? domain->maxY() : domain->maxX();
for(int i = 1; i< series.size(); i++) {
AbstractDomain* domain = series[i]->d_ptr->domain();
min = qMin((orientation == Qt::Vertical) ? domain->minY() : domain->minX(), min);
max = qMax((orientation == Qt::Vertical) ? domain->maxY() : domain->maxX(), max);
}
if (min == max) {
min -= 0.5;
max += 0.5;
}
}
void ChartDataSet::deleteAllSeries()
{
foreach (QAbstractSeries *s , m_seriesList){
removeSeries(s);
s->deleteLater();
}
Q_ASSERT(m_seriesList.count() == 0);
}
void ChartDataSet::deleteAllAxes()
{
foreach (QAbstractAxis *a , m_axisList){
removeAxis(a);
a->deleteLater();
}
Q_ASSERT(m_axisList.count() == 0);
}
void ChartDataSet::zoomInDomain(const QRectF &rect)
{
QList<AbstractDomain*> domains;
foreach(QAbstractSeries *s, m_seriesList) {
AbstractDomain* domain = s->d_ptr->domain();
s->d_ptr->m_domain->blockRangeSignals(true);
domains<<domain;
}
foreach(AbstractDomain *domain, domains)
domain->zoomIn(rect);
foreach(AbstractDomain *domain, domains)
domain->blockRangeSignals(false);
}
void ChartDataSet::zoomOutDomain(const QRectF &rect)
{
QList<AbstractDomain*> domains;
foreach(QAbstractSeries *s, m_seriesList) {
AbstractDomain* domain = s->d_ptr->domain();
s->d_ptr->m_domain->blockRangeSignals(true);
domains<<domain;
}
foreach(AbstractDomain *domain, domains)
domain->zoomOut(rect);
foreach(AbstractDomain *domain, domains)
domain->blockRangeSignals(false);
}
void ChartDataSet::scrollDomain(qreal dx, qreal dy)
{
QList<AbstractDomain*> domains;
foreach(QAbstractSeries *s, m_seriesList) {
AbstractDomain* domain = s->d_ptr->domain();
s->d_ptr->m_domain->blockRangeSignals(true);
domains<<domain;
}
foreach(AbstractDomain *domain, domains)
domain->move(dx, dy);
foreach(AbstractDomain *domain, domains)
domain->blockRangeSignals(false);
}
QPointF ChartDataSet::mapToValue(const QPointF &position, QAbstractSeries *series)
{
QPointF point;
if (series == 0 && !m_seriesList.isEmpty())
series = m_seriesList.first();
if (series && series->type() == QAbstractSeries::SeriesTypePie)
return point;
if (series && m_seriesList.contains(series))
point = series->d_ptr->m_domain->calculateDomainPoint(position - m_chart->plotArea().topLeft());
return point;
}
QPointF ChartDataSet::mapToPosition(const QPointF &value, QAbstractSeries *series)
{
QPointF point = m_chart->plotArea().topLeft();
if (series == 0 && !m_seriesList.isEmpty())
series = m_seriesList.first();
if (series && series->type() == QAbstractSeries::SeriesTypePie)
return QPoint(0, 0);
bool ok;
if (series && m_seriesList.contains(series))
point += series->d_ptr->m_domain->calculateGeometryPoint(value, ok);
return point;
}
QList<QAbstractAxis*> ChartDataSet::axes() const
{
return m_axisList;
}
QList<QAbstractSeries *> ChartDataSet::series() const
{
return m_seriesList;
}
AbstractDomain::DomainType ChartDataSet::selectDomain(QList<QAbstractAxis*> axes)
{
enum Type {
Undefined = 0,
LogType = 0x1,
ValueType = 0x2
};
int horizontal(Undefined);
int vertical(Undefined);
foreach(QAbstractAxis* axis, axes)
{
switch(axis->type()) {
case QAbstractAxis::AxisTypeLogValue:
if(axis->orientation()==Qt::Horizontal) {
horizontal|=LogType;
}
if(axis->orientation()==Qt::Vertical) {
vertical|=LogType;
}
break;
case QAbstractAxis::AxisTypeValue:
case QAbstractAxis::AxisTypeBarCategory:
case QAbstractAxis::AxisTypeCategory:
case QAbstractAxis::AxisTypeDateTime:
if(axis->orientation()==Qt::Horizontal) {
horizontal|=ValueType;
}
if(axis->orientation()==Qt::Vertical) {
vertical|=ValueType;
}
break;
default:
qWarning()<<"Undefined type";
break;
}
}
if(vertical==Undefined) vertical=ValueType;
if(horizontal==Undefined) horizontal=ValueType;
if(vertical==ValueType && horizontal== ValueType) {
return AbstractDomain::XYDomain;
}
if(vertical==LogType && horizontal== ValueType) {
return AbstractDomain::XLogYDomain;
}
if(vertical==ValueType && horizontal== LogType) {
return AbstractDomain::LogXYDomain;
}
if(vertical==LogType && horizontal== LogType) {
return AbstractDomain::LogXLogYDomain;
}
return AbstractDomain::UndefinedDomain;
}
//refactor create factory
AbstractDomain* ChartDataSet::createDomain(AbstractDomain::DomainType type)
{
switch(type)
{
case AbstractDomain::LogXLogYDomain:
return new LogXLogYDomain();
case AbstractDomain::XYDomain:
return new XYDomain();
case AbstractDomain::XLogYDomain:
return new XLogYDomain();
case AbstractDomain::LogXYDomain:
return new LogXYDomain();
default:
return 0;
}
}
#include "moc_chartdataset_p.cpp"
QTCOMMERCIALCHART_END_NAMESPACE