blob: 9695a60e106bb375fdb2e1433283329b42c4fb78 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Charts module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <private/abstractbarchartitem_p.h>
#include <private/bar_p.h>
#include <QtCharts/QBarSet>
#include <private/qbarset_p.h>
#include <QtCharts/QAbstractBarSeries>
#include <private/qabstractbarseries_p.h>
#include <private/qchart_p.h>
#include <private/chartpresenter_p.h>
#include <private/charttheme_p.h>
#include <private/baranimation_p.h>
#include <private/chartdataset_p.h>
#include <QtCore/QtMath>
#include <QtGui/QPainter>
#include <QtGui/QTextDocument>
QT_CHARTS_BEGIN_NAMESPACE
AbstractBarChartItem::AbstractBarChartItem(QAbstractBarSeries *series, QGraphicsItem* item) :
ChartItem(series->d_func(),item),
m_animation(0),
m_series(series),
m_firstCategory(-1),
m_lastCategory(-2),
m_categoryCount(0),
m_labelItemsMissing(false),
m_orientation(Qt::Horizontal),
m_resetAnimation(true)
{
setAcceptedMouseButtons({});
setFlag(ItemClipsChildrenToShape);
setFlag(QGraphicsItem::ItemIsSelectable);
connect(series->d_func(), SIGNAL(updatedLayout()), this, SLOT(handleLayoutChanged()));
connect(series->d_func(), SIGNAL(updatedBars()), this, SLOT(handleUpdatedBars()));
connect(series->d_func(), SIGNAL(labelsVisibleChanged(bool)), this, SLOT(handleLabelsVisibleChanged(bool)));
connect(series->d_func(), SIGNAL(restructuredBars()), this, SLOT(handleDataStructureChanged()));
connect(series->d_func(), &QAbstractBarSeriesPrivate::setValueChanged,
this, &AbstractBarChartItem::handleBarValueChange);
connect(series->d_func(), &QAbstractBarSeriesPrivate::setValueAdded,
this, &AbstractBarChartItem::handleBarValueAdd);
connect(series->d_func(), &QAbstractBarSeriesPrivate::setValueRemoved,
this, &AbstractBarChartItem::handleBarValueRemove);
connect(series, SIGNAL(visibleChanged()), this, SLOT(handleVisibleChanged()));
connect(series, SIGNAL(opacityChanged()), this, SLOT(handleOpacityChanged()));
connect(series, SIGNAL(labelsFormatChanged(QString)), this, SLOT(handleUpdatedBars()));
connect(series, SIGNAL(labelsFormatChanged(QString)), this, SLOT(positionLabels()));
connect(series, SIGNAL(labelsPositionChanged(QAbstractBarSeries::LabelsPosition)),
this, SLOT(handleLabelsPositionChanged()));
connect(series, SIGNAL(labelsAngleChanged(qreal)), this, SLOT(positionLabels()));
connect(series, &QAbstractBarSeries::labelsPrecisionChanged,
this, &AbstractBarChartItem::handleUpdatedBars);
connect(series, &QAbstractBarSeries::labelsPrecisionChanged,
this, &AbstractBarChartItem::positionLabels);
connect(series->chart()->d_ptr->m_dataset, &ChartDataSet::seriesAdded,
this, &AbstractBarChartItem::handleSeriesAdded);
connect(series->chart()->d_ptr->m_dataset, &ChartDataSet::seriesRemoved,
this, &AbstractBarChartItem::handleSeriesRemoved);
setZValue(ChartPresenter::BarSeriesZValue);
calculateSeriesPositionAdjustmentAndWidth();
handleDataStructureChanged();
}
AbstractBarChartItem::~AbstractBarChartItem()
{
}
void AbstractBarChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(painter);
Q_UNUSED(option);
Q_UNUSED(widget);
}
QRectF AbstractBarChartItem::boundingRect() const
{
return m_rect;
}
void AbstractBarChartItem::initializeFullLayout()
{
qreal setCount = m_series->count();
for (int set = 0; set < setCount; set++) {
QBarSet *barSet = m_series->barSets().at(set);
const QList<Bar *> bars = m_barMap.value(barSet);
for (int i = 0; i < bars.size(); i++) {
Bar *bar = bars.at(i);
initializeLayout(set, bar->index(), bar->layoutIndex(), true);
// Make bar initially hidden to avoid artifacts, layout setting will show it
bar->setVisible(false);
}
}
}
void AbstractBarChartItem::applyLayout(const QVector<QRectF> &layout)
{
QSizeF size = geometry().size();
if (geometry().size().isValid()) {
if (m_animation) {
// If geometry changes along the value axis, do full animation reset, as
// it can cause "ungrounded" bars otherwise.
// Changes to axis labels on bar axis can occur naturally with scrolling,
// which can cause geometry changes that shouldn't trigger animation reset.
const bool sizeChanged = m_orientation == Qt::Horizontal
? m_oldSize.width() != size.width()
: m_oldSize.height() != size.height();
m_oldSize = size;
if (m_resetAnimation || sizeChanged) {
initializeFullLayout();
m_resetAnimation = false;
}
m_animation->setup(m_layout, layout);
presenter()->startAnimation(m_animation);
} else {
setLayout(layout);
update();
}
}
}
void AbstractBarChartItem::setAnimation(BarAnimation *animation)
{
m_animation = animation;
m_resetAnimation = true;
}
void AbstractBarChartItem::setLayout(const QVector<QRectF> &layout)
{
int setCount = m_series->count();
if (layout.size() != m_layout.size() || m_barMap.size() != setCount)
return;
m_layout = layout;
const bool visible = m_series->isVisible();
for (int set = 0; set < setCount; set++) {
QBarSet *barSet = m_series->d_func()->barsetAt(set);
const QList<Bar *> bars = m_barMap.value(barSet);
for (int i = 0; i < bars.size(); i++) {
Bar *bar = bars.at(i);
const QRectF &rect = layout.at(bar->layoutIndex());
bar->setRect(rect);
// Hide empty bars to avoid artifacts at animation start when adding a new series
// as it doesn't have correct axes yet
bar->setVisible(visible && !rect.isEmpty());
}
}
positionLabels();
}
void AbstractBarChartItem::resetAnimation()
{
m_resetAnimation = true;
}
void AbstractBarChartItem::handleDomainUpdated()
{
QRectF rect(QPointF(0,0),domain()->size());
if(m_rect != rect){
prepareGeometryChange();
m_rect = rect;
}
handleLayoutChanged();
}
void AbstractBarChartItem::handleLayoutChanged()
{
if ((m_rect.width() <= 0) || (m_rect.height() <= 0))
return; // rect size zero.
updateBarItems();
QVector<QRectF> layout = calculateLayout();
handleUpdatedBars();
applyLayout(layout);
}
void AbstractBarChartItem::handleLabelsVisibleChanged(bool visible)
{
bool newVisible = visible && m_series->isVisible();
for (const QList<Bar *> &bars : qAsConst(m_barMap)) {
for (Bar *bar : bars) {
QGraphicsTextItem *label = bar->labelItem();
if (label)
label->setVisible(newVisible);
}
}
if (newVisible) {
handleUpdatedBars();
positionLabels();
}
update();
}
void AbstractBarChartItem::handleDataStructureChanged()
{
handleSetStructureChange();
handleLayoutChanged();
}
void AbstractBarChartItem::handleVisibleChanged()
{
bool visible = m_series->isVisible();
handleLabelsVisibleChanged(m_series->isLabelsVisible());
for (auto i = m_barMap.cbegin(), end = m_barMap.cend(); i != end; ++i) {
const QList<Bar *> &bars = i.value();
for (int j = 0; j < bars.size(); j++) {
Bar *bar = bars.at(j);
bar->setVisible(visible && i.key()->at(bar->index()) != 0.0);
}
}
}
void AbstractBarChartItem::handleOpacityChanged()
{
foreach (QGraphicsItem *item, childItems())
item->setOpacity(m_series->opacity());
}
void AbstractBarChartItem::handleUpdatedBars()
{
if (!m_series->d_func()->blockBarUpdate()) {
// Handle changes in pen, brush, labels etc.
int setCount = m_series->count();
const bool seriesVisualsDirty = m_series->d_func()->visualsDirty();
const bool seriesLabelsDirty = m_series->d_func()->labelsDirty();
m_series->d_func()->setVisualsDirty(false);
const bool updateLabels =
m_series->isLabelsVisible() && m_series->isVisible() && presenter();
if (updateLabels) {
createLabelItems();
m_series->d_func()->setLabelsDirty(false);
}
for (int set = 0; set < setCount; set++) {
QBarSet *barSet = m_series->d_func()->barsetAt(set);
QBarSetPrivate *barSetP = barSet->d_ptr.data();
const bool setVisualsDirty = barSetP->visualsDirty();
const bool setLabelsDirty = barSetP->labelsDirty();
barSetP->setVisualsDirty(false);
if (updateLabels)
barSetP->setLabelsDirty(false);
const int actualBarCount = barSet->count();
const QList<Bar *> bars = m_barMap.value(barSet);
for (int i = 0; i < bars.size(); i++) {
Bar *bar = bars.at(i);
if (seriesVisualsDirty || setVisualsDirty || bar->visualsDirty()) {
bar->setPen(barSetP->m_pen);
bar->setBrush(barSetP->m_brush);
bar->setVisualsDirty(false);
bar->update();
}
if (updateLabels && actualBarCount > bar->index()) {
if (seriesLabelsDirty || setLabelsDirty || bar->labelDirty()) {
bar->setLabelDirty(false);
QGraphicsTextItem *label = bar->labelItem();
QString valueLabel;
qreal value = barSetP->value(bar->index());
if (value == 0.0) {
label->setVisible(false);
} else {
label->setVisible(m_series->isLabelsVisible());
valueLabel = generateLabelText(set, bar->index(), value);
}
label->setHtml(valueLabel);
label->setFont(barSetP->m_labelFont);
label->setDefaultTextColor(barSetP->m_labelBrush.color());
label->update();
}
}
}
}
}
}
void AbstractBarChartItem::handleLabelsPositionChanged()
{
positionLabels();
}
void AbstractBarChartItem::positionLabels()
{
// By default position labels on horizontal bar series
// Vertical bar series overload positionLabels() to call positionLabelsVertical()
if (!m_series->isLabelsVisible())
return;
createLabelItems();
QTransform transform;
const qreal angle = m_series->d_func()->labelsAngle();
if (angle != 0.0)
transform.rotate(angle);
int setCount = m_series->count();
for (int set = 0; set < setCount; set++) {
QBarSet *barSet = m_series->d_func()->barsetAt(set);
const QList<Bar *> bars = m_barMap.value(barSet);
for (int i = 0; i < bars.size(); i++) {
Bar *bar = bars.at(i);
QGraphicsTextItem *label = bar->labelItem();
QRectF labelRect = label->boundingRect();
QPointF center = labelRect.center();
qreal xPos = 0;
qreal yPos = m_layout.at(bar->layoutIndex()).center().y() - center.y();
int xDiff = 0;
if (angle != 0.0) {
label->setTransformOriginPoint(center.x(), center.y());
label->setRotation(m_series->d_func()->labelsAngle());
qreal oldWidth = labelRect.width();
labelRect = transform.mapRect(labelRect);
xDiff = (labelRect.width() - oldWidth) / 2;
}
int offset = bar->pen().width() / 2 + 2;
switch (m_series->labelsPosition()) {
case QAbstractBarSeries::LabelsCenter:
xPos = m_layout.at(bar->layoutIndex()).center().x() - center.x();
break;
case QAbstractBarSeries::LabelsOutsideEnd:
xPos = m_layout.at(bar->layoutIndex()).right() + offset + xDiff;
if (xPos + labelRect.width() - offset <= m_rect.right())
break;
Q_FALLTHROUGH();
case QAbstractBarSeries::LabelsInsideEnd:
xPos = m_layout.at(bar->layoutIndex()).right() - labelRect.width() - offset + xDiff;
break;
case QAbstractBarSeries::LabelsInsideBase:
xPos = m_layout.at(bar->layoutIndex()).left() + offset + xDiff;
break;
default:
// Invalid position, never comes here
break;
}
label->setPos(xPos, yPos);
label->setZValue(zValue() + 1);
}
}
}
void AbstractBarChartItem::handleBarValueChange(int index, QtCharts::QBarSet *barset)
{
markLabelsDirty(barset, index, 1);
handleLayoutChanged();
}
void AbstractBarChartItem::handleBarValueAdd(int index, int count, QBarSet *barset)
{
Q_UNUSED(count)
// Value insertions into middle of barset need to dirty the rest of the labels of the set
markLabelsDirty(barset, index, -1);
handleLayoutChanged();
}
void AbstractBarChartItem::handleBarValueRemove(int index, int count, QBarSet *barset)
{
Q_UNUSED(count)
// Value removals from the middle of barset need to dirty the rest of the labels of the set.
markLabelsDirty(barset, index, -1);
// make sure labels are not visible for removed bars
const auto bars = m_barMap.value(barset);
for (int c = barset->count(); c < bars.count(); ++c) {
auto label = bars.at(c)->labelItem();
if (label)
label->setVisible(false);
}
handleLayoutChanged();
}
void AbstractBarChartItem::handleSeriesAdded(QAbstractSeries *series)
{
Q_UNUSED(series)
// If the parent series was added, do nothing, as series pos and width calculations will
// happen anyway.
QAbstractBarSeries *addedSeries = static_cast<QAbstractBarSeries *>(series);
if (addedSeries != m_series) {
calculateSeriesPositionAdjustmentAndWidth();
handleLayoutChanged();
}
}
void AbstractBarChartItem::handleSeriesRemoved(QAbstractSeries *series)
{
// If the parent series was removed, disconnect everything connected by this item,
// as the item will be scheduled for deletion but it is done asynchronously with deleteLater.
QAbstractBarSeries *removedSeries = static_cast<QAbstractBarSeries *>(series);
if (removedSeries == m_series) {
disconnect(m_series->d_func(), 0, this, 0);
disconnect(m_series, 0, this, 0);
disconnect(m_series->chart()->d_ptr->m_dataset, 0, this, 0);
} else {
calculateSeriesPositionAdjustmentAndWidth();
handleLayoutChanged();
}
}
void AbstractBarChartItem::positionLabelsVertical()
{
if (!m_series->isLabelsVisible())
return;
createLabelItems();
QTransform transform;
const qreal angle = m_series->d_func()->labelsAngle();
if (angle != 0.0)
transform.rotate(angle);
int setCount = m_series->count();
for (int set = 0; set < setCount; set++) {
QBarSet *barSet = m_series->d_func()->barsetAt(set);
const QList<Bar *> bars = m_barMap.value(barSet);
for (int i = 0; i < bars.size(); i++) {
Bar *bar = bars.at(i);
QGraphicsTextItem *label = bar->labelItem();
QRectF labelRect = label->boundingRect();
QPointF center = labelRect.center();
qreal xPos = m_layout.at(bar->layoutIndex()).center().x() - center.x();
qreal yPos = 0;
int yDiff = 0;
if (angle != 0.0) {
label->setTransformOriginPoint(center.x(), center.y());
label->setRotation(m_series->d_func()->labelsAngle());
qreal oldHeight = labelRect.height();
labelRect = transform.mapRect(labelRect);
yDiff = (labelRect.height() - oldHeight) / 2;
}
int offset = bar->pen().width() / 2 + 2;
switch (m_series->labelsPosition()) {
case QAbstractBarSeries::LabelsCenter:
yPos = m_layout.at(bar->layoutIndex()).center().y() - center.y();
break;
case QAbstractBarSeries::LabelsOutsideEnd:
yPos = m_layout.at(bar->layoutIndex()).top() - labelRect.height() - offset + yDiff;
if (yPos + offset >= m_rect.y())
break;
Q_FALLTHROUGH();
case QAbstractBarSeries::LabelsInsideEnd:
yPos = m_layout.at(bar->layoutIndex()).top() + offset + yDiff;
break;
case QAbstractBarSeries::LabelsInsideBase:
yPos = m_layout.at(bar->layoutIndex()).bottom() - labelRect.height() - offset + yDiff;
break;
default:
// Invalid position, never comes here
break;
}
label->setPos(xPos, yPos);
label->setZValue(zValue() + 1);
}
}
}
void AbstractBarChartItem::createLabelItems()
{
if (!m_labelItemsMissing)
return;
m_labelItemsMissing = false;
for (const QList<Bar *> &bars : qAsConst(m_barMap)) {
for (Bar *bar : bars) {
QGraphicsTextItem *label = bar->labelItem();
if (!label) {
QGraphicsTextItem *newLabel = new QGraphicsTextItem(this);
newLabel->setAcceptHoverEvents(false);
newLabel->document()->setDocumentMargin(ChartPresenter::textMargin());
bar->setLabelItem(newLabel);
}
}
}
}
// This function is called whenever barsets change
void AbstractBarChartItem::handleSetStructureChange()
{
QList<QBarSet *> newSets = m_series->barSets();
QList<QBarSet *> oldSets = m_barMap.keys();
// Remove obsolete sets
for (int i = 0; i < oldSets.size(); i++) {
if (!newSets.contains(oldSets.at(i))) {
qDeleteAll(m_barMap.value(oldSets.at(i)));
m_barMap.remove(oldSets.at(i));
}
}
// Create new sets
for (int s = 0; s < newSets.size(); s++) {
QBarSet *set = newSets.at(s);
if (!m_barMap.contains(set)) {
QList<Bar *> bars;
m_barMap.insert(set, bars);
} else {
// Dirty the old set labels to ensure labels are updated correctly on all series types
markLabelsDirty(set, 0, -1);
}
}
if (themeManager())
themeManager()->updateSeries(m_series);
}
QString AbstractBarChartItem::generateLabelText(int set, int category, qreal value)
{
Q_UNUSED(set);
Q_UNUSED(category);
static const QString valueTag(QLatin1String("@value"));
QString valueString = presenter()->numberToString(value, 'g', m_series->labelsPrecision());
QString valueLabel;
if (m_series->labelsFormat().isEmpty()) {
valueLabel = valueString;
} else {
valueLabel = m_series->labelsFormat();
valueLabel.replace(valueTag, valueString);
}
return valueLabel;
}
void AbstractBarChartItem::updateBarItems()
{
int min(0);
int max(0);
if (m_orientation == Qt::Vertical) {
min = qFloor(domain()->minX()) - 1;
max = qCeil(domain()->maxX()) + 1;
} else {
min = qFloor(domain()->minY()) - 1;
max = qCeil(domain()->maxY()) + 1;
}
int lastBarIndex = m_series->d_func()->categoryCount() - 1;
if (lastBarIndex < 0) {
// Indicate invalid categories by negatives
// Last should be one less than the first to make loops work right in case of no categories
m_firstCategory = -1;
m_lastCategory = -2;
m_categoryCount = 0;
} else {
m_firstCategory = qMax(qMin(min, lastBarIndex), 0);
m_lastCategory = qMax(qMin(max, lastBarIndex), m_firstCategory);
m_categoryCount = m_lastCategory - m_firstCategory + 1;
}
QList<QBarSet *> newSets = m_series->barSets();
QList<QBarSet *> oldSets = m_barMap.keys();
Q_ASSERT(newSets.size() == oldSets.size());
int layoutSize = m_categoryCount * newSets.size();
QVector<QRectF> oldLayout = m_layout;
if (layoutSize != m_layout.size())
m_layout.resize(layoutSize);
// Create new graphic items for bars or remove excess ones
int layoutIndex = 0;
for (int s = 0; s < newSets.size(); s++) {
QBarSet *set = newSets.at(s);
QList<Bar *> bars = m_barMap.value(set);
int addCount = m_categoryCount - bars.size();
if (addCount > 0) {
for (int c = 0; c < addCount; c++) {
Bar *bar = new Bar(set, this);
bars.append(bar);
connect(bar, &Bar::clicked, m_series, &QAbstractBarSeries::clicked);
connect(bar, &Bar::hovered, m_series, &QAbstractBarSeries::hovered);
connect(bar, &Bar::pressed, m_series, &QAbstractBarSeries::pressed);
connect(bar, &Bar::released, m_series, &QAbstractBarSeries::released);
connect(bar, &Bar::doubleClicked, m_series, &QAbstractBarSeries::doubleClicked);
connect(bar, &Bar::clicked, set, &QBarSet::clicked);
connect(bar, &Bar::hovered, set, &QBarSet::hovered);
connect(bar, &Bar::pressed, set, &QBarSet::pressed);
connect(bar, &Bar::released, set, &QBarSet::released);
connect(bar, &Bar::doubleClicked, set, &QBarSet::doubleClicked);
m_labelItemsMissing = true;
}
}
// Update bar indexes
QHash<int, Bar*> indexMap;
QVector<Bar *> unassignedBars(m_categoryCount, nullptr);
int unassignedIndex(0);
QList<Bar *> newBars;
newBars.reserve(m_categoryCount);
for (int c = 0; c < bars.size(); c++) {
Bar *bar = bars.at(c);
if (bar->index() < m_firstCategory || bar->index() > m_lastCategory) {
// Delete excess unassigned bars first
if (addCount < 0) {
addCount++;
delete bar;
bar = nullptr;
} else {
unassignedBars[unassignedIndex++] = bar;
bar->setLayoutIndex(layoutIndex);
newBars.append(bar);
layoutIndex++;
}
} else {
indexMap.insert(bar->index(), bar);
newBars.append(bar);
m_layout[layoutIndex] = oldLayout.at(bar->layoutIndex());
bar->setLayoutIndex(layoutIndex);
layoutIndex++;
}
}
unassignedIndex = 0;
for (int c = m_firstCategory; c <= m_lastCategory; c++) {
Bar *bar = indexMap.value(c);
if (!bar) {
bar = unassignedBars.at(unassignedIndex++);
bar->setIndex(c);
indexMap.insert(bar->index(), bar);
}
}
m_indexForBarMap.insert(set, indexMap);
if (m_animation) {
for (int i = 0; i < unassignedIndex; i++) {
Bar *bar = unassignedBars.at(i);
initializeLayout(s, bar->index(), bar->layoutIndex(), m_resetAnimation);
bar->setRect(m_layout.at(bar->layoutIndex()));
// Make bar initially hidden to avoid artifacts, layout setting will show it
bar->setVisible(false);
}
}
m_barMap.insert(set, newBars);
}
}
void AbstractBarChartItem::markLabelsDirty(QBarSet *barset, int index, int count)
{
Q_ASSERT(barset);
if (index <= 0 && count < 0) {
barset->d_ptr.data()->setLabelsDirty(true);
} else {
const QList<Bar *> bars = m_barMap.value(barset);
const int maxIndex = count > 0 ? index + count : barset->count();
for (int i = 0; i < bars.size(); i++) {
Bar *bar = bars.at(i);
if (bar->index() >= index && bar->index() < maxIndex)
bar->setLabelDirty(true);
}
}
}
void AbstractBarChartItem::calculateSeriesPositionAdjustmentAndWidth()
{
m_seriesPosAdjustment = 0.0;
m_seriesWidth = 1.0;
if (!m_series->chart())
return;
// Find out total number of bar series in chart and the index of this series among them
const QList<QAbstractSeries *> seriesList = m_series->chart()->series();
int index = -1;
int count = 0;
for (QAbstractSeries *series : seriesList) {
if (qobject_cast<QAbstractBarSeries *>(series)){
if (series == m_series)
index = count;
count++;
}
}
if (index > -1 && count > 1) {
m_seriesWidth = 1.0 / count;
m_seriesPosAdjustment = (m_seriesWidth * index) + (m_seriesWidth / 2.0) - 0.5;
}
}
ChartAnimation *AbstractBarChartItem::animation() const
{
return m_animation;
}
QT_CHARTS_END_NAMESPACE
#include "moc_abstractbarchartitem_p.cpp"