From e65f6f3d183fe91b5d34dc9b09ea11cd83f40c23 2012-04-18 12:23:25 From: Marek Rosa Date: 2012-04-18 12:23:25 Subject: [PATCH] QXYSeries: support for adding data to model when using custom mapping --- diff --git a/src/qabstractseries.cpp b/src/qabstractseries.cpp index c124a40..9882c26 100644 --- a/src/qabstractseries.cpp +++ b/src/qabstractseries.cpp @@ -101,6 +101,15 @@ QAbstractItemModel* QAbstractSeries::model() const return d_ptr->m_model; } +int QAbstractSeries::mapFirst() const +{ + return d_ptr->m_mapFirst; +} +int QAbstractSeries::mapCount() const +{ + return d_ptr->m_mapCount; +} + void QAbstractSeries::setName(const QString& name) { d_ptr->m_name = name; @@ -117,7 +126,11 @@ QString QAbstractSeries::name() const /////////////////////////////////////////////////////////////////////////////////////////////////// -QAbstractSeriesPrivate::QAbstractSeriesPrivate(QAbstractSeries* q): q_ptr(q),m_model(0) +QAbstractSeriesPrivate::QAbstractSeriesPrivate(QAbstractSeries* q): + q_ptr(q), + m_model(0), + m_mapFirst(0), + m_mapCount(-1) { } diff --git a/src/qabstractseries.h b/src/qabstractseries.h index 98dd281..fb4059a 100644 --- a/src/qabstractseries.h +++ b/src/qabstractseries.h @@ -57,6 +57,8 @@ public: virtual QSeriesType type() const = 0; virtual bool setModel(QAbstractItemModel* model) = 0; QAbstractItemModel* model() const; + int mapFirst() const; + int mapCount() const; void setName(const QString& name); QString name() const; diff --git a/src/qabstractseries_p.h b/src/qabstractseries_p.h index 4080a9f..e6d93d7 100644 --- a/src/qabstractseries_p.h +++ b/src/qabstractseries_p.h @@ -56,6 +56,8 @@ public: protected: QAbstractSeries *q_ptr; QAbstractItemModel *m_model; + int m_mapFirst; + int m_mapCount; QString m_name; friend class QAbstractSeries; diff --git a/src/xychart/qxyseries.cpp b/src/xychart/qxyseries.cpp index cfaa082..95223ff 100644 --- a/src/xychart/qxyseries.cpp +++ b/src/xychart/qxyseries.cpp @@ -207,10 +207,10 @@ qreal QXYSeries::x(int pos) const if (d->m_model) { if (d->m_mapOrientation == Qt::Vertical) // consecutive data is read from model's column - return d->m_model->data(d->m_model->index(pos, d->m_mapX), Qt::DisplayRole).toDouble(); + return d->m_model->data(d->m_model->index(pos + d->m_mapFirst, d->m_mapX), Qt::DisplayRole).toDouble(); else // consecutive data is read from model's row - return d->m_model->data(d->m_model->index(d->m_mapX, pos), Qt::DisplayRole).toDouble(); + return d->m_model->data(d->m_model->index(d->m_mapX, pos + d->m_mapFirst), Qt::DisplayRole).toDouble(); } else { // model is not specified, return the data from series' internal data store return d->m_x.at(pos); @@ -226,10 +226,10 @@ qreal QXYSeries::y(int pos) const if (d->m_model) { if (d->m_mapOrientation == Qt::Vertical) // consecutive data is read from model's column - return d->m_model->data(d->m_model->index(pos, d->m_mapY), Qt::DisplayRole).toDouble(); + return d->m_model->data(d->m_model->index(pos + d->m_mapFirst, d->m_mapY), Qt::DisplayRole).toDouble(); else // consecutive data is read from model's row - return d->m_model->data(d->m_model->index(d->m_mapY, pos), Qt::DisplayRole).toDouble(); + return d->m_model->data(d->m_model->index(d->m_mapY, pos + d->m_mapFirst), Qt::DisplayRole).toDouble(); } else { // model is not specified, return the data from series' internal data store return d->m_y.at(pos); @@ -247,11 +247,19 @@ int QXYSeries::count() const if (d->m_model) { if (d->m_mapOrientation == Qt::Vertical) { - // data is in a column. Return the number of mapped items - return d->m_model->rowCount(); + // data is in a column. Return the number of mapped items if the model's column have enough items + // or the number of items that can be mapped + if (d->m_mapCount != -1) + return qMin(d->m_mapCount, qMax(d->m_model->rowCount() - d->m_mapFirst, 0)); + else + return qMax(d->m_model->rowCount() - d->m_mapFirst, 0); } else { - // data is in a row. Return the number of mapped items - return d->m_model->columnCount(); + // data is in a row. Return the number of mapped items if the model's row have enough items + // or the number of items that can be mapped + if (d->m_mapCount != -1) + return qMin(d->m_mapCount, qMax(d->m_model->columnCount() - d->m_mapFirst, 0)); + else + return qMax(d->m_model->columnCount() - d->m_mapFirst, 0); } } @@ -358,22 +366,6 @@ QXYSeries& QXYSeries::operator<< (const QList points) } /*! - \internal - */ -void QXYSeries::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight) -{ - Q_UNUSED(bottomRight) - Q_D(QXYSeries); - if (d->m_mapOrientation == Qt::Vertical) { - if (topLeft.column() == d->m_mapX || topLeft.column() == d->m_mapY) - emit d->pointReplaced(topLeft.row()); - } else { - if (topLeft.row() == d->m_mapX || topLeft.row() == d->m_mapY) - emit d->pointReplaced(topLeft.column()); - } -} - -/*! \fn bool QXYSeries::setModel(QAbstractItemModel *model) Sets the \a model to be used as a data source \sa setModelMapping() @@ -413,7 +405,23 @@ void QXYSeries::setModelMapping(int modelX, int modelY, Qt::Orientation orientat d->m_mapX = modelX; d->m_mapY = modelY; d->m_mapOrientation = orientation; - connect(d->m_model,SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(modelUpdated(QModelIndex,QModelIndex))); + + // connect the signals from the model + connect(d->m_model,SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex))); + if (d->m_mapOrientation == Qt::Vertical) { + connect(d->m_model,SIGNAL(rowsInserted(QModelIndex,int,int)), d, SLOT(modelDataAdded(QModelIndex,int,int))); + connect(d->m_model,SIGNAL(rowsRemoved(QModelIndex,int,int)), d, SLOT(modelDataRemoved(QModelIndex,int,int))); + } else { + connect(d->m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, SLOT(modelDataAdded(QModelIndex,int,int))); + connect(d->m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, SLOT(modelDataRemoved(QModelIndex,int,int))); + } +} + +void QXYSeries::setModelMappingRange(int first, int count) +{ + Q_D(QXYSeries); + d->m_mapFirst = first; + d->m_mapCount = count; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -458,6 +466,38 @@ QList QXYSeriesPrivate::createLegendMarker(QLegend* legend) return list << new XYLegendMarker(q,legend); } +void QXYSeriesPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight) +{ + for (int row = topLeft.row(); row <= bottomRight.row(); row++) { + for (int column = topLeft.column(); column <= bottomRight.column(); column++) { + if (m_mapOrientation == Qt::Vertical) { + if ((column == m_mapX || column == m_mapY) // modified item is in a mapped column + && row >= m_mapFirst // modfied item in not before first item + && (m_mapCount == -1 || row < m_mapFirst + m_mapCount)) // map is not limited or item lays before the end of map + emit pointReplaced(row - m_mapFirst); + } else { + if ((row == m_mapX || row == m_mapY) // modified item is in a mapped row + && column >= m_mapFirst // modfied item in not before first item + && (m_mapCount == -1 || column < m_mapFirst + m_mapCount)) // map is not limited or item lays before the end of map + emit pointReplaced(column - m_mapFirst); + } + } + } +} + + +void QXYSeriesPrivate::modelDataAdded(QModelIndex parent, int start, int end) +{ + Q_UNUSED(parent); + emit pointsAdded(start, end); +} + +void QXYSeriesPrivate::modelDataRemoved(QModelIndex parent, int start, int end) +{ + Q_UNUSED(parent); + emit pointsRemoved(start, end); +} + #include "moc_qxyseries.cpp" #include "moc_qxyseries_p.cpp" diff --git a/src/xychart/qxyseries.h b/src/xychart/qxyseries.h index e0a8500..f99c591 100644 --- a/src/xychart/qxyseries.h +++ b/src/xychart/qxyseries.h @@ -69,9 +69,10 @@ public: bool setModel(QAbstractItemModel *model); virtual void setModelMapping(int modelX, int modelY, Qt::Orientation orientation = Qt::Vertical); + void setModelMappingRange(int first, int count = -1); -private Q_SLOTS: - void modelUpdated(QModelIndex topLeft, QModelIndex bottomRight); +//private Q_SLOTS: +// void modelUpdated(QModelIndex topLeft, QModelIndex bottomRight); Q_SIGNALS: void clicked(const QPointF &point); diff --git a/src/xychart/qxyseries_p.h b/src/xychart/qxyseries_p.h index 18fc64b..e0f1b56 100644 --- a/src/xychart/qxyseries_p.h +++ b/src/xychart/qxyseries_p.h @@ -46,11 +46,20 @@ public: void scaleDomain(Domain& domain); QList createLegendMarker(QLegend* legend); +private Q_SLOTS: + void modelUpdated(QModelIndex topLeft, QModelIndex bottomRight); + void modelDataAdded(QModelIndex parent, int start, int end); + void modelDataRemoved(QModelIndex parent, int start, int end); + Q_SIGNALS: void updated(); void pointReplaced(int index); void pointRemoved(int index); + void pointsRemoved(int start, int end); void pointAdded(int index); + void pointsAdded(int start, int end); + + protected: QVector m_x; diff --git a/src/xychart/xychartitem.cpp b/src/xychart/xychartitem.cpp index 95aa017..1269069 100644 --- a/src/xychart/xychartitem.cpp +++ b/src/xychart/xychartitem.cpp @@ -40,7 +40,9 @@ XYChartItem::XYChartItem(QXYSeries *series, ChartPresenter *presenter):ChartItem { connect(series->d_func(),SIGNAL(pointReplaced(int)),this,SLOT(handlePointReplaced(int))); connect(series->d_func(),SIGNAL(pointAdded(int)),this,SLOT(handlePointAdded(int))); + connect(series->d_func(),SIGNAL(pointsAdded(int, int)),this,SLOT(handlePointsAdded(int, int))); connect(series->d_func(),SIGNAL(pointRemoved(int)),this,SLOT(handlePointRemoved(int))); + connect(series->d_func(),SIGNAL(pointsRemoved(int, int)),this,SLOT(handlePointsRemoved(int, int))); connect(this,SIGNAL(clicked(QPointF)),series,SIGNAL(clicked(QPointF))); } @@ -106,8 +108,10 @@ void XYChartItem::setLayout(QVector &points) void XYChartItem::handlePointAdded(int index) { - Q_ASSERT(indexcount()); - Q_ASSERT(index>=0); + if (m_series->model() == 0) { + Q_ASSERT(indexcount()); + Q_ASSERT(index>=0); + } QVector points = m_points; QPointF point; point = calculateGeometryPoint(index); @@ -115,16 +119,78 @@ void XYChartItem::handlePointAdded(int index) updateLayout(m_points, points, index); update(); } + +void XYChartItem::handlePointsAdded(int start, int end) +{ + if (m_series->model() == 0) { + for (int i = start; i <= end; i++) + handlePointAdded(i); + } else { + // series uses model as a data source + int first = m_series->mapFirst(); + int count = m_series->mapCount(); + int addedCount = end - start + 1; + if (count != -1 && start >= first + count) { + return; + } + + // adding items to unlimited map + else if (count == -1 && start >= first) { + for (int i = start; i <= end; i++) + handlePointAdded(i - first); + } else if (count == - 1 && start < first) { + // not all newly added items + for (int i = first; i < first + addedCount; i++) + handlePointAdded(i - first); + } + // commented out code below does the same thing, but its more confusing. + // } else if (count == -1) { + // int begin = qMax(start, first); + // for (int i = begin; i < begin + (end - start + 1); i++) + // handlePointAdded(i - first); + // } + + // adding items to limited map + else if (start >= first) { + // remove the items that will no longer fit into the map + // int toRemove = addedCount - (count - points().size()); + for (int i = start; i <= end; i++) { + handlePointAdded(i - first); + } + if (m_points.size() > count) + for (int i = m_points.size() - 1; i >= count; i--) + handlePointRemoved(i); + // update(); + } else { + // + for (int i = first; i < first + addedCount; i++) { + handlePointAdded(i - first); + } + if (m_points.size() > count) + for (int i = m_points.size() - 1; i >= count; i--) + handlePointRemoved(i); + } + } +} + void XYChartItem::handlePointRemoved(int index) { - Q_ASSERT(indexcount() + 1); - Q_ASSERT(index>=0); + if (m_series->model() == 0) { + Q_ASSERT(indexcount() + 1); + Q_ASSERT(index>=0); + } QVector points = m_points; points.remove(index); updateLayout(m_points, points, index); update(); } +void XYChartItem::handlePointsRemoved(int start, int end) +{ + Q_UNUSED(start) + Q_UNUSED(end) +} + void XYChartItem::handlePointReplaced(int index) { Q_ASSERT(indexcount()); diff --git a/src/xychart/xychartitem_p.h b/src/xychart/xychartitem_p.h index 0a1174d..897596f 100644 --- a/src/xychart/xychartitem_p.h +++ b/src/xychart/xychartitem_p.h @@ -43,7 +43,9 @@ public: public Q_SLOTS: void handlePointAdded(int index); + void handlePointsAdded(int start, int end); void handlePointRemoved(int index); + void handlePointsRemoved(int start, int end); void handlePointReplaced(int index); void handleDomainChanged(qreal minX, qreal maxX, qreal minY, qreal maxY); void handleGeometryChanged(const QRectF &size); diff --git a/test/tablemodelchart/tablewidget.cpp b/test/tablemodelchart/tablewidget.cpp index 1aa9b11..375e58a 100644 --- a/test/tablemodelchart/tablewidget.cpp +++ b/test/tablemodelchart/tablewidget.cpp @@ -52,6 +52,7 @@ TableWidget::TableWidget(QWidget *parent) // tableView->setItemDelegate(new QStyledItemDelegate); m_chart = new QChart; m_chart->legend()->setVisible(true); +// m_chart->setAnimationOptions(QChart::SeriesAnimations); m_chartView = new QChartView(m_chart); m_chartView->setRenderHint(QPainter::Antialiasing); m_chartView->setMinimumSize(640, 480); @@ -169,10 +170,10 @@ void TableWidget::updateChartType(bool toggle) m_series = new QLineSeries; m_series->setModel(m_model); m_series->setModelMapping(0,1, Qt::Vertical); -// m_series->setModelMappingRange(1, 4); + m_series->setModelMappingRange(4, 4); m_chart->addSeries(m_series); seriesColorHex = "#" + QString::number(m_series->pen().color().rgb(), 16).right(6).toUpper(); - m_model->addMapping(seriesColorHex, QRect(0, 1, 2, 4)); + m_model->addMapping(seriesColorHex, QRect(0, 4, 2, 4)); // series 2 m_series = new QLineSeries; @@ -186,7 +187,7 @@ void TableWidget::updateChartType(bool toggle) m_series = new QLineSeries; m_series->setModel(m_model); m_series->setModelMapping(4,5, Qt::Vertical); -// m_series->setModelMappingRange(2, 0); + m_series->setModelMappingRange(2, -1); m_chart->addSeries(m_series); seriesColorHex = "#" + QString::number(m_series->pen().color().rgb(), 16).right(6).toUpper(); m_model->addMapping(seriesColorHex, QRect(4, 2, 2, 1000));