diff --git a/demos/demos.pro b/demos/demos.pro index 137da92..3660c4d 100644 --- a/demos/demos.pro +++ b/demos/demos.pro @@ -12,4 +12,5 @@ SUBDIRS += chartthemes \ qmlf1legends \ qmlcustomizations \ qmlcustommodel \ - chartviewer \ No newline at end of file + qmloscilloscope \ + chartviewer diff --git a/demos/qmloscilloscope/datasource.cpp b/demos/qmloscilloscope/datasource.cpp new file mode 100644 index 0000000..25362d6 --- /dev/null +++ b/demos/qmloscilloscope/datasource.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2012 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 Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial 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 "datasource.h" +#include +#include + +QTCOMMERCIALCHART_USE_NAMESPACE + +DataSource::DataSource(QObject *parent) : + QObject(parent), + m_index(0) +{ + const int rowCount = 5; + const int colCount = 1024; + + for (int i(0); i < rowCount; i++) { + QList points; + for (int j(0); j < colCount; j++) { + qreal x = j; + qreal y = sin(3.14159265358979 / 50 * x) + 0.5 + (qreal) rand() / (qreal) RAND_MAX; + points.append(QPointF(x, y)); + } + m_data.append(points); + } +} + +void DataSource::update(QAbstractSeries *series) +{ + QXYSeries *xySeries = qobject_cast(series); + Q_ASSERT(xySeries); + + QList points = m_data.at(m_index); +//xySeries->clear(); +//xySeries->append(points); + xySeries->replace(points); + m_index = (m_index + 1) % m_data.count(); +} diff --git a/demos/qmloscilloscope/datasource.h b/demos/qmloscilloscope/datasource.h new file mode 100644 index 0000000..f39bcfe --- /dev/null +++ b/demos/qmloscilloscope/datasource.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2012 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 Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial 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 DATASOURCE_H +#define DATASOURCE_H + +#include +#include + +QTCOMMERCIALCHART_USE_NAMESPACE + +class DataSource : public QObject +{ + Q_OBJECT +public: + explicit DataSource(QObject *parent = 0); + +signals: + +public slots: + void update(QAbstractSeries *series); + +private: + QList > m_data; + int m_index; +}; + +#endif // DATASOURCE_H diff --git a/demos/qmloscilloscope/main.cpp b/demos/qmloscilloscope/main.cpp new file mode 100644 index 0000000..a9687f9 --- /dev/null +++ b/demos/qmloscilloscope/main.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2012 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 Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial 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 +#include +#include +#include +#include "qmlapplicationviewer.h" +#include "datasource.h" + +Q_DECL_EXPORT int main(int argc, char *argv[]) +{ + QScopedPointer app(createApplication(argc, argv)); + QScopedPointer viewer(QmlApplicationViewer::create()); + + DataSource dataSource; + viewer->rootContext()->setContextProperty("dataSource", &dataSource); + + viewer->setOrientation(QmlApplicationViewer::ScreenOrientationAuto); + viewer->setSource(QUrl("qrc:/qml/qmloscilloscope/main.qml")); + viewer->setViewport(new QGLWidget()); + viewer->showExpanded(); + + return app->exec(); +} diff --git a/demos/qmloscilloscope/qml/qmloscilloscope/main.qml b/demos/qmloscilloscope/qml/qmloscilloscope/main.qml new file mode 100644 index 0000000..0a17e98 --- /dev/null +++ b/demos/qmloscilloscope/qml/qmloscilloscope/main.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2012 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 Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial 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$ +** +****************************************************************************/ + +import QtQuick 1.0 +import QtCommercial.Chart 1.0 + +Rectangle { + width: 400 + height: 300 + + ChartView { + id: chartView + anchors.fill: parent + title: "Oscilloscope" + animationOptions: ChartView.NoAnimation + + ValuesAxis { + id: axisY + min: -1 + max: 3 + } + + ValuesAxis { + id: axisX + min: 0 + max: 1000 + } + + LineSeries { + id: lineSeries1 + name: "signal 1" + } + LineSeries { + id: lineSeries2 + name: "signal 2" + } + } + + Timer { + interval: 16 // 60 Hz + running: true + repeat: true + onTriggered: { + dataSource.update(lineSeries1); + dataSource.update(lineSeries2); + } + } + + Component.onCompleted: { + chartView.setAxisX(axisX, lineSeries1); + chartView.setAxisY(axisY, lineSeries1); + chartView.setAxisX(axisX, lineSeries2); + chartView.setAxisY(axisY, lineSeries2); + } +} diff --git a/demos/qmloscilloscope/qmlapplicationviewer/qmlapplicationviewer.cpp b/demos/qmloscilloscope/qmlapplicationviewer/qmlapplicationviewer.cpp new file mode 100644 index 0000000..8ba6e88 --- /dev/null +++ b/demos/qmloscilloscope/qmlapplicationviewer/qmlapplicationviewer.cpp @@ -0,0 +1,200 @@ +// checksum 0x78c version 0x60010 +/* + This file was generated by the Qt Quick Application wizard of Qt Creator. + QmlApplicationViewer is a convenience class containing mobile device specific + code such as screen orientation handling. Also QML paths and debugging are + handled here. + It is recommended not to modify this file, since newer versions of Qt Creator + may offer an updated version of it. +*/ + +#include "qmlapplicationviewer.h" + +#include +#include +#include +#include +#include +#include + +#include // MEEGO_EDITION_HARMATTAN + +#ifdef HARMATTAN_BOOSTER +#include +#endif + +#if defined(QMLJSDEBUGGER) && QT_VERSION < 0x040800 + +#include + +#if !defined(NO_JSDEBUGGER) +#include +#endif +#if !defined(NO_QMLOBSERVER) +#include +#endif + +// Enable debugging before any QDeclarativeEngine is created +struct QmlJsDebuggingEnabler +{ + QmlJsDebuggingEnabler() + { + QDeclarativeDebugHelper::enableDebugging(); + } +}; + +// Execute code in constructor before first QDeclarativeEngine is instantiated +static QmlJsDebuggingEnabler enableDebuggingHelper; + +#endif // QMLJSDEBUGGER + +class QmlApplicationViewerPrivate +{ + QmlApplicationViewerPrivate(QDeclarativeView *view_) : view(view_) {} + + QString mainQmlFile; + QDeclarativeView *view; + friend class QmlApplicationViewer; + QString adjustPath(const QString &path); +}; + +QString QmlApplicationViewerPrivate::adjustPath(const QString &path) +{ +#ifdef Q_OS_UNIX +#ifdef Q_OS_MAC + if (!QDir::isAbsolutePath(path)) + return QCoreApplication::applicationDirPath() + + QLatin1String("/../Resources/") + path; +#else + QString pathInInstallDir; + const QString applicationDirPath = QCoreApplication::applicationDirPath(); + pathInInstallDir = QString::fromAscii("%1/../%2").arg(applicationDirPath, path); + + if (QFileInfo(pathInInstallDir).exists()) + return pathInInstallDir; +#endif +#endif + return path; +} + +QmlApplicationViewer::QmlApplicationViewer(QWidget *parent) + : QDeclarativeView(parent) + , d(new QmlApplicationViewerPrivate(this)) +{ + connect(engine(), SIGNAL(quit()), SLOT(close())); + setResizeMode(QDeclarativeView::SizeRootObjectToView); + // Qt versions prior to 4.8.0 don't have QML/JS debugging services built in +#if defined(QMLJSDEBUGGER) && QT_VERSION < 0x040800 +#if !defined(NO_JSDEBUGGER) + new QmlJSDebugger::JSDebuggerAgent(d->view->engine()); +#endif +#if !defined(NO_QMLOBSERVER) + new QmlJSDebugger::QDeclarativeViewObserver(d->view, d->view); +#endif +#endif +} + +QmlApplicationViewer::QmlApplicationViewer(QDeclarativeView *view, QWidget *parent) + : QDeclarativeView(parent) + , d(new QmlApplicationViewerPrivate(view)) +{ + connect(view->engine(), SIGNAL(quit()), view, SLOT(close())); + view->setResizeMode(QDeclarativeView::SizeRootObjectToView); + // Qt versions prior to 4.8.0 don't have QML/JS debugging services built in +#if defined(QMLJSDEBUGGER) && QT_VERSION < 0x040800 +#if !defined(NO_JSDEBUGGER) + new QmlJSDebugger::JSDebuggerAgent(d->view->engine()); +#endif +#if !defined(NO_QMLOBSERVER) + new QmlJSDebugger::QDeclarativeViewObserver(d->view, d->view); +#endif +#endif +} + +QmlApplicationViewer::~QmlApplicationViewer() +{ + delete d; +} + +QmlApplicationViewer *QmlApplicationViewer::create() +{ +#ifdef HARMATTAN_BOOSTER + return new QmlApplicationViewer(MDeclarativeCache::qDeclarativeView(), 0); +#else + return new QmlApplicationViewer(); +#endif +} + +void QmlApplicationViewer::setMainQmlFile(const QString &file) +{ + d->mainQmlFile = d->adjustPath(file); + d->view->setSource(QUrl::fromLocalFile(d->mainQmlFile)); +} + +void QmlApplicationViewer::addImportPath(const QString &path) +{ + d->view->engine()->addImportPath(d->adjustPath(path)); +} + +void QmlApplicationViewer::setOrientation(ScreenOrientation orientation) +{ +#if defined(Q_OS_SYMBIAN) + // If the version of Qt on the device is < 4.7.2, that attribute won't work + if (orientation != ScreenOrientationAuto) { + const QStringList v = QString::fromAscii(qVersion()).split(QLatin1Char('.')); + if (v.count() == 3 && (v.at(0).toInt() << 16 | v.at(1).toInt() << 8 | v.at(2).toInt()) < 0x040702) { + qWarning("Screen orientation locking only supported with Qt 4.7.2 and above"); + return; + } + } +#endif // Q_OS_SYMBIAN + + Qt::WidgetAttribute attribute; + switch (orientation) { +#if QT_VERSION < 0x040702 + // Qt < 4.7.2 does not yet have the Qt::WA_*Orientation attributes + case ScreenOrientationLockPortrait: + attribute = static_cast(128); + break; + case ScreenOrientationLockLandscape: + attribute = static_cast(129); + break; + default: + case ScreenOrientationAuto: + attribute = static_cast(130); + break; +#else // QT_VERSION < 0x040702 + case ScreenOrientationLockPortrait: + attribute = Qt::WA_LockPortraitOrientation; + break; + case ScreenOrientationLockLandscape: + attribute = Qt::WA_LockLandscapeOrientation; + break; + default: + case ScreenOrientationAuto: + attribute = Qt::WA_AutoOrientation; + break; +#endif // QT_VERSION < 0x040702 + }; + setAttribute(attribute, true); +} + +void QmlApplicationViewer::showExpanded() +{ +#if defined(Q_OS_SYMBIAN) || defined(MEEGO_EDITION_HARMATTAN) || defined(Q_WS_SIMULATOR) + d->view->showFullScreen(); +#elif defined(Q_WS_MAEMO_5) + d->view->showMaximized(); +#else + d->view->show(); +#endif +} + +QApplication *createApplication(int &argc, char **argv) +{ +#ifdef HARMATTAN_BOOSTER + return MDeclarativeCache::qApplication(argc, argv); +#else + return new QApplication(argc, argv); +#endif +} diff --git a/demos/qmloscilloscope/qmlapplicationviewer/qmlapplicationviewer.h b/demos/qmloscilloscope/qmlapplicationviewer/qmlapplicationviewer.h new file mode 100644 index 0000000..f8008f5 --- /dev/null +++ b/demos/qmloscilloscope/qmlapplicationviewer/qmlapplicationviewer.h @@ -0,0 +1,47 @@ +// checksum 0x82ed version 0x60010 +/* + This file was generated by the Qt Quick Application wizard of Qt Creator. + QmlApplicationViewer is a convenience class containing mobile device specific + code such as screen orientation handling. Also QML paths and debugging are + handled here. + It is recommended not to modify this file, since newer versions of Qt Creator + may offer an updated version of it. +*/ + +#ifndef QMLAPPLICATIONVIEWER_H +#define QMLAPPLICATIONVIEWER_H + +#include + +class QmlApplicationViewer : public QDeclarativeView +{ + Q_OBJECT + +public: + enum ScreenOrientation { + ScreenOrientationLockPortrait, + ScreenOrientationLockLandscape, + ScreenOrientationAuto + }; + + explicit QmlApplicationViewer(QWidget *parent = 0); + virtual ~QmlApplicationViewer(); + + static QmlApplicationViewer *create(); + + void setMainQmlFile(const QString &file); + void addImportPath(const QString &path); + + // Note that this will only have an effect on Symbian and Fremantle. + void setOrientation(ScreenOrientation orientation); + + void showExpanded(); + +private: + explicit QmlApplicationViewer(QDeclarativeView *view, QWidget *parent); + class QmlApplicationViewerPrivate *d; +}; + +QApplication *createApplication(int &argc, char **argv); + +#endif // QMLAPPLICATIONVIEWER_H diff --git a/demos/qmloscilloscope/qmlapplicationviewer/qmlapplicationviewer.pri b/demos/qmloscilloscope/qmlapplicationviewer/qmlapplicationviewer.pri new file mode 100644 index 0000000..567c6dc --- /dev/null +++ b/demos/qmloscilloscope/qmlapplicationviewer/qmlapplicationviewer.pri @@ -0,0 +1,13 @@ +QT += declarative + +SOURCES += $$PWD/qmlapplicationviewer.cpp +HEADERS += $$PWD/qmlapplicationviewer.h +INCLUDEPATH += $$PWD + +# Include JS debugger library if QMLJSDEBUGGER_PATH is set +!isEmpty(QMLJSDEBUGGER_PATH) { + include($$QMLJSDEBUGGER_PATH/qmljsdebugger-lib.pri) +} else { + DEFINES -= QMLJSDEBUGGER +} + diff --git a/demos/qmloscilloscope/qmloscilloscope.pro b/demos/qmloscilloscope/qmloscilloscope.pro new file mode 100644 index 0000000..bab2aec --- /dev/null +++ b/demos/qmloscilloscope/qmloscilloscope.pro @@ -0,0 +1,13 @@ +!include( ../demos.pri ) { + error( "Couldn't find the demos.pri file!" ) +} + +QT += opengl +RESOURCES += resources.qrc +SOURCES += main.cpp \ + datasource.cpp + +include(qmlapplicationviewer/qmlapplicationviewer.pri) + +HEADERS += \ + datasource.h diff --git a/demos/qmloscilloscope/resources.qrc b/demos/qmloscilloscope/resources.qrc new file mode 100644 index 0000000..52678b7 --- /dev/null +++ b/demos/qmloscilloscope/resources.qrc @@ -0,0 +1,5 @@ + + + qml/qmloscilloscope/main.qml + + diff --git a/src/splinechart/qsplineseries.cpp b/src/splinechart/qsplineseries.cpp index b6e507c..239dc3b 100644 --- a/src/splinechart/qsplineseries.cpp +++ b/src/splinechart/qsplineseries.cpp @@ -75,6 +75,7 @@ QSplineSeries::QSplineSeries(QObject *parent) : QObject::connect(this,SIGNAL(pointAdded(int)), d, SLOT(updateControlPoints())); QObject::connect(this,SIGNAL(pointRemoved(int)), d, SLOT(updateControlPoints())); QObject::connect(this,SIGNAL(pointReplaced(int)), d, SLOT(updateControlPoints())); + QObject::connect(this,SIGNAL(pointsReplaced()), d, SLOT(updateControlPoints())); } /*! diff --git a/src/xychart/qxyseries.cpp b/src/xychart/qxyseries.cpp index eb86d41..2ebcb4c 100644 --- a/src/xychart/qxyseries.cpp +++ b/src/xychart/qxyseries.cpp @@ -98,6 +98,15 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE */ /*! + \fn void QXYSeries::pointsReplaced() + Signal is emitted when all points have been replaced with another points. + \sa replace() +*/ +/*! + \qmlsignal XYSeries::onPointsReplaced() +*/ + +/*! \fn void QXYSeries::pointAdded(int index) Signal is emitted when a point has been added at \a index. \sa append(), insert() @@ -192,7 +201,6 @@ void QXYSeries::append(const QPointF &point) { Q_D(QXYSeries); d->m_points<pointAdded(d->m_points.count()-1); emit pointAdded(d->m_points.count()-1); } @@ -209,6 +217,7 @@ void QXYSeries::append(const QList &points) /*! Replaces data point \a oldX \a oldY with data point \a newX \a newY. + \sa QXYSeries::pointReplaced() */ void QXYSeries::replace(qreal oldX,qreal oldY,qreal newX,qreal newY) { @@ -217,6 +226,7 @@ void QXYSeries::replace(qreal oldX,qreal oldY,qreal newX,qreal newY) /*! Replaces \a oldPoint with \a newPoint. + \sa QXYSeries::pointReplaced() */ void QXYSeries::replace(const QPointF &oldPoint,const QPointF &newPoint) { @@ -228,6 +238,19 @@ void QXYSeries::replace(const QPointF &oldPoint,const QPointF &newPoint) } /*! + Replaces the current points with \a points. This is faster than replacing data points one by one, + or first clearing all data, and then appending the new data. Emits QXYSeries::pointsReplaced() + when the points have been replaced. + \sa QXYSeries::pointsReplaced() +*/ +void QXYSeries::replace(QList points) +{ + Q_D(QXYSeries); + d->m_points = points.toVector(); + emit pointsReplaced(); +} + +/*! Removes current \a x and \a y value. */ void QXYSeries::remove(qreal x,qreal y) @@ -246,7 +269,6 @@ void QXYSeries::remove(const QPointF &point) int index = d->m_points.indexOf(point); if(index==-1) return; d->m_points.remove(index); -// emit d->pointRemoved(index); emit pointRemoved(index); } @@ -257,7 +279,6 @@ void QXYSeries::insert(int index, const QPointF &point) { Q_D(QXYSeries); d->m_points.insert(index, point); -// emit d->pointAdded(index); emit pointAdded(index); } diff --git a/src/xychart/qxyseries.h b/src/xychart/qxyseries.h index 1257240..277bc58 100644 --- a/src/xychart/qxyseries.h +++ b/src/xychart/qxyseries.h @@ -72,12 +72,15 @@ public: void setPointsVisible(bool visible = true); bool pointsVisible() const; + void replace(QList points); + Q_SIGNALS: void clicked(const QPointF &point); void pointReplaced(int index); void pointRemoved(int index); void pointAdded(int index); void colorChanged(QColor color); + void pointsReplaced(); private: Q_DECLARE_PRIVATE(QXYSeries) diff --git a/src/xychart/xychart.cpp b/src/xychart/xychart.cpp index 557bd29..e97a360 100644 --- a/src/xychart/xychart.cpp +++ b/src/xychart/xychart.cpp @@ -42,6 +42,7 @@ m_animation(0), m_dirty(true) { QObject::connect(series, SIGNAL(pointReplaced(int)), this, SLOT(handlePointReplaced(int))); + QObject::connect(series, SIGNAL(pointsReplaced()), this, SLOT(handlePointsReplaced())); QObject::connect(series, SIGNAL(pointAdded(int)), this, SLOT(handlePointAdded(int))); QObject::connect(series, SIGNAL(pointRemoved(int)), this, SLOT(handlePointRemoved(int))); QObject::connect(this, SIGNAL(clicked(QPointF)), series, SIGNAL(clicked(QPointF))); @@ -182,6 +183,13 @@ void XYChart::handlePointReplaced(int index) updateChart(m_points,points,index); } +void XYChart::handlePointsReplaced() +{ + // All the points were replaced -> recalculate + QVector points = calculateGeometryPoints(); + updateChart(m_points, points, -1); +} + void XYChart::handleDomainUpdated() { m_minX=domain()->minX(); diff --git a/src/xychart/xychart_p.h b/src/xychart/xychart_p.h index b4bab5a..f0aba48 100644 --- a/src/xychart/xychart_p.h +++ b/src/xychart/xychart_p.h @@ -68,6 +68,7 @@ public Q_SLOTS: void handlePointAdded(int index); void handlePointRemoved(int index); void handlePointReplaced(int index); + void handlePointsReplaced(); void handleDomainUpdated(); void handleGeometryChanged(const QRectF &size); diff --git a/tests/auto/qxyseries/tst_qxyseries.cpp b/tests/auto/qxyseries/tst_qxyseries.cpp index 63e5223..0cfd891 100644 --- a/tests/auto/qxyseries/tst_qxyseries.cpp +++ b/tests/auto/qxyseries/tst_qxyseries.cpp @@ -254,27 +254,37 @@ void tst_QXYSeries::replace_raw_data() void tst_QXYSeries::replace_raw() { QFETCH(QList, points); - QSignalSpy replacedSpy(m_series, SIGNAL(pointReplaced(int))); + QSignalSpy pointReplacedSpy(m_series, SIGNAL(pointReplaced(int))); + QSignalSpy pointsReplacedSpy(m_series, SIGNAL(pointsReplaced())); m_series->append(points); - TRY_COMPARE(replacedSpy.count(), 0); + TRY_COMPARE(pointReplacedSpy.count(), 0); + TRY_COMPARE(pointsReplacedSpy.count(), 0); QCOMPARE(m_series->points(), points); foreach(const QPointF& point, points) m_series->replace(point.x(),point.y(),point.x(),0); - TRY_COMPARE(replacedSpy.count(), points.count()); + TRY_COMPARE(pointReplacedSpy.count(), points.count()); + TRY_COMPARE(pointsReplacedSpy.count(), 0); // Replace a point that does not exist m_series->replace(-123, 999, 0, 0); - TRY_COMPARE(replacedSpy.count(), points.count()); + TRY_COMPARE(pointReplacedSpy.count(), points.count()); + TRY_COMPARE(pointsReplacedSpy.count(), 0); QList newPoints = m_series->points(); - QCOMPARE(newPoints.count(), points.count()); - for(int i =0 ; i allPoints; + for (int i = 0; i < 10; i++) + allPoints.append(QPointF(i, (qreal) rand() / (qreal) RAND_MAX)); + m_series->replace(allPoints); + TRY_COMPARE(pointReplacedSpy.count(), points.count()); + TRY_COMPARE(pointsReplacedSpy.count(), 1); }