diff options
Diffstat (limited to 'src/chartsqml2/declarativechart.cpp')
-rw-r--r-- | src/chartsqml2/declarativechart.cpp | 1063 |
1 files changed, 1063 insertions, 0 deletions
diff --git a/src/chartsqml2/declarativechart.cpp b/src/chartsqml2/declarativechart.cpp new file mode 100644 index 00000000..d2044ed0 --- /dev/null +++ b/src/chartsqml2/declarativechart.cpp @@ -0,0 +1,1063 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 Enterprise Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise 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 "declarativechart.h" +#include <QPainter> +#include "declarativelineseries.h" +#include "declarativeareaseries.h" +#include "declarativebarseries.h" +#include "declarativepieseries.h" +#include "declarativesplineseries.h" +#include "declarativeboxplotseries.h" +#include "declarativescatterseries.h" +#include "qbarcategoryaxis.h" +#include "qvalueaxis.h" +#include "qlogvalueaxis.h" +#include "qcategoryaxis.h" +#include "qabstractseries_p.h" +#include "declarativemargins.h" +#include "chartdataset_p.h" +#include "declarativeaxes.h" +#include "qchart_p.h" +#include "qpolarchart.h" + +#ifndef QT_ON_ARM + #include "qdatetimeaxis.h" +#endif + +#include <QGraphicsSceneMouseEvent> +#include <QGraphicsSceneHoverEvent> +#include <QApplication> +#include <QTimer> +#include <QThread> + +QT_CHARTS_BEGIN_NAMESPACE + +/*! + \qmltype ChartView + \instantiates DeclarativeChart + \inqmlmodule QtCharts + + ChartView element is the parent that is responsible for showing different chart series types. + + The following QML shows how to create a simple chart with one pie series: + \snippet qmlpiechart/qml/qmlpiechart/main.qml 1 + \snippet qmlpiechart/qml/qmlpiechart/main.qml 2 + \snippet qmlpiechart/qml/qmlpiechart/main.qml 3 + + \beginfloatleft + \image examples_qmlpiechart.png + \endfloat + \clearfloat +*/ + +/*! + \qmlproperty Theme ChartView::theme + Theme defines the visual appearance of the chart, including for example colors, fonts, line + widths and chart background. +*/ + +/*! + \qmlproperty Animation ChartView::animationOptions + Animation configuration of the chart. One of ChartView.NoAnimation, ChartView.GridAxisAnimations, + ChartView.SeriesAnimations or ChartView.AllAnimations. +*/ + +/*! + \qmlproperty Font ChartView::titleFont + The title font of the chart. + + See the Qt documentation for more details of Font. +*/ + +/*! + \qmlproperty string ChartView::title + The title of the chart, shown on top of the chart. + \sa ChartView::titleColor +*/ + +/*! + \qmlproperty color ChartView::titleColor + The color of the title text. +*/ + +/*! + \qmlproperty Legend ChartView::legend + The legend of the chart. Legend lists all the series, pie slices and bar sets added on the chart. +*/ + +/*! + \qmlproperty int ChartView::count + The count of series added to the chart. +*/ + +/*! + \qmlproperty color ChartView::backgroundColor + The color of the chart's background. By default background color is defined by chart theme. + \sa ChartView::theme +*/ + +/*! + \qmlproperty real ChartView::backgroundRoundness + The diameter of the rounding cirle at the corners of the chart background. +*/ + +/*! + \qmlproperty color ChartView::plotAreaColor + The color of the background of the chart's plot area. By default plot area background uses chart's + background color. + \sa ChartView::backgroundColor +*/ + +/*! + \qmlproperty bool ChartView::dropShadowEnabled + The chart's border drop shadow. Set to true to enable drop shadow. +*/ + +/*! + \qmlproperty real ChartView::topMargin + Deprecated; use margins instead. +*/ + +/*! + \qmlproperty real ChartView::bottomMargin + Deprecated; use margins instead. +*/ + +/*! + \qmlproperty real ChartView::leftMargin + Deprecated; use margins instead. +*/ + +/*! + \qmlproperty real ChartView::rightMargin + Deprecated; use margins instead. +*/ + +/*! + \qmlproperty Margins ChartView::minimumMargins + Deprecated; use margins instead. + The minimum margins allowed between the outer bounds and the plotArea of the ChartView. Margins + area of ChartView is used for drawing title, axes and legend. Please note that setting the + properties of minimumMargins may be bigger than the defined value, depending on other ChartView + properties that affect it's layout. If you need to know the actual plotting area used at any + given time, you can check ChartView::plotArea instead. +*/ + +/*! + \qmlproperty rect ChartView::plotArea + The area on the ChartView that is used for drawing series. This is the ChartView rect without the + margins. + \sa ChartView::minimumMargins +*/ + +/*! + \qmlproperty Margins ChartView::margins + The minimum margins allowed between the outer bounds and the plotArea of the ChartView. Margins + area of ChartView is used for drawing title, axes and legend. +*/ + +/*! + \qmlproperty bool ChartView::localizeNumbers + \since QtCharts 2.0 + When \c{true}, all generated numbers appearing in various series and axis labels will be + localized using the default QLocale of the application, which defaults to the system locale. + When \c{false}, the "C" locale is always used. + Defaults to \c{false}. + + \sa locale +*/ + +/*! + \qmlproperty locale ChartView::locale + \since QtCharts 2.0 + Sets the locale used to format various chart labels when localizeNumbers is \c{true}. + This also determines the locale used to format DateTimeAxis labels regardless of + localizeNumbers property. + Defaults to application default locale at the time the chart is constructed. + + \sa localizeNumbers +*/ + +/*! + \qmlmethod AbstractSeries ChartView::series(int index) + Returns the series with \a index on the chart. This allows you to loop through the series of a chart together with + the count property of the chart. +*/ + +/*! + \qmlmethod AbstractSeries ChartView::series(string name) + Returns the first series on the chart with \a name. If there is no series with that name, returns null. +*/ + +/*! + \qmlmethod AbstractSeries ChartView::createSeries(SeriesType type, string name, AbstractAxis axisX, AbstractAxis axisY) + Creates a series object of \a type to the chart with name \a name, optional axis \a axisX and + optional axis \a axisY. For example: + \code + // lineSeries is a LineSeries object that has already been added to the ChartView; re-use it's axes + var myAxisX = chartView.axisX(lineSeries); + var myAxisY = chartView.axisY(lineSeries); + var scatter = chartView.createSeries(ChartView.SeriesTypeScatter, "scatter series", myAxisX, myAxisY); + \endcode +*/ + +/*! + \qmlmethod ChartView::removeSeries(AbstractSeries series) + Removes the \a series from the chart. The series object is also destroyed. +*/ + +/*! + \qmlmethod ChartView::removeAllSeries() + Removes all series from the chart. All the series objects are also destroyed. +*/ + +/*! + \qmlmethod Axis ChartView::axisX(AbstractSeries series) + The x-axis of the series. +*/ + +/*! + \qmlmethod Axis ChartView::axisY(AbstractSeries series) + The y-axis of the series. +*/ + +/*! + \qmlmethod ChartView::zoomY(real factor) + Zooms in by \a factor on the center of the chart. +*/ + +/*! + \qmlmethod ChartView::scrollLeft(real pixels) + Scrolls to left by \a pixels. This is a convenience function that suits for example for key navigation. +*/ + +/*! + \qmlmethod ChartView::scrollRight(real pixels) + Scrolls to right by \a pixels. This is a convenience function that suits for example for key navigation. +*/ + +/*! + \qmlmethod ChartView::scrollUp(real pixels) + Scrolls up by \a pixels. This is a convenience function that suits for example for key navigation. +*/ + +/*! + \qmlmethod ChartView::scrollDown(real pixels) + Scrolls down by \a pixels. This is a convenience function that suits for example for key navigation. +*/ + +/*! + \qmlsignal ChartView::onPlotAreaChanged(rect plotArea) + The plot area of the chart has changed. This may happen for example, if you modify minimumMargins + or if you resize the chart, or if you modify font size related properties of the legend or chart + title. +*/ + +/*! + \qmlsignal ChartView::seriesAdded(AbstractSeries series) + The \a series has been added to the chart. +*/ + +/*! + \qmlsignal ChartView::seriesRemoved(AbstractSeries series) + The \a series has been removed from the chart. Please note that \a series is no longer a valid + object after the signal handler has completed. +*/ + +DeclarativeChart::DeclarativeChart(QQuickItem *parent) + : QQuickPaintedItem(parent) +{ + initChart(QChart::ChartTypeCartesian); +} + +DeclarativeChart::DeclarativeChart(QChart::ChartType type, QQuickItem *parent) + : QQuickPaintedItem(parent) +{ + initChart(type); +} + +void DeclarativeChart::initChart(QChart::ChartType type) +{ + m_currentSceneImage = 0; + m_guiThreadId = QThread::currentThreadId(); + m_paintThreadId = 0; + m_updatePending = false; + + if (type == QChart::ChartTypePolar) + m_chart = new QPolarChart(); + else + m_chart = new QChart(); + + m_scene = new QGraphicsScene(this); + m_scene->addItem(m_chart); + + setAntialiasing(QQuickItem::antialiasing()); + connect(m_scene, SIGNAL(changed(QList<QRectF>)), this, SLOT(sceneChanged(QList<QRectF>))); + connect(this, SIGNAL(antialiasingChanged(bool)), this, SLOT(handleAntialiasingChanged(bool))); + + setAcceptedMouseButtons(Qt::AllButtons); + setAcceptHoverEvents(true); + + m_margins = new DeclarativeMargins(this); + m_margins->setTop(m_chart->margins().top()); + m_margins->setLeft(m_chart->margins().left()); + m_margins->setRight(m_chart->margins().right()); + m_margins->setBottom(m_chart->margins().bottom()); + connect(m_margins, SIGNAL(topChanged(int,int,int,int)), this, SLOT(changeMinimumMargins(int,int,int,int))); + connect(m_margins, SIGNAL(bottomChanged(int,int,int,int)), this, SLOT(changeMinimumMargins(int,int,int,int))); + connect(m_margins, SIGNAL(leftChanged(int,int,int,int)), this, SLOT(changeMinimumMargins(int,int,int,int))); + connect(m_margins, SIGNAL(rightChanged(int,int,int,int)), this, SLOT(changeMinimumMargins(int,int,int,int))); + connect(m_chart->d_ptr->m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)), this, SLOT(handleSeriesAdded(QAbstractSeries*))); + connect(m_chart->d_ptr->m_dataset, SIGNAL(seriesRemoved(QAbstractSeries*)), this, SIGNAL(seriesRemoved(QAbstractSeries*))); +} + +void DeclarativeChart::handleSeriesAdded(QAbstractSeries *series) +{ + emit seriesAdded(series); +} + +void DeclarativeChart::changeMinimumMargins(int top, int bottom, int left, int right) +{ + m_chart->setMargins(QMargins(left, top, right, bottom)); + emit minimumMarginsChanged(); + emit plotAreaChanged(m_chart->plotArea()); +} + +DeclarativeChart::~DeclarativeChart() +{ + delete m_chart; + m_sceneImageLock.lock(); + delete m_currentSceneImage; + m_currentSceneImage = 0; + m_sceneImageLock.unlock(); +} + +void DeclarativeChart::childEvent(QChildEvent *event) +{ + if (event->type() == QEvent::ChildAdded) { + if (qobject_cast<QAbstractSeries *>(event->child())) { + m_chart->addSeries(qobject_cast<QAbstractSeries *>(event->child())); + } + } +} + +void DeclarativeChart::componentComplete() +{ + foreach (QObject *child, children()) { + if (qobject_cast<QAbstractSeries *>(child)) { + // Add series to the chart + QAbstractSeries *series = qobject_cast<QAbstractSeries *>(child); + m_chart->addSeries(series); + + // Connect to axis changed signals (unless this is a pie series) + if (!qobject_cast<DeclarativePieSeries *>(series)) { + connect(series, SIGNAL(axisXChanged(QAbstractAxis*)), this, SLOT(handleAxisXSet(QAbstractAxis*))); + connect(series, SIGNAL(axisXTopChanged(QAbstractAxis*)), this, SLOT(handleAxisXTopSet(QAbstractAxis*))); + connect(series, SIGNAL(axisYChanged(QAbstractAxis*)), this, SLOT(handleAxisYSet(QAbstractAxis*))); + connect(series, SIGNAL(axisYRightChanged(QAbstractAxis*)), this, SLOT(handleAxisYRightSet(QAbstractAxis*))); + } + + initializeAxes(series); + } + } + + QQuickItem::componentComplete(); +} + +void DeclarativeChart::handleAxisXSet(QAbstractAxis *axis) +{ + QAbstractSeries *s = qobject_cast<QAbstractSeries *>(sender()); + if (axis && s) { + if (!m_chart->axes(Qt::Horizontal).contains(axis)) + m_chart->setAxisX(axis, s); + if (!s->attachedAxes().contains(axis)) + s->attachAxis(axis); + } else { + qWarning() << "Trying to set axisX to null."; + } +} + +void DeclarativeChart::handleAxisXTopSet(QAbstractAxis *axis) +{ + QAbstractSeries *s = qobject_cast<QAbstractSeries *>(sender()); + if (axis && s) { + if (!m_chart->axes(Qt::Horizontal).contains(axis)) { + QList<QAbstractAxis *> oldAxes = m_chart->axes(Qt::Horizontal, s); + foreach (QAbstractAxis* a, oldAxes) { + m_chart->removeAxis(a); + delete a; + } + m_chart->addAxis(axis, Qt::AlignTop); + } + if (!s->attachedAxes().contains(axis)) + s->attachAxis(axis); + } else { + qWarning() << "Trying to set axisXTop to null."; + } +} + +void DeclarativeChart::handleAxisYSet(QAbstractAxis *axis) +{ + QAbstractSeries *s = qobject_cast<QAbstractSeries *>(sender()); + if (axis && s) { + if (!m_chart->axes(Qt::Vertical).contains(axis)) + m_chart->setAxisY(axis, s); + if (!s->attachedAxes().contains(axis)) + s->attachAxis(axis); + } else { + qWarning() << "Trying to set axisY to null."; + } +} + +void DeclarativeChart::handleAxisYRightSet(QAbstractAxis *axis) +{ + QAbstractSeries *s = qobject_cast<QAbstractSeries *>(sender()); + if (axis && s) { + if (!m_chart->axes(Qt::Vertical).contains(axis)) { + QList<QAbstractAxis *> oldAxes = m_chart->axes((Qt::Vertical), s); + foreach (QAbstractAxis* a, oldAxes) { + m_chart->removeAxis(a); + delete a; + } + m_chart->addAxis(axis, Qt::AlignRight); + } + if (!s->attachedAxes().contains(axis)) + s->attachAxis(axis); + } else { + qWarning() << "Trying to set axisYRight to null."; + } +} + +void DeclarativeChart::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + if (newGeometry.isValid()) { + if (newGeometry.width() > 0 && newGeometry.height() > 0) { + m_chart->resize(newGeometry.width(), newGeometry.height()); + } + } + QQuickItem::geometryChanged(newGeometry, oldGeometry); + + // It would be better to trigger the plotAreaChanged signal from QChart::plotAreaChanged or + // similar. Since that kind of a signal is not clearly needed in the C++ API the work-around is + // to implement it here for the QML API purposes. + emit plotAreaChanged(m_chart->plotArea()); +} + +void DeclarativeChart::sceneChanged(QList<QRectF> region) +{ + Q_UNUSED(region); + + if (m_guiThreadId == m_paintThreadId) { + // Rendering in gui thread, no need for shenannigans, just update + update(); + } else { + // Multi-threaded rendering, need to ensure scene is actually rendered in gui thread + if (!m_updatePending) { + m_updatePending = true; + // Do async render to avoid some unnecessary renders. + QTimer::singleShot(0, this, SLOT(renderScene())); + } + } +} + +void DeclarativeChart::renderScene() +{ + m_updatePending = false; + m_sceneImageLock.lock(); + delete m_currentSceneImage; + m_currentSceneImage = new QImage(m_chart->size().toSize(), QImage::Format_ARGB32); + m_currentSceneImage->fill(Qt::transparent); + QPainter painter(m_currentSceneImage); + if (antialiasing()) + painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform); + QRect renderRect(QPoint(0, 0), m_chart->size().toSize()); + m_scene->render(&painter, renderRect, renderRect); + m_sceneImageLock.unlock(); + + update(); +} + +void DeclarativeChart::paint(QPainter *painter) +{ + if (!m_paintThreadId) { + m_paintThreadId = QThread::currentThreadId(); + if (m_guiThreadId == m_paintThreadId) { + // No need for scene image in single threaded rendering, so delete + // the one that got made by default before the rendering type was + // detected. + delete m_currentSceneImage; + m_currentSceneImage = 0; + } + } + + if (m_guiThreadId == m_paintThreadId) { + QRectF renderRect(QPointF(0, 0), m_chart->size()); + m_scene->render(painter, renderRect, renderRect); + } else { + m_sceneImageLock.lock(); + if (m_currentSceneImage) { + QRect imageRect(QPoint(0, 0), m_currentSceneImage->size()); + QRect itemRect(QPoint(0, 0), QSize(width(), height())); + painter->drawImage(itemRect, *m_currentSceneImage, imageRect); + } + m_sceneImageLock.unlock(); + } +} + +void DeclarativeChart::mousePressEvent(QMouseEvent *event) +{ + m_mousePressScenePoint = event->pos(); + m_mousePressScreenPoint = event->globalPos(); + m_lastMouseMoveScenePoint = m_mousePressScenePoint; + m_lastMouseMoveScreenPoint = m_mousePressScreenPoint; + m_mousePressButton = event->button(); + m_mousePressButtons = event->buttons(); + + QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMousePress); + mouseEvent.setWidget(0); + mouseEvent.setButtonDownScenePos(m_mousePressButton, m_mousePressScenePoint); + mouseEvent.setButtonDownScreenPos(m_mousePressButton, m_mousePressScreenPoint); + mouseEvent.setScenePos(m_mousePressScenePoint); + mouseEvent.setScreenPos(m_mousePressScreenPoint); + mouseEvent.setLastScenePos(m_lastMouseMoveScenePoint); + mouseEvent.setLastScreenPos(m_lastMouseMoveScreenPoint); + mouseEvent.setButtons(m_mousePressButtons); + mouseEvent.setButton(m_mousePressButton); + mouseEvent.setModifiers(event->modifiers()); + mouseEvent.setAccepted(false); + + QApplication::sendEvent(m_scene, &mouseEvent); +} + +void DeclarativeChart::mouseReleaseEvent(QMouseEvent *event) +{ + QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseRelease); + mouseEvent.setWidget(0); + mouseEvent.setButtonDownScenePos(m_mousePressButton, m_mousePressScenePoint); + mouseEvent.setButtonDownScreenPos(m_mousePressButton, m_mousePressScreenPoint); + mouseEvent.setScenePos(event->pos()); + mouseEvent.setScreenPos(event->globalPos()); + mouseEvent.setLastScenePos(m_lastMouseMoveScenePoint); + mouseEvent.setLastScreenPos(m_lastMouseMoveScreenPoint); + mouseEvent.setButtons(event->buttons()); + mouseEvent.setButton(event->button()); + mouseEvent.setModifiers(event->modifiers()); + mouseEvent.setAccepted(false); + + QApplication::sendEvent(m_scene, &mouseEvent); + + m_mousePressButtons = event->buttons(); + m_mousePressButton = Qt::NoButton; +} + +void DeclarativeChart::hoverMoveEvent(QHoverEvent *event) +{ + // Convert hover move to mouse move, since we don't seem to get actual mouse move events. + // QGraphicsScene generates hover events from mouse move events, so we don't need + // to pass hover events there. + QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove); + mouseEvent.setWidget(0); + mouseEvent.setButtonDownScenePos(m_mousePressButton, m_mousePressScenePoint); + mouseEvent.setButtonDownScreenPos(m_mousePressButton, m_mousePressScreenPoint); + mouseEvent.setScenePos(event->pos()); + // Hover events do not have global pos in them, and the screen position doesn't seem to + // matter anyway in this use case, so just pass event pos instead of trying to + // calculate the real screen position. + mouseEvent.setScreenPos(event->pos()); + mouseEvent.setLastScenePos(m_lastMouseMoveScenePoint); + mouseEvent.setLastScreenPos(m_lastMouseMoveScreenPoint); + mouseEvent.setButtons(m_mousePressButtons); + mouseEvent.setButton(m_mousePressButton); + mouseEvent.setModifiers(event->modifiers()); + m_lastMouseMoveScenePoint = mouseEvent.scenePos(); + m_lastMouseMoveScreenPoint = mouseEvent.screenPos(); + mouseEvent.setAccepted(false); + + QApplication::sendEvent(m_scene, &mouseEvent); +} + +void DeclarativeChart::handleAntialiasingChanged(bool enable) +{ + setAntialiasing(enable); +} + +void DeclarativeChart::setTheme(DeclarativeChart::Theme theme) +{ + QChart::ChartTheme chartTheme = (QChart::ChartTheme) theme; + if (chartTheme != m_chart->theme()) + m_chart->setTheme(chartTheme); +} + +DeclarativeChart::Theme DeclarativeChart::theme() +{ + return (DeclarativeChart::Theme) m_chart->theme(); +} + +void DeclarativeChart::setAnimationOptions(DeclarativeChart::Animation animations) +{ + QChart::AnimationOption animationOptions = (QChart::AnimationOption) animations; + if (animationOptions != m_chart->animationOptions()) + m_chart->setAnimationOptions(animationOptions); +} + +DeclarativeChart::Animation DeclarativeChart::animationOptions() +{ + if (m_chart->animationOptions().testFlag(QChart::AllAnimations)) + return DeclarativeChart::AllAnimations; + else if (m_chart->animationOptions().testFlag(QChart::GridAxisAnimations)) + return DeclarativeChart::GridAxisAnimations; + else if (m_chart->animationOptions().testFlag(QChart::SeriesAnimations)) + return DeclarativeChart::SeriesAnimations; + else + return DeclarativeChart::NoAnimation; +} + +void DeclarativeChart::setTitle(QString title) +{ + if (title != m_chart->title()) + m_chart->setTitle(title); +} +QString DeclarativeChart::title() +{ + return m_chart->title(); +} + +QAbstractAxis *DeclarativeChart::axisX(QAbstractSeries *series) +{ + QList<QAbstractAxis *> axes = m_chart->axes(Qt::Horizontal, series); + if (axes.count()) + return axes[0]; + return 0; +} + +QAbstractAxis *DeclarativeChart::axisY(QAbstractSeries *series) +{ + QList<QAbstractAxis *> axes = m_chart->axes(Qt::Vertical, series); + if (axes.count()) + return axes[0]; + return 0; +} + +QLegend *DeclarativeChart::legend() +{ + return m_chart->legend(); +} + +void DeclarativeChart::setTitleColor(QColor color) +{ + QBrush b = m_chart->titleBrush(); + if (color != b.color()) { + b.setColor(color); + m_chart->setTitleBrush(b); + emit titleColorChanged(color); + } +} + +QFont DeclarativeChart::titleFont() const +{ + return m_chart->titleFont(); +} + +void DeclarativeChart::setTitleFont(const QFont &font) +{ + m_chart->setTitleFont(font); +} + +QColor DeclarativeChart::titleColor() +{ + return m_chart->titleBrush().color(); +} + +void DeclarativeChart::setBackgroundColor(QColor color) +{ + QBrush b = m_chart->backgroundBrush(); + if (b.style() != Qt::SolidPattern || color != b.color()) { + b.setStyle(Qt::SolidPattern); + b.setColor(color); + m_chart->setBackgroundBrush(b); + emit backgroundColorChanged(); + } +} + +QColor DeclarativeChart::backgroundColor() +{ + return m_chart->backgroundBrush().color(); +} + +void QtCharts::DeclarativeChart::setPlotAreaColor(QColor color) +{ + QBrush b = m_chart->plotAreaBackgroundBrush(); + if (b.style() != Qt::SolidPattern || color != b.color()) { + b.setStyle(Qt::SolidPattern); + b.setColor(color); + m_chart->setPlotAreaBackgroundBrush(b); + m_chart->setPlotAreaBackgroundVisible(true); + emit plotAreaColorChanged(); + } +} + +QColor QtCharts::DeclarativeChart::plotAreaColor() +{ + return m_chart->plotAreaBackgroundBrush().color(); +} + +void DeclarativeChart::setLocalizeNumbers(bool localize) +{ + if (m_chart->localizeNumbers() != localize) { + m_chart->setLocalizeNumbers(localize); + emit localizeNumbersChanged(); + } +} + +bool DeclarativeChart::localizeNumbers() const +{ + return m_chart->localizeNumbers(); +} + +void QtCharts::DeclarativeChart::setLocale(const QLocale &locale) +{ + if (m_chart->locale() != locale) { + m_chart->setLocale(locale); + emit localeChanged(); + } +} + +QLocale QtCharts::DeclarativeChart::locale() const +{ + return m_chart->locale(); +} + +int DeclarativeChart::count() +{ + return m_chart->series().count(); +} + +void DeclarativeChart::setDropShadowEnabled(bool enabled) +{ + if (enabled != m_chart->isDropShadowEnabled()) { + m_chart->setDropShadowEnabled(enabled); + dropShadowEnabledChanged(enabled); + } +} + +bool DeclarativeChart::dropShadowEnabled() +{ + return m_chart->isDropShadowEnabled(); +} + +qreal DeclarativeChart::backgroundRoundness() const +{ + return m_chart->backgroundRoundness(); +} + +void DeclarativeChart::setBackgroundRoundness(qreal diameter) +{ + if (m_chart->backgroundRoundness() != diameter) { + m_chart->setBackgroundRoundness(diameter); + emit backgroundRoundnessChanged(diameter); + } +} + +qreal DeclarativeChart::topMargin() +{ + qWarning() << "ChartView.topMargin is deprecated. Use margins instead."; + return m_chart->margins().top(); +} + +qreal DeclarativeChart::bottomMargin() +{ + qWarning() << "ChartView.bottomMargin is deprecated. Use margins instead."; + return m_chart->margins().bottom(); +} + +qreal DeclarativeChart::leftMargin() +{ + qWarning() << "ChartView.leftMargin is deprecated. Use margins instead."; + return m_chart->margins().left(); +} + +qreal DeclarativeChart::rightMargin() +{ + qWarning() << "ChartView.rightMargin is deprecated. Use margins instead."; + return m_chart->margins().right(); +} + +void DeclarativeChart::zoom(qreal factor) +{ + m_chart->zoom(factor); +} + +void DeclarativeChart::scrollLeft(qreal pixels) +{ + m_chart->scroll(-pixels, 0); +} + +void DeclarativeChart::scrollRight(qreal pixels) +{ + m_chart->scroll(pixels, 0); +} + +void DeclarativeChart::scrollUp(qreal pixels) +{ + m_chart->scroll(0, pixels); +} + +void DeclarativeChart::scrollDown(qreal pixels) +{ + m_chart->scroll(0, -pixels); +} + +QQmlListProperty<QAbstractAxis> DeclarativeChart::axes() +{ + return QQmlListProperty<QAbstractAxis>(this, 0, + &DeclarativeChart::axesAppendFunc, + &DeclarativeChart::axesCountFunc, + &DeclarativeChart::axesAtFunc, + &DeclarativeChart::axesClearFunc); +} + +void DeclarativeChart::axesAppendFunc(QQmlListProperty<QAbstractAxis> *list, QAbstractAxis *element) +{ + // Empty implementation + Q_UNUSED(list); + Q_UNUSED(element); +} + +int DeclarativeChart::axesCountFunc(QQmlListProperty<QAbstractAxis> *list) +{ + if (qobject_cast<DeclarativeChart *>(list->object)) { + DeclarativeChart *chart = qobject_cast<DeclarativeChart *>(list->object); + return chart->m_chart->axes(Qt::Horizontal | Qt::Vertical).count(); + } + return 0; +} + +QAbstractAxis *DeclarativeChart::axesAtFunc(QQmlListProperty<QAbstractAxis> *list, int index) +{ + if (qobject_cast<DeclarativeChart *>(list->object)) { + DeclarativeChart *chart = qobject_cast<DeclarativeChart *>(list->object); + QList<QAbstractAxis *> axes = chart->m_chart->axes(Qt::Horizontal | Qt::Vertical, chart->m_chart->series()[0]); + return axes.at(index); + } + return 0; +} + +void DeclarativeChart::axesClearFunc(QQmlListProperty<QAbstractAxis> *list) +{ + // Empty implementation + Q_UNUSED(list); +} + + +QAbstractSeries *DeclarativeChart::series(int index) +{ + if (index < m_chart->series().count()) { + return m_chart->series().at(index); + } + return 0; +} + +QAbstractSeries *DeclarativeChart::series(QString seriesName) +{ + foreach (QAbstractSeries *series, m_chart->series()) { + if (series->name() == seriesName) + return series; + } + return 0; +} + +QAbstractSeries *DeclarativeChart::createSeries(int type, QString name, QAbstractAxis *axisX, QAbstractAxis *axisY) +{ + QAbstractSeries *series = 0; + + switch (type) { + case DeclarativeChart::SeriesTypeLine: + series = new DeclarativeLineSeries(); + break; + case DeclarativeChart::SeriesTypeArea: { + DeclarativeAreaSeries *area = new DeclarativeAreaSeries(); + area->setUpperSeries(new DeclarativeLineSeries()); + series = area; + break; + } + case DeclarativeChart::SeriesTypeStackedBar: + series = new DeclarativeStackedBarSeries(); + break; + case DeclarativeChart::SeriesTypePercentBar: + series = new DeclarativePercentBarSeries(); + break; + case DeclarativeChart::SeriesTypeBar: + series = new DeclarativeBarSeries(); + break; + case DeclarativeChart::SeriesTypeHorizontalBar: + series = new DeclarativeHorizontalBarSeries(); + break; + case DeclarativeChart::SeriesTypeHorizontalPercentBar: + series = new DeclarativeHorizontalPercentBarSeries(); + break; + case DeclarativeChart::SeriesTypeHorizontalStackedBar: + series = new DeclarativeHorizontalStackedBarSeries(); + break; + case DeclarativeChart::SeriesTypeBoxPlot: + series = new DeclarativeBoxPlotSeries(); + break; + case DeclarativeChart::SeriesTypePie: + series = new DeclarativePieSeries(); + break; + case DeclarativeChart::SeriesTypeScatter: + series = new DeclarativeScatterSeries(); + break; + case DeclarativeChart::SeriesTypeSpline: + series = new DeclarativeSplineSeries(); + break; + default: + qWarning() << "Illegal series type"; + } + + if (series) { + // Connect to axis changed signals (unless this is a pie series) + if (!qobject_cast<DeclarativePieSeries *>(series)) { + connect(series, SIGNAL(axisXChanged(QAbstractAxis*)), this, SLOT(handleAxisXSet(QAbstractAxis*))); + connect(series, SIGNAL(axisXTopChanged(QAbstractAxis*)), this, SLOT(handleAxisXSet(QAbstractAxis*))); + connect(series, SIGNAL(axisYChanged(QAbstractAxis*)), this, SLOT(handleAxisYSet(QAbstractAxis*))); + connect(series, SIGNAL(axisYRightChanged(QAbstractAxis*)), this, SLOT(handleAxisYRightSet(QAbstractAxis*))); + } + + series->setName(name); + m_chart->addSeries(series); + + if (axisX) + setAxisX(axisX, series); + if (axisY) + setAxisY(axisY, series); + + if (series->attachedAxes().count() < 2) + initializeAxes(series); + } + + return series; +} + +void DeclarativeChart::removeSeries(QAbstractSeries *series) +{ + if (series) + m_chart->removeSeries(series); + else + qWarning("removeSeries: cannot remove null"); +} + +void DeclarativeChart::setAxisX(QAbstractAxis *axis, QAbstractSeries *series) +{ + if (axis) + m_chart->setAxisX(axis, series); +} + +void DeclarativeChart::setAxisY(QAbstractAxis *axis, QAbstractSeries *series) +{ + if (axis) + m_chart->setAxisY(axis, series); +} + +void DeclarativeChart::createDefaultAxes() +{ + qWarning() << "ChartView.createDefaultAxes() is deprecated. Axes are created automatically."; +} + +QAbstractAxis *DeclarativeChart::defaultAxis(Qt::Orientation orientation, QAbstractSeries *series) +{ + if (!series) { + qWarning() << "No axis type defined for null series"; + return 0; + } + + foreach (QAbstractAxis *existingAxis, m_chart->axes(orientation)) { + if (existingAxis->type() == series->d_ptr->defaultAxisType(orientation)) + return existingAxis; + } + + switch (series->d_ptr->defaultAxisType(orientation)) { + case QAbstractAxis::AxisTypeValue: + return new QValueAxis(this); + case QAbstractAxis::AxisTypeBarCategory: + return new QBarCategoryAxis(this); + case QAbstractAxis::AxisTypeCategory: + return new QCategoryAxis(this); +#ifndef QT_ON_ARM + case QAbstractAxis::AxisTypeDateTime: + return new QDateTimeAxis(this); +#endif + case QAbstractAxis::AxisTypeLogValue: + return new QLogValueAxis(this); + default: + // assume AxisTypeNoAxis + return 0; + } +} + +void DeclarativeChart::initializeAxes(QAbstractSeries *series) +{ + if (qobject_cast<DeclarativeLineSeries *>(series)) + doInitializeAxes(series, qobject_cast<DeclarativeLineSeries *>(series)->m_axes); + else if (qobject_cast<DeclarativeScatterSeries *>(series)) + doInitializeAxes(series, qobject_cast<DeclarativeScatterSeries *>(series)->m_axes); + else if (qobject_cast<DeclarativeSplineSeries *>(series)) + doInitializeAxes(series, qobject_cast<DeclarativeSplineSeries *>(series)->m_axes); + else if (qobject_cast<DeclarativeAreaSeries *>(series)) + doInitializeAxes(series, qobject_cast<DeclarativeAreaSeries *>(series)->m_axes); + else if (qobject_cast<DeclarativeBarSeries *>(series)) + doInitializeAxes(series, qobject_cast<DeclarativeBarSeries *>(series)->m_axes); + else if (qobject_cast<DeclarativeStackedBarSeries *>(series)) + doInitializeAxes(series, qobject_cast<DeclarativeStackedBarSeries *>(series)->m_axes); + else if (qobject_cast<DeclarativePercentBarSeries *>(series)) + doInitializeAxes(series, qobject_cast<DeclarativePercentBarSeries *>(series)->m_axes); + else if (qobject_cast<DeclarativeHorizontalBarSeries *>(series)) + doInitializeAxes(series, qobject_cast<DeclarativeHorizontalBarSeries *>(series)->m_axes); + else if (qobject_cast<DeclarativeHorizontalStackedBarSeries *>(series)) + doInitializeAxes(series, qobject_cast<DeclarativeHorizontalStackedBarSeries *>(series)->m_axes); + else if (qobject_cast<DeclarativeHorizontalPercentBarSeries *>(series)) + doInitializeAxes(series, qobject_cast<DeclarativeHorizontalPercentBarSeries *>(series)->m_axes); + else if (qobject_cast<DeclarativeBoxPlotSeries *>(series)) + doInitializeAxes(series, qobject_cast<DeclarativeBoxPlotSeries *>(series)->m_axes); + // else: do nothing +} + +void DeclarativeChart::doInitializeAxes(QAbstractSeries *series, DeclarativeAxes *axes) +{ + // Initialize axis X + if (axes->axisX()) + axes->emitAxisXChanged(); + else if (axes->axisXTop()) + axes->emitAxisXTopChanged(); + else + axes->setAxisX(defaultAxis(Qt::Horizontal, series)); + + // Initialize axis Y + if (axes->axisY()) + axes->emitAxisYChanged(); + else if (axes->axisYRight()) + axes->emitAxisYRightChanged(); + else + axes->setAxisY(defaultAxis(Qt::Vertical, series)); +} + +#include "moc_declarativechart.cpp" + +QT_CHARTS_END_NAMESPACE |