diff options
Diffstat (limited to 'src/charts/barchart')
48 files changed, 6509 insertions, 0 deletions
diff --git a/src/charts/barchart/abstractbarchartitem.cpp b/src/charts/barchart/abstractbarchartitem.cpp new file mode 100644 index 00000000..4cf8b366 --- /dev/null +++ b/src/charts/barchart/abstractbarchartitem.cpp @@ -0,0 +1,268 @@ +/**************************************************************************** +** +** 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 "abstractbarchartitem_p.h" +#include "bar_p.h" +#include "qbarset.h" +#include "qbarset_p.h" +#include "qabstractbarseries.h" +#include "qabstractbarseries_p.h" +#include "qchart.h" +#include "chartpresenter_p.h" +#include "charttheme_p.h" +#include "baranimation_p.h" +#include "chartdataset_p.h" +#include <QPainter> +#include <QTextDocument> + +QT_CHARTS_BEGIN_NAMESPACE + +AbstractBarChartItem::AbstractBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item) : + ChartItem(series->d_func(),item), + m_animation(0), + m_series(series) +{ + + setFlag(ItemClipsChildrenToShape); + connect(series->d_func(), SIGNAL(updatedLayout()), this, SLOT(handleLayoutChanged())); + connect(series->d_func(), SIGNAL(updatedBars()), this, SLOT(handleUpdatedBars())); + connect(series->d_func(), SIGNAL(labelsVisibleChanged(bool)), this, SLOT(handleLabelsVisibleChanged(bool))); + connect(series->d_func(), SIGNAL(restructuredBars()), this, SLOT(handleDataStructureChanged())); + connect(series, SIGNAL(visibleChanged()), this, SLOT(handleVisibleChanged())); + connect(series, SIGNAL(opacityChanged()), this, SLOT(handleOpacityChanged())); + connect(series, SIGNAL(labelsFormatChanged(QString)), this, SLOT(handleUpdatedBars())); + connect(series, SIGNAL(labelsFormatChanged(QString)), this, SLOT(positionLabels())); + connect(series, SIGNAL(labelsPositionChanged(QAbstractBarSeries::LabelsPosition)), + this, SLOT(handleLabelsPositionChanged())); + setZValue(ChartPresenter::BarSeriesZValue); + handleDataStructureChanged(); + handleVisibleChanged(); + handleUpdatedBars(); +} + +AbstractBarChartItem::~AbstractBarChartItem() +{ +} + +void AbstractBarChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(painter); + Q_UNUSED(option); + Q_UNUSED(widget); +} + +QRectF AbstractBarChartItem::boundingRect() const +{ + return m_rect; +} + +void AbstractBarChartItem::applyLayout(const QVector<QRectF> &layout) +{ + QSizeF size = geometry().size(); + if (geometry().size().isValid()) { + if (m_animation) { + if (m_layout.count() == 0 || m_oldSize != size) { + initializeLayout(); + m_oldSize = size; + } + m_animation->setup(m_layout, layout); + presenter()->startAnimation(m_animation); + } else { + setLayout(layout); + update(); + } + } +} + +void AbstractBarChartItem::setAnimation(BarAnimation *animation) +{ + m_animation = animation; +} + +void AbstractBarChartItem::setLayout(const QVector<QRectF> &layout) +{ + if (layout.count() != m_bars.count()) + return; + + m_layout = layout; + + for (int i = 0; i < m_bars.count(); i++) + m_bars.at(i)->setRect(layout.at(i)); + + positionLabels(); +} +//handlers + +void AbstractBarChartItem::handleDomainUpdated() +{ + m_domainMinX = domain()->minX(); + m_domainMaxX = domain()->maxX(); + m_domainMinY = domain()->minY(); + m_domainMaxY = domain()->maxY(); + + QRectF rect(QPointF(0,0),domain()->size()); + + if(m_rect != rect){ + prepareGeometryChange(); + m_rect = rect; + } + + handleLayoutChanged(); +} + +void AbstractBarChartItem::handleLayoutChanged() +{ + if ((m_rect.width() <= 0) || (m_rect.height() <= 0)) + return; // rect size zero. + QVector<QRectF> layout = calculateLayout(); + applyLayout(layout); + handleUpdatedBars(); +} + +void AbstractBarChartItem::handleLabelsVisibleChanged(bool visible) +{ + foreach (QGraphicsTextItem *label, m_labels) + label->setVisible(visible); + update(); +} + +void AbstractBarChartItem::handleDataStructureChanged() +{ + foreach (QGraphicsItem *item, childItems()) + delete item; + + m_bars.clear(); + m_labels.clear(); + m_layout.clear(); + + // Create new graphic items for bars + for (int c = 0; c < m_series->d_func()->categoryCount(); c++) { + for (int s = 0; s < m_series->count(); s++) { + QBarSet *set = m_series->d_func()->barsetAt(s); + + // Bars + Bar *bar = new Bar(set, c, this); + m_bars.append(bar); + connect(bar, SIGNAL(clicked(int,QBarSet*)), m_series, SIGNAL(clicked(int,QBarSet*))); + connect(bar, SIGNAL(hovered(bool,QBarSet*)), m_series, SIGNAL(hovered(bool,QBarSet*))); + connect(bar, SIGNAL(hovered(bool, int, QBarSet*)), m_series, SIGNAL(hovered(bool, int, QBarSet*))); + connect(bar, SIGNAL(clicked(int,QBarSet*)), set, SIGNAL(clicked(int))); + connect(bar, SIGNAL(hovered(bool,QBarSet*)), set, SIGNAL(hovered(bool))); + connect(bar, SIGNAL(hovered(bool, int, QBarSet*)), set, SIGNAL(hovered(bool, int))); + // m_layout.append(QRectF(0, 0, 1, 1)); + + // Labels + QGraphicsTextItem *newLabel = new QGraphicsTextItem(this); + newLabel->document()->setDocumentMargin(ChartPresenter::textMargin()); + m_labels.append(newLabel); + } + } + + if(themeManager()) themeManager()->updateSeries(m_series); + handleLayoutChanged(); + handleVisibleChanged(); +} + +void AbstractBarChartItem::handleVisibleChanged() +{ + bool visible = m_series->isVisible(); + if (visible) + handleLabelsVisibleChanged(m_series->isLabelsVisible()); + else + handleLabelsVisibleChanged(visible); + + foreach (QGraphicsItem *bar, m_bars) + bar->setVisible(visible); +} + +void AbstractBarChartItem::handleOpacityChanged() +{ + foreach (QGraphicsItem *item, childItems()) + item->setOpacity(m_series->opacity()); +} + +void AbstractBarChartItem::handleUpdatedBars() +{ + if (!m_series->d_func()->blockBarUpdate()) { + // Handle changes in pen, brush, labels etc. + int categoryCount = m_series->d_func()->categoryCount(); + int setCount = m_series->count(); + int itemIndex(0); + static const QString valueTag(QLatin1String("@value")); + + for (int category = 0; category < categoryCount; category++) { + for (int set = 0; set < setCount; set++) { + QBarSetPrivate *barSet = m_series->d_func()->barsetAt(set)->d_ptr.data(); + Bar *bar = m_bars.at(itemIndex); + bar->setPen(barSet->m_pen); + bar->setBrush(barSet->m_brush); + bar->update(); + + QGraphicsTextItem *label = m_labels.at(itemIndex); + QString valueLabel; + if (presenter()) { // At startup presenter is not yet set, yet somehow update comes + if (m_series->labelsFormat().isEmpty()) { + valueLabel = presenter()->numberToString(barSet->value(category)); + } else { + valueLabel = m_series->labelsFormat(); + valueLabel.replace(valueTag, + presenter()->numberToString(barSet->value(category))); + } + } + label->setHtml(valueLabel); + label->setFont(barSet->m_labelFont); + label->setDefaultTextColor(barSet->m_labelBrush.color()); + label->update(); + itemIndex++; + } + } + } +} + +void AbstractBarChartItem::handleLabelsPositionChanged() +{ + positionLabels(); +} + +void AbstractBarChartItem::positionLabels() +{ + for (int i = 0; i < m_layout.count(); i++) { + QGraphicsTextItem *label = m_labels.at(i); + qreal xPos = 0; + qreal yPos = m_layout.at(i).center().y() - label->boundingRect().center().y(); + + int offset = m_bars.at(i)->pen().width() / 2 + 2; + if (m_series->labelsPosition() == QAbstractBarSeries::LabelsCenter) + xPos = m_layout.at(i).center().x() - label->boundingRect().center().x(); + else if (m_series->labelsPosition() == QAbstractBarSeries::LabelsInsideEnd) + xPos = m_layout.at(i).right() - label->boundingRect().width() - offset; + else if (m_series->labelsPosition() == QAbstractBarSeries::LabelsInsideBase) + xPos = m_layout.at(i).left() + offset; + else if (m_series->labelsPosition() == QAbstractBarSeries::LabelsOutsideEnd) + xPos = m_layout.at(i).right() + offset; + + label->setPos(xPos, yPos); + label->setZValue(zValue() + 1); + } +} + +#include "moc_abstractbarchartitem_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/abstractbarchartitem_p.h b/src/charts/barchart/abstractbarchartitem_p.h new file mode 100644 index 00000000..66551a62 --- /dev/null +++ b/src/charts/barchart/abstractbarchartitem_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + + +#ifndef ABSTRACTBARCHARTITEM_H +#define ABSTRACTBARCHARTITEM_H + +#include "chartitem_p.h" +#include "qabstractbarseries.h" +#include <QPen> +#include <QBrush> + +QT_CHARTS_BEGIN_NAMESPACE + +class Bar; +class QAxisCategories; +class QChart; +class BarAnimation; + +class AbstractBarChartItem : public ChartItem +{ + Q_OBJECT +public: + AbstractBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item = 0); + virtual ~AbstractBarChartItem(); + +public: + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + QRectF boundingRect() const; + + virtual QVector<QRectF> calculateLayout() = 0; + virtual void initializeLayout() = 0; + virtual void applyLayout(const QVector<QRectF> &layout); + virtual void setAnimation(BarAnimation *animation); + void setLayout(const QVector<QRectF> &layout); + void updateLayout(const QVector<QRectF> &layout); + QRectF geometry() const { return m_rect;} + +public Q_SLOTS: + void handleDomainUpdated(); + void handleLayoutChanged(); + void handleLabelsVisibleChanged(bool visible); + void handleDataStructureChanged(); // structure of of series has changed, recreate graphic items + void handleVisibleChanged(); + void handleOpacityChanged(); + virtual void handleUpdatedBars(); + void handleLabelsPositionChanged(); + virtual void positionLabels(); + +protected: + + qreal m_domainMinX; + qreal m_domainMaxX; + qreal m_domainMinY; + qreal m_domainMaxY; + + QRectF m_rect; + QVector<QRectF> m_layout; + + BarAnimation *m_animation; + + QAbstractBarSeries *m_series; // Not owned. + QList<Bar *> m_bars; + QList<QGraphicsTextItem *> m_labels; + QSizeF m_oldSize; +}; + +QT_CHARTS_END_NAMESPACE + +#endif // ABSTRACTBARCHARTITEM_H diff --git a/src/charts/barchart/bar.cpp b/src/charts/barchart/bar.cpp new file mode 100644 index 00000000..de6c442f --- /dev/null +++ b/src/charts/barchart/bar.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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 "bar_p.h" +#include <QPainter> +#include <QGraphicsSceneEvent> + +QT_CHARTS_BEGIN_NAMESPACE + +Bar::Bar(QBarSet *barset, int index, QGraphicsItem *parent) : QGraphicsRectItem(parent), + m_index(index), + m_barset(barset), + m_hovering(false) +{ + setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton); + setAcceptHoverEvents(true); +} + +Bar::~Bar() +{ + // End hover event, if bar is deleted during it + if (m_hovering) { + emit hovered(false, m_barset); + emit hovered(false, m_index, m_barset); + } +} + +void Bar::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(event) + emit clicked(m_index, m_barset); + QGraphicsItem::mousePressEvent(event); +} + +void Bar::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + Q_UNUSED(event) + m_hovering = true; + emit hovered(true, m_barset); + emit hovered(true, m_index, m_barset); + +} + +void Bar::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + Q_UNUSED(event) + m_hovering = false; + emit hovered(false, m_barset); + emit hovered(false, m_index, m_barset); +} + +#include "moc_bar_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/bar_p.h b/src/charts/barchart/bar_p.h new file mode 100644 index 00000000..0d46e2b6 --- /dev/null +++ b/src/charts/barchart/bar_p.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef BAR_H +#define BAR_H + +#include "qchartglobal.h" +#include <QGraphicsRectItem> + +QT_CHARTS_BEGIN_NAMESPACE + +class QBarSet; + +// Single visual bar item of chart +class Bar : public QObject, public QGraphicsRectItem +{ + Q_OBJECT +public: + Bar(QBarSet *barset, int index, QGraphicsItem *parent = 0); + ~Bar(); + +public: + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + +Q_SIGNALS: + void clicked(int index, QBarSet *barset); + void hovered(bool status, QBarSet *barset); + void hovered(bool status, int index, QBarSet *barset); + +private: + int m_index; + QBarSet *m_barset; + bool m_hovering; +}; + +QT_CHARTS_END_NAMESPACE + +#endif // BAR_H diff --git a/src/charts/barchart/barchart.pri b/src/charts/barchart/barchart.pri new file mode 100644 index 00000000..0e78d232 --- /dev/null +++ b/src/charts/barchart/barchart.pri @@ -0,0 +1,71 @@ +#Subdirectiores are defined here, because qt creator doesn't handle nested include(foo.pri) chains very well. + +INCLUDEPATH += $$PWD \ + $$PWD/vertical/bar \ + $$PWD/vertical/stacked \ + $$PWD/vertical/percent \ + $$PWD/horizontal/bar \ + $$PWD/horizontal/stacked \ + $$PWD/horizontal/percent + +DEPENDPATH += $$PWD \ + $$PWD/vertical/bar \ + $$PWD/vertical/stacked \ + $$PWD/vertical/percent \ + $$PWD/horizontal/bar \ + $$PWD/horizontal/stacked \ + $$PWD/horizontal/percent + +SOURCES += \ + $$PWD/bar.cpp \ + $$PWD/abstractbarchartitem.cpp \ + $$PWD/qabstractbarseries.cpp \ + $$PWD/qbarset.cpp \ + $$PWD/qbarmodelmapper.cpp \ + $$PWD/qvbarmodelmapper.cpp \ + $$PWD/qhbarmodelmapper.cpp \ + $$PWD/vertical/bar/qbarseries.cpp \ + $$PWD/vertical/bar/barchartitem.cpp \ + $$PWD/vertical/stacked/qstackedbarseries.cpp \ + $$PWD/vertical/stacked/stackedbarchartitem.cpp \ + $$PWD/vertical/percent/qpercentbarseries.cpp \ + $$PWD/vertical/percent/percentbarchartitem.cpp \ + $$PWD/horizontal/bar/qhorizontalbarseries.cpp \ + $$PWD/horizontal/bar/horizontalbarchartitem.cpp \ + $$PWD/horizontal/stacked/qhorizontalstackedbarseries.cpp \ + $$PWD/horizontal/stacked/horizontalstackedbarchartitem.cpp \ + $$PWD/horizontal/percent/qhorizontalpercentbarseries.cpp \ + $$PWD/horizontal/percent/horizontalpercentbarchartitem.cpp + +PRIVATE_HEADERS += \ + $$PWD/bar_p.h \ + $$PWD/qbarset_p.h \ + $$PWD/abstractbarchartitem_p.h \ + $$PWD/qabstractbarseries_p.h \ + $$PWD/qbarmodelmapper_p.h \ + $$PWD/vertical/bar/qbarseries_p.h \ + $$PWD/vertical/bar/barchartitem_p.h \ + $$PWD/vertical/stacked/qstackedbarseries_p.h \ + $$PWD/vertical/stacked/stackedbarchartitem_p.h \ + $$PWD/vertical/percent/qpercentbarseries_p.h \ + $$PWD/vertical/percent/percentbarchartitem_p.h \ + $$PWD/horizontal/bar/qhorizontalbarseries_p.h \ + $$PWD/horizontal/bar/horizontalbarchartitem_p.h \ + $$PWD/horizontal/stacked/qhorizontalstackedbarseries_p.h \ + $$PWD/horizontal/stacked/horizontalstackedbarchartitem_p.h \ + $$PWD/horizontal/percent/qhorizontalpercentbarseries_p.h \ + $$PWD/horizontal/percent/horizontalpercentbarchartitem_p.h + +PUBLIC_HEADERS += \ + $$PWD/qabstractbarseries.h \ + $$PWD/qbarset.h \ + $$PWD/qbarmodelmapper.h \ + $$PWD/qvbarmodelmapper.h \ + $$PWD/qhbarmodelmapper.h \ + $$PWD/vertical/bar/qbarseries.h \ + $$PWD/vertical/stacked/qstackedbarseries.h \ + $$PWD/vertical/percent/qpercentbarseries.h \ + $$PWD/horizontal/bar/qhorizontalbarseries.h \ + $$PWD/horizontal/stacked/qhorizontalstackedbarseries.h \ + $$PWD/horizontal/percent/qhorizontalpercentbarseries.h + diff --git a/src/charts/barchart/horizontal/bar/horizontalbarchartitem.cpp b/src/charts/barchart/horizontal/bar/horizontalbarchartitem.cpp new file mode 100644 index 00000000..d5370a2f --- /dev/null +++ b/src/charts/barchart/horizontal/bar/horizontalbarchartitem.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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 "horizontalbarchartitem_p.h" +#include "qabstractbarseries_p.h" +#include "qbarset_p.h" +#include "bar_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +HorizontalBarChartItem::HorizontalBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item) + : AbstractBarChartItem(series, item) +{ +} + +void HorizontalBarChartItem::initializeLayout() +{ + qreal categoryCount = m_series->d_func()->categoryCount(); + qreal setCount = m_series->count(); + qreal barWidth = m_series->d_func()->barWidth(); + + m_layout.clear(); + for(int category = 0; category < categoryCount; category++) { + for (int set = 0; set < setCount; set++) { + QRectF rect; + QPointF topLeft; + QPointF bottomRight; + if (domain()->type() == AbstractDomain::LogXYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) { + topLeft = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category - barWidth / 2 + set/setCount * barWidth), m_validData); + bottomRight = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category - barWidth / 2 + (set + 1)/setCount * barWidth), m_validData); + } else { + topLeft = domain()->calculateGeometryPoint(QPointF(0, category - barWidth / 2 + set/setCount * barWidth), m_validData); + bottomRight = domain()->calculateGeometryPoint(QPointF(0, category - barWidth / 2 + (set + 1)/setCount * barWidth), m_validData); + } + + if (!m_validData) + return; + + rect.setTopLeft(topLeft); + rect.setBottomRight(bottomRight); + m_layout.append(rect.normalized()); + } + } +} + +QVector<QRectF> HorizontalBarChartItem::calculateLayout() +{ + QVector<QRectF> layout; + + // Use temporary qreals for accuracy + qreal categoryCount = m_series->d_func()->categoryCount(); + qreal setCount = m_series->count(); + qreal barWidth = m_series->d_func()->barWidth(); + + for(int category = 0; category < categoryCount; category++) { + for (int set = 0; set < setCount; set++) { + qreal value = m_series->barSets().at(set)->at(category); + QRectF rect; + QPointF topLeft; + if (domain()->type() == AbstractDomain::LogXYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) + topLeft = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category - barWidth / 2 + set/setCount * barWidth), m_validData); + else + topLeft = domain()->calculateGeometryPoint(QPointF(0, category - barWidth / 2 + set/setCount * barWidth), m_validData); + + QPointF bottomRight = domain()->calculateGeometryPoint(QPointF(value, category - barWidth / 2 + (set + 1)/setCount * barWidth), m_validData); + + rect.setTopLeft(topLeft); + rect.setBottomRight(bottomRight); + layout.append(rect.normalized()); + } + } + return layout; +} + +#include "moc_horizontalbarchartitem_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/horizontal/bar/horizontalbarchartitem_p.h b/src/charts/barchart/horizontal/bar/horizontalbarchartitem_p.h new file mode 100644 index 00000000..df7e793e --- /dev/null +++ b/src/charts/barchart/horizontal/bar/horizontalbarchartitem_p.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef HORIZONTALBARCHARTITEM_H +#define HORIZONTALBARCHARTITEM_H + +#include "abstractbarchartitem_p.h" +#include <QGraphicsItem> + +QT_CHARTS_BEGIN_NAMESPACE + +class HorizontalBarChartItem : public AbstractBarChartItem +{ + Q_OBJECT +public: + HorizontalBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item = 0); + +private: + virtual QVector<QRectF> calculateLayout(); + void initializeLayout(); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // HORIZONTALBARCHARTITEM_H diff --git a/src/charts/barchart/horizontal/bar/qhorizontalbarseries.cpp b/src/charts/barchart/horizontal/bar/qhorizontalbarseries.cpp new file mode 100644 index 00000000..d381aadf --- /dev/null +++ b/src/charts/barchart/horizontal/bar/qhorizontalbarseries.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** 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 "qhorizontalbarseries.h" +#include "qhorizontalbarseries_p.h" +#include "horizontalbarchartitem_p.h" +#include "qbarcategoryaxis.h" + +#include "chartdataset_p.h" +#include "charttheme_p.h" + + +QT_CHARTS_BEGIN_NAMESPACE + +/*! + \class QHorizontalBarSeries + \inmodule Qt Charts + \brief Series for creating horizontal bar chart. + \mainclass + + QHorizontalBarSeries represents a series of data shown as bars. The purpose of this class is to draw bars + as groups, where bars in same category are grouped next to each other. QHorizontalBarSeries groups the data + from sets to categories, which are defined by a QStringList. + + See the \l {HorizontalBarChart Example} {horizontal bar chart example} to learn how to create a horizontal bar chart. + \image examples_horizontalbarchart.png + + \sa QBarSet, QBarSeries, QPercentBarSeries, QAbstractBarSeries, QStackedBarSeries, QHorizontalStackedBarSeries, QHorizontalPercentBarSeries +*/ +/*! + \qmltype HorizontalBarSeries + \instantiates QHorizontalBarSeries + \inqmlmodule QtCharts + + \inherits AbstractBarSeries + + \brief Series type for creating horizontal bar chart. + + The following QML shows how to create a simple horizontal bar chart: + \snippet qmlchart/qml/qmlchart/View9.qml 1 + \beginfloatleft + \image examples_qmlchart9.png + \endfloat + \clearfloat +*/ + +/*! + Constructs empty QHorizontalBarSeries. + QHorizontalBarSeries is QObject which is a child of a \a parent. +*/ +QHorizontalBarSeries::QHorizontalBarSeries(QObject *parent) + : QAbstractBarSeries(*new QHorizontalBarSeriesPrivate(this), parent) +{ +} + +/*! + Destructor. + Removes series from chart. +*/ +QHorizontalBarSeries::~QHorizontalBarSeries() +{ + Q_D(QHorizontalBarSeries); + if (d->m_chart) + d->m_chart->removeSeries(this); +} + +/*! + Returns QChartSeries::SeriesTypeHorizontalBar. +*/ +QAbstractSeries::SeriesType QHorizontalBarSeries::type() const +{ + return QAbstractSeries::SeriesTypeHorizontalBar; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QHorizontalBarSeriesPrivate::QHorizontalBarSeriesPrivate(QHorizontalBarSeries *q) + : QAbstractBarSeriesPrivate(q) +{ + +} + +void QHorizontalBarSeriesPrivate::initializeDomain() +{ + qreal minX(domain()->minX()); + qreal minY(domain()->minY()); + qreal maxX(domain()->maxX()); + qreal maxY(domain()->maxY()); + + qreal y = categoryCount(); + minX = qMin(minX, min()); + minY = qMin(minY, - (qreal)0.5); + maxX = qMax(maxX, max()); + maxY = qMax(maxY, y - (qreal)0.5); + + domain()->setRange(minX, maxX, minY, maxY); +} + +void QHorizontalBarSeriesPrivate::initializeGraphics(QGraphicsItem* parent) +{ + Q_Q(QHorizontalBarSeries); + HorizontalBarChartItem *bar = new HorizontalBarChartItem(q,parent); + m_item.reset(bar); + QAbstractSeriesPrivate::initializeGraphics(parent); +} + +#include "moc_qhorizontalbarseries.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/horizontal/bar/qhorizontalbarseries.h b/src/charts/barchart/horizontal/bar/qhorizontalbarseries.h new file mode 100644 index 00000000..b5cf137b --- /dev/null +++ b/src/charts/barchart/horizontal/bar/qhorizontalbarseries.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QHORIZONTALBARSERIES_H +#define QHORIZONTALBARSERIES_H + +#include <QtCharts/qabstractbarseries.h> + +QT_CHARTS_BEGIN_NAMESPACE + +class QHorizontalBarSeriesPrivate; + +class QT_CHARTS_EXPORT QHorizontalBarSeries : public QAbstractBarSeries +{ + Q_OBJECT +public: + explicit QHorizontalBarSeries(QObject *parent = 0); + ~QHorizontalBarSeries(); + QAbstractSeries::SeriesType type() const; + +private: + Q_DECLARE_PRIVATE(QHorizontalBarSeries) + Q_DISABLE_COPY(QHorizontalBarSeries) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QHORIZONTALBARSERIES_H diff --git a/src/charts/barchart/horizontal/bar/qhorizontalbarseries_p.h b/src/charts/barchart/horizontal/bar/qhorizontalbarseries_p.h new file mode 100644 index 00000000..d32ed320 --- /dev/null +++ b/src/charts/barchart/horizontal/bar/qhorizontalbarseries_p.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QHORIZONTALBARSERIES_P_H +#define QHORIZONTALBARSERIES_P_H + +#include "qabstractbarseries_p.h" +#include "abstractdomain_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QHorizontalBarSeriesPrivate: public QAbstractBarSeriesPrivate +{ +public: + QHorizontalBarSeriesPrivate(QHorizontalBarSeries *q); + void initializeGraphics(QGraphicsItem* parent); + void initializeDomain(); +private: + Q_DECLARE_PUBLIC(QHorizontalBarSeries) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QHORIZONTALBARSERIES_P_H diff --git a/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem.cpp b/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem.cpp new file mode 100644 index 00000000..0bf9afbe --- /dev/null +++ b/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** 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 "horizontalpercentbarchartitem_p.h" +#include "qabstractbarseries_p.h" +#include "qbarset_p.h" +#include "bar_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +HorizontalPercentBarChartItem::HorizontalPercentBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item) + : AbstractBarChartItem(series, item) +{ +} + +void HorizontalPercentBarChartItem::initializeLayout() +{ + qreal categoryCount = m_series->d_func()->categoryCount(); + qreal setCount = m_series->count(); + qreal barWidth = m_series->d_func()->barWidth(); + + m_layout.clear(); + for(int category = 0; category < categoryCount; category++) { + for (int set = 0; set < setCount; set++) { + QRectF rect; + QPointF topLeft; + QPointF bottomRight; + if (domain()->type() == AbstractDomain::LogXYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) { + topLeft = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category - barWidth / 2), m_validData); + bottomRight = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category + barWidth / 2), m_validData); + } else { + topLeft = domain()->calculateGeometryPoint(QPointF(0, category - barWidth / 2), m_validData); + bottomRight = domain()->calculateGeometryPoint(QPointF(0, category + barWidth / 2), m_validData); + } + + if (!m_validData) + return; + + rect.setTopLeft(topLeft); + rect.setBottomRight(bottomRight); + m_layout.append(rect.normalized()); + } + } +} + +QVector<QRectF> HorizontalPercentBarChartItem::calculateLayout() +{ + QVector<QRectF> layout; + + // Use temporary qreals for accuracy + qreal categoryCount = m_series->d_func()->categoryCount(); + qreal setCount = m_series->count(); + qreal barWidth = m_series->d_func()->barWidth(); + + for(int category = 0; category < categoryCount; category++) { + qreal sum = 0; + qreal categorySum = m_series->d_func()->categorySum(category); + for (int set = 0; set < setCount; set++) { + qreal value = m_series->barSets().at(set)->at(category); + QRectF rect; + qreal topX = 0; + if (sum > 0) + topX = 100 * sum / categorySum; + qreal bottomX = 0; + qreal newSum = value + sum; + if (newSum > 0) + bottomX = 100 * newSum / categorySum; + QPointF topLeft; + if (domain()->type() == AbstractDomain::LogXYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) + topLeft = domain()->calculateGeometryPoint(QPointF(set ? topX : domain()->minX(), category - barWidth/2), m_validData); + else + topLeft = domain()->calculateGeometryPoint(QPointF(set ? topX : 0, category - barWidth/2), m_validData); + QPointF bottomRight = domain()->calculateGeometryPoint(QPointF(bottomX, category + barWidth/2), m_validData); + + rect.setTopLeft(topLeft); + rect.setBottomRight(bottomRight); + layout.append(rect.normalized()); + sum = newSum; + } + } + return layout; +} + +void HorizontalPercentBarChartItem::handleUpdatedBars() +{ + // Handle changes in pen, brush, labels etc. + int categoryCount = m_series->d_func()->categoryCount(); + int setCount = m_series->count(); + int itemIndex(0); + static const QString valueTag(QLatin1String("@value")); + + for (int category = 0; category < categoryCount; category++) { + for (int set = 0; set < setCount; set++) { + QBarSetPrivate *barSet = m_series->d_func()->barsetAt(set)->d_ptr.data(); + Bar *bar = m_bars.at(itemIndex); + bar->setPen(barSet->m_pen); + bar->setBrush(barSet->m_brush); + bar->update(); + + QGraphicsTextItem *label = m_labels.at(itemIndex); + qreal p = m_series->d_func()->percentageAt(set, category) * 100.0; + QString vString(presenter()->numberToString(p, 'f', 0)); + QString valueLabel; + if (m_series->labelsFormat().isEmpty()) { + vString.append(QStringLiteral("%")); + valueLabel = vString; + } else { + valueLabel = m_series->labelsFormat(); + valueLabel.replace(valueTag, vString); + } + label->setHtml(valueLabel); + label->setFont(barSet->m_labelFont); + label->setDefaultTextColor(barSet->m_labelBrush.color()); + label->update(); + itemIndex++; + } + } +} + +#include "moc_horizontalpercentbarchartitem_p.cpp" + +QT_CHARTS_END_NAMESPACE + diff --git a/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem_p.h b/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem_p.h new file mode 100644 index 00000000..e24cdcf0 --- /dev/null +++ b/src/charts/barchart/horizontal/percent/horizontalpercentbarchartitem_p.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef HORIZONTALPERCENTBARCHARTITEM_P_H +#define HORIZONTALPERCENTBARCHARTITEM_P_H + +#include "abstractbarchartitem_p.h" +#include <QGraphicsItem> + +QT_CHARTS_BEGIN_NAMESPACE + +class HorizontalPercentBarChartItem : public AbstractBarChartItem +{ + Q_OBJECT +public: + HorizontalPercentBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item = 0); + void handleUpdatedBars(); + +private: + virtual QVector<QRectF> calculateLayout(); + void initializeLayout(); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // HORIZONTALPERCENTBARCHARTITEM_P_H diff --git a/src/charts/barchart/horizontal/percent/qhorizontalpercentbarseries.cpp b/src/charts/barchart/horizontal/percent/qhorizontalpercentbarseries.cpp new file mode 100644 index 00000000..bf915c85 --- /dev/null +++ b/src/charts/barchart/horizontal/percent/qhorizontalpercentbarseries.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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 "qhorizontalpercentbarseries.h" +#include "qhorizontalpercentbarseries_p.h" +#include "horizontalpercentbarchartitem_p.h" + +#include "chartdataset_p.h" +#include "charttheme_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +/*! + \class QHorizontalPercentBarSeries + \inmodule Qt Charts + \brief Series for creating horizontal percent bar chart. + \mainclass + + QHorizontalPercentBarSeries represents a series of data shown as bars. The purpose of this + class is to draw bars as groups, where bars in same category are grouped next to each other. + QHorizontalPercentBarSeries groups the data from sets to categories, which are defined by a + QStringList. Bars with zero value are not drawn. + + See the \l {HorizontalPercentBarChart Example} {horizontal percent bar chart example} to learn + how to create a horizontal percent bar chart. + \image examples_horizontalpercentbarchart.png + + \sa QBarSet, QBarSeries, QPercentBarSeries, QAbstractBarSeries, QStackedBarSeries, + QHorizontalStackedBarSeries, QHorizontalBarSeries +*/ +/*! + \qmltype HorizontalPercentBarSeries + \instantiates QHorizontalPercentBarSeries + \inqmlmodule QtCharts + + \inherits AbstractBarSeries + + \brief Series type for creating horizontal precent bar chart. + + The following QML shows how to create a simple horizontal percent bar chart: + \snippet qmlchart/qml/qmlchart/View11.qml 1 + \beginfloatleft + \image examples_qmlchart11.png + \endfloat + \clearfloat +*/ + +/*! + Constructs empty QHorizontalPercentBarSeries. + QHorizontalPercentBarSeries is QObject which is a child of a \a parent. +*/ +QHorizontalPercentBarSeries::QHorizontalPercentBarSeries(QObject *parent) : + QAbstractBarSeries(*new QHorizontalPercentBarSeriesPrivate(this), parent) +{ +} + +/*! + Returns QAbstractSeries::SeriesTypeHorizontalPercentBar. +*/ +QAbstractSeries::SeriesType QHorizontalPercentBarSeries::type() const +{ + return QAbstractSeries::SeriesTypeHorizontalPercentBar; +} + +/*! + Destructor. + Removes series from chart. +*/ +QHorizontalPercentBarSeries::~QHorizontalPercentBarSeries() +{ + Q_D(QHorizontalPercentBarSeries); + if (d->m_chart) + d->m_chart->removeSeries(this); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QHorizontalPercentBarSeriesPrivate::QHorizontalPercentBarSeriesPrivate(QHorizontalPercentBarSeries *q) : QAbstractBarSeriesPrivate(q) +{ + +} + +void QHorizontalPercentBarSeriesPrivate::initializeDomain() +{ + qreal minX(domain()->minX()); + qreal minY(domain()->minY()); + qreal maxX(domain()->maxX()); + qreal maxY(domain()->maxY()); + + qreal y = categoryCount(); + minX = 0; + maxX = 100; + minY = qMin(minY, - (qreal)0.5); + maxY = qMax(maxY, y - (qreal)0.5); + + domain()->setRange(minX, maxX, minY, maxY); +} + +void QHorizontalPercentBarSeriesPrivate::initializeGraphics(QGraphicsItem* parent) +{ + Q_Q(QHorizontalPercentBarSeries); + HorizontalPercentBarChartItem *bar = new HorizontalPercentBarChartItem(q,parent); + m_item.reset(bar); + QAbstractSeriesPrivate::initializeGraphics(parent); +} + +#include "moc_qhorizontalpercentbarseries.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/horizontal/percent/qhorizontalpercentbarseries.h b/src/charts/barchart/horizontal/percent/qhorizontalpercentbarseries.h new file mode 100644 index 00000000..0595532b --- /dev/null +++ b/src/charts/barchart/horizontal/percent/qhorizontalpercentbarseries.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QHORIZONTALPERCENTBARSERIES_H +#define QHORIZONTALPERCENTBARSERIES_H + +#include <QtCharts/qabstractbarseries.h> + +QT_CHARTS_BEGIN_NAMESPACE + +class QHorizontalPercentBarSeriesPrivate; + +class QT_CHARTS_EXPORT QHorizontalPercentBarSeries : public QAbstractBarSeries +{ + Q_OBJECT +public: + explicit QHorizontalPercentBarSeries(QObject *parent = 0); + ~QHorizontalPercentBarSeries(); + QAbstractSeries::SeriesType type() const; + +private: + Q_DECLARE_PRIVATE(QHorizontalPercentBarSeries) + Q_DISABLE_COPY(QHorizontalPercentBarSeries) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QHORIZONTALPERCENTBARSERIES_H diff --git a/src/charts/barchart/horizontal/percent/qhorizontalpercentbarseries_p.h b/src/charts/barchart/horizontal/percent/qhorizontalpercentbarseries_p.h new file mode 100644 index 00000000..079f97bb --- /dev/null +++ b/src/charts/barchart/horizontal/percent/qhorizontalpercentbarseries_p.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QHORIZONTALPERCENTBARSERIES_P_H +#define QHORIZONTALPERCENTBARSERIES_P_H + +#include "qabstractbarseries_p.h" +#include "abstractdomain_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QHorizontalPercentBarSeriesPrivate: public QAbstractBarSeriesPrivate +{ +public: + QHorizontalPercentBarSeriesPrivate(QHorizontalPercentBarSeries *q); + void initializeGraphics(QGraphicsItem* parent); + void initializeDomain(); +private: + Q_DECLARE_PUBLIC(QHorizontalPercentBarSeries) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QHORIZONTALPERCENTBARSERIES_P_H diff --git a/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem.cpp b/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem.cpp new file mode 100644 index 00000000..fe6f162d --- /dev/null +++ b/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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 "horizontalstackedbarchartitem_p.h" +#include "qabstractbarseries_p.h" +#include "qbarset_p.h" +#include "bar_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +HorizontalStackedBarChartItem::HorizontalStackedBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item) + : AbstractBarChartItem(series, item) +{ +} + +void HorizontalStackedBarChartItem::initializeLayout() +{ + qreal categoryCount = m_series->d_func()->categoryCount(); + qreal setCount = m_series->count(); + qreal barWidth = m_series->d_func()->barWidth(); + + m_layout.clear(); + for(int category = 0; category < categoryCount; category++) { + for (int set = 0; set < setCount; set++) { + QRectF rect; + QPointF topLeft; + QPointF bottomRight; + if (domain()->type() == AbstractDomain::LogXYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) { + topLeft = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category - barWidth / 2), m_validData); + bottomRight = domain()->calculateGeometryPoint(QPointF(domain()->minX(), category + barWidth / 2), m_validData); + } else { + topLeft = domain()->calculateGeometryPoint(QPointF(0, category - barWidth / 2), m_validData); + bottomRight = domain()->calculateGeometryPoint(QPointF(0, category + barWidth / 2), m_validData); + } + + if (!m_validData) + return; + + rect.setTopLeft(topLeft); + rect.setBottomRight(bottomRight); + m_layout.append(rect.normalized()); + } + } +} + +QVector<QRectF> HorizontalStackedBarChartItem::calculateLayout() +{ + QVector<QRectF> layout; + + // Use temporary qreals for accuracy + qreal categoryCount = m_series->d_func()->categoryCount(); + qreal setCount = m_series->count(); + qreal barWidth = m_series->d_func()->barWidth(); + + for(int category = 0; category < categoryCount; category++) { + qreal positiveSum = 0; + qreal negativeSum = 0; + for (int set = 0; set < setCount; set++) { + qreal value = m_series->barSets().at(set)->at(category); + QRectF rect; + QPointF topLeft; + QPointF bottomRight; + if (value < 0) { + bottomRight = domain()->calculateGeometryPoint(QPointF(value + negativeSum, category - barWidth / 2), m_validData); + if (domain()->type() == AbstractDomain::LogXYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) + topLeft = domain()->calculateGeometryPoint(QPointF(set ? negativeSum : domain()->minX(), category + barWidth / 2), m_validData); + else + topLeft = domain()->calculateGeometryPoint(QPointF(set ? negativeSum : 0, category + barWidth / 2), m_validData); + negativeSum += value; + } else { + bottomRight = domain()->calculateGeometryPoint(QPointF(value + positiveSum, category - barWidth / 2), m_validData); + if (domain()->type() == AbstractDomain::LogXYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) + topLeft = domain()->calculateGeometryPoint(QPointF(set ? positiveSum : domain()->minX(), category + barWidth / 2), m_validData); + else + topLeft = domain()->calculateGeometryPoint(QPointF(set ? positiveSum : 0, category + barWidth / 2), m_validData); + positiveSum += value; + } + + rect.setTopLeft(topLeft); + rect.setBottomRight(bottomRight); + layout.append(rect.normalized()); + } + } + return layout; +} + +#include "moc_horizontalstackedbarchartitem_p.cpp" + +QT_CHARTS_END_NAMESPACE + diff --git a/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem_p.h b/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem_p.h new file mode 100644 index 00000000..930a53a5 --- /dev/null +++ b/src/charts/barchart/horizontal/stacked/horizontalstackedbarchartitem_p.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef HORIZONTALSTACKEDBARCHARTITEM_P_H +#define HORIZONTALSTACKEDBARCHARTITEM_P_H + +#include "abstractbarchartitem_p.h" +#include <QGraphicsItem> + +QT_CHARTS_BEGIN_NAMESPACE + +class HorizontalStackedBarChartItem : public AbstractBarChartItem +{ + Q_OBJECT +public: + HorizontalStackedBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item = 0); + +private: + virtual QVector<QRectF> calculateLayout(); + void initializeLayout(); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // HORIZONTALSTACKEDBARCHARTITEM_P_H diff --git a/src/charts/barchart/horizontal/stacked/qhorizontalstackedbarseries.cpp b/src/charts/barchart/horizontal/stacked/qhorizontalstackedbarseries.cpp new file mode 100644 index 00000000..32c553bf --- /dev/null +++ b/src/charts/barchart/horizontal/stacked/qhorizontalstackedbarseries.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** 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 "qhorizontalstackedbarseries.h" +#include "qhorizontalstackedbarseries_p.h" +#include "horizontalstackedbarchartitem_p.h" + +#include "chartdataset_p.h" +#include "charttheme_p.h" + +QT_CHARTS_BEGIN_NAMESPACE +/*! + \class QHorizontalStackedBarSeries + \inmodule Qt Charts + \brief Series for creating horizontal stacked bar chart. + \mainclass + + QHorizontalStackedBarSeries represents a series of data shown as bars. The purpose of this class is to draw bars + as groups, where bars in same category are grouped next to each other. QHorizontalStackedBarSeries groups the data + from sets to categories, which are defined by a QStringList. + + See the \l {HorizontalStackedBarChart Example} {horizontal stacked bar chart example} to learn how to create a horizontal stacked bar chart. + \image examples_horizontalstackedbarchart.png + + \sa QBarSet, QBarSeries, QPercentBarSeries, QAbstractBarSeries, QStackedBarSeries, QHorizontalPercentBarSeries, QHorizontalBarSeries +*/ +/*! + \qmltype HorizontalStackedBarSeries + \instantiates QHorizontalStackedBarSeries + \inqmlmodule QtCharts + + \inherits AbstractBarSeries + + \brief Series type for creating horizontal stacked bar chart. + + The following QML shows how to create a simple horizontal stacked bar chart: + \snippet qmlchart/qml/qmlchart/View10.qml 1 + \beginfloatleft + \image examples_qmlchart10.png + \endfloat + \clearfloat +*/ + +/*! + Constructs empty QHorizontalStackedBarSeries. + QHorizontalStackedBarSeries is QObject which is a child of a \a parent. +*/ +QHorizontalStackedBarSeries::QHorizontalStackedBarSeries(QObject *parent) + : QAbstractBarSeries(*new QHorizontalStackedBarSeriesPrivate(this), parent) +{ +} + +/*! + Destructor. + Removes series from chart. +*/ +QHorizontalStackedBarSeries::~QHorizontalStackedBarSeries() +{ + Q_D(QHorizontalStackedBarSeries); + if (d->m_chart) + d->m_chart->removeSeries(this); +} + +/*! + Returns QAbstractSeries::SeriesTypeHorizontalStackedBar. +*/ +QAbstractSeries::SeriesType QHorizontalStackedBarSeries::type() const +{ + return QAbstractSeries::SeriesTypeHorizontalStackedBar; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QHorizontalStackedBarSeriesPrivate::QHorizontalStackedBarSeriesPrivate(QHorizontalStackedBarSeries *q) : QAbstractBarSeriesPrivate(q) +{ + +} + +void QHorizontalStackedBarSeriesPrivate::initializeDomain() +{ + qreal minX(domain()->minX()); + qreal minY(domain()->minY()); + qreal maxX(domain()->maxX()); + qreal maxY(domain()->maxY()); + + qreal y = categoryCount(); + minX = qMin(minX, bottom()); + minY = qMin(minY, - (qreal)0.5); + maxX = qMax(maxX, top()); + maxY = qMax(maxY, y - (qreal)0.5); + + domain()->setRange(minX, maxX, minY, maxY); +} + +void QHorizontalStackedBarSeriesPrivate::initializeGraphics(QGraphicsItem *parent) +{ + Q_Q(QHorizontalStackedBarSeries); + HorizontalStackedBarChartItem *bar = new HorizontalStackedBarChartItem(q,parent); + m_item.reset(bar); + QAbstractSeriesPrivate::initializeGraphics(parent); +} + +#include "moc_qhorizontalstackedbarseries.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/horizontal/stacked/qhorizontalstackedbarseries.h b/src/charts/barchart/horizontal/stacked/qhorizontalstackedbarseries.h new file mode 100644 index 00000000..fbcf4011 --- /dev/null +++ b/src/charts/barchart/horizontal/stacked/qhorizontalstackedbarseries.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QHORIZONTALSTACKEDBARSERIES_H +#define QHORIZONTALSTACKEDBARSERIES_H + +#include <QtCharts/qabstractbarseries.h> + +QT_CHARTS_BEGIN_NAMESPACE + +class QHorizontalStackedBarSeriesPrivate; + +class QT_CHARTS_EXPORT QHorizontalStackedBarSeries : public QAbstractBarSeries +{ + Q_OBJECT +public: + explicit QHorizontalStackedBarSeries(QObject *parent = 0); + ~QHorizontalStackedBarSeries(); + QAbstractSeries::SeriesType type() const; + +private: + Q_DECLARE_PRIVATE(QHorizontalStackedBarSeries) + Q_DISABLE_COPY(QHorizontalStackedBarSeries) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QHORIZONTALSTACKEDBARSERIES_H diff --git a/src/charts/barchart/horizontal/stacked/qhorizontalstackedbarseries_p.h b/src/charts/barchart/horizontal/stacked/qhorizontalstackedbarseries_p.h new file mode 100644 index 00000000..ab643ebd --- /dev/null +++ b/src/charts/barchart/horizontal/stacked/qhorizontalstackedbarseries_p.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QHORIZONTALSTACKEDBARSERIES_P_H +#define QHORIZONTALSTACKEDBARSERIES_P_H + +#include "qabstractbarseries_p.h" +#include "abstractdomain_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +class QHorizontalStackedBarSeriesPrivate: public QAbstractBarSeriesPrivate +{ +public: + QHorizontalStackedBarSeriesPrivate(QHorizontalStackedBarSeries *q); + void initializeGraphics(QGraphicsItem* parent); + void initializeDomain(); +private: + Q_DECLARE_PUBLIC(QHorizontalStackedBarSeries) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QHORIZONTALSTACKEDBARSERIES_P_H diff --git a/src/charts/barchart/qabstractbarseries.cpp b/src/charts/barchart/qabstractbarseries.cpp new file mode 100644 index 00000000..08345112 --- /dev/null +++ b/src/charts/barchart/qabstractbarseries.cpp @@ -0,0 +1,1030 @@ +/**************************************************************************** +** +** 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 "qabstractbarseries.h" +#include "qabstractbarseries_p.h" +#include "qbarset.h" +#include "qbarset_p.h" +#include "abstractdomain_p.h" +#include "chartdataset_p.h" +#include "charttheme_p.h" +#include "qvalueaxis.h" +#include "qbarcategoryaxis.h" +#include "qbarlegendmarker.h" +#include "baranimation_p.h" +#include "abstractbarchartitem_p.h" +#include "qchart_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +/*! + \class QAbstractBarSeries + \inmodule Qt Charts + \brief Series for creating a bar chart. + \mainclass + + QAbstractBarSeries represents a series of data shown as bars. The purpose of this class is to draw bars to + the position defined by data. Single bar is defined by QPointF, where x value is the x-coordinate of the bar + and y-value is the height of the bar. The category names are ignored with this series and x-axis + shows the x-values. + + See the \l {BarChart Example} {bar chart example} to learn how to create a simple bar chart. + \image examples_barchart.png + + \sa QBarSet, QStackedBarSeries, QPercentBarSeries +*/ +/*! + \qmltype AbstractBarSeries + \instantiates QAbstractBarSeries + \inqmlmodule QtCharts + + \inherits AbstractSeries + + \brief Series type for creating a bar chart. + + The following QML shows how to create a simple bar chart: + \snippet qmlchart/qml/qmlchart/View6.qml 1 + + \beginfloatleft + \image examples_qmlchart6.png + \endfloat + \clearfloat +*/ + +/*! + \qmlproperty AbstractAxis AbstractBarSeries::axisX + The x axis used for the series. If you leave both axisX and axisXTop undefined, a BarCategoriesAxis is created for + the series. + \sa axisXTop +*/ + +/*! + \qmlproperty AbstractAxis AbstractBarSeries::axisY + The y axis used for the series. If you leave both axisY and axisYRight undefined, a ValueAxis is created for + the series. + \sa axisYRight +*/ + +/*! + \qmlproperty AbstractAxis AbstractBarSeries::axisXTop + The x axis used for the series, drawn on top of the chart view. Note that you can only provide either axisX or + axisXTop, but not both. + \sa axisX +*/ + +/*! + \qmlproperty AbstractAxis AbstractBarSeries::axisYRight + The y axis used for the series, drawn to the right on the chart view. Note that you can only provide either axisY + or axisYRight, but not both. + \sa axisY +*/ + +/*! + \property QAbstractBarSeries::barWidth + The width of the bars of the series. The unit of \a width is the unit of x-axis. The minimum width for bars + is zero and negative values are treated as zero. Setting the width to zero means that width of the bar on screen + is one pixel no matter what the scale of x-axis is. Bars wider than zero are scaled with x-axis. + Note that with QBarSeries this value means the width of one group of bars instead of just one bar. + \sa QBarSeries +*/ +/*! + \qmlproperty real AbstractBarSeries::barWidth + The width of the bars of the series. The unit of width is the unit of x-axis. The minimum width for bars + is zero and negative values are treated as zero. Setting the width to zero means that width of the bar on screen + is one pixel no matter what the scale of x-axis is. Bars wider than zero are scaled with x-axis. + Note that with QBarSeries this value means the width of one group of bars instead of just one bar. +*/ + +/*! + \property QAbstractBarSeries::count + Holds the number of sets in series. +*/ +/*! + \qmlproperty int AbstractBarSeries::count + Holds the number of sets in series. +*/ + +/*! + \property QAbstractBarSeries::labelsVisible + Defines the visibility of the labels in series +*/ +/*! + \qmlproperty bool AbstractBarSeries::labelsVisible + Defines the visibility of the labels in series +*/ + +/*! + \property QAbstractBarSeries::labelsFormat + The \a format used for showing labels in series. + + QAbstractBarSeries supports the following format tag: + \table + \row + \li @value \li The value of the bar + \endtable + + For example, the following usage of the format tags would produce labels that show the value + followed by unit ('u'): + \code + series->setLabelsFormat("@value u"); + \endcode + + By default, the labels shows the value of the bar. For percent bar series '%' is added after + the value. The labels are shown on the plot area, labels on the edge of the plot area are cut. + If the bars are close to each other the labels may overlap. + + \sa QAbstractBarSeries::labelsVisible, QAbstractBarSeries::labelsPosition +*/ +/*! + \qmlproperty string AbstractBarSeries::labelsFormat + The format used for showing labels in series. + + \sa QAbstractBarSeries::labelsFormat, labelsVisible, labelsPosition +*/ +/*! + \fn void QAbstractBarSeries::labelsFormatChanged(const QString &format) + Signal is emitted when the \a format of data value labels is changed. +*/ +/*! + \qmlsignal XYSeries::onLabelsFormatChanged(string format) + Signal is emitted when the \a format of data value labels is changed. +*/ + +/*! + \enum QAbstractBarSeries::LabelsPosition + + This enum describes the position of the data value labels. + + \value LabelsCenter Label is in the center of the bar. + \value LabelsInsideEnd Label is inside the bar at the high end of it. + \value LabelsInsideBase Label is inside the bar at the low end of it. + \value LabelsOutsideEnd Label is outside the bar at the high end of it. + */ + +/*! + \property QAbstractBarSeries::labelsPosition + Defines the \a position of value labels. + + \sa QAbstractBarSeries::labelsVisible, QAbstractBarSeries::labelsFormat +*/ +/*! + \qmlproperty string AbstractBarSeries::labelsPosition + Defines the \a position of value labels. + + \sa labelsVisible, labelsFormat +*/ +/*! + \fn void QAbstractBarSeries::labelsPositionChanged(QAbstractBarSeries::LabelsPosition position) + Signal is emitted when the \a position of value labels is changed. +*/ +/*! + \qmlsignal AbstractBarSeries::onLabelsPositionChanged(LabelsPosition position) + Signal is emitted when the \a position of value labels is changed. +*/ + +/*! + \fn void QAbstractBarSeries::clicked(int index, QBarSet *barset) + The signal is emitted if the user clicks with a mouse on top of QBarSet \a barset. + Clicked bar inside set is indexed by \a index +*/ +/*! + \qmlsignal AbstractBarSeries::onClicked(int index, BarSet barset) + The signal is emitted if the user clicks with a mouse on top of BarSet. + Clicked bar inside set is indexed by \a index +*/ + +/*! + \fn void QAbstractBarSeries::hovered(bool status, QBarSet* barset) + + The signal is emitted if mouse is hovered on top of series. + Parameter \a barset is the pointer of barset, where hover happened. + Parameter \a status is true, if mouse entered on top of series, false if mouse left from top of series. +*/ + +/*! + \fn void QAbstractBarSeries::hovered(bool status, int index, QBarSet* barset) + + The signal is emitted if mouse is hovered on top of series. + Parameter \a barset is the pointer of barset, where hover happened. + Parameter \a status is true, if mouse entered on top of series, false if mouse left from top of series. + Hovered bar inside the set is indexed by \a index. +*/ +/*! + \qmlsignal AbstractBarSeries::onHovered(bool status, int index, BarSet barset) + + The signal is emitted if mouse is hovered on top of series. + Parameter \a barset is the pointer of barset, where hover happened. + Parameter \a status is true, if mouse entered on top of series, false if mouse left from top of series. + Hovered bar inside the set is indexed by \a index. +*/ + +/*! + \fn void QAbstractBarSeries::countChanged() + This signal is emitted when barset count has been changed, for example by append or remove. +*/ +/*! + \qmlsignal AbstractBarSeries::onCountChanged() + This signal is emitted when barset count has been changed, for example by append or remove. +*/ + +/*! + \fn void QAbstractBarSeries::labelsVisibleChanged() + This signal is emitted when labels visibility have changed. + \sa isLabelsVisible(), setLabelsVisible() +*/ + +/*! + \fn void QAbstractBarSeries::barsetsAdded(QList<QBarSet*> sets) + This signal is emitted when \a sets have been added to the series. + \sa append(), insert() +*/ +/*! + \qmlsignal AbstractBarSeries::onBarsetsAdded(BarSet barset) + Emitted when \a barset has been added to the series. +*/ + +/*! + \fn void QAbstractBarSeries::barsetsRemoved(QList<QBarSet*> sets) + This signal is emitted when \a sets have been removed from the series. + \sa remove() +*/ +/*! + \qmlsignal AbstractBarSeries::onBarsetsRemoved(BarSet barset) + Emitted when \a barset has been removed from the series. +*/ + +/*! + \qmlmethod BarSet AbstractBarSeries::at(int index) + Returns bar set at \a index. Returns null if the index is not valid. +*/ + +/*! + \qmlmethod BarSet AbstractBarSeries::append(string label, VariantList values) + Adds a new bar set with \a label and \a values to \a index. Values is a list of reals. + For example: + \code + myBarSeries.append("set 1", [0, 0.2, 0.2, 0.5, 0.4, 1.5, 0.9]); + \endcode +*/ + +/*! + \qmlmethod BarSet AbstractBarSeries::insert(int index, string label, VariantList values) + Inserts a new bar set with \a label and \a values to \a index. Values can be a list of reals or a list of XYPoints. + If index is zero or smaller, the new barset is prepended. If the index is count or bigger, the new barset is + appended. + \sa AbstractBarSeries::append() +*/ + +/*! + \qmlmethod bool AbstractBarSeries::remove(BarSet barset) + Removes the barset from the series. Returns true if successful, false otherwise. +*/ + +/*! + \qmlmethod AbstractBarSeries::clear() + Removes all barsets from the series. +*/ + +/*! + Destructs abstractbarseries and owned barsets. +*/ +QAbstractBarSeries::~QAbstractBarSeries() +{ + +} + +/*! + \internal +*/ +QAbstractBarSeries::QAbstractBarSeries(QAbstractBarSeriesPrivate &o, QObject *parent) + : QAbstractSeries(o, parent) +{ + Q_D(QAbstractSeries); + QObject::connect(this, SIGNAL(countChanged()), d, SIGNAL(countChanged())); +} + +/*! + Sets the width of the bars of the series. The unit of \a width is the unit of x-axis. The minimum width for bars + is zero and negative values are treated as zero. Setting the width to zero means that width of the bar on screen + is one pixel no matter what the scale of x-axis is. Bars wider than zero are scaled with x-axis. + Note that with \link QBarSeries \endlink this value means the width of one group of bars instead of just one bar. +*/ +void QAbstractBarSeries::setBarWidth(qreal width) +{ + Q_D(QAbstractBarSeries); + d->setBarWidth(width); +} + +/*! + Returns the width of the bars of the series. + \sa setBarWidth() +*/ +qreal QAbstractBarSeries::barWidth() const +{ + Q_D(const QAbstractBarSeries); + return d->barWidth(); +} + +/*! + Adds a set of bars to series. Takes ownership of \a set. If the set is null or is already in series, it won't be appended. + Returns true, if appending succeeded. +*/ +bool QAbstractBarSeries::append(QBarSet *set) +{ + Q_D(QAbstractBarSeries); + bool success = d->append(set); + if (success) { + QList<QBarSet *> sets; + sets.append(set); + set->setParent(this); + emit barsetsAdded(sets); + emit countChanged(); + } + return success; +} + +/*! + Removes barset from series. Releases ownership of \a set. Deletes the set, if remove + was successful. + Returns true, if set was removed. +*/ +bool QAbstractBarSeries::remove(QBarSet *set) +{ + Q_D(QAbstractBarSeries); + bool success = d->remove(set); + if (success) { + QList<QBarSet *> sets; + sets.append(set); + set->setParent(0); + emit barsetsRemoved(sets); + emit countChanged(); + delete set; + set = 0; + } + return success; +} + +/*! + Takes a single \a set from the series. Does not delete the barset object. + + NOTE: The series remains as the barset's parent object. You must set the + parent object to take full ownership. + + Returns true if take was successful. +*/ +bool QAbstractBarSeries::take(QBarSet *set) +{ + Q_D(QAbstractBarSeries); + bool success = d->remove(set); + if (success) { + QList<QBarSet *> sets; + sets.append(set); + emit barsetsRemoved(sets); + emit countChanged(); + } + return success; +} + +/*! + Adds a list of barsets to series. Takes ownership of \a sets. + Returns true, if all sets were appended successfully. If any of the sets is null or is already appended to series, + nothing is appended and function returns false. If any of the sets is in list more than once, nothing is appended + and function returns false. +*/ +bool QAbstractBarSeries::append(QList<QBarSet *> sets) +{ + Q_D(QAbstractBarSeries); + bool success = d->append(sets); + if (success) { + emit barsetsAdded(sets); + emit countChanged(); + } + return success; +} + +/*! + Insert a set of bars to series at \a index postion. Takes ownership of \a set. If the set is null or is already in series, it won't be appended. + Returns true, if inserting succeeded. + +*/ +bool QAbstractBarSeries::insert(int index, QBarSet *set) +{ + Q_D(QAbstractBarSeries); + bool success = d->insert(index, set); + if (success) { + QList<QBarSet *> sets; + sets.append(set); + emit barsetsAdded(sets); + emit countChanged(); + } + return success; +} + +/*! + Removes all barsets from the series. Deletes removed sets. +*/ +void QAbstractBarSeries::clear() +{ + Q_D(QAbstractBarSeries); + QList<QBarSet *> sets = barSets(); + bool success = d->remove(sets); + if (success) { + emit barsetsRemoved(sets); + emit countChanged(); + foreach (QBarSet *set, sets) + delete set; + } +} + +/*! + Returns number of sets in series. +*/ +int QAbstractBarSeries::count() const +{ + Q_D(const QAbstractBarSeries); + return d->m_barSets.count(); +} + +/*! + Returns a list of sets in series. Keeps ownership of sets. + */ +QList<QBarSet *> QAbstractBarSeries::barSets() const +{ + Q_D(const QAbstractBarSeries); + return d->m_barSets; +} + +/*! + Sets the visibility of labels in series to \a visible +*/ +void QAbstractBarSeries::setLabelsVisible(bool visible) +{ + Q_D(QAbstractBarSeries); + if (d->m_labelsVisible != visible) { + d->setLabelsVisible(visible); + emit labelsVisibleChanged(); + } +} + +/*! + Returns the visibility of labels +*/ +bool QAbstractBarSeries::isLabelsVisible() const +{ + Q_D(const QAbstractBarSeries); + return d->m_labelsVisible; +} + +void QAbstractBarSeries::setLabelsFormat(const QString &format) +{ + Q_D(QAbstractBarSeries); + if (d->m_labelsFormat != format) { + d->m_labelsFormat = format; + emit labelsFormatChanged(format); + } +} + +QString QAbstractBarSeries::labelsFormat() const +{ + Q_D(const QAbstractBarSeries); + return d->m_labelsFormat; +} + +void QAbstractBarSeries::setLabelsPosition(QAbstractBarSeries::LabelsPosition position) +{ + Q_D(QAbstractBarSeries); + if (d->m_labelsPosition != position) { + d->m_labelsPosition = position; + emit labelsPositionChanged(position); + } +} + +QAbstractBarSeries::LabelsPosition QAbstractBarSeries::labelsPosition() const +{ + Q_D(const QAbstractBarSeries); + return d->m_labelsPosition; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QAbstractBarSeriesPrivate::QAbstractBarSeriesPrivate(QAbstractBarSeries *q) : + QAbstractSeriesPrivate(q), + m_barWidth(0.5), // Default value is 50% of category width + m_labelsVisible(false), + m_visible(true), + m_blockBarUpdate(false), + m_labelsFormat(), + m_labelsPosition(QAbstractBarSeries::LabelsCenter) +{ +} + +int QAbstractBarSeriesPrivate::categoryCount() const +{ + // No categories defined. return count of longest set. + int count = 0; + for (int i = 0; i < m_barSets.count(); i++) { + if (m_barSets.at(i)->count() > count) + count = m_barSets.at(i)->count(); + } + + return count; +} + +void QAbstractBarSeriesPrivate::setBarWidth(qreal width) +{ + if (width < 0.0) + width = 0.0; + m_barWidth = width; + emit updatedLayout(); +} + +qreal QAbstractBarSeriesPrivate::barWidth() const +{ + return m_barWidth; +} + +QBarSet *QAbstractBarSeriesPrivate::barsetAt(int index) +{ + return m_barSets.at(index); +} + +void QAbstractBarSeriesPrivate::setVisible(bool visible) +{ + m_visible = visible; + emit visibleChanged(); +} + +void QAbstractBarSeriesPrivate::setLabelsVisible(bool visible) +{ + m_labelsVisible = visible; + emit labelsVisibleChanged(visible); +} + +qreal QAbstractBarSeriesPrivate::min() +{ + if (m_barSets.count() <= 0) + return 0; + + qreal min = INT_MAX; + + for (int i = 0; i < m_barSets.count(); i++) { + int categoryCount = m_barSets.at(i)->count(); + for (int j = 0; j < categoryCount; j++) { + qreal temp = m_barSets.at(i)->at(j); + if (temp < min) + min = temp; + } + } + return min; +} + +qreal QAbstractBarSeriesPrivate::max() +{ + if (m_barSets.count() <= 0) + return 0; + + qreal max = INT_MIN; + + for (int i = 0; i < m_barSets.count(); i++) { + int categoryCount = m_barSets.at(i)->count(); + for (int j = 0; j < categoryCount; j++) { + qreal temp = m_barSets.at(i)->at(j); + if (temp > max) + max = temp; + } + } + + return max; +} + +qreal QAbstractBarSeriesPrivate::valueAt(int set, int category) +{ + if ((set < 0) || (set >= m_barSets.count())) + return 0; // No set, no value. + else if ((category < 0) || (category >= m_barSets.at(set)->count())) + return 0; // No category, no value. + + return m_barSets.at(set)->at(category); +} + +qreal QAbstractBarSeriesPrivate::percentageAt(int set, int category) +{ + if ((set < 0) || (set >= m_barSets.count())) + return 0; // No set, no value. + else if ((category < 0) || (category >= m_barSets.at(set)->count())) + return 0; // No category, no value. + + qreal value = m_barSets.at(set)->at(category); + qreal sum = categorySum(category); + if (qFuzzyCompare(sum, 0)) + return 0; + + return value / sum; +} + +qreal QAbstractBarSeriesPrivate::categorySum(int category) +{ + qreal sum(0); + int count = m_barSets.count(); // Count sets + for (int set = 0; set < count; set++) { + if (category < m_barSets.at(set)->count()) + sum += m_barSets.at(set)->at(category); + } + return sum; +} + +qreal QAbstractBarSeriesPrivate::absoluteCategorySum(int category) +{ + qreal sum(0); + int count = m_barSets.count(); // Count sets + for (int set = 0; set < count; set++) { + if (category < m_barSets.at(set)->count()) + sum += qAbs(m_barSets.at(set)->at(category)); + } + return sum; +} + +qreal QAbstractBarSeriesPrivate::maxCategorySum() +{ + qreal max = INT_MIN; + int count = categoryCount(); + for (int i = 0; i < count; i++) { + qreal sum = categorySum(i); + if (sum > max) + max = sum; + } + return max; +} + +qreal QAbstractBarSeriesPrivate::minX() +{ + if (m_barSets.count() <= 0) + return 0; + + qreal min = INT_MAX; + + for (int i = 0; i < m_barSets.count(); i++) { + int categoryCount = m_barSets.at(i)->count(); + for (int j = 0; j < categoryCount; j++) { + qreal temp = m_barSets.at(i)->d_ptr.data()->m_values.at(j).x(); + if (temp < min) + min = temp; + } + } + return min; +} + +qreal QAbstractBarSeriesPrivate::maxX() +{ + if (m_barSets.count() <= 0) + return 0; + + qreal max = INT_MIN; + + for (int i = 0; i < m_barSets.count(); i++) { + int categoryCount = m_barSets.at(i)->count(); + for (int j = 0; j < categoryCount; j++) { + qreal temp = m_barSets.at(i)->d_ptr.data()->m_values.at(j).x(); + if (temp > max) + max = temp; + } + } + + return max; +} + +qreal QAbstractBarSeriesPrivate::categoryTop(int category) +{ + // Returns top (sum of all positive values) of category. + // Returns 0, if all values are negative + qreal top(0); + int count = m_barSets.count(); + for (int set = 0; set < count; set++) { + if (category < m_barSets.at(set)->count()) { + qreal temp = m_barSets.at(set)->at(category); + if (temp > 0) { + top += temp; + } + } + } + return top; +} + +qreal QAbstractBarSeriesPrivate::categoryBottom(int category) +{ + // Returns bottom (sum of all negative values) of category + // Returns 0, if all values are positive + qreal bottom(0); + int count = m_barSets.count(); + for (int set = 0; set < count; set++) { + if (category < m_barSets.at(set)->count()) { + qreal temp = m_barSets.at(set)->at(category); + if (temp < 0) { + bottom += temp; + } + } + } + return bottom; +} + +qreal QAbstractBarSeriesPrivate::top() +{ + // Returns top of all categories + qreal top(0); + int count = categoryCount(); + for (int i = 0; i < count; i++) { + qreal temp = categoryTop(i); + if (temp > top) + top = temp; + } + return top; +} + +qreal QAbstractBarSeriesPrivate::bottom() +{ + // Returns bottom of all categories + qreal bottom(0); + int count = categoryCount(); + for (int i = 0; i < count; i++) { + qreal temp = categoryBottom(i); + if (temp < bottom) + bottom = temp; + } + return bottom; +} + +bool QAbstractBarSeriesPrivate::blockBarUpdate() +{ + return m_blockBarUpdate; +} + +void QAbstractBarSeriesPrivate::initializeDomain() +{ + qreal minX(domain()->minX()); + qreal minY(domain()->minY()); + qreal maxX(domain()->maxX()); + qreal maxY(domain()->maxY()); + + qreal seriesMinX = this->minX(); + qreal seriesMaxX = this->maxX(); + qreal y = max(); + minX = qMin(minX, seriesMinX - (qreal)0.5); + minY = qMin(minY, y); + maxX = qMax(maxX, seriesMaxX + (qreal)0.5); + maxY = qMax(maxY, y); + + domain()->setRange(minX, maxX, minY, maxY); +} + +QList<QLegendMarker*> QAbstractBarSeriesPrivate::createLegendMarkers(QLegend* legend) +{ + Q_Q(QAbstractBarSeries); + QList<QLegendMarker*> markers; + + foreach(QBarSet* set, q->barSets()) { + QBarLegendMarker* marker = new QBarLegendMarker(q,set,legend); + markers << marker; + } + return markers; +} + + +bool QAbstractBarSeriesPrivate::append(QBarSet *set) +{ + if ((m_barSets.contains(set)) || (set == 0)) + return false; // Fail if set is already in list or set is null. + + m_barSets.append(set); + QObject::connect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout())); + QObject::connect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SIGNAL(updatedBars())); + QObject::connect(set->d_ptr.data(), SIGNAL(restructuredBars()), this, SIGNAL(restructuredBars())); + + emit restructuredBars(); // this notifies barchartitem + return true; +} + +bool QAbstractBarSeriesPrivate::remove(QBarSet *set) +{ + if (!m_barSets.contains(set)) + return false; // Fail if set is not in list + + m_barSets.removeOne(set); + QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout())); + QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SIGNAL(updatedBars())); + QObject::disconnect(set->d_ptr.data(), SIGNAL(restructuredBars()), this, SIGNAL(restructuredBars())); + + emit restructuredBars(); // this notifies barchartitem + return true; +} + +bool QAbstractBarSeriesPrivate::append(QList<QBarSet * > sets) +{ + foreach (QBarSet *set, sets) { + if ((set == 0) || (m_barSets.contains(set))) + return false; // Fail if any of the sets is null or is already appended. + if (sets.count(set) != 1) + return false; // Also fail if same set is more than once in given list. + } + + foreach (QBarSet *set, sets) { + m_barSets.append(set); + QObject::connect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout())); + QObject::connect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SIGNAL(updatedBars())); + QObject::connect(set->d_ptr.data(), SIGNAL(restructuredBars()), this, SIGNAL(restructuredBars())); + } + + emit restructuredBars(); // this notifies barchartitem + return true; +} + +bool QAbstractBarSeriesPrivate::remove(QList<QBarSet * > sets) +{ + if (sets.count() == 0) + return false; + + foreach (QBarSet *set, sets) { + if ((set == 0) || (!m_barSets.contains(set))) + return false; // Fail if any of the sets is null or is not in series + if (sets.count(set) != 1) + return false; // Also fail if same set is more than once in given list. + } + + foreach (QBarSet *set, sets) { + m_barSets.removeOne(set); + QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout())); + QObject::disconnect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SIGNAL(updatedBars())); + QObject::disconnect(set->d_ptr.data(), SIGNAL(restructuredBars()), this, SIGNAL(restructuredBars())); + } + + emit restructuredBars(); // this notifies barchartitem + + return true; +} + +bool QAbstractBarSeriesPrivate::insert(int index, QBarSet *set) +{ + if ((m_barSets.contains(set)) || (set == 0)) + return false; // Fail if set is already in list or set is null. + + m_barSets.insert(index, set); + QObject::connect(set->d_ptr.data(), SIGNAL(updatedLayout()), this, SIGNAL(updatedLayout())); + QObject::connect(set->d_ptr.data(), SIGNAL(updatedBars()), this, SIGNAL(updatedBars())); + QObject::connect(set->d_ptr.data(), SIGNAL(restructuredBars()), this, SIGNAL(restructuredBars())); + + emit restructuredBars(); // this notifies barchartitem + return true; +} + +void QAbstractBarSeriesPrivate::initializeAxes() +{ + Q_Q(QAbstractBarSeries); + + foreach(QAbstractAxis* axis, m_axes) { + + if (axis->type() == QAbstractAxis::AxisTypeBarCategory) { + switch (q->type()) { + case QAbstractSeries::SeriesTypeHorizontalBar: + case QAbstractSeries::SeriesTypeHorizontalPercentBar: + case QAbstractSeries::SeriesTypeHorizontalStackedBar: + if (axis->orientation() == Qt::Vertical) + populateCategories(qobject_cast<QBarCategoryAxis *>(axis)); + break; + case QAbstractSeries::SeriesTypeBar: + case QAbstractSeries::SeriesTypePercentBar: + case QAbstractSeries::SeriesTypeStackedBar: + case QAbstractSeries::SeriesTypeBoxPlot: + if (axis->orientation() == Qt::Horizontal) + populateCategories(qobject_cast<QBarCategoryAxis *>(axis)); + break; + default: + qWarning() << "Unexpected series type"; + break; + } + } + } +} + +QAbstractAxis::AxisType QAbstractBarSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const +{ + Q_Q(const QAbstractBarSeries); + + switch (q->type()) { + case QAbstractSeries::SeriesTypeHorizontalBar: + case QAbstractSeries::SeriesTypeHorizontalPercentBar: + case QAbstractSeries::SeriesTypeHorizontalStackedBar: + if (orientation == Qt::Vertical) + return QAbstractAxis::AxisTypeBarCategory; + break; + case QAbstractSeries::SeriesTypeBar: + case QAbstractSeries::SeriesTypePercentBar: + case QAbstractSeries::SeriesTypeStackedBar: + case QAbstractSeries::SeriesTypeBoxPlot: + if (orientation == Qt::Horizontal) + return QAbstractAxis::AxisTypeBarCategory; + break; + default: + qWarning() << "Unexpected series type"; + break; + } + return QAbstractAxis::AxisTypeValue; + +} + +void QAbstractBarSeriesPrivate::populateCategories(QBarCategoryAxis *axis) +{ + QStringList categories; + if (axis->categories().isEmpty()) { + for (int i(1); i < categoryCount() + 1; i++) + categories << presenter()->numberToString(i); + axis->append(categories); + } +} + +QAbstractAxis* QAbstractBarSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const +{ + if (defaultAxisType(orientation) == QAbstractAxis::AxisTypeBarCategory) + return new QBarCategoryAxis; + else + return new QValueAxis; +} + +void QAbstractBarSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced) +{ + m_blockBarUpdate = true; // Ensures that the bars are not updated before the theme is ready + + const QList<QGradient> gradients = theme->seriesGradients(); + + qreal takeAtPos = 0.5; + qreal step = 0.2; + if (m_barSets.count() > 1) { + step = 1.0 / (qreal) m_barSets.count(); + if (m_barSets.count() % gradients.count()) + step *= gradients.count(); + else + step *= (gradients.count() - 1); + } + + for (int i(0); i < m_barSets.count(); i++) { + int colorIndex = (index + i) % gradients.count(); + if (i > 0 && i %gradients.count() == 0) { + // There is no dedicated base color for each sets, generate more colors + takeAtPos += step; + if (takeAtPos == 1.0) + takeAtPos += step; + takeAtPos -= (int) takeAtPos; + } + if (forced || QChartPrivate::defaultBrush() == m_barSets.at(i)->d_ptr->m_brush) + m_barSets.at(i)->setBrush(ChartThemeManager::colorAt(gradients.at(colorIndex), takeAtPos)); + + // Pick label color from the opposite end of the gradient. + // 0.3 as a boundary seems to work well. + if (forced || QChartPrivate::defaultBrush() == m_barSets.at(i)->d_ptr->m_labelBrush) { + if (takeAtPos < 0.3) + m_barSets.at(i)->setLabelBrush(ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 1)); + else + m_barSets.at(i)->setLabelBrush(ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 0)); + } + if (forced || QChartPrivate::defaultPen() == m_barSets.at(i)->d_ptr->m_pen) { + QColor c = ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 0.0); + m_barSets.at(i)->setPen(c); + } + } + m_blockBarUpdate = false; + emit updatedBars(); +} + +void QAbstractBarSeriesPrivate::initializeAnimations(QChart::AnimationOptions options) +{ + AbstractBarChartItem *bar = static_cast<AbstractBarChartItem *>(m_item.data()); + Q_ASSERT(bar); + if (bar->animation()) + bar->animation()->stopAndDestroyLater(); + + if (options.testFlag(QChart::SeriesAnimations)) + bar->setAnimation(new BarAnimation(bar)); + else + bar->setAnimation(0); + QAbstractSeriesPrivate::initializeAnimations(options); +} + +#include "moc_qabstractbarseries.cpp" +#include "moc_qabstractbarseries_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/qabstractbarseries.h b/src/charts/barchart/qabstractbarseries.h new file mode 100644 index 00000000..85f32ff7 --- /dev/null +++ b/src/charts/barchart/qabstractbarseries.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QABSTRACTBARSERIES_H +#define QABSTRACTBARSERIES_H + +#include <QtCharts/qabstractseries.h> +#include <QStringList> + +QT_CHARTS_BEGIN_NAMESPACE + +class QBarSet; +class QAbstractBarSeriesPrivate; + +// Container for series +class QT_CHARTS_EXPORT QAbstractBarSeries : public QAbstractSeries +{ + Q_OBJECT + Q_PROPERTY(qreal barWidth READ barWidth WRITE setBarWidth) + Q_PROPERTY(int count READ count NOTIFY countChanged) + Q_PROPERTY(bool labelsVisible READ isLabelsVisible WRITE setLabelsVisible NOTIFY labelsVisibleChanged) + Q_PROPERTY(QString labelsFormat READ labelsFormat WRITE setLabelsFormat NOTIFY labelsFormatChanged) + Q_PROPERTY(LabelsPosition labelsPosition READ labelsPosition WRITE setLabelsPosition NOTIFY labelsPositionChanged) + Q_ENUMS(LabelsPosition) + +public: + enum LabelsPosition { + LabelsCenter = 0, + LabelsInsideEnd, + LabelsInsideBase, + LabelsOutsideEnd + }; + +public: + virtual ~QAbstractBarSeries(); + + void setBarWidth(qreal width); + qreal barWidth() const; + + bool append(QBarSet *set); + bool remove(QBarSet *set); + bool take(QBarSet *set); + bool append(QList<QBarSet *> sets); + bool insert(int index, QBarSet *set); + int count() const; + QList<QBarSet *> barSets() const; + void clear(); + + void setLabelsVisible(bool visible = true); + bool isLabelsVisible() const; + + void setLabelsFormat(const QString &format); + QString labelsFormat() const; + + void setLabelsPosition(QAbstractBarSeries::LabelsPosition position); + QAbstractBarSeries::LabelsPosition labelsPosition() const; + +protected: + explicit QAbstractBarSeries(QAbstractBarSeriesPrivate &d, QObject *parent = 0); + +Q_SIGNALS: + void clicked(int index, QBarSet *barset); + void hovered(bool status, QBarSet *barset); + void hovered(bool status, int index, QBarSet *barset); + void countChanged(); + void labelsVisibleChanged(); + void labelsFormatChanged(const QString &format); + void labelsPositionChanged(QAbstractBarSeries::LabelsPosition position); + + void barsetsAdded(QList<QBarSet *> sets); + void barsetsRemoved(QList<QBarSet *> sets); + +protected: + Q_DECLARE_PRIVATE(QAbstractBarSeries) + friend class AbstractBarChartItem; + friend class PercentBarChartItem; + friend class StackedBarChartItem; + friend class BoxPlotChartItem; + friend class BarChartItem; + friend class HorizontalBarChartItem; + friend class HorizontalStackedBarChartItem; + friend class HorizontalPercentBarChartItem; + friend class BarSet; +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QABSTRACTBARSERIES_H diff --git a/src/charts/barchart/qabstractbarseries_p.h b/src/charts/barchart/qabstractbarseries_p.h new file mode 100644 index 00000000..c7b0b827 --- /dev/null +++ b/src/charts/barchart/qabstractbarseries_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QABSTRACTBARSERIES_P_H +#define QABSTRACTBARSERIES_P_H + +#include <QtCharts/qabstractbarseries.h> +#include "qabstractseries_p.h" +#include <QStringList> +#include <QAbstractSeries> + +QT_CHARTS_BEGIN_NAMESPACE + +class QBarModelMapper; +class QBarCategoryAxis; +class QLegendMarker; + +class QAbstractBarSeriesPrivate : public QAbstractSeriesPrivate +{ + Q_OBJECT +public: + QAbstractBarSeriesPrivate(QAbstractBarSeries *parent); + int categoryCount() const; + + void setBarWidth(qreal width); + qreal barWidth() const; + + void setVisible(bool visible); + void setLabelsVisible(bool visible); + + void initializeDomain(); + void initializeAxes(); + void initializeAnimations(QChart::AnimationOptions options); + void initializeTheme(int index, ChartTheme* theme, bool forced = false); + + QList<QLegendMarker*> createLegendMarkers(QLegend *legend); + + virtual QAbstractAxis::AxisType defaultAxisType(Qt::Orientation orientation) const; + QAbstractAxis* createDefaultAxis(Qt::Orientation orientation) const; + + bool append(QBarSet *set); + bool remove(QBarSet *set); + bool append(QList<QBarSet *> sets); + bool remove(QList<QBarSet *> sets); + bool insert(int index, QBarSet *set); + + QBarSet *barsetAt(int index); + qreal min(); + qreal max(); + qreal valueAt(int set, int category); + qreal percentageAt(int set, int category); + qreal categorySum(int category); + qreal absoluteCategorySum(int category); + qreal maxCategorySum(); + qreal minX(); + qreal maxX(); + qreal categoryTop(int category); + qreal categoryBottom(int category); + qreal top(); + qreal bottom(); + + bool blockBarUpdate(); + +Q_SIGNALS: + void clicked(int index, QBarSet *barset); + void updatedBars(); + void updatedLayout(); + void restructuredBars(); + void labelsVisibleChanged(bool visible); + void visibleChanged(); + +private: + void populateCategories(QBarCategoryAxis *axis); + +protected: + QList<QBarSet *> m_barSets; + qreal m_barWidth; + bool m_labelsVisible; + bool m_visible; + bool m_blockBarUpdate; + QString m_labelsFormat; + QAbstractBarSeries::LabelsPosition m_labelsPosition; + +private: + Q_DECLARE_PUBLIC(QAbstractBarSeries) + friend class HorizontalBarChartItem; + friend class BarChartItem; +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QABSTRACTBARSERIES_P_H diff --git a/src/charts/barchart/qbarmodelmapper.cpp b/src/charts/barchart/qbarmodelmapper.cpp new file mode 100644 index 00000000..459a72ca --- /dev/null +++ b/src/charts/barchart/qbarmodelmapper.cpp @@ -0,0 +1,561 @@ +/**************************************************************************** +** +** 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 "qbarmodelmapper.h" +#include "qbarmodelmapper_p.h" +#include "qabstractbarseries.h" +#include "qbarset.h" +#include "qchart.h" +#include <QAbstractItemModel> + +QT_CHARTS_BEGIN_NAMESPACE + +QBarModelMapper::QBarModelMapper(QObject *parent) : + QObject(parent), + d_ptr(new QBarModelMapperPrivate(this)) +{ +} + +QAbstractItemModel *QBarModelMapper::model() const +{ + Q_D(const QBarModelMapper); + return d->m_model; +} + +void QBarModelMapper::setModel(QAbstractItemModel *model) +{ + if (model == 0) + return; + + Q_D(QBarModelMapper); + if (d->m_model) + disconnect(d->m_model, 0, d, 0); + + d->m_model = model; + d->initializeBarFromModel(); + // connect signals from the model + connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex))); + connect(d->m_model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), d, SLOT(modelHeaderDataUpdated(Qt::Orientation,int,int))); + connect(d->m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), d, SLOT(modelRowsAdded(QModelIndex,int,int))); + connect(d->m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), d, SLOT(modelRowsRemoved(QModelIndex,int,int))); + connect(d->m_model, SIGNAL(columnsInserted(QModelIndex,int,int)), d, SLOT(modelColumnsAdded(QModelIndex,int,int))); + connect(d->m_model, SIGNAL(columnsRemoved(QModelIndex,int,int)), d, SLOT(modelColumnsRemoved(QModelIndex,int,int))); + connect(d->m_model, SIGNAL(destroyed()), d, SLOT(handleModelDestroyed())); +} + +QAbstractBarSeries *QBarModelMapper::series() const +{ + Q_D(const QBarModelMapper); + return d->m_series; +} + +void QBarModelMapper::setSeries(QAbstractBarSeries *series) +{ + Q_D(QBarModelMapper); + if (d->m_series) + disconnect(d->m_series, 0, d, 0); + + if (series == 0) + return; + + d->m_series = series; + d->initializeBarFromModel(); + // connect the signals from the series + connect(d->m_series, SIGNAL(barsetsAdded(QList<QBarSet*>)), d, SLOT(barSetsAdded(QList<QBarSet*>))); + connect(d->m_series, SIGNAL(barsetsRemoved(QList<QBarSet*>)), d, SLOT(barSetsRemoved(QList<QBarSet*>))); + connect(d->m_series, SIGNAL(destroyed()), d, SLOT(handleSeriesDestroyed())); +} + +/*! + Returns which row/column of the model contains the first values of the QBarSets in the series. + The default value is 0. +*/ +int QBarModelMapper::first() const +{ + Q_D(const QBarModelMapper); + return d->m_first; +} + +/*! + Sets which row of the model contains the \a first values of the QBarSets in the series. + The default value is 0. +*/ +void QBarModelMapper::setFirst(int first) +{ + Q_D(QBarModelMapper); + d->m_first = qMax(first, 0); + d->initializeBarFromModel(); +} + +/*! + Returns the number of rows/columns of the model that are mapped as the data for QAbstractBarSeries + Minimal and default value is: -1 (count limited by the number of rows/columns in the model) +*/ +int QBarModelMapper::count() const +{ + Q_D(const QBarModelMapper); + return d->m_count; +} + +/*! + Sets the \a count of rows/columns of the model that are mapped as the data for QAbstractBarSeries + Minimal and default value is: -1 (count limited by the number of rows/columns in the model) +*/ +void QBarModelMapper::setCount(int count) +{ + Q_D(QBarModelMapper); + d->m_count = qMax(count, -1); + d->initializeBarFromModel(); +} + +/*! + Returns the orientation that is used when QBarModelMapper accesses the model. + This mean whether the consecutive values of the bar set are read from row (Qt::Horizontal) + or from columns (Qt::Vertical) +*/ +Qt::Orientation QBarModelMapper::orientation() const +{ + Q_D(const QBarModelMapper); + return d->m_orientation; +} + +/*! + Returns the \a orientation that is used when QBarModelMapper accesses the model. + This mean whether the consecutive values of the pie are read from row (Qt::Horizontal) + or from columns (Qt::Vertical) +*/ +void QBarModelMapper::setOrientation(Qt::Orientation orientation) +{ + Q_D(QBarModelMapper); + d->m_orientation = orientation; + d->initializeBarFromModel(); +} + +/*! + Returns which section of the model is used as the data source for the first bar set +*/ +int QBarModelMapper::firstBarSetSection() const +{ + Q_D(const QBarModelMapper); + return d->m_firstBarSetSection; +} + +/*! + Sets the model section that is used as the data source for the first bar set + Parameter \a firstBarSetSection specifies the section of the model. +*/ +void QBarModelMapper::setFirstBarSetSection(int firstBarSetSection) +{ + Q_D(QBarModelMapper); + d->m_firstBarSetSection = qMax(-1, firstBarSetSection); + d->initializeBarFromModel(); +} + +/*! + Returns which section of the model is used as the data source for the last bar set +*/ +int QBarModelMapper::lastBarSetSection() const +{ + Q_D(const QBarModelMapper); + return d->m_lastBarSetSection; +} + +/*! + Sets the model section that is used as the data source for the last bar set + Parameter \a lastBarSetSection specifies the section of the model. +*/ +void QBarModelMapper::setLastBarSetSection(int lastBarSetSection) +{ + Q_D(QBarModelMapper); + d->m_lastBarSetSection = qMax(-1, lastBarSetSection); + d->initializeBarFromModel(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QBarModelMapperPrivate::QBarModelMapperPrivate(QBarModelMapper *q) : + QObject(q), + m_series(0), + m_model(0), + m_first(0), + m_count(-1), + m_orientation(Qt::Vertical), + m_firstBarSetSection(-1), + m_lastBarSetSection(-1), + m_seriesSignalsBlock(false), + m_modelSignalsBlock(false), + q_ptr(q) +{ +} + +void QBarModelMapperPrivate::blockModelSignals(bool block) +{ + m_modelSignalsBlock = block; +} + +void QBarModelMapperPrivate::blockSeriesSignals(bool block) +{ + m_seriesSignalsBlock = block; +} + +QBarSet *QBarModelMapperPrivate::barSet(QModelIndex index) +{ + if (!index.isValid()) + return 0; + + if (m_orientation == Qt::Vertical && index.column() >= m_firstBarSetSection && index.column() <= m_lastBarSetSection) { + if (index.row() >= m_first && (m_count == - 1 || index.row() < m_first + m_count)) { + return m_series->barSets().at(index.column() - m_firstBarSetSection); + } + } else if (m_orientation == Qt::Horizontal && index.row() >= m_firstBarSetSection && index.row() <= m_lastBarSetSection) { + if (index.column() >= m_first && (m_count == - 1 || index.column() < m_first + m_count)) + return m_series->barSets().at(index.row() - m_firstBarSetSection); + } + return 0; // This part of model has not been mapped to any slice +} + +QModelIndex QBarModelMapperPrivate::barModelIndex(int barSection, int posInBar) +{ + if (m_count != -1 && posInBar >= m_count) + return QModelIndex(); // invalid + + if (barSection < m_firstBarSetSection || barSection > m_lastBarSetSection) + return QModelIndex(); // invalid + + if (m_orientation == Qt::Vertical) + return m_model->index(posInBar + m_first, barSection); + else + return m_model->index(barSection, posInBar + m_first); +} + +void QBarModelMapperPrivate::handleSeriesDestroyed() +{ + m_series = 0; +} + +void QBarModelMapperPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight) +{ + Q_UNUSED(topLeft) + Q_UNUSED(bottomRight) + + if (m_model == 0 || m_series == 0) + return; + + if (m_modelSignalsBlock) + return; + + blockSeriesSignals(); + QModelIndex index; + for (int row = topLeft.row(); row <= bottomRight.row(); row++) { + for (int column = topLeft.column(); column <= bottomRight.column(); column++) { + index = topLeft.sibling(row, column); + QBarSet *bar = barSet(index); + if (bar) { + if (m_orientation == Qt::Vertical) + bar->replace(row - m_first, m_model->data(index).toReal()); + else + bar->replace(column - m_first, m_model->data(index).toReal()); + } + } + } + blockSeriesSignals(false); +} + +void QBarModelMapperPrivate::modelHeaderDataUpdated(Qt::Orientation orientation, int first, int last) +{ + if (m_model == 0 || m_series == 0) + return; + + if (m_modelSignalsBlock) + return; + + blockSeriesSignals(); + if (orientation != m_orientation) { + for (int section = first; section <= last; section++) { + if (section >= m_firstBarSetSection && section <= m_lastBarSetSection) { + QBarSet *bar = m_series->barSets().at(section - m_firstBarSetSection); + if (bar) + bar->setLabel(m_model->headerData(section, orientation).toString()); + } + } + } + blockSeriesSignals(false); +} + +void QBarModelMapperPrivate::modelRowsAdded(QModelIndex parent, int start, int end) +{ + Q_UNUSED(parent) + if (m_modelSignalsBlock) + return; + + blockSeriesSignals(); + if (m_orientation == Qt::Vertical) + insertData(start, end); + else if (start <= m_firstBarSetSection || start <= m_lastBarSetSection) // if the changes affect the map - reinitialize + initializeBarFromModel(); + blockSeriesSignals(false); +} + +void QBarModelMapperPrivate::modelRowsRemoved(QModelIndex parent, int start, int end) +{ + Q_UNUSED(parent) + if (m_modelSignalsBlock) + return; + + blockSeriesSignals(); + if (m_orientation == Qt::Vertical) + removeData(start, end); + else if (start <= m_firstBarSetSection || start <= m_lastBarSetSection) // if the changes affect the map - reinitialize + initializeBarFromModel(); + blockSeriesSignals(false); +} + +void QBarModelMapperPrivate::modelColumnsAdded(QModelIndex parent, int start, int end) +{ + Q_UNUSED(parent) + if (m_modelSignalsBlock) + return; + + blockSeriesSignals(); + if (m_orientation == Qt::Horizontal) + insertData(start, end); + else if (start <= m_firstBarSetSection || start <= m_lastBarSetSection) // if the changes affect the map - reinitialize + initializeBarFromModel(); + blockSeriesSignals(false); +} + +void QBarModelMapperPrivate::modelColumnsRemoved(QModelIndex parent, int start, int end) +{ + Q_UNUSED(parent) + if (m_modelSignalsBlock) + return; + + blockSeriesSignals(); + if (m_orientation == Qt::Horizontal) + removeData(start, end); + else if (start <= m_firstBarSetSection || start <= m_lastBarSetSection) // if the changes affect the map - reinitialize + initializeBarFromModel(); + blockSeriesSignals(false); +} + +void QBarModelMapperPrivate::handleModelDestroyed() +{ + m_model = 0; +} + +void QBarModelMapperPrivate::insertData(int start, int end) +{ + Q_UNUSED(end) + Q_UNUSED(start) + Q_UNUSED(end) + // Currently barchart needs to be fully recalculated when change is made. + // Re-initialize + initializeBarFromModel(); +} + +void QBarModelMapperPrivate::removeData(int start, int end) +{ + Q_UNUSED(end) + Q_UNUSED(start) + Q_UNUSED(end) + // Currently barchart needs to be fully recalculated when change is made. + // Re-initialize + initializeBarFromModel(); +} + +void QBarModelMapperPrivate::barSetsAdded(QList<QBarSet *> sets) +{ + if (m_seriesSignalsBlock) + return; + + if (sets.count() == 0) + return; + + int firstIndex = m_series->barSets().indexOf(sets.at(0)); + if (firstIndex == -1) + return; + + int maxCount = 0; + for (int i = 0; i < sets.count(); i++) { + if (sets.at(i)->count() > m_count) + maxCount = sets.at(i)->count(); + } + + if (m_count != -1 && m_count < maxCount) + m_count = maxCount; + + m_lastBarSetSection += sets.count(); + + blockModelSignals(); + int modelCapacity = m_orientation == Qt::Vertical ? m_model->rowCount() - m_first : m_model->columnCount() - m_first; + if (maxCount > modelCapacity) { + if (m_orientation == Qt::Vertical) + m_model->insertRows(m_model->rowCount(), maxCount - modelCapacity); + else + m_model->insertColumns(m_model->columnCount(), maxCount - modelCapacity); + } + + if (m_orientation == Qt::Vertical) + m_model->insertColumns(firstIndex + m_firstBarSetSection, sets.count()); + else + m_model->insertRows(firstIndex + m_firstBarSetSection, sets.count()); + + + for (int i = firstIndex + m_firstBarSetSection; i < firstIndex + m_firstBarSetSection + sets.count(); i++) { + m_model->setHeaderData(i, m_orientation == Qt::Vertical ? Qt::Horizontal : Qt::Vertical, sets.at(i - firstIndex - m_firstBarSetSection)->label()); + for (int j = 0; j < sets.at(i - firstIndex - m_firstBarSetSection)->count(); j++) + m_model->setData(barModelIndex(i, j), sets.at(i - firstIndex - m_firstBarSetSection)->at(j)); + } + blockModelSignals(false); + initializeBarFromModel(); +} + +void QBarModelMapperPrivate::barSetsRemoved(QList<QBarSet *> sets) +{ + if (m_seriesSignalsBlock) + return; + + if (sets.count() == 0) + return; + + int firstIndex = m_barSets.indexOf(sets.at(0)); + if (firstIndex == -1) + return; + + m_lastBarSetSection -= sets.count(); + + for (int i = firstIndex + sets.count() - 1; i >= firstIndex; i--) + m_barSets.removeAt(i); + + blockModelSignals(); + if (m_orientation == Qt::Vertical) + m_model->removeColumns(firstIndex + m_firstBarSetSection, sets.count()); + else + m_model->removeRows(firstIndex + m_firstBarSetSection, sets.count()); + blockModelSignals(false); + initializeBarFromModel(); +} + +void QBarModelMapperPrivate::valuesAdded(int index, int count) +{ + if (m_seriesSignalsBlock) + return; + + if (m_count != -1) + m_count += count; + + int barSetIndex = m_barSets.indexOf(qobject_cast<QBarSet *>(QObject::sender())); + + blockModelSignals(); + if (m_orientation == Qt::Vertical) + m_model->insertRows(index + m_first, count); + else + m_model->insertColumns(index + m_first, count); + + for (int j = index; j < index + count; j++) + m_model->setData(barModelIndex(barSetIndex + m_firstBarSetSection, j), m_barSets.at(barSetIndex)->at(j)); + + blockModelSignals(false); + initializeBarFromModel(); +} + +void QBarModelMapperPrivate::valuesRemoved(int index, int count) +{ + if (m_seriesSignalsBlock) + return; + + if (m_count != -1) + m_count -= count; + + blockModelSignals(); + if (m_orientation == Qt::Vertical) + m_model->removeRows(index + m_first, count); + else + m_model->removeColumns(index + m_first, count); + + blockModelSignals(false); + initializeBarFromModel(); +} + +void QBarModelMapperPrivate::barLabelChanged() +{ + if (m_seriesSignalsBlock) + return; + + int barSetIndex = m_barSets.indexOf(qobject_cast<QBarSet *>(QObject::sender())); + + blockModelSignals(); + m_model->setHeaderData(barSetIndex + m_firstBarSetSection, m_orientation == Qt::Vertical ? Qt::Horizontal : Qt::Vertical, m_barSets.at(barSetIndex)->label()); + blockModelSignals(false); + initializeBarFromModel(); +} + +void QBarModelMapperPrivate::barValueChanged(int index) +{ + if (m_seriesSignalsBlock) + return; + + int barSetIndex = m_barSets.indexOf(qobject_cast<QBarSet *>(QObject::sender())); + + blockModelSignals(); + m_model->setData(barModelIndex(barSetIndex + m_firstBarSetSection, index), m_barSets.at(barSetIndex)->at(index)); + blockModelSignals(false); + initializeBarFromModel(); +} + +void QBarModelMapperPrivate::initializeBarFromModel() +{ + if (m_model == 0 || m_series == 0) + return; + + blockSeriesSignals(); + // clear current content + m_series->clear(); + m_barSets.clear(); + + // create the initial bar sets + for (int i = m_firstBarSetSection; i <= m_lastBarSetSection; i++) { + int posInBar = 0; + QModelIndex barIndex = barModelIndex(i, posInBar); + // check if there is such model index + if (barIndex.isValid()) { + QBarSet *barSet = new QBarSet(m_model->headerData(i, m_orientation == Qt::Vertical ? Qt::Horizontal : Qt::Vertical).toString()); + while (barIndex.isValid()) { + barSet->append(m_model->data(barIndex, Qt::DisplayRole).toDouble()); + posInBar++; + barIndex = barModelIndex(i, posInBar); + } + connect(barSet, SIGNAL(valuesAdded(int,int)), this, SLOT(valuesAdded(int,int))); + connect(barSet, SIGNAL(valuesRemoved(int,int)), this, SLOT(valuesRemoved(int,int))); + connect(barSet, SIGNAL(valueChanged(int)), this, SLOT(barValueChanged(int))); + connect(barSet, SIGNAL(labelChanged()), this, SLOT(barLabelChanged())); + m_series->append(barSet); + m_barSets.append(barSet); + } else { + break; + } + } + blockSeriesSignals(false); +} + +#include "moc_qbarmodelmapper.cpp" +#include "moc_qbarmodelmapper_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/qbarmodelmapper.h b/src/charts/barchart/qbarmodelmapper.h new file mode 100644 index 00000000..a527165a --- /dev/null +++ b/src/charts/barchart/qbarmodelmapper.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QBARMODELMAPPER_H +#define QBARMODELMAPPER_H + +#include <QtCharts/qchartglobal.h> +#include <QObject> + +class QAbstractItemModel; + +QT_CHARTS_BEGIN_NAMESPACE + +class QBarModelMapperPrivate; +class QAbstractBarSeries; + +class QT_CHARTS_EXPORT QBarModelMapper : public QObject +{ + Q_OBJECT + +protected: + explicit QBarModelMapper(QObject *parent = 0); + + QAbstractItemModel *model() const; + void setModel(QAbstractItemModel *model); + + QAbstractBarSeries *series() const; + void setSeries(QAbstractBarSeries *series); + + int first() const; + void setFirst(int first); + + int count() const; + void setCount(int count); + + int firstBarSetSection() const; + void setFirstBarSetSection(int firstBarSetSection); + + int lastBarSetSection() const; + void setLastBarSetSection(int lastBarSetSection); + + Qt::Orientation orientation() const; + void setOrientation(Qt::Orientation orientation); + +protected: + QBarModelMapperPrivate * const d_ptr; + Q_DECLARE_PRIVATE(QBarModelMapper) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QBARMODELMAPPER_H diff --git a/src/charts/barchart/qbarmodelmapper_p.h b/src/charts/barchart/qbarmodelmapper_p.h new file mode 100644 index 00000000..754ebec1 --- /dev/null +++ b/src/charts/barchart/qbarmodelmapper_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QBARMODELMAPPER_P_H +#define QBARMODELMAPPER_P_H + +#include <QObject> +#include "qbarmodelmapper.h" + +class QModelIndex; + +QT_CHARTS_BEGIN_NAMESPACE + +class QBarSet; + +class QBarModelMapperPrivate : public QObject +{ + Q_OBJECT +public: + explicit QBarModelMapperPrivate(QBarModelMapper *q); + +public Q_SLOTS: + // for the model + void modelUpdated(QModelIndex topLeft, QModelIndex bottomRight); + void modelHeaderDataUpdated(Qt::Orientation orientation, int first, int last); + void modelRowsAdded(QModelIndex parent, int start, int end); + void modelRowsRemoved(QModelIndex parent, int start, int end); + void modelColumnsAdded(QModelIndex parent, int start, int end); + void modelColumnsRemoved(QModelIndex parent, int start, int end); + void handleModelDestroyed(); + + // for the series + void barSetsAdded(QList<QBarSet *> sets); + void barSetsRemoved(QList<QBarSet *> sets); + void valuesAdded(int index, int count); + void valuesRemoved(int index, int count); + void barLabelChanged(); + void barValueChanged(int index); + void handleSeriesDestroyed(); + + void initializeBarFromModel(); + +private: + QBarSet *barSet(QModelIndex index); + QModelIndex barModelIndex(int barSection, int posInBar); + void insertData(int start, int end); + void removeData(int start, int end); + void blockModelSignals(bool block = true); + void blockSeriesSignals(bool block = true); + +private: + QAbstractBarSeries *m_series; + QList<QBarSet *> m_barSets; + QAbstractItemModel *m_model; + int m_first; + int m_count; + Qt::Orientation m_orientation; + int m_firstBarSetSection; + int m_lastBarSetSection; + bool m_seriesSignalsBlock; + bool m_modelSignalsBlock; + +private: + QBarModelMapper *q_ptr; + Q_DECLARE_PUBLIC(QBarModelMapper) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QBARMODELMAPPER_P_H diff --git a/src/charts/barchart/qbarset.cpp b/src/charts/barchart/qbarset.cpp new file mode 100644 index 00000000..e378b327 --- /dev/null +++ b/src/charts/barchart/qbarset.cpp @@ -0,0 +1,676 @@ +/**************************************************************************** +** +** 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 "qbarset.h" +#include "qbarset_p.h" +#include "charthelpers_p.h" +#include "qchart_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +/*! + \class QBarSet + \inmodule Qt Charts + \brief Building block for different bar charts. + + QBarSet represents one set of bars. Set of bars contains one data value for each category. + First value of set is assumed to belong to first category, second to second category and so on. + If set has fewer values than there are categories, then the missing values are assumed to be + at the end of set. For missing values in middle of a set, numerical value of zero is used. + + \mainclass + + \sa QAbstractBarSeries, QBarSeries, QStackedBarSeries, QPercentBarSeries +*/ +/*! + \qmltype BarSet + \instantiates QBarSet + \inqmlmodule QtCharts + + \brief Building block for different bar charts. + + BarSet represents one set of bars. Set of bars contains one data value for each category. + First value of set is assumed to belong to first category, second to second category and so on. + If set has fewer values than there are categories, then the missing values are assumed to be + at the end of set. For missing values in middle of a set, numerical value of zero is used. + \sa AbstractBarSeries, BarSeries, StackedBarSeries, PercentBarSeries +*/ + +/*! + \property QBarSet::label + Defines the label of the bar set. +*/ +/*! + \qmlproperty string BarSet::label + Defines the label of the bar set. +*/ + +/*! + \property QBarSet::pen + \brief Defines the pen used by the bar set. +*/ + +/*! + \property QBarSet::brush + \brief Defines the brush used by the bar set. +*/ + +/*! + \qmlproperty QString BarSet::brushFilename + The name of the file used as a brush for the set. +*/ + +/*! + \property QBarSet::labelBrush + \brief Defines the brush used by the bar set's label. +*/ + +/*! + \property QBarSet::labelFont + \brief Defines the font used by the bar set's label. +*/ + +/*! + \qmlproperty Font BarSet::labelFont + Defines the font used by the bar set's label. + + See the Qt documentation for more details of Font. +*/ + +/*! + \property QBarSet::color + The fill (brush) color of the bar set. +*/ +/*! + \qmlproperty color BarSet::color + The fill (brush) color of the bar set. +*/ + +/*! + \property QBarSet::borderColor + The line (pen) color of the bar set. +*/ +/*! + \qmlproperty color BarSet::borderColor + The line (pen) color of the bar set. +*/ + +/*! + \qmlproperty real BarSet::borderWidth + The width of the border line. By default the width is 2.0. +*/ + +/*! + \property QBarSet::labelColor + The text (label) color of the bar set. +*/ +/*! + \qmlproperty color BarSet::labelColor + The text (label) color of the bar set. +*/ + +/*! + \fn void QBarSet::clicked(int index) + + The signal is emitted if the user clicks with a mouse on top of bar set. + Clicked bar inside set is indexed by \a index +*/ + +/*! + \fn void QBarSet::hovered(bool status) + + The signal is emitted if mouse is hovered on top of bar set. + Parameter \a status is true, if mouse entered on top of bar set, false if mouse left from top of bar set. +*/ + +/*! + \fn void QBarSet::hovered(bool status, int index) + + The signal is emitted if mouse is hovered on top of bar set. + Parameter \a status is true, if mouse entered on top of bar set, false if mouse left from top of bar set. + Hovered bar inside the set is indexed by \a index. +*/ + + +/*! + \fn void QBarSet::labelChanged() + This signal is emitted when the label of the bar set has changed. + \sa label +*/ +/*! + \qmlsignal BarSet::onLabelChanged() + This signal is emitted when the label of the bar set has changed. +*/ + +/*! + \fn void QBarSet::penChanged() + This signal is emitted when the pen of the bar set has changed. + \sa pen +*/ + +/*! + \fn void QBarSet::brushChanged() + This signal is emitted when the brush of the bar set has changed. + \sa brush +*/ + +/*! + \fn void QBarSet::labelBrushChanged() + This signal is emitted when the brush of the bar set's label has changed. + \sa labelBrush +*/ + +/*! + \fn void QBarSet::labelFontChanged() + This signal is emitted when the font of the bar set's label has changed. + \sa labelBrush +*/ + +/*! + \fn void QBarSet::colorChanged(QColor) + This signal is emitted when the fill (brush) color of the set has changed to \a color. +*/ +/*! + \qmlsignal BarSet::onColorChanged(color color) + This signal is emitted when the fill (brush) color of the set has changed to \a color. +*/ + +/*! + \fn void QBarSet::borderColorChanged(QColor) + This signal is emitted when the line (pen) color of the set has changed to \a color. +*/ +/*! + \qmlsignal BarSet::onBorderColorChanged(color color) + This signal is emitted when the line (pen) color of the set has changed to \a color. +*/ + +/*! + \fn void QBarSet::labelColorChanged(QColor) + This signal is emitted when the text (label) color of the set has changed to \a color. +*/ +/*! + \qmlsignal BarSet::onLabelColorChanged(color color) + This signal is emitted when the text (label) color of the set has changed to \a color. +*/ + +/*! + \fn void QBarSet::valuesAdded(int index, int count) + This signal is emitted when new values have been added to the set. + Parameter \a index indicates the position of the first inserted value. + Parameter \a count is the number of inserted values. + \sa append(), insert() +*/ +/*! + \qmlsignal BarSet::onValuesAdded(int index, int count) + This signal is emitted when new values have been added to the set. + Parameter \a index indicates the position of the first inserted value. + Parameter \a count is the number of inserted values. +*/ + +/*! + \fn void QBarSet::valuesRemoved(int index, int count) + This signal is emitted values have been removed from the set. + Parameter \a index indicates the position of the first removed value. + Parameter \a count is the number of removed values. + \sa remove() +*/ +/*! + \qmlsignal BarSet::onValuesRemoved(int index, int count) + This signal is emitted values have been removed from the set. + Parameter \a index indicates the position of the first removed value. + Parameter \a count is the number of removed values. +*/ + +/*! + \fn void QBarSet::valueChanged(int index) + This signal is emitted values the value in the set has been modified. + Parameter \a index indicates the position of the modified value. + \sa at() +*/ +/*! + \qmlsignal BarSet::onValueChanged(int index) + This signal is emitted values the value in the set has been modified. + Parameter \a index indicates the position of the modified value. +*/ + +/*! + \qmlproperty int BarSet::count + The count of values on the bar set +*/ + +/*! + \qmlproperty QVariantList BarSet::values + The values of the bar set. You can set either a list of reals or a list of points as values. If you set a list of + reals as values, the values are automatically completed to points by using the index of a value as it's + x-coordinate. For example the following sets have equal values: + \code + myBarSet1.values = [0, 5, 1, 5]; + myBarSet2.values = [Qt.point(0, 0), Qt.point(1, 5), Qt.point(2, 1), Qt.point(3, 5)]; + \endcode +*/ + +/*! + Constructs QBarSet with a label of \a label and with parent of \a parent. +*/ +QBarSet::QBarSet(const QString label, QObject *parent) + : QObject(parent), + d_ptr(new QBarSetPrivate(label, this)) +{ +} + +/*! + Destroys the bar set. +*/ +QBarSet::~QBarSet() +{ + // NOTE: d_ptr destroyed by QObject +} + +/*! + Sets new \a label for set. +*/ +void QBarSet::setLabel(const QString label) +{ + d_ptr->m_label = label; + emit labelChanged(); +} + +/*! + Returns label of the set. +*/ +QString QBarSet::label() const +{ + return d_ptr->m_label; +} + +/*! + Appends new value \a value to the end of set. +*/ +void QBarSet::append(const qreal value) +{ + // Convert to QPointF + int index = d_ptr->m_values.count(); + d_ptr->append(QPointF(d_ptr->m_values.count(), value)); + emit valuesAdded(index, 1); +} + +/*! + Appends a list of reals to set. Works like append with single real value. The \a values in list + are appended to end of bar set. + \sa append() +*/ +void QBarSet::append(const QList<qreal> &values) +{ + int index = d_ptr->m_values.count(); + d_ptr->append(values); + emit valuesAdded(index, values.count()); +} + +/*! + Convenience operator. Same as append, with real \a value. + \sa append() +*/ +QBarSet &QBarSet::operator << (const qreal &value) +{ + append(value); + return *this; +} + +/*! + Inserts new \a value on the \a index position. + The value that is currently at this postion is moved to position index + 1 + \sa remove() +*/ +void QBarSet::insert(const int index, const qreal value) +{ + d_ptr->insert(index, value); + emit valuesAdded(index, 1); +} + +/*! + Removes \a count number of values from the set starting at \a index. + \sa insert() +*/ +void QBarSet::remove(const int index, const int count) +{ + int removedCount = d_ptr->remove(index, count); + if (removedCount > 0) + emit valuesRemoved(index, removedCount); + return; +} + +/*! + Sets a new value \a value to set, indexed by \a index. +*/ +void QBarSet::replace(const int index, const qreal value) +{ + if (index >= 0 && index < d_ptr->m_values.count()) { + d_ptr->replace(index, value); + emit valueChanged(index); + } +} + + +/*! + Returns value of set indexed by \a index. + If the index is out of bounds 0.0 is returned. +*/ +qreal QBarSet::at(const int index) const +{ + if (index < 0 || index >= d_ptr->m_values.count()) + return 0; + return d_ptr->m_values.at(index).y(); +} + +/*! + Returns value of set indexed by \a index. + If the index is out of bounds 0.0 is returned. +*/ +qreal QBarSet::operator [](const int index) const +{ + return at(index); +} + +/*! + Returns count of values in set. +*/ +int QBarSet::count() const +{ + return d_ptr->m_values.count(); +} + +/*! + Returns sum of all values in the bar set. +*/ +qreal QBarSet::sum() const +{ + qreal total(0); + for (int i = 0; i < d_ptr->m_values.count(); i++) + total += d_ptr->m_values.at(i).y(); + return total; +} + +/*! + Sets pen for set. Bars of this set are drawn using \a pen +*/ +void QBarSet::setPen(const QPen &pen) +{ + if (d_ptr->m_pen != pen) { + d_ptr->m_pen = pen; + emit d_ptr->updatedBars(); + emit penChanged(); + } +} + +/*! + Returns pen of the set. +*/ +QPen QBarSet::pen() const +{ + if (d_ptr->m_pen == QChartPrivate::defaultPen()) + return QPen(); + else + return d_ptr->m_pen; +} + +/*! + Sets brush for the set. Bars of this set are drawn using \a brush. +*/ +void QBarSet::setBrush(const QBrush &brush) +{ + if (d_ptr->m_brush != brush) { + d_ptr->m_brush = brush; + emit d_ptr->updatedBars(); + emit brushChanged(); + } +} + +/*! + Returns brush of the set. +*/ +QBrush QBarSet::brush() const +{ + if (d_ptr->m_brush == QChartPrivate::defaultBrush()) + return QBrush(); + else + return d_ptr->m_brush; +} + +/*! + Sets \a brush of the values that are drawn on top of this bar set. +*/ +void QBarSet::setLabelBrush(const QBrush &brush) +{ + if (d_ptr->m_labelBrush != brush) { + d_ptr->m_labelBrush = brush; + emit d_ptr->updatedBars(); + emit labelBrushChanged(); + } +} + +/*! + Returns brush of the values that are drawn on top of this bar set. +*/ +QBrush QBarSet::labelBrush() const +{ + if (d_ptr->m_labelBrush == QChartPrivate::defaultBrush()) + return QBrush(); + else + return d_ptr->m_labelBrush; +} + +/*! + Sets the \a font for values that are drawn on top of this bar set. +*/ +void QBarSet::setLabelFont(const QFont &font) +{ + if (d_ptr->m_labelFont != font) { + d_ptr->m_labelFont = font; + emit d_ptr->updatedBars(); + emit labelFontChanged(); + } + +} + +/*! + Returns the pen for values that are drawn on top of this bar set. +*/ +QFont QBarSet::labelFont() const +{ + return d_ptr->m_labelFont; +} + +/*! + Returns the color of the brush of bar set. +*/ +QColor QBarSet::color() +{ + return brush().color(); +} + +/*! + Sets the \a color of brush for this bar set. +*/ +void QBarSet::setColor(QColor color) +{ + QBrush b = brush(); + if ((b.color() != color) || (b.style() == Qt::NoBrush)) { + b.setColor(color); + if (b.style() == Qt::NoBrush) { + // Set tyle to Qt::SolidPattern. (Default is Qt::NoBrush) + // This prevents theme to override color defined in QML side: + // BarSet { label: "Bob"; color:"red"; values: [1,2,3] } + // The color must be obeyed, since user wanted it. + b.setStyle(Qt::SolidPattern); + } + setBrush(b); + emit colorChanged(color); + } +} + +/*! + Returns the color of pen of this bar set. +*/ +QColor QBarSet::borderColor() +{ + return pen().color(); +} + +/*! + Sets the color of pen for this bar set. +*/ +void QBarSet::setBorderColor(QColor color) +{ + QPen p = pen(); + if (p.color() != color) { + p.setColor(color); + setPen(p); + emit borderColorChanged(color); + } +} + +/*! + Returns the color of labels of this bar set. +*/ +QColor QBarSet::labelColor() +{ + return labelBrush().color(); +} + +/*! + Sets the color of labels for this bar set. +*/ +void QBarSet::setLabelColor(QColor color) +{ + QBrush b = labelBrush(); + if (b == QBrush()) + b.setStyle(Qt::SolidPattern); + + if (b.color() != color) { + b.setColor(color); + setLabelBrush(b); + emit labelColorChanged(color); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QBarSetPrivate::QBarSetPrivate(const QString label, QBarSet *parent) : QObject(parent), + q_ptr(parent), + m_label(label), + m_pen(QChartPrivate::defaultPen()), + m_brush(QChartPrivate::defaultBrush()), + m_labelBrush(QChartPrivate::defaultBrush()) +{ +} + +QBarSetPrivate::~QBarSetPrivate() +{ +} + +void QBarSetPrivate::append(QPointF value) +{ + if (isValidValue(value)) { + m_values.append(value); + emit restructuredBars(); + } +} + +void QBarSetPrivate::append(QList<QPointF> values) +{ + for (int i = 0; i < values.count(); i++) { + if (isValidValue(values.at(i))) + m_values.append(values.at(i)); + } + emit restructuredBars(); +} + +void QBarSetPrivate::append(QList<qreal> values) +{ + int index = m_values.count(); + for (int i = 0; i < values.count(); i++) { + if (isValidValue(values.at(i))) { + m_values.append(QPointF(index, values.at(i))); + index++; + } + } + emit restructuredBars(); +} + +void QBarSetPrivate::insert(const int index, const qreal value) +{ + m_values.insert(index, QPointF(index, value)); + emit restructuredBars(); +} + +void QBarSetPrivate::insert(const int index, const QPointF value) +{ + m_values.insert(index, value); + emit restructuredBars(); +} + +int QBarSetPrivate::remove(const int index, const int count) +{ + int removeCount = count; + + if ((index < 0) || (m_values.count() == 0)) + return 0; // Invalid index or not values in list, remove nothing. + else if ((index + count) > m_values.count()) + removeCount = m_values.count() - index; // Trying to remove more items than list has. Limit amount to be removed. + + int c = 0; + while (c < removeCount) { + m_values.removeAt(index); + c++; + } + emit restructuredBars(); + return removeCount; +} + +void QBarSetPrivate::replace(const int index, const qreal value) +{ + m_values.replace(index, QPointF(index, value)); + emit updatedLayout(); +} + +void QBarSetPrivate::replace(const int index, const QPointF value) +{ + m_values.replace(index, value); + emit updatedLayout(); +} + +qreal QBarSetPrivate::pos(const int index) +{ + if (index < 0 || index >= m_values.count()) + return 0; + return m_values.at(index).x(); +} + +qreal QBarSetPrivate::value(const int index) +{ + if (index < 0 || index >= m_values.count()) + return 0; + return m_values.at(index).y(); +} + +#include "moc_qbarset.cpp" +#include "moc_qbarset_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/qbarset.h b/src/charts/barchart/qbarset.h new file mode 100644 index 00000000..7d96dec4 --- /dev/null +++ b/src/charts/barchart/qbarset.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QBARSET_H +#define QBARSET_H + +#include <QtCharts/qchartglobal.h> +#include <QPen> +#include <QBrush> +#include <QFont> + +QT_CHARTS_BEGIN_NAMESPACE +class QBarSetPrivate; + +class QT_CHARTS_EXPORT QBarSet : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged) + Q_PROPERTY(QPen pen READ pen WRITE setPen NOTIFY penChanged) + Q_PROPERTY(QBrush brush READ brush WRITE setBrush NOTIFY brushChanged) + Q_PROPERTY(QBrush labelBrush READ labelBrush WRITE setLabelBrush NOTIFY labelBrushChanged) + Q_PROPERTY(QFont labelFont READ labelFont WRITE setLabelFont NOTIFY labelFontChanged) + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor NOTIFY borderColorChanged) + Q_PROPERTY(QColor labelColor READ labelColor WRITE setLabelColor NOTIFY labelColorChanged) + +public: + explicit QBarSet(const QString label, QObject *parent = 0); + virtual ~QBarSet(); + + void setLabel(const QString label); + QString label() const; + + void append(const qreal value); + void append(const QList<qreal> &values); + + QBarSet &operator << (const qreal &value); + + void insert(const int index, const qreal value); + void remove(const int index, const int count = 1); + void replace(const int index, const qreal value); + qreal at(const int index) const; + qreal operator [](const int index) const; + int count() const; + qreal sum() const; + + void setPen(const QPen &pen); + QPen pen() const; + + void setBrush(const QBrush &brush); + QBrush brush() const; + + void setLabelBrush(const QBrush &brush); + QBrush labelBrush() const; + + void setLabelFont(const QFont &font); + QFont labelFont() const; + + QColor color(); + void setColor(QColor color); + + QColor borderColor(); + void setBorderColor(QColor color); + + QColor labelColor(); + void setLabelColor(QColor color); + +Q_SIGNALS: + void clicked(int index); + void hovered(bool status); + void hovered(bool status, int index); + void penChanged(); + void brushChanged(); + void labelChanged(); + void labelBrushChanged(); + void labelFontChanged(); + void colorChanged(QColor color); + void borderColorChanged(QColor color); + void labelColorChanged(QColor color); + + void valuesAdded(int index, int count); + void valuesRemoved(int index, int count); + void valueChanged(int index); + +private: + QScopedPointer<QBarSetPrivate> d_ptr; + Q_DISABLE_COPY(QBarSet) + friend class QAbstractBarSeries; + friend class BarLegendMarker; + friend class AbstractBarChartItem; + friend class QAbstractBarSeriesPrivate; + friend class StackedBarChartItem; + friend class PercentBarChartItem; + friend class BarChartItem; + friend class HorizontalBarChartItem; + friend class HorizontalStackedBarChartItem; + friend class HorizontalPercentBarChartItem; + friend class BoxPlotChartItem; +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QBARSET_H diff --git a/src/charts/barchart/qbarset_p.h b/src/charts/barchart/qbarset_p.h new file mode 100644 index 00000000..d0b03efa --- /dev/null +++ b/src/charts/barchart/qbarset_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QBARSET_P_H +#define QBARSET_P_H + +#include <qbarset.h> +#include <QMap> +#include <QPen> +#include <QBrush> +#include <QFont> + +QT_CHARTS_BEGIN_NAMESPACE + +class QBarSetPrivate : public QObject +{ + Q_OBJECT + +public: + QBarSetPrivate(const QString label, QBarSet *parent); + ~QBarSetPrivate(); + + void append(QPointF value); + void append(QList<QPointF> values); + void append(QList<qreal> values); + + void insert(const int index, const qreal value); + void insert(const int index, const QPointF value); + int remove(const int index, const int count); + + void replace(const int index, const qreal value); + void replace(const int index, const QPointF value); + + qreal pos(const int index); + qreal value(const int index); + +Q_SIGNALS: + void restructuredBars(); + void updatedBars(); + void updatedLayout(); + +public: + QBarSet * const q_ptr; + QString m_label; + QList<QPointF> m_values; + QPen m_pen; + QBrush m_brush; + QBrush m_labelBrush; + QFont m_labelFont; + + friend class QBarSet; +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QBARSETPRIVATE_P_H diff --git a/src/charts/barchart/qhbarmodelmapper.cpp b/src/charts/barchart/qhbarmodelmapper.cpp new file mode 100644 index 00000000..0312df40 --- /dev/null +++ b/src/charts/barchart/qhbarmodelmapper.cpp @@ -0,0 +1,258 @@ +/**************************************************************************** +** +** 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 "qhbarmodelmapper.h" + +QT_CHARTS_BEGIN_NAMESPACE + +/*! + \class QHBarModelMapper + \inmodule Qt Charts + \brief Horizontal model mapper for bar series. + \mainclass + + Model mappers allow you to use QAbstractItemModel derived models as a data source for a chart series. + Horizontal model mapper is used to create a connection between QAbstractBarSeries and QAbstractItemModel derived model object. + Model mapper maintains equal size of all the BarSets. + Adding/removing value from the BarSet causes the the same change in the rest of the BarSets added to the same series. + \note Used model has to support adding/removing rows/columns and modifying the data of the cells. +*/ +/*! + \qmltype HBarModelMapper + \instantiates QHBarModelMapper + \inqmlmodule QtCharts + + \brief Horizontal model mapper for bar series. + + HBarModelMapper allows you to use your own QAbstractItemModel derived model with data in rows as + a data source for any bar series. It is possible to use both QAbstractItemModel and bar series + data API to manipulate data. HBarModelMapper keeps the series and the model in sync. + + The following QML example would create a bar series with three bar sets (assuming the model has + at least four rows). Each bar set would contain data starting from column 1. The name of a set + would be defined by the vertical header (of the row). + \code + BarSeries { + HBarModelMapper { + model: myCustomModel // QAbstractItemModel derived implementation + firstBarSetRow: 1 + lastBarSetRow: 3 + firstColumn: 1 + } + } + \endcode +*/ + +/*! + \property QHBarModelMapper::series + \brief Defines the QPieSeries object that is used by the mapper. + + All the data in the series is discarded when it is set to the mapper. + When new series is specified the old series is disconnected (it preserves its data) +*/ +/*! + \qmlproperty AbstractBarSeries HBarModelMapper::series + Defines the AbstractBarSeries based object that is used by the mapper. All the data in the series is discarded when it is + set to the mapper. When new series is specified the old series is disconnected (it preserves its data). +*/ + +/*! + \property QHBarModelMapper::model + \brief Defines the model that is used by the mapper. +*/ +/*! + \qmlproperty SomeModel HBarModelMapper::model + The QAbstractItemModel based model that is used by the mapper. You need to implement the model + and expose it to QML. Note: the model has to support adding/removing rows/columns and modifying + the data of the cells. +*/ + +/*! + \property QHBarModelMapper::firstBarSetRow + \brief Defines which column of the model is used as the data source for the first bar set. + + Default value is: -1 (invalid mapping) +*/ +/*! + \qmlproperty int HBarModelMapper::firstBarSetRow + Defines which column of the model is used as the data source for the first bar set. The default value is -1 + (invalid mapping). +*/ + +/*! + \property QHBarModelMapper::lastBarSetRow + \brief Defines which column of the model is used as the data source for the last bar set. + + Default value is: -1 (invalid mapping) +*/ +/*! + \qmlproperty int HBarModelMapper::lastBarSetRow + Defines which column of the model is used as the data source for the last bar set. The default value is -1 + (invalid mapping). +*/ + +/*! + \property QHBarModelMapper::firstColumn + \brief Defines which column of the model contains the first values of the QBarSets in the series. + + Minimal and default value is: 0 +*/ +/*! + \qmlproperty int HBarModelMapper::firstColumn + Defines which column of the model contains the first values of the QBarSets in the series. + The default value is 0. +*/ + +/*! + \property QHBarModelMapper::columnCount + \brief Defines the number of columns of the model that are mapped as the data for QAbstractBarSeries. + + Minimal and default value is: -1 (count limited by the number of columns in the model) +*/ +/*! + \qmlproperty int HBarModelMapper::columnCount + Defines the number of columns of the model that are mapped as the data for QAbstractBarSeries. The default value is + -1 (count limited by the number of columns in the model) +*/ + +/*! + \fn void QHBarModelMapper::seriesReplaced() + + Emitted when the series to which mapper is connected to has changed. +*/ + +/*! + \fn void QHBarModelMapper::modelReplaced() + + Emitted when the model to which mapper is connected to has changed. +*/ + +/*! + \fn void QHBarModelMapper::firstBarSetRowChanged() + + Emitted when the firstBarSetRow has changed. +*/ + +/*! + \fn void QHBarModelMapper::lastBarSetRowChanged() + + Emitted when the lastBarSetRow has changed. +*/ + +/*! + \fn void QHBarModelMapper::firstColumnChanged() + Emitted when the firstColumn has changed. +*/ + +/*! + \fn void QHBarModelMapper::columnCountChanged() + Emitted when the columnCount has changed. +*/ + +/*! + Constructs a mapper object which is a child of \a parent. +*/ +QHBarModelMapper::QHBarModelMapper(QObject *parent) : + QBarModelMapper(parent) +{ + QBarModelMapper::setOrientation(Qt::Horizontal); +} + +QAbstractItemModel *QHBarModelMapper::model() const +{ + return QBarModelMapper::model(); +} + +void QHBarModelMapper::setModel(QAbstractItemModel *model) +{ + if (model != QBarModelMapper::model()) { + QBarModelMapper::setModel(model); + emit modelReplaced(); + } +} + +QAbstractBarSeries *QHBarModelMapper::series() const +{ + return QBarModelMapper::series(); +} + +void QHBarModelMapper::setSeries(QAbstractBarSeries *series) +{ + if (series != QBarModelMapper::series()) { + QBarModelMapper::setSeries(series); + emit seriesReplaced(); + } +} + +int QHBarModelMapper::firstBarSetRow() const +{ + return QBarModelMapper::firstBarSetSection(); +} + +void QHBarModelMapper::setFirstBarSetRow(int firstBarSetRow) +{ + if (firstBarSetRow != firstBarSetSection()) { + QBarModelMapper::setFirstBarSetSection(firstBarSetRow); + emit firstBarSetRowChanged(); + } +} + +int QHBarModelMapper::lastBarSetRow() const +{ + return QBarModelMapper::lastBarSetSection(); +} + +void QHBarModelMapper::setLastBarSetRow(int lastBarSetRow) +{ + if (lastBarSetRow != lastBarSetSection()) { + QBarModelMapper::setLastBarSetSection(lastBarSetRow); + emit lastBarSetRowChanged(); + } +} + +int QHBarModelMapper::firstColumn() const +{ + return QBarModelMapper::first(); +} + +void QHBarModelMapper::setFirstColumn(int firstColumn) +{ + if (firstColumn != first()) { + QBarModelMapper::setFirst(firstColumn); + emit firstColumnChanged(); + } +} + +int QHBarModelMapper::columnCount() const +{ + return QBarModelMapper::count(); +} + +void QHBarModelMapper::setColumnCount(int columnCount) +{ + if (columnCount != count()) { + QBarModelMapper::setCount(columnCount); + emit columnCountChanged(); + } +} + +#include "moc_qhbarmodelmapper.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/qhbarmodelmapper.h b/src/charts/barchart/qhbarmodelmapper.h new file mode 100644 index 00000000..ee281aef --- /dev/null +++ b/src/charts/barchart/qhbarmodelmapper.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QHBARMODELMAPPER_H +#define QHBARMODELMAPPER_H + +#include <QtCharts/QBarModelMapper> + +QT_CHARTS_BEGIN_NAMESPACE +/* Comment line for syncqt to generate the fwd-include correctly, due to QTBUG-22432 */ +class QT_CHARTS_EXPORT QHBarModelMapper : public QBarModelMapper +{ + Q_OBJECT + Q_PROPERTY(QAbstractBarSeries *series READ series WRITE setSeries NOTIFY seriesReplaced) + Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelReplaced) + Q_PROPERTY(int firstBarSetRow READ firstBarSetRow WRITE setFirstBarSetRow NOTIFY firstBarSetRowChanged) + Q_PROPERTY(int lastBarSetRow READ lastBarSetRow WRITE setLastBarSetRow NOTIFY lastBarSetRowChanged) + Q_PROPERTY(int firstColumn READ firstColumn WRITE setFirstColumn NOTIFY firstColumnChanged) + Q_PROPERTY(int columnCount READ columnCount WRITE setColumnCount NOTIFY columnCountChanged) + +public: + explicit QHBarModelMapper(QObject *parent = 0); + + QAbstractItemModel *model() const; + void setModel(QAbstractItemModel *model); + + QAbstractBarSeries *series() const; + void setSeries(QAbstractBarSeries *series); + + int firstBarSetRow() const; + void setFirstBarSetRow(int firstBarSetRow); + + int lastBarSetRow() const; + void setLastBarSetRow(int lastBarSetRow); + + int firstColumn() const; + void setFirstColumn(int firstColumn); + + int columnCount() const; + void setColumnCount(int columnCount); + +Q_SIGNALS: + void seriesReplaced(); + void modelReplaced(); + void firstBarSetRowChanged(); + void lastBarSetRowChanged(); + void firstColumnChanged(); + void columnCountChanged(); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QHBARMODELMAPPER_H diff --git a/src/charts/barchart/qvbarmodelmapper.cpp b/src/charts/barchart/qvbarmodelmapper.cpp new file mode 100644 index 00000000..a239e696 --- /dev/null +++ b/src/charts/barchart/qvbarmodelmapper.cpp @@ -0,0 +1,258 @@ +/**************************************************************************** +** +** 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 "qvbarmodelmapper.h" + +QT_CHARTS_BEGIN_NAMESPACE + +/*! + \class QVBarModelMapper + \inmodule Qt Charts + \brief Vertical model mapper for bar series. + \mainclass + + Model mappers allow you to use QAbstractItemModel derived models as a data source for a chart series. + Vertical model mapper is used to create a connection between QAbstractBarSeries and QAbstractItemModel derived model object. + Model mapper maintains equal size of all the BarSets. + Adding/removing value from the BarSet causes the the same change in the rest of the BarSets added to the same series. + \note Used model has to support adding/removing rows/columns and modifying the data of the cells. +*/ +/*! + \qmltype VBarModelMapper + \instantiates QVBarModelMapper + \inqmlmodule QtCharts + + \inherits BarModelMapper + + \brief Vertical model mapper for bar series. + + VBarModelMapper allows you to use your own QAbstractItemModel derived model with data in columns + as a data source for any bar series. It is possible to use both QAbstractItemModel and bar + series data API to manipulate data. VBarModelMapper keeps the series and the model in sync. + + The following QML example would create a bar series with three bar sets (assuming the model has + at least four columns). Each bar set would contain data starting from row 1. The name of a set + would be defined by the horizontal header (of the column). + \code + BarSeries { + VBarModelMapper { + model: myCustomModel // QAbstractItemModel derived implementation + firstBarSetColumn: 1 + lastBarSetColumn: 3 + firstRow: 1 + } + } + \endcode +*/ + +/*! + \property QVBarModelMapper::series + \brief Defines the QBarSeries object that is used by the mapper. + + All the data in the series is discarded when it is set to the mapper. + When new series is specified the old series is disconnected (it preserves its data) +*/ +/*! + \qmlproperty AbstractBarSeries VBarModelMapper::series + Defines the AbstractBarSeries based object that is used by the mapper. All the data in the series is discarded when it is + set to the mapper. When new series is specified the old series is disconnected (it preserves its data). +*/ + +/*! + \property QVBarModelMapper::model + \brief Defines the model that is used by the mapper. +*/ +/*! + \qmlproperty SomeModel VBarModelMapper::model + The QAbstractItemModel based model that is used by the mapper. You need to implement the model + and expose it to QML. Note: the model has to support adding/removing rows/columns and modifying + the data of the cells. +*/ + +/*! + \property QVBarModelMapper::firstBarSetColumn + \brief Defines which column of the model is used as the data source for the first bar set. + + Default value is: -1 (invalid mapping) +*/ +/*! + \qmlproperty int VBarModelMapper::firstBarSetColumn + Defines which column of the model is used as the data source for the first bar set. Default value + is: -1 (invalid mapping). +*/ + +/*! + \property QVBarModelMapper::lastBarSetColumn + \brief Defines which column of the model is used as the data source for the last bar set. + + Default value is: -1 (invalid mapping) +*/ +/*! + \qmlproperty int VBarModelMapper::lastBarSetColumn + Defines which column of the model is used as the data source for the last bar set. Default + value is: -1 (invalid mapping). +*/ + +/*! + \property QVBarModelMapper::firstRow + \brief Defines which row of the model contains the first values of the QBarSets in the series. + + Minimal and default value is: 0 +*/ +/*! + \qmlproperty int VBarModelMapper::firstRow + Defines which row of the model contains the first values of the QBarSets in the series. + The default value is 0. +*/ + +/*! + \property QVBarModelMapper::rowCount + \brief Defines the number of rows of the model that are mapped as the data for QAbstractBarSeries. + + Minimal and default value is: -1 (count limited by the number of rows in the model) +*/ +/*! + \qmlproperty int VBarModelMapper::rowCount + Defines the number of rows of the model that are mapped as the data for QAbstractBarSeries. The default value is + -1 (count limited by the number of rows in the model) +*/ + +/*! + \fn void QVBarModelMapper::seriesReplaced() + + Emitted when the series to which mapper is connected to has changed. +*/ + +/*! + \fn void QVBarModelMapper::modelReplaced() + + Emitted when the model to which mapper is connected to has changed. +*/ + +/*! + \fn void QVBarModelMapper::firstBarSetColumnChanged() + Emitted when the firstBarSetColumn has changed. +*/ + +/*! + \fn void QVBarModelMapper::lastBarSetColumnChanged() + Emitted when the lastBarSetColumn has changed. +*/ + +/*! + \fn void QVBarModelMapper::firstRowChanged() + Emitted when the firstRow has changed. +*/ + +/*! + \fn void QVBarModelMapper::rowCountChanged() + Emitted when the rowCount has changed. +*/ + +/*! + Constructs a mapper object which is a child of \a parent. +*/ +QVBarModelMapper::QVBarModelMapper(QObject *parent) : + QBarModelMapper(parent) +{ + QBarModelMapper::setOrientation(Qt::Vertical); +} + +QAbstractItemModel *QVBarModelMapper::model() const +{ + return QBarModelMapper::model(); +} + +void QVBarModelMapper::setModel(QAbstractItemModel *model) +{ + if (model != QBarModelMapper::model()) { + QBarModelMapper::setModel(model); + emit modelReplaced(); + } +} + +QAbstractBarSeries *QVBarModelMapper::series() const +{ + return QBarModelMapper::series(); +} + +void QVBarModelMapper::setSeries(QAbstractBarSeries *series) +{ + if (series != QBarModelMapper::series()) { + QBarModelMapper::setSeries(series); + emit seriesReplaced(); + } +} + +int QVBarModelMapper::firstBarSetColumn() const +{ + return QBarModelMapper::firstBarSetSection(); +} + +void QVBarModelMapper::setFirstBarSetColumn(int firstBarSetColumn) +{ + if (firstBarSetColumn != firstBarSetSection()) { + QBarModelMapper::setFirstBarSetSection(firstBarSetColumn); + emit firstBarSetColumnChanged(); + } +} + +int QVBarModelMapper::lastBarSetColumn() const +{ + return QBarModelMapper::lastBarSetSection(); +} + +void QVBarModelMapper::setLastBarSetColumn(int lastBarSetColumn) +{ + if (lastBarSetColumn != lastBarSetSection()) { + QBarModelMapper::setLastBarSetSection(lastBarSetColumn); + emit lastBarSetColumnChanged(); + } +} + +int QVBarModelMapper::firstRow() const +{ + return QBarModelMapper::first(); +} + +void QVBarModelMapper::setFirstRow(int firstRow) +{ + if (firstRow != first()) { + QBarModelMapper::setFirst(firstRow); + emit firstRowChanged(); + } +} + +int QVBarModelMapper::rowCount() const +{ + return QBarModelMapper::count(); +} + +void QVBarModelMapper::setRowCount(int rowCount) +{ + if (rowCount != count()) { + QBarModelMapper::setCount(rowCount); + emit rowCountChanged(); + } +} + +#include "moc_qvbarmodelmapper.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/qvbarmodelmapper.h b/src/charts/barchart/qvbarmodelmapper.h new file mode 100644 index 00000000..5f16ac72 --- /dev/null +++ b/src/charts/barchart/qvbarmodelmapper.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QVBARMODELMAPPER_H +#define QVBARMODELMAPPER_H + +#include <QtCharts/QBarModelMapper> + +QT_CHARTS_BEGIN_NAMESPACE +/* Comment line for syncqt to generate the fwd-include correctly, due to QTBUG-22432 */ +class QT_CHARTS_EXPORT QVBarModelMapper : public QBarModelMapper +{ + Q_OBJECT + Q_PROPERTY(QAbstractBarSeries *series READ series WRITE setSeries NOTIFY seriesReplaced) + Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelReplaced) + Q_PROPERTY(int firstBarSetColumn READ firstBarSetColumn WRITE setFirstBarSetColumn NOTIFY firstBarSetColumnChanged) + Q_PROPERTY(int lastBarSetColumn READ lastBarSetColumn WRITE setLastBarSetColumn NOTIFY lastBarSetColumnChanged) + Q_PROPERTY(int firstRow READ firstRow WRITE setFirstRow NOTIFY firstRowChanged) + Q_PROPERTY(int rowCount READ rowCount WRITE setRowCount NOTIFY rowCountChanged) + +public: + explicit QVBarModelMapper(QObject *parent = 0); + + QAbstractItemModel *model() const; + void setModel(QAbstractItemModel *model); + + QAbstractBarSeries *series() const; + void setSeries(QAbstractBarSeries *series); + + int firstBarSetColumn() const; + void setFirstBarSetColumn(int firstBarSetColumn); + + int lastBarSetColumn() const; + void setLastBarSetColumn(int lastBarSetColumn); + + int firstRow() const; + void setFirstRow(int firstRow); + + int rowCount() const; + void setRowCount(int rowCount); + +Q_SIGNALS: + void seriesReplaced(); + void modelReplaced(); + void firstBarSetColumnChanged(); + void lastBarSetColumnChanged(); + void firstRowChanged(); + void rowCountChanged(); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QVBARMODELMAPPER_H diff --git a/src/charts/barchart/vertical/bar/barchartitem.cpp b/src/charts/barchart/vertical/bar/barchartitem.cpp new file mode 100644 index 00000000..86b63045 --- /dev/null +++ b/src/charts/barchart/vertical/bar/barchartitem.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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 "barchartitem_p.h" +#include "bar_p.h" +#include "qabstractbarseries_p.h" +#include "qbarset.h" +#include "qbarset_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +BarChartItem::BarChartItem(QAbstractBarSeries *series, QGraphicsItem* item) : + AbstractBarChartItem(series, item) +{ + connect(series, SIGNAL(labelsPositionChanged(QAbstractBarSeries::LabelsPosition)), + this, SLOT(handleLabelsPositionChanged())); + connect(series, SIGNAL(labelsFormatChanged(QString)), this, SLOT(positionLabels())); +} + +void BarChartItem::initializeLayout() +{ + qreal categoryCount = m_series->d_func()->categoryCount(); + qreal setCount = m_series->count(); + qreal barWidth = m_series->d_func()->barWidth(); + + m_layout.clear(); + for(int category = 0; category < categoryCount; category++) { + for (int set = 0; set < setCount; set++) { + QRectF rect; + QPointF topLeft; + QPointF bottomRight; + + if (domain()->type() == AbstractDomain::XLogYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) { + topLeft = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2 + set/setCount * barWidth, domain()->minY()), m_validData); + bottomRight = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2 + (set + 1)/setCount * barWidth, domain()->minY()), m_validData); + } else { + topLeft = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2 + set/setCount * barWidth, 0), m_validData); + bottomRight = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2 + (set + 1)/setCount * barWidth, 0), m_validData); + } + + if (!m_validData) + return; + rect.setTopLeft(topLeft); + rect.setBottomRight(bottomRight); + m_layout.append(rect.normalized()); + } + } +} + +QVector<QRectF> BarChartItem::calculateLayout() +{ + QVector<QRectF> layout; + + // Use temporary qreals for accuracy + qreal categoryCount = m_series->d_func()->categoryCount(); + qreal setCount = m_series->count(); + qreal barWidth = m_series->d_func()->barWidth(); + + for(int category = 0; category < categoryCount; category++) { + for (int set = 0; set < setCount; set++) { + qreal value = m_series->barSets().at(set)->at(category); + QRectF rect; + QPointF topLeft = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2 + (set)/(setCount) * barWidth, value), m_validData); + QPointF bottomRight; + if (domain()->type() == AbstractDomain::XLogYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) + bottomRight = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2 + (set + 1)/(setCount) * barWidth, domain()->minY()), m_validData); + else + bottomRight = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2 + (set + 1)/(setCount) * barWidth, 0), m_validData); + + rect.setTopLeft(topLeft); + rect.setBottomRight(bottomRight); + layout.append(rect.normalized()); + } + } + + return layout; +} + +void BarChartItem::handleLabelsPositionChanged() +{ + positionLabels(); +} + +void BarChartItem::positionLabels() +{ + for (int i = 0; i < m_layout.count(); i++) { + QGraphicsTextItem *label = m_labels.at(i); + qreal xPos = m_layout.at(i).center().x() - label->boundingRect().center().x(); + qreal yPos = 0; + + int offset = m_bars.at(i)->pen().width() / 2 + 2; + if (m_series->labelsPosition() == QAbstractBarSeries::LabelsCenter) + yPos = m_layout.at(i).center().y() - label->boundingRect().center().y(); + else if (m_series->labelsPosition() == QAbstractBarSeries::LabelsInsideEnd) + yPos = m_layout.at(i).top() - offset; + else if (m_series->labelsPosition() == QAbstractBarSeries::LabelsInsideBase) + yPos = m_layout.at(i).bottom() - label->boundingRect().height() + offset; + else if (m_series->labelsPosition() == QAbstractBarSeries::LabelsOutsideEnd) + yPos = m_layout.at(i).top() - label->boundingRect().height() + offset; + + label->setPos(xPos, yPos); + label->setZValue(zValue() + 1); + } +} + +#include "moc_barchartitem_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/vertical/bar/barchartitem_p.h b/src/charts/barchart/vertical/bar/barchartitem_p.h new file mode 100644 index 00000000..09df0dbf --- /dev/null +++ b/src/charts/barchart/vertical/bar/barchartitem_p.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + + +#ifndef BARCHARTITEM_H +#define BARCHARTITEM_H + +#include "abstractbarchartitem_p.h" +#include <qstackedbarseries.h> +#include <QGraphicsItem> + +QT_CHARTS_BEGIN_NAMESPACE + +class BarChartItem : public AbstractBarChartItem +{ + Q_OBJECT +public: + BarChartItem(QAbstractBarSeries *series, QGraphicsItem* item = 0); + +private slots: + void handleLabelsPositionChanged(); + void positionLabels(); + +private: + virtual QVector<QRectF> calculateLayout(); + void initializeLayout(); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // BARCHARTITEM_H diff --git a/src/charts/barchart/vertical/bar/qbarseries.cpp b/src/charts/barchart/vertical/bar/qbarseries.cpp new file mode 100644 index 00000000..3ab2a1ee --- /dev/null +++ b/src/charts/barchart/vertical/bar/qbarseries.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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 "qbarseries.h" +#include "qbarseries_p.h" +#include "barchartitem_p.h" +#include "chartdataset_p.h" +#include "charttheme_p.h" +#include "qvalueaxis.h" +#include "qbarcategoryaxis.h" + +QT_CHARTS_BEGIN_NAMESPACE + +/*! + \class QBarSeries + \inmodule Qt Charts + \brief Series for creating bar chart. + \mainclass + + QBarSeries represents a series of data shown as bars. The purpose of this class is to draw bars + as groups, where bars in same category are grouped next to each other. QBarSeries groups the data + from sets to categories, which are defined by a QStringList. + + See the \l {BarChart Example} {bar chart example} to learn how to create a grouped bar chart. + \image examples_barchart.png + + \sa QBarSet, QPercentBarSeries, QAbstractBarSeries, QStackedBarSeries +*/ +/*! + \qmltype BarSeries + \instantiates QBarSeries + \inqmlmodule QtCharts + + \inherits AbstractBarSeries + + \brief Series for creating bar chart. + + The following QML shows how to create a simple grouped bar chart: + \snippet qmlchart/qml/qmlchart/View6.qml 1 + \beginfloatleft + \image examples_qmlchart6.png + \endfloat + \clearfloat +*/ + +/*! + Constructs empty QBarSeries. + QBarSeries is QObject which is a child of a \a parent. +*/ +QBarSeries::QBarSeries(QObject *parent) + : QAbstractBarSeries(*new QBarSeriesPrivate(this), parent) +{ + +} + +/*! + Returns QAbstractSeries::SeriesTypeBar. +*/ +QAbstractSeries::SeriesType QBarSeries::type() const +{ + return QAbstractSeries::SeriesTypeBar; +} + +/*! + Destructor. Removes series from chart. +*/ +QBarSeries::~QBarSeries() +{ + Q_D(QBarSeries); + if (d->m_chart) + d->m_chart->removeSeries(this); +} +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QBarSeriesPrivate::QBarSeriesPrivate(QBarSeries *q) : QAbstractBarSeriesPrivate(q) +{ + +} + +void QBarSeriesPrivate::initializeDomain() +{ + qreal minX(domain()->minX()); + qreal minY(domain()->minY()); + qreal maxX(domain()->maxX()); + qreal maxY(domain()->maxY()); + + qreal x = categoryCount(); + minX = qMin(minX, - (qreal)0.5); + minY = qMin(minY, min()); + maxX = qMax(maxX, x - (qreal)0.5); + maxY = qMax(maxY, max()); + + domain()->setRange(minX, maxX, minY, maxY); +} + + +void QBarSeriesPrivate::initializeGraphics(QGraphicsItem* parent) +{ + Q_Q(QBarSeries); + BarChartItem *bar = new BarChartItem(q,parent); + m_item.reset(bar); + QAbstractSeriesPrivate::initializeGraphics(parent); +} + +#include "moc_qbarseries.cpp" + +QT_CHARTS_END_NAMESPACE + diff --git a/src/charts/barchart/vertical/bar/qbarseries.h b/src/charts/barchart/vertical/bar/qbarseries.h new file mode 100644 index 00000000..d3fefd8a --- /dev/null +++ b/src/charts/barchart/vertical/bar/qbarseries.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QBARSERIES_H +#define QBARSERIES_H + +#include <QtCharts/qabstractbarseries.h> + +QT_CHARTS_BEGIN_NAMESPACE + +class QBarSeriesPrivate; + +class QT_CHARTS_EXPORT QBarSeries : public QAbstractBarSeries +{ + Q_OBJECT +public: + explicit QBarSeries(QObject *parent = 0); + ~QBarSeries(); + QAbstractSeries::SeriesType type() const; + +private: + Q_DECLARE_PRIVATE(QBarSeries) + Q_DISABLE_COPY(QBarSeries) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QBARSERIES_H diff --git a/src/charts/barchart/vertical/bar/qbarseries_p.h b/src/charts/barchart/vertical/bar/qbarseries_p.h new file mode 100644 index 00000000..c74194d3 --- /dev/null +++ b/src/charts/barchart/vertical/bar/qbarseries_p.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QBARSERIES_P_H +#define QBARSERIES_P_H + +#include "qabstractbarseries_p.h" +#include "abstractdomain_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + + +class QBarSeriesPrivate: public QAbstractBarSeriesPrivate +{ +public: + QBarSeriesPrivate(QBarSeries *q); + void initializeGraphics(QGraphicsItem* parent); + void initializeDomain(); + +private: + Q_DECLARE_PUBLIC(QBarSeries) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QBARSERIES_P_H diff --git a/src/charts/barchart/vertical/percent/percentbarchartitem.cpp b/src/charts/barchart/vertical/percent/percentbarchartitem.cpp new file mode 100644 index 00000000..1e0bbbae --- /dev/null +++ b/src/charts/barchart/vertical/percent/percentbarchartitem.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** 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 "percentbarchartitem_p.h" +#include "bar_p.h" +#include "qabstractbarseries_p.h" +#include "qbarset.h" +#include "qbarset_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + +PercentBarChartItem::PercentBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item) : + AbstractBarChartItem(series, item) +{ + connect(series, SIGNAL(labelsPositionChanged(QAbstractBarSeries::LabelsPosition)), + this, SLOT(handleLabelsPositionChanged())); + connect(series, SIGNAL(labelsFormatChanged(QString)), this, SLOT(positionLabels())); +} + +void PercentBarChartItem::initializeLayout() +{ + qreal categoryCount = m_series->d_func()->categoryCount(); + qreal setCount = m_series->count(); + qreal barWidth = m_series->d_func()->barWidth(); + + m_layout.clear(); + for(int category = 0; category < categoryCount; category++) { + for (int set = 0; set < setCount; set++) { + QRectF rect; + QPointF topLeft; + QPointF bottomRight; + + if (domain()->type() == AbstractDomain::XLogYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) { + topLeft = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2, domain()->minY()), m_validData); + bottomRight = domain()->calculateGeometryPoint(QPointF(category + barWidth / 2, domain()->minY()), m_validData); + } else { + topLeft = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2, 0), m_validData); + bottomRight = domain()->calculateGeometryPoint(QPointF(category + barWidth / 2, 0), m_validData); + } + + if (!m_validData) + return; + + rect.setTopLeft(topLeft); + rect.setBottomRight(bottomRight); + m_layout.append(rect.normalized()); + } + } +} + +QVector<QRectF> PercentBarChartItem::calculateLayout() +{ + QVector<QRectF> layout; + + // Use temporary qreals for accuracy + qreal categoryCount = m_series->d_func()->categoryCount(); + qreal setCount = m_series->count(); + qreal barWidth = m_series->d_func()->barWidth(); + + for(int category = 0; category < categoryCount; category++) { + qreal sum = 0; + qreal categorySum = m_series->d_func()->categorySum(category); + for (int set = 0; set < setCount; set++) { + qreal value = m_series->barSets().at(set)->at(category); + QRectF rect; + qreal topY = 0; + qreal newSum = value + sum; + if (newSum > 0) + topY = 100 * newSum / categorySum; + qreal bottomY = 0; + if (sum > 0) + bottomY = 100 * sum / categorySum; + QPointF topLeft = domain()->calculateGeometryPoint(QPointF(category - barWidth/2, topY), m_validData); + QPointF bottomRight; + if (domain()->type() == AbstractDomain::XLogYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) + bottomRight = domain()->calculateGeometryPoint(QPointF(category + barWidth/2, set ? bottomY : domain()->minY()), m_validData); + else + bottomRight = domain()->calculateGeometryPoint(QPointF(category + barWidth/2, set ? bottomY : 0), m_validData); + + rect.setTopLeft(topLeft); + rect.setBottomRight(bottomRight); + layout.append(rect.normalized()); + sum = newSum; + } + } + return layout; +} + +void PercentBarChartItem::handleUpdatedBars() +{ + // Handle changes in pen, brush, labels etc. + int categoryCount = m_series->d_func()->categoryCount(); + int setCount = m_series->count(); + int itemIndex(0); + static const QString valueTag(QLatin1String("@value")); + + for (int category = 0; category < categoryCount; category++) { + for (int set = 0; set < setCount; set++) { + QBarSetPrivate *barSet = m_series->d_func()->barsetAt(set)->d_ptr.data(); + Bar *bar = m_bars.at(itemIndex); + bar->setPen(barSet->m_pen); + bar->setBrush(barSet->m_brush); + bar->update(); + + QGraphicsTextItem *label = m_labels.at(itemIndex); + qreal p = m_series->d_func()->percentageAt(set, category) * 100.0; + QString vString(presenter()->numberToString(p, 'f', 0)); + QString valueLabel; + if (m_series->labelsFormat().isEmpty()) { + vString.append(QStringLiteral("%")); + valueLabel = vString; + } else { + valueLabel = m_series->labelsFormat(); + valueLabel.replace(valueTag, vString); + } + label->setHtml(valueLabel); + label->setFont(barSet->m_labelFont); + label->setDefaultTextColor(barSet->m_labelBrush.color()); + label->update(); + itemIndex++; + } + } +} + +void PercentBarChartItem::handleLabelsPositionChanged() +{ + positionLabels(); +} + +void PercentBarChartItem::positionLabels() +{ + for (int i = 0; i < m_layout.count(); i++) { + QGraphicsTextItem *label = m_labels.at(i); + qreal xPos = m_layout.at(i).center().x() - label->boundingRect().center().x(); + qreal yPos = 0; + + int offset = m_bars.at(i)->pen().width() / 2 + 2; + if (m_series->labelsPosition() == QAbstractBarSeries::LabelsCenter) + yPos = m_layout.at(i).center().y() - label->boundingRect().center().y(); + else if (m_series->labelsPosition() == QAbstractBarSeries::LabelsInsideEnd) + yPos = m_layout.at(i).top() - offset; + else if (m_series->labelsPosition() == QAbstractBarSeries::LabelsInsideBase) + yPos = m_layout.at(i).bottom() - label->boundingRect().height() + offset; + else if (m_series->labelsPosition() == QAbstractBarSeries::LabelsOutsideEnd) + yPos = m_layout.at(i).top() - label->boundingRect().height() + offset; + + label->setPos(xPos, yPos); + label->setZValue(zValue() + 1); + } +} + +#include "moc_percentbarchartitem_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/vertical/percent/percentbarchartitem_p.h b/src/charts/barchart/vertical/percent/percentbarchartitem_p.h new file mode 100644 index 00000000..4293d875 --- /dev/null +++ b/src/charts/barchart/vertical/percent/percentbarchartitem_p.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + + +#ifndef PERCENTBARCHARTITEM_H +#define PERCENTBARCHARTITEM_H + +#include "abstractbarchartitem_p.h" +#include <QGraphicsItem> + +QT_CHARTS_BEGIN_NAMESPACE + +class QAbstractBarSeries; + +class PercentBarChartItem : public AbstractBarChartItem +{ + Q_OBJECT +public: + PercentBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item = 0); + void handleUpdatedBars(); + +private slots: + void handleLabelsPositionChanged(); + void positionLabels(); + +private: + virtual QVector<QRectF> calculateLayout(); + void initializeLayout(); +}; + +QT_CHARTS_END_NAMESPACE + +#endif // PERCENTBARCHARTITEM_H diff --git a/src/charts/barchart/vertical/percent/qpercentbarseries.cpp b/src/charts/barchart/vertical/percent/qpercentbarseries.cpp new file mode 100644 index 00000000..7899899b --- /dev/null +++ b/src/charts/barchart/vertical/percent/qpercentbarseries.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** 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 "qpercentbarseries.h" +#include "qpercentbarseries_p.h" +#include "percentbarchartitem_p.h" +#include "chartdataset_p.h" +#include "charttheme_p.h" +#include "qvalueaxis.h" + +QT_CHARTS_BEGIN_NAMESPACE + +/*! + \class QPercentBarSeries + \inmodule Qt Charts + \brief Series for creating percent bar chart. + \mainclass + + QPercentBarSeries represents a series of data shown as bars. The purpose of this class is to + draw bars as stacks, where each bar is shown as percentage of all bars in that category. + QPercentBarSeries groups the data from sets to categories, which are defined by a QStringList. + Bars with zero value are not drawn. + + See the \l {PercentbarChart Example} {percent bar chart example} to learn how to create a + percent bar chart. + \image examples_percentbarchart.png + + \sa QBarSet, QStackedBarSeries, QAbstractBarSeries +*/ +/*! + \qmltype PercentBarSeries + \instantiates QPercentBarSeries + \inqmlmodule QtCharts + + \inherits AbstractBarSeries + + \brief Series for creating persent bar chart. + + The following QML shows how to create a simple percent bar chart: + \snippet qmlchart/qml/qmlchart/View8.qml 1 + \beginfloatleft + \image examples_qmlchart8.png + \endfloat + \clearfloat +*/ + +/*! + Constructs empty QPercentBarSeries. + QPercentBarSeries is QObject which is a child of a \a parent. +*/ +QPercentBarSeries::QPercentBarSeries(QObject *parent) + : QAbstractBarSeries(*new QPercentBarSeriesPrivate(this), parent) +{ +} + +/*! + Destructor. Removes series from chart. +*/ +QPercentBarSeries::~QPercentBarSeries() +{ + Q_D(QPercentBarSeries); + if (d->m_chart) + d->m_chart->removeSeries(this); +} + +/*! + Returns QAbstractSeries::SeriesTypePercentBar. +*/ +QAbstractSeries::SeriesType QPercentBarSeries::type() const +{ + return QAbstractSeries::SeriesTypePercentBar; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QPercentBarSeriesPrivate::QPercentBarSeriesPrivate(QPercentBarSeries *q) : QAbstractBarSeriesPrivate(q) +{ + +} + +void QPercentBarSeriesPrivate::initializeDomain() +{ + qreal minX(domain()->minX()); + qreal minY(domain()->minY()); + qreal maxX(domain()->maxX()); + qreal maxY(domain()->maxY()); + + qreal x = categoryCount(); + minX = qMin(minX, - (qreal)0.5); + maxX = qMax(maxX, x - (qreal)0.5); + minY = 0; + maxY = 100; + + domain()->setRange(minX, maxX, minY, maxY); +} + + +void QPercentBarSeriesPrivate::initializeGraphics(QGraphicsItem* parent) +{ + Q_Q(QPercentBarSeries); + PercentBarChartItem *bar = new PercentBarChartItem(q,parent); + m_item.reset(bar); + QAbstractSeriesPrivate::initializeGraphics(parent); +} + +#include "moc_qpercentbarseries.cpp" + +QT_CHARTS_END_NAMESPACE + diff --git a/src/charts/barchart/vertical/percent/qpercentbarseries.h b/src/charts/barchart/vertical/percent/qpercentbarseries.h new file mode 100644 index 00000000..5f9ce140 --- /dev/null +++ b/src/charts/barchart/vertical/percent/qpercentbarseries.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QPERCENTBARSERIES_H +#define QPERCENTBARSERIES_H + +#include <QStringList> +#include <QtCharts/qabstractbarseries.h> + +QT_CHARTS_BEGIN_NAMESPACE + +class QPercentBarSeriesPrivate; + +class QT_CHARTS_EXPORT QPercentBarSeries : public QAbstractBarSeries +{ + Q_OBJECT +public: + explicit QPercentBarSeries(QObject *parent = 0); + ~QPercentBarSeries(); + QAbstractSeries::SeriesType type() const; + +private: + Q_DECLARE_PRIVATE(QPercentBarSeries) + Q_DISABLE_COPY(QPercentBarSeries) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QPERCENTBARSERIES_H diff --git a/src/charts/barchart/vertical/percent/qpercentbarseries_p.h b/src/charts/barchart/vertical/percent/qpercentbarseries_p.h new file mode 100644 index 00000000..f31c9638 --- /dev/null +++ b/src/charts/barchart/vertical/percent/qpercentbarseries_p.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QPERCENTBARSERIES_P_H +#define QPERCENTBARSERIES_P_H + +#include "qabstractbarseries_p.h" +#include "abstractdomain_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + + +class QPercentBarSeriesPrivate: public QAbstractBarSeriesPrivate +{ +public: + QPercentBarSeriesPrivate(QPercentBarSeries *q); + void initializeDomain(); + void initializeGraphics(QGraphicsItem* parent); +private: + Q_DECLARE_PUBLIC(QPercentBarSeries) +}; + +QT_CHARTS_END_NAMESPACE + +#endif diff --git a/src/charts/barchart/vertical/stacked/qstackedbarseries.cpp b/src/charts/barchart/vertical/stacked/qstackedbarseries.cpp new file mode 100644 index 00000000..7a1946f7 --- /dev/null +++ b/src/charts/barchart/vertical/stacked/qstackedbarseries.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** 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 "qstackedbarseries.h" +#include "qstackedbarseries_p.h" +#include "stackedbarchartitem_p.h" +#include "chartdataset_p.h" +#include "charttheme_p.h" +#include "qvalueaxis.h" + +QT_CHARTS_BEGIN_NAMESPACE + +/*! + \class QStackedBarSeries + \inmodule Qt Charts + \brief Series for creating stacked bar chart. + \mainclass + + QStackedBarSeries represents a series of data shown as bars. The purpose of this class is to draw bars + as stacks, where bars in same category are stacked on top of each other. + QStackedBarSeries groups the data from sets to categories, which are defined by QStringList. + + See the \l {StackedbarChart Example} {stacked bar chart example} to learn how to create a stacked bar chart. + \image examples_stackedbarchart.png + + \sa QBarSet, QPercentBarSeries, QAbstractBarSeries +*/ + +/*! + \qmltype StackedBarSeries + \instantiates QStackedBarSeries + \inqmlmodule QtCharts + + \inherits AbstractBarSeries + + \brief Series for creating stacked bar chart. + + The following QML shows how to create a simple stacked bar chart: + \snippet qmlchart/qml/qmlchart/View7.qml 1 + \beginfloatleft + \image examples_qmlchart7.png + \endfloat + \clearfloat +*/ + +/*! + Constructs empty QStackedBarSeries. + QStackedBarSeries is QObject which is a child of a \a parent. +*/ +QStackedBarSeries::QStackedBarSeries(QObject *parent) + : QAbstractBarSeries(*new QStackedBarSeriesPrivate(this), parent) +{ +} + +/*! + Destructor. Removes series from chart. +*/ +QStackedBarSeries::~QStackedBarSeries() +{ + Q_D(QStackedBarSeries); + if (d->m_chart) + d->m_chart->removeSeries(this); +} +/*! + Returns QAbstractSeries::SeriesTypeStackedBar. +*/ +QAbstractSeries::SeriesType QStackedBarSeries::type() const +{ + return QAbstractSeries::SeriesTypeStackedBar; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +QStackedBarSeriesPrivate::QStackedBarSeriesPrivate(QStackedBarSeries *q) : QAbstractBarSeriesPrivate(q) +{ + +} + +void QStackedBarSeriesPrivate::initializeDomain() +{ + qreal minX(domain()->minX()); + qreal minY(domain()->minY()); + qreal maxX(domain()->maxX()); + qreal maxY(domain()->maxY()); + + qreal x = categoryCount(); + minX = qMin(minX, - (qreal)0.5); + minY = qMin(minY, bottom()); + maxX = qMax(maxX, x - (qreal)0.5); + maxY = qMax(maxY, top()); + + domain()->setRange(minX, maxX, minY, maxY); +} + +void QStackedBarSeriesPrivate::initializeGraphics(QGraphicsItem* parent) +{ + Q_Q(QStackedBarSeries); + StackedBarChartItem *bar = new StackedBarChartItem(q,parent); + m_item.reset(bar); + QAbstractSeriesPrivate::initializeGraphics(parent); +} + +#include "moc_qstackedbarseries.cpp" + +QT_CHARTS_END_NAMESPACE + diff --git a/src/charts/barchart/vertical/stacked/qstackedbarseries.h b/src/charts/barchart/vertical/stacked/qstackedbarseries.h new file mode 100644 index 00000000..bab6e174 --- /dev/null +++ b/src/charts/barchart/vertical/stacked/qstackedbarseries.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QSTACKEDBARSERIES_H +#define QSTACKEDBARSERIES_H + +#include <QStringList> +#include <QtCharts/qabstractbarseries.h> + +QT_CHARTS_BEGIN_NAMESPACE + +class QStackedBarSeriesPrivate; + +class QT_CHARTS_EXPORT QStackedBarSeries : public QAbstractBarSeries +{ + Q_OBJECT +public: + explicit QStackedBarSeries(QObject *parent = 0); + ~QStackedBarSeries(); + QAbstractSeries::SeriesType type() const; + +private: + Q_DECLARE_PRIVATE(QStackedBarSeries) + Q_DISABLE_COPY(QStackedBarSeries) +}; + +QT_CHARTS_END_NAMESPACE + +#endif // QSTACKEDBARSERIES_H diff --git a/src/charts/barchart/vertical/stacked/qstackedbarseries_p.h b/src/charts/barchart/vertical/stacked/qstackedbarseries_p.h new file mode 100644 index 00000000..d5cf3c2d --- /dev/null +++ b/src/charts/barchart/vertical/stacked/qstackedbarseries_p.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef QSTACKEDBARSERIES_P_H +#define QSTACKEDBARSERIES_P_H + +#include "qabstractbarseries_p.h" +#include "abstractdomain_p.h" + +QT_CHARTS_BEGIN_NAMESPACE + + +class QStackedBarSeriesPrivate: public QAbstractBarSeriesPrivate +{ +public: + QStackedBarSeriesPrivate(QStackedBarSeries *q); + void initializeGraphics(QGraphicsItem* parent); + void initializeDomain(); +private: + Q_DECLARE_PUBLIC(QStackedBarSeries) +}; + +QT_CHARTS_END_NAMESPACE + +#endif diff --git a/src/charts/barchart/vertical/stacked/stackedbarchartitem.cpp b/src/charts/barchart/vertical/stacked/stackedbarchartitem.cpp new file mode 100644 index 00000000..953bb455 --- /dev/null +++ b/src/charts/barchart/vertical/stacked/stackedbarchartitem.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** 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 "stackedbarchartitem_p.h" +#include "bar_p.h" +#include "qbarset_p.h" +#include "qabstractbarseries_p.h" +#include "qbarset.h" + +QT_CHARTS_BEGIN_NAMESPACE + +StackedBarChartItem::StackedBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item) : + AbstractBarChartItem(series, item) +{ + connect(series, SIGNAL(labelsPositionChanged(QAbstractBarSeries::LabelsPosition)), + this, SLOT(handleLabelsPositionChanged())); + connect(series, SIGNAL(labelsFormatChanged(QString)), this, SLOT(positionLabels())); +} + +void StackedBarChartItem::initializeLayout() +{ + qreal categoryCount = m_series->d_func()->categoryCount(); + qreal setCount = m_series->count(); + qreal barWidth = m_series->d_func()->barWidth(); + + m_layout.clear(); + for(int category = 0; category < categoryCount; category++) { + for (int set = 0; set < setCount; set++) { + QRectF rect; + QPointF topLeft; + QPointF bottomRight; + + if (domain()->type() == AbstractDomain::XLogYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) { + topLeft = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2, domain()->minY()), m_validData); + bottomRight = domain()->calculateGeometryPoint(QPointF(category + barWidth / 2, domain()->minY()), m_validData); + } else { + topLeft = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2, 0), m_validData); + bottomRight = domain()->calculateGeometryPoint(QPointF(category + barWidth / 2, 0), m_validData); + } + + if (!m_validData) + return; + + rect.setTopLeft(topLeft); + rect.setBottomRight(bottomRight); + m_layout.append(rect.normalized()); + } + } +} + +QVector<QRectF> StackedBarChartItem::calculateLayout() +{ + QVector<QRectF> layout; + // Use temporary qreals for accuracy + qreal categoryCount = m_series->d_func()->categoryCount(); + qreal setCount = m_series->count(); + qreal barWidth = m_series->d_func()->barWidth(); + + for(int category = 0; category < categoryCount; category++) { + qreal positiveSum = 0; + qreal negativeSum = 0; + for (int set = 0; set < setCount; set++) { + qreal value = m_series->barSets().at(set)->at(category); + QRectF rect; + QPointF topLeft; + QPointF bottomRight; + if (value < 0) { + bottomRight = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2, value + negativeSum), m_validData); + if (domain()->type() == AbstractDomain::XLogYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) + topLeft = domain()->calculateGeometryPoint(QPointF(category + barWidth / 2, set ? negativeSum : domain()->minY()), m_validData); + else + topLeft = domain()->calculateGeometryPoint(QPointF(category + barWidth / 2, set ? negativeSum : 0), m_validData); + negativeSum += value; + } else { + topLeft = domain()->calculateGeometryPoint(QPointF(category - barWidth / 2, value + positiveSum), m_validData); + if (domain()->type() == AbstractDomain::XLogYDomain || domain()->type() == AbstractDomain::LogXLogYDomain) + bottomRight = domain()->calculateGeometryPoint(QPointF(category + barWidth / 2, set ? positiveSum : domain()->minY()), m_validData); + else + bottomRight = domain()->calculateGeometryPoint(QPointF(category + barWidth / 2, set ? positiveSum : 0), m_validData); + positiveSum += value; + } + + rect.setTopLeft(topLeft); + rect.setBottomRight(bottomRight); + layout.append(rect.normalized()); + } + } + return layout; +} + +void StackedBarChartItem::handleLabelsPositionChanged() +{ + positionLabels(); +} + +void StackedBarChartItem::positionLabels() +{ + for (int i = 0; i < m_layout.count(); i++) { + QGraphicsTextItem *label = m_labels.at(i); + qreal xPos = m_layout.at(i).center().x() - label->boundingRect().center().x(); + qreal yPos = 0; + + int offset = m_bars.at(i)->pen().width() / 2 + 2; + if (m_series->labelsPosition() == QAbstractBarSeries::LabelsCenter) + yPos = m_layout.at(i).center().y() - label->boundingRect().center().y(); + else if (m_series->labelsPosition() == QAbstractBarSeries::LabelsInsideEnd) + yPos = m_layout.at(i).top() - offset; + else if (m_series->labelsPosition() == QAbstractBarSeries::LabelsInsideBase) + yPos = m_layout.at(i).bottom() - label->boundingRect().height() + offset; + else if (m_series->labelsPosition() == QAbstractBarSeries::LabelsOutsideEnd) + yPos = m_layout.at(i).top() - label->boundingRect().height() + offset; + + label->setPos(xPos, yPos); + label->setZValue(zValue() + 1); + } +} + +#include "moc_stackedbarchartitem_p.cpp" + +QT_CHARTS_END_NAMESPACE diff --git a/src/charts/barchart/vertical/stacked/stackedbarchartitem_p.h b/src/charts/barchart/vertical/stacked/stackedbarchartitem_p.h new file mode 100644 index 00000000..f2fa6b73 --- /dev/null +++ b/src/charts/barchart/vertical/stacked/stackedbarchartitem_p.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Enterprise Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + + +#ifndef STACKEDBARCHARTITEM_H +#define STACKEDBARCHARTITEM_H + +#include "abstractbarchartitem_p.h" +#include <qstackedbarseries.h> +#include <QGraphicsItem> + +QT_CHARTS_BEGIN_NAMESPACE + +class StackedBarChartItem : public AbstractBarChartItem +{ + Q_OBJECT +public: + StackedBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item =0); + +private slots: + void handleLabelsPositionChanged(); + void positionLabels(); + +private: + virtual QVector<QRectF> calculateLayout(); + void initializeLayout(); + +}; + +QT_CHARTS_END_NAMESPACE + +#endif // STACKEDBARCHARTITEM_H |