summaryrefslogtreecommitdiffstats
path: root/src/charts/chartpresenter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/charts/chartpresenter.cpp')
-rw-r--r--src/charts/chartpresenter.cpp508
1 files changed, 508 insertions, 0 deletions
diff --git a/src/charts/chartpresenter.cpp b/src/charts/chartpresenter.cpp
new file mode 100644
index 00000000..7d3f41a7
--- /dev/null
+++ b/src/charts/chartpresenter.cpp
@@ -0,0 +1,508 @@
+/****************************************************************************
+ **
+ ** 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 "chartpresenter_p.h"
+#include "qchart.h"
+#include "chartitem_p.h"
+#include "qchart_p.h"
+#include "qabstractaxis.h"
+#include "qabstractaxis_p.h"
+#include "chartdataset_p.h"
+#include "chartanimation_p.h"
+#include "qabstractseries_p.h"
+#include "qareaseries.h"
+#include "chartaxiselement_p.h"
+#include "chartbackground_p.h"
+#include "cartesianchartlayout_p.h"
+#include "polarchartlayout_p.h"
+#include "charttitle_p.h"
+#include <QTimer>
+#include <QTextDocument>
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+ChartPresenter::ChartPresenter(QChart *chart, QChart::ChartType type)
+ : QObject(chart),
+ m_chart(chart),
+ m_options(QChart::NoAnimation),
+ m_state(ShowState),
+ m_background(0),
+ m_plotAreaBackground(0),
+ m_title(0),
+ m_localizeNumbers(false)
+{
+ if (type == QChart::ChartTypeCartesian)
+ m_layout = new CartesianChartLayout(this);
+ else if (type == QChart::ChartTypePolar)
+ m_layout = new PolarChartLayout(this);
+ Q_ASSERT(m_layout);
+}
+
+ChartPresenter::~ChartPresenter()
+{
+
+}
+
+void ChartPresenter::setGeometry(const QRectF rect)
+{
+ if (m_rect != rect) {
+ m_rect = rect;
+ foreach (ChartItem *chart, m_chartItems) {
+ chart->domain()->setSize(rect.size());
+ chart->setPos(rect.topLeft());
+ }
+ }
+}
+
+QRectF ChartPresenter::geometry() const
+{
+ return m_rect;
+}
+
+void ChartPresenter::handleAxisAdded(QAbstractAxis *axis)
+{
+ axis->d_ptr->initializeGraphics(rootItem());
+ axis->d_ptr->initializeAnimations(m_options);
+ ChartAxisElement *item = axis->d_ptr->axisItem();
+ item->setPresenter(this);
+ item->setThemeManager(m_chart->d_ptr->m_themeManager);
+ m_axisItems<<item;
+ m_axes<<axis;
+ m_layout->invalidate();
+}
+
+void ChartPresenter::handleAxisRemoved(QAbstractAxis *axis)
+{
+ ChartAxisElement *item = axis->d_ptr->m_item.take();
+ item->hide();
+ item->disconnect();
+ item->deleteLater();
+ m_axisItems.removeAll(item);
+ m_axes.removeAll(axis);
+ m_layout->invalidate();
+}
+
+
+void ChartPresenter::handleSeriesAdded(QAbstractSeries *series)
+{
+ series->d_ptr->initializeGraphics(rootItem());
+ series->d_ptr->initializeAnimations(m_options);
+ series->d_ptr->setPresenter(this);
+ ChartItem *chart = series->d_ptr->chartItem();
+ chart->setPresenter(this);
+ chart->setThemeManager(m_chart->d_ptr->m_themeManager);
+ chart->domain()->setSize(m_rect.size());
+ chart->setPos(m_rect.topLeft());
+ chart->handleDomainUpdated(); //this could be moved to intializeGraphics when animator is refactored
+ m_chartItems<<chart;
+ m_series<<series;
+ m_layout->invalidate();
+}
+
+void ChartPresenter::handleSeriesRemoved(QAbstractSeries *series)
+{
+ ChartItem *chart = series->d_ptr->m_item.take();
+ chart->hide();
+ chart->disconnect();
+ chart->deleteLater();
+ m_chartItems.removeAll(chart);
+ m_series.removeAll(series);
+ m_layout->invalidate();
+}
+
+void ChartPresenter::setAnimationOptions(QChart::AnimationOptions options)
+{
+ if (m_options != options) {
+ QChart::AnimationOptions oldOptions = m_options;
+ m_options = options;
+ if (options.testFlag(QChart::SeriesAnimations) != oldOptions.testFlag(QChart::SeriesAnimations)) {
+ foreach (QAbstractSeries *series, m_series)
+ series->d_ptr->initializeAnimations(m_options);
+ }
+ if (options.testFlag(QChart::GridAxisAnimations) != oldOptions.testFlag(QChart::GridAxisAnimations)) {
+ foreach (QAbstractAxis *axis, m_axes)
+ axis->d_ptr->initializeAnimations(m_options);
+ }
+ m_layout->invalidate(); // So that existing animations don't just stop halfway
+ }
+}
+
+void ChartPresenter::setState(State state,QPointF point)
+{
+ m_state=state;
+ m_statePoint=point;
+}
+
+QChart::AnimationOptions ChartPresenter::animationOptions() const
+{
+ return m_options;
+}
+
+void ChartPresenter::createBackgroundItem()
+{
+ if (!m_background) {
+ m_background = new ChartBackground(rootItem());
+ m_background->setPen(Qt::NoPen); // Theme doesn't touch pen so don't use default
+ m_background->setBrush(QChartPrivate::defaultBrush());
+ m_background->setZValue(ChartPresenter::BackgroundZValue);
+ }
+}
+
+void ChartPresenter::createPlotAreaBackgroundItem()
+{
+ if (!m_plotAreaBackground) {
+ if (m_chart->chartType() == QChart::ChartTypeCartesian)
+ m_plotAreaBackground = new QGraphicsRectItem(rootItem());
+ else
+ m_plotAreaBackground = new QGraphicsEllipseItem(rootItem());
+ // Use transparent pen instead of Qt::NoPen, as Qt::NoPen causes
+ // antialising artifacts with axis lines for some reason.
+ m_plotAreaBackground->setPen(QPen(Qt::transparent));
+ m_plotAreaBackground->setBrush(Qt::NoBrush);
+ m_plotAreaBackground->setZValue(ChartPresenter::PlotAreaZValue);
+ m_plotAreaBackground->setVisible(false);
+ }
+}
+
+void ChartPresenter::createTitleItem()
+{
+ if (!m_title) {
+ m_title = new ChartTitle(rootItem());
+ m_title->setZValue(ChartPresenter::BackgroundZValue);
+ }
+}
+
+void ChartPresenter::startAnimation(ChartAnimation *animation)
+{
+ animation->stop();
+ QTimer::singleShot(0, animation, SLOT(startChartAnimation()));
+}
+
+void ChartPresenter::setBackgroundBrush(const QBrush &brush)
+{
+ createBackgroundItem();
+ m_background->setBrush(brush);
+ m_layout->invalidate();
+}
+
+QBrush ChartPresenter::backgroundBrush() const
+{
+ if (!m_background)
+ return QBrush();
+ return m_background->brush();
+}
+
+void ChartPresenter::setBackgroundPen(const QPen &pen)
+{
+ createBackgroundItem();
+ m_background->setPen(pen);
+ m_layout->invalidate();
+}
+
+QPen ChartPresenter::backgroundPen() const
+{
+ if (!m_background)
+ return QPen();
+ return m_background->pen();
+}
+
+void ChartPresenter::setBackgroundRoundness(qreal diameter)
+{
+ createBackgroundItem();
+ m_background->setDiameter(diameter);
+ m_layout->invalidate();
+}
+
+qreal ChartPresenter::backgroundRoundness() const
+{
+ if (!m_background)
+ return 0;
+ return m_background->diameter();
+}
+
+void ChartPresenter::setPlotAreaBackgroundBrush(const QBrush &brush)
+{
+ createPlotAreaBackgroundItem();
+ m_plotAreaBackground->setBrush(brush);
+ m_layout->invalidate();
+}
+
+QBrush ChartPresenter::plotAreaBackgroundBrush() const
+{
+ if (!m_plotAreaBackground)
+ return QBrush();
+ return m_plotAreaBackground->brush();
+}
+
+void ChartPresenter::setPlotAreaBackgroundPen(const QPen &pen)
+{
+ createPlotAreaBackgroundItem();
+ m_plotAreaBackground->setPen(pen);
+ m_layout->invalidate();
+}
+
+QPen ChartPresenter::plotAreaBackgroundPen() const
+{
+ if (!m_plotAreaBackground)
+ return QPen();
+ return m_plotAreaBackground->pen();
+}
+
+void ChartPresenter::setTitle(const QString &title)
+{
+ createTitleItem();
+ m_title->setText(title);
+ m_layout->invalidate();
+}
+
+QString ChartPresenter::title() const
+{
+ if (!m_title)
+ return QString();
+ return m_title->text();
+}
+
+void ChartPresenter::setTitleFont(const QFont &font)
+{
+ createTitleItem();
+ m_title->setFont(font);
+ m_layout->invalidate();
+}
+
+QFont ChartPresenter::titleFont() const
+{
+ if (!m_title)
+ return QFont();
+ return m_title->font();
+}
+
+void ChartPresenter::setTitleBrush(const QBrush &brush)
+{
+ createTitleItem();
+ m_title->setDefaultTextColor(brush.color());
+ m_layout->invalidate();
+}
+
+QBrush ChartPresenter::titleBrush() const
+{
+ if (!m_title)
+ return QBrush();
+ return QBrush(m_title->defaultTextColor());
+}
+
+void ChartPresenter::setBackgroundVisible(bool visible)
+{
+ createBackgroundItem();
+ m_background->setVisible(visible);
+}
+
+
+bool ChartPresenter::isBackgroundVisible() const
+{
+ if (!m_background)
+ return false;
+ return m_background->isVisible();
+}
+
+void ChartPresenter::setPlotAreaBackgroundVisible(bool visible)
+{
+ createPlotAreaBackgroundItem();
+ m_plotAreaBackground->setVisible(visible);
+}
+
+bool ChartPresenter::isPlotAreaBackgroundVisible() const
+{
+ if (!m_plotAreaBackground)
+ return false;
+ return m_plotAreaBackground->isVisible();
+}
+
+void ChartPresenter::setBackgroundDropShadowEnabled(bool enabled)
+{
+ createBackgroundItem();
+ m_background->setDropShadowEnabled(enabled);
+}
+
+bool ChartPresenter::isBackgroundDropShadowEnabled() const
+{
+ if (!m_background)
+ return false;
+ return m_background->isDropShadowEnabled();
+}
+
+void ChartPresenter::setLocalizeNumbers(bool localize)
+{
+ m_localizeNumbers = localize;
+ m_layout->invalidate();
+}
+
+void ChartPresenter::setLocale(const QLocale &locale)
+{
+ m_locale = locale;
+ m_layout->invalidate();
+}
+
+AbstractChartLayout *ChartPresenter::layout()
+{
+ return m_layout;
+}
+
+QLegend *ChartPresenter::legend()
+{
+ return m_chart->legend();
+}
+
+void ChartPresenter::setVisible(bool visible)
+{
+ m_chart->setVisible(visible);
+}
+
+ChartBackground *ChartPresenter::backgroundElement()
+{
+ return m_background;
+}
+
+QAbstractGraphicsShapeItem *ChartPresenter::plotAreaElement()
+{
+ return m_plotAreaBackground;
+}
+
+QList<ChartAxisElement *> ChartPresenter::axisItems() const
+{
+ return m_axisItems;
+}
+
+QList<ChartItem *> ChartPresenter::chartItems() const
+{
+ return m_chartItems;
+}
+
+ChartTitle *ChartPresenter::titleElement()
+{
+ return m_title;
+}
+
+QRectF ChartPresenter::textBoundingRect(const QFont &font, const QString &text, qreal angle)
+{
+ static QGraphicsTextItem dummyTextItem;
+ static bool initMargin = true;
+ if (initMargin) {
+ dummyTextItem.document()->setDocumentMargin(textMargin());
+ initMargin = false;
+ }
+
+ dummyTextItem.setFont(font);
+ dummyTextItem.setHtml(text);
+ QRectF boundingRect = dummyTextItem.boundingRect();
+
+ // Take rotation into account
+ if (angle) {
+ QTransform transform;
+ transform.rotate(angle);
+ boundingRect = transform.mapRect(boundingRect);
+ }
+
+ return boundingRect;
+}
+
+// boundingRect parameter returns the rotated bounding rect of the text
+QString ChartPresenter::truncatedText(const QFont &font, const QString &text, qreal angle,
+ qreal maxWidth, qreal maxHeight, QRectF &boundingRect)
+{
+ QString truncatedString(text);
+ boundingRect = textBoundingRect(font, truncatedString, angle);
+ if (boundingRect.width() > maxWidth || boundingRect.height() > maxHeight) {
+ // It can be assumed that almost any amount of string manipulation is faster
+ // than calculating one bounding rectangle, so first prepare a list of truncated strings
+ // to try.
+ static QRegExp truncateMatcher(QStringLiteral("&#?[0-9a-zA-Z]*;$"));
+
+ QVector<QString> testStrings(text.length());
+ int count(0);
+ static QLatin1Char closeTag('>');
+ static QLatin1Char openTag('<');
+ static QLatin1Char semiColon(';');
+ static QLatin1String ellipsis("...");
+ while (truncatedString.length() > 1) {
+ int chopIndex(-1);
+ int chopCount(1);
+ QChar lastChar(truncatedString.at(truncatedString.length() - 1));
+
+ if (lastChar == closeTag)
+ chopIndex = truncatedString.lastIndexOf(openTag);
+ else if (lastChar == semiColon)
+ chopIndex = truncateMatcher.indexIn(truncatedString, 0);
+
+ if (chopIndex != -1)
+ chopCount = truncatedString.length() - chopIndex;
+ truncatedString.chop(chopCount);
+ testStrings[count] = truncatedString + ellipsis;
+ count++;
+ }
+
+ // Binary search for best fit
+ int minIndex(0);
+ int maxIndex(count - 1);
+ int bestIndex(count);
+ QRectF checkRect;
+
+ while (maxIndex >= minIndex) {
+ int mid = (maxIndex + minIndex) / 2;
+ checkRect = textBoundingRect(font, testStrings.at(mid), angle);
+ if (checkRect.width() > maxWidth || checkRect.height() > maxHeight) {
+ // Checked index too large, all under this are also too large
+ minIndex = mid + 1;
+ } else {
+ // Checked index fits, all over this also fit
+ maxIndex = mid - 1;
+ bestIndex = mid;
+ boundingRect = checkRect;
+ }
+ }
+ // Default to "..." if nothing fits
+ if (bestIndex == count) {
+ boundingRect = textBoundingRect(font, ellipsis, angle);
+ truncatedString = ellipsis;
+ } else {
+ truncatedString = testStrings.at(bestIndex);
+ }
+ }
+
+ return truncatedString;
+}
+
+QString ChartPresenter::numberToString(double value, char f, int prec)
+{
+ if (m_localizeNumbers)
+ return m_locale.toString(value, f, prec);
+ else
+ return QString::number(value, f, prec);
+}
+
+QString ChartPresenter::numberToString(int value)
+{
+ if (m_localizeNumbers)
+ return m_locale.toString(value);
+ else
+ return QString::number(value);
+}
+
+#include "moc_chartpresenter_p.cpp"
+
+QT_CHARTS_END_NAMESPACE