diff options
author | Liang Qi <liang.qi@qt.io> | 2016-08-30 06:56:05 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-08-30 06:56:12 +0200 |
commit | bf26aa9d15e525fdcf6fd3f59268418533f06790 (patch) | |
tree | e1a12cc49f338bd1ac419a4d774d6f4570df3e40 | |
parent | d352d707f95c3c4e213585361a3ec737389e301e (diff) | |
parent | 8ed3130583510feba58e6f289d1c7b5d051a6663 (diff) |
Merge remote-tracking branch 'origin/5.6' into 5.7
Change-Id: Ibf7679696d7b659621cf511fd5e1d5eda244a810
-rw-r--r-- | dist/changes-2.1.2 | 1 | ||||
-rw-r--r-- | src/charts/areachart/areachartitem.cpp | 94 | ||||
-rw-r--r-- | src/charts/areachart/areachartitem_p.h | 3 | ||||
-rw-r--r-- | src/charts/areachart/qareaseries.cpp | 16 | ||||
-rw-r--r-- | tests/auto/auto.pro | 1 | ||||
-rw-r--r-- | tests/auto/qareaseries/qareaseries.pro | 4 | ||||
-rw-r--r-- | tests/auto/qareaseries/tst_qareaseries.cpp | 183 |
7 files changed, 269 insertions, 33 deletions
diff --git a/dist/changes-2.1.2 b/dist/changes-2.1.2 index e73605e6..96ec6710 100644 --- a/dist/changes-2.1.2 +++ b/dist/changes-2.1.2 @@ -19,6 +19,7 @@ Fixed issues - [QTBUG-53337] Fix setting axis color properties to black for the first time - [QTBUG-55348] Disconnect a series from ChartItem when it is removed from a chart - Fix logarithmic axis for area chart +- [QTBUG-55431] Fix setting area series edge series after area series is shown Fixed examples -------------- diff --git a/src/charts/areachart/areachartitem.cpp b/src/charts/areachart/areachartitem.cpp index a51e46ff..df3cc8af 100644 --- a/src/charts/areachart/areachartitem.cpp +++ b/src/charts/areachart/areachartitem.cpp @@ -95,10 +95,39 @@ void AreaChartItem::setPresenter(ChartPresenter *presenter) { if (m_upper) m_upper->setPresenter(presenter); - if (m_lower) { + if (m_lower) m_lower->setPresenter(presenter); + ChartItem::setPresenter(presenter); +} + +void AreaChartItem::setUpperSeries(QLineSeries *series) +{ + delete m_upper; + if (series) + m_upper = new AreaBoundItem(this, series); + else + m_upper = 0; + if (m_upper) { + m_upper->setPresenter(presenter()); + fixEdgeSeriesDomain(m_upper); + } else { + updatePath(); + } +} + +void AreaChartItem::setLowerSeries(QLineSeries *series) +{ + delete m_lower; + if (series) + m_lower = new AreaBoundItem(this, series); + else + m_lower = 0; + if (m_lower) { + m_lower->setPresenter(presenter()); + fixEdgeSeriesDomain(m_lower); + } else { + updatePath(); } - ChartItem::setPresenter(presenter); } QRectF AreaChartItem::boundingRect() const @@ -116,31 +145,34 @@ void AreaChartItem::updatePath() QPainterPath path; QRectF rect(QPointF(0,0),domain()->size()); - path = m_upper->path(); - - if (m_lower) { - // Note: Polarcharts always draw area correctly only when both series have equal width or are - // fully displayed. If one series is partally off-chart, the connecting line between - // the series does not attach to the end of the partially hidden series but to the point - // where it intersects the axis line. The problem is especially noticeable when one of the series - // is entirely off-chart, in which case the connecting line connects two ends of the - // visible series. - // This happens because we get the paths from linechart, which omits off-chart segments. - // To properly fix, linechart would need to provide true full path, in right, left, and the rest - // portions to enable proper clipping. However, combining those to single visually unified area - // would be a nightmare, since they would have to be painted separately. - path.connectPath(m_lower->path().toReversed()); - } else { - QPointF first = path.pointAtPercent(0); - QPointF last = path.pointAtPercent(1); - if (presenter()->chartType() == QChart::ChartTypeCartesian) { - path.lineTo(last.x(), rect.bottom()); - path.lineTo(first.x(), rect.bottom()); - } else { // polar - path.lineTo(rect.center()); + if (m_upper) { + path = m_upper->path(); + + if (m_lower) { + // Note: Polarcharts draw area correctly only when both series have equal width or are + // fully displayed. If one series is partally off-chart, the connecting line between + // the series does not attach to the end of the partially hidden series but to the point + // where it intersects the axis line. The problem is especially noticeable when one of + // the series is entirely off-chart, in which case the connecting line connects two + // ends of the visible series. + // This happens because we get the paths from linechart, which omits off-chart segments. + // To properly fix, linechart would need to provide true full path, in right, left, + // and the rest portions to enable proper clipping. However, combining those to single + // visually unified area would be a nightmare, since they would have to be painted + // separately. + path.connectPath(m_lower->path().toReversed()); + } else { + QPointF first = path.pointAtPercent(0); + QPointF last = path.pointAtPercent(1); + if (presenter()->chartType() == QChart::ChartTypeCartesian) { + path.lineTo(last.x(), rect.bottom()); + path.lineTo(first.x(), rect.bottom()); + } else { // polar + path.lineTo(rect.center()); + } } + path.closeSubpath(); } - path.closeSubpath(); // Only zoom in if the bounding rect of the path fits inside int limits. QWidget::update() uses // a region that has to be compatible with QRect. @@ -199,6 +231,7 @@ void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt { Q_UNUSED(widget) Q_UNUSED(option) + painter->save(); painter->setPen(m_linePen); painter->setBrush(m_brush); @@ -211,7 +244,8 @@ void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt painter->drawPath(m_path); if (m_pointsVisible) { painter->setPen(m_pointPen); - painter->drawPoints(m_upper->geometryPoints()); + if (m_upper) + painter->drawPoints(m_upper->geometryPoints()); if (m_lower) painter->drawPoints(m_lower->geometryPoints()); } @@ -275,7 +309,7 @@ void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt void AreaChartItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { - emit pressed(m_upper->domain()->calculateDomainPoint(event->pos())); + emit pressed(domain()->calculateDomainPoint(event->pos())); m_lastMousePos = event->pos(); m_mousePressed = true; ChartItem::mousePressEvent(event); @@ -297,16 +331,16 @@ void AreaChartItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) void AreaChartItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { - emit released(m_upper->domain()->calculateDomainPoint(m_lastMousePos)); + emit released(domain()->calculateDomainPoint(m_lastMousePos)); if (m_mousePressed) - emit clicked(m_upper->domain()->calculateDomainPoint(m_lastMousePos)); + emit clicked(domain()->calculateDomainPoint(m_lastMousePos)); m_mousePressed = false; ChartItem::mouseReleaseEvent(event); } void AreaChartItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { - emit doubleClicked(m_upper->domain()->calculateDomainPoint(m_lastMousePos)); + emit doubleClicked(domain()->calculateDomainPoint(m_lastMousePos)); ChartItem::mouseDoubleClickEvent(event); } diff --git a/src/charts/areachart/areachartitem_p.h b/src/charts/areachart/areachartitem_p.h index a36315ed..be943877 100644 --- a/src/charts/areachart/areachartitem_p.h +++ b/src/charts/areachart/areachartitem_p.h @@ -68,6 +68,9 @@ public: void setPresenter(ChartPresenter *presenter); QAreaSeries *series() const { return m_series; } + void setUpperSeries(QLineSeries *series); + void setLowerSeries(QLineSeries *series); + protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); void hoverEnterEvent(QGraphicsSceneHoverEvent *event); diff --git a/src/charts/areachart/qareaseries.cpp b/src/charts/areachart/qareaseries.cpp index ebff7f0f..739efd71 100644 --- a/src/charts/areachart/qareaseries.cpp +++ b/src/charts/areachart/qareaseries.cpp @@ -406,13 +406,18 @@ QAbstractSeries::SeriesType QAreaSeries::type() const /*! Sets the \a series that is to be used as the area chart upper series. + If the upper series is null, the area chart is not drawn, even if it has a lower series. */ void QAreaSeries::setUpperSeries(QLineSeries *series) { Q_D(QAreaSeries); + if (d->m_upperSeries != series) { - series->d_ptr->setBlockOpenGL(true); + if (series) + series->d_ptr->setBlockOpenGL(true); d->m_upperSeries = series; + if (!d->m_item.isNull()) + static_cast<AreaChartItem *>(d->m_item.data())->setUpperSeries(series); } } @@ -428,8 +433,13 @@ QLineSeries *QAreaSeries::upperSeries() const void QAreaSeries::setLowerSeries(QLineSeries *series) { Q_D(QAreaSeries); - series->d_ptr->setBlockOpenGL(true); - d->m_lowerSeries = series; + if (d->m_lowerSeries != series) { + if (series) + series->d_ptr->setBlockOpenGL(true); + d->m_lowerSeries = series; + if (!d->m_item.isNull()) + static_cast<AreaChartItem *>(d->m_item.data())->setLowerSeries(series); + } } QLineSeries *QAreaSeries::lowerSeries() const diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index e8cad75c..35f93556 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -23,6 +23,7 @@ SUBDIRS += \ domain \ chartdataset \ qlegend \ + qareaseries \ cmake !contains(QT_COORD_TYPE, float): { diff --git a/tests/auto/qareaseries/qareaseries.pro b/tests/auto/qareaseries/qareaseries.pro new file mode 100644 index 00000000..a87857ab --- /dev/null +++ b/tests/auto/qareaseries/qareaseries.pro @@ -0,0 +1,4 @@ +!include( ../auto.pri ) { + error( "Couldn't find the auto.pri file!" ) +} +SOURCES += tst_qareaseries.cpp diff --git a/tests/auto/qareaseries/tst_qareaseries.cpp b/tests/auto/qareaseries/tst_qareaseries.cpp new file mode 100644 index 00000000..e03989c0 --- /dev/null +++ b/tests/auto/qareaseries/tst_qareaseries.cpp @@ -0,0 +1,183 @@ +/****************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Charts module. +** +** $QT_BEGIN_LICENSE:COMM$ +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** $QT_END_LICENSE$ +** +******************************************************************************/ + +#include <QtTest/QtTest> +#include <QtGui/QImage> +#include <QtCharts/QChartView> +#include <QtCharts/QAreaSeries> +#include <QtCharts/QLineSeries> +#include <QtCharts/QChartView> +#include <QtCharts/QValueAxis> +#include <tst_definitions.h> + +QT_CHARTS_USE_NAMESPACE + +class tst_QAreaSeries : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); +private slots: + void areaSeries(); + void dynamicEdgeSeriesChange(); + +protected: + QLineSeries *createUpperSeries(); + QLineSeries *createLowerSeries(); + void checkPixels(const QColor &upperColor, const QColor ¢erColor, const QColor &lowerColor); + + QChartView *m_view; + QChart *m_chart; + QColor m_brushColor; + QColor m_backgroundColor; + QValueAxis *m_axisX; + QValueAxis *m_axisY; +}; + +void tst_QAreaSeries::initTestCase() +{ + m_brushColor = QColor("#123456"); + m_backgroundColor = QColor("#abcfef"); +} + +void tst_QAreaSeries::cleanupTestCase() +{ + QTest::qWait(1); // Allow final deleteLaters to run +} + +void tst_QAreaSeries::init() +{ + m_view = new QChartView(newQChartOrQPolarChart()); + m_view->setGeometry(0, 0, 400, 400); + m_chart = m_view->chart(); + m_chart->setBackgroundBrush(m_backgroundColor); + m_chart->legend()->setVisible(false); + m_axisX = new QValueAxis; + m_axisY = new QValueAxis; + m_axisX->setRange(0, 4); + m_axisY->setRange(0, 10); + m_chart->addAxis(m_axisX, Qt::AlignBottom); + m_chart->addAxis(m_axisY, Qt::AlignRight); +} + +void tst_QAreaSeries::cleanup() +{ + delete m_view; + m_view = 0; + m_chart = 0; +} + +void tst_QAreaSeries::areaSeries() +{ + QLineSeries *series0 = createUpperSeries(); + QLineSeries *series1 = createLowerSeries(); + QAreaSeries *series = new QAreaSeries(series0, series1); + + QCOMPARE(series->brush(), QBrush()); + QCOMPARE(series->pen(), QPen()); + QCOMPARE(series->pointsVisible(), false); + QCOMPARE(series->pointLabelsVisible(), false); + QCOMPARE(series->pointLabelsFormat(), QLatin1String("@xPoint, @yPoint")); + QCOMPARE(series->pointLabelsClipping(), true); + QCOMPARE(series->pointLabelsColor(), QPen().color()); + QCOMPARE(series->upperSeries(), series0); + QCOMPARE(series->lowerSeries(), series1); + QCOMPARE(series->color(), QPen().color()); + QCOMPARE(series->borderColor(), QPen().color()); + + series->setBrush(QBrush(m_brushColor)); + m_chart->addSeries(series); + series->attachAxis(m_axisX); + series->attachAxis(m_axisY); + m_view->show(); + QTest::qWaitForWindowShown(m_view); + + checkPixels(m_backgroundColor, m_brushColor, m_backgroundColor); +} + +void tst_QAreaSeries::dynamicEdgeSeriesChange() +{ + QAreaSeries *series = new QAreaSeries; + series->setBrush(QBrush(m_brushColor)); + + m_chart->addSeries(series); + series->attachAxis(m_axisX); + series->attachAxis(m_axisY); + m_view->show(); + QTest::qWaitForWindowShown(m_view); + + checkPixels(m_backgroundColor, m_backgroundColor, m_backgroundColor); + + QLineSeries *series0 = createUpperSeries(); + series->setUpperSeries(series0); + + QApplication::processEvents(); + checkPixels(m_backgroundColor, m_brushColor, m_brushColor); + + QLineSeries *series1 = createLowerSeries(); + series->setLowerSeries(series1); + + QApplication::processEvents(); + checkPixels(m_backgroundColor, m_brushColor, m_backgroundColor); + + series->setLowerSeries(nullptr); + + QApplication::processEvents(); + checkPixels(m_backgroundColor, m_brushColor, m_brushColor); + + series->setUpperSeries(nullptr); + + QApplication::processEvents(); + checkPixels(m_backgroundColor, m_backgroundColor, m_backgroundColor); +} + +QLineSeries *tst_QAreaSeries::createUpperSeries() +{ + QLineSeries *series = new QLineSeries(); + *series << QPointF(0, 10) << QPointF(1, 7) << QPointF(2, 6) << QPointF(3, 7) << QPointF(4, 10); + return series; +} + +QLineSeries *tst_QAreaSeries::createLowerSeries() +{ + QLineSeries *series = new QLineSeries(); + *series << QPointF(0, 0) << QPointF(1, 3) << QPointF(2, 4) << QPointF(3, 3) << QPointF(4, 0); + return series; +} + +void tst_QAreaSeries::checkPixels(const QColor &upperColor, + const QColor ¢erColor, + const QColor &lowerColor) +{ + QImage screenGrab = m_view->grab().toImage(); + QCOMPARE(QColor(screenGrab.pixel(200, 50)), upperColor); + QCOMPARE(QColor(screenGrab.pixel(200, 200)), centerColor); + QCOMPARE(QColor(screenGrab.pixel(200, 350)), lowerColor); +} + +QTEST_MAIN(tst_QAreaSeries) + +#include "tst_qareaseries.moc" + |