summaryrefslogtreecommitdiffstats
path: root/src/charts/axis/chartaxiselement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/charts/axis/chartaxiselement.cpp')
-rw-r--r--src/charts/axis/chartaxiselement.cpp404
1 files changed, 404 insertions, 0 deletions
diff --git a/src/charts/axis/chartaxiselement.cpp b/src/charts/axis/chartaxiselement.cpp
new file mode 100644
index 00000000..b7a60d27
--- /dev/null
+++ b/src/charts/axis/chartaxiselement.cpp
@@ -0,0 +1,404 @@
+/****************************************************************************
+**
+** 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 "chartaxiselement_p.h"
+#include "qabstractaxis_p.h"
+#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
+#include <qmath.h>
+#include <QDateTime>
+#include <QTextDocument>
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+static const char *labelFormatMatchString = "%[\\-\\+#\\s\\d\\.lhjztL]*([dicuoxfegXFEG])";
+static const char *labelFormatMatchLocalizedString = "^([^%]*)%\\.(\\d+)([defgiEG])(.*)$";
+static QRegExp *labelFormatMatcher = 0;
+static QRegExp *labelFormatMatcherLocalized = 0;
+class StaticLabelFormatMatcherDeleter
+{
+public:
+ StaticLabelFormatMatcherDeleter() {}
+ ~StaticLabelFormatMatcherDeleter() {
+ delete labelFormatMatcher;
+ delete labelFormatMatcherLocalized;
+ }
+};
+static StaticLabelFormatMatcherDeleter staticLabelFormatMatcherDeleter;
+
+ChartAxisElement::ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
+ : ChartElement(item),
+ m_axis(axis),
+ m_animation(0),
+ m_grid(new QGraphicsItemGroup(item)),
+ m_arrow(new QGraphicsItemGroup(item)),
+ m_shades(new QGraphicsItemGroup(item)),
+ m_labels(new QGraphicsItemGroup(item)),
+ m_title(new QGraphicsTextItem(item)),
+ m_intervalAxis(intervalAxis)
+
+{
+ //initial initialization
+ m_arrow->setHandlesChildEvents(false);
+ m_arrow->setZValue(ChartPresenter::AxisZValue);
+ m_labels->setZValue(ChartPresenter::AxisZValue);
+ m_shades->setZValue(ChartPresenter::ShadesZValue);
+ m_grid->setZValue(ChartPresenter::GridZValue);
+ m_title->setZValue(ChartPresenter::GridZValue);
+ m_title->document()->setDocumentMargin(ChartPresenter::textMargin());
+ handleVisibleChanged(axis->isVisible());
+ connectSlots();
+
+ setFlag(QGraphicsItem::ItemHasNoContents, true);
+}
+
+ChartAxisElement::~ChartAxisElement()
+{
+}
+
+void ChartAxisElement::connectSlots()
+{
+ QObject::connect(axis(), SIGNAL(visibleChanged(bool)), this, SLOT(handleVisibleChanged(bool)));
+ QObject::connect(axis(), SIGNAL(lineVisibleChanged(bool)), this, SLOT(handleArrowVisibleChanged(bool)));
+ QObject::connect(axis(), SIGNAL(gridVisibleChanged(bool)), this, SLOT(handleGridVisibleChanged(bool)));
+ QObject::connect(axis(), SIGNAL(labelsVisibleChanged(bool)), this, SLOT(handleLabelsVisibleChanged(bool)));
+ QObject::connect(axis(), SIGNAL(shadesVisibleChanged(bool)), this, SLOT(handleShadesVisibleChanged(bool)));
+ QObject::connect(axis(), SIGNAL(labelsAngleChanged(int)), this, SLOT(handleLabelsAngleChanged(int)));
+ QObject::connect(axis(), SIGNAL(linePenChanged(const QPen&)), this, SLOT(handleArrowPenChanged(const QPen&)));
+ QObject::connect(axis(), SIGNAL(labelsPenChanged(const QPen&)), this, SLOT(handleLabelsPenChanged(const QPen&)));
+ QObject::connect(axis(), SIGNAL(labelsBrushChanged(const QBrush&)), this, SLOT(handleLabelsBrushChanged(const QBrush&)));
+ QObject::connect(axis(), SIGNAL(labelsFontChanged(const QFont&)), this, SLOT(handleLabelsFontChanged(const QFont&)));
+ QObject::connect(axis(), SIGNAL(gridLinePenChanged(const QPen&)), this, SLOT(handleGridPenChanged(const QPen&)));
+ QObject::connect(axis(), SIGNAL(shadesPenChanged(const QPen&)), this, SLOT(handleShadesPenChanged(const QPen&)));
+ QObject::connect(axis(), SIGNAL(shadesBrushChanged(const QBrush&)), this, SLOT(handleShadesBrushChanged(const QBrush&)));
+ QObject::connect(axis(), SIGNAL(titleTextChanged(const QString&)), this, SLOT(handleTitleTextChanged(const QString&)));
+ QObject::connect(axis(), SIGNAL(titleFontChanged(const QFont&)), this, SLOT(handleTitleFontChanged(const QFont&)));
+ QObject::connect(axis(), SIGNAL(titlePenChanged(const QPen&)), this, SLOT(handleTitlePenChanged(const QPen&)));
+ QObject::connect(axis(), SIGNAL(titleBrushChanged(const QBrush&)), this, SLOT(handleTitleBrushChanged(const QBrush&)));
+ QObject::connect(axis(), SIGNAL(titleVisibleChanged(bool)), this, SLOT(handleTitleVisibleChanged(bool)));
+ QObject::connect(axis()->d_ptr.data(), SIGNAL(rangeChanged(qreal, qreal)), this, SLOT(handleRangeChanged(qreal, qreal)));
+}
+
+void ChartAxisElement::handleArrowVisibleChanged(bool visible)
+{
+ m_arrow->setVisible(visible);
+}
+
+void ChartAxisElement::handleGridVisibleChanged(bool visible)
+{
+ m_grid->setVisible(visible);
+}
+
+void ChartAxisElement::handleLabelsVisibleChanged(bool visible)
+{
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+ m_labels->setVisible(visible);
+}
+
+void ChartAxisElement::handleShadesVisibleChanged(bool visible)
+{
+ m_shades->setVisible(visible);
+}
+
+void ChartAxisElement::handleTitleVisibleChanged(bool visible)
+{
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+ m_title->setVisible(visible);
+}
+
+void ChartAxisElement::handleLabelsAngleChanged(int angle)
+{
+ foreach (QGraphicsItem *item, m_labels->childItems())
+ item->setRotation(angle);
+
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+}
+
+void ChartAxisElement::handleLabelsPenChanged(const QPen &pen)
+{
+ Q_UNUSED(pen)
+}
+
+void ChartAxisElement::handleLabelsBrushChanged(const QBrush &brush)
+{
+ foreach (QGraphicsItem *item, m_labels->childItems())
+ static_cast<QGraphicsTextItem *>(item)->setDefaultTextColor(brush.color());
+}
+
+void ChartAxisElement::handleLabelsFontChanged(const QFont &font)
+{
+ foreach (QGraphicsItem *item, m_labels->childItems())
+ static_cast<QGraphicsTextItem *>(item)->setFont(font);
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+}
+
+void ChartAxisElement::handleTitleTextChanged(const QString &title)
+{
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+ if (title.isEmpty() || !m_title->isVisible())
+ m_title->setHtml(title);
+}
+
+void ChartAxisElement::handleTitlePenChanged(const QPen &pen)
+{
+ Q_UNUSED(pen)
+}
+
+void ChartAxisElement::handleTitleBrushChanged(const QBrush &brush)
+{
+ m_title->setDefaultTextColor(brush.color());
+}
+
+void ChartAxisElement::handleTitleFontChanged(const QFont &font)
+{
+ if (m_title->font() != font) {
+ m_title->setFont(font);
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+ }
+}
+
+void ChartAxisElement::handleVisibleChanged(bool visible)
+{
+ setVisible(visible);
+ if (!visible) {
+ m_grid->setVisible(visible);
+ m_arrow->setVisible(visible);
+ m_shades->setVisible(visible);
+ m_labels->setVisible(visible);
+ m_title->setVisible(visible);
+ } else {
+ m_grid->setVisible(axis()->isGridLineVisible());
+ m_arrow->setVisible(axis()->isLineVisible());
+ m_shades->setVisible(axis()->shadesVisible());
+ m_labels->setVisible(axis()->labelsVisible());
+ m_title->setVisible(axis()->isTitleVisible());
+ }
+
+ if (presenter()) presenter()->layout()->invalidate();
+}
+
+void ChartAxisElement::handleRangeChanged(qreal min, qreal max)
+{
+ Q_UNUSED(min);
+ Q_UNUSED(max);
+
+ if (!isEmpty()) {
+ QVector<qreal> layout = calculateLayout();
+ updateLayout(layout);
+ QSizeF before = effectiveSizeHint(Qt::PreferredSize);
+ QSizeF after = sizeHint(Qt::PreferredSize);
+
+ if (before != after) {
+ QGraphicsLayoutItem::updateGeometry();
+ // We don't want to call invalidate on layout, since it will change minimum size of
+ // component, which we would like to avoid since it causes nasty flips when scrolling
+ // or zooming, instead recalculate layout and use plotArea for extra space.
+ presenter()->layout()->setGeometry(presenter()->layout()->geometry());
+ }
+ }
+}
+
+bool ChartAxisElement::isEmpty()
+{
+ return axisGeometry().isEmpty()
+ || gridGeometry().isEmpty()
+ || qFuzzyCompare(min(), max());
+}
+
+qreal ChartAxisElement::min() const
+{
+ return m_axis->d_ptr->min();
+}
+
+qreal ChartAxisElement::max() const
+{
+ return m_axis->d_ptr->max();
+}
+
+QString ChartAxisElement::formatLabel(const QString &formatSpec, const QByteArray &array,
+ qreal value, int precision, const QString &preStr,
+ const QString &postStr) const
+{
+ QString retVal;
+ if (!formatSpec.isEmpty()) {
+ if (formatSpec.at(0) == QLatin1Char('d')
+ || formatSpec.at(0) == QLatin1Char('i')
+ || formatSpec.at(0) == QLatin1Char('c')) {
+ if (presenter()->localizeNumbers())
+ retVal = preStr + presenter()->locale().toString(qint64(value)) + postStr;
+ else
+ retVal = QString().sprintf(array, qint64(value));
+ } else if (formatSpec.at(0) == QLatin1Char('u')
+ || formatSpec.at(0) == QLatin1Char('o')
+ || formatSpec.at(0) == QLatin1Char('x')
+ || formatSpec.at(0) == QLatin1Char('X')) {
+ // These formats are not supported by localized numbers
+ retVal = QString().sprintf(array, quint64(value));
+ } else if (formatSpec.at(0) == QLatin1Char('f')
+ || formatSpec.at(0) == QLatin1Char('F')
+ || formatSpec.at(0) == QLatin1Char('e')
+ || formatSpec.at(0) == QLatin1Char('E')
+ || formatSpec.at(0) == QLatin1Char('g')
+ || formatSpec.at(0) == QLatin1Char('G')) {
+ if (presenter()->localizeNumbers()) {
+ retVal = preStr
+ + presenter()->locale().toString(value, formatSpec.at(0).toLatin1(),
+ precision)
+ + postStr;
+ } else {
+ retVal = QString().sprintf(array, value);
+ }
+ }
+ }
+ return retVal;
+}
+
+QStringList ChartAxisElement::createValueLabels(qreal min, qreal max, int ticks,
+ const QString &format) const
+{
+ QStringList labels;
+
+ if (max <= min || ticks < 1)
+ return labels;
+
+ if (format.isNull()) {
+ int n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0) + 1;
+ for (int i = 0; i < ticks; i++) {
+ qreal value = min + (i * (max - min) / (ticks - 1));
+ labels << presenter()->numberToString(value, 'f', n);
+ }
+ } else {
+ QByteArray array = format.toLatin1();
+ QString formatSpec;
+ QString preStr;
+ QString postStr;
+ int precision = 6; // Six is the default precision in Qt API
+ if (presenter()->localizeNumbers()) {
+ if (!labelFormatMatcherLocalized)
+ labelFormatMatcherLocalized
+ = new QRegExp(QString::fromLatin1(labelFormatMatchLocalizedString));
+ if (labelFormatMatcherLocalized->indexIn(format, 0) != -1) {
+ preStr = labelFormatMatcherLocalized->cap(1);
+ if (!labelFormatMatcherLocalized->cap(2).isEmpty())
+ precision = labelFormatMatcherLocalized->cap(2).toInt();
+ formatSpec = labelFormatMatcherLocalized->cap(3);
+ postStr = labelFormatMatcherLocalized->cap(4);
+ }
+ } else {
+ if (!labelFormatMatcher)
+ labelFormatMatcher = new QRegExp(QString::fromLatin1(labelFormatMatchString));
+ if (labelFormatMatcher->indexIn(format, 0) != -1)
+ formatSpec = labelFormatMatcher->cap(1);
+ }
+ for (int i = 0; i < ticks; i++) {
+ qreal value = min + (i * (max - min) / (ticks - 1));
+ labels << formatLabel(formatSpec, array, value, precision, preStr, postStr);
+ }
+ }
+
+ return labels;
+}
+
+QStringList ChartAxisElement::createLogValueLabels(qreal min, qreal max, qreal base, int ticks,
+ const QString &format) const
+{
+ QStringList labels;
+
+ if (max <= min || ticks < 1)
+ return labels;
+
+ int firstTick;
+ if (base > 1)
+ firstTick = ceil(log10(min) / log10(base));
+ else
+ firstTick = ceil(log10(max) / log10(base));
+
+ if (format.isNull()) {
+ int n = 0;
+ if (ticks > 1)
+ n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0);
+ n++;
+ for (int i = firstTick; i < ticks + firstTick; i++) {
+ qreal value = qPow(base, i);
+ labels << presenter()->numberToString(value, 'f', n);
+ }
+ } else {
+ QByteArray array = format.toLatin1();
+ QString formatSpec;
+ QString preStr;
+ QString postStr;
+ int precision = 6; // Six is the default precision in Qt API
+ if (presenter()->localizeNumbers()) {
+ if (!labelFormatMatcherLocalized)
+ labelFormatMatcherLocalized =
+ new QRegExp(QString::fromLatin1(labelFormatMatchLocalizedString));
+ if (labelFormatMatcherLocalized->indexIn(format, 0) != -1) {
+ preStr = labelFormatMatcherLocalized->cap(1);
+ if (!labelFormatMatcherLocalized->cap(2).isEmpty())
+ precision = labelFormatMatcherLocalized->cap(2).toInt();
+ formatSpec = labelFormatMatcherLocalized->cap(3);
+ postStr = labelFormatMatcherLocalized->cap(4);
+ }
+ } else {
+ if (!labelFormatMatcher)
+ labelFormatMatcher = new QRegExp(QString::fromLatin1(labelFormatMatchString));
+ if (labelFormatMatcher->indexIn(format, 0) != -1)
+ formatSpec = labelFormatMatcher->cap(1);
+ }
+ for (int i = firstTick; i < ticks + firstTick; i++) {
+ qreal value = qPow(base, i);
+ labels << formatLabel(formatSpec, array, value, precision, preStr, postStr);
+ }
+ }
+
+ return labels;
+}
+
+QStringList ChartAxisElement::createDateTimeLabels(qreal min, qreal max,int ticks,
+ const QString &format) const
+{
+ QStringList labels;
+
+ if (max <= min || ticks < 1)
+ return labels;
+
+ int n = qMax(int(-floor(log10((max - min) / (ticks - 1)))), 0);
+ n++;
+ for (int i = 0; i < ticks; i++) {
+ qreal value = min + (i * (max - min) / (ticks - 1));
+ labels << presenter()->locale().toString(QDateTime::fromMSecsSinceEpoch(value), format);
+ }
+ return labels;
+}
+
+void ChartAxisElement::axisSelected()
+{
+ emit clicked();
+}
+
+#include "moc_chartaxiselement_p.cpp"
+
+QT_CHARTS_END_NAMESPACE