/**************************************************************************** ** ** 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$ ** ****************************************************************************/ #include "chartdataset_p.h" #include "qchart.h" #include "qvalueaxis.h" #include "qbarcategoryaxis.h" #include "qvalueaxis_p.h" #include "qcategoryaxis.h" #include "qdatetimeaxis.h" #include "qabstractseries_p.h" #include "qabstractbarseries.h" #include "qstackedbarseries.h" #include "qpercentbarseries.h" #include "qpieseries.h" QTCOMMERCIALCHART_BEGIN_NAMESPACE ChartDataSet::ChartDataSet(QChart *parent):QObject(parent) { } ChartDataSet::~ChartDataSet() { removeAllSeries(); } void ChartDataSet::addSeries(QAbstractSeries* series) { Domain* domain = m_seriesDomainMap.value(series); if(domain) { qWarning() << "Can not add series. Series already on the chart"; return; } domain = new Domain(series); m_seriesDomainMap.insert(series,domain); series->d_ptr->scaleDomain(*domain); createSeriesIndex(series); series->setParent(this); // take ownership series->d_ptr->m_chart = qobject_cast(parent()); series->d_ptr->m_dataset = this; emit seriesAdded(series,domain); } void ChartDataSet::removeSeries(QAbstractSeries* series) { if(!m_seriesDomainMap.contains(series)) { qWarning()<<"Can not remove series. Series not found on the chart."; return; } emit seriesRemoved(series); Domain* domain = m_seriesDomainMap.take(series); delete domain; domain = 0; removeSeriesIndex(series); series->setParent(0); series->d_ptr->m_chart = 0; series->d_ptr->m_dataset = 0; removeAxes(series); } void ChartDataSet::createSeriesIndex(QAbstractSeries* series) { QMapIterator i(m_indexSeriesMap); int key=0; while (i.hasNext()) { i.next(); if(i.key()!=key) { break; } key++; } m_indexSeriesMap.insert(key,series); } void ChartDataSet::removeSeriesIndex(QAbstractSeries* series) { int key = seriesIndex(series); Q_ASSERT(key!=-1); m_indexSeriesMap.remove(key); } void ChartDataSet::createDefaultAxes() { if (m_seriesDomainMap.isEmpty()) return; QAbstractAxis::AxisTypes typeX(0); QAbstractAxis::AxisTypes typeY(0); // Remove possibly existing axes QMapIterator i(m_seriesDomainMap); while (i.hasNext()) { i.next(); removeAxes(i.key()); } i.toFront(); // Select the required axis x and axis y types based on the types of the current series while (i.hasNext()) { i.next(); QAbstractAxis* axisX = m_seriesAxisXMap.value(i.key()); QAbstractAxis* axisY = m_seriesAxisYMap.value(i.key()); if(axisX) typeX&=axisX->type(); else typeX|=i.key()->d_ptr->defaultAxisType(Qt::Horizontal); if(axisY) typeY&=axisY->type(); else typeY|=i.key()->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) { QMapIterator i(m_seriesDomainMap); // TODO: Add a descriptive comment of what happens here if (type.testFlag(QAbstractAxis::AxisTypeValue) && type.testFlag(QAbstractAxis::AxisTypeBarCategory)) { while (i.hasNext()) { i.next(); QAbstractAxis* axis = createAxis(i.key()->d_ptr->defaultAxisType(orientation), orientation); if (axis) { initializeAxis(axis, i.key()); emit axisAdded(axis, i.value()); } } } else if (!type.testFlag(QAbstractAxis::AxisTypeNoAxis)) { QAbstractAxis* axis = createAxis(QAbstractAxis::AxisType(int(type)), orientation); i.toFront(); while (i.hasNext()) { i.next(); initializeAxis(axis,i.key()); } emit axisAdded(axis,i.value()); } } QAbstractAxis* ChartDataSet::createAxis(QAbstractAxis::AxisType type, Qt::Orientation orientation) { QAbstractAxis* axis = 0; 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; case QAbstractAxis::AxisTypeDateTime: axis = new QDateTimeAxis(this); break; default: axis = 0; break; } if(axis) axis->d_ptr->setOrientation(orientation); return axis; } void ChartDataSet::initializeAxis(QAbstractAxis* axis,QAbstractSeries* series) { Domain* domain = m_seriesDomainMap.value(series); axis->d_ptr->m_dataset = this; series->d_ptr->initializeAxis(axis); axis->d_ptr->intializeDomain(domain); if(axis->orientation()==Qt::Horizontal) { QObject::connect(axis->d_ptr.data(),SIGNAL(updated()),domain,SLOT(handleAxisUpdated())); QObject::connect(domain,SIGNAL(updated()),axis->d_ptr.data(),SLOT(handleDomainUpdated())); m_seriesAxisXMap.insert(series,axis); } else { QObject::connect(axis->d_ptr.data(),SIGNAL(updated()),domain,SLOT(handleAxisUpdated())); QObject::connect(domain,SIGNAL(updated()),axis->d_ptr.data(),SLOT(handleDomainUpdated())); m_seriesAxisYMap.insert(series,axis); } axis->d_ptr->emitUpdated(); } void ChartDataSet::removeAxes(QAbstractSeries* series) { QAbstractAxis* axisX = m_seriesAxisXMap.take(series); if(axisX) { QList axesX = m_seriesAxisXMap.values(); int x = axesX.indexOf(axisX); if(x==-1) { emit axisRemoved(axisX); axisX->d_ptr->m_dataset=0; axisX->deleteLater(); } } QAbstractAxis* axisY = m_seriesAxisYMap.take(series); if(axisY) { QList axesY = m_seriesAxisYMap.values(); int y = axesY.indexOf(axisY); if(y==-1) { emit axisRemoved(axisY); axisY->d_ptr->m_dataset=0; axisY->deleteLater(); } } } void ChartDataSet::removeAxis(QAbstractAxis* axis) { if(!axis->d_ptr->m_dataset) { qWarning()<<"UnBound axis found !"; return; } QMap *seriesAxisMap; if(axis->orientation()==Qt::Vertical) { seriesAxisMap= &m_seriesAxisYMap; } else { seriesAxisMap= &m_seriesAxisXMap; } QMapIterator i(*seriesAxisMap); while (i.hasNext()) { i.next(); if(i.value()==axis) { removeSeries(i.key()); } } } void ChartDataSet::removeAllSeries() { QList series = m_seriesDomainMap.keys(); foreach(QAbstractSeries *s , series) { removeSeries(s); } Q_ASSERT(m_seriesAxisXMap.count()==0); Q_ASSERT(m_seriesAxisXMap.count()==0); Q_ASSERT(m_seriesDomainMap.count()==0); qDeleteAll(series); } void ChartDataSet::zoomInDomain(const QRectF& rect, const QSizeF& size) { //for performance reasons block, signals and scale "full" domain one by one. Gives twice less screen updates blockAxisSignals(true); QMapIterator i(m_seriesDomainMap); while (i.hasNext()) { i.next(); i.value()->zoomIn(rect,size); } blockAxisSignals(false); } void ChartDataSet::zoomOutDomain(const QRectF& rect, const QSizeF& size) { //for performance reasons block, signals and scale "full" domain one by one. Gives twice less screen updates blockAxisSignals(true); QMapIterator i(m_seriesDomainMap); while (i.hasNext()) { i.next(); i.value()->zoomOut(rect,size); } blockAxisSignals(false); } void ChartDataSet::blockAxisSignals(bool enabled) { QMapIterator i(m_seriesDomainMap); while (i.hasNext()) { i.next(); QAbstractAxis* axisX = m_seriesAxisXMap.value(i.key()); QAbstractAxis* axisY = m_seriesAxisYMap.value(i.key()); if(axisX) { axisX->d_ptr->blockSignals(enabled); if(!enabled) { axisX->d_ptr->setDirty(false); axisX->d_ptr->emitUpdated(); } } if(axisY) { axisY->d_ptr->blockSignals(enabled); if(!enabled) { axisY->d_ptr->setDirty(false); axisY->d_ptr->emitUpdated(); } } } } int ChartDataSet::seriesCount(QAbstractSeries::SeriesType type) { int count=0; QMapIterator i(m_seriesDomainMap); while (i.hasNext()) { i.next(); if(i.key()->type()==type) count++; } return count; } int ChartDataSet::seriesIndex(QAbstractSeries *series) { QMapIterator i(m_indexSeriesMap); while (i.hasNext()) { i.next(); if (i.value() == series) return i.key(); } return -1; } QAbstractAxis* ChartDataSet::axisX(QAbstractSeries *series) const { if(series == 0) { QMapIterator i(m_seriesAxisXMap); while (i.hasNext()) { i.next(); if(i.value()->isVisible()) return i.value(); } return 0; } return m_seriesAxisXMap.value(series); } QAbstractAxis* ChartDataSet::axisY(QAbstractSeries *series) const { if(series == 0) { QMapIterator i(m_seriesAxisYMap); while (i.hasNext()) { i.next(); if(i.value()->isVisible()) return i.value(); } return 0; } return m_seriesAxisYMap.value(series); } void ChartDataSet::setAxis(QAbstractSeries *series, QAbstractAxis *axis, Qt::Orientation orientation) { Q_ASSERT(axis); if(!series) { qWarning() << "Series not found on the chart."; return; } Domain* domain = m_seriesDomainMap.value(series); if(!domain) { qWarning() << "Series not found on the chart."; return; } if(orientation==Qt::Horizontal && axis->orientation()==Qt::Vertical) { qWarning()<<"Axis already defined as axis Y"; return; } if(orientation==Qt::Vertical && axis->orientation()==Qt::Horizontal) { qWarning()<<"Axis already defined as axis X"; return; } axis->d_ptr->setOrientation(orientation); QMap *seriesAxisMap; if(orientation==Qt::Vertical) { seriesAxisMap= &m_seriesAxisYMap; }else{ seriesAxisMap= &m_seriesAxisXMap; } if (seriesAxisMap->value(series) == axis) { qWarning() << "The axis already set for the series"; return; } QAbstractAxis *oldAxis = seriesAxisMap->take(series); QList axes = seriesAxisMap->values(); if(oldAxis) { if(axes.indexOf(oldAxis)==-1) { emit axisRemoved(oldAxis); oldAxis->disconnect(); QObject::disconnect(domain,0,oldAxis,0); oldAxis->d_ptr->m_dataset=0; oldAxis->deleteLater(); } } if(axes.indexOf(axis)==-1) { initializeAxis(axis,series); emit axisAdded(axis,domain); }else{ initializeAxis(axis,series); } } Domain* ChartDataSet::domain(QAbstractSeries *series) const { return m_seriesDomainMap.value(series); } void ChartDataSet::scrollDomain(qreal dx,qreal dy,const QSizeF& size) { blockAxisSignals(true); QMapIterator i(m_seriesDomainMap); while (i.hasNext()) { i.next(); i.value()->move(dx,dy,size); } blockAxisSignals(false); } QList ChartDataSet::series() const { return m_seriesDomainMap.keys(); } void ChartDataSet::updateSeries(QAbstractSeries *series) { emit seriesUpdated(series); } #include "moc_chartdataset_p.cpp" QTCOMMERCIALCHART_END_NAMESPACE