summaryrefslogtreecommitdiffstats
path: root/src/charts/piechart
diff options
context:
space:
mode:
Diffstat (limited to 'src/charts/piechart')
-rw-r--r--src/charts/piechart/piechart.pri26
-rw-r--r--src/charts/piechart/piechartitem.cpp228
-rw-r--r--src/charts/piechart/piechartitem_p.h86
-rw-r--r--src/charts/piechart/pieslicedata_p.h141
-rw-r--r--src/charts/piechart/piesliceitem.cpp319
-rw-r--r--src/charts/piechart/piesliceitem_p.h91
-rw-r--r--src/charts/piechart/qhpiemodelmapper.cpp267
-rw-r--r--src/charts/piechart/qhpiemodelmapper.h70
-rw-r--r--src/charts/piechart/qpiemodelmapper.cpp568
-rw-r--r--src/charts/piechart/qpiemodelmapper.h69
-rw-r--r--src/charts/piechart/qpiemodelmapper_p.h99
-rw-r--r--src/charts/piechart/qpieseries.cpp947
-rw-r--r--src/charts/piechart/qpieseries.h103
-rw-r--r--src/charts/piechart/qpieseries_p.h93
-rw-r--r--src/charts/piechart/qpieslice.cpp794
-rw-r--r--src/charts/piechart/qpieslice.h147
-rw-r--r--src/charts/piechart/qpieslice_p.h80
-rw-r--r--src/charts/piechart/qvpiemodelmapper.cpp270
-rw-r--r--src/charts/piechart/qvpiemodelmapper.h70
19 files changed, 4468 insertions, 0 deletions
diff --git a/src/charts/piechart/piechart.pri b/src/charts/piechart/piechart.pri
new file mode 100644
index 00000000..2c45c4e6
--- /dev/null
+++ b/src/charts/piechart/piechart.pri
@@ -0,0 +1,26 @@
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+
+SOURCES += \
+ $$PWD/qpieseries.cpp \
+ $$PWD/piesliceitem.cpp \
+ $$PWD/piechartitem.cpp \
+ $$PWD/qpieslice.cpp \
+ $$PWD/qpiemodelmapper.cpp \
+ $$PWD/qvpiemodelmapper.cpp \
+ $$PWD/qhpiemodelmapper.cpp
+
+PRIVATE_HEADERS += \
+ $$PWD/pieslicedata_p.h \
+ $$PWD/piechartitem_p.h \
+ $$PWD/piesliceitem_p.h \
+ $$PWD/qpieslice_p.h \
+ $$PWD/qpieseries_p.h \
+ $$PWD/qpiemodelmapper_p.h
+
+PUBLIC_HEADERS += \
+ $$PWD/qpieseries.h \
+ $$PWD/qpieslice.h \
+ $$PWD/qpiemodelmapper.h \
+ $$PWD/qvpiemodelmapper.h \
+ $$PWD/qhpiemodelmapper.h
diff --git a/src/charts/piechart/piechartitem.cpp b/src/charts/piechart/piechartitem.cpp
new file mode 100644
index 00000000..dbf7edf8
--- /dev/null
+++ b/src/charts/piechart/piechartitem.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** 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 "piechartitem_p.h"
+#include "piesliceitem_p.h"
+#include "qpieslice.h"
+#include "qpieslice_p.h"
+#include "qpieseries.h"
+#include "qpieseries_p.h"
+#include "chartpresenter_p.h"
+#include "chartdataset_p.h"
+#include "pieanimation_p.h"
+#include <QPainter>
+#include <QTimer>
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+PieChartItem::PieChartItem(QPieSeries *series, QGraphicsItem* item)
+ : ChartItem(series->d_func(),item),
+ m_series(series),
+ m_animation(0)
+{
+ Q_ASSERT(series);
+
+ QPieSeriesPrivate *p = QPieSeriesPrivate::fromSeries(series);
+ connect(series, SIGNAL(visibleChanged()), this, SLOT(handleSeriesVisibleChanged()));
+ connect(series, SIGNAL(opacityChanged()), this, SLOT(handleOpacityChanged()));
+ connect(series, SIGNAL(added(QList<QPieSlice*>)), this, SLOT(handleSlicesAdded(QList<QPieSlice*>)));
+ connect(series, SIGNAL(removed(QList<QPieSlice*>)), this, SLOT(handleSlicesRemoved(QList<QPieSlice*>)));
+ connect(p, SIGNAL(horizontalPositionChanged()), this, SLOT(updateLayout()));
+ connect(p, SIGNAL(verticalPositionChanged()), this, SLOT(updateLayout()));
+ connect(p, SIGNAL(pieSizeChanged()), this, SLOT(updateLayout()));
+ connect(p, SIGNAL(calculatedDataChanged()), this, SLOT(updateLayout()));
+
+ // Note: the following does not affect as long as the item does not have anything to paint
+ setZValue(ChartPresenter::PieSeriesZValue);
+
+ // Note: will not create slice items until we have a proper rectangle to draw on.
+}
+
+PieChartItem::~PieChartItem()
+{
+ // slices deleted automatically through QGraphicsItem
+ if (m_series) {
+ m_series->disconnect(this);
+ QPieSeriesPrivate::fromSeries(m_series)->disconnect(this);
+ }
+ foreach (QPieSlice *slice, m_sliceItems.keys()) {
+ slice->disconnect(this);
+ QPieSlicePrivate::fromSlice(slice)->disconnect(this);
+ }
+}
+
+void PieChartItem::setAnimation(PieAnimation *animation)
+{
+ m_animation = animation;
+}
+
+ChartAnimation *PieChartItem::animation() const
+{
+ return m_animation;
+}
+
+void PieChartItem::handleDomainUpdated()
+{
+ QRectF rect(QPointF(0,0),domain()->size());
+ if(m_rect!=rect){
+ prepareGeometryChange();
+ m_rect = rect;
+ updateLayout();
+
+ if (m_sliceItems.isEmpty())
+ handleSlicesAdded(m_series->slices());
+ }
+}
+
+void PieChartItem::updateLayout()
+{
+ // find pie center coordinates
+ m_pieCenter.setX(m_rect.left() + (m_rect.width() * m_series->horizontalPosition()));
+ m_pieCenter.setY(m_rect.top() + (m_rect.height() * m_series->verticalPosition()));
+
+ // find maximum radius for pie
+ m_pieRadius = m_rect.height() / 2;
+ if (m_rect.width() < m_rect.height())
+ m_pieRadius = m_rect.width() / 2;
+
+ m_holeSize = m_pieRadius;
+ // apply size factor
+ m_pieRadius *= m_series->pieSize();
+ m_holeSize *= m_series->holeSize();
+
+ // set layouts for existing slice items
+ foreach (QPieSlice *slice, m_series->slices()) {
+ PieSliceItem *sliceItem = m_sliceItems.value(slice);
+ if (sliceItem) {
+ PieSliceData sliceData = updateSliceGeometry(slice);
+ if (m_animation)
+ presenter()->startAnimation(m_animation->updateValue(sliceItem, sliceData));
+ else
+ sliceItem->setLayout(sliceData);
+ }
+ }
+
+ update();
+}
+
+void PieChartItem::handleSlicesAdded(QList<QPieSlice *> slices)
+{
+ // delay creating slice items until there is a proper rectangle
+ if (!m_rect.isValid() && m_sliceItems.isEmpty())
+ return;
+
+ themeManager()->updateSeries(m_series);
+
+ bool startupAnimation = m_sliceItems.isEmpty();
+
+ foreach(QPieSlice * slice, slices) {
+ PieSliceItem *sliceItem = new PieSliceItem(this);
+ m_sliceItems.insert(slice, sliceItem);
+
+ // Note: no need to connect to slice valueChanged() etc.
+ // This is handled through calculatedDataChanged signal.
+ connect(slice, SIGNAL(labelChanged()), this, SLOT(handleSliceChanged()));
+ connect(slice, SIGNAL(labelVisibleChanged()), this, SLOT(handleSliceChanged()));
+ connect(slice, SIGNAL(penChanged()), this, SLOT(handleSliceChanged()));
+ connect(slice, SIGNAL(brushChanged()), this, SLOT(handleSliceChanged()));
+ connect(slice, SIGNAL(labelBrushChanged()), this, SLOT(handleSliceChanged()));
+ connect(slice, SIGNAL(labelFontChanged()), this, SLOT(handleSliceChanged()));
+
+ QPieSlicePrivate *p = QPieSlicePrivate::fromSlice(slice);
+ connect(p, SIGNAL(labelPositionChanged()), this, SLOT(handleSliceChanged()));
+ connect(p, SIGNAL(explodedChanged()), this, SLOT(handleSliceChanged()));
+ connect(p, SIGNAL(labelArmLengthFactorChanged()), this, SLOT(handleSliceChanged()));
+ connect(p, SIGNAL(explodeDistanceFactorChanged()), this, SLOT(handleSliceChanged()));
+
+ connect(sliceItem, SIGNAL(clicked(Qt::MouseButtons)), slice, SIGNAL(clicked()));
+ connect(sliceItem, SIGNAL(hovered(bool)), slice, SIGNAL(hovered(bool)));
+
+ PieSliceData sliceData = updateSliceGeometry(slice);
+ if (m_animation)
+ presenter()->startAnimation(m_animation->addSlice(sliceItem, sliceData, startupAnimation));
+ else
+ sliceItem->setLayout(sliceData);
+ }
+}
+
+void PieChartItem::handleSlicesRemoved(QList<QPieSlice *> slices)
+{
+ themeManager()->updateSeries(m_series);
+
+ foreach (QPieSlice *slice, slices) {
+
+ PieSliceItem *sliceItem = m_sliceItems.value(slice);
+
+ // this can happen if you call append() & remove() in a row so that PieSliceItem is not even created
+ if (!sliceItem)
+ continue;
+
+ m_sliceItems.remove(slice);
+ slice->disconnect(this);
+ QPieSlicePrivate::fromSlice(slice)->disconnect(this);
+
+ if (m_animation)
+ presenter()->startAnimation(m_animation->removeSlice(sliceItem)); // animator deletes the PieSliceItem
+ else
+ delete sliceItem;
+ }
+}
+
+void PieChartItem::handleSliceChanged()
+{
+ QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
+ if (!slice) {
+ QPieSlicePrivate *slicep = qobject_cast<QPieSlicePrivate *>(sender());
+ slice = slicep->q_ptr;
+ }
+ Q_ASSERT(m_sliceItems.contains(slice));
+
+ PieSliceItem *sliceItem = m_sliceItems.value(slice);
+ PieSliceData sliceData = updateSliceGeometry(slice);
+ if (m_animation)
+ presenter()->startAnimation(m_animation->updateValue(sliceItem, sliceData));
+ else
+ sliceItem->setLayout(sliceData);
+
+ update();
+}
+
+void PieChartItem::handleSeriesVisibleChanged()
+{
+ setVisible(m_series->isVisible());
+}
+
+void PieChartItem::handleOpacityChanged()
+{
+ setOpacity(m_series->opacity());
+}
+
+PieSliceData PieChartItem::updateSliceGeometry(QPieSlice *slice)
+{
+ PieSliceData &sliceData = QPieSlicePrivate::fromSlice(slice)->m_data;
+ sliceData.m_center = PieSliceItem::sliceCenter(m_pieCenter, m_pieRadius, slice);
+ sliceData.m_radius = m_pieRadius;
+ sliceData.m_holeRadius = m_holeSize;
+ return sliceData;
+}
+
+#include "moc_piechartitem_p.cpp"
+
+QT_CHARTS_END_NAMESPACE
diff --git a/src/charts/piechart/piechartitem_p.h b/src/charts/piechart/piechartitem_p.h
new file mode 100644
index 00000000..a6511b42
--- /dev/null
+++ b/src/charts/piechart/piechartitem_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** 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 PIECHARTITEM_H
+#define PIECHARTITEM_H
+
+#include "qpieseries.h"
+#include "chartitem_p.h"
+#include "piesliceitem_p.h"
+#include <QPointer>
+
+class QGraphicsItem;
+QT_CHARTS_BEGIN_NAMESPACE
+class QPieSlice;
+class ChartPresenter;
+class PieAnimation;
+
+class PieChartItem : public ChartItem
+{
+ Q_OBJECT
+
+public:
+ explicit PieChartItem(QPieSeries *series, QGraphicsItem* item = 0);
+ ~PieChartItem();
+
+ // from QGraphicsItem
+ QRectF boundingRect() const { return m_rect; }
+ void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {}
+
+public Q_SLOTS:
+ // from Chart
+ virtual void handleDomainUpdated();
+
+ void updateLayout();
+ void handleSlicesAdded(QList<QPieSlice *> slices);
+ void handleSlicesRemoved(QList<QPieSlice *> slices);
+ void handleSliceChanged();
+ void handleSeriesVisibleChanged();
+ void handleOpacityChanged();
+
+ void setAnimation(PieAnimation *animation);
+ ChartAnimation *animation() const;
+
+private:
+ PieSliceData updateSliceGeometry(QPieSlice *slice);
+
+private:
+ QHash<QPieSlice *, PieSliceItem *> m_sliceItems;
+ QPointer<QPieSeries> m_series;
+ QRectF m_rect;
+ QPointF m_pieCenter;
+ qreal m_pieRadius;
+ qreal m_holeSize;
+ PieAnimation *m_animation;
+
+};
+
+QT_CHARTS_END_NAMESPACE
+
+#endif // PIECHARTITEM_H
diff --git a/src/charts/piechart/pieslicedata_p.h b/src/charts/piechart/pieslicedata_p.h
new file mode 100644
index 00000000..37985121
--- /dev/null
+++ b/src/charts/piechart/pieslicedata_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** 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 PIESLICEDATA_P_H
+#define PIESLICEDATA_P_H
+
+#include <qchartglobal.h>
+#include <qpieslice.h>
+#include <QPen>
+#include <QBrush>
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+template <class T>
+class Themed : public T
+{
+public:
+ Themed(): m_isThemed(true) {}
+
+ inline T &operator=(const T &other) { return T::operator =(other); }
+
+ inline bool operator!=(const T &other) const { return T::operator !=(other); }
+ inline bool operator!=(const Themed &other) const
+ {
+ if (T::operator !=(other))
+ return true;
+
+ if (m_isThemed != other.m_isThemed)
+ return true;
+
+ return false;
+ }
+
+ inline void setThemed(bool state) { m_isThemed = state; }
+ inline bool isThemed() const { return m_isThemed; }
+
+private:
+ bool m_isThemed;
+};
+
+class PieSliceData
+{
+public:
+ PieSliceData() :
+ m_value(0),
+ m_isExploded(false),
+ m_explodeDistanceFactor(0.15),
+ m_isLabelVisible(false),
+ m_labelPosition(QPieSlice::LabelOutside),
+ m_labelArmLengthFactor(0.15),
+ m_percentage(0),
+ m_radius(0),
+ m_startAngle(0),
+ m_angleSpan(0),
+ m_holeRadius(0)
+ {
+ }
+
+ bool operator!=(const PieSliceData &other) const {
+ if (!qFuzzyIsNull(m_value - other.m_value))
+ return true;
+
+ if (m_slicePen != other.m_slicePen ||
+ m_sliceBrush != other.m_sliceBrush)
+ return true;
+
+ if (m_isExploded != other.m_isExploded ||
+ !qFuzzyIsNull(m_explodeDistanceFactor - other.m_explodeDistanceFactor))
+ return true;
+
+ if (m_isLabelVisible != other.m_isLabelVisible ||
+ m_labelText != other.m_labelText ||
+ m_labelFont != other.m_labelFont ||
+ m_labelPosition != other.m_labelPosition ||
+ !qFuzzyIsNull(m_labelArmLengthFactor - other.m_labelArmLengthFactor) ||
+ m_labelBrush != other.m_labelBrush)
+ return true;
+
+ if (!qFuzzyIsNull(m_percentage - other.m_percentage) ||
+ m_center != other.m_center ||
+ !qFuzzyIsNull(m_radius - other.m_radius) ||
+ !qFuzzyIsNull(m_startAngle - other.m_startAngle) ||
+ !qFuzzyIsNull(m_angleSpan - other.m_angleSpan))
+ return true;
+
+ return false;
+ }
+
+ qreal m_value;
+
+ Themed<QPen> m_slicePen;
+ Themed<QBrush> m_sliceBrush;
+
+ bool m_isExploded;
+ qreal m_explodeDistanceFactor;
+
+ bool m_isLabelVisible;
+ QString m_labelText;
+ Themed<QFont> m_labelFont;
+ QPieSlice::LabelPosition m_labelPosition;
+ qreal m_labelArmLengthFactor;
+ Themed<QBrush> m_labelBrush;
+
+ qreal m_percentage;
+ QPointF m_center;
+ qreal m_radius;
+ qreal m_startAngle;
+ qreal m_angleSpan;
+
+ qreal m_holeRadius;
+};
+
+QT_CHARTS_END_NAMESPACE
+
+#endif // PIESLICEDATA_P_H
diff --git a/src/charts/piechart/piesliceitem.cpp b/src/charts/piechart/piesliceitem.cpp
new file mode 100644
index 00000000..70f03a94
--- /dev/null
+++ b/src/charts/piechart/piesliceitem.cpp
@@ -0,0 +1,319 @@
+/****************************************************************************
+**
+** 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 "piesliceitem_p.h"
+#include "piechartitem_p.h"
+#include "qpieseries.h"
+#include "qpieslice.h"
+#include "chartpresenter_p.h"
+#include <QPainter>
+#include <qmath.h>
+#include <QGraphicsSceneEvent>
+#include <QTime>
+#include <QTextDocument>
+#include <QDebug>
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+QPointF offset(qreal angle, qreal length)
+{
+ qreal dx = qSin(angle * (M_PI / 180)) * length;
+ qreal dy = qCos(angle * (M_PI / 180)) * length;
+ return QPointF(dx, -dy);
+}
+
+PieSliceItem::PieSliceItem(QGraphicsItem *parent)
+ : QGraphicsObject(parent),
+ m_hovered(false)
+{
+ setAcceptHoverEvents(true);
+ setAcceptedMouseButtons(Qt::MouseButtonMask);
+ setZValue(ChartPresenter::PieSeriesZValue);
+ m_labelItem = new QGraphicsTextItem(this);
+ m_labelItem->document()->setDocumentMargin(1.0);
+}
+
+PieSliceItem::~PieSliceItem()
+{
+ // If user is hovering over the slice and it gets destroyed we do
+ // not get a hover leave event. So we must emit the signal here.
+ if (m_hovered)
+ emit hovered(false);
+}
+
+QRectF PieSliceItem::boundingRect() const
+{
+ return m_boundingRect;
+}
+
+QPainterPath PieSliceItem::shape() const
+{
+ // Don't include the label and label arm.
+ // This is used to detect a mouse clicks. We do not want clicks from label.
+ return m_slicePath;
+}
+
+void PieSliceItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
+{
+ painter->save();
+ painter->setClipRect(parentItem()->boundingRect());
+ painter->setPen(m_data.m_slicePen);
+ painter->setBrush(m_data.m_sliceBrush);
+ painter->drawPath(m_slicePath);
+ painter->restore();
+
+ if (m_data.m_isLabelVisible) {
+ painter->save();
+
+ // Pen for label arm not defined in the QPieSeries api, let's use brush's color instead
+ painter->setBrush(m_data.m_labelBrush);
+
+ if (m_data.m_labelPosition == QPieSlice::LabelOutside) {
+ painter->setClipRect(parentItem()->boundingRect());
+ painter->strokePath(m_labelArmPath, m_data.m_labelBrush.color());
+ }
+
+ painter->restore();
+ }
+}
+
+void PieSliceItem::hoverEnterEvent(QGraphicsSceneHoverEvent * /*event*/)
+{
+ m_hovered = true;
+ emit hovered(true);
+}
+
+void PieSliceItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * /*event*/)
+{
+ m_hovered = false;
+ emit hovered(false);
+}
+
+void PieSliceItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ emit clicked(event->buttons());
+}
+
+void PieSliceItem::setLayout(const PieSliceData &sliceData)
+{
+ m_data = sliceData;
+ updateGeometry();
+ update();
+}
+
+void PieSliceItem::updateGeometry()
+{
+ if (m_data.m_radius <= 0)
+ return;
+
+ prepareGeometryChange();
+
+ // slice path
+ qreal centerAngle;
+ QPointF armStart;
+ m_slicePath = slicePath(m_data.m_center, m_data.m_radius, m_data.m_startAngle, m_data.m_angleSpan, &centerAngle, &armStart);
+
+ m_labelItem->setVisible(m_data.m_isLabelVisible);
+
+ if (m_data.m_isLabelVisible) {
+ // text rect
+ m_labelTextRect = ChartPresenter::textBoundingRect(m_data.m_labelFont,
+ m_data.m_labelText,
+ 0);
+
+ QString label(m_data.m_labelText);
+ m_labelItem->setDefaultTextColor(m_data.m_labelBrush.color());
+ m_labelItem->setFont(m_data.m_labelFont);
+
+ // text position
+ if (m_data.m_labelPosition == QPieSlice::LabelOutside) {
+ setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
+
+ // label arm path
+ QPointF labelTextStart;
+ m_labelArmPath = labelArmPath(armStart, centerAngle,
+ m_data.m_radius * m_data.m_labelArmLengthFactor,
+ m_labelTextRect.width(), &labelTextStart);
+
+ m_labelTextRect.moveBottomLeft(labelTextStart);
+ if (m_labelTextRect.left() < 0)
+ m_labelTextRect.setLeft(0);
+ else if (m_labelTextRect.left() < parentItem()->boundingRect().left())
+ m_labelTextRect.setLeft(parentItem()->boundingRect().left());
+ if (m_labelTextRect.right() > parentItem()->boundingRect().right())
+ m_labelTextRect.setRight(parentItem()->boundingRect().right());
+
+ label = ChartPresenter::truncatedText(m_data.m_labelFont, m_data.m_labelText,
+ qreal(0.0), m_labelTextRect.width(),
+ m_labelTextRect.height(), m_labelTextRect);
+ m_labelArmPath = labelArmPath(armStart, centerAngle,
+ m_data.m_radius * m_data.m_labelArmLengthFactor,
+ m_labelTextRect.width(), &labelTextStart);
+ m_labelTextRect.moveBottomLeft(labelTextStart);
+
+ m_labelItem->setTextWidth(m_labelTextRect.width()
+ + m_labelItem->document()->documentMargin());
+ m_labelItem->setHtml(label);
+ m_labelItem->setRotation(0);
+ m_labelItem->setPos(m_labelTextRect.x(), m_labelTextRect.y() + 1.0);
+ } else {
+ // label inside
+ setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+ m_labelItem->setTextWidth(m_labelTextRect.width()
+ + m_labelItem->document()->documentMargin());
+ m_labelItem->setHtml(label);
+
+ QPointF textCenter;
+ if (m_data.m_holeRadius > 0) {
+ textCenter = m_data.m_center + offset(centerAngle, m_data.m_holeRadius
+ + (m_data.m_radius
+ - m_data.m_holeRadius) / 2);
+ } else {
+ textCenter = m_data.m_center + offset(centerAngle, m_data.m_radius / 2);
+ }
+ m_labelItem->setPos(textCenter.x() - m_labelItem->boundingRect().width() / 2,
+ textCenter.y() - m_labelTextRect.height() / 2);
+
+ QPointF labelCenter = m_labelItem->boundingRect().center();
+ m_labelItem->setTransformOriginPoint(labelCenter);
+
+ if (m_data.m_labelPosition == QPieSlice::LabelInsideTangential) {
+ m_labelItem->setRotation(m_data.m_startAngle + m_data.m_angleSpan / 2);
+ } else if (m_data.m_labelPosition == QPieSlice::LabelInsideNormal) {
+ if (m_data.m_startAngle + m_data.m_angleSpan / 2 < 180)
+ m_labelItem->setRotation(m_data.m_startAngle + m_data.m_angleSpan / 2 - 90);
+ else
+ m_labelItem->setRotation(m_data.m_startAngle + m_data.m_angleSpan / 2 + 90);
+ } else {
+ m_labelItem->setRotation(0);
+ }
+ }
+ // Hide label if it's outside the bounding rect of parent item
+ QRectF labelRect(m_labelItem->boundingRect());
+ labelRect.moveTopLeft(m_labelItem->pos());
+ if ((parentItem()->boundingRect().left()
+ < (labelRect.left() + m_labelItem->document()->documentMargin() + 1.0))
+ && (parentItem()->boundingRect().right()
+ > (labelRect.right() - m_labelItem->document()->documentMargin() - 1.0))
+ && (parentItem()->boundingRect().top()
+ < (labelRect.top() + m_labelItem->document()->documentMargin() + 1.0))
+ && (parentItem()->boundingRect().bottom()
+ > (labelRect.bottom() - m_labelItem->document()->documentMargin() - 1.0)))
+ m_labelItem->show();
+ else
+ m_labelItem->hide();
+ }
+
+ // bounding rect
+ if (m_data.m_isLabelVisible)
+ m_boundingRect = m_slicePath.boundingRect().united(m_labelArmPath.boundingRect()).united(m_labelTextRect);
+ else
+ m_boundingRect = m_slicePath.boundingRect();
+
+ // Inflate bounding rect by 2/3 pen width to make sure it encompasses whole slice also for thick pens
+ // and miter joins.
+ int penWidth = (m_data.m_slicePen.width() * 2) / 3;
+ m_boundingRect = m_boundingRect.adjusted(-penWidth, -penWidth, penWidth, penWidth);
+}
+
+QPointF PieSliceItem::sliceCenter(QPointF point, qreal radius, QPieSlice *slice)
+{
+ if (slice->isExploded()) {
+ qreal centerAngle = slice->startAngle() + (slice->angleSpan() / 2);
+ qreal len = radius * slice->explodeDistanceFactor();
+ point += offset(centerAngle, len);
+ }
+ return point;
+}
+
+QPainterPath PieSliceItem::slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart)
+{
+ // calculate center angle
+ *centerAngle = startAngle + (angleSpan / 2);
+
+ // calculate slice rectangle
+ QRectF rect(center.x() - radius, center.y() - radius, radius * 2, radius * 2);
+
+ // slice path
+ QPainterPath path;
+ if (m_data.m_holeRadius > 0) {
+ QRectF insideRect(center.x() - m_data.m_holeRadius, center.y() - m_data.m_holeRadius, m_data.m_holeRadius * 2, m_data.m_holeRadius * 2);
+ path.arcMoveTo(rect, -startAngle + 90);
+ path.arcTo(rect, -startAngle + 90, -angleSpan);
+ path.arcTo(insideRect, -startAngle + 90 - angleSpan, angleSpan);
+ path.closeSubpath();
+ } else {
+ path.moveTo(rect.center());
+ path.arcTo(rect, -startAngle + 90, -angleSpan);
+ path.closeSubpath();
+ }
+
+ // calculate label arm start point
+ *armStart = center;
+ *armStart += offset(*centerAngle, radius + PIESLICE_LABEL_GAP);
+
+ return path;
+}
+
+QPainterPath PieSliceItem::labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart)
+{
+ // Normalize the angle to 0-360 range
+ // NOTE: We are using int here on purpose. Depenging on platform and hardware
+ // qreal can be a double, float or something the user gives to the Qt configure
+ // (QT_COORD_TYPE). Compilers do not seem to support modulo for double or float
+ // but there are fmod() and fmodf() functions for that. So instead of some #ifdef
+ // that might break we just use int. Precision for this is just fine for our needs.
+ int normalized = angle * 10.0;
+ normalized = normalized % 3600;
+ if (normalized < 0)
+ normalized += 3600;
+ angle = (qreal) normalized / 10.0;
+
+ // prevent label arm pointing straight down because it will look bad
+ if (angle < 180 && angle > 170)
+ angle = 170;
+ if (angle > 180 && angle < 190)
+ angle = 190;
+
+ // line from slice to label
+ QPointF parm1 = start + offset(angle, length);
+
+ // line to underline the label
+ QPointF parm2 = parm1;
+ if (angle < 180) { // arm swings the other way on the left side
+ parm2 += QPointF(textWidth, 0);
+ *textStart = parm1;
+ } else {
+ parm2 += QPointF(-textWidth, 0);
+ *textStart = parm2;
+ }
+
+ QPainterPath path;
+ path.moveTo(start);
+ path.lineTo(parm1);
+ path.lineTo(parm2);
+
+ return path;
+}
+
+#include "moc_piesliceitem_p.cpp"
+
+QT_CHARTS_END_NAMESPACE
+
diff --git a/src/charts/piechart/piesliceitem_p.h b/src/charts/piechart/piesliceitem_p.h
new file mode 100644
index 00000000..d6b7768c
--- /dev/null
+++ b/src/charts/piechart/piesliceitem_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** 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 PIESLICEITEM_H
+#define PIESLICEITEM_H
+
+#include "qchartglobal.h"
+#include "charttheme_p.h"
+#include "qpieseries.h"
+#include "pieslicedata_p.h"
+#include <QGraphicsItem>
+#include <QRectF>
+#include <QColor>
+#include <QPen>
+
+#define PIESLICE_LABEL_GAP 5
+
+QT_CHARTS_BEGIN_NAMESPACE
+class PieChartItem;
+class PieSliceLabel;
+class QPieSlice;
+
+class PieSliceItem : public QGraphicsObject
+{
+ Q_OBJECT
+
+public:
+ PieSliceItem(QGraphicsItem *parent = 0);
+ ~PieSliceItem();
+
+ // from QGraphicsItem
+ QRectF boundingRect() const;
+ QPainterPath shape() const;
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+ void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+
+ void setLayout(const PieSliceData &sliceData);
+ static QPointF sliceCenter(QPointF point, qreal radius, QPieSlice *slice);
+
+Q_SIGNALS:
+ void clicked(Qt::MouseButtons buttons);
+ void hovered(bool state);
+
+private:
+ void updateGeometry();
+ QPainterPath slicePath(QPointF center, qreal radius, qreal startAngle, qreal angleSpan, qreal *centerAngle, QPointF *armStart);
+ QPainterPath labelArmPath(QPointF start, qreal angle, qreal length, qreal textWidth, QPointF *textStart);
+
+private:
+ PieSliceData m_data;
+ QRectF m_boundingRect;
+ QPainterPath m_slicePath;
+ QPainterPath m_labelArmPath;
+ QRectF m_labelTextRect;
+ bool m_hovered;
+ QGraphicsTextItem *m_labelItem;
+
+ friend class PieSliceAnimation;
+};
+
+QT_CHARTS_END_NAMESPACE
+
+#endif // PIESLICEITEM_H
diff --git a/src/charts/piechart/qhpiemodelmapper.cpp b/src/charts/piechart/qhpiemodelmapper.cpp
new file mode 100644
index 00000000..b1c7d84f
--- /dev/null
+++ b/src/charts/piechart/qhpiemodelmapper.cpp
@@ -0,0 +1,267 @@
+/****************************************************************************
+**
+** 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 "qhpiemodelmapper.h"
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+/*!
+ \class QHPieModelMapper
+ \inmodule Qt Charts
+ \brief Horizontal model mapper for pie 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 QPieSeries and QAbstractItemModel derived model object that keeps the consecutive pie slices data in rows.
+ It is possible to use both QAbstractItemModel and QPieSeries model API. QHPieModelMapper makes sure that Pie and the model are kept in sync.
+ \note Used model has to support adding/removing rows/columns and modifying the data of the cells.
+*/
+/*!
+ \qmltype HPieModelMapper
+ \instantiates QHPieModelMapper
+ \inqmlmodule QtCharts
+
+ \brief Horizontal model mapper for pie series.
+
+ HPieModelMapper allows you to use your own QAbstractItemModel derived model with data in rows as
+ a data source for a pie series. It is possible to use both QAbstractItemModel and PieSeries data
+ API to manipulate data. HPieModelMapper keeps the Pie and the model in sync.
+
+ The following QML example would create a pie series with four slices (assuming the model has
+ at least five columns). Each slice would contain a label from row 1 and a value from row 2.
+ \code
+ HPieModelMapper {
+ series: pieSeries
+ model: customModel
+ labelsRow: 1
+ valuesRow: 2
+ firstColumn: 1
+ columnCount: 4
+ }
+ \endcode
+*/
+
+/*!
+ \property QHPieModelMapper::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 PieSeries HPieModelMapper::series
+ Defines the PieSeries object that is used by the mapper. If you define the mapper element as a child for a
+ PieSeries, leave this property undefined. 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 QHPieModelMapper::model
+ \brief Defines the model that is used by the mapper.
+*/
+/*!
+ \qmlproperty SomeModel HPieModelMapper::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 QHPieModelMapper::valuesRow
+ \brief Defines which row of the model is kept in sync with the values of the pie's slices.
+
+ Default value is: -1 (invalid mapping)
+*/
+/*!
+ \qmlproperty int HPieModelMapper::valuesRow
+ Defines which row of the model is kept in sync with the values of the pie's slices. Default value is: -1 (invalid
+ mapping).
+*/
+
+/*!
+ \property QHPieModelMapper::labelsRow
+ \brief Defines which row of the model is kept in sync with the labels of the pie's slices.
+
+ Default value is: -1 (invalid mapping)
+*/
+/*!
+ \qmlproperty int HPieModelMapper::labelsRow
+ Defines which row of the model is kept in sync with the labels of the pie's slices
+ Default value is: -1 (invalid mapping)
+*/
+
+/*!
+ \property QHPieModelMapper::firstColumn
+ \brief Defines which column of the model contains the first slice value.
+
+ Minimal and default value is: 0
+*/
+/*!
+ \qmlproperty int HPieModelMapper::firstColumn
+ Defines which column of the model contains the first slice value.
+ The default value is 0.
+*/
+
+/*!
+ \property QHPieModelMapper::columnCount
+ \brief Defines the number of columns of the model that are mapped as the data for QPieSeries.
+
+ Minimal and default value is: -1 (count limited by the number of columns in the model)
+*/
+/*!
+ \qmlproperty int HPieModelMapper::columnCount
+ Defines the number of columns of the model that are mapped as the data for QPieSeries. The default value is
+ -1 (count limited by the number of columns in the model)
+*/
+
+/*!
+ \fn void QHPieModelMapper::seriesReplaced()
+ Emitted when the series to which mapper is connected to has changed.
+*/
+
+/*!
+ \fn void QHPieModelMapper::modelReplaced()
+ Emitted when the model to which mapper is connected to has changed.
+*/
+
+/*!
+ \fn void QHPieModelMapper::valuesRowChanged()
+ Emitted when the valuesRow has changed.
+*/
+
+/*!
+ \fn void QHPieModelMapper::labelsRowChanged()
+ Emitted when the labelsRow has changed.
+*/
+
+/*!
+ \fn void QHPieModelMapper::firstColumnChanged()
+ Emitted when the firstColumn has changed.
+*/
+
+/*!
+ \fn void QHPieModelMapper::columnCountChanged()
+ Emitted when the columnCount has changed.
+*/
+
+/*!
+ Constructs a mapper object which is a child of \a parent.
+*/
+QHPieModelMapper::QHPieModelMapper(QObject *parent) :
+ QPieModelMapper(parent)
+{
+ setOrientation(Qt::Horizontal);
+}
+
+QAbstractItemModel *QHPieModelMapper::model() const
+{
+ return QPieModelMapper::model();
+}
+
+void QHPieModelMapper::setModel(QAbstractItemModel *model)
+{
+ if (model != QPieModelMapper::model()) {
+ QPieModelMapper::setModel(model);
+ emit modelReplaced();
+ }
+}
+
+QPieSeries *QHPieModelMapper::series() const
+{
+ return QPieModelMapper::series();
+}
+
+void QHPieModelMapper::setSeries(QPieSeries *series)
+{
+ if (series != QPieModelMapper::series()) {
+ QPieModelMapper::setSeries(series);
+ emit seriesReplaced();
+ }
+}
+
+/*!
+ Returns which row of the model is kept in sync with the values of the pie's slices
+*/
+int QHPieModelMapper::valuesRow() const
+{
+ return valuesSection();
+}
+
+/*!
+ Sets the model row that is kept in sync with the pie slices values.
+ Parameter \a valuesRow specifies the row of the model.
+*/
+void QHPieModelMapper::setValuesRow(int valuesRow)
+{
+ if (valuesRow != valuesSection()) {
+ setValuesSection(valuesRow);
+ emit valuesRowChanged();
+ }
+}
+
+/*!
+ Returns which row of the model is kept in sync with the labels of the pie's slices
+*/
+int QHPieModelMapper::labelsRow() const
+{
+ return labelsSection();
+}
+
+/*!
+ Sets the model row that is kept in sync with the pie's slices labels.
+ Parameter \a labelsRow specifies the row of the model.
+*/
+void QHPieModelMapper::setLabelsRow(int labelsRow)
+{
+ if (labelsRow != labelsSection()) {
+ setLabelsSection(labelsRow);
+ emit labelsRowChanged();
+ }
+}
+
+int QHPieModelMapper::firstColumn() const
+{
+ return first();
+}
+
+void QHPieModelMapper::setFirstColumn(int firstColumn)
+{
+ if (firstColumn != first()) {
+ setFirst(firstColumn);
+ emit firstColumnChanged();
+ }
+}
+
+int QHPieModelMapper::columnCount() const
+{
+ return count();
+}
+
+void QHPieModelMapper::setColumnCount(int columnCount)
+{
+ if (columnCount != count()) {
+ setCount(columnCount);
+ emit columnCountChanged();
+ }
+}
+
+#include "moc_qhpiemodelmapper.cpp"
+
+QT_CHARTS_END_NAMESPACE
diff --git a/src/charts/piechart/qhpiemodelmapper.h b/src/charts/piechart/qhpiemodelmapper.h
new file mode 100644
index 00000000..50b5c6f2
--- /dev/null
+++ b/src/charts/piechart/qhpiemodelmapper.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 QHPIEMODELMAPPER_H
+#define QHPIEMODELMAPPER_H
+
+#include <QtCharts/qpiemodelmapper.h>
+
+QT_CHARTS_BEGIN_NAMESPACE
+/* Comment line for syncqt to generate the fwd-include correctly, due to QTBUG-22432 */
+class QT_CHARTS_EXPORT QHPieModelMapper : public QPieModelMapper
+{
+ Q_OBJECT
+ Q_PROPERTY(QPieSeries *series READ series WRITE setSeries NOTIFY seriesReplaced)
+ Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelReplaced)
+ Q_PROPERTY(int valuesRow READ valuesRow WRITE setValuesRow NOTIFY valuesRowChanged)
+ Q_PROPERTY(int labelsRow READ labelsRow WRITE setLabelsRow NOTIFY labelsRowChanged)
+ Q_PROPERTY(int firstColumn READ firstColumn WRITE setFirstColumn NOTIFY firstColumnChanged)
+ Q_PROPERTY(int columnCount READ columnCount WRITE setColumnCount NOTIFY columnCountChanged)
+
+public:
+ explicit QHPieModelMapper(QObject *parent = 0);
+
+ QAbstractItemModel *model() const;
+ void setModel(QAbstractItemModel *model);
+
+ QPieSeries *series() const;
+ void setSeries(QPieSeries *series);
+
+ int valuesRow() const;
+ void setValuesRow(int valuesRow);
+
+ int labelsRow() const;
+ void setLabelsRow(int labelsRow);
+
+ int firstColumn() const;
+ void setFirstColumn(int firstColumn);
+
+ int columnCount() const;
+ void setColumnCount(int columnCount);
+
+Q_SIGNALS:
+ void seriesReplaced();
+ void modelReplaced();
+ void valuesRowChanged();
+ void labelsRowChanged();
+ void firstColumnChanged();
+ void columnCountChanged();
+};
+
+QT_CHARTS_END_NAMESPACE
+
+#endif // QHPIEMODELMAPPER_H
diff --git a/src/charts/piechart/qpiemodelmapper.cpp b/src/charts/piechart/qpiemodelmapper.cpp
new file mode 100644
index 00000000..186be815
--- /dev/null
+++ b/src/charts/piechart/qpiemodelmapper.cpp
@@ -0,0 +1,568 @@
+/****************************************************************************
+**
+** 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 "qpiemodelmapper.h"
+#include "qpiemodelmapper_p.h"
+#include "qpieseries.h"
+#include "qpieslice.h"
+#include <QAbstractItemModel>
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+QPieModelMapper::QPieModelMapper(QObject *parent)
+ : QObject(parent),
+ d_ptr(new QPieModelMapperPrivate(this))
+{
+}
+
+QAbstractItemModel *QPieModelMapper::model() const
+{
+ Q_D(const QPieModelMapper);
+ return d->m_model;
+}
+
+void QPieModelMapper::setModel(QAbstractItemModel *model)
+{
+ if (model == 0)
+ return;
+
+ Q_D(QPieModelMapper);
+ if (d->m_model) {
+ disconnect(d->m_model, 0, d, 0);
+ }
+
+ d->m_model = model;
+ d->initializePieFromModel();
+ // connect signals from the model
+ connect(d->m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), d, SLOT(modelUpdated(QModelIndex,QModelIndex)));
+ 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()));
+}
+
+QPieSeries *QPieModelMapper::series() const
+{
+ Q_D(const QPieModelMapper);
+ return d->m_series;
+}
+
+void QPieModelMapper::setSeries(QPieSeries *series)
+{
+ Q_D(QPieModelMapper);
+ if (d->m_series) {
+ disconnect(d->m_series, 0, d, 0);
+ }
+
+ if (series == 0)
+ return;
+
+ d->m_series = series;
+ d->initializePieFromModel();
+ // connect the signals from the series
+ connect(d->m_series, SIGNAL(added(QList<QPieSlice*>)), d, SLOT(slicesAdded(QList<QPieSlice*>)));
+ connect(d->m_series, SIGNAL(removed(QList<QPieSlice*>)), d, SLOT(slicesRemoved(QList<QPieSlice*>)));
+ connect(d->m_series, SIGNAL(destroyed()), d, SLOT(handleSeriesDestroyed()));
+}
+
+/*!
+ Defines which row/column of the model contains the first slice value.
+ Minimal and default value is: 0
+*/
+int QPieModelMapper::first() const
+{
+ Q_D(const QPieModelMapper);
+ return d->m_first;
+}
+
+/*!
+ Sets which row/column of the model contains the \a first slice value.
+ Minimal and default value is: 0
+*/
+void QPieModelMapper::setFirst(int first)
+{
+ Q_D(QPieModelMapper);
+ d->m_first = qMax(first, 0);
+ d->initializePieFromModel();
+}
+
+/*!
+ Defines the number of rows/columns of the model that are mapped as the data for QPieSeries
+ Minimal and default value is: -1 (count limited by the number of rows/columns in the model)
+*/
+int QPieModelMapper::count() const
+{
+ Q_D(const QPieModelMapper);
+ return d->m_count;
+}
+
+/*!
+ Defines the \a count of rows/columns of the model that are mapped as the data for QPieSeries
+ Minimal and default value is: -1 (count limited by the number of rows/columns in the model)
+*/
+void QPieModelMapper::setCount(int count)
+{
+ Q_D(QPieModelMapper);
+ d->m_count = qMax(count, -1);
+ d->initializePieFromModel();
+}
+
+/*!
+ Returns the orientation that is used when QPieModelMapper accesses the model.
+ This mean whether the consecutive values/labels of the pie are read from row (Qt::Horizontal)
+ or from columns (Qt::Vertical)
+*/
+Qt::Orientation QPieModelMapper::orientation() const
+{
+ Q_D(const QPieModelMapper);
+ return d->m_orientation;
+}
+
+/*!
+ Returns the \a orientation that is used when QPieModelMapper accesses the model.
+ This mean whether the consecutive values/labels of the pie are read from row (Qt::Horizontal)
+ or from columns (Qt::Vertical)
+*/
+void QPieModelMapper::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QPieModelMapper);
+ d->m_orientation = orientation;
+ d->initializePieFromModel();
+}
+
+/*!
+ Returns which section of the model is kept in sync with the values of the pie's slices
+*/
+int QPieModelMapper::valuesSection() const
+{
+ Q_D(const QPieModelMapper);
+ return d->m_valuesSection;
+}
+
+/*!
+ Sets the model section that is kept in sync with the pie slices values.
+ Parameter \a valuesSection specifies the section of the model.
+*/
+void QPieModelMapper::setValuesSection(int valuesSection)
+{
+ Q_D(QPieModelMapper);
+ d->m_valuesSection = qMax(-1, valuesSection);
+ d->initializePieFromModel();
+}
+
+/*!
+ Returns which section of the model is kept in sync with the labels of the pie's slices
+*/
+int QPieModelMapper::labelsSection() const
+{
+ Q_D(const QPieModelMapper);
+ return d->m_labelsSection;
+}
+
+/*!
+ Sets the model section that is kept in sync with the pie slices labels.
+ Parameter \a labelsSection specifies the section of the model.
+*/
+void QPieModelMapper::setLabelsSection(int labelsSection)
+{
+ Q_D(QPieModelMapper);
+ d->m_labelsSection = qMax(-1, labelsSection);
+ d->initializePieFromModel();
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+QPieModelMapperPrivate::QPieModelMapperPrivate(QPieModelMapper *q) :
+ QObject(q),
+ m_series(0),
+ m_model(0),
+ m_first(0),
+ m_count(-1),
+ m_orientation(Qt::Vertical),
+ m_valuesSection(-1),
+ m_labelsSection(-1),
+ m_seriesSignalsBlock(false),
+ m_modelSignalsBlock(false),
+ q_ptr(q)
+{
+}
+
+void QPieModelMapperPrivate::blockModelSignals(bool block)
+{
+ m_modelSignalsBlock = block;
+}
+
+void QPieModelMapperPrivate::blockSeriesSignals(bool block)
+{
+ m_seriesSignalsBlock = block;
+}
+
+
+QPieSlice *QPieModelMapperPrivate::pieSlice(QModelIndex index) const
+{
+ if (!index.isValid())
+ return 0; // index is invalid
+
+ if (m_orientation == Qt::Vertical && (index.column() == m_valuesSection || index.column() == m_labelsSection)) {
+ if (index.row() >= m_first && (m_count == - 1 || index.row() < m_first + m_count)) {
+ if (m_model->index(index.row(), m_valuesSection).isValid() && m_model->index(index.row(), m_labelsSection).isValid())
+ return m_series->slices().at(index.row() - m_first);
+ else
+ return 0;
+ }
+ } else if (m_orientation == Qt::Horizontal && (index.row() == m_valuesSection || index.row() == m_labelsSection)) {
+ if (index.column() >= m_first && (m_count == - 1 || index.column() < m_first + m_count)) {
+ if (m_model->index(m_valuesSection, index.column()).isValid() && m_model->index(m_labelsSection, index.column()).isValid())
+ return m_series->slices().at(index.column() - m_first);
+ else
+ return 0;
+ }
+ }
+ return 0; // This part of model has not been mapped to any slice
+}
+
+QModelIndex QPieModelMapperPrivate::valueModelIndex(int slicePos)
+{
+ if (m_count != -1 && slicePos >= m_count)
+ return QModelIndex(); // invalid
+
+ if (m_orientation == Qt::Vertical)
+ return m_model->index(slicePos + m_first, m_valuesSection);
+ else
+ return m_model->index(m_valuesSection, slicePos + m_first);
+}
+
+QModelIndex QPieModelMapperPrivate::labelModelIndex(int slicePos)
+{
+ if (m_count != -1 && slicePos >= m_count)
+ return QModelIndex(); // invalid
+
+ if (m_orientation == Qt::Vertical)
+ return m_model->index(slicePos + m_first, m_labelsSection);
+ else
+ return m_model->index(m_labelsSection, slicePos + m_first);
+}
+
+bool QPieModelMapperPrivate::isLabelIndex(QModelIndex index) const
+{
+ if (m_orientation == Qt::Vertical && index.column() == m_labelsSection)
+ return true;
+ else if (m_orientation == Qt::Horizontal && index.row() == m_labelsSection)
+ return true;
+
+ return false;
+}
+
+bool QPieModelMapperPrivate::isValueIndex(QModelIndex index) const
+{
+ if (m_orientation == Qt::Vertical && index.column() == m_valuesSection)
+ return true;
+ else if (m_orientation == Qt::Horizontal && index.row() == m_valuesSection)
+ return true;
+
+ return false;
+}
+
+void QPieModelMapperPrivate::slicesAdded(QList<QPieSlice *> slices)
+{
+ if (m_seriesSignalsBlock)
+ return;
+
+ if (slices.count() == 0)
+ return;
+
+ int firstIndex = m_series->slices().indexOf(slices.at(0));
+ if (firstIndex == -1)
+ return;
+
+ if (m_count != -1)
+ m_count += slices.count();
+
+ for (int i = firstIndex; i < firstIndex + slices.count(); i++) {
+ m_slices.insert(i, slices.at(i - firstIndex));
+ connect(slices.at(i - firstIndex), SIGNAL(labelChanged()), this, SLOT(sliceLabelChanged()));
+ connect(slices.at(i - firstIndex), SIGNAL(valueChanged()), this, SLOT(sliceValueChanged()));
+ }
+
+ blockModelSignals();
+ if (m_orientation == Qt::Vertical)
+ m_model->insertRows(firstIndex + m_first, slices.count());
+ else
+ m_model->insertColumns(firstIndex + m_first, slices.count());
+
+ for (int i = firstIndex; i < firstIndex + slices.count(); i++) {
+ m_model->setData(valueModelIndex(i), slices.at(i - firstIndex)->value());
+ m_model->setData(labelModelIndex(i), slices.at(i - firstIndex)->label());
+ }
+ blockModelSignals(false);
+}
+
+void QPieModelMapperPrivate::slicesRemoved(QList<QPieSlice *> slices)
+{
+ if (m_seriesSignalsBlock)
+ return;
+
+ if (slices.count() == 0)
+ return;
+
+ int firstIndex = m_slices.indexOf(slices.at(0));
+ if (firstIndex == -1)
+ return;
+
+ if (m_count != -1)
+ m_count -= slices.count();
+
+ for (int i = firstIndex + slices.count() - 1; i >= firstIndex; i--)
+ m_slices.removeAt(i);
+
+ blockModelSignals();
+ if (m_orientation == Qt::Vertical)
+ m_model->removeRows(firstIndex + m_first, slices.count());
+ else
+ m_model->removeColumns(firstIndex + m_first, slices.count());
+ blockModelSignals(false);
+}
+
+void QPieModelMapperPrivate::sliceLabelChanged()
+{
+ if (m_seriesSignalsBlock)
+ return;
+
+ blockModelSignals();
+ QPieSlice *slice = qobject_cast<QPieSlice *>(QObject::sender());
+ m_model->setData(labelModelIndex(m_series->slices().indexOf(slice)), slice->label());
+ blockModelSignals(false);
+}
+
+void QPieModelMapperPrivate::sliceValueChanged()
+{
+ if (m_seriesSignalsBlock)
+ return;
+
+ blockModelSignals();
+ QPieSlice *slice = qobject_cast<QPieSlice *>(QObject::sender());
+ m_model->setData(valueModelIndex(m_series->slices().indexOf(slice)), slice->value());
+ blockModelSignals(false);
+}
+
+void QPieModelMapperPrivate::handleSeriesDestroyed()
+{
+ m_series = 0;
+}
+
+void QPieModelMapperPrivate::modelUpdated(QModelIndex topLeft, QModelIndex bottomRight)
+{
+ if (m_model == 0 || m_series == 0)
+ return;
+
+ if (m_modelSignalsBlock)
+ return;
+
+ blockSeriesSignals();
+ QModelIndex index;
+ QPieSlice *slice;
+ for (int row = topLeft.row(); row <= bottomRight.row(); row++) {
+ for (int column = topLeft.column(); column <= bottomRight.column(); column++) {
+ index = topLeft.sibling(row, column);
+ slice = pieSlice(index);
+ if (slice) {
+ if (isValueIndex(index))
+ slice->setValue(m_model->data(index, Qt::DisplayRole).toReal());
+ if (isLabelIndex(index))
+ slice->setLabel(m_model->data(index, Qt::DisplayRole).toString());
+ }
+ }
+ }
+ blockSeriesSignals(false);
+}
+
+
+void QPieModelMapperPrivate::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_valuesSection || start <= m_labelsSection) // if the changes affect the map - reinitialize the pie
+ initializePieFromModel();
+ blockSeriesSignals(false);
+}
+
+void QPieModelMapperPrivate::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_valuesSection || start <= m_labelsSection) // if the changes affect the map - reinitialize the pie
+ initializePieFromModel();
+ blockSeriesSignals(false);
+}
+
+void QPieModelMapperPrivate::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_valuesSection || start <= m_labelsSection) // if the changes affect the map - reinitialize the pie
+ initializePieFromModel();
+ blockSeriesSignals(false);
+}
+
+void QPieModelMapperPrivate::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_valuesSection || start <= m_labelsSection) // if the changes affect the map - reinitialize the pie
+ initializePieFromModel();
+ blockSeriesSignals(false);
+}
+
+void QPieModelMapperPrivate::handleModelDestroyed()
+{
+ m_model = 0;
+}
+
+void QPieModelMapperPrivate::insertData(int start, int end)
+{
+ if (m_model == 0 || m_series == 0)
+ return;
+
+ if (m_count != -1 && start >= m_first + m_count) {
+ return;
+ } else {
+ int addedCount = end - start + 1;
+ if (m_count != -1 && addedCount > m_count)
+ addedCount = m_count;
+ int first = qMax(start, m_first);
+ int last = qMin(first + addedCount - 1, m_orientation == Qt::Vertical ? m_model->rowCount() - 1 : m_model->columnCount() - 1);
+ for (int i = first; i <= last; i++) {
+ QModelIndex valueIndex = valueModelIndex(i - m_first);
+ QModelIndex labelIndex = labelModelIndex(i - m_first);
+ if (valueIndex.isValid() && labelIndex.isValid()) {
+ QPieSlice *slice = new QPieSlice;
+ slice->setValue(m_model->data(valueIndex, Qt::DisplayRole).toDouble());
+ slice->setLabel(m_model->data(labelIndex, Qt::DisplayRole).toString());
+ connect(slice, SIGNAL(labelChanged()), this, SLOT(sliceLabelChanged()));
+ connect(slice, SIGNAL(valueChanged()), this, SLOT(sliceValueChanged()));
+ m_series->insert(i - m_first, slice);
+ m_slices.insert(i - m_first, slice);
+ }
+ }
+
+ // remove excess of slices (abouve m_count)
+ if (m_count != -1 && m_series->slices().size() > m_count)
+ for (int i = m_series->slices().size() - 1; i >= m_count; i--) {
+ m_series->remove(m_series->slices().at(i));
+ m_slices.removeAt(i);
+ }
+ }
+}
+
+void QPieModelMapperPrivate::removeData(int start, int end)
+{
+ if (m_model == 0 || m_series == 0)
+ return;
+
+ int removedCount = end - start + 1;
+ if (m_count != -1 && start >= m_first + m_count) {
+ return;
+ } else {
+ int toRemove = qMin(m_series->slices().size(), removedCount); // first find how many items can actually be removed
+ int first = qMax(start, m_first); // get the index of the first item that will be removed.
+ int last = qMin(first + toRemove - 1, m_series->slices().size() + m_first - 1); // get the index of the last item that will be removed.
+ for (int i = last; i >= first; i--) {
+ m_series->remove(m_series->slices().at(i - m_first));
+ m_slices.removeAt(i - m_first);
+ }
+
+ if (m_count != -1) {
+ int itemsAvailable; // check how many are available to be added
+ if (m_orientation == Qt::Vertical)
+ itemsAvailable = m_model->rowCount() - m_first - m_series->slices().size();
+ else
+ itemsAvailable = m_model->columnCount() - m_first - m_series->slices().size();
+ int toBeAdded = qMin(itemsAvailable, m_count - m_series->slices().size()); // add not more items than there is space left to be filled.
+ int currentSize = m_series->slices().size();
+ if (toBeAdded > 0)
+ for (int i = m_series->slices().size(); i < currentSize + toBeAdded; i++) {
+ QModelIndex valueIndex = valueModelIndex(i - m_first);
+ QModelIndex labelIndex = labelModelIndex(i - m_first);
+ if (valueIndex.isValid() && labelIndex.isValid()) {
+ QPieSlice *slice = new QPieSlice;
+ slice->setValue(m_model->data(valueIndex, Qt::DisplayRole).toDouble());
+ slice->setLabel(m_model->data(labelIndex, Qt::DisplayRole).toString());
+ m_series->insert(i, slice);
+ m_slices.insert(i, slice);
+ }
+ }
+ }
+ }
+}
+
+void QPieModelMapperPrivate::initializePieFromModel()
+{
+ if (m_model == 0 || m_series == 0)
+ return;
+
+ blockSeriesSignals();
+ // clear current content
+ m_series->clear();
+ m_slices.clear();
+
+ // create the initial slices set
+ int slicePos = 0;
+ QModelIndex valueIndex = valueModelIndex(slicePos);
+ QModelIndex labelIndex = labelModelIndex(slicePos);
+ while (valueIndex.isValid() && labelIndex.isValid()) {
+ QPieSlice *slice = new QPieSlice;
+ slice->setLabel(m_model->data(labelIndex, Qt::DisplayRole).toString());
+ slice->setValue(m_model->data(valueIndex, Qt::DisplayRole).toDouble());
+ connect(slice, SIGNAL(labelChanged()), this, SLOT(sliceLabelChanged()));
+ connect(slice, SIGNAL(valueChanged()), this, SLOT(sliceValueChanged()));
+ m_series->append(slice);
+ m_slices.append(slice);
+ slicePos++;
+ valueIndex = valueModelIndex(slicePos);
+ labelIndex = labelModelIndex(slicePos);
+ }
+ blockSeriesSignals(false);
+}
+
+#include "moc_qpiemodelmapper_p.cpp"
+#include "moc_qpiemodelmapper.cpp"
+
+QT_CHARTS_END_NAMESPACE
diff --git a/src/charts/piechart/qpiemodelmapper.h b/src/charts/piechart/qpiemodelmapper.h
new file mode 100644
index 00000000..a4ab6a2c
--- /dev/null
+++ b/src/charts/piechart/qpiemodelmapper.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 QPIEMODELMAPPER_H
+#define QPIEMODELMAPPER_H
+
+#include <QtCharts/qchartglobal.h>
+#include <QObject>
+
+class QAbstractItemModel;
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+class QPieModelMapperPrivate;
+class QPieSeries;
+
+class QT_CHARTS_EXPORT QPieModelMapper : public QObject
+{
+ Q_OBJECT
+
+protected:
+ explicit QPieModelMapper(QObject *parent = 0);
+
+ QAbstractItemModel *model() const;
+ void setModel(QAbstractItemModel *model);
+
+ QPieSeries *series() const;
+ void setSeries(QPieSeries *series);
+
+ int first() const;
+ void setFirst(int first);
+
+ int count() const;
+ void setCount(int count);
+
+ int valuesSection() const;
+ void setValuesSection(int valuesSection);
+
+ int labelsSection() const;
+ void setLabelsSection(int labelsSection);
+
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation orientation);
+
+protected:
+ QPieModelMapperPrivate * const d_ptr;
+ Q_DECLARE_PRIVATE(QPieModelMapper)
+};
+
+QT_CHARTS_END_NAMESPACE
+
+#endif // QPIEMODELMAPPER_H
diff --git a/src/charts/piechart/qpiemodelmapper_p.h b/src/charts/piechart/qpiemodelmapper_p.h
new file mode 100644
index 00000000..a287497f
--- /dev/null
+++ b/src/charts/piechart/qpiemodelmapper_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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 QPIEMODELMAPPER_P_H
+#define QPIEMODELMAPPER_P_H
+
+#include <QObject>
+#include <qpiemodelmapper.h>
+
+class QModelIndex;
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+class QPieSlice;
+
+class QPieModelMapperPrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QPieModelMapperPrivate(QPieModelMapper *q);
+
+public Q_SLOTS:
+ // for the model
+ void modelUpdated(QModelIndex topLeft, QModelIndex bottomRight);
+ 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 slicesAdded(QList<QPieSlice *> slices);
+ void slicesRemoved(QList<QPieSlice *> slices);
+ void sliceLabelChanged();
+ void sliceValueChanged();
+ void handleSeriesDestroyed();
+
+ void initializePieFromModel();
+
+private:
+ QPieSlice *pieSlice(QModelIndex index) const;
+ bool isLabelIndex(QModelIndex index) const;
+ bool isValueIndex(QModelIndex index) const;
+ QModelIndex valueModelIndex(int slicePos);
+ QModelIndex labelModelIndex(int slicePos);
+ void insertData(int start, int end);
+ void removeData(int start, int end);
+
+ void blockModelSignals(bool block = true);
+ void blockSeriesSignals(bool block = true);
+
+private:
+ QPieSeries *m_series;
+ QList<QPieSlice *> m_slices;
+ QAbstractItemModel *m_model;
+ int m_first;
+ int m_count;
+ Qt::Orientation m_orientation;
+ int m_valuesSection;
+ int m_labelsSection;
+ bool m_seriesSignalsBlock;
+ bool m_modelSignalsBlock;
+
+private:
+
+ QPieModelMapper *q_ptr;
+ Q_DECLARE_PUBLIC(QPieModelMapper)
+};
+
+QT_CHARTS_END_NAMESPACE
+
+#endif // QPIEMODELMAPPER_P_H
diff --git a/src/charts/piechart/qpieseries.cpp b/src/charts/piechart/qpieseries.cpp
new file mode 100644
index 00000000..733429d1
--- /dev/null
+++ b/src/charts/piechart/qpieseries.cpp
@@ -0,0 +1,947 @@
+/****************************************************************************
+**
+** 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 "qpieseries.h"
+#include "qpieseries_p.h"
+#include "qpieslice.h"
+#include "qpieslice_p.h"
+#include "pieslicedata_p.h"
+#include "chartdataset_p.h"
+#include "charttheme_p.h"
+#include "qabstractaxis.h"
+#include "pieanimation_p.h"
+#include "charthelpers_p.h"
+
+#include "qpielegendmarker.h"
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+/*!
+ \class QPieSeries
+ \inmodule Qt Charts
+ \brief Pie series API for Qt Charts.
+
+ The pie series defines a pie chart which consists of pie slices which are defined as QPieSlice objects.
+ The slices can have any values as the QPieSeries will calculate its relative value to the sum of all slices.
+ The actual slice size is determined by that relative value.
+
+ Pie size and position on the chart is controlled by using relative values which range from 0.0 to 1.0.
+ These relate to the actual chart rectangle.
+
+ By default the pie is defined as a full pie but it can also be a partial pie.
+ This can be done by setting a starting angle and angle span to the series.
+ Full pie is 360 degrees where 0 is at 12 a'clock.
+
+ See the \l {PieChart Example} {pie chart example} or \l {DonutChart Example} {donut chart example} to learn how to use QPieSeries.
+ \table 100%
+ \row
+ \li \image examples_piechart.png
+ \li \image examples_donutchart.png
+ \endtable
+*/
+/*!
+ \qmltype PieSeries
+ \instantiates QPieSeries
+ \inqmlmodule QtCharts
+
+ \inherits AbstractSeries
+
+ \brief The PieSeries type is used for making pie charts.
+
+ The following QML shows how to create a simple pie chart.
+
+ \snippet qmlchart/qml/qmlchart/View1.qml 1
+
+ \beginfloatleft
+ \image examples_qmlchart1.png
+ \endfloat
+ \clearfloat
+*/
+
+/*!
+ \property QPieSeries::horizontalPosition
+ \brief Defines the horizontal position of the pie.
+
+ The value is a relative value to the chart rectangle where:
+
+ \list
+ \li 0.0 is the absolute left.
+ \li 1.0 is the absolute right.
+ \endlist
+ Default value is 0.5 (center).
+ \sa verticalPosition
+*/
+
+/*!
+ \qmlproperty real PieSeries::horizontalPosition
+
+ Defines the horizontal position of the pie.
+
+ The value is a relative value to the chart rectangle where:
+
+ \list
+ \li 0.0 is the absolute left.
+ \li 1.0 is the absolute right.
+ \endlist
+ Default value is 0.5 (center).
+ \sa verticalPosition
+*/
+
+/*!
+ \property QPieSeries::verticalPosition
+ \brief Defines the vertical position of the pie.
+
+ The value is a relative value to the chart rectangle where:
+
+ \list
+ \li 0.0 is the absolute top.
+ \li 1.0 is the absolute bottom.
+ \endlist
+ Default value is 0.5 (center).
+ \sa horizontalPosition
+*/
+
+/*!
+ \qmlproperty real PieSeries::verticalPosition
+
+ Defines the vertical position of the pie.
+
+ The value is a relative value to the chart rectangle where:
+
+ \list
+ \li 0.0 is the absolute top.
+ \li 1.0 is the absolute bottom.
+ \endlist
+ Default value is 0.5 (center).
+ \sa horizontalPosition
+*/
+
+/*!
+ \property QPieSeries::size
+ \brief Defines the pie size.
+
+ The value is a relative value to the chart rectangle where:
+
+ \list
+ \li 0.0 is the minimum size (pie not drawn).
+ \li 1.0 is the maximum size that can fit the chart.
+ \endlist
+
+ When setting this property the holeSize property is adjusted if necessary, to ensure that the hole size is not greater than the outer size.
+
+ Default value is 0.7.
+*/
+
+/*!
+ \qmlproperty real PieSeries::size
+
+ Defines the pie size.
+
+ The value is a relative value to the chart rectangle where:
+
+ \list
+ \li 0.0 is the minimum size (pie not drawn).
+ \li 1.0 is the maximum size that can fit the chart.
+ \endlist
+
+ Default value is 0.7.
+*/
+
+/*!
+ \property QPieSeries::holeSize
+ \brief Defines the donut hole size.
+
+ The value is a relative value to the chart rectangle where:
+
+ \list
+ \li 0.0 is the minimum size (full pie drawn, without any hole inside).
+ \li 1.0 is the maximum size that can fit the chart. (donut has no width)
+ \endlist
+
+ The value is never greater then size property.
+ Default value is 0.0.
+*/
+
+/*!
+ \qmlproperty real PieSeries::holeSize
+
+ Defines the donut hole size.
+
+ The value is a relative value to the chart rectangle where:
+
+ \list
+ \li 0.0 is the minimum size (full pie drawn, without any hole inside).
+ \li 1.0 is the maximum size that can fit the chart. (donut has no width)
+ \endlist
+
+ When setting this property the size property is adjusted if necessary, to ensure that the inner size is not greater than the outer size.
+
+ Default value is 0.0.
+*/
+
+/*!
+ \property QPieSeries::startAngle
+ \brief Defines the starting angle of the pie.
+
+ Full pie is 360 degrees where 0 degrees is at 12 a'clock.
+
+ Default is value is 0.
+*/
+
+/*!
+ \qmlproperty real PieSeries::startAngle
+
+ Defines the starting angle of the pie.
+
+ Full pie is 360 degrees where 0 degrees is at 12 a'clock.
+
+ Default is value is 0.
+*/
+
+/*!
+ \property QPieSeries::endAngle
+ \brief Defines the ending angle of the pie.
+
+ Full pie is 360 degrees where 0 degrees is at 12 a'clock.
+
+ Default is value is 360.
+*/
+
+/*!
+ \qmlproperty real PieSeries::endAngle
+
+ Defines the ending angle of the pie.
+
+ Full pie is 360 degrees where 0 degrees is at 12 a'clock.
+
+ Default is value is 360.
+*/
+
+/*!
+ \property QPieSeries::count
+
+ Number of slices in the series.
+*/
+
+/*!
+ \qmlproperty int PieSeries::count
+
+ Number of slices in the series.
+*/
+
+/*!
+ \fn void QPieSeries::countChanged()
+ Emitted when the slice count has changed.
+ \sa count
+*/
+/*!
+ \qmlsignal PieSeries::onCountChanged()
+ Emitted when the slice count has changed.
+*/
+
+/*!
+ \property QPieSeries::sum
+
+ Sum of all slices.
+
+ The series keeps track of the sum of all slices it holds.
+*/
+
+/*!
+ \qmlproperty real PieSeries::sum
+
+ Sum of all slices.
+
+ The series keeps track of the sum of all slices it holds.
+*/
+
+/*!
+ \fn void QPieSeries::sumChanged()
+ Emitted when the sum of all slices has changed.
+ \sa sum
+*/
+/*!
+ \qmlsignal PieSeries::onSumChanged()
+ Emitted when the sum of all slices has changed. This may happen for example if you add or remove slices, or if you
+ change value of a slice.
+*/
+
+/*!
+ \fn void QPieSeries::added(QList<QPieSlice*> slices)
+
+ This signal is emitted when \a slices have been added to the series.
+
+ \sa append(), insert()
+*/
+/*!
+ \qmlsignal PieSeries::onAdded(PieSlice slice)
+ Emitted when \a slice has been added to the series.
+*/
+
+/*!
+ \fn void QPieSeries::removed(QList<QPieSlice*> slices)
+ This signal is emitted when \a slices have been removed from the series.
+ \sa remove()
+*/
+/*!
+ \qmlsignal PieSeries::onRemoved(PieSlice slice)
+ Emitted when \a slice has been removed from the series.
+*/
+
+/*!
+ \fn void QPieSeries::clicked(QPieSlice* slice)
+ This signal is emitted when a \a slice has been clicked.
+ \sa QPieSlice::clicked()
+*/
+/*!
+ \qmlsignal PieSeries::onClicked(PieSlice slice)
+ This signal is emitted when a \a slice has been clicked.
+*/
+
+/*!
+ \fn void QPieSeries::hovered(QPieSlice* slice, bool state)
+ This signal is emitted when user has hovered over or away from the \a slice.
+ \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
+ \sa QPieSlice::hovered()
+*/
+/*!
+ \qmlsignal PieSeries::onHovered(PieSlice slice, bool state)
+ This signal is emitted when user has hovered over or away from the \a slice. \a state is true when user has hovered
+ over the slice and false when hover has moved away from the slice.
+*/
+
+/*!
+ \qmlmethod PieSlice PieSeries::at(int index)
+ Returns slice at \a index. Returns null if the index is not valid.
+*/
+
+/*!
+ \qmlmethod PieSlice PieSeries::find(string label)
+ Returns the first slice with \a label. Returns null if the index is not valid.
+*/
+
+/*!
+ \qmlmethod PieSlice PieSeries::append(string label, real value)
+ Adds a new slice with \a label and \a value to the pie.
+*/
+
+/*!
+ \qmlmethod bool PieSeries::remove(PieSlice slice)
+ Removes the \a slice from the pie. Returns true if the removal was successful, false otherwise.
+*/
+
+/*!
+ \qmlmethod PieSeries::clear()
+ Removes all slices from the pie.
+*/
+
+/*!
+ Constructs a series object which is a child of \a parent.
+*/
+QPieSeries::QPieSeries(QObject *parent)
+ : QAbstractSeries(*new QPieSeriesPrivate(this), parent)
+{
+ Q_D(QPieSeries);
+ QObject::connect(this, SIGNAL(countChanged()), d, SIGNAL(countChanged()));
+}
+
+/*!
+ Destroys the series and its slices.
+*/
+QPieSeries::~QPieSeries()
+{
+ // NOTE: d_prt destroyed by QObject
+ clear();
+}
+
+/*!
+ Returns QAbstractSeries::SeriesTypePie.
+*/
+QAbstractSeries::SeriesType QPieSeries::type() const
+{
+ return QAbstractSeries::SeriesTypePie;
+}
+
+/*!
+ Appends a single \a slice to the series.
+ Slice ownership is passed to the series.
+
+ Returns true if append was succesfull.
+*/
+bool QPieSeries::append(QPieSlice *slice)
+{
+ return append(QList<QPieSlice *>() << slice);
+}
+
+/*!
+ Appends an array of \a slices to the series.
+ Slice ownership is passed to the series.
+
+ Returns true if append was successful.
+*/
+bool QPieSeries::append(QList<QPieSlice *> slices)
+{
+ Q_D(QPieSeries);
+
+ if (slices.count() == 0)
+ return false;
+
+ foreach (QPieSlice *s, slices) {
+ if (!s || d->m_slices.contains(s))
+ return false;
+ if (s->series()) // already added to some series
+ return false;
+ if (!isValidValue(s->value()))
+ return false;
+ }
+
+ foreach (QPieSlice *s, slices) {
+ s->setParent(this);
+ QPieSlicePrivate::fromSlice(s)->m_series = this;
+ d->m_slices << s;
+ }
+
+ d->updateDerivativeData();
+
+ foreach(QPieSlice * s, slices) {
+ connect(s, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
+ connect(s, SIGNAL(clicked()), d, SLOT(sliceClicked()));
+ connect(s, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
+ }
+
+ emit added(slices);
+ emit countChanged();
+
+ return true;
+}
+
+/*!
+ Appends a single \a slice to the series and returns a reference to the series.
+ Slice ownership is passed to the series.
+*/
+QPieSeries &QPieSeries::operator << (QPieSlice *slice)
+{
+ append(slice);
+ return *this;
+}
+
+
+/*!
+ Appends a single slice to the series with give \a value and \a label.
+ Slice ownership is passed to the series.
+ Returns NULL if value is NaN, Inf or -Inf and no slice is added to the series.
+*/
+QPieSlice *QPieSeries::append(QString label, qreal value)
+{
+ if (isValidValue(value)) {
+ QPieSlice *slice = new QPieSlice(label, value);
+ append(slice);
+ return slice;
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ Inserts a single \a slice to the series before the slice at \a index position.
+ Slice ownership is passed to the series.
+
+ Returns true if insert was successful.
+*/
+bool QPieSeries::insert(int index, QPieSlice *slice)
+{
+ Q_D(QPieSeries);
+
+ if (index < 0 || index > d->m_slices.count())
+ return false;
+
+ if (!slice || d->m_slices.contains(slice))
+ return false;
+
+ if (slice->series()) // already added to some series
+ return false;
+
+ if (!isValidValue(slice->value()))
+ return false;
+
+ slice->setParent(this);
+ QPieSlicePrivate::fromSlice(slice)->m_series = this;
+ d->m_slices.insert(index, slice);
+
+ d->updateDerivativeData();
+
+ connect(slice, SIGNAL(valueChanged()), d, SLOT(sliceValueChanged()));
+ connect(slice, SIGNAL(clicked()), d, SLOT(sliceClicked()));
+ connect(slice, SIGNAL(hovered(bool)), d, SLOT(sliceHovered(bool)));
+
+ emit added(QList<QPieSlice *>() << slice);
+ emit countChanged();
+
+ return true;
+}
+
+/*!
+ Removes a single \a slice from the series and deletes the slice.
+
+ Do not reference the pointer after this call.
+
+ Returns true if remove was successful.
+*/
+bool QPieSeries::remove(QPieSlice *slice)
+{
+ Q_D(QPieSeries);
+
+ if (!d->m_slices.removeOne(slice))
+ return false;
+
+ d->updateDerivativeData();
+
+ emit removed(QList<QPieSlice *>() << slice);
+ emit countChanged();
+
+ delete slice;
+ slice = 0;
+
+ return true;
+}
+
+/*!
+ Takes a single \a slice from the series. Does not destroy the slice object.
+
+ \note The series remains as the slice's parent object. You must set the
+ parent object to take full ownership.
+
+ Returns true if take was successful.
+*/
+bool QPieSeries::take(QPieSlice *slice)
+{
+ Q_D(QPieSeries);
+
+ if (!d->m_slices.removeOne(slice))
+ return false;
+
+ QPieSlicePrivate::fromSlice(slice)->m_series = 0;
+ slice->disconnect(d);
+
+ d->updateDerivativeData();
+
+ emit removed(QList<QPieSlice *>() << slice);
+ emit countChanged();
+
+ return true;
+}
+
+/*!
+ Clears all slices from the series.
+*/
+void QPieSeries::clear()
+{
+ Q_D(QPieSeries);
+ if (d->m_slices.count() == 0)
+ return;
+
+ QList<QPieSlice *> slices = d->m_slices;
+ foreach (QPieSlice *s, d->m_slices)
+ d->m_slices.removeOne(s);
+
+ d->updateDerivativeData();
+
+ emit removed(slices);
+ emit countChanged();
+
+ foreach (QPieSlice *s, slices)
+ delete s;
+}
+
+/*!
+ Returns a list of slices that belong to this series.
+*/
+QList<QPieSlice *> QPieSeries::slices() const
+{
+ Q_D(const QPieSeries);
+ return d->m_slices;
+}
+
+/*!
+ returns the number of the slices in this series.
+*/
+int QPieSeries::count() const
+{
+ Q_D(const QPieSeries);
+ return d->m_slices.count();
+}
+
+/*!
+ Returns true is the series is empty.
+*/
+bool QPieSeries::isEmpty() const
+{
+ Q_D(const QPieSeries);
+ return d->m_slices.isEmpty();
+}
+
+/*!
+ Returns the sum of all slice values in this series.
+
+ \sa QPieSlice::value(), QPieSlice::setValue(), QPieSlice::percentage()
+*/
+qreal QPieSeries::sum() const
+{
+ Q_D(const QPieSeries);
+ return d->m_sum;
+}
+
+void QPieSeries::setHoleSize(qreal holeSize)
+{
+ Q_D(QPieSeries);
+ holeSize = qBound((qreal)0.0, holeSize, (qreal)1.0);
+ d->setSizes(holeSize, qMax(d->m_pieRelativeSize, holeSize));
+}
+
+qreal QPieSeries::holeSize() const
+{
+ Q_D(const QPieSeries);
+ return d->m_holeRelativeSize;
+}
+
+void QPieSeries::setHorizontalPosition(qreal relativePosition)
+{
+ Q_D(QPieSeries);
+
+ if (relativePosition < 0.0)
+ relativePosition = 0.0;
+ if (relativePosition > 1.0)
+ relativePosition = 1.0;
+
+ if (!qFuzzyCompare(d->m_pieRelativeHorPos, relativePosition)) {
+ d->m_pieRelativeHorPos = relativePosition;
+ emit d->horizontalPositionChanged();
+ }
+}
+
+qreal QPieSeries::horizontalPosition() const
+{
+ Q_D(const QPieSeries);
+ return d->m_pieRelativeHorPos;
+}
+
+void QPieSeries::setVerticalPosition(qreal relativePosition)
+{
+ Q_D(QPieSeries);
+
+ if (relativePosition < 0.0)
+ relativePosition = 0.0;
+ if (relativePosition > 1.0)
+ relativePosition = 1.0;
+
+ if (!qFuzzyCompare(d->m_pieRelativeVerPos, relativePosition)) {
+ d->m_pieRelativeVerPos = relativePosition;
+ emit d->verticalPositionChanged();
+ }
+}
+
+qreal QPieSeries::verticalPosition() const
+{
+ Q_D(const QPieSeries);
+ return d->m_pieRelativeVerPos;
+}
+
+void QPieSeries::setPieSize(qreal relativeSize)
+{
+ Q_D(QPieSeries);
+ relativeSize = qBound((qreal)0.0, relativeSize, (qreal)1.0);
+ d->setSizes(qMin(d->m_holeRelativeSize, relativeSize), relativeSize);
+
+}
+
+qreal QPieSeries::pieSize() const
+{
+ Q_D(const QPieSeries);
+ return d->m_pieRelativeSize;
+}
+
+
+void QPieSeries::setPieStartAngle(qreal angle)
+{
+ Q_D(QPieSeries);
+ if (qFuzzyCompare(d->m_pieStartAngle, angle))
+ return;
+ d->m_pieStartAngle = angle;
+ d->updateDerivativeData();
+ emit d->pieStartAngleChanged();
+}
+
+qreal QPieSeries::pieStartAngle() const
+{
+ Q_D(const QPieSeries);
+ return d->m_pieStartAngle;
+}
+
+/*!
+ Sets the end angle of the pie.
+
+ Full pie is 360 degrees where 0 degrees is at 12 a'clock.
+
+ \a angle must be greater than start angle.
+
+ \sa pieEndAngle(), pieStartAngle(), setPieStartAngle()
+*/
+void QPieSeries::setPieEndAngle(qreal angle)
+{
+ Q_D(QPieSeries);
+ if (qFuzzyCompare(d->m_pieEndAngle, angle))
+ return;
+ d->m_pieEndAngle = angle;
+ d->updateDerivativeData();
+ emit d->pieEndAngleChanged();
+}
+
+/*!
+ Returns the end angle of the pie.
+
+ Full pie is 360 degrees where 0 degrees is at 12 a'clock.
+
+ \sa setPieEndAngle(), pieStartAngle(), setPieStartAngle()
+*/
+qreal QPieSeries::pieEndAngle() const
+{
+ Q_D(const QPieSeries);
+ return d->m_pieEndAngle;
+}
+
+/*!
+ Sets the all the slice labels \a visible or invisible.
+
+ Note that this affects only the current slices in the series.
+ If user adds a new slice the default label visibility is false.
+
+ \sa QPieSlice::isLabelVisible(), QPieSlice::setLabelVisible()
+*/
+void QPieSeries::setLabelsVisible(bool visible)
+{
+ Q_D(QPieSeries);
+ foreach (QPieSlice *s, d->m_slices)
+ s->setLabelVisible(visible);
+}
+
+/*!
+ Sets the all the slice labels \a position
+
+ Note that this affects only the current slices in the series.
+ If user adds a new slice the default label position is LabelOutside
+
+ \sa QPieSlice::labelPosition(), QPieSlice::setLabelPosition()
+*/
+void QPieSeries::setLabelsPosition(QPieSlice::LabelPosition position)
+{
+ Q_D(QPieSeries);
+ foreach (QPieSlice *s, d->m_slices)
+ s->setLabelPosition(position);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+QPieSeriesPrivate::QPieSeriesPrivate(QPieSeries *parent) :
+ QAbstractSeriesPrivate(parent),
+ m_pieRelativeHorPos(0.5),
+ m_pieRelativeVerPos(0.5),
+ m_pieRelativeSize(0.7),
+ m_pieStartAngle(0),
+ m_pieEndAngle(360),
+ m_sum(0),
+ m_holeRelativeSize(0.0)
+{
+}
+
+QPieSeriesPrivate::~QPieSeriesPrivate()
+{
+}
+
+void QPieSeriesPrivate::updateDerivativeData()
+{
+ // calculate sum of all slices
+ qreal sum = 0;
+ foreach (QPieSlice *s, m_slices)
+ sum += s->value();
+
+ if (!qFuzzyCompare(m_sum, sum)) {
+ m_sum = sum;
+ emit q_func()->sumChanged();
+ }
+
+ // nothing to show..
+ if (qFuzzyCompare(m_sum, 0))
+ return;
+
+ // update slice attributes
+ qreal sliceAngle = m_pieStartAngle;
+ qreal pieSpan = m_pieEndAngle - m_pieStartAngle;
+ QVector<QPieSlice *> changed;
+ foreach (QPieSlice *s, m_slices) {
+ QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
+ d->setPercentage(s->value() / m_sum);
+ d->setStartAngle(sliceAngle);
+ d->setAngleSpan(pieSpan * s->percentage());
+ sliceAngle += s->angleSpan();
+ }
+
+
+ emit calculatedDataChanged();
+}
+
+void QPieSeriesPrivate::setSizes(qreal innerSize, qreal outerSize)
+{
+ bool changed = false;
+
+ if (!qFuzzyCompare(m_holeRelativeSize, innerSize)) {
+ m_holeRelativeSize = innerSize;
+ changed = true;
+ }
+
+ if (!qFuzzyCompare(m_pieRelativeSize, outerSize)) {
+ m_pieRelativeSize = outerSize;
+ changed = true;
+ }
+
+ if (changed)
+ emit pieSizeChanged();
+}
+
+QPieSeriesPrivate *QPieSeriesPrivate::fromSeries(QPieSeries *series)
+{
+ return series->d_func();
+}
+
+void QPieSeriesPrivate::sliceValueChanged()
+{
+ Q_ASSERT(m_slices.contains(qobject_cast<QPieSlice *>(sender())));
+ updateDerivativeData();
+}
+
+void QPieSeriesPrivate::sliceClicked()
+{
+ QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
+ Q_ASSERT(m_slices.contains(slice));
+ Q_Q(QPieSeries);
+ emit q->clicked(slice);
+}
+
+void QPieSeriesPrivate::sliceHovered(bool state)
+{
+ QPieSlice *slice = qobject_cast<QPieSlice *>(sender());
+ if (!m_slices.isEmpty()) {
+ Q_ASSERT(m_slices.contains(slice));
+ Q_Q(QPieSeries);
+ emit q->hovered(slice, state);
+ }
+}
+
+void QPieSeriesPrivate::initializeDomain()
+{
+ // does not apply to pie
+}
+
+void QPieSeriesPrivate::initializeGraphics(QGraphicsItem* parent)
+{
+ Q_Q(QPieSeries);
+ PieChartItem *pie = new PieChartItem(q,parent);
+ m_item.reset(pie);
+ QAbstractSeriesPrivate::initializeGraphics(parent);
+}
+
+void QPieSeriesPrivate::initializeAnimations(QtCharts::QChart::AnimationOptions options)
+{
+ PieChartItem *item = static_cast<PieChartItem *>(m_item.data());
+ Q_ASSERT(item);
+ if (item->animation())
+ item->animation()->stopAndDestroyLater();
+
+ if (options.testFlag(QChart::SeriesAnimations))
+ item->setAnimation(new PieAnimation(item));
+ else
+ item->setAnimation(0);
+ QAbstractSeriesPrivate::initializeAnimations(options);
+}
+
+QList<QLegendMarker*> QPieSeriesPrivate::createLegendMarkers(QLegend* legend)
+{
+ Q_Q(QPieSeries);
+ QList<QLegendMarker*> markers;
+ foreach(QPieSlice* slice, q->slices()) {
+ QPieLegendMarker* marker = new QPieLegendMarker(q,slice,legend);
+ markers << marker;
+ }
+ return markers;
+}
+
+void QPieSeriesPrivate::initializeAxes()
+{
+
+}
+
+QAbstractAxis::AxisType QPieSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const
+{
+ Q_UNUSED(orientation);
+ return QAbstractAxis::AxisTypeNoAxis;
+}
+
+QAbstractAxis* QPieSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const
+{
+ Q_UNUSED(orientation);
+ return 0;
+}
+
+void QPieSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
+{
+ //Q_Q(QPieSeries);
+ //const QList<QColor>& colors = theme->seriesColors();
+ const QList<QGradient>& gradients = theme->seriesGradients();
+
+ for (int i(0); i < m_slices.count(); i++) {
+
+ QColor penColor = ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 0.0);
+
+ // Get color for a slice from a gradient linearly, beginning from the start of the gradient
+ qreal pos = (qreal)(i + 1) / (qreal) m_slices.count();
+ QColor brushColor = ChartThemeManager::colorAt(gradients.at(index % gradients.size()), pos);
+
+ QPieSlice *s = m_slices.at(i);
+ QPieSlicePrivate *d = QPieSlicePrivate::fromSlice(s);
+
+ if (forced || d->m_data.m_slicePen.isThemed())
+ d->setPen(penColor, true);
+
+ if (forced || d->m_data.m_sliceBrush.isThemed())
+ d->setBrush(brushColor, true);
+
+ if (forced || d->m_data.m_labelBrush.isThemed())
+ d->setLabelBrush(theme->labelBrush().color(), true);
+
+ if (forced || d->m_data.m_labelFont.isThemed())
+ d->setLabelFont(theme->labelFont(), true);
+ }
+}
+
+
+#include "moc_qpieseries.cpp"
+#include "moc_qpieseries_p.cpp"
+
+QT_CHARTS_END_NAMESPACE
diff --git a/src/charts/piechart/qpieseries.h b/src/charts/piechart/qpieseries.h
new file mode 100644
index 00000000..27c8042b
--- /dev/null
+++ b/src/charts/piechart/qpieseries.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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 QPIESERIES_H
+#define QPIESERIES_H
+
+#include <QtCharts/qabstractseries.h>
+#include <QtCharts/QPieSlice>
+
+QT_CHARTS_BEGIN_NAMESPACE
+class QPieSeriesPrivate;
+
+class QT_CHARTS_EXPORT QPieSeries : public QAbstractSeries
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal horizontalPosition READ horizontalPosition WRITE setHorizontalPosition)
+ Q_PROPERTY(qreal verticalPosition READ verticalPosition WRITE setVerticalPosition)
+ Q_PROPERTY(qreal size READ pieSize WRITE setPieSize)
+ Q_PROPERTY(qreal startAngle READ pieStartAngle WRITE setPieStartAngle)
+ Q_PROPERTY(qreal endAngle READ pieEndAngle WRITE setPieEndAngle)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(qreal sum READ sum NOTIFY sumChanged)
+ Q_PROPERTY(qreal holeSize READ holeSize WRITE setHoleSize)
+
+public:
+ explicit QPieSeries(QObject *parent = 0);
+ virtual ~QPieSeries();
+
+ QAbstractSeries::SeriesType type() const;
+
+ bool append(QPieSlice *slice);
+ bool append(QList<QPieSlice *> slices);
+ QPieSeries &operator << (QPieSlice *slice);
+ QPieSlice *append(QString label, qreal value);
+
+ bool insert(int index, QPieSlice *slice);
+
+ bool remove(QPieSlice *slice);
+ bool take(QPieSlice *slice);
+ void clear();
+
+ QList<QPieSlice *> slices() const;
+ int count() const;
+
+ bool isEmpty() const;
+
+ qreal sum() const;
+
+ void setHoleSize(qreal holeSize);
+ qreal holeSize() const;
+
+ void setHorizontalPosition(qreal relativePosition);
+ qreal horizontalPosition() const;
+
+ void setVerticalPosition(qreal relativePosition);
+ qreal verticalPosition() const;
+
+ void setPieSize(qreal relativeSize);
+ qreal pieSize() const;
+
+ void setPieStartAngle(qreal startAngle);
+ qreal pieStartAngle() const;
+
+ void setPieEndAngle(qreal endAngle);
+ qreal pieEndAngle() const;
+
+ void setLabelsVisible(bool visible = true);
+ void setLabelsPosition(QPieSlice::LabelPosition position);
+
+Q_SIGNALS:
+ void added(QList<QPieSlice *> slices);
+ void removed(QList<QPieSlice *> slices);
+ void clicked(QPieSlice *slice);
+ void hovered(QPieSlice *slice, bool state);
+ void countChanged();
+ void sumChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QPieSeries)
+ Q_DISABLE_COPY(QPieSeries)
+ friend class PieChartItem;
+};
+
+QT_CHARTS_END_NAMESPACE
+
+#endif // QPIESERIES_H
diff --git a/src/charts/piechart/qpieseries_p.h b/src/charts/piechart/qpieseries_p.h
new file mode 100644
index 00000000..f2a52180
--- /dev/null
+++ b/src/charts/piechart/qpieseries_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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 QPIESERIES_P_H
+#define QPIESERIES_P_H
+
+#include "qpieseries.h"
+#include "qabstractseries_p.h"
+
+QT_CHARTS_BEGIN_NAMESPACE
+class QLegendPrivate;
+
+class QPieSeriesPrivate : public QAbstractSeriesPrivate
+{
+ Q_OBJECT
+
+public:
+ QPieSeriesPrivate(QPieSeries *parent);
+ ~QPieSeriesPrivate();
+
+ void initializeDomain();
+ void initializeAxes();
+ void initializeGraphics(QGraphicsItem* parent);
+ void initializeAnimations(QtCharts::QChart::AnimationOptions options);
+ void initializeTheme(int index, ChartTheme* theme, bool forced = false);
+
+ QList<QLegendMarker *> createLegendMarkers(QLegend *legend);
+
+ QAbstractAxis::AxisType defaultAxisType(Qt::Orientation orientation) const;
+ QAbstractAxis* createDefaultAxis(Qt::Orientation orientation) const;
+
+ void updateDerivativeData();
+ void setSizes(qreal innerSize, qreal outerSize);
+
+ static QPieSeriesPrivate *fromSeries(QPieSeries *series);
+
+signals:
+ void calculatedDataChanged();
+ void pieSizeChanged();
+ void pieStartAngleChanged();
+ void pieEndAngleChanged();
+ void horizontalPositionChanged();
+ void verticalPositionChanged();
+
+public Q_SLOTS:
+ void sliceValueChanged();
+ void sliceClicked();
+ void sliceHovered(bool state);
+
+private:
+ QList<QPieSlice *> m_slices;
+ qreal m_pieRelativeHorPos;
+ qreal m_pieRelativeVerPos;
+ qreal m_pieRelativeSize;
+ qreal m_pieStartAngle;
+ qreal m_pieEndAngle;
+ qreal m_sum;
+ qreal m_holeRelativeSize;
+
+public:
+ friend class QLegendPrivate;
+ Q_DECLARE_PUBLIC(QPieSeries)
+};
+
+QT_CHARTS_END_NAMESPACE
+
+#endif // QPIESERIES_P_H
diff --git a/src/charts/piechart/qpieslice.cpp b/src/charts/piechart/qpieslice.cpp
new file mode 100644
index 00000000..48227e26
--- /dev/null
+++ b/src/charts/piechart/qpieslice.cpp
@@ -0,0 +1,794 @@
+/****************************************************************************
+**
+** 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 "qpieslice.h"
+#include "qpieslice_p.h"
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+/*!
+ \class QPieSlice
+ \inmodule Qt Charts
+ \brief Defines a slice in pie series.
+
+ This object defines the properties of a single slice in a QPieSeries.
+
+ In addition to the obvious value and label properties the user can also control
+ the visual appearance of a slice. By modifying the visual appearance also means that
+ the user is overriding the default appearance set by the theme.
+
+ Note that if the user has customized slices and theme is changed all customizations will be lost.
+
+ To enable user interaction with the pie some basic signals are provided about clicking and hovering.
+*/
+
+/*!
+ \qmltype PieSlice
+ \instantiates QPieSlice
+ \inqmlmodule QtCharts
+
+ \brief Defines a slice in pie series.
+
+ PieSlice defines the properties of a single slice in a PieSeries. The element should be used
+ as a child for a PieSeries. For example:
+ \snippet qmlpiechart/qml/qmlpiechart/main.qml 2
+
+ An alternative (dynamic) method for adding slices to a PieSeries is using PieSeries.append
+ method.
+ \snippet qmlpiechart/qml/qmlpiechart/main.qml 4
+
+ In that case you may want to use PieSeries.at or PieSeries.find to access the properties of
+ an individual PieSlice instance.
+ \snippet qmlpiechart/qml/qmlpiechart/main.qml 5
+ \sa PieSeries
+*/
+
+/*!
+ \enum QPieSlice::LabelPosition
+
+ This enum describes the position of the slice label.
+
+ \value LabelOutside Label is outside the slice with an arm.
+ \value LabelInsideHorizontal Label is centered inside the slice and laid out horizontally.
+ \value LabelInsideTangential Label is centered inside the slice and rotated to be parallel to the tangential of the slice's arc.
+ \value LabelInsideNormal Label is centered inside the slice rotated to be parallel to the normal of the slice's arc.
+ */
+
+/*!
+ \property QPieSlice::label
+ Label of the slice.
+ \sa labelVisible, labelBrush, labelFont, labelArmLengthFactor
+*/
+/*!
+ \qmlproperty string PieSlice::label
+ Label (text) of the slice.
+*/
+
+/*!
+ \fn void QPieSlice::labelChanged()
+ This signal emitted when the slice label has been changed.
+ \sa label
+*/
+/*!
+ \qmlsignal PieSlice::onLabelChanged()
+ This signal emitted when the slice label has been changed.
+ \sa label
+*/
+
+/*!
+ \property QPieSlice::value
+ Value of the slice.
+ Note that if users sets a negative value it is converted to a positive value.
+ \sa percentage(), QPieSeries::sum()
+*/
+/*!
+ \qmlproperty real PieSlice::value
+ Value of the slice. Note that if users sets a negative value it is converted to a positive value.
+*/
+
+/*!
+ \fn void QPieSlice::valueChanged()
+ This signal is emitted when the slice value changes.
+ \sa value
+*/
+/*!
+ \qmlsignal PieSlice::onValueChanged()
+ This signal is emitted when the slice value changes.
+ \sa value
+*/
+
+/*!
+ \property QPieSlice::labelVisible
+ Defines the visibility of slice label. By default the label is not visible.
+ \sa label, labelBrush, labelFont, labelArmLengthFactor
+*/
+/*!
+ \qmlproperty bool PieSlice::labelVisible
+ Defines the visibility of slice label. By default the label is not visible.
+*/
+
+/*!
+ \fn void QPieSlice::labelVisibleChanged()
+ This signal emitted when visibility of the slice label has changed.
+ \sa labelVisible
+*/
+/*!
+ \qmlsignal PieSlice::onLabelVisibleChanged()
+ This signal emitted when visibility of the slice label has changed.
+ \sa labelVisible
+*/
+
+/*!
+ \property QPieSlice::exploded
+ If set to true the slice is "exploded" away from the pie.
+ \sa explodeDistanceFactor
+*/
+/*!
+ \qmlproperty bool PieSlice::exploded
+ If set to true the slice is "exploded" away from the pie.
+ \sa explodeDistanceFactor
+*/
+
+/*!
+ \property QPieSlice::pen
+ Pen used to draw the slice border.
+*/
+
+/*!
+ \fn void QPieSlice::penChanged()
+ This signal is emitted when the pen of the slice has changed.
+ \sa pen
+*/
+
+/*!
+ \property QPieSlice::borderColor
+ Color used to draw the slice border.
+ This is a convenience property for modifying the slice pen.
+ \sa pen, borderWidth
+*/
+/*!
+ \qmlproperty color PieSlice::borderColor
+ Color used to draw the slice border (pen color).
+ \sa borderWidth
+*/
+
+/*!
+ \fn void QPieSlice::borderColorChanged()
+ This signal is emitted when slice border color changes.
+ \sa pen, borderColor
+*/
+/*!
+ \qmlsignal PieSlice::onBorderColorChanged()
+ This signal is emitted when slice border color changes.
+ \sa borderColor
+*/
+
+/*!
+ \property QPieSlice::borderWidth
+ Width of the slice border.
+ This is a convenience property for modifying the slice pen.
+ \sa pen, borderColor
+*/
+/*!
+ \qmlproperty int PieSlice::borderWidth
+ Width of the slice border.
+ This is a convenience property for modifying the slice pen.
+ \sa borderColor
+*/
+
+/*!
+ \fn void QPieSlice::borderWidthChanged()
+ This signal is emitted when slice border width changes.
+ \sa pen, borderWidth
+*/
+/*!
+ \qmlsignal PieSlice::onBorderWidthChanged()
+ This signal is emitted when slice border width changes.
+ \sa borderWidth
+*/
+
+/*!
+ \property QPieSlice::brush
+ Brush used to draw the slice.
+*/
+
+/*!
+ \fn void QPieSlice::brushChanged()
+ This signal is emitted when the brush of the slice has changed.
+ \sa brush
+*/
+
+/*!
+ \qmlproperty QString PieSlice::brushFilename
+ The name of the file used as a brush for the slice.
+*/
+
+/*!
+ \property QPieSlice::color
+ Fill (brush) color of the slice.
+ This is a convenience property for modifying the slice brush.
+ \sa brush
+*/
+/*!
+ \qmlproperty color PieSlice::color
+ Fill (brush) color of the slice.
+*/
+
+/*!
+ \fn void QPieSlice::colorChanged()
+ This signal is emitted when slice color changes.
+ \sa brush
+*/
+/*!
+ \qmlsignal PieSlice::onColorChanged()
+ This signal is emitted when slice color changes.
+*/
+
+/*!
+ \property QPieSlice::labelBrush
+ Brush used to draw label and label arm of the slice.
+ \sa label, labelVisible, labelFont, labelArmLengthFactor
+*/
+
+/*!
+ \fn void QPieSlice::labelBrushChanged()
+ This signal is emitted when the label brush of the slice has changed.
+ \sa labelBrush
+*/
+
+/*!
+ \property QPieSlice::labelColor
+ Color used to draw the slice label.
+ This is a convenience property for modifying the slice label brush.
+ \sa labelBrush
+*/
+/*!
+ \qmlproperty color PieSlice::labelColor
+ Color used to draw the slice label.
+*/
+
+/*!
+ \fn void QPieSlice::labelColorChanged()
+ This signal is emitted when slice label color changes.
+ \sa labelColor
+*/
+/*!
+ \qmlsignal PieSlice::onLabelColorChanged()
+ This signal is emitted when slice label color changes.
+ \sa labelColor
+*/
+
+/*!
+ \property QPieSlice::labelFont
+ Font used for drawing label text.
+ \sa label, labelVisible, labelArmLengthFactor
+*/
+
+/*!
+ \fn void QPieSlice::labelFontChanged()
+ This signal is emitted when the label font of the slice has changed.
+ \sa labelFont
+*/
+
+/*!
+ \qmlproperty Font PieSlice::labelFont
+
+ Defines the font used for slice label.
+
+ See the Qt documentation for more details of Font.
+
+ \sa labelVisible, labelPosition
+*/
+
+/*!
+ \property QPieSlice::labelPosition
+ Position of the slice label.
+ \sa label, labelVisible
+*/
+/*!
+ \qmlproperty LabelPosition PieSlice::labelPosition
+ Position of the slice label. One of PieSlice.LabelOutside, PieSlice.LabelInsideHorizontal,
+ PieSlice.LabelInsideTangential or PieSlice.LabelInsideNormal. By default the position is
+ PieSlice.LabelOutside.
+ \sa labelVisible
+*/
+
+/*!
+ \property QPieSlice::labelArmLengthFactor
+ Defines the length of the label arm.
+ The factor is relative to pie radius. For example:
+ 1.0 means the length is the same as the radius.
+ 0.5 means the length is half of the radius.
+ By default the arm length is 0.15
+ \sa label, labelVisible, labelBrush, labelFont
+*/
+/*!
+ \qmlproperty real PieSlice::labelArmLengthFactor
+ Defines the length of the label arm.
+ The factor is relative to pie radius. For example:
+ 1.0 means the length is the same as the radius.
+ 0.5 means the length is half of the radius.
+ By default the arm length is 0.15
+ \sa labelVisible
+*/
+
+/*!
+ \property QPieSlice::explodeDistanceFactor
+ When the slice is exploded this factor defines how far the slice is exploded away from the pie.
+ The factor is relative to pie radius. For example:
+ 1.0 means the distance is the same as the radius.
+ 0.5 means the distance is half of the radius.
+ By default the distance is is 0.15
+ \sa exploded
+*/
+/*!
+ \qmlproperty real PieSlice::explodeDistanceFactor
+ When the slice is exploded this factor defines how far the slice is exploded away from the pie.
+ The factor is relative to pie radius. For example:
+ 1.0 means the distance is the same as the radius.
+ 0.5 means the distance is half of the radius.
+ By default the distance is is 0.15
+ \sa exploded
+*/
+
+/*!
+ \property QPieSlice::percentage
+ Percentage of the slice compared to the sum of all slices in the series.
+ The actual value ranges from 0.0 to 1.0.
+ Updated automatically once the slice is added to the series.
+ \sa value, QPieSeries::sum
+*/
+/*!
+ \qmlproperty real PieSlice::percentage
+ Percentage of the slice compared to the sum of all slices in the series.
+ The actual value ranges from 0.0 to 1.0.
+ Updated automatically once the slice is added to the series.
+*/
+
+/*!
+ \fn void QPieSlice::percentageChanged()
+ This signal is emitted when the percentage of the slice has changed.
+ \sa percentage
+*/
+/*!
+ \qmlsignal void PieSlice::onPercentageChanged()
+ This signal is emitted when the percentage of the slice has changed.
+ \sa percentage
+*/
+
+/*!
+ \property QPieSlice::startAngle
+ Defines the starting angle of this slice in the series it belongs to.
+ Full pie is 360 degrees where 0 degrees is at 12 a'clock.
+ Updated automatically once the slice is added to the series.
+*/
+/*!
+ \qmlproperty real PieSlice::startAngle
+ Defines the starting angle of this slice in the series it belongs to.
+ Full pie is 360 degrees where 0 degrees is at 12 a'clock.
+ Updated automatically once the slice is added to the series.
+*/
+
+/*!
+ \fn void QPieSlice::startAngleChanged()
+ This signal is emitted when the starting angle f the slice has changed.
+ \sa startAngle
+*/
+/*!
+ \qmlsignal PieSlice::onStartAngleChanged()
+ This signal is emitted when the starting angle f the slice has changed.
+ \sa startAngle
+*/
+
+/*!
+ \property QPieSlice::angleSpan
+ Span of the slice in degrees.
+ Full pie is 360 degrees where 0 degrees is at 12 a'clock.
+ Updated automatically once the slice is added to the series.
+*/
+/*!
+ \qmlproperty real PieSlice::angleSpan
+ Span of the slice in degrees.
+ Full pie is 360 degrees where 0 degrees is at 12 a'clock.
+ Updated automatically once the slice is added to the series.
+*/
+
+/*!
+ \fn void QPieSlice::angleSpanChanged()
+ This signal is emitted when the angle span of the slice has changed.
+ \sa angleSpan
+*/
+/*!
+ \qmlsignal PieSlice::onAngleSpanChanged()
+ This signal is emitted when the angle span of the slice has changed.
+ \sa angleSpan
+*/
+
+/*!
+ \fn void QPieSlice::clicked()
+ This signal is emitted when user has clicked the slice.
+ \sa QPieSeries::clicked()
+*/
+/*!
+ \qmlsignal PieSlice::onClicked()
+ This signal is emitted when user has clicked the slice.
+*/
+
+/*!
+ \fn void QPieSlice::hovered(bool state)
+ This signal is emitted when user has hovered over or away from the slice.
+ \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
+ \sa QPieSeries::hovered()
+*/
+/*!
+ \qmlsignal PieSlice::onHovered(bool state)
+ This signal is emitted when user has hovered over or away from the slice.
+ \a state is true when user has hovered over the slice and false when hover has moved away from the slice.
+*/
+
+/*!
+ Constructs an empty slice with a \a parent.
+ \sa QPieSeries::append(), QPieSeries::insert()
+*/
+QPieSlice::QPieSlice(QObject *parent)
+ : QObject(parent),
+ d_ptr(new QPieSlicePrivate(this))
+{
+
+}
+
+/*!
+ Constructs an empty slice with given \a value, \a label and a \a parent.
+ \sa QPieSeries::append(), QPieSeries::insert()
+*/
+QPieSlice::QPieSlice(QString label, qreal value, QObject *parent)
+ : QObject(parent),
+ d_ptr(new QPieSlicePrivate(this))
+{
+ setValue(value);
+ setLabel(label);
+}
+
+/*!
+ Destroys the slice.
+ User should not delete the slice if it has been added to the series.
+*/
+QPieSlice::~QPieSlice()
+{
+
+}
+
+void QPieSlice::setLabel(QString label)
+{
+ if (d_ptr->m_data.m_labelText != label) {
+ d_ptr->m_data.m_labelText = label;
+ emit labelChanged();
+ }
+}
+
+QString QPieSlice::label() const
+{
+ return d_ptr->m_data.m_labelText;
+}
+
+void QPieSlice::setValue(qreal value)
+{
+ value = qAbs(value); // negative values not allowed
+ if (!qFuzzyCompare(d_ptr->m_data.m_value, value)) {
+ d_ptr->m_data.m_value = value;
+ emit valueChanged();
+ }
+}
+
+qreal QPieSlice::value() const
+{
+ return d_ptr->m_data.m_value;
+}
+
+void QPieSlice::setLabelVisible(bool visible)
+{
+ if (d_ptr->m_data.m_isLabelVisible != visible) {
+ d_ptr->m_data.m_isLabelVisible = visible;
+ emit labelVisibleChanged();
+ }
+}
+
+bool QPieSlice::isLabelVisible() const
+{
+ return d_ptr->m_data.m_isLabelVisible;
+}
+
+void QPieSlice::setExploded(bool exploded)
+{
+ if (d_ptr->m_data.m_isExploded != exploded) {
+ d_ptr->m_data.m_isExploded = exploded;
+ emit d_ptr->explodedChanged();
+ }
+}
+
+QPieSlice::LabelPosition QPieSlice::labelPosition()
+{
+ return d_ptr->m_data.m_labelPosition;
+}
+
+void QPieSlice::setLabelPosition(LabelPosition position)
+{
+ if (d_ptr->m_data.m_labelPosition != position) {
+ d_ptr->m_data.m_labelPosition = position;
+ emit d_ptr->labelPositionChanged();
+ }
+}
+
+bool QPieSlice::isExploded() const
+{
+ return d_ptr->m_data.m_isExploded;
+}
+
+void QPieSlice::setPen(const QPen &pen)
+{
+ d_ptr->setPen(pen, false);
+}
+
+QPen QPieSlice::pen() const
+{
+ return d_ptr->m_data.m_slicePen;
+}
+
+QColor QPieSlice::borderColor()
+{
+ return pen().color();
+}
+
+void QPieSlice::setBorderColor(QColor color)
+{
+ QPen p = pen();
+ if (color != p.color()) {
+ p.setColor(color);
+ setPen(p);
+ }
+}
+
+int QPieSlice::borderWidth()
+{
+ return pen().width();
+}
+
+void QPieSlice::setBorderWidth(int width)
+{
+ QPen p = pen();
+ if (width != p.width()) {
+ p.setWidth(width);
+ setPen(p);
+ }
+}
+
+void QPieSlice::setBrush(const QBrush &brush)
+{
+ d_ptr->setBrush(brush, false);
+}
+
+QBrush QPieSlice::brush() const
+{
+ return d_ptr->m_data.m_sliceBrush;
+}
+
+QColor QPieSlice::color()
+{
+ return brush().color();
+}
+
+void QPieSlice::setColor(QColor color)
+{
+ QBrush b = brush();
+
+ if (b == QBrush())
+ b.setStyle(Qt::SolidPattern);
+ b.setColor(color);
+ setBrush(b);
+}
+
+void QPieSlice::setLabelBrush(const QBrush &brush)
+{
+ d_ptr->setLabelBrush(brush, false);
+}
+
+QBrush QPieSlice::labelBrush() const
+{
+ return d_ptr->m_data.m_labelBrush;
+}
+
+QColor QPieSlice::labelColor()
+{
+ return labelBrush().color();
+}
+
+void QPieSlice::setLabelColor(QColor color)
+{
+ QBrush b = labelBrush();
+ if (color != b.color()) {
+ b.setColor(color);
+ setLabelBrush(b);
+ }
+}
+
+void QPieSlice::setLabelFont(const QFont &font)
+{
+ d_ptr->setLabelFont(font, false);
+}
+
+QFont QPieSlice::labelFont() const
+{
+ return d_ptr->m_data.m_labelFont;
+}
+
+void QPieSlice::setLabelArmLengthFactor(qreal factor)
+{
+ if (!qFuzzyCompare(d_ptr->m_data.m_labelArmLengthFactor, factor)) {
+ d_ptr->m_data.m_labelArmLengthFactor = factor;
+ emit d_ptr->labelArmLengthFactorChanged();
+ }
+}
+
+qreal QPieSlice::labelArmLengthFactor() const
+{
+ return d_ptr->m_data.m_labelArmLengthFactor;
+}
+
+void QPieSlice::setExplodeDistanceFactor(qreal factor)
+{
+ if (!qFuzzyCompare(d_ptr->m_data.m_explodeDistanceFactor, factor)) {
+ d_ptr->m_data.m_explodeDistanceFactor = factor;
+ emit d_ptr->explodeDistanceFactorChanged();
+ }
+}
+
+qreal QPieSlice::explodeDistanceFactor() const
+{
+ return d_ptr->m_data.m_explodeDistanceFactor;
+}
+
+qreal QPieSlice::percentage() const
+{
+ return d_ptr->m_data.m_percentage;
+}
+
+qreal QPieSlice::startAngle() const
+{
+ return d_ptr->m_data.m_startAngle;
+}
+
+qreal QPieSlice::angleSpan() const
+{
+ return d_ptr->m_data.m_angleSpan;
+}
+
+/*!
+ Returns the series that this slice belongs to.
+
+ \sa QPieSeries::append()
+*/
+QPieSeries *QPieSlice::series() const
+{
+ return d_ptr->m_series;
+}
+
+QPieSlicePrivate::QPieSlicePrivate(QPieSlice *parent)
+ : QObject(parent),
+ q_ptr(parent),
+ m_series(0)
+{
+
+}
+
+QPieSlicePrivate::~QPieSlicePrivate()
+{
+
+}
+
+QPieSlicePrivate *QPieSlicePrivate::fromSlice(QPieSlice *slice)
+{
+ return slice->d_func();
+}
+
+void QPieSlicePrivate::setPen(const QPen &pen, bool themed)
+{
+ if (m_data.m_slicePen != pen) {
+
+ QPen oldPen = m_data.m_slicePen;
+
+ m_data.m_slicePen = pen;
+ m_data.m_slicePen.setThemed(themed);
+
+ emit q_ptr->penChanged();
+ if (oldPen.color() != pen.color())
+ emit q_ptr->borderColorChanged();
+ if (oldPen.width() != pen.width())
+ emit q_ptr->borderWidthChanged();
+ }
+}
+
+void QPieSlicePrivate::setBrush(const QBrush &brush, bool themed)
+{
+ if (m_data.m_sliceBrush != brush) {
+
+ QBrush oldBrush = m_data.m_sliceBrush;
+
+ m_data.m_sliceBrush = brush;
+ m_data.m_sliceBrush.setThemed(themed);
+
+ emit q_ptr->brushChanged();
+ if (oldBrush.color() != brush.color())
+ emit q_ptr->colorChanged();
+ }
+}
+
+void QPieSlicePrivate::setLabelBrush(const QBrush &brush, bool themed)
+{
+ if (m_data.m_labelBrush != brush) {
+
+ QBrush oldBrush = m_data.m_labelBrush;
+
+ m_data.m_labelBrush = brush;
+ m_data.m_labelBrush.setThemed(themed);
+
+ emit q_ptr->labelBrushChanged();
+ if (oldBrush.color() != brush.color())
+ emit q_ptr->labelColorChanged();
+ }
+}
+
+void QPieSlicePrivate::setLabelFont(const QFont &font, bool themed)
+{
+ if (m_data.m_labelFont != font) {
+ m_data.m_labelFont = font;
+ m_data.m_labelFont.setThemed(themed);
+ emit q_ptr->labelFontChanged();
+ }
+}
+
+void QPieSlicePrivate::setPercentage(qreal percentage)
+{
+ if (!qFuzzyCompare(m_data.m_percentage, percentage)) {
+ m_data.m_percentage = percentage;
+ emit q_ptr->percentageChanged();
+ }
+}
+
+void QPieSlicePrivate::setStartAngle(qreal angle)
+{
+ if (!qFuzzyCompare(m_data.m_startAngle, angle)) {
+ m_data.m_startAngle = angle;
+ emit q_ptr->startAngleChanged();
+ }
+}
+
+void QPieSlicePrivate::setAngleSpan(qreal span)
+{
+ if (!qFuzzyCompare(m_data.m_angleSpan, span)) {
+ m_data.m_angleSpan = span;
+ emit q_ptr->angleSpanChanged();
+ }
+}
+
+QT_CHARTS_END_NAMESPACE
+
+QT_CHARTS_USE_NAMESPACE
+#include "moc_qpieslice.cpp"
+#include "moc_qpieslice_p.cpp"
diff --git a/src/charts/piechart/qpieslice.h b/src/charts/piechart/qpieslice.h
new file mode 100644
index 00000000..8be5d3cc
--- /dev/null
+++ b/src/charts/piechart/qpieslice.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** 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 QPIESLICE_H
+#define QPIESLICE_H
+
+#include <QtCharts/qchartglobal.h>
+#include <QObject>
+#include <QPen>
+#include <QBrush>
+#include <QFont>
+
+QT_CHARTS_BEGIN_NAMESPACE
+class QPieSlicePrivate;
+class QPieSeries;
+
+class QT_CHARTS_EXPORT QPieSlice : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(LabelPosition)
+ Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged)
+ Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged)
+ Q_PROPERTY(bool labelVisible READ isLabelVisible WRITE setLabelVisible NOTIFY labelVisibleChanged)
+ Q_PROPERTY(LabelPosition labelPosition READ labelPosition WRITE setLabelPosition)
+ Q_PROPERTY(bool exploded READ isExploded WRITE setExploded)
+ Q_PROPERTY(QPen pen READ pen WRITE setPen NOTIFY penChanged)
+ Q_PROPERTY(QColor borderColor READ borderColor WRITE setBorderColor NOTIFY borderColorChanged)
+ Q_PROPERTY(int borderWidth READ borderWidth WRITE setBorderWidth NOTIFY borderWidthChanged)
+ Q_PROPERTY(QBrush brush READ brush WRITE setBrush NOTIFY brushChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ Q_PROPERTY(QBrush labelBrush READ labelBrush WRITE setLabelBrush NOTIFY labelBrushChanged)
+ Q_PROPERTY(QColor labelColor READ labelColor WRITE setLabelColor NOTIFY labelColorChanged)
+ Q_PROPERTY(QFont labelFont READ labelFont WRITE setLabelFont NOTIFY labelFontChanged)
+ Q_PROPERTY(qreal labelArmLengthFactor READ labelArmLengthFactor WRITE setLabelArmLengthFactor)
+ Q_PROPERTY(qreal explodeDistanceFactor READ explodeDistanceFactor WRITE setExplodeDistanceFactor)
+ Q_PROPERTY(qreal percentage READ percentage NOTIFY percentageChanged)
+ Q_PROPERTY(qreal startAngle READ startAngle NOTIFY startAngleChanged)
+ Q_PROPERTY(qreal angleSpan READ angleSpan NOTIFY angleSpanChanged)
+
+public:
+ enum LabelPosition {
+ LabelOutside,
+ LabelInsideHorizontal,
+ LabelInsideTangential,
+ LabelInsideNormal
+ };
+
+public:
+ explicit QPieSlice(QObject *parent = 0);
+ QPieSlice(QString label, qreal value, QObject *parent = 0);
+ virtual ~QPieSlice();
+
+ void setLabel(QString label);
+ QString label() const;
+
+ void setValue(qreal value);
+ qreal value() const;
+
+ void setLabelVisible(bool visible = true);
+ bool isLabelVisible() const;
+
+ LabelPosition labelPosition();
+ void setLabelPosition(LabelPosition position);
+
+ void setExploded(bool exploded = true);
+ bool isExploded() const;
+
+ void setPen(const QPen &pen);
+ QPen pen() const;
+
+ QColor borderColor();
+ void setBorderColor(QColor color);
+
+ int borderWidth();
+ void setBorderWidth(int width);
+
+ void setBrush(const QBrush &brush);
+ QBrush brush() const;
+
+ QColor color();
+ void setColor(QColor color);
+
+ void setLabelBrush(const QBrush &brush);
+ QBrush labelBrush() const;
+
+ QColor labelColor();
+ void setLabelColor(QColor color);
+
+ void setLabelFont(const QFont &font);
+ QFont labelFont() const;
+
+ void setLabelArmLengthFactor(qreal factor);
+ qreal labelArmLengthFactor() const;
+
+ void setExplodeDistanceFactor(qreal factor);
+ qreal explodeDistanceFactor() const;
+
+ qreal percentage() const;
+ qreal startAngle() const;
+ qreal angleSpan() const;
+
+ QPieSeries *series() const;
+
+Q_SIGNALS:
+ void clicked();
+ void hovered(bool state);
+ void labelChanged();
+ void valueChanged();
+ void labelVisibleChanged();
+ void penChanged();
+ void brushChanged();
+ void labelBrushChanged();
+ void labelFontChanged();
+ void percentageChanged();
+ void startAngleChanged();
+ void angleSpanChanged();
+ void colorChanged();
+ void borderColorChanged();
+ void borderWidthChanged();
+ void labelColorChanged();
+
+private:
+ QPieSlicePrivate * const d_ptr;
+ Q_DECLARE_PRIVATE(QPieSlice)
+ Q_DISABLE_COPY(QPieSlice)
+};
+
+QT_CHARTS_END_NAMESPACE
+
+#endif // QPIESLICE_H
diff --git a/src/charts/piechart/qpieslice_p.h b/src/charts/piechart/qpieslice_p.h
new file mode 100644
index 00000000..340a4753
--- /dev/null
+++ b/src/charts/piechart/qpieslice_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** 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 QPIESLICE_P_H
+#define QPIESLICE_P_H
+
+#include <QObject>
+#include "qpieslice.h"
+#include "pieslicedata_p.h"
+
+QT_CHARTS_BEGIN_NAMESPACE
+class QPieSeries;
+
+class QPieSlicePrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ QPieSlicePrivate(QPieSlice *parent);
+ ~QPieSlicePrivate();
+
+ static QPieSlicePrivate *fromSlice(QPieSlice *slice);
+
+ void setPen(const QPen &pen, bool themed);
+ void setBrush(const QBrush &brush, bool themed);
+ void setLabelBrush(const QBrush &brush, bool themed);
+ void setLabelFont(const QFont &font, bool themed);
+
+ void setPercentage(qreal percentage);
+ void setStartAngle(qreal angle);
+ void setAngleSpan(qreal span);
+
+Q_SIGNALS:
+ void labelPositionChanged();
+ void explodedChanged();
+ void labelArmLengthFactorChanged();
+ void explodeDistanceFactorChanged();
+
+private:
+ friend class QPieSeries;
+ friend class QPieSeriesPrivate;
+ friend class ChartThemeManager;
+ friend class PieChartItem;
+
+ QPieSlice * const q_ptr;
+ Q_DECLARE_PUBLIC(QPieSlice)
+
+ PieSliceData m_data;
+ QPieSeries *m_series;
+};
+
+QT_CHARTS_END_NAMESPACE
+
+#endif // QPIESLICE_P_H
diff --git a/src/charts/piechart/qvpiemodelmapper.cpp b/src/charts/piechart/qvpiemodelmapper.cpp
new file mode 100644
index 00000000..7b9c0a0c
--- /dev/null
+++ b/src/charts/piechart/qvpiemodelmapper.cpp
@@ -0,0 +1,270 @@
+/****************************************************************************
+**
+** 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 "qvpiemodelmapper.h"
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+/*!
+ \class QVPieModelMapper
+ \inmodule Qt Charts
+ \brief Vertical model mapper for pie 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 QPieSeries and QAbstractItemModel derived model object that keeps the consecutive pie slices data in columns.
+ It is possible to use both QAbstractItemModel and QPieSeries model API. QVPieModelMapper makes sure that Pie and the model are kept in sync.
+ \note Used model has to support adding/removing rows/columns and modifying the data of the cells.
+*/
+/*!
+ \qmltype VPieModelMapper
+ \instantiates QVPieModelMapper
+ \inqmlmodule QtCharts
+
+ \brief Vertical model mapper for pie series.
+
+ VPieModelMapper allows you to use your own QAbstractItemModel derived model with data in columns
+ as a data source for a pie series. It is possible to use both QAbstractItemModel and PieSeries
+ data API to manipulate data. VPieModelMapper keeps the Pie and the model in sync.
+
+ The following QML example would create a pie series with four slices (assuming the model has at
+ least five rows). Each slice would contain a label from column 1 and a value from column 2.
+ \code
+ VPieModelMapper {
+ series: pieSeries
+ model: customModel
+ labelsColumn: 1
+ valuesColumn: 2
+ firstRow: 1
+ rowCount: 4
+ }
+ \endcode
+*/
+
+/*!
+ \property QVPieModelMapper::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 PieSeries VPieModelMapper::series
+ Defines the PieSeries object that is used by the mapper. If you define the mapper element as a child for a
+ PieSeries, leave this property undefined. 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 QVPieModelMapper::model
+ \brief Defines the model that is used by the mapper.
+*/
+/*!
+ \qmlproperty SomeModel VPieModelMapper::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 QVPieModelMapper::valuesColumn
+ \brief Defines which column of the model is kept in sync with the values of the pie's slices.
+
+ Default value is: -1 (invalid mapping)
+*/
+/*!
+ \qmlproperty int VPieModelMapper::valuesColumn
+ Defines which column of the model is kept in sync with the values of the pie's slices. Default value is -1 (invalid
+ mapping).
+*/
+
+/*!
+ \property QVPieModelMapper::labelsColumn
+ \brief Defines which column of the model is kept in sync with the labels of the pie's slices.
+
+ Default value is: -1 (invalid mapping)
+*/
+/*!
+ \qmlproperty int VPieModelMapper::labelsColumn
+ Defines which column of the model is kept in sync with the labels of the pie's slices. Default value is -1 (invalid
+ mapping).
+*/
+
+/*!
+ \property QVPieModelMapper::firstRow
+ \brief Defines which row of the model contains the first slice value.
+
+ Minimal and default value is: 0
+*/
+/*!
+ \qmlproperty int VPieModelMapper::firstRow
+ Defines which row of the model contains the first slice value.
+ The default value is 0.
+*/
+
+/*!
+ \property QVPieModelMapper::rowCount
+ \brief Defines the number of rows of the model that are mapped as the data for QPieSeries.
+
+ Minimal and default value is: -1 (count limited by the number of rows in the model)
+*/
+/*!
+ \qmlproperty int VPieModelMapper::columnCount
+ Defines the number of rows of the model that are mapped as the data for QPieSeries. The default value is
+ -1 (count limited by the number of rows in the model)
+*/
+
+/*!
+ \fn void QVPieModelMapper::seriesReplaced()
+
+ Emitted when the series to which mapper is connected to has changed.
+*/
+
+/*!
+ \fn void QVPieModelMapper::modelReplaced()
+
+ Emitted when the model to which mapper is connected to has changed.
+*/
+
+/*!
+ \fn void QVPieModelMapper::valuesColumnChanged()
+
+ Emitted when the valuesColumn has changed.
+*/
+
+/*!
+ \fn void QVPieModelMapper::labelsColumnChanged()
+
+ Emitted when the labelsColumn has changed.
+*/
+
+/*!
+ \fn void QVPieModelMapper::firstRowChanged()
+ Emitted when the firstRow has changed.
+*/
+
+/*!
+ \fn void QVPieModelMapper::rowCountChanged()
+ Emitted when the rowCount has changed.
+*/
+
+/*!
+ Constructs a mapper object which is a child of \a parent.
+*/
+QVPieModelMapper::QVPieModelMapper(QObject *parent) :
+ QPieModelMapper(parent)
+{
+ QPieModelMapper::setOrientation(Qt::Vertical);
+}
+
+QAbstractItemModel *QVPieModelMapper::model() const
+{
+ return QPieModelMapper::model();
+}
+
+void QVPieModelMapper::setModel(QAbstractItemModel *model)
+{
+ if (model != QPieModelMapper::model()) {
+ QPieModelMapper::setModel(model);
+ emit modelReplaced();
+ }
+}
+
+QPieSeries *QVPieModelMapper::series() const
+{
+ return QPieModelMapper::series();
+}
+
+void QVPieModelMapper::setSeries(QPieSeries *series)
+{
+ if (series != QPieModelMapper::series()) {
+ QPieModelMapper::setSeries(series);
+ emit seriesReplaced();
+ }
+}
+
+/*!
+ Returns which column of the model is kept in sync with the values of the pie's slices
+*/
+int QVPieModelMapper::valuesColumn() const
+{
+ return QPieModelMapper::valuesSection();
+}
+
+/*!
+ Sets the model column that is kept in sync with the pie slices values.
+ Parameter \a valuesColumn specifies the row of the model.
+*/
+void QVPieModelMapper::setValuesColumn(int valuesColumn)
+{
+ if (valuesColumn != valuesSection()) {
+ QPieModelMapper::setValuesSection(valuesColumn);
+ emit valuesColumnChanged();
+ }
+}
+
+/*!
+ Returns which column of the model is kept in sync with the labels of the pie's slices
+*/
+int QVPieModelMapper::labelsColumn() const
+{
+ return QPieModelMapper::labelsSection();
+}
+
+/*!
+ Sets the model column that is kept in sync with the pie's slices labels.
+ Parameter \a labelsColumn specifies the row of the model.
+*/
+void QVPieModelMapper::setLabelsColumn(int labelsColumn)
+{
+ if (labelsColumn != labelsSection()) {
+ QPieModelMapper::setLabelsSection(labelsColumn);
+ emit labelsColumnChanged();
+ }
+}
+
+int QVPieModelMapper::firstRow() const
+{
+ return first();
+}
+
+void QVPieModelMapper::setFirstRow(int firstRow)
+{
+ if (firstRow != first()) {
+ setFirst(firstRow);
+ emit firstRowChanged();
+ }
+}
+
+int QVPieModelMapper::rowCount() const
+{
+ return count();
+}
+
+void QVPieModelMapper::setRowCount(int rowCount)
+{
+ if (rowCount != count()) {
+ setCount(rowCount);
+ emit rowCountChanged();
+ }
+}
+
+#include "moc_qvpiemodelmapper.cpp"
+
+QT_CHARTS_END_NAMESPACE
diff --git a/src/charts/piechart/qvpiemodelmapper.h b/src/charts/piechart/qvpiemodelmapper.h
new file mode 100644
index 00000000..2135ff9b
--- /dev/null
+++ b/src/charts/piechart/qvpiemodelmapper.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 QVPIEMODELMAPPER_H
+#define QVPIEMODELMAPPER_H
+
+#include <QtCharts/qpiemodelmapper.h>
+
+QT_CHARTS_BEGIN_NAMESPACE
+/* Comment line for syncqt to generate the fwd-include correctly, due to QTBUG-22432 */
+class QT_CHARTS_EXPORT QVPieModelMapper : public QPieModelMapper
+{
+ Q_OBJECT
+ Q_PROPERTY(QPieSeries *series READ series WRITE setSeries NOTIFY seriesReplaced)
+ Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelReplaced)
+ Q_PROPERTY(int valuesColumn READ valuesColumn WRITE setValuesColumn NOTIFY valuesColumnChanged)
+ Q_PROPERTY(int labelsColumn READ labelsColumn WRITE setLabelsColumn NOTIFY labelsColumnChanged)
+ Q_PROPERTY(int firstRow READ firstRow WRITE setFirstRow NOTIFY firstRowChanged)
+ Q_PROPERTY(int rowCount READ rowCount WRITE setRowCount NOTIFY rowCountChanged)
+
+public:
+ explicit QVPieModelMapper(QObject *parent = 0);
+
+ QAbstractItemModel *model() const;
+ void setModel(QAbstractItemModel *model);
+
+ QPieSeries *series() const;
+ void setSeries(QPieSeries *series);
+
+ int valuesColumn() const;
+ void setValuesColumn(int valuesColumn);
+
+ int labelsColumn() const;
+ void setLabelsColumn(int labelsColumn);
+
+ int firstRow() const;
+ void setFirstRow(int firstRow);
+
+ int rowCount() const;
+ void setRowCount(int rowCount);
+
+Q_SIGNALS:
+ void seriesReplaced();
+ void modelReplaced();
+ void valuesColumnChanged();
+ void labelsColumnChanged();
+ void firstRowChanged();
+ void rowCountChanged();
+};
+
+QT_CHARTS_END_NAMESPACE
+
+#endif // QVPIEMODELMAPPER_H