summaryrefslogtreecommitdiffstats
path: root/INSTALL
Commit message (Expand)AuthorAgeFilesLines
* Fix links to docs in INSTALL and READMEJason McDonald2009-11-251-7/+7
* Update INSTALL and README + friends for the everywhere packageJason McDonald2009-11-091-145/+11
* Remove incorrect statement from INSTALL file.Jason McDonald2009-10-061-3/+1
* Add INSTALL file.Jason McDonald2009-09-211-0/+150
t: main; rotation: 90 + rotationDelta; width: main.baseHeight; height: main.baseWidth } }, State { name: "orientation " + Orientation.PortraitInverted - PropertyChanges { target: main; rotation: 180; } - PropertyChanges { target: rotateButton; operation: rotateRight } + PropertyChanges { target: main; rotation: 180 + rotationDelta; } }, State { name: "orientation " + Orientation.LandscapeInverted - PropertyChanges { target: main; rotation: 270; width: window.height; height: window.width } - PropertyChanges { target: rotateButton; operation: rotateLeft } + PropertyChanges { target: main; rotation: 270 + rotationDelta; width: main.baseHeight; height: main.baseWidth } } ] transitions: Transition { SequentialAnimation { - PropertyAction { target: rotateButton; property: "operation" } RotationAnimation { direction: RotationAnimation.Shortest; duration: 300; easing.type: Easing.InOutQuint } NumberAnimation { properties: "x,y,width,height"; duration: 300; easing.type: Easing.InOutQuint } } -- cgit v0.12 From 54ca4ebba8aa5c26516424a952f8e6d4ab919f6e Mon Sep 17 00:00:00 2001 From: Joona Petrell Date: Tue, 2 Nov 2010 19:44:06 +1000 Subject: Make it possible to add your own graphics scene to QDeclarativeView Task-number: QTBUG-14771 Reviewed-by: Martin Jones --- src/declarative/util/qdeclarativeview.cpp | 24 ++++++++++++---------- .../qdeclarativeview/tst_qdeclarativeview.cpp | 21 +++++++++++++++++++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/declarative/util/qdeclarativeview.cpp b/src/declarative/util/qdeclarativeview.cpp index 2381172..6864a8b 100644 --- a/src/declarative/util/qdeclarativeview.cpp +++ b/src/declarative/util/qdeclarativeview.cpp @@ -76,7 +76,7 @@ DEFINE_BOOL_CONFIG_OPTION(frameRateDebug, QML_SHOW_FRAMERATE) class QDeclarativeScene : public QGraphicsScene { public: - QDeclarativeScene(); + QDeclarativeScene(QObject *parent = 0); protected: virtual void keyPressEvent(QKeyEvent *); @@ -87,7 +87,7 @@ protected: virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *); }; -QDeclarativeScene::QDeclarativeScene() +QDeclarativeScene::QDeclarativeScene(QObject *parent) : QGraphicsScene(parent) { } @@ -131,7 +131,8 @@ class QDeclarativeViewPrivate : public QGraphicsViewPrivate, public QDeclarative Q_DECLARE_PUBLIC(QDeclarativeView) public: QDeclarativeViewPrivate() - : root(0), declarativeItemRoot(0), graphicsWidgetRoot(0), component(0), resizeMode(QDeclarativeView::SizeViewToRootObject), initialSize(0,0) {} + : root(0), declarativeItemRoot(0), graphicsWidgetRoot(0), component(0), + resizeMode(QDeclarativeView::SizeViewToRootObject), initialSize(0,0) {} ~QDeclarativeViewPrivate() { delete root; delete engine; } void execute(); void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry); @@ -154,8 +155,6 @@ public: QElapsedTimer frameTimer; void init(); - - QDeclarativeScene scene; }; void QDeclarativeViewPrivate::execute() @@ -233,6 +232,9 @@ void QDeclarativeViewPrivate::itemGeometryChanged(QDeclarativeItem *resizeItem, you can connect to the statusChanged() signal and monitor for QDeclarativeView::Error. The errors are available via QDeclarativeView::errors(). + If you're using your own QGraphicsScene-based scene with QDeclarativeView, remember to + enable scene's sticky focus mode and to set itemIndexMethod to QGraphicsScene::NoIndex. + \sa {Integrating QML with existing Qt UI code}, {Using QML in C++ Applications} */ @@ -276,7 +278,7 @@ void QDeclarativeViewPrivate::init() { Q_Q(QDeclarativeView); engine = new QDeclarativeEngine(); - q->setScene(&scene); + q->setScene(new QDeclarativeScene(q)); q->setOptimizationFlags(QGraphicsView::DontSavePainterState); q->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -285,11 +287,11 @@ void QDeclarativeViewPrivate::init() // These seem to give the best performance q->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); - scene.setItemIndexMethod(QGraphicsScene::NoIndex); + q->scene()->setItemIndexMethod(QGraphicsScene::NoIndex); q->viewport()->setFocusPolicy(Qt::NoFocus); q->setFocusPolicy(Qt::StrongFocus); - scene.setStickyFocus(true); //### needed for correct focus handling + q->scene()->setStickyFocus(true); //### needed for correct focus handling } /*! @@ -555,14 +557,14 @@ void QDeclarativeView::continueExecute() void QDeclarativeView::setRootObject(QObject *obj) { Q_D(QDeclarativeView); - if (d->root == obj) + if (d->root == obj || !scene()) return; if (QDeclarativeItem *declarativeItem = qobject_cast(obj)) { - d->scene.addItem(declarativeItem); + scene()->addItem(declarativeItem); d->root = declarativeItem; d->declarativeItemRoot = declarativeItem; } else if (QGraphicsObject *graphicsObject = qobject_cast(obj)) { - d->scene.addItem(graphicsObject); + scene()->addItem(graphicsObject); d->root = graphicsObject; if (graphicsObject->isWidget()) { d->graphicsWidgetRoot = static_cast(graphicsObject); diff --git a/tests/auto/declarative/qdeclarativeview/tst_qdeclarativeview.cpp b/tests/auto/declarative/qdeclarativeview/tst_qdeclarativeview.cpp index 9ac79e4..efa5a9b 100644 --- a/tests/auto/declarative/qdeclarativeview/tst_qdeclarativeview.cpp +++ b/tests/auto/declarative/qdeclarativeview/tst_qdeclarativeview.cpp @@ -60,6 +60,7 @@ public: tst_QDeclarativeView(); private slots: + void scene(); void resizemodedeclarativeitem(); void resizemodegraphicswidget(); void errors(); @@ -74,6 +75,26 @@ tst_QDeclarativeView::tst_QDeclarativeView() { } +void tst_QDeclarativeView::scene() +{ + // QTBUG-14771 + QGraphicsScene scene; + scene.setItemIndexMethod(QGraphicsScene::NoIndex); + scene.setStickyFocus(true); + + QDeclarativeView *view = new QDeclarativeView(); + QVERIFY(view); + QVERIFY(view->scene()); + view->setScene(&scene); + QCOMPARE(view->scene(), &scene); + + view->setSource(QUrl::fromLocalFile(SRCDIR "/data/resizemodedeclarativeitem.qml")); + QDeclarativeItem* declarativeItem = qobject_cast(view->rootObject()); + QVERIFY(declarativeItem); + QVERIFY(scene.items().count() > 0); + QCOMPARE(scene.items().at(0), declarativeItem); +} + void tst_QDeclarativeView::resizemodedeclarativeitem() { QWidget window; -- cgit v0.12 From 1d228b5d532dc158d1c9ac3347168cdc11378779 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Thu, 11 Nov 2010 13:41:38 +1000 Subject: Performance fix We weren't always taking advantage of the property cache for model data when we should have been. Reviewed-by: Martin Jones --- src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp index 1f01a45..9b5a072 100644 --- a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp +++ b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp @@ -557,8 +557,9 @@ QDeclarativeVisualDataModelData::~QDeclarativeVisualDataModelData() void QDeclarativeVisualDataModelData::ensureProperties() { QDeclarativeVisualDataModelPrivate *modelPriv = QDeclarativeVisualDataModelPrivate::get(m_model); - if (modelPriv->m_metaDataCacheable && !modelPriv->m_metaDataCreated) { - modelPriv->createMetaData(); + if (modelPriv->m_metaDataCacheable) { + if (!modelPriv->m_metaDataCreated) + modelPriv->createMetaData(); if (modelPriv->m_metaDataCreated) m_meta->setCached(true); } -- cgit v0.12 From af60542fc4214cc716ffb1bdc46e2e7f6b5a6b8a Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Fri, 12 Nov 2010 13:02:58 +1000 Subject: Add 'cached' property to Image element Setting cached to false is useful when dealing with large images, to make sure that they aren't cached at the expense of small 'ui element' images. Task-number: QTBUG-7300 Reviewed-by: Aaron Kennedy --- .../photoviewer/PhotoViewerCore/PhotoDelegate.qml | 4 +-- .../graphicsitems/qdeclarativeborderimage.cpp | 14 +++++++++-- .../graphicsitems/qdeclarativeimage.cpp | 9 +++++++ .../graphicsitems/qdeclarativeimagebase.cpp | 25 ++++++++++++++++++- .../graphicsitems/qdeclarativeimagebase_p.h | 5 ++++ .../graphicsitems/qdeclarativeimagebase_p_p.h | 4 ++- src/declarative/util/qdeclarativepixmapcache.cpp | 22 ++++++++-------- src/declarative/util/qdeclarativepixmapcache_p.h | 12 +++++++-- .../qdeclarativeimage/tst_qdeclarativeimage.cpp | 29 +++++++++++++++------- 9 files changed, 97 insertions(+), 27 deletions(-) diff --git a/demos/declarative/photoviewer/PhotoViewerCore/PhotoDelegate.qml b/demos/declarative/photoviewer/PhotoViewerCore/PhotoDelegate.qml index 5948b5d..856a2c7 100644 --- a/demos/declarative/photoviewer/PhotoViewerCore/PhotoDelegate.qml +++ b/demos/declarative/photoviewer/PhotoViewerCore/PhotoDelegate.qml @@ -88,11 +88,11 @@ Package { } BusyIndicator { anchors.centerIn: parent; on: originalImage.status != Image.Ready } Image { - id: originalImage; smooth: true; source: "http://" + Script.getImagePath(content) + id: originalImage; smooth: true; source: "http://" + Script.getImagePath(content); cached: false fillMode: Image.PreserveAspectFit; width: photoWrapper.width; height: photoWrapper.height } Image { - id: hqImage; smooth: true; source: ""; visible: false + id: hqImage; smooth: true; source: ""; visible: false; cached: false fillMode: Image.PreserveAspectFit; width: photoWrapper.width; height: photoWrapper.height } Binding { diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp index 649c8fb..4e35f87 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp @@ -290,7 +290,12 @@ void QDeclarativeBorderImage::load() } } else { - d->pix.load(qmlEngine(this), d->url, d->async); + QDeclarativePixmap::Options options; + if (d->async) + options |= QDeclarativePixmap::Asynchronous; + if (d->cached) + options |= QDeclarativePixmap::Cached; + d->pix.load(qmlEngine(this), d->url, options); if (d->pix.isLoading()) { d->pix.connectFinished(this, SLOT(requestFinished())); @@ -413,7 +418,12 @@ void QDeclarativeBorderImage::setGridScaledImage(const QDeclarativeGridScaledIma d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl())); - d->pix.load(qmlEngine(this), d->sciurl, d->async); + QDeclarativePixmap::Options options; + if (d->async) + options |= QDeclarativePixmap::Asynchronous; + if (d->cached) + options |= QDeclarativePixmap::Cached; + d->pix.load(qmlEngine(this), d->sciurl, options); if (d->pix.isLoading()) { static int thisRequestProgress = -1; diff --git a/src/declarative/graphicsitems/qdeclarativeimage.cpp b/src/declarative/graphicsitems/qdeclarativeimage.cpp index 3b08a9b..c9eb258 100644 --- a/src/declarative/graphicsitems/qdeclarativeimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimage.cpp @@ -458,6 +458,15 @@ QRectF QDeclarativeImage::boundingRect() const are always loaded asynchonously. */ +/*! + \qmlproperty bool Image::cached + \since Quick 1.1 + + Specifies that the image should be cached. The default value is + true. Setting \a cached to false is useful when dealing with large images, + to make sure that they aren't cached at the expense of small 'ui element' images. +*/ + void QDeclarativeImage::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) { Q_D(QDeclarativeImage); diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp index c3bac2d..37b0734 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp @@ -128,6 +128,24 @@ QSize QDeclarativeImageBase::sourceSize() const return QSize(width != -1 ? width : implicitWidth(), height != -1 ? height : implicitHeight()); } +bool QDeclarativeImageBase::cached() const +{ + Q_D(const QDeclarativeImageBase); + return d->cached; +} + +void QDeclarativeImageBase::setCached(bool cached) +{ + Q_D(QDeclarativeImageBase); + if (d->cached == cached) + return; + + d->cached = cached; + emit cachedChanged(); + if (isComponentComplete()) + load(); +} + void QDeclarativeImageBase::load() { Q_D(QDeclarativeImageBase); @@ -143,7 +161,12 @@ void QDeclarativeImageBase::load() pixmapChange(); update(); } else { - d->pix.load(qmlEngine(this), d->url, d->explicitSourceSize ? sourceSize() : QSize(), d->async); + QDeclarativePixmap::Options options; + if (d->async) + options |= QDeclarativePixmap::Asynchronous; + if (d->cached) + options |= QDeclarativePixmap::Cached; + d->pix.load(qmlEngine(this), d->url, d->explicitSourceSize ? sourceSize() : QSize(), options); if (d->pix.isLoading()) { d->progress = 0.0; diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p.h index 68eb8d0..d25f7c3 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase_p.h +++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p.h @@ -58,6 +58,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeImageBase : public QDeclarativeItem Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged) + Q_PROPERTY(bool cached READ cached WRITE setCached NOTIFY cachedChanged) // ### VERSIONING: Only in QtQuick 1.1 Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize NOTIFY sourceSizeChanged) public: @@ -72,6 +73,9 @@ public: bool asynchronous() const; void setAsynchronous(bool); + bool cached() const; + void setCached(bool); + virtual void setSourceSize(const QSize&); QSize sourceSize() const; @@ -81,6 +85,7 @@ Q_SIGNALS: void statusChanged(QDeclarativeImageBase::Status); void progressChanged(qreal progress); void asynchronousChanged(); + void cachedChanged(); protected: virtual void load(); diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h index 3d23ba9..a539649 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h @@ -70,7 +70,8 @@ public: : status(QDeclarativeImageBase::Null), progress(0.0), explicitSourceSize(false), - async(false) + async(false), + cached(true) { QGraphicsItemPrivate::flags = QGraphicsItemPrivate::flags & ~QGraphicsItem::ItemHasNoContents; } @@ -82,6 +83,7 @@ public: QSize sourcesize; bool explicitSourceSize : 1; bool async : 1; + bool cached : 1; }; QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp index a07b1bb..5ef568f 100644 --- a/src/declarative/util/qdeclarativepixmapcache.cpp +++ b/src/declarative/util/qdeclarativepixmapcache.cpp @@ -959,20 +959,20 @@ QRect QDeclarativePixmap::rect() const void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url) { - load(engine, url, QSize(), false); + load(engine, url, QSize(), QDeclarativePixmap::Cached); } -void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, bool async) +void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, QDeclarativePixmap::Options options) { - load(engine, url, QSize(), async); + load(engine, url, QSize(), options); } void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const QSize &size) { - load(engine, url, size, false); + load(engine, url, size, QDeclarativePixmap::Cached); } -void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const QSize &requestSize, bool async) +void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const QSize &requestSize, QDeclarativePixmap::Options options) { if (d) { d->release(); d = 0; } @@ -982,19 +982,20 @@ void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const QHash::Iterator iter = store->m_cache.find(key); if (iter == store->m_cache.end()) { - if (async) { + if (options & QDeclarativePixmap::Asynchronous) { // pixmaps can only be loaded synchronously if (url.scheme() == QLatin1String("image") && QDeclarativeEnginePrivate::get(engine)->getImageProviderType(url) == QDeclarativeImageProvider::Pixmap) { - async = false; + options &= ~QDeclarativePixmap::Asynchronous; } } - if (!async) { + if (!(options & QDeclarativePixmap::Asynchronous)) { bool ok = false; d = createPixmapDataSync(engine, url, requestSize, &ok); if (ok) { - d->addToCache(); + if (options & QDeclarativePixmap::Cached) + d->addToCache(); return; } if (d) // loadable, but encountered error while loading @@ -1007,7 +1008,8 @@ void QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url, const QDeclarativePixmapReader *reader = QDeclarativePixmapReader::instance(engine); d = new QDeclarativePixmapData(url, requestSize); - d->addToCache(); + if (options & QDeclarativePixmap::Cached) + d->addToCache(); d->reply = reader->getImage(d); } else { diff --git a/src/declarative/util/qdeclarativepixmapcache_p.h b/src/declarative/util/qdeclarativepixmapcache_p.h index 2e83cc4..9e1016f 100644 --- a/src/declarative/util/qdeclarativepixmapcache_p.h +++ b/src/declarative/util/qdeclarativepixmapcache_p.h @@ -66,6 +66,12 @@ public: enum Status { Null, Ready, Error, Loading }; + enum Option { + Asynchronous = 0x00000001, + Cached = 0x00000002 + }; + Q_DECLARE_FLAGS(Options, Option) + bool isNull() const; bool isReady() const; bool isError() const; @@ -85,9 +91,9 @@ public: inline operator const QPixmap &() const; void load(QDeclarativeEngine *, const QUrl &); - void load(QDeclarativeEngine *, const QUrl &, bool); + void load(QDeclarativeEngine *, const QUrl &, QDeclarativePixmap::Options options); void load(QDeclarativeEngine *, const QUrl &, const QSize &); - void load(QDeclarativeEngine *, const QUrl &, const QSize &, bool); + void load(QDeclarativeEngine *, const QUrl &, const QSize &, QDeclarativePixmap::Options options); void clear(); void clear(QObject *); @@ -107,6 +113,8 @@ inline QDeclarativePixmap::operator const QPixmap &() const return pixmap(); } +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePixmap::Options) + QT_END_NAMESPACE QT_END_HEADER diff --git a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp index bf779ad..3cee976 100644 --- a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp +++ b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp @@ -123,19 +123,21 @@ void tst_qdeclarativeimage::imageSource_data() QTest::addColumn("height"); QTest::addColumn("remote"); QTest::addColumn("async"); + QTest::addColumn("cached"); QTest::addColumn("error"); - QTest::newRow("local") << QUrl::fromLocalFile(SRCDIR "/data/colors.png").toString() << 120.0 << 120.0 << false << false << ""; - QTest::newRow("local async") << QUrl::fromLocalFile(SRCDIR "/data/colors1.png").toString() << 120.0 << 120.0 << false << true << ""; + QTest::newRow("local") << QUrl::fromLocalFile(SRCDIR "/data/colors.png").toString() << 120.0 << 120.0 << false << false << true << ""; + QTest::newRow("local no cache") << QUrl::fromLocalFile(SRCDIR "/data/colors.png").toString() << 120.0 << 120.0 << false << false << false << ""; + QTest::newRow("local async") << QUrl::fromLocalFile(SRCDIR "/data/colors1.png").toString() << 120.0 << 120.0 << false << true << true << ""; QTest::newRow("local not found") << QUrl::fromLocalFile(SRCDIR "/data/no-such-file.png").toString() << 0.0 << 0.0 << false - << false << "file::2:1: QML Image: Cannot open: " + QUrl::fromLocalFile(SRCDIR "/data/no-such-file.png").toString(); + << false << true << "file::2:1: QML Image: Cannot open: " + QUrl::fromLocalFile(SRCDIR "/data/no-such-file.png").toString(); QTest::newRow("local async not found") << QUrl::fromLocalFile(SRCDIR "/data/no-such-file-1.png").toString() << 0.0 << 0.0 << false - << true << "file::2:1: QML Image: Cannot open: " + QUrl::fromLocalFile(SRCDIR "/data/no-such-file-1.png").toString(); - QTest::newRow("remote") << SERVER_ADDR "/colors.png" << 120.0 << 120.0 << true << false << ""; - QTest::newRow("remote redirected") << SERVER_ADDR "/oldcolors.png" << 120.0 << 120.0 << true << false << ""; - QTest::newRow("remote svg") << SERVER_ADDR "/heart.svg" << 550.0 << 500.0 << true << false << ""; + << true << true << "file::2:1: QML Image: Cannot open: " + QUrl::fromLocalFile(SRCDIR "/data/no-such-file-1.png").toString(); + QTest::newRow("remote") << SERVER_ADDR "/colors.png" << 120.0 << 120.0 << true << false << true << ""; + QTest::newRow("remote redirected") << SERVER_ADDR "/oldcolors.png" << 120.0 << 120.0 << true << false << false << ""; + QTest::newRow("remote svg") << SERVER_ADDR "/heart.svg" << 550.0 << 500.0 << true << false << false << ""; QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << 0.0 << 0.0 << true - << false << "file::2:1: QML Image: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found"; + << false << true << "file::2:1: QML Image: Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found"; } @@ -146,6 +148,7 @@ void tst_qdeclarativeimage::imageSource() QFETCH(double, height); QFETCH(bool, remote); QFETCH(bool, async); + QFETCH(bool, cached); QFETCH(QString, error); TestHTTPServer server(SERVER_PORT); @@ -159,7 +162,8 @@ void tst_qdeclarativeimage::imageSource() QTest::ignoreMessage(QtWarningMsg, error.toUtf8()); QString componentStr = "import QtQuick 1.0\nImage { source: \"" + source + "\"; asynchronous: " - + (async ? QLatin1String("true") : QLatin1String("false")) + " }"; + + (async ? QLatin1String("true") : QLatin1String("false")) + "; cached: " + + (cached ? QLatin1String("true") : QLatin1String("false")) + " }"; QDeclarativeComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QDeclarativeImage *obj = qobject_cast(component.create()); @@ -167,6 +171,13 @@ void tst_qdeclarativeimage::imageSource() if (async) QVERIFY(obj->asynchronous() == true); + else + QVERIFY(obj->asynchronous() == false); + + if (cached) + QVERIFY(obj->cached() == true); + else + QVERIFY(obj->cached() == false); if (remote || async) QTRY_VERIFY(obj->status() == QDeclarativeImage::Loading); -- cgit v0.12 From f809dc1b16d6a56c1a2d57997748bddb313f7f4c Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 12 Nov 2010 13:44:06 +1000 Subject: Small optimization of enum detection in script. Reviewed-by: Martin Jones --- src/declarative/qml/qdeclarativetypenamescriptclass.cpp | 5 ++--- src/script/bridge/qscriptdeclarativeclass.cpp | 8 ++++++++ src/script/bridge/qscriptdeclarativeclass_p.h | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp index cba7b4a..e93aae2 100644 --- a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp +++ b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp @@ -109,9 +109,8 @@ QDeclarativeTypeNameScriptClass::queryProperty(Object *obj, const Identifier &na } else if (data->type) { - QString strName = toString(name); - - if (strName.at(0).isUpper()) { + if (startsWithUpper(name)) { + QString strName = toString(name); // Must be an enum if (data->mode == IncludeEnums) { // ### Optimize diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index 8080b9f..92248a0 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -468,6 +468,14 @@ QString QScriptDeclarativeClass::toString(const Identifier &identifier) return QString((QChar *)r->data(), r->size()); } +bool QScriptDeclarativeClass::startsWithUpper(const Identifier &identifier) +{ + JSC::UString::Rep *r = (JSC::UString::Rep *)identifier; + if (r->size() < 1) + return false; + return QChar::category(r->data()[0]) == QChar::Letter_Uppercase; +} + quint32 QScriptDeclarativeClass::toArrayIndex(const Identifier &identifier, bool *ok) { JSC::UString::Rep *r = (JSC::UString::Rep *)identifier; diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h index 420b133..fe38eeb 100644 --- a/src/script/bridge/qscriptdeclarativeclass_p.h +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -126,6 +126,7 @@ public: PersistentIdentifier createPersistentIdentifier(const Identifier &); QString toString(const Identifier &); + bool startsWithUpper(const Identifier &); quint32 toArrayIndex(const Identifier &, bool *ok); virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, -- cgit v0.12 From f2cd51abd592a4da45892e42f0d38803e7c1620e Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 16 Nov 2010 10:15:05 +1000 Subject: Treat easing.type: Easing.InOutQuad as a literal assignment, not binding This was already being done for most enum assignments, but wasn't being done for value types. This patch extends the optimization for enums in a value type. Reviewed-by: Martin Jones --- src/declarative/qml/qdeclarativecompiler.cpp | 34 ++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index b2740b8..b371f52 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -1836,14 +1836,22 @@ bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type, COMPILE_EXCEPTION(prop, tr("Unexpected object assignment")); } else if (value->value.isScript()) { // ### Check for writability - BindingReference reference; - reference.expression = value->value; - reference.property = prop; - reference.value = value; - reference.bindingContext = ctxt; - reference.bindingContext.owner++; - addBindingReference(reference); - value->type = Value::PropertyBinding; + + //optimization for . enum assignments + bool isEnumAssignment = false; + COMPILE_CHECK(testQualifiedEnumAssignment(p, obj, value, &isEnumAssignment)); + if (isEnumAssignment) { + value->type = Value::Literal; + } else { + BindingReference reference; + reference.expression = value->value; + reference.property = prop; + reference.value = value; + reference.bindingContext = ctxt; + reference.bindingContext.owner++; + addBindingReference(reference); + value->type = Value::PropertyBinding; + } } else { COMPILE_CHECK(testLiteralAssignment(p, value)); value->type = Value::Literal; @@ -2138,7 +2146,15 @@ bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop QDeclarativeType *type = 0; unit->imports().resolveType(typeName.toUtf8(), &type, 0, 0, 0, 0); - if (!type || obj->typeName != type->qmlTypeName()) + //handle enums on value types (where obj->typeName is empty) + QByteArray objTypeName = obj->typeName; + if (objTypeName.isEmpty()) { + QDeclarativeType *objType = toQmlType(obj); + if (objType) + objTypeName = objType->qmlTypeName(); + } + + if (!type || objTypeName != type->qmlTypeName()) return true; QString enumValue = parts.at(1); -- cgit v0.12 From 463786121871c7b0934949f4fcb8ef8b4d64712f Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 16 Nov 2010 15:44:11 +1000 Subject: Optimize string->color conversion in QML. Reviewed-by: Martin Jones --- src/declarative/qml/qdeclarativestringconverters.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/declarative/qml/qdeclarativestringconverters.cpp b/src/declarative/qml/qdeclarativestringconverters.cpp index 7534a2c..55fae87 100644 --- a/src/declarative/qml/qdeclarativestringconverters.cpp +++ b/src/declarative/qml/qdeclarativestringconverters.cpp @@ -136,7 +136,7 @@ QVariant QDeclarativeStringConverters::variantFromString(const QString &s, int p QColor QDeclarativeStringConverters::colorFromString(const QString &s, bool *ok) { - if (s.startsWith(QLatin1Char('#')) && s.length() == 9) { + if (s.length() == 9 && s.startsWith(QLatin1Char('#'))) { uchar a = fromHex(s, 1); uchar r = fromHex(s, 3); uchar g = fromHex(s, 5); @@ -144,9 +144,7 @@ QColor QDeclarativeStringConverters::colorFromString(const QString &s, bool *ok) if (ok) *ok = true; return QColor(r, g, b, a); } else { - QColor rv; - if (s.startsWith(QLatin1Char('#')) || QColor::colorNames().contains(s.toLower())) - rv = QColor(s); + QColor rv(s); if (ok) *ok = rv.isValid(); return rv; } -- cgit v0.12 From e8e28735046d419463e235a58a7c4c88d04163db Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 16 Nov 2010 15:46:39 +1000 Subject: Optimize test for sharable bindings. Reviewed-by: Martin Jones --- src/declarative/qml/qdeclarativecompiler.cpp | 7 ++----- src/declarative/qml/qdeclarativerewrite.cpp | 13 +++++++++++-- src/declarative/qml/qdeclarativerewrite_p.h | 3 ++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index b371f52..3e63bb1 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -2800,13 +2800,10 @@ bool QDeclarativeCompiler::completeComponentBuild() // Pre-rewrite the expression QString expression = binding.expression.asScript(); - // ### Optimize - QDeclarativeRewrite::SharedBindingTester sharableTest; - bool isSharable = sharableTest.isSharable(expression); - QDeclarativeRewrite::RewriteBinding rewriteBinding; rewriteBinding.setName('$'+binding.property->name); - expression = rewriteBinding(expression); + bool isSharable = false; + expression = rewriteBinding(expression,0,&isSharable); quint32 length = expression.length(); quint32 pc; diff --git a/src/declarative/qml/qdeclarativerewrite.cpp b/src/declarative/qml/qdeclarativerewrite.cpp index bc9a114..80b9ab2 100644 --- a/src/declarative/qml/qdeclarativerewrite.cpp +++ b/src/declarative/qml/qdeclarativerewrite.cpp @@ -62,12 +62,17 @@ bool SharedBindingTester::isSharable(const QString &code) if (!parser.statement()) return false; + return isSharable(parser.statement()); +} + +bool SharedBindingTester::isSharable(AST::Statement *statement) +{ _sharable = true; - AST::Node::acceptChild(parser.statement(), this); + AST::Node::acceptChild(statement, this); return _sharable; } -QString RewriteBinding::operator()(const QString &code, bool *ok) +QString RewriteBinding::operator()(const QString &code, bool *ok, bool *sharable) { Engine engine; NodePool pool(QString(), &engine); @@ -80,6 +85,10 @@ QString RewriteBinding::operator()(const QString &code, bool *ok) return QString(); } else { if (ok) *ok = true; + if (sharable) { + SharedBindingTester tester; + *sharable = tester.isSharable(parser.statement()); + } } return rewrite(code, 0, parser.statement()); } diff --git a/src/declarative/qml/qdeclarativerewrite_p.h b/src/declarative/qml/qdeclarativerewrite_p.h index 6f3c46e..40c8321 100644 --- a/src/declarative/qml/qdeclarativerewrite_p.h +++ b/src/declarative/qml/qdeclarativerewrite_p.h @@ -68,6 +68,7 @@ class SharedBindingTester : protected AST::Visitor bool _sharable; public: bool isSharable(const QString &code); + bool isSharable(AST::Statement *statement); virtual bool visit(AST::FunctionDeclaration *) { _sharable = false; return false; } virtual bool visit(AST::FunctionExpression *) { _sharable = false; return false; } @@ -81,7 +82,7 @@ class RewriteBinding: protected AST::Visitor QByteArray _name; public: - QString operator()(const QString &code, bool *ok = 0); + QString operator()(const QString &code, bool *ok = 0, bool *sharable = 0); //name of the function: used for the debugger void setName(const QByteArray &name) { _name = name; } -- cgit v0.12 From 03c671e557a59a2c908cb8241c7ad5c31536841d Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Thu, 18 Nov 2010 14:26:33 +1000 Subject: Optimize binding rewrites. Use the existing AST rather than recreating it. Task-number: QTBUG-15331 Reviewed-by: Aaron Kennedy --- src/declarative/qml/qdeclarativecompiler.cpp | 2 +- src/declarative/qml/qdeclarativerewrite.cpp | 53 ++++++++++++++++++++++++++-- src/declarative/qml/qdeclarativerewrite_p.h | 3 +- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 3e63bb1..d590d11 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -2803,7 +2803,7 @@ bool QDeclarativeCompiler::completeComponentBuild() QDeclarativeRewrite::RewriteBinding rewriteBinding; rewriteBinding.setName('$'+binding.property->name); bool isSharable = false; - expression = rewriteBinding(expression,0,&isSharable); + expression = rewriteBinding(binding.expression.asAST(), expression, &isSharable); quint32 length = expression.length(); quint32 pc; diff --git a/src/declarative/qml/qdeclarativerewrite.cpp b/src/declarative/qml/qdeclarativerewrite.cpp index 80b9ab2..219674f 100644 --- a/src/declarative/qml/qdeclarativerewrite.cpp +++ b/src/declarative/qml/qdeclarativerewrite.cpp @@ -65,10 +65,10 @@ bool SharedBindingTester::isSharable(const QString &code) return isSharable(parser.statement()); } -bool SharedBindingTester::isSharable(AST::Statement *statement) +bool SharedBindingTester::isSharable(AST::Node *node) { _sharable = true; - AST::Node::acceptChild(statement, this); + AST::Node::acceptChild(node, this); return _sharable; } @@ -93,6 +93,55 @@ QString RewriteBinding::operator()(const QString &code, bool *ok, bool *sharable return rewrite(code, 0, parser.statement()); } +QString RewriteBinding::operator()(QDeclarativeJS::AST::Node *node, const QString &code, bool *sharable) +{ + if (!node) + return code; + + if (sharable) { + SharedBindingTester tester; + *sharable = tester.isSharable(node); + } + + QDeclarativeJS::AST::ExpressionNode *expression = node->expressionCast(); + QDeclarativeJS::AST::Statement *statement = node->statementCast(); + if(!expression && !statement) + return code; + + TextWriter w; + _writer = &w; + _position = expression ? expression->firstSourceLocation().begin() : statement->firstSourceLocation().begin(); + _inLoop = 0; + + accept(node); + + unsigned startOfStatement = 0; + unsigned endOfStatement = (expression ? expression->lastSourceLocation().end() : statement->lastSourceLocation().end()) - _position; + + QString startString = QLatin1String("(function ") + QString::fromUtf8(_name) + QLatin1String("() { "); + if (expression) + startString += QLatin1String("return "); + _writer->replace(startOfStatement, 0, startString); + _writer->replace(endOfStatement, 0, QLatin1String(" })")); + + if (rewriteDump()) { + qWarning() << "============================================================="; + qWarning() << "Rewrote:"; + qWarning() << qPrintable(code); + } + + QString codeCopy = code; + w.write(&codeCopy); + + if (rewriteDump()) { + qWarning() << "To:"; + qWarning() << qPrintable(code); + qWarning() << "============================================================="; + } + + return codeCopy; +} + void RewriteBinding::accept(AST::Node *node) { AST::Node::acceptChild(node, this); diff --git a/src/declarative/qml/qdeclarativerewrite_p.h b/src/declarative/qml/qdeclarativerewrite_p.h index 40c8321..310ef3c 100644 --- a/src/declarative/qml/qdeclarativerewrite_p.h +++ b/src/declarative/qml/qdeclarativerewrite_p.h @@ -68,7 +68,7 @@ class SharedBindingTester : protected AST::Visitor bool _sharable; public: bool isSharable(const QString &code); - bool isSharable(AST::Statement *statement); + bool isSharable(AST::Node *Node); virtual bool visit(AST::FunctionDeclaration *) { _sharable = false; return false; } virtual bool visit(AST::FunctionExpression *) { _sharable = false; return false; } @@ -83,6 +83,7 @@ class RewriteBinding: protected AST::Visitor public: QString operator()(const QString &code, bool *ok = 0, bool *sharable = 0); + QString operator()(QDeclarativeJS::AST::Node *node, const QString &code, bool *sharable = 0); //name of the function: used for the debugger void setName(const QByteArray &name) { _name = name; } -- cgit v0.12 From 3d100ab29820b4dcf14afbcadb05d0bf40fdacbc Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 29 Oct 2010 15:44:21 +1000 Subject: Add a private high-performance timer for profiling. --- src/declarative/qml/qml.pri | 9 +- src/declarative/qml/qperformancetimer.cpp | 226 +++++++++++++++++++++ src/declarative/qml/qperformancetimer_p.h | 79 +++++++ .../qperformancetimer/qperformancetimer.pro | 7 + .../qperformancetimer/tst_qperformancetimer.cpp | 68 +++++++ .../qperformancetimer/qperformancetimer.pro | 8 + .../qperformancetimer/tst_qperformancetimer.cpp | 89 ++++++++ 7 files changed, 484 insertions(+), 2 deletions(-) create mode 100644 src/declarative/qml/qperformancetimer.cpp create mode 100644 src/declarative/qml/qperformancetimer_p.h create mode 100644 tests/auto/declarative/qperformancetimer/qperformancetimer.pro create mode 100644 tests/auto/declarative/qperformancetimer/tst_qperformancetimer.cpp create mode 100644 tests/benchmarks/declarative/qperformancetimer/qperformancetimer.pro create mode 100644 tests/benchmarks/declarative/qperformancetimer/tst_qperformancetimer.cpp diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 66b69f9..bf9e54a 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -55,7 +55,8 @@ SOURCES += \ $$PWD/qdeclarativedirparser.cpp \ $$PWD/qdeclarativeextensionplugin.cpp \ $$PWD/qdeclarativeimport.cpp \ - $$PWD/qdeclarativelist.cpp + $$PWD/qdeclarativelist.cpp \ + $$PWD/qperformancetimer.cpp HEADERS += \ $$PWD/qdeclarativeparser_p.h \ @@ -129,8 +130,12 @@ HEADERS += \ $$PWD/qdeclarativedirparser_p.h \ $$PWD/qdeclarativeextensioninterface.h \ $$PWD/qdeclarativeimport_p.h \ - $$PWD/qdeclarativeextensionplugin.h + $$PWD/qdeclarativeextensionplugin.h \ + $$PWD/qperformancetimer_p.h QT += sql include(parser/parser.pri) include(rewriter/rewriter.pri) + +# mirrors logic in corelib/kernel/kernel.pri +unix:!symbian: contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri) diff --git a/src/declarative/qml/qperformancetimer.cpp b/src/declarative/qml/qperformancetimer.cpp new file mode 100644 index 0000000..1d7ca80 --- /dev/null +++ b/src/declarative/qml/qperformancetimer.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qperformancetimer_p.h" + +#if defined(Q_OS_MAC) +#include +#include +#include +#elif defined(Q_OS_UNIX) +#include +#include +#include +#elif defined(Q_OS_SYMBIAN) +#include +#include +#include +#elif defined(Q_OS_WIN) +#include +#endif + +// mac/unix code heavily copied from QElapsedTimer + +QT_BEGIN_NAMESPACE + +////////////////////////////// Mac ////////////////////////////// +#if defined(Q_OS_MAC) + +static mach_timebase_info_data_t info = {0,0}; +static qint64 absoluteToNSecs(qint64 cpuTime) +{ + if (info.denom == 0) + mach_timebase_info(&info); + qint64 nsecs = cpuTime * info.numer / info.denom; + return nsecs; +} + +void QPerformanceTimer::start() +{ + t1 = mach_absolute_time(); +} + +qint64 QPerformanceTimer::elapsed() const +{ + uint64_t cpu_time = mach_absolute_time(); + return absoluteToNSecs(cpu_time - t1); +} + +////////////////////////////// Unix ////////////////////////////// +#elif defined(Q_OS_UNIX) + +#if defined(QT_NO_CLOCK_MONOTONIC) || defined(QT_BOOTSTRAPPED) +// turn off the monotonic clock +# ifdef _POSIX_MONOTONIC_CLOCK +# undef _POSIX_MONOTONIC_CLOCK +# endif +# define _POSIX_MONOTONIC_CLOCK -1 +#endif + +#if (_POSIX_MONOTONIC_CLOCK-0 != 0) +static const bool monotonicClockChecked = true; +static const bool monotonicClockAvailable = _POSIX_MONOTONIC_CLOCK > 0; +#else +static int monotonicClockChecked = false; +static int monotonicClockAvailable = false; +#endif + +#ifdef Q_CC_GNU +# define is_likely(x) __builtin_expect((x), 1) +#else +# define is_likely(x) (x) +#endif +#define load_acquire(x) ((volatile const int&)(x)) +#define store_release(x,v) ((volatile int&)(x) = (v)) + +static void unixCheckClockType() +{ +#if (_POSIX_MONOTONIC_CLOCK-0 == 0) + if (is_likely(load_acquire(monotonicClockChecked))) + return; + +# if defined(_SC_MONOTONIC_CLOCK) + // detect if the system support monotonic timers + long x = sysconf(_SC_MONOTONIC_CLOCK); + store_release(monotonicClockAvailable, x >= 200112L); +# endif + + store_release(monotonicClockChecked, true); +#endif +} + +static inline void do_gettime(qint64 *sec, qint64 *frac) +{ +#if (_POSIX_MONOTONIC_CLOCK-0 >= 0) + unixCheckClockType(); + if (is_likely(monotonicClockAvailable)) { + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + *sec = ts.tv_sec; + *frac = ts.tv_nsec; + return; + } +#endif + *sec = 0; + *frac = 0; +} + +void QPerformanceTimer::start() +{ + do_gettime(&t1, &t2); +} + +qint64 QPerformanceTimer::elapsed() const +{ + qint64 sec, frac; + do_gettime(&sec, &frac); + sec = sec - t1; + frac = frac - t2; + + return sec * Q_INT64_C(1000000000) + frac; +} + +////////////////////////////// Symbian ////////////////////////////// +#elif defined(Q_OS_SYMBIAN) + +static qint64 getTimeFromTick(quint64 elapsed) +{ + static TInt freq; + if (!freq) + HAL::Get(HALData::EFastCounterFrequency, freq); + + // ### not sure on units + return elapsed / freq; +} + +void QPerformanceTimer::start() +{ + t1 = User::FastCounter(); +} + +qint64 QPerformanceTimer::elapsed() const +{ + return getTimeFromTick(User::FastCounter() - t1); +} + +////////////////////////////// Windows ////////////////////////////// +#elif defined(Q_OS_WIN) + +static qint64 getTimeFromTick(quint64 elapsed) +{ + static LARGE_INTEGER freq; + if (!freq.QuadPart) + QueryPerformanceFrequency(&freq); + return 1000000000 * elapsed / freq.QuadPart; +} + +void QPerformanceTimer::start() +{ + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + t1 = li.QuadPart; +} + +qint64 QPerformanceTimer::elapsed() const +{ + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + return getTimeFromTick(li.QuadPart - t1); +} + +////////////////////////////// Default ////////////////////////////// +#else + +// default implementation (no hi-perf timer) does nothing +void QPerformanceTimer::start() +{ +} + +qint64 QPerformanceTimer::elapsed() const +{ + return 0; +} + +#endif + +QT_END_NAMESPACE + + diff --git a/src/declarative/qml/qperformancetimer_p.h b/src/declarative/qml/qperformancetimer_p.h new file mode 100644 index 0000000..14310bf --- /dev/null +++ b/src/declarative/qml/qperformancetimer_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPERFORMANCETIMER_P_H +#define QPERFORMANCETIMER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of moc. This header file may change from version to version without notice, +// or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_AUTOTEST_EXPORT QPerformanceTimer +{ +public: + void start(); + qint64 elapsed() const; + +private: + qint64 t1; + qint64 t2; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QPERFORMANCETIMER_P_H diff --git a/tests/auto/declarative/qperformancetimer/qperformancetimer.pro b/tests/auto/declarative/qperformancetimer/qperformancetimer.pro new file mode 100644 index 0000000..656bf68 --- /dev/null +++ b/tests/auto/declarative/qperformancetimer/qperformancetimer.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +SOURCES += tst_qperformancetimer.cpp +macx:CONFIG -= app_bundle + +CONFIG += parallel_test + diff --git a/tests/auto/declarative/qperformancetimer/tst_qperformancetimer.cpp b/tests/auto/declarative/qperformancetimer/tst_qperformancetimer.cpp new file mode 100644 index 0000000..2029c8a --- /dev/null +++ b/tests/auto/declarative/qperformancetimer/tst_qperformancetimer.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +class tst_qperformancetimer : public QObject +{ + Q_OBJECT + +public: + tst_qperformancetimer() {} + +private slots: + void units(); +}; + +void tst_qperformancetimer::units() +{ + QPerformanceTimer timer; + timer.start(); + QTest::qWait(300); + qint64 elapsed = timer.elapsed(); + QVERIFY(elapsed > 300000000 && elapsed < 310000000); +} + +QTEST_MAIN(tst_qperformancetimer) + +#include "tst_qperformancetimer.moc" diff --git a/tests/benchmarks/declarative/qperformancetimer/qperformancetimer.pro b/tests/benchmarks/declarative/qperformancetimer/qperformancetimer.pro new file mode 100644 index 0000000..a39cd3d --- /dev/null +++ b/tests/benchmarks/declarative/qperformancetimer/qperformancetimer.pro @@ -0,0 +1,8 @@ +load(qttest_p4) +QT += declarative +TEMPLATE = app +TARGET = tst_qperformancetimer +macx:CONFIG -= app_bundle + +SOURCES += tst_qperformancetimer.cpp + diff --git a/tests/benchmarks/declarative/qperformancetimer/tst_qperformancetimer.cpp b/tests/benchmarks/declarative/qperformancetimer/tst_qperformancetimer.cpp new file mode 100644 index 0000000..04737e7 --- /dev/null +++ b/tests/benchmarks/declarative/qperformancetimer/tst_qperformancetimer.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +class tst_qperformancetimer : public QObject +{ + Q_OBJECT + +public: + tst_qperformancetimer() {} + +private slots: + void all(); + void startElapsed(); + void doubleElapsed(); +}; + +void tst_qperformancetimer::all() +{ + QBENCHMARK { + QPerformanceTimer t; + t.start(); + t.elapsed(); + } +} + +void tst_qperformancetimer::startElapsed() +{ + QPerformanceTimer t; + QBENCHMARK { + t.start(); + t.elapsed(); + } +} + +void tst_qperformancetimer::doubleElapsed() +{ + QPerformanceTimer t; + t.start(); + QBENCHMARK { + t.elapsed(); + t.elapsed(); + } +} + +QTEST_MAIN(tst_qperformancetimer) + +#include "tst_qperformancetimer.moc" -- cgit v0.12 From 458c237ea807330de8b15cb2b6e99f564bb7fd66 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 3 Nov 2010 10:24:29 +1000 Subject: Use high performance timer for profiling. Add binding profile info. --- src/declarative/debugger/qdeclarativedebugtrace_p.h | 5 +++-- src/declarative/qml/qdeclarativebinding.cpp | 15 +++++++++++++++ src/declarative/qml/qdeclarativecompiledbindings.cpp | 3 +++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/declarative/debugger/qdeclarativedebugtrace_p.h b/src/declarative/debugger/qdeclarativedebugtrace_p.h index 704c49a..d6fe0b0 100644 --- a/src/declarative/debugger/qdeclarativedebugtrace_p.h +++ b/src/declarative/debugger/qdeclarativedebugtrace_p.h @@ -43,7 +43,7 @@ #define QDECLARATIVEDEBUGTRACE_P_H #include -#include +#include QT_BEGIN_HEADER @@ -74,6 +74,7 @@ public: Painting, Compiling, Creating, + Binding, MaximumRangeType }; @@ -90,7 +91,7 @@ private: void startRangeImpl(RangeType); void rangeDataImpl(RangeType, const QUrl &); void endRangeImpl(RangeType); - QElapsedTimer m_timer; + QPerformanceTimer m_timer; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index cb6ad8c..2a1abd0 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -49,6 +49,7 @@ #include "private/qdeclarativedata_p.h" #include "private/qdeclarativestringconverters_p.h" #include "private/qdeclarativestate_p_p.h" +#include "private/qdeclarativedebugtrace_p.h" #include #include @@ -114,6 +115,19 @@ QDeclarativeProperty QDeclarativeBinding::property() const return d->property; } +class QDeclarativeBindingProfiler { +public: + QDeclarativeBindingProfiler() + { + QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding); + } + + ~QDeclarativeBindingProfiler() + { + QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding); + } +}; + void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) { Q_D(QDeclarativeBinding); @@ -122,6 +136,7 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) return; if (!d->updating) { + QDeclarativeBindingProfiler prof; d->updating = true; bool wasDeleted = false; d->deleted = &wasDeleted; diff --git a/src/declarative/qml/qdeclarativecompiledbindings.cpp b/src/declarative/qml/qdeclarativecompiledbindings.cpp index 5f0fd56..77fb48e 100644 --- a/src/declarative/qml/qdeclarativecompiledbindings.cpp +++ b/src/declarative/qml/qdeclarativecompiledbindings.cpp @@ -54,6 +54,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -316,7 +317,9 @@ int QDeclarativeCompiledBindingsPrivate::Binding::propertyIndex() void QDeclarativeCompiledBindingsPrivate::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags) { + QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding); parent->run(this, flags); + QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Binding); } void QDeclarativeCompiledBindingsPrivate::Binding::destroy() -- cgit v0.12 From 1a8bf28261facf1e97cecf842fcbfff48b383984 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 3 Nov 2010 12:53:41 +1000 Subject: Add support for a record-then-send debug process. --- .../debugger/qdeclarativedebugtrace.cpp | 55 ++++++++++++++++++---- .../debugger/qdeclarativedebugtrace_p.h | 7 +++ 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/declarative/debugger/qdeclarativedebugtrace.cpp b/src/declarative/debugger/qdeclarativedebugtrace.cpp index 03e2d56..5edc3b6 100644 --- a/src/declarative/debugger/qdeclarativedebugtrace.cpp +++ b/src/declarative/debugger/qdeclarativedebugtrace.cpp @@ -43,11 +43,13 @@ #include #include +#include Q_GLOBAL_STATIC(QDeclarativeDebugTrace, traceInstance); QDeclarativeDebugTrace::QDeclarativeDebugTrace() -: QDeclarativeDebugService(QLatin1String("CanvasFrameRate")) +: QDeclarativeDebugService(QLatin1String("CanvasFrameRate")), + m_enabled(false), m_deferredSend(true) { m_timer.start(); } @@ -78,45 +80,80 @@ void QDeclarativeDebugTrace::endRange(RangeType t) void QDeclarativeDebugTrace::addEventImpl(EventType event) { - if (status() != Enabled) + if (status() != Enabled || !m_enabled) return; QByteArray data; QDataStream ds(&data, QIODevice::WriteOnly); ds << m_timer.elapsed() << (int)Event << (int)event; - sendMessage(data); + processMessage(data); } void QDeclarativeDebugTrace::startRangeImpl(RangeType range) { - if (status() != Enabled) + if (status() != Enabled || !m_enabled) return; QByteArray data; QDataStream ds(&data, QIODevice::WriteOnly); ds << m_timer.elapsed() << (int)RangeStart << (int)range; - sendMessage(data); + processMessage(data); } void QDeclarativeDebugTrace::rangeDataImpl(RangeType range, const QUrl &u) { - if (status() != Enabled) + if (status() != Enabled || !m_enabled) return; QByteArray data; QDataStream ds(&data, QIODevice::WriteOnly); ds << m_timer.elapsed() << (int)RangeData << (int)range << (QString)u.toString(); - sendMessage(data); + processMessage(data); } void QDeclarativeDebugTrace::endRangeImpl(RangeType range) { - if (status() != Enabled) + if (status() != Enabled || !m_enabled) return; QByteArray data; QDataStream ds(&data, QIODevice::WriteOnly); ds << m_timer.elapsed() << (int)RangeEnd << (int)range; - sendMessage(data); + processMessage(data); } +/* + Either send the message directly, or queue up + a list of messages to send later (via sendMessages) +*/ +void QDeclarativeDebugTrace::processMessage(const QByteArray &message) +{ + if (m_deferredSend) + m_data.append(message); + else + sendMessage(message); +} + +/* + Send the messages queued up by processMessage +*/ +void QDeclarativeDebugTrace::sendMessages() +{ + if (m_deferredSend) { + //### this is a suboptimal way to send batched messages + for (int i = 0; i < m_data.count(); ++i) + sendMessage(m_data.at(i)); + m_data.clear(); + } +} + +void QDeclarativeDebugTrace::messageReceived(const QByteArray &message) +{ + QByteArray rwData = message; + QDataStream stream(&rwData, QIODevice::ReadOnly); + + stream >> m_enabled; + + if (!m_enabled) + sendMessages(); +} diff --git a/src/declarative/debugger/qdeclarativedebugtrace_p.h b/src/declarative/debugger/qdeclarativedebugtrace_p.h index d6fe0b0..c7c61bd 100644 --- a/src/declarative/debugger/qdeclarativedebugtrace_p.h +++ b/src/declarative/debugger/qdeclarativedebugtrace_p.h @@ -86,12 +86,19 @@ public: static void endRange(RangeType); QDeclarativeDebugTrace(); +protected: + virtual void messageReceived(const QByteArray &); private: void addEventImpl(EventType); void startRangeImpl(RangeType); void rangeDataImpl(RangeType, const QUrl &); void endRangeImpl(RangeType); + void processMessage(const QByteArray &); + void sendMessages(); QPerformanceTimer m_timer; + bool m_enabled; + bool m_deferredSend; + QList m_data; }; QT_END_NAMESPACE -- cgit v0.12 From 530b052bed6fd74699fead438035dc4684d83335 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 3 Nov 2010 15:12:16 +1000 Subject: Add additional tracing. Tracing for compile time, signal handlers, and deferred creation. --- src/declarative/debugger/qdeclarativedebugtrace_p.h | 3 ++- src/declarative/qml/qdeclarativeboundsignal.cpp | 3 +++ src/declarative/qml/qdeclarativeengine.cpp | 4 +++- src/declarative/qml/qdeclarativetypeloader.cpp | 3 +++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/declarative/debugger/qdeclarativedebugtrace_p.h b/src/declarative/debugger/qdeclarativedebugtrace_p.h index c7c61bd..d0e776e 100644 --- a/src/declarative/debugger/qdeclarativedebugtrace_p.h +++ b/src/declarative/debugger/qdeclarativedebugtrace_p.h @@ -74,7 +74,8 @@ public: Painting, Compiling, Creating, - Binding, + Binding, //running a binding + HandlingSignal, //running a signal handler MaximumRangeType }; diff --git a/src/declarative/qml/qdeclarativeboundsignal.cpp b/src/declarative/qml/qdeclarativeboundsignal.cpp index 6af3e05..1bb92dd 100644 --- a/src/declarative/qml/qdeclarativeboundsignal.cpp +++ b/src/declarative/qml/qdeclarativeboundsignal.cpp @@ -49,6 +49,7 @@ #include "qdeclarative.h" #include "qdeclarativecontext.h" #include "private/qdeclarativeglobal_p.h" +#include "private/qdeclarativedebugtrace_p.h" #include @@ -165,6 +166,7 @@ QDeclarativeBoundSignal *QDeclarativeBoundSignal::cast(QObject *o) int QDeclarativeBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a) { if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) { + QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::HandlingSignal); m_isEvaluating = true; if (!m_paramsValid) { if (!m_signal.parameterTypes().isEmpty()) @@ -180,6 +182,7 @@ int QDeclarativeBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a) } if (m_params) m_params->clearValues(); m_isEvaluating = false; + QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::HandlingSignal); return -1; } else { return QObject::qt_metacall(c, id, a); diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 808ba68..dac40b0 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -69,6 +69,7 @@ #include "private/qdeclarativetypenamecache_p.h" #include "private/qdeclarativeinclude_p.h" #include "private/qdeclarativenotifier_p.h" +#include "private/qdeclarativedebugtrace_p.h" #include #include @@ -927,7 +928,7 @@ Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object) QDeclarativeData *data = QDeclarativeData::get(object); if (data && data->deferredComponent) { - + QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating); QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(data->context->engine); QDeclarativeComponentPrivate::ConstructionState state; @@ -937,6 +938,7 @@ Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object) data->deferredComponent = 0; QDeclarativeComponentPrivate::complete(ep, &state); + QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Creating); } } diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp index c015519..d9b4c54 100644 --- a/src/declarative/qml/qdeclarativetypeloader.cpp +++ b/src/declarative/qml/qdeclarativetypeloader.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -895,6 +896,7 @@ void QDeclarativeTypeData::downloadProgressChanged(qreal p) void QDeclarativeTypeData::compile() { Q_ASSERT(m_compiledData == 0); + QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Compiling); m_compiledData = new QDeclarativeCompiledData(typeLoader()->engine()); m_compiledData->url = m_imports.baseUrl(); @@ -906,6 +908,7 @@ void QDeclarativeTypeData::compile() m_compiledData->release(); m_compiledData = 0; } + QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Compiling); } void QDeclarativeTypeData::resolveTypes() -- cgit v0.12 From 3c05109ce609574f1525c465f68817d3af39397e Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Thu, 4 Nov 2010 15:34:17 +1000 Subject: Support directly setting string range data. --- src/declarative/debugger/qdeclarativedebugtrace.cpp | 8 ++++---- src/declarative/debugger/qdeclarativedebugtrace_p.h | 4 ++-- src/declarative/qml/qdeclarativebinding.cpp | 5 +++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/declarative/debugger/qdeclarativedebugtrace.cpp b/src/declarative/debugger/qdeclarativedebugtrace.cpp index 5edc3b6..cd4306b 100644 --- a/src/declarative/debugger/qdeclarativedebugtrace.cpp +++ b/src/declarative/debugger/qdeclarativedebugtrace.cpp @@ -66,10 +66,10 @@ void QDeclarativeDebugTrace::startRange(RangeType t) traceInstance()->startRangeImpl(t); } -void QDeclarativeDebugTrace::rangeData(RangeType t, const QUrl &url) +void QDeclarativeDebugTrace::rangeData(RangeType t, const QString &data) { if (QDeclarativeDebugService::isDebuggingEnabled()) - traceInstance()->rangeDataImpl(t, url); + traceInstance()->rangeDataImpl(t, data); } void QDeclarativeDebugTrace::endRange(RangeType t) @@ -100,14 +100,14 @@ void QDeclarativeDebugTrace::startRangeImpl(RangeType range) processMessage(data); } -void QDeclarativeDebugTrace::rangeDataImpl(RangeType range, const QUrl &u) +void QDeclarativeDebugTrace::rangeDataImpl(RangeType range, const QString &rData) { if (status() != Enabled || !m_enabled) return; QByteArray data; QDataStream ds(&data, QIODevice::WriteOnly); - ds << m_timer.elapsed() << (int)RangeData << (int)range << (QString)u.toString(); + ds << m_timer.elapsed() << (int)RangeData << (int)range << rData; processMessage(data); } diff --git a/src/declarative/debugger/qdeclarativedebugtrace_p.h b/src/declarative/debugger/qdeclarativedebugtrace_p.h index d0e776e..b935fbe 100644 --- a/src/declarative/debugger/qdeclarativedebugtrace_p.h +++ b/src/declarative/debugger/qdeclarativedebugtrace_p.h @@ -83,7 +83,7 @@ public: static void addEvent(EventType); static void startRange(RangeType); - static void rangeData(RangeType, const QUrl &); + static void rangeData(RangeType, const QString &); static void endRange(RangeType); QDeclarativeDebugTrace(); @@ -92,7 +92,7 @@ protected: private: void addEventImpl(EventType); void startRangeImpl(RangeType); - void rangeDataImpl(RangeType, const QUrl &); + void rangeDataImpl(RangeType, const QString &); void endRangeImpl(RangeType); void processMessage(const QByteArray &); void sendMessages(); diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index 2a1abd0..055d009 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -117,9 +117,10 @@ QDeclarativeProperty QDeclarativeBinding::property() const class QDeclarativeBindingProfiler { public: - QDeclarativeBindingProfiler() + QDeclarativeBindingProfiler(QDeclarativeBinding *bind) { QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding); + //QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Binding, bind->expression()); } ~QDeclarativeBindingProfiler() @@ -136,7 +137,7 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) return; if (!d->updating) { - QDeclarativeBindingProfiler prof; + QDeclarativeBindingProfiler prof(this); d->updating = true; bool wasDeleted = false; d->deleted = &wasDeleted; -- cgit v0.12 From 7aebf28291288ea6e8c1d9d28f4ed752b00dca97 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 5 Nov 2010 13:27:30 +1000 Subject: Make deferred tracing less expensive (real-time cost is the same) --- .../debugger/qdeclarativedebugtrace.cpp | 44 ++++++++++++---------- .../debugger/qdeclarativedebugtrace_p.h | 32 +++++++++++----- src/declarative/qml/qdeclarativebinding.cpp | 2 +- .../qperformancetimer/tst_qperformancetimer.cpp | 11 ++++++ 4 files changed, 59 insertions(+), 30 deletions(-) diff --git a/src/declarative/debugger/qdeclarativedebugtrace.cpp b/src/declarative/debugger/qdeclarativedebugtrace.cpp index cd4306b..7f970bf 100644 --- a/src/declarative/debugger/qdeclarativedebugtrace.cpp +++ b/src/declarative/debugger/qdeclarativedebugtrace.cpp @@ -47,6 +47,20 @@ Q_GLOBAL_STATIC(QDeclarativeDebugTrace, traceInstance); +// convert to a QByteArray that can be sent to the debug client +// use of QDataStream can skew results if m_deferredSend == false +// (see tst_qperformancetimer::trace() benchmark) +QByteArray QDeclarativeDebugData::toByteArray() const +{ + QByteArray data; + //### using QDataStream is relatively expensive + QDataStream ds(&data, QIODevice::WriteOnly); + ds << time << messageType << detailType; + if (messageType == (int)QDeclarativeDebugTrace::RangeData) + ds << detailData; + return data; +} + QDeclarativeDebugTrace::QDeclarativeDebugTrace() : QDeclarativeDebugService(QLatin1String("CanvasFrameRate")), m_enabled(false), m_deferredSend(true) @@ -83,10 +97,8 @@ void QDeclarativeDebugTrace::addEventImpl(EventType event) if (status() != Enabled || !m_enabled) return; - QByteArray data; - QDataStream ds(&data, QIODevice::WriteOnly); - ds << m_timer.elapsed() << (int)Event << (int)event; - processMessage(data); + QDeclarativeDebugData ed = {m_timer.elapsed(), (int)Event, (int)event, QString()}; + processMessage(ed); } void QDeclarativeDebugTrace::startRangeImpl(RangeType range) @@ -94,10 +106,8 @@ void QDeclarativeDebugTrace::startRangeImpl(RangeType range) if (status() != Enabled || !m_enabled) return; - QByteArray data; - QDataStream ds(&data, QIODevice::WriteOnly); - ds << m_timer.elapsed() << (int)RangeStart << (int)range; - processMessage(data); + QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeStart, (int)range, QString()}; + processMessage(rd); } void QDeclarativeDebugTrace::rangeDataImpl(RangeType range, const QString &rData) @@ -105,10 +115,8 @@ void QDeclarativeDebugTrace::rangeDataImpl(RangeType range, const QString &rData if (status() != Enabled || !m_enabled) return; - QByteArray data; - QDataStream ds(&data, QIODevice::WriteOnly); - ds << m_timer.elapsed() << (int)RangeData << (int)range << rData; - processMessage(data); + QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeData, (int)range, rData}; + processMessage(rd); } void QDeclarativeDebugTrace::endRangeImpl(RangeType range) @@ -116,22 +124,20 @@ void QDeclarativeDebugTrace::endRangeImpl(RangeType range) if (status() != Enabled || !m_enabled) return; - QByteArray data; - QDataStream ds(&data, QIODevice::WriteOnly); - ds << m_timer.elapsed() << (int)RangeEnd << (int)range; - processMessage(data); + QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeEnd, (int)range, QString()}; + processMessage(rd); } /* Either send the message directly, or queue up a list of messages to send later (via sendMessages) */ -void QDeclarativeDebugTrace::processMessage(const QByteArray &message) +void QDeclarativeDebugTrace::processMessage(const QDeclarativeDebugData &message) { if (m_deferredSend) m_data.append(message); else - sendMessage(message); + sendMessage(message.toByteArray()); } /* @@ -142,7 +148,7 @@ void QDeclarativeDebugTrace::sendMessages() if (m_deferredSend) { //### this is a suboptimal way to send batched messages for (int i = 0; i < m_data.count(); ++i) - sendMessage(m_data.at(i)); + sendMessage(m_data.at(i).toByteArray()); m_data.clear(); } } diff --git a/src/declarative/debugger/qdeclarativedebugtrace_p.h b/src/declarative/debugger/qdeclarativedebugtrace_p.h index b935fbe..86c0987 100644 --- a/src/declarative/debugger/qdeclarativedebugtrace_p.h +++ b/src/declarative/debugger/qdeclarativedebugtrace_p.h @@ -49,18 +49,22 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE +struct QDeclarativeDebugData +{ + qint64 time; + int messageType; + int detailType; + QString detailData; + + QByteArray toByteArray() const; +}; + +Q_DECLARE_TYPEINFO(QDeclarativeDebugData,Q_PRIMITIVE_TYPE); + class QUrl; class Q_AUTOTEST_EXPORT QDeclarativeDebugTrace : public QDeclarativeDebugService { public: - enum EventType { - FramePaint, - Mouse, - Key, - - MaximumEventType - }; - enum Message { Event, RangeStart, @@ -70,6 +74,14 @@ public: MaximumMessage }; + enum EventType { + FramePaint, + Mouse, + Key, + + MaximumEventType + }; + enum RangeType { Painting, Compiling, @@ -94,12 +106,12 @@ private: void startRangeImpl(RangeType); void rangeDataImpl(RangeType, const QString &); void endRangeImpl(RangeType); - void processMessage(const QByteArray &); + void processMessage(const QDeclarativeDebugData &); void sendMessages(); QPerformanceTimer m_timer; bool m_enabled; bool m_deferredSend; - QList m_data; + QList m_data; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index 055d009..c8b4c7d 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -120,7 +120,7 @@ public: QDeclarativeBindingProfiler(QDeclarativeBinding *bind) { QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Binding); - //QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Binding, bind->expression()); + QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Binding, bind->expression()); } ~QDeclarativeBindingProfiler() diff --git a/tests/benchmarks/declarative/qperformancetimer/tst_qperformancetimer.cpp b/tests/benchmarks/declarative/qperformancetimer/tst_qperformancetimer.cpp index 04737e7..497a556 100644 --- a/tests/benchmarks/declarative/qperformancetimer/tst_qperformancetimer.cpp +++ b/tests/benchmarks/declarative/qperformancetimer/tst_qperformancetimer.cpp @@ -54,6 +54,7 @@ private slots: void all(); void startElapsed(); void doubleElapsed(); + void trace(); }; void tst_qperformancetimer::all() @@ -84,6 +85,16 @@ void tst_qperformancetimer::doubleElapsed() } } +void tst_qperformancetimer::trace() +{ + QString s("A decent sized string of text here."); + QBENCHMARK { + QByteArray data; + QDataStream ds(&data, QIODevice::WriteOnly); + ds << (qint64)100 << (int)5 << (int)5 << s; + } +} + QTEST_MAIN(tst_qperformancetimer) #include "tst_qperformancetimer.moc" -- cgit v0.12 From 280f67d16430ce0dcfcc31a0c88ce7156126066c Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 5 Nov 2010 15:05:53 +1000 Subject: Add additional trace range data. --- src/declarative/debugger/qdeclarativedebugtrace.cpp | 15 +++++++++++++++ src/declarative/debugger/qdeclarativedebugtrace_p.h | 2 ++ src/declarative/qml/qdeclarativeboundsignal.cpp | 1 + src/declarative/qml/qdeclarativecomponent.cpp | 4 +++- src/declarative/qml/qdeclarativeengine.cpp | 1 + src/declarative/qml/qdeclarativetypeloader.cpp | 1 + 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/declarative/debugger/qdeclarativedebugtrace.cpp b/src/declarative/debugger/qdeclarativedebugtrace.cpp index 7f970bf..314db70 100644 --- a/src/declarative/debugger/qdeclarativedebugtrace.cpp +++ b/src/declarative/debugger/qdeclarativedebugtrace.cpp @@ -86,6 +86,12 @@ void QDeclarativeDebugTrace::rangeData(RangeType t, const QString &data) traceInstance()->rangeDataImpl(t, data); } +void QDeclarativeDebugTrace::rangeData(RangeType t, const QUrl &data) +{ + if (QDeclarativeDebugService::isDebuggingEnabled()) + traceInstance()->rangeDataImpl(t, data); +} + void QDeclarativeDebugTrace::endRange(RangeType t) { if (QDeclarativeDebugService::isDebuggingEnabled()) @@ -119,6 +125,15 @@ void QDeclarativeDebugTrace::rangeDataImpl(RangeType range, const QString &rData processMessage(rd); } +void QDeclarativeDebugTrace::rangeDataImpl(RangeType range, const QUrl &rData) +{ + if (status() != Enabled || !m_enabled) + return; + + QDeclarativeDebugData rd = {m_timer.elapsed(), (int)RangeData, (int)range, rData.toEncoded(QUrl::FormattingOption(0x100))}; + processMessage(rd); +} + void QDeclarativeDebugTrace::endRangeImpl(RangeType range) { if (status() != Enabled || !m_enabled) diff --git a/src/declarative/debugger/qdeclarativedebugtrace_p.h b/src/declarative/debugger/qdeclarativedebugtrace_p.h index 86c0987..3f9b904 100644 --- a/src/declarative/debugger/qdeclarativedebugtrace_p.h +++ b/src/declarative/debugger/qdeclarativedebugtrace_p.h @@ -96,6 +96,7 @@ public: static void startRange(RangeType); static void rangeData(RangeType, const QString &); + static void rangeData(RangeType, const QUrl &); static void endRange(RangeType); QDeclarativeDebugTrace(); @@ -105,6 +106,7 @@ private: void addEventImpl(EventType); void startRangeImpl(RangeType); void rangeDataImpl(RangeType, const QString &); + void rangeDataImpl(RangeType, const QUrl &); void endRangeImpl(RangeType); void processMessage(const QDeclarativeDebugData &); void sendMessages(); diff --git a/src/declarative/qml/qdeclarativeboundsignal.cpp b/src/declarative/qml/qdeclarativeboundsignal.cpp index 1bb92dd..030fb2c 100644 --- a/src/declarative/qml/qdeclarativeboundsignal.cpp +++ b/src/declarative/qml/qdeclarativeboundsignal.cpp @@ -167,6 +167,7 @@ int QDeclarativeBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a) { if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) { QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::HandlingSignal); + QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::HandlingSignal, QLatin1String(m_signal.signature()) + QLatin1String(": ") + (m_expression ? m_expression->expression() : "")); m_isEvaluating = true; if (!m_paramsValid) { if (!m_signal.parameterTypes().isEmpty()) diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp index 2686ce3..5be41ab 100644 --- a/src/declarative/qml/qdeclarativecomponent.cpp +++ b/src/declarative/qml/qdeclarativecomponent.cpp @@ -785,8 +785,10 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon Q_ASSERT(!isRoot || state); // Either this isn't a root component, or a state data must be provided Q_ASSERT((state != 0) ^ (errors != 0)); // One of state or errors (but not both) must be provided - if (isRoot) + if (isRoot) { QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating); + QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, component->url); + } QDeclarativeContextData *ctxt = new QDeclarativeContextData; ctxt->isInternal = true; diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index dac40b0..5122bdf 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -929,6 +929,7 @@ Q_AUTOTEST_EXPORT void qmlExecuteDeferred(QObject *object) if (data && data->deferredComponent) { QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating); + QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, QLatin1String("Deferred Creation:") + object->metaObject()->className()); QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(data->context->engine); QDeclarativeComponentPrivate::ConstructionState state; diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp index d9b4c54..f42e8a7 100644 --- a/src/declarative/qml/qdeclarativetypeloader.cpp +++ b/src/declarative/qml/qdeclarativetypeloader.cpp @@ -901,6 +901,7 @@ void QDeclarativeTypeData::compile() m_compiledData = new QDeclarativeCompiledData(typeLoader()->engine()); m_compiledData->url = m_imports.baseUrl(); m_compiledData->name = m_compiledData->url.toString(); + QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Compiling, m_compiledData->name); QDeclarativeCompiler compiler; if (!compiler.compile(typeLoader()->engine(), this, m_compiledData)) { -- cgit v0.12 From e64535b227599b5adb8847dfda0b2516ae7e5625 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 10 Nov 2010 14:43:11 +1000 Subject: Fix ListModel::set() to update the model cache when setting a list value Task-number: QTBUG-15190 --- src/declarative/util/qdeclarativelistmodel.cpp | 2 ++ .../qdeclarativelistmodel/data/setmodelcachelist.qml | 20 ++++++++++++++++++++ .../tst_qdeclarativelistmodel.cpp | 12 ++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 tests/auto/declarative/qdeclarativelistmodel/data/setmodelcachelist.qml diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp index 398480e..538e8af 100644 --- a/src/declarative/util/qdeclarativelistmodel.cpp +++ b/src/declarative/util/qdeclarativelistmodel.cpp @@ -1450,6 +1450,8 @@ void ModelNode::setObjectValue(const QScriptValue& valuemap, bool writeToCache) if (v.isArray()) { value->isArray = true; value->setListValue(v); + if (writeToCache && objectCache) + objectCache->setValue(it.name().toUtf8(), QVariant::fromValue(value->model(m_model))); } else { value->values << v.toVariant(); if (writeToCache && objectCache) diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/setmodelcachelist.qml b/tests/auto/declarative/qdeclarativelistmodel/data/setmodelcachelist.qml new file mode 100644 index 0000000..ffe417a --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/setmodelcachelist.qml @@ -0,0 +1,20 @@ +import QtQuick 1.0 + +ListModel { + id: model + property bool ok : false + + Component.onCompleted: { + model.append({"attrs": []}) + model.get(0) + model.set(0, {"attrs": [{'abc': 123, 'def': 456}] } ) + ok = ( model.get(0).attrs.get(0).abc == 123 + && model.get(0).attrs.get(0).def == 456 ) + + model.set(0, {"attrs": [{'abc': 789, 'def': 101}] } ) + ok = ( model.get(0).attrs.get(0).abc == 789 + && model.get(0).attrs.get(0).def == 101 ) + + } +} + diff --git a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp index 4b8d772..55f7421 100644 --- a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp +++ b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp @@ -100,6 +100,7 @@ private slots: void get_nested(); void get_nested_data(); void crash_model_with_multiple_roles(); + void set_model_cache(); }; int tst_qdeclarativelistmodel::roleFromName(const QDeclarativeListModel *model, const QString &roleName) { @@ -928,6 +929,17 @@ void tst_qdeclarativelistmodel::crash_model_with_multiple_roles() model->setProperty(0, "black", true); } +//QTBUG-15190 +void tst_qdeclarativelistmodel::set_model_cache() +{ + QDeclarativeEngine eng; + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/setmodelcachelist.qml")); + QObject *model = component.create(); + QVERIFY2(component.errorString().isEmpty(), QTest::toString(component.errorString())); + QVERIFY(model != 0); + QVERIFY(model->property("ok").toBool()); +} + QTEST_MAIN(tst_qdeclarativelistmodel) #include "tst_qdeclarativelistmodel.moc" -- cgit v0.12 From 940856ee20287ce0a61cfaf46012dd5509f857b5 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 29 Nov 2010 09:10:08 +1000 Subject: Add PinchArea. Provides two finger gestures: zoom, rotate, pan. Task-number: QTBUG-15491 Reviewed-by: Aaron Kennedy --- src/declarative/graphicsitems/graphicsitems.pri | 7 +- .../graphicsitems/qdeclarativeitemsmodule.cpp | 4 + .../graphicsitems/qdeclarativepincharea.cpp | 579 +++++++++++++++++++++ .../graphicsitems/qdeclarativepincharea_p.h | 308 +++++++++++ .../graphicsitems/qdeclarativepincharea_p_p.h | 109 ++++ .../qdeclarativepincharea/data/pinchproperties.qml | 46 ++ .../qdeclarativepincharea.pro | 16 + .../tst_qdeclarativepincharea.cpp | 315 +++++++++++ 8 files changed, 1382 insertions(+), 2 deletions(-) create mode 100644 src/declarative/graphicsitems/qdeclarativepincharea.cpp create mode 100644 src/declarative/graphicsitems/qdeclarativepincharea_p.h create mode 100644 src/declarative/graphicsitems/qdeclarativepincharea_p_p.h create mode 100644 tests/auto/declarative/qdeclarativepincharea/data/pinchproperties.qml create mode 100644 tests/auto/declarative/qdeclarativepincharea/qdeclarativepincharea.pro create mode 100644 tests/auto/declarative/qdeclarativepincharea/tst_qdeclarativepincharea.cpp diff --git a/src/declarative/graphicsitems/graphicsitems.pri b/src/declarative/graphicsitems/graphicsitems.pri index ffdeb29..2cd3323 100644 --- a/src/declarative/graphicsitems/graphicsitems.pri +++ b/src/declarative/graphicsitems/graphicsitems.pri @@ -50,7 +50,9 @@ HEADERS += \ $$PWD/qdeclarativelayoutitem_p.h \ $$PWD/qdeclarativeitemchangelistener_p.h \ $$PWD/qdeclarativegraphicswidget_p.h \ - $$PWD/qdeclarativetextlayout_p.h + $$PWD/qdeclarativetextlayout_p.h \ + $$PWD/qdeclarativepincharea_p.h \ + $$PWD/qdeclarativepincharea_p_p.h SOURCES += \ $$PWD/qdeclarativeitemsmodule.cpp \ @@ -83,5 +85,6 @@ SOURCES += \ $$PWD/qdeclarativelistview.cpp \ $$PWD/qdeclarativelayoutitem.cpp \ $$PWD/qdeclarativegraphicswidget.cpp \ - $$PWD/qdeclarativetextlayout.cpp + $$PWD/qdeclarativetextlayout.cpp \ + $$PWD/qdeclarativepincharea.cpp diff --git a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp index 52703c2..a462763 100644 --- a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp @@ -78,6 +78,7 @@ #include "private/qdeclarativewebview_p_p.h" #endif #include "private/qdeclarativeanchors_p.h" +#include "private/qdeclarativepincharea_p.h" static QDeclarativePrivate::AutoParentResult qgraphicsobject_autoParent(QObject *obj, QObject *parent) { @@ -147,10 +148,13 @@ void QDeclarativeItemModule::defineModule() qmlRegisterType("QtQuick",1,0,"ViewSection"); qmlRegisterType("QtQuick",1,0,"VisualDataModel"); qmlRegisterType("QtQuick",1,0,"VisualItemModel"); + qmlRegisterType("QtQuick",1,1,"PinchArea"); + qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); + qmlRegisterType(); qmlRegisterType(); qmlRegisterType("QtQuick",1,0,"QGraphicsWidget"); qmlRegisterExtendedType("QtQuick",1,0,"QGraphicsWidget"); diff --git a/src/declarative/graphicsitems/qdeclarativepincharea.cpp b/src/declarative/graphicsitems/qdeclarativepincharea.cpp new file mode 100644 index 0000000..998c30d --- /dev/null +++ b/src/declarative/graphicsitems/qdeclarativepincharea.cpp @@ -0,0 +1,579 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativepincharea_p.h" +#include "qdeclarativepincharea_p_p.h" + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + + +/*! + \qmlclass PinchEvent QDeclarativePinchEvent + \ingroup qml-event-elements + \brief The PinchEvent object provides information about a pinch event. + + \bold {The PinchEvent element was added in QtQuick 1.1} + + The \c center, \c startCenter, \c lastCenter properties provide the center position between the two touch points. + + The \c scale and \c lastScale properties provide the scale factor. + + The \c angle, \c lastAngle and \c rotation properties provide the angle between the two points and the amount of rotation. + + The \c point1, \c point2, \c startPoint1, \c startPoint2 properties provide the positions of the touch points. + + The \c accepted property may be set to false in the \c onPinchStarted handler if the gesture should not + be handled. + + \sa PinchArea +*/ + +/*! + \qmlproperty QPointF PinchEvent::center + \qmlproperty QPointF PinchEvent::startCenter + \qmlproperty QPointF PinchEvent::lastCenter + + These properties hold the position of the center point between the two touch points. + + \list + \o \c center is the current center point + \o \c lastCenter is the center point of the previous event. + \o \c startCenter is the center point when the gesture began + \endlist +*/ + +/*! + \qmlproperty real PinchEvent::scale + \qmlproperty real PinchEvent::lastScale + + These properties hold the scale factor determined by the change in distance between the two touch points. + + \list + \o \c scale is the current scale factor. + \o \c lastScale is the scale factor of the previous event. + \endlist + + When a pinch gesture is started, the scale is 1.0. +*/ + +/*! + \qmlproperty real PinchEvent::angle + \qmlproperty real PinchEvent::lastAngle + \qmlproperty real PinchEvent::rotation + + These properties hold the angle between the two touch points. + + \list + \o \c angle is the current angle between the two points in the range -180 to 180. + \o \c lastAngle is the angle of the previous event. + \o \c rotation is the total rotation since the pinch gesture started. + \endlist + + When a pinch gesture is started, the rotation is 0.0. +*/ + +/*! + \qmlproperty QPointF PinchEvent::point1 + \qmlproperty QPointF PinchEvent::startPoint1 + \qmlproperty QPointF PinchEvent::point2 + \qmlproperty QPointF PinchEvent::startPoint2 + + These properties provide the actual touch points generating the pinch. + + \list + \o \c point1 and \c point2 hold the current positions of the points. + \o \c startPoint1 and \c startPoint2 hold the positions of the points when the second point was touched. + \endlist +*/ + +/*! + \qmlproperty bool PinchEvent::accepted + + Setting this property to false in the \c PinchArea::onPinchStarted handler + will result in no further pinch events being generated, and the gesture + ignored. +*/ + +QDeclarativePinch::QDeclarativePinch() + : m_target(0), m_minScale(1.0), m_maxScale(1.0) + , m_minRotation(0.0), m_maxRotation(0.0) + , m_axis(NoDrag), m_xmin(-FLT_MAX), m_xmax(FLT_MAX) + , m_ymin(-FLT_MAX), m_ymax(FLT_MAX), m_active(false) +{ +} + +QDeclarativePinchAreaPrivate::~QDeclarativePinchAreaPrivate() +{ + delete pinch; +} + +/*! + \qmlclass PinchArea QDeclarativePinchArea + \brief The PinchArea item enables simple pinch gesture handling. + \inherits Item + + \bold {The PinchArea element was added in QtQuick 1.1} + + A PinchArea is an invisible item that is typically used in conjunction with + a visible item in order to provide pinch gesture handling for that item. + + The \l enabled property is used to enable and disable pinch handling for + the proxied item. When disabled, the pinch area becomes transparent to + mouse/touch events. + + PinchArea can be used in two ways: + + \list + \o setting a \c pinch.target to provide automatic interaction with an element + \o using the onPinchStarted, onPinchChanged and onPinchFinished handlers + \endlist + + \sa PinchEvent +*/ + +/*! + \qmlsignal PinchArea::onPinchStarted() + + This handler is called when the pinch area detects that a pinch gesture has started. + + The \l {PinchEvent}{pinch} parameter provides information about the pinch gesture, + including the scale, center and angle of the pinch. + + To ignore this gesture set the \c pinch.accepted property to false. The gesture + will be cancelled and no further events will be sent. +*/ + +/*! + \qmlsignal PinchArea::onPinchChanged() + + This handler is called when the pinch area detects that a pinch gesture has changed. + + The \l {PinchEvent}{pinch} parameter provides information about the pinch gesture, + including the scale, center and angle of the pinch. +*/ + +/*! + \qmlsignal PinchArea::onPinchFinished() + + This handler is called when the pinch area detects that a pinch gesture has finished. + + The \l {PinchEvent}{pinch} parameter provides information about the pinch gesture, + including the scale, center and angle of the pinch. +*/ + + +/*! + \qmlproperty Item PinchArea::pinch.target + \qmlproperty bool PinchArea::pinch.active + \qmlproperty real PinchArea::pinch.minimumScale + \qmlproperty real PinchArea::pinch.maximumScale + \qmlproperty real PinchArea::pinch.minimumRotation + \qmlproperty real PinchArea::pinch.maximumRotation + \qmlproperty enumeration PinchArea::pinch.dragAxis + \qmlproperty real PinchArea::pinch.minimumX + \qmlproperty real PinchArea::pinch.maximumX + \qmlproperty real PinchArea::pinch.minimumY + \qmlproperty real PinchArea::pinch.maximumY + + \c pinch provides a convenient way to make an item react to pinch gestures. + + \list + \i \c pinch.target specifies the id of the item to drag. + \i \c pinch.active specifies if the target item is currently being dragged. + \i \c pinch.minimumScale and \c pinch.maximumScale limit the range of the Item::scale property. + \i \c pinch.minimumRotation and \c pinch.maximumRotation limit the range of the Item::rotation property. + \i \c pinch.dragAxis specifies whether dragging in not allowed (\c Pinch.NoDrag), can be done horizontally (\c Pinch.XAxis), vertically (\c Pinch.YAxis), or both (\c Pinch.XandYAxis) + \i \c pinch.minimum and \c pinch.maximum limit how far the target can be dragged along the corresponding axes. + \endlist +*/ + +QDeclarativePinchArea::QDeclarativePinchArea(QDeclarativeItem *parent) + : QDeclarativeItem(*(new QDeclarativePinchAreaPrivate), parent) +{ + Q_D(QDeclarativePinchArea); + d->init(); +} + +QDeclarativePinchArea::~QDeclarativePinchArea() +{ +} + +/*! + \qmlproperty bool PinchArea::enabled + This property holds whether the item accepts pinch gestures. + + This property defaults to true. +*/ +bool QDeclarativePinchArea::isEnabled() const +{ + Q_D(const QDeclarativePinchArea); + return d->absorb; +} + +void QDeclarativePinchArea::setEnabled(bool a) +{ + Q_D(QDeclarativePinchArea); + if (a != d->absorb) { + d->absorb = a; + emit enabledChanged(); + } +} + +bool QDeclarativePinchArea::event(QEvent *event) +{ + Q_D(QDeclarativePinchArea); + if (!d->absorb || !isVisible()) + return QDeclarativeItem::event(event); + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: { + QTouchEvent *touch = static_cast(event); + d->touchPoints.clear(); + for (int i = 0; i < touch->touchPoints().count(); ++i) { + if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased)) { + d->touchPoints << touch->touchPoints().at(i); + } + } + updatePinch(); + } + return true; + case QEvent::TouchEnd: + d->touchPoints.clear(); + updatePinch(); + break; + default: + return QDeclarativeItem::event(event); + } + + return QDeclarativeItem::event(event); +} + +void QDeclarativePinchArea::updatePinch() +{ + Q_D(QDeclarativePinchArea); + if (d->touchPoints.count() != 2) { + if (d->inPinch) { + d->stealMouse = false; + setKeepMouseGrab(false); + d->inPinch = false; + const qreal rotationAngle = d->pinchStartAngle - d->pinchLastAngle; + QPointF pinchCenter = mapFromScene(d->sceneLastCenter); + QDeclarativePinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, rotationAngle); + pe.setStartCenter(d->pinchStartCenter); + pe.setLastCenter(pinchCenter); + pe.setLastAngle(d->pinchLastAngle); + pe.setLastScale(d->pinchLastScale); + pe.setStartPoint1(mapFromScene(d->sceneStartPoint1)); + pe.setStartPoint2(mapFromScene(d->sceneStartPoint2)); + pe.setPoint1(d->lastPoint1); + pe.setPoint2(d->lastPoint2); + emit pinchFinished(&pe); + if (d->pinch && d->pinch->target()) + d->pinch->setActive(false); + } + return; + } + if (d->touchPoints.at(0).state() & Qt::TouchPointPressed + || d->touchPoints.at(1).state() & Qt::TouchPointPressed) { + d->sceneStartPoint1 = d->touchPoints.at(0).scenePos(); + d->sceneStartPoint2 = d->touchPoints.at(1).scenePos(); + d->inPinch = false; + d->pinchRejected = false; + } else if (!d->pinchRejected){ + QDeclarativeItem *grabber = scene() ? qobject_cast(scene()->mouseGrabberItem()) : 0; + if (grabber == this || !grabber || !grabber->keepMouseGrab()) { + const int dragThreshold = QApplication::startDragDistance(); + QPointF p1 = d->touchPoints.at(0).scenePos(); + QPointF p2 = d->touchPoints.at(1).scenePos(); + qreal dx = p1.x() - p2.x(); + qreal dy = p1.y() - p2.y(); + qreal dist = sqrt(dx*dx + dy*dy); + QPointF sceneCenter = (p1 + p2)/2; + qreal angle = QLineF(p1, p2).angle(); + if (angle > 180) + angle -= 360; + if (!d->inPinch) { + if (qAbs(p1.x()-d->sceneStartPoint1.x()) > dragThreshold + || qAbs(p1.y()-d->sceneStartPoint1.y()) > dragThreshold + || qAbs(p2.x()-d->sceneStartPoint2.x()) > dragThreshold + || qAbs(p2.y()-d->sceneStartPoint2.y()) > dragThreshold) { + d->sceneStartCenter = sceneCenter; + d->sceneLastCenter = sceneCenter; + d->pinchStartCenter = mapFromScene(sceneCenter); + d->pinchStartDist = dist; + d->pinchStartAngle = angle; + d->pinchLastScale = 1.0; + d->pinchLastAngle = angle; + d->lastPoint1 = d->touchPoints.at(0).pos(); + d->lastPoint2 = d->touchPoints.at(1).pos(); + QDeclarativePinchEvent pe(d->pinchStartCenter, 1.0, angle, 0.0); + pe.setStartCenter(d->pinchStartCenter); + pe.setLastCenter(d->pinchStartCenter); + pe.setLastAngle(d->pinchLastAngle); + pe.setLastScale(d->pinchLastScale); + pe.setStartPoint1(mapFromScene(d->sceneStartPoint1)); + pe.setStartPoint2(mapFromScene(d->sceneStartPoint2)); + pe.setPoint1(d->lastPoint1); + pe.setPoint2(d->lastPoint2); + emit pinchStarted(&pe); + if (pe.accepted()) { + d->inPinch = true; + d->stealMouse = true; + grabMouse(); + setKeepMouseGrab(true); + if (d->pinch && d->pinch->target()) { + d->pinchStartPos = pinch()->target()->pos(); + d->pinchStartScale = d->pinch->target()->scale(); + d->pinchStartRotation = d->pinch->target()->rotation(); + d->pinch->setActive(true); + } + } else { + d->pinchRejected = true; + } + } + } else if (d->pinchStartDist > 0) { + qreal scale = dist / d->pinchStartDist; + qreal rotationAngle = d->pinchStartAngle - angle; + if (rotationAngle > 180) + rotationAngle -= 360; + QPointF pinchCenter = mapFromScene(sceneCenter); + QDeclarativePinchEvent pe(pinchCenter, scale, angle, rotationAngle); + pe.setStartCenter(d->pinchStartCenter); + pe.setLastCenter(mapFromScene(d->sceneLastCenter)); + pe.setLastAngle(d->pinchLastAngle); + pe.setLastScale(d->pinchLastScale); + pe.setStartPoint1(mapFromScene(d->sceneStartPoint1)); + pe.setStartPoint2(mapFromScene(d->sceneStartPoint2)); + pe.setPoint1(d->touchPoints.at(0).pos()); + pe.setPoint2(d->touchPoints.at(1).pos()); + d->pinchLastScale = scale; + d->sceneLastCenter = sceneCenter; + d->pinchLastAngle = angle; + d->lastPoint1 = d->touchPoints.at(0).pos(); + d->lastPoint2 = d->touchPoints.at(1).pos(); + emit pinchChanged(&pe); + if (d->pinch && d->pinch->target()) { + qreal s = d->pinchStartScale * scale; + s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale()); + pinch()->target()->setScale(s); + QPointF pos = sceneCenter - d->sceneStartCenter + d->pinchStartPos; + if (pinch()->axis() & QDeclarativePinch::XAxis) { + qreal x = pos.x(); + if (x < pinch()->xmin()) + x = pinch()->xmin(); + else if (x > pinch()->xmax()) + x = pinch()->xmax(); + pinch()->target()->setX(x); + } + if (pinch()->axis() & QDeclarativePinch::YAxis) { + qreal y = pos.y(); + if (y < pinch()->ymin()) + y = pinch()->ymin(); + else if (y > pinch()->ymax()) + y = pinch()->ymax(); + pinch()->target()->setY(y); + } + if (d->pinchStartRotation >= pinch()->minimumRotation() + && d->pinchStartRotation <= pinch()->maximumRotation()) { + qreal r = rotationAngle + d->pinchStartRotation; + r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation()); + pinch()->target()->setRotation(r); + } + } + } + } + } +} + +void QDeclarativePinchArea::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + Q_D(QDeclarativePinchArea); + d->stealMouse = false; + if (!d->absorb) + QDeclarativeItem::mousePressEvent(event); + else { + setKeepMouseGrab(false); + event->setAccepted(true); + } +} + +void QDeclarativePinchArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + Q_D(QDeclarativePinchArea); + if (!d->absorb) { + QDeclarativeItem::mouseMoveEvent(event); + return; + } +} + +void QDeclarativePinchArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + Q_D(QDeclarativePinchArea); + d->stealMouse = false; + if (!d->absorb) { + QDeclarativeItem::mouseReleaseEvent(event); + } else { + QGraphicsScene *s = scene(); + if (s && s->mouseGrabberItem() == this) + ungrabMouse(); + setKeepMouseGrab(false); + } +} + +bool QDeclarativePinchArea::sceneEvent(QEvent *event) +{ + bool rv = QDeclarativeItem::sceneEvent(event); + if (event->type() == QEvent::UngrabMouse) { + setKeepMouseGrab(false); + } + return rv; +} + +bool QDeclarativePinchArea::sendMouseEvent(QGraphicsSceneMouseEvent *event) +{ + Q_D(QDeclarativePinchArea); + QGraphicsSceneMouseEvent mouseEvent(event->type()); + QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect(); + + QGraphicsScene *s = scene(); + QDeclarativeItem *grabber = s ? qobject_cast(s->mouseGrabberItem()) : 0; + bool stealThisEvent = d->stealMouse; + if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) { + mouseEvent.setAccepted(false); + for (int i = 0x1; i <= 0x10; i <<= 1) { + if (event->buttons() & i) { + Qt::MouseButton button = Qt::MouseButton(i); + mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button))); + } + } + mouseEvent.setScenePos(event->scenePos()); + mouseEvent.setLastScenePos(event->lastScenePos()); + mouseEvent.setPos(mapFromScene(event->scenePos())); + mouseEvent.setLastPos(mapFromScene(event->lastScenePos())); + + switch(mouseEvent.type()) { + case QEvent::GraphicsSceneMouseMove: + mouseMoveEvent(&mouseEvent); + break; + case QEvent::GraphicsSceneMousePress: + mousePressEvent(&mouseEvent); + break; + case QEvent::GraphicsSceneMouseRelease: + mouseReleaseEvent(&mouseEvent); + break; + default: + break; + } + grabber = qobject_cast(s->mouseGrabberItem()); + if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) + grabMouse(); + + return stealThisEvent; + } + if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) { + d->stealMouse = false; + if (s && s->mouseGrabberItem() == this) + ungrabMouse(); + setKeepMouseGrab(false); + } + return false; +} + +bool QDeclarativePinchArea::sceneEventFilter(QGraphicsItem *i, QEvent *e) +{ + Q_D(QDeclarativePinchArea); + if (!d->absorb || !isVisible()) + return QDeclarativeItem::sceneEventFilter(i, e); + switch (e->type()) { + case QEvent::GraphicsSceneMousePress: + case QEvent::GraphicsSceneMouseMove: + case QEvent::GraphicsSceneMouseRelease: + return sendMouseEvent(static_cast(e)); + break; + case QEvent::TouchBegin: + case QEvent::TouchUpdate: { + QTouchEvent *touch = static_cast(e); + d->touchPoints.clear(); + for (int i = 0; i < touch->touchPoints().count(); ++i) + if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased)) + d->touchPoints << touch->touchPoints().at(i); + updatePinch(); + } + return d->inPinch; + case QEvent::TouchEnd: + d->touchPoints.clear(); + updatePinch(); + break; + default: + break; + } + + return QDeclarativeItem::sceneEventFilter(i, e); +} + +void QDeclarativePinchArea::geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry) +{ + QDeclarativeItem::geometryChanged(newGeometry, oldGeometry); +} + +QVariant QDeclarativePinchArea::itemChange(GraphicsItemChange change, + const QVariant &value) +{ + return QDeclarativeItem::itemChange(change, value); +} + +QDeclarativePinch *QDeclarativePinchArea::pinch() +{ + Q_D(QDeclarativePinchArea); + if (!d->pinch) + d->pinch = new QDeclarativePinch; + return d->pinch; +} + + +QT_END_NAMESPACE diff --git a/src/declarative/graphicsitems/qdeclarativepincharea_p.h b/src/declarative/graphicsitems/qdeclarativepincharea_p.h new file mode 100644 index 0000000..9a73a17 --- /dev/null +++ b/src/declarative/graphicsitems/qdeclarativepincharea_p.h @@ -0,0 +1,308 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPINCHAREA_H +#define QDECLARATIVEPINCHAREA_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_AUTOTEST_EXPORT QDeclarativePinch : public QObject +{ + Q_OBJECT + + Q_ENUMS(Axis) + Q_PROPERTY(QGraphicsObject *target READ target WRITE setTarget RESET resetTarget) + Q_PROPERTY(qreal minimumScale READ minimumScale WRITE setMinimumScale NOTIFY minimumScaleChanged) + Q_PROPERTY(qreal maximumScale READ maximumScale WRITE setMaximumScale NOTIFY maximumScaleChanged) + Q_PROPERTY(qreal minimumRotation READ minimumRotation WRITE setMinimumRotation NOTIFY minimumRotationChanged) + Q_PROPERTY(qreal maximumRotation READ maximumRotation WRITE setMaximumRotation NOTIFY maximumRotationChanged) + Q_PROPERTY(Axis dragAxis READ axis WRITE setAxis NOTIFY dragAxisChanged) + Q_PROPERTY(qreal minimumX READ xmin WRITE setXmin NOTIFY minimumXChanged) + Q_PROPERTY(qreal maximumX READ xmax WRITE setXmax NOTIFY maximumXChanged) + Q_PROPERTY(qreal minimumY READ ymin WRITE setYmin NOTIFY minimumYChanged) + Q_PROPERTY(qreal maximumY READ ymax WRITE setYmax NOTIFY maximumYChanged) + Q_PROPERTY(bool active READ active NOTIFY activeChanged) + +public: + QDeclarativePinch(); + + QGraphicsObject *target() const { return m_target; } + void setTarget(QGraphicsObject *target) { + if (target == m_target) + return; + m_target = target; + emit targetChanged(); + } + void resetTarget() { + if (!m_target) + return; + m_target = 0; + emit targetChanged(); + } + + qreal minimumScale() const { return m_minScale; } + void setMinimumScale(qreal s) { + if (s == m_minScale) + return; + m_minScale = s; + emit minimumScaleChanged(); + } + qreal maximumScale() const { return m_maxScale; } + void setMaximumScale(qreal s) { + if (s == m_maxScale) + return; + m_maxScale = s; + emit maximumScaleChanged(); + } + + qreal minimumRotation() const { return m_minRotation; } + void setMinimumRotation(qreal r) { + if (r == m_minRotation) + return; + m_minRotation = r; + emit minimumRotationChanged(); + } + qreal maximumRotation() const { return m_maxRotation; } + void setMaximumRotation(qreal r) { + if (r == m_maxRotation) + return; + m_maxRotation = r; + emit maximumRotationChanged(); + } + + enum Axis { NoDrag=0x00, XAxis=0x01, YAxis=0x02, XandYAxis=0x03 }; + Axis axis() const { return m_axis; } + void setAxis(Axis a) { + if (a == m_axis) + return; + m_axis = a; + emit dragAxisChanged(); + } + + qreal xmin() const { return m_xmin; } + void setXmin(qreal x) { + if (x == m_xmin) + return; + m_xmin = x; + emit minimumXChanged(); + } + qreal xmax() const { return m_xmax; } + void setXmax(qreal x) { + if (x == m_xmax) + return; + m_xmax = x; + emit maximumXChanged(); + } + qreal ymin() const { return m_ymin; } + void setYmin(qreal y) { + if (y == m_ymin) + return; + m_ymin = y; + emit minimumYChanged(); + } + qreal ymax() const { return m_ymax; } + void setYmax(qreal y) { + if (y == m_ymax) + return; + m_ymax = y; + emit maximumYChanged(); + } + + bool active() const { return m_active; } + void setActive(bool a) { + if (a == m_active) + return; + m_active = a; + emit activeChanged(); + } + +signals: + void targetChanged(); + void minimumScaleChanged(); + void maximumScaleChanged(); + void minimumRotationChanged(); + void maximumRotationChanged(); + void dragAxisChanged(); + void minimumXChanged(); + void maximumXChanged(); + void minimumYChanged(); + void maximumYChanged(); + void activeChanged(); + +private: + QGraphicsObject *m_target; + qreal m_minScale; + qreal m_maxScale; + qreal m_minRotation; + qreal m_maxRotation; + Axis m_axis; + qreal m_xmin; + qreal m_xmax; + qreal m_ymin; + qreal m_ymax; + bool m_active; +}; + +class Q_AUTOTEST_EXPORT QDeclarativePinchEvent : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QPointF center READ center) + Q_PROPERTY(QPointF startCenter READ startCenter) + Q_PROPERTY(QPointF lastCenter READ lastCenter) + Q_PROPERTY(qreal scale READ scale) + Q_PROPERTY(qreal lastScale READ lastScale) + Q_PROPERTY(qreal angle READ angle) + Q_PROPERTY(qreal lastAngle READ lastAngle) + Q_PROPERTY(qreal rotation READ rotation) + Q_PROPERTY(QPointF point1 READ point1) + Q_PROPERTY(QPointF startPoint1 READ startPoint1) + Q_PROPERTY(QPointF point2 READ point2) + Q_PROPERTY(QPointF startPoint2 READ startPoint2) + Q_PROPERTY(bool accepted READ accepted WRITE setAccepted) + +public: + QDeclarativePinchEvent(QPointF c, qreal s, qreal a, qreal r) + : QObject(), m_center(c), m_scale(s), m_angle(a), m_rotation(r) {} + + QPointF center() const { return m_center; } + QPointF startCenter() const { return m_startCenter; } + void setStartCenter(QPointF c) { m_startCenter = c; } + QPointF lastCenter() const { return m_lastCenter; } + void setLastCenter(QPointF c) { m_lastCenter = c; } + qreal scale() const { return m_scale; } + qreal lastScale() const { return m_lastScale; } + void setLastScale(qreal s) { m_lastScale = s; } + qreal angle() const { return m_angle; } + qreal lastAngle() const { return m_lastAngle; } + void setLastAngle(qreal a) { m_lastAngle = a; } + qreal rotation() const { return m_rotation; } + QPointF point1() const { return m_point1; } + void setPoint1(QPointF p) { m_point1 = p; } + QPointF startPoint1() const { return m_startPoint1; } + void setStartPoint1(QPointF p) { m_startPoint1 = p; } + QPointF point2() const { return m_point2; } + void setPoint2(QPointF p) { m_point2 = p; } + QPointF startPoint2() const { return m_startPoint2; } + void setStartPoint2(QPointF p) { m_startPoint2 = p; } + + bool accepted() const { return m_accepted; } + void setAccepted(bool a) { m_accepted = a; } + +private: + QPointF m_center; + QPointF m_startCenter; + QPointF m_lastCenter; + qreal m_scale; + qreal m_lastScale; + qreal m_angle; + qreal m_lastAngle; + qreal m_rotation; + QPointF m_point1; + QPointF m_point2; + QPointF m_startPoint1; + QPointF m_startPoint2; + bool m_accepted; +}; + + +class QDeclarativeMouseEvent; +class QDeclarativePinchAreaPrivate; +class Q_AUTOTEST_EXPORT QDeclarativePinchArea : public QDeclarativeItem +{ + Q_OBJECT + + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) + Q_PROPERTY(QDeclarativePinch *pinch READ pinch CONSTANT) + +public: + QDeclarativePinchArea(QDeclarativeItem *parent=0); + ~QDeclarativePinchArea(); + + bool isEnabled() const; + void setEnabled(bool); + + QDeclarativePinch *pinch(); + +Q_SIGNALS: + void enabledChanged(); + void pinchStarted(QDeclarativePinchEvent *pinch); + void pinchChanged(QDeclarativePinchEvent *pinch); + void pinchFinished(QDeclarativePinchEvent *pinch); + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + bool sceneEvent(QEvent *); + bool sendMouseEvent(QGraphicsSceneMouseEvent *event); + bool sceneEventFilter(QGraphicsItem *i, QEvent *e); + bool event(QEvent *); + + virtual void geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry); + virtual QVariant itemChange(GraphicsItemChange change, const QVariant& value); + +private: + void updatePinch(); + void handlePress(); + void handleRelease(); + +private: + Q_DISABLE_COPY(QDeclarativePinchArea) + Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativePinchArea) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativePinch) +QML_DECLARE_TYPE(QDeclarativePinchEvent) +QML_DECLARE_TYPE(QDeclarativePinchArea) + +QT_END_HEADER + +#endif // QDECLARATIVEPINCHAREA_H diff --git a/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h b/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h new file mode 100644 index 0000000..b1cdf68 --- /dev/null +++ b/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPINCHAREA_P_H +#define QDECLARATIVEPINCHAREA_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt 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. +// + +#include +#include +#include +#include +#include "qdeclarativeitem_p.h" + +QT_BEGIN_NAMESPACE + +class QDeclarativePinch; +class QDeclarativePinchAreaPrivate : public QDeclarativeItemPrivate +{ + Q_DECLARE_PUBLIC(QDeclarativePinchArea) +public: + QDeclarativePinchAreaPrivate() + : absorb(true), stealMouse(false), inPinch(false) + , pinchRejected(false), pinch(0) + { + } + + ~QDeclarativePinchAreaPrivate(); + + void init() + { + Q_Q(QDeclarativePinchArea); + q->setAcceptedMouseButtons(Qt::LeftButton); + q->setAcceptTouchEvents(true); + q->setFiltersChildEvents(true); + } + + bool absorb : 1; + bool stealMouse : 1; + bool inPinch : 1; + bool pinchRejected : 1; + QDeclarativePinch *pinch; + QPointF sceneStartPoint1; + QPointF sceneStartPoint2; + QPointF lastPoint1; + QPointF lastPoint2; + qreal pinchStartDist; + qreal pinchStartScale; + qreal pinchLastScale; + qreal pinchStartRotation; + qreal pinchStartAngle; + qreal pinchLastAngle; + QPointF sceneStartCenter; + QPointF pinchStartCenter; + QPointF sceneLastCenter; + QPointF pinchStartPos; + QList touchPoints; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEPINCHAREA_P_H diff --git a/tests/auto/declarative/qdeclarativepincharea/data/pinchproperties.qml b/tests/auto/declarative/qdeclarativepincharea/data/pinchproperties.qml new file mode 100644 index 0000000..f39ea06 --- /dev/null +++ b/tests/auto/declarative/qdeclarativepincharea/data/pinchproperties.qml @@ -0,0 +1,46 @@ +import QtQuick 1.1 +Rectangle { + id: whiteRect + property variant center + property real scale + width: 240; height: 320 + color: "white" + Rectangle { + id: blackRect + objectName: "blackrect" + color: "black" + y: 50 + x: 50 + width: 100 + height: 100 + opacity: (whiteRect.width-blackRect.x+whiteRect.height-blackRect.y-199)/200 + Text { text: blackRect.opacity} + PinchArea { + id: pincharea + objectName: "pincharea" + anchors.fill: parent + pinch.target: blackRect + pinch.dragAxis: Drag.XandYAxis + pinch.minimumX: 0 + pinch.maximumX: whiteRect.width-blackRect.width + pinch.minimumY: 0 + pinch.maximumY: whiteRect.height-blackRect.height + pinch.minimumScale: 1.0 + pinch.maximumScale: 2.0 + pinch.minimumRotation: 0.0 + pinch.maximumRotation: 90.0 + onPinchStarted: { + whiteRect.center = pinch.center + whiteRect.scale = pinch.scale + } + onPinchChanged: { + whiteRect.center = pinch.center + whiteRect.scale = pinch.scale + } + onPinchFinished: { + whiteRect.center = pinch.center + whiteRect.scale = pinch.scale + } + } + } + } diff --git a/tests/auto/declarative/qdeclarativepincharea/qdeclarativepincharea.pro b/tests/auto/declarative/qdeclarativepincharea/qdeclarativepincharea.pro new file mode 100644 index 0000000..2c13644 --- /dev/null +++ b/tests/auto/declarative/qdeclarativepincharea/qdeclarativepincharea.pro @@ -0,0 +1,16 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative gui +macx:CONFIG -= app_bundle + +SOURCES += tst_qdeclarativepincharea.cpp + +symbian: { + importFiles.sources = data + importFiles.path = . + DEPLOYMENT = importFiles +} else { + DEFINES += SRCDIR=\\\"$$PWD\\\" +} + +CONFIG += parallel_test + diff --git a/tests/auto/declarative/qdeclarativepincharea/tst_qdeclarativepincharea.cpp b/tests/auto/declarative/qdeclarativepincharea/tst_qdeclarativepincharea.cpp new file mode 100644 index 0000000..d1015fc --- /dev/null +++ b/tests/auto/declarative/qdeclarativepincharea/tst_qdeclarativepincharea.cpp @@ -0,0 +1,315 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_SYMBIAN +// In Symbian OS test data is located in applications private dir +#define SRCDIR "." +#endif + +class tst_QDeclarativePinchArea: public QObject +{ + Q_OBJECT +private slots: + void pinchProperties(); + void scale(); + void pan(); + +private: + QDeclarativeView *createView(); +}; + +void tst_QDeclarativePinchArea::pinchProperties() +{ + QDeclarativeView *canvas = createView(); + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pinchproperties.qml")); + canvas->show(); + canvas->setFocus(); + QVERIFY(canvas->rootObject() != 0); + + QDeclarativePinchArea *pinchArea = canvas->rootObject()->findChild("pincharea"); + QDeclarativePinch *pinch = pinchArea->pinch(); + QVERIFY(pinchArea != 0); + QVERIFY(pinch != 0); + + // target + QDeclarativeItem *blackRect = canvas->rootObject()->findChild("blackrect"); + QVERIFY(blackRect != 0); + QVERIFY(blackRect == pinch->target()); + QDeclarativeItem *rootItem = qobject_cast(canvas->rootObject()); + QVERIFY(rootItem != 0); + QSignalSpy targetSpy(pinch, SIGNAL(targetChanged())); + pinch->setTarget(rootItem); + QCOMPARE(targetSpy.count(),1); + pinch->setTarget(rootItem); + QCOMPARE(targetSpy.count(),1); + + // axis + QCOMPARE(pinch->axis(), QDeclarativePinch::XandYAxis); + QSignalSpy axisSpy(pinch, SIGNAL(dragAxisChanged())); + pinch->setAxis(QDeclarativePinch::XAxis); + QCOMPARE(pinch->axis(), QDeclarativePinch::XAxis); + QCOMPARE(axisSpy.count(),1); + pinch->setAxis(QDeclarativePinch::XAxis); + QCOMPARE(axisSpy.count(),1); + + // minimum and maximum drag properties + QSignalSpy xminSpy(pinch, SIGNAL(minimumXChanged())); + QSignalSpy xmaxSpy(pinch, SIGNAL(maximumXChanged())); + QSignalSpy yminSpy(pinch, SIGNAL(minimumYChanged())); + QSignalSpy ymaxSpy(pinch, SIGNAL(maximumYChanged())); + + QCOMPARE(pinch->xmin(), 0.0); + QCOMPARE(pinch->xmax(), rootItem->width()-blackRect->width()); + QCOMPARE(pinch->ymin(), 0.0); + QCOMPARE(pinch->ymax(), rootItem->height()-blackRect->height()); + + pinch->setXmin(10); + pinch->setXmax(10); + pinch->setYmin(10); + pinch->setYmax(10); + + QCOMPARE(pinch->xmin(), 10.0); + QCOMPARE(pinch->xmax(), 10.0); + QCOMPARE(pinch->ymin(), 10.0); + QCOMPARE(pinch->ymax(), 10.0); + + QCOMPARE(xminSpy.count(),1); + QCOMPARE(xmaxSpy.count(),1); + QCOMPARE(yminSpy.count(),1); + QCOMPARE(ymaxSpy.count(),1); + + pinch->setXmin(10); + pinch->setXmax(10); + pinch->setYmin(10); + pinch->setYmax(10); + + QCOMPARE(xminSpy.count(),1); + QCOMPARE(xmaxSpy.count(),1); + QCOMPARE(yminSpy.count(),1); + QCOMPARE(ymaxSpy.count(),1); + + // minimum and maximum scale properties + QSignalSpy scaleMinSpy(pinch, SIGNAL(minimumScaleChanged())); + QSignalSpy scaleMaxSpy(pinch, SIGNAL(maximumScaleChanged())); + + QCOMPARE(pinch->minimumScale(), 1.0); + QCOMPARE(pinch->maximumScale(), 2.0); + + pinch->setMinimumScale(0.5); + pinch->setMaximumScale(1.5); + + QCOMPARE(pinch->minimumScale(), 0.5); + QCOMPARE(pinch->maximumScale(), 1.5); + + QCOMPARE(scaleMinSpy.count(),1); + QCOMPARE(scaleMaxSpy.count(),1); + + pinch->setMinimumScale(0.5); + pinch->setMaximumScale(1.5); + + QCOMPARE(scaleMinSpy.count(),1); + QCOMPARE(scaleMaxSpy.count(),1); + + // minimum and maximum rotation properties + QSignalSpy rotMinSpy(pinch, SIGNAL(minimumRotationChanged())); + QSignalSpy rotMaxSpy(pinch, SIGNAL(maximumRotationChanged())); + + QCOMPARE(pinch->minimumRotation(), 0.0); + QCOMPARE(pinch->maximumRotation(), 90.0); + + pinch->setMinimumRotation(-90.0); + pinch->setMaximumRotation(45.0); + + QCOMPARE(pinch->minimumRotation(), -90.0); + QCOMPARE(pinch->maximumRotation(), 45.0); + + QCOMPARE(rotMinSpy.count(),1); + QCOMPARE(rotMaxSpy.count(),1); + + pinch->setMinimumRotation(-90.0); + pinch->setMaximumRotation(45.0); + + QCOMPARE(rotMinSpy.count(),1); + QCOMPARE(rotMaxSpy.count(),1); + + delete canvas; +} + +QTouchEvent::TouchPoint makeTouchPoint(int id, QPoint p, QGraphicsView *v, QGraphicsItem *i) +{ + QTouchEvent::TouchPoint touchPoint(id); + touchPoint.setPos(i->mapFromScene(p)); + touchPoint.setScreenPos(v->mapToGlobal(p)); + touchPoint.setScenePos(p); + return touchPoint; +} + +void tst_QDeclarativePinchArea::scale() +{ + QDeclarativeView *canvas = createView(); + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pinchproperties.qml")); + canvas->show(); + canvas->setFocus(); + QTest::qWaitForWindowShown(canvas); + QVERIFY(canvas->rootObject() != 0); + qApp->processEvents(); + + QDeclarativePinchArea *pinchArea = canvas->rootObject()->findChild("pincharea"); + QDeclarativePinch *pinch = pinchArea->pinch(); + QVERIFY(pinchArea != 0); + QVERIFY(pinch != 0); + + QDeclarativeItem *root = qobject_cast(canvas->rootObject()); + QVERIFY(root != 0); + + // target + QDeclarativeItem *blackRect = canvas->rootObject()->findChild("blackrect"); + QVERIFY(blackRect != 0); + + QWidget *vp = canvas->viewport(); + + QPoint p1(80, 80); + QPoint p2(100, 100); + + QTest::touchEvent(vp).press(0, p1); + QTest::touchEvent(vp).stationary(0).press(1, p2); + p1 -= QPoint(10,10); + p2 += QPoint(10,10); + QTest::touchEvent(vp).move(0, p1).move(1, p2); + + QCOMPARE(root->property("scale").toReal(), 1.0); + + p1 -= QPoint(10,10); + p2 += QPoint(10,10); + QTest::touchEvent(vp).move(0, p1).move(1, p2); + + QCOMPARE(root->property("scale").toReal(), 1.5); + QCOMPARE(root->property("center").toPointF(), QPointF(90, 90)); + QCOMPARE(blackRect->scale(), 1.5); + + // scale beyond bound + p1 -= QPoint(50,50); + p2 += QPoint(50,50); + QTest::touchEvent(vp).move(0, p1).move(1, p2); + + QCOMPARE(blackRect->scale(), 2.0); + + QTest::touchEvent(vp).release(0, p1).release(1, p2); + + delete canvas; +} + +void tst_QDeclarativePinchArea::pan() +{ + QDeclarativeView *canvas = createView(); + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/pinchproperties.qml")); + canvas->show(); + canvas->setFocus(); + QTest::qWaitForWindowShown(canvas); + QVERIFY(canvas->rootObject() != 0); + qApp->processEvents(); + + QDeclarativePinchArea *pinchArea = canvas->rootObject()->findChild("pincharea"); + QDeclarativePinch *pinch = pinchArea->pinch(); + QVERIFY(pinchArea != 0); + QVERIFY(pinch != 0); + + QDeclarativeItem *root = qobject_cast(canvas->rootObject()); + QVERIFY(root != 0); + + // target + QDeclarativeItem *blackRect = canvas->rootObject()->findChild("blackrect"); + QVERIFY(blackRect != 0); + + QWidget *vp = canvas->viewport(); + + QPoint p1(80, 80); + QPoint p2(100, 100); + + QTest::touchEvent(vp).press(0, p1); + QTest::touchEvent(vp).stationary(0).press(1, p2); + p1 += QPoint(10,10); + p2 += QPoint(10,10); + QTest::touchEvent(vp).move(0, p1).move(1, p2); + + QCOMPARE(root->property("scale").toReal(), 1.0); + + p1 += QPoint(10,10); + p2 += QPoint(10,10); + QTest::touchEvent(vp).move(0, p1).move(1, p2); + + QCOMPARE(root->property("center").toPointF(), QPointF(110, 110)); + + QCOMPARE(blackRect->x(), 60.0); + QCOMPARE(blackRect->y(), 60.0); + + // pan x beyond bound + p1 += QPoint(100,100); + p2 += QPoint(100,100); + QTest::touchEvent(vp).move(0, p1).move(1, p2); + + QCOMPARE(blackRect->x(), 140.0); + QCOMPARE(blackRect->y(), 160.0); + + QTest::touchEvent(vp).release(0, p1).release(1, p2); + + delete canvas; +} + +QDeclarativeView *tst_QDeclarativePinchArea::createView() +{ + QDeclarativeView *canvas = new QDeclarativeView(0); + canvas->viewport()->setAttribute(Qt::WA_AcceptTouchEvents); + canvas->setFixedSize(240,320); + + return canvas; +} + +QTEST_MAIN(tst_QDeclarativePinchArea) + +#include "tst_qdeclarativepincharea.moc" -- cgit v0.12 From 031ab2136c632d582a324941798be9e37825d287 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 29 Nov 2010 11:01:46 +1000 Subject: Allow resizing Flickable content about a center point. Useful for zooming via pinch, for example. Task-number: QTBUG-15148 Reviewed-by: Aaron Kennedy --- .../graphicsitems/qdeclarativeflickable.cpp | 54 ++++++++++++++++++++++ .../graphicsitems/qdeclarativeflickable_p.h | 4 ++ .../qdeclarativeflickable/data/resize.qml | 27 +++++++++++ .../tst_qdeclarativeflickable.cpp | 54 ++++++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 tests/auto/declarative/qdeclarativeflickable/data/resize.qml diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp index 377f3b5..b13d82b 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp +++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp @@ -1269,6 +1269,60 @@ void QDeclarativeFlickable::setContentHeight(qreal h) d->updateBeginningEnd(); } +/*! + \qmlmethod Flickable::resizeContent(real width, real height, QPointF center) + \preliminary + + Resizes the content to \a width x \a height about \a center. + + \bold {This method was added in QtQuick 1.1.} + + This does not scale the contents of the Flickable - it only resizes the \l contentWidth + and \l contentHeight. + + Resizing the content may result in the content being positioned outside + the bounds of the Flickable. Calling \l returnToBounds() will + move the content back within legal bounds. +*/ +void QDeclarativeFlickable::resizeContent(qreal w, qreal h, QPointF center) +{ + Q_D(QDeclarativeFlickable); + if (w != d->hData.viewSize) { + qreal oldSize = d->hData.viewSize; + setContentWidth(w); + if (center.x() != 0) { + qreal pos = center.x() * w / oldSize; + setContentX(contentX() + pos - center.x()); + } + } + if (h != d->vData.viewSize) { + qreal oldSize = d->vData.viewSize; + setContentHeight(h); + if (center.y() != 0) { + qreal pos = center.y() * h / oldSize; + setContentY(contentY() + pos - center.y()); + } + } +} + +/*! + \qmlmethod Flickable::returnToBounds() + \preliminary + + Ensures the content is within legal bounds. + + \bold {This method was added in QtQuick 1.1.} + + This may be called to ensure that the content is within legal bounds + after manually positioning the content. +*/ +void QDeclarativeFlickable::returnToBounds() +{ + Q_D(QDeclarativeFlickable); + d->fixupX(); + d->fixupY(); +} + qreal QDeclarativeFlickable::vWidth() const { Q_D(const QDeclarativeFlickable); diff --git a/src/declarative/graphicsitems/qdeclarativeflickable_p.h b/src/declarative/graphicsitems/qdeclarativeflickable_p.h index 6e4d8ed..ece2db7 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable_p.h +++ b/src/declarative/graphicsitems/qdeclarativeflickable_p.h @@ -149,6 +149,10 @@ public: FlickableDirection flickableDirection() const; void setFlickableDirection(FlickableDirection); + //XXX Added in QtQuick 1.1 + Q_INVOKABLE void resizeContent(qreal w, qreal h, QPointF center); + Q_INVOKABLE void returnToBounds(); + Q_SIGNALS: void contentWidthChanged(); void contentHeightChanged(); diff --git a/tests/auto/declarative/qdeclarativeflickable/data/resize.qml b/tests/auto/declarative/qdeclarativeflickable/data/resize.qml new file mode 100644 index 0000000..e2abb99 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeflickable/data/resize.qml @@ -0,0 +1,27 @@ +import QtQuick 1.1 + +Rectangle { + function resizeContent() { + flick.resizeContent(600, 600, Qt.point(100, 100)) + } + function returnToBounds() { + flick.returnToBounds() + } + width: 400 + height: 360 + color: "gray" + + Flickable { + id: flick + objectName: "flick" + anchors.fill: parent + contentWidth: 300 + contentHeight: 300 + + Rectangle { + width: flick.contentWidth + height: flick.contentHeight + color: "red" + } + } +} diff --git a/tests/auto/declarative/qdeclarativeflickable/tst_qdeclarativeflickable.cpp b/tests/auto/declarative/qdeclarativeflickable/tst_qdeclarativeflickable.cpp index 25edb36..c1564bc 100644 --- a/tests/auto/declarative/qdeclarativeflickable/tst_qdeclarativeflickable.cpp +++ b/tests/auto/declarative/qdeclarativeflickable/tst_qdeclarativeflickable.cpp @@ -46,6 +46,7 @@ #include #include #include +#include "../../../shared/util.h" #ifdef Q_OS_SYMBIAN // In Symbian OS test data is located in applications private dir @@ -69,6 +70,8 @@ private slots: void pressDelay(); void flickableDirection(); void qgraphicswidget(); + void resizeContent(); + void returnToBounds(); private: QDeclarativeEngine engine; @@ -277,6 +280,57 @@ void tst_qdeclarativeflickable::qgraphicswidget() QVERIFY(widget); } +// QtQuick 1.1 +void tst_qdeclarativeflickable::resizeContent() +{ + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/resize.qml")); + QDeclarativeItem *root = qobject_cast(c.create()); + QDeclarativeFlickable *obj = findItem(root, "flick"); + + QVERIFY(obj != 0); + QCOMPARE(obj->contentX(), 0.); + QCOMPARE(obj->contentY(), 0.); + QCOMPARE(obj->contentWidth(), 300.); + QCOMPARE(obj->contentHeight(), 300.); + + QMetaObject::invokeMethod(root, "resizeContent"); + + QCOMPARE(obj->contentX(), 100.); + QCOMPARE(obj->contentY(), 100.); + QCOMPARE(obj->contentWidth(), 600.); + QCOMPARE(obj->contentHeight(), 600.); + + delete root; +} + +// QtQuick 1.1 +void tst_qdeclarativeflickable::returnToBounds() +{ + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/resize.qml")); + QDeclarativeItem *root = qobject_cast(c.create()); + QDeclarativeFlickable *obj = findItem(root, "flick"); + + QVERIFY(obj != 0); + QCOMPARE(obj->contentX(), 0.); + QCOMPARE(obj->contentY(), 0.); + QCOMPARE(obj->contentWidth(), 300.); + QCOMPARE(obj->contentHeight(), 300.); + + obj->setContentX(100); + obj->setContentY(400); + QTRY_COMPARE(obj->contentX(), 100.); + QTRY_COMPARE(obj->contentY(), 400.); + + QMetaObject::invokeMethod(root, "returnToBounds"); + + QTRY_COMPARE(obj->contentX(), 0.); + QTRY_COMPARE(obj->contentY(), 0.); + + delete root; +} + template T *tst_qdeclarativeflickable::findItem(QGraphicsObject *parent, const QString &objectName) { -- cgit v0.12 From 6258fc281f5b66b2634b81a2633b117165cea7ef Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 29 Nov 2010 11:03:31 +1000 Subject: Add an example of using PinchArea. Task-number: QTBUG-15491 --- .../touchinteraction/pincharea/flickresize.qml | 50 +++++++++++++++++++++ .../touchinteraction/pincharea/qt-logo.jpg | Bin 0 -> 40886 bytes 2 files changed, 50 insertions(+) create mode 100644 examples/declarative/touchinteraction/pincharea/flickresize.qml create mode 100644 examples/declarative/touchinteraction/pincharea/qt-logo.jpg diff --git a/examples/declarative/touchinteraction/pincharea/flickresize.qml b/examples/declarative/touchinteraction/pincharea/flickresize.qml new file mode 100644 index 0000000..8034e29 --- /dev/null +++ b/examples/declarative/touchinteraction/pincharea/flickresize.qml @@ -0,0 +1,50 @@ +import QtQuick 1.1 + +Rectangle { + width: 640 + height: 360 + color: "gray" + + Flickable { + id: flick + anchors.fill: parent + contentWidth: 500 + contentHeight: 500 + + PinchArea { + width: Math.max(flick.contentWidth, flick.width) + height: Math.max(flick.contentHeight, flick.height) + onPinchChanged: { + // adjust content pos due to drag + flick.contentX += pinch.lastCenter.x - pinch.center.x + flick.contentY += pinch.lastCenter.y - pinch.center.y + + // resize content + var scale = 1.0 + pinch.scale - pinch.lastScale + flick.resizeContent(flick.contentWidth * scale, flick.contentHeight * scale, pinch.center) + } + + onPinchFinished: { + // Move its content within bounds. + flick.returnToBounds() + } + + Rectangle { + width: flick.contentWidth + height: flick.contentHeight + color: "white" + Image { + anchors.fill: parent + source: "qt-logo.jpg" + MouseArea { + anchors.fill: parent + onDoubleClicked: { + flick.contentWidth = 500 + flick.contentHeight = 500 + } + } + } + } + } + } +} diff --git a/examples/declarative/touchinteraction/pincharea/qt-logo.jpg b/examples/declarative/touchinteraction/pincharea/qt-logo.jpg new file mode 100644 index 0000000..4014b46 Binary files /dev/null and b/examples/declarative/touchinteraction/pincharea/qt-logo.jpg differ -- cgit v0.12 From b02cf26c0c236679439826cb8093f6dd6d3b2fec Mon Sep 17 00:00:00 2001 From: Christopher Ham Date: Fri, 3 Dec 2010 16:20:58 +1000 Subject: borderImage should not support setting sourceSize SIGNAL sourceSizeChanged is properly called. Setting the sourceSize for borderImage in QML returns a warning. Auto tests were added to check that sourceSize remains consistent. Reviewed-by: Joona Petrell --- src/declarative/graphicsitems/qdeclarativeborderimage.cpp | 10 ++++++++++ src/declarative/graphicsitems/qdeclarativeborderimage_p.h | 2 ++ .../qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp index c770a85..0bf09ad 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp @@ -246,6 +246,12 @@ void QDeclarativeBorderImage::setSource(const QUrl &url) load(); } +void QDeclarativeBorderImage::setSourceSize(const QSize& size) +{ + Q_UNUSED(size); + qmlInfo(this) << "Setting sourceSize for borderImage not supported"; +} + void QDeclarativeBorderImage::load() { Q_D(QDeclarativeBorderImage); @@ -315,6 +321,7 @@ void QDeclarativeBorderImage::load() d->progress = 1.0; emit statusChanged(d->status); emit progressChanged(d->progress); + requestFinished(); update(); } } @@ -475,6 +482,9 @@ void QDeclarativeBorderImage::requestFinished() setImplicitWidth(impsize.width()); setImplicitHeight(impsize.height()); + if (d->sourcesize.width() != d->pix.width() || d->sourcesize.height() != d->pix.height()) + emit sourceSizeChanged(); + d->progress = 1.0; emit statusChanged(d->status); emit progressChanged(1.0); diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage_p.h b/src/declarative/graphicsitems/qdeclarativeborderimage_p.h index 9944cbe..7cf24f2 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage_p.h +++ b/src/declarative/graphicsitems/qdeclarativeborderimage_p.h @@ -80,6 +80,8 @@ public: void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); void setSource(const QUrl &url); + void setSourceSize(const QSize&); + Q_SIGNALS: void horizontalTileModeChanged(); void verticalTileModeChanged(); diff --git a/tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp b/tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp index 2f00f60..5478145 100644 --- a/tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp +++ b/tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp @@ -153,6 +153,8 @@ void tst_qdeclarativeborderimage::imageSource() QTRY_VERIFY(obj->status() == QDeclarativeBorderImage::Ready); QCOMPARE(obj->width(), 120.); QCOMPARE(obj->height(), 120.); + QCOMPARE(obj->sourceSize().width(), 120); + QCOMPARE(obj->sourceSize().height(), 120); QCOMPARE(obj->horizontalTileMode(), QDeclarativeBorderImage::Stretch); QCOMPARE(obj->verticalTileMode(), QDeclarativeBorderImage::Stretch); } else { @@ -192,6 +194,8 @@ void tst_qdeclarativeborderimage::resized() QVERIFY(obj != 0); QCOMPARE(obj->width(), 300.); QCOMPARE(obj->height(), 300.); + QCOMPARE(obj->sourceSize().width(), 120); + QCOMPARE(obj->sourceSize().height(), 120); QCOMPARE(obj->horizontalTileMode(), QDeclarativeBorderImage::Stretch); QCOMPARE(obj->verticalTileMode(), QDeclarativeBorderImage::Stretch); -- cgit v0.12 From 61a5cc5fcde2de0c3639e20104ff58ca91cf793b Mon Sep 17 00:00:00 2001 From: Christiaan Janssen Date: Thu, 9 Dec 2010 14:31:10 +0100 Subject: QmlDebugger: avoid deferring properties when compiling in a debug environment Reviewed-by: Kai Koehne --- src/declarative/qml/qdeclarativecompiler.cpp | 6 +- .../qdeclarativedebug/tst_qdeclarativedebug.cpp | 97 +++++++++++++++++++++- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 4749bf8..b375b27 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -65,6 +65,7 @@ #include "private/qdeclarativebinding_p.h" #include "private/qdeclarativecompiledbindings_p.h" #include "private/qdeclarativeglobalscriptclass_p.h" +#include "private/qdeclarativedebugservice_p.h" #include #include @@ -754,7 +755,10 @@ bool QDeclarativeCompiler::buildObject(Object *obj, const BindingContext &ctxt) QList customProps; // Fetch the list of deferred properties - QStringList deferredList = deferredProperties(obj); + QStringList deferredList; + if (!QDeclarativeDebugService::isDebuggingEnabled()) { + deferredList = deferredProperties(obj); + } // Must do id property first. This is to ensure that the id given to any // id reference created matches the order in which the objects are diff --git a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp index 53471bf..20a3fa6 100644 --- a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp +++ b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp @@ -114,6 +114,7 @@ private slots: void tst_QDeclarativeDebugPropertyReference(); void setMethodBody(); + void queryObjectTree(); }; QDeclarativeDebugObjectReference tst_QDeclarativeDebug::findRootObject(int context) @@ -308,6 +309,34 @@ void tst_QDeclarativeDebug::initTestCase() "function myMethodIndirect() { myMethod(3); }\n" "}"; + // and a fourth to test states + qml << "import QtQuick 1.0\n" + "Rectangle {\n" + "id:rootRect\n" + "width:100\n" + "states: [\n" + "State {\n" + "name:\"state1\"\n" + "PropertyChanges {\n" + "target:rootRect\n" + "width:200\n" + "}\n" + "}\n" + "]\n" + "transitions: [\n" + "Transition {\n" + "from:\"*\"\n" + "to:\"state1\"\n" + "PropertyAnimation {\n" + "target:rootRect\n" + "property:\"width\"\n" + "duration:100\n" + "}\n" + "}\n" + "]\n" + "}\n" + ; + for (int i=0; iobjectName()); - QCOMPARE(context.objects().count(), 3); // 3 qml component objects created for context in main() + QCOMPARE(context.objects().count(), 4); // 4 qml component objects created for context in main() // root context query sends only root object data - it doesn't fill in // the children or property info QCOMPARE(context.objects()[0].properties().count(), 0); QCOMPARE(context.objects()[0].children().count(), 0); - QCOMPARE(context.contexts().count(), 4); + QCOMPARE(context.contexts().count(), 5); QVERIFY(context.contexts()[0].debugId() >= 0); QCOMPARE(context.contexts()[0].name(), QString("tst_QDeclarativeDebug_childContext")); @@ -897,6 +926,70 @@ void tst_QDeclarativeDebug::tst_QDeclarativeDebugPropertyReference() compareProperties(r, ref); } +void tst_QDeclarativeDebug::queryObjectTree() +{ + const int sourceIndex = 3; + + // Check if states/transitions are initialized when fetching root item + QDeclarativeDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this); + waitForQuery(q_engines); + + QDeclarativeDebugRootContextQuery *q_context = m_dbg->queryRootContexts(q_engines->engines()[0].debugId(), this); + waitForQuery(q_context); + + QVERIFY(q_context->rootContext().objects().count() > sourceIndex); + QDeclarativeDebugObjectReference rootObject = q_context->rootContext().objects()[sourceIndex]; + + QDeclarativeDebugObjectQuery *q_obj = m_dbg->queryObjectRecursive(rootObject, this); + waitForQuery(q_obj); + + QDeclarativeDebugObjectReference obj = q_obj->object(); + + delete q_engines; + delete q_context; + delete q_obj; + + QVERIFY(obj.debugId() != -1); + QVERIFY(obj.children().count() >= 2); + + + + // check state + QDeclarativeDebugObjectReference state = obj.children()[0]; + QCOMPARE(state.className(), QString("State")); + QVERIFY(state.children().count() > 0); + + QDeclarativeDebugObjectReference propertyChange = state.children()[0]; + QVERIFY(propertyChange.debugId() != -1); + + QDeclarativeDebugPropertyReference propertyChangeTarget = findProperty(propertyChange.properties(),"target"); + QCOMPARE(propertyChangeTarget.objectDebugId(), propertyChange.debugId()); + + QDeclarativeDebugObjectReference targetReference = qvariant_cast(propertyChangeTarget.value()); + QVERIFY(targetReference.debugId() != -1); + + + + // check transition + QDeclarativeDebugObjectReference transition = obj.children()[1]; + QCOMPARE(transition.className(), QString("Transition")); + QCOMPARE(findProperty(transition.properties(),"from").value().toString(), QString("*")); + QCOMPARE(findProperty(transition.properties(),"to").value(), findProperty(state.properties(),"name").value()); + QVERIFY(transition.children().count() > 0); + + QDeclarativeDebugObjectReference animation = transition.children()[0]; + QVERIFY(animation.debugId() != -1); + + QDeclarativeDebugPropertyReference animationTarget = findProperty(animation.properties(),"target"); + QCOMPARE(animationTarget.objectDebugId(), animation.debugId()); + + targetReference = qvariant_cast(animationTarget.value()); + QVERIFY(targetReference.debugId() != -1); + + QCOMPARE(findProperty(animation.properties(),"property").value().toString(), QString("width")); + QCOMPARE(findProperty(animation.properties(),"duration").value().toInt(), 100); +} + int main(int argc, char *argv[]) { int _argc = argc + 1; -- cgit v0.12 From f2eca0c0380a0e06ccc7f98c8d112549ac9fa085 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Fri, 10 Dec 2010 11:24:49 +1000 Subject: Add 'mirror' property to Image element. Setting mirror to true will horizontally invert an image. This feature is part of the task to support RTL in QML (see QTBUG-11042). Task-number: QTBUG-15878 Reviewed-by: Joona Petrell --- .../graphicsitems/qdeclarativeanimatedimage.cpp | 12 ++- .../graphicsitems/qdeclarativeborderimage.cpp | 19 ++++ .../graphicsitems/qdeclarativeimage.cpp | 103 +++++++++++---------- .../graphicsitems/qdeclarativeimagebase.cpp | 20 ++++ .../graphicsitems/qdeclarativeimagebase_p.h | 5 + .../graphicsitems/qdeclarativeimagebase_p_p.h | 4 +- .../qdeclarativeanimatedimage/data/hearts.gif | Bin 0 -> 6524 bytes .../qdeclarativeanimatedimage/data/hearts.qml | 6 ++ .../tst_qdeclarativeanimatedimage.cpp | 103 +++++++++++++++++++++ .../qdeclarativeborderimage/data/heart200.png | Bin 0 -> 7943 bytes .../tst_qdeclarativeborderimage.cpp | 34 +++++++ .../qdeclarativeimage/tst_qdeclarativeimage.cpp | 86 +++++++++++++++++ 12 files changed, 343 insertions(+), 49 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativeanimatedimage/data/hearts.gif create mode 100644 tests/auto/declarative/qdeclarativeanimatedimage/data/hearts.qml create mode 100644 tests/auto/declarative/qdeclarativeborderimage/data/heart200.png diff --git a/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp b/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp index 12a820f..abdfdfa 100644 --- a/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp @@ -86,6 +86,16 @@ QT_BEGIN_NAMESPACE \sa BorderImage, Image */ +/*! + \qmlproperty bool AnimatedImage::mirror + \since Quick 1.1 + + This property holds whether the image should be horizontally inverted + (effectively displaying a mirrored image). + + The default value is false. +*/ + QDeclarativeAnimatedImage::QDeclarativeAnimatedImage(QDeclarativeItem *parent) : QDeclarativeImage(*(new QDeclarativeAnimatedImagePrivate), parent) { @@ -126,7 +136,7 @@ void QDeclarativeAnimatedImage::setPaused(bool pause) \qmlproperty bool AnimatedImage::playing This property holds whether the animated image is playing. - By defaults, this property is true, meaning that the animation + By default, this property is true, meaning that the animation will start playing immediately. */ bool QDeclarativeAnimatedImage::isPlaying() const diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp index 0bf09ad..a25074a 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp @@ -200,6 +200,16 @@ QDeclarativeBorderImage::~QDeclarativeBorderImage() */ /*! + \qmlproperty bool BorderImage::mirror + \since Quick 1.1 + + This property holds whether the image should be horizontally inverted + (effectively displaying a mirrored image). + + The default value is false. +*/ + +/*! \qmlproperty url BorderImage::source This property holds the URL that refers to the source image. @@ -534,8 +544,15 @@ void QDeclarativeBorderImage::paint(QPainter *p, const QStyleOptionGraphicsItem bool oldAA = p->testRenderHint(QPainter::Antialiasing); bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform); + QTransform oldTransform; if (d->smooth) p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth); + if (d->mirror) { + oldTransform = p->transform(); + QTransform mirror; + mirror.translate(d->width(), 0).scale(-1, 1.0); + p->setWorldTransform(mirror * oldTransform); + } const QDeclarativeScaleGrid *border = d->getScaleGrid(); int left = border->left(); @@ -561,6 +578,8 @@ void QDeclarativeBorderImage::paint(QPainter *p, const QStyleOptionGraphicsItem p->setRenderHint(QPainter::Antialiasing, oldAA); p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth); } + if (d->mirror) + p->setWorldTransform(oldTransform); } QT_END_NAMESPACE diff --git a/src/declarative/graphicsitems/qdeclarativeimage.cpp b/src/declarative/graphicsitems/qdeclarativeimage.cpp index e07292b..68a1ecb 100644 --- a/src/declarative/graphicsitems/qdeclarativeimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimage.cpp @@ -467,84 +467,93 @@ QRectF QDeclarativeImage::boundingRect() const to make sure that they aren't cached at the expense of small 'ui element' images. */ +/*! + \qmlproperty bool Image::mirror + \since Quick 1.1 + + This property holds whether the image should be horizontally inverted + (effectively displaying a mirrored image). + + The default value is false. +*/ + + void QDeclarativeImage::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) { Q_D(QDeclarativeImage); if (d->pix.pixmap().isNull() ) return; - bool oldAA = p->testRenderHint(QPainter::Antialiasing); - bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform); - if (d->smooth) - p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth); + int drawWidth = width(); + int drawHeight = height(); + bool doClip = false; + QTransform transform; + qreal widthScale = width() / qreal(d->pix.width()); + qreal heightScale = height() / qreal(d->pix.height()); if (width() != d->pix.width() || height() != d->pix.height()) { if (d->fillMode >= Tile) { - if (d->fillMode == Tile) { - p->drawTiledPixmap(QRectF(0,0,width(),height()), d->pix); - } else { - qreal widthScale = width() / qreal(d->pix.width()); - qreal heightScale = height() / qreal(d->pix.height()); - - QTransform scale; - if (d->fillMode == TileVertically) { - scale.scale(widthScale, 1.0); - QTransform old = p->transform(); - p->setWorldTransform(scale * old); - p->drawTiledPixmap(QRectF(0,0,d->pix.width(),height()), d->pix); - p->setWorldTransform(old); - } else { - scale.scale(1.0, heightScale); - QTransform old = p->transform(); - p->setWorldTransform(scale * old); - p->drawTiledPixmap(QRectF(0,0,width(),d->pix.height()), d->pix); - p->setWorldTransform(old); - } + if (d->fillMode == TileVertically) { + transform.scale(widthScale, 1.0); + drawWidth = d->pix.width(); + } else if (d->fillMode == TileHorizontally) { + transform.scale(1.0, heightScale); + drawHeight = d->pix.height(); } } else { - qreal widthScale = width() / qreal(d->pix.width()); - qreal heightScale = height() / qreal(d->pix.height()); - - QTransform scale; - if (d->fillMode == PreserveAspectFit) { if (widthScale <= heightScale) { heightScale = widthScale; - scale.translate(0, (height() - heightScale * d->pix.height()) / 2); + transform.translate(0, (height() - heightScale * d->pix.height()) / 2); } else if(heightScale < widthScale) { widthScale = heightScale; - scale.translate((width() - widthScale * d->pix.width()) / 2, 0); + transform.translate((width() - widthScale * d->pix.width()) / 2, 0); } } else if (d->fillMode == PreserveAspectCrop) { if (widthScale < heightScale) { widthScale = heightScale; - scale.translate((width() - widthScale * d->pix.width()) / 2, 0); + transform.translate((width() - widthScale * d->pix.width()) / 2, 0); } else if(heightScale < widthScale) { heightScale = widthScale; - scale.translate(0, (height() - heightScale * d->pix.height()) / 2); + transform.translate(0, (height() - heightScale * d->pix.height()) / 2); } } - if (clip()) { - p->save(); - p->setClipRect(QRectF(0, 0, d->mWidth, d->mHeight), Qt::IntersectClip); - } - scale.scale(widthScale, heightScale); - QTransform old = p->transform(); - p->setWorldTransform(scale * old); - p->drawPixmap(0, 0, d->pix); - p->setWorldTransform(old); - if (clip()) { - p->restore(); - } + transform.scale(widthScale, heightScale); + drawWidth = d->pix.width(); + drawHeight = d->pix.height(); + doClip = clip(); } - } else { - p->drawPixmap(0, 0, d->pix); } + QTransform oldTransform; + bool oldAA = p->testRenderHint(QPainter::Antialiasing); + bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform); + if (d->smooth) + p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth); + if (doClip) { + p->save(); + p->setClipRect(QRectF(0, 0, d->mWidth, d->mHeight), Qt::IntersectClip); + } + if (d->mirror) + transform.translate(drawWidth, 0).scale(-1.0, 1.0); + if (!transform.isIdentity()) { + oldTransform = p->transform(); + p->setWorldTransform(transform * oldTransform); + } + + if (d->fillMode >= Tile) + p->drawTiledPixmap(QRectF(0, 0, drawWidth, drawHeight), d->pix); + else + p->drawPixmap(QRectF(0, 0, drawWidth, drawHeight), d->pix, QRectF(0, 0, drawWidth, drawHeight)); + if (d->smooth) { p->setRenderHint(QPainter::Antialiasing, oldAA); p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth); } + if (doClip) + p->restore(); + if (!transform.isIdentity()) + p->setWorldTransform(oldTransform); } void QDeclarativeImage::pixmapChange() diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp index 37b0734..c745635 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp @@ -146,6 +146,26 @@ void QDeclarativeImageBase::setCached(bool cached) load(); } +void QDeclarativeImageBase::setMirror(bool mirror) +{ + Q_D(QDeclarativeImageBase); + if (mirror == d->mirror) + return; + + d->mirror = mirror; + + if (isComponentComplete()) + update(); + + emit mirrorChanged(); +} + +bool QDeclarativeImageBase::mirror() const +{ + Q_D(const QDeclarativeImageBase); + return d->mirror; +} + void QDeclarativeImageBase::load() { Q_D(QDeclarativeImageBase); diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p.h index d25f7c3..b6e55ec 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase_p.h +++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p.h @@ -60,6 +60,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeImageBase : public QDeclarativeItem Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged) Q_PROPERTY(bool cached READ cached WRITE setCached NOTIFY cachedChanged) // ### VERSIONING: Only in QtQuick 1.1 Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize NOTIFY sourceSizeChanged) + Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged) // ### VERSIONING: Only in QtQuick 1.1 public: ~QDeclarativeImageBase(); @@ -79,6 +80,9 @@ public: virtual void setSourceSize(const QSize&); QSize sourceSize() const; + virtual void setMirror(bool mirror); + bool mirror() const; + Q_SIGNALS: void sourceChanged(const QUrl &); void sourceSizeChanged(); @@ -86,6 +90,7 @@ Q_SIGNALS: void progressChanged(qreal progress); void asynchronousChanged(); void cachedChanged(); + void mirrorChanged(); protected: virtual void load(); diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h index a539649..950914f 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p_p.h @@ -71,7 +71,8 @@ public: progress(0.0), explicitSourceSize(false), async(false), - cached(true) + cached(true), + mirror(false) { QGraphicsItemPrivate::flags = QGraphicsItemPrivate::flags & ~QGraphicsItem::ItemHasNoContents; } @@ -84,6 +85,7 @@ public: bool explicitSourceSize : 1; bool async : 1; bool cached : 1; + bool mirror: 1; }; QT_END_NAMESPACE diff --git a/tests/auto/declarative/qdeclarativeanimatedimage/data/hearts.gif b/tests/auto/declarative/qdeclarativeanimatedimage/data/hearts.gif new file mode 100644 index 0000000..cfb55f2 Binary files /dev/null and b/tests/auto/declarative/qdeclarativeanimatedimage/data/hearts.gif differ diff --git a/tests/auto/declarative/qdeclarativeanimatedimage/data/hearts.qml b/tests/auto/declarative/qdeclarativeanimatedimage/data/hearts.qml new file mode 100644 index 0000000..8729dd2 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeanimatedimage/data/hearts.qml @@ -0,0 +1,6 @@ +import QtQuick 1.0 + +AnimatedImage { + source: "hearts.gif" + playing: false +} diff --git a/tests/auto/declarative/qdeclarativeanimatedimage/tst_qdeclarativeanimatedimage.cpp b/tests/auto/declarative/qdeclarativeanimatedimage/tst_qdeclarativeanimatedimage.cpp index 8cbe813..bd701e7 100644 --- a/tests/auto/declarative/qdeclarativeanimatedimage/tst_qdeclarativeanimatedimage.cpp +++ b/tests/auto/declarative/qdeclarativeanimatedimage/tst_qdeclarativeanimatedimage.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include "../shared/testhttpserver.h" #include "../../../shared/util.h" @@ -66,13 +67,28 @@ private slots: void stopped(); void setFrame(); void frameCount(); + void mirror_running(); + void mirror_notRunning(); + void mirror_notRunning_data(); void remote(); void remote_data(); void sourceSize(); void sourceSizeReadOnly(); void invalidSource(); + +private: + QPixmap grabScene(QGraphicsScene *scene, int width, int height); }; +QPixmap tst_qdeclarativeanimatedimage::grabScene(QGraphicsScene *scene, int width, int height) +{ + QPixmap screenshot(width, height); + screenshot.fill(); + QPainter p_screenshot(&screenshot); + scene->render(&p_screenshot, QRect(0, 0, width, height), QRect(0, 0, width, height)); + return screenshot; +} + void tst_qdeclarativeanimatedimage::play() { QDeclarativeEngine engine; @@ -132,6 +148,93 @@ void tst_qdeclarativeanimatedimage::frameCount() delete anim; } +void tst_qdeclarativeanimatedimage::mirror_running() +{ + // test where mirror is set to true after animation has started + + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/hearts.qml")); + QDeclarativeAnimatedImage *anim = qobject_cast(component.create()); + QVERIFY(anim); + + QGraphicsScene scene; + int width = anim->property("width").toInt(); + int height = anim->property("height").toInt(); + scene.addItem(qobject_cast(anim)); + + QCOMPARE(anim->currentFrame(), 0); + QPixmap frame0 = grabScene(&scene, width, height); + anim->setCurrentFrame(1); + QPixmap frame1 = grabScene(&scene, width, height); + + anim->setCurrentFrame(0); + + QSignalSpy spy(anim, SIGNAL(frameChanged())); + anim->setPlaying(true); + + QTRY_VERIFY(spy.count() == 1); spy.clear(); + anim->setProperty("mirror", true); + + QCOMPARE(anim->currentFrame(), 1); + QPixmap frame1_flipped = grabScene(&scene, width, height); + + QTRY_VERIFY(spy.count() == 1); spy.clear(); + QCOMPARE(anim->currentFrame(), 0); // animation only has 2 frames, should cycle back to first + QPixmap frame0_flipped = grabScene(&scene, width, height); + + QTransform transform; + transform.translate(width, 0).scale(-1, 1.0); + QPixmap frame0_expected = frame0.transformed(transform); + QPixmap frame1_expected = frame1.transformed(transform); + + QCOMPARE(frame0_flipped, frame0_expected); + QCOMPARE(frame1_flipped, frame1_expected); +} + +void tst_qdeclarativeanimatedimage::mirror_notRunning() +{ + QFETCH(QUrl, fileUrl); + + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine, fileUrl); + QDeclarativeAnimatedImage *anim = qobject_cast(component.create()); + QVERIFY(anim); + + QGraphicsScene scene; + int width = anim->property("width").toInt(); + int height = anim->property("height").toInt(); + scene.addItem(qobject_cast(anim)); + QPixmap screenshot = grabScene(&scene, width, height); + + QTransform transform; + transform.translate(width, 0).scale(-1, 1.0); + QPixmap expected = screenshot.transformed(transform); + + int frame = anim->currentFrame(); + bool playing = anim->isPlaying(); + bool paused = anim->isPlaying(); + + anim->setProperty("mirror", true); + screenshot = grabScene(&scene, width, height); + + QCOMPARE(screenshot, expected); + + // mirroring should not change the current frame or playing status + QCOMPARE(anim->currentFrame(), frame); + QCOMPARE(anim->isPlaying(), playing); + QCOMPARE(anim->isPaused(), paused); + + delete anim; +} + +void tst_qdeclarativeanimatedimage::mirror_notRunning_data() +{ + QTest::addColumn("fileUrl"); + + QTest::newRow("paused") << QUrl::fromLocalFile(SRCDIR "/data/stickmanpause.qml"); + QTest::newRow("stopped") << QUrl::fromLocalFile(SRCDIR "/data/stickmanstopped.qml"); +} + void tst_qdeclarativeanimatedimage::remote() { QFETCH(QString, fileName); diff --git a/tests/auto/declarative/qdeclarativeborderimage/data/heart200.png b/tests/auto/declarative/qdeclarativeborderimage/data/heart200.png new file mode 100644 index 0000000..5a31ae8 Binary files /dev/null and b/tests/auto/declarative/qdeclarativeborderimage/data/heart200.png differ diff --git a/tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp b/tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp index 5478145..c22cde2 100644 --- a/tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp +++ b/tests/auto/declarative/qdeclarativeborderimage/tst_qdeclarativeborderimage.cpp @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include @@ -77,6 +79,7 @@ private slots: void clearSource(); void resized(); void smooth(); + void mirror(); void tileModes(); void sciSource(); void sciSource_data(); @@ -218,6 +221,37 @@ void tst_qdeclarativeborderimage::smooth() delete obj; } +void tst_qdeclarativeborderimage::mirror() +{ + QString componentStr = "import QtQuick 1.0\nBorderImage { source: \"" SRCDIR "/data/heart200.png\"; smooth: true; width: 300; height: 300; border { top: 50; right: 50; bottom: 50; left: 50 } }"; + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QDeclarativeBorderImage *obj = qobject_cast(component.create()); + QVERIFY(obj != 0); + + int width = obj->property("width").toInt(); + int height = obj->property("height").toInt(); + + QGraphicsScene scene; + scene.addItem(qobject_cast(obj)); + QPixmap screenshot(width, height); + screenshot.fill(); + QPainter p_screenshot(&screenshot); + scene.render(&p_screenshot, QRect(0, 0, width, height), QRect(0, 0, width, height)); + + QTransform transform; + transform.translate(width, 0).scale(-1, 1.0); + QPixmap expected = screenshot.transformed(transform); + + obj->setProperty("mirror", true); + p_screenshot.fillRect(QRect(0, 0, width, height), Qt::white); + scene.render(&p_screenshot, QRect(0, 0, width, height), QRect(0, 0, width, height)); + + QCOMPARE(screenshot, expected); + + delete obj; +} + void tst_qdeclarativeborderimage::tileModes() { { diff --git a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp index c811f62..27c7964 100644 --- a/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp +++ b/tests/auto/declarative/qdeclarativeimage/tst_qdeclarativeimage.cpp @@ -79,6 +79,8 @@ private slots: void resized(); void preserveAspectRatio(); void smooth(); + void mirror(); + void mirror_data(); void svg(); void geometry(); void geometry_data(); @@ -270,6 +272,90 @@ void tst_qdeclarativeimage::smooth() delete obj; } +void tst_qdeclarativeimage::mirror() +{ + QFETCH(int, fillMode); + + qreal width = 300; + qreal height = 250; + + QString src = QUrl::fromLocalFile(SRCDIR "/data/heart200.png").toString(); + QString componentStr = "import QtQuick 1.0\nImage { source: \"" + src + "\"; }"; + + QDeclarativeComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QDeclarativeImage *obj = qobject_cast(component.create()); + QVERIFY(obj != 0); + + obj->setProperty("width", width); + obj->setProperty("height", height); + obj->setFillMode((QDeclarativeImage::FillMode)fillMode); + obj->setProperty("mirror", true); + + QGraphicsScene scene; + scene.addItem(qobject_cast(obj)); + QPixmap screenshot(width, height); + screenshot.fill(); + QPainter p_screenshot(&screenshot); + scene.render(&p_screenshot, QRect(0, 0, width, height), QRect(0, 0, width, height)); + + QPixmap srcPixmap; + QVERIFY(srcPixmap.load(SRCDIR "/data/heart200.png")); + + QPixmap expected(width, height); + expected.fill(); + QPainter p_e(&expected); + QTransform transform; + transform.translate(width, 0).scale(-1, 1.0); + p_e.setTransform(transform); + + switch (fillMode) { + case QDeclarativeImage::Stretch: + p_e.drawPixmap(QRect(0, 0, width, height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height())); + break; + case QDeclarativeImage::PreserveAspectFit: + p_e.drawPixmap(QRect(25, 0, width / (width/height), height), srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height())); + break; + case QDeclarativeImage::PreserveAspectCrop: + { + qreal ratio = width/srcPixmap.width(); // width is the longer side + QRect rect(0, 0, srcPixmap.width()*ratio, srcPixmap.height()*ratio); + rect.moveCenter(QRect(0, 0, width, height).center()); + p_e.drawPixmap(rect, srcPixmap, QRect(0, 0, srcPixmap.width(), srcPixmap.height())); + break; + } + case QDeclarativeImage::Tile: + p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap); + break; + case QDeclarativeImage::TileVertically: + transform.scale(width / srcPixmap.width(), 1.0); + p_e.setTransform(transform); + p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap); + break; + case QDeclarativeImage::TileHorizontally: + transform.scale(1.0, height / srcPixmap.height()); + p_e.setTransform(transform); + p_e.drawTiledPixmap(QRect(0, 0, width, height), srcPixmap); + break; + } + + QCOMPARE(screenshot, expected); + + delete obj; +} + +void tst_qdeclarativeimage::mirror_data() +{ + QTest::addColumn("fillMode"); + + QTest::newRow("Stretch") << int(QDeclarativeImage::Stretch); + QTest::newRow("PreserveAspectFit") << int(QDeclarativeImage::PreserveAspectFit); + QTest::newRow("PreserveAspectCrop") << int(QDeclarativeImage::PreserveAspectCrop); + QTest::newRow("Tile") << int(QDeclarativeImage::Tile); + QTest::newRow("TileVertically") << int(QDeclarativeImage::TileVertically); + QTest::newRow("TileHorizontally") << int(QDeclarativeImage::TileHorizontally); +} + void tst_qdeclarativeimage::svg() { QString src = QUrl::fromLocalFile(SRCDIR "/data/heart.svg").toString(); -- cgit v0.12 From a32728ce8cf4fa1d1dc1001b1fadc66e9c86e025 Mon Sep 17 00:00:00 2001 From: Christopher Ham Date: Fri, 10 Dec 2010 13:03:59 +1000 Subject: The sourceSize property for borderImage should be read only Trying the sourceSize property from QML should emit a read-only warning. Task-number: QTBUG-15703 Reviewed-by: Bea Lam --- src/declarative/graphicsitems/qdeclarativeborderimage.cpp | 6 ------ src/declarative/graphicsitems/qdeclarativeborderimage_p.h | 6 ++++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp index a25074a..d9ba2bd 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp @@ -256,12 +256,6 @@ void QDeclarativeBorderImage::setSource(const QUrl &url) load(); } -void QDeclarativeBorderImage::setSourceSize(const QSize& size) -{ - Q_UNUSED(size); - qmlInfo(this) << "Setting sourceSize for borderImage not supported"; -} - void QDeclarativeBorderImage::load() { Q_D(QDeclarativeBorderImage); diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage_p.h b/src/declarative/graphicsitems/qdeclarativeborderimage_p.h index 7cf24f2..d9db0ac 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage_p.h +++ b/src/declarative/graphicsitems/qdeclarativeborderimage_p.h @@ -63,6 +63,9 @@ class Q_AUTOTEST_EXPORT QDeclarativeBorderImage : public QDeclarativeImageBase Q_PROPERTY(TileMode horizontalTileMode READ horizontalTileMode WRITE setHorizontalTileMode NOTIFY horizontalTileModeChanged) Q_PROPERTY(TileMode verticalTileMode READ verticalTileMode WRITE setVerticalTileMode NOTIFY verticalTileModeChanged) + // read-only for BorderImage + Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged) + public: QDeclarativeBorderImage(QDeclarativeItem *parent=0); ~QDeclarativeBorderImage(); @@ -80,11 +83,10 @@ public: void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); void setSource(const QUrl &url); - void setSourceSize(const QSize&); - Q_SIGNALS: void horizontalTileModeChanged(); void verticalTileModeChanged(); + void sourceSizeChanged(); protected: virtual void load(); -- cgit v0.12 From 5710cc981ae39a018d4c30b2c77f6623713a5bf1 Mon Sep 17 00:00:00 2001 From: Christopher Ham Date: Fri, 10 Dec 2010 13:19:03 +1000 Subject: KeyNavigation skips disabled or invisible items When using KeyNavigation, if the "visible" or "enabled" property of the item set in the KeyNavigation handler is false, an attempt will be made to skip this item and setFocus to the following item. Task-number: QTBUG-15862 Reviewed-by: Martin Jones --- src/declarative/graphicsitems/qdeclarativeitem.cpp | 46 ++++++++++--- src/declarative/graphicsitems/qdeclarativeitem_p.h | 1 + .../qdeclarativeitem/tst_qdeclarativeitem.cpp | 79 ++++++++++++++++++++++ 3 files changed, 118 insertions(+), 8 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp index 9d6fe12..cf12688 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp @@ -444,6 +444,11 @@ void QDeclarativeItemKeyFilter::componentComplete() \c KeyNavigation.BeforeItem allows the event to be used for key navigation before the item, rather than after. + If item to which the focus is switching is not enabled or visible, an attempt will + be made to skip this item and focus on the next. This is possible if there are + a chain of items with the same KeyNavigation handler. If multiple items in a row are not enabled + or visible, they will also be skipped. + \sa {Keys}{Keys attached property} */ @@ -452,10 +457,12 @@ void QDeclarativeItemKeyFilter::componentComplete() \qmlproperty Item KeyNavigation::right \qmlproperty Item KeyNavigation::up \qmlproperty Item KeyNavigation::down + \qmlproperty Item KeyNavigation::tab + \qmlproperty Item KeyNavigation::backtab These properties hold the item to assign focus to - when Key_Left, Key_Right, Key_Up or Key_Down are - pressed. + when Key_Left, Key_Right, Key_Up, Key_Down, Key_Tab or Key_BackTab + are pressed. */ QDeclarativeKeyNavigationAttached::QDeclarativeKeyNavigationAttached(QObject *parent) @@ -603,37 +610,37 @@ void QDeclarativeKeyNavigationAttached::keyPressed(QKeyEvent *event, bool post) switch(event->key()) { case Qt::Key_Left: if (d->left) { - d->left->setFocus(true); + setFocusNavigation(d->left, "left"); event->accept(); } break; case Qt::Key_Right: if (d->right) { - d->right->setFocus(true); + setFocusNavigation(d->right, "right"); event->accept(); } break; case Qt::Key_Up: if (d->up) { - d->up->setFocus(true); + setFocusNavigation(d->up, "up"); event->accept(); } break; case Qt::Key_Down: if (d->down) { - d->down->setFocus(true); + setFocusNavigation(d->down, "down"); event->accept(); } break; case Qt::Key_Tab: if (d->tab) { - d->tab->setFocus(true); + setFocusNavigation(d->tab, "tab"); event->accept(); } break; case Qt::Key_Backtab: if (d->backtab) { - d->backtab->setFocus(true); + setFocusNavigation(d->backtab, "backtab"); event->accept(); } break; @@ -692,6 +699,29 @@ void QDeclarativeKeyNavigationAttached::keyReleased(QKeyEvent *event, bool post) if (!event->isAccepted()) QDeclarativeItemKeyFilter::keyReleased(event, post); } +void QDeclarativeKeyNavigationAttached::setFocusNavigation(QDeclarativeItem *currentItem, const char *dir) +{ + QDeclarativeItem *initialItem = currentItem; + bool isNextItem = false; + do { + isNextItem = false; + if (currentItem->isVisible() && currentItem->isEnabled()) { + currentItem->setFocus(true); + } else { + QObject *attached = + qmlAttachedPropertiesObject(currentItem, false); + if (attached) { + QDeclarativeItem *tempItem = qvariant_cast(attached->property(dir)); + if (tempItem) { + currentItem = tempItem; + isNextItem = true; + } + } + } + } + while (currentItem != initialItem && isNextItem); +} + /*! \qmlclass Keys QDeclarativeKeysAttached \ingroup qml-basic-interaction-elements diff --git a/src/declarative/graphicsitems/qdeclarativeitem_p.h b/src/declarative/graphicsitems/qdeclarativeitem_p.h index d8635b9..402554b 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem_p.h +++ b/src/declarative/graphicsitems/qdeclarativeitem_p.h @@ -411,6 +411,7 @@ Q_SIGNALS: private: virtual void keyPressed(QKeyEvent *event, bool post); virtual void keyReleased(QKeyEvent *event, bool post); + void setFocusNavigation(QDeclarativeItem *currentItem, const char *dir); }; class QDeclarativeKeysAttachedPrivate : public QObjectPrivate diff --git a/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp b/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp index 711bf00..9587254 100644 --- a/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp +++ b/tests/auto/declarative/qdeclarativeitem/tst_qdeclarativeitem.cpp @@ -65,6 +65,7 @@ private slots: void keys(); void keysProcessingOrder(); void keyNavigation(); + void keyNavigation_skipNotVisible(); void smooth(); void clip(); void mapCoordinates(); @@ -450,6 +451,84 @@ void tst_QDeclarativeItem::keyNavigation() delete canvas; } +void tst_QDeclarativeItem::keyNavigation_skipNotVisible() +{ + QDeclarativeView *canvas = new QDeclarativeView(0); + canvas->setFixedSize(240,320); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/keynavigationtest.qml")); + canvas->show(); + qApp->processEvents(); + + QEvent wa(QEvent::WindowActivate); + QApplication::sendEvent(canvas, &wa); + QFocusEvent fe(QEvent::FocusIn); + QApplication::sendEvent(canvas, &fe); + + QDeclarativeItem *item = findItem(canvas->rootObject(), "item1"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + // Set item 2 to not visible + item = findItem(canvas->rootObject(), "item2"); + QVERIFY(item); + item->setVisible(false); + QVERIFY(!item->isVisible()); + + // right + QKeyEvent key(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1); + QApplication::sendEvent(canvas, &key); + QVERIFY(key.isAccepted()); + + item = findItem(canvas->rootObject(), "item1"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + // tab + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); + QApplication::sendEvent(canvas, &key); + QVERIFY(key.isAccepted()); + + item = findItem(canvas->rootObject(), "item3"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + // backtab + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1); + QApplication::sendEvent(canvas, &key); + QVERIFY(key.isAccepted()); + + item = findItem(canvas->rootObject(), "item1"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + //Set item 3 to not visible + item = findItem(canvas->rootObject(), "item3"); + QVERIFY(item); + item->setVisible(false); + QVERIFY(!item->isVisible()); + + // tab + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); + QApplication::sendEvent(canvas, &key); + QVERIFY(key.isAccepted()); + + item = findItem(canvas->rootObject(), "item4"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + // backtab + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Backtab, Qt::NoModifier, "", false, 1); + QApplication::sendEvent(canvas, &key); + QVERIFY(key.isAccepted()); + + item = findItem(canvas->rootObject(), "item1"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + delete canvas; +} + void tst_QDeclarativeItem::smooth() { QDeclarativeComponent component(&engine); -- cgit v0.12 From 6541562252cecd102788257022d3cf159954cae8 Mon Sep 17 00:00:00 2001 From: Christiaan Janssen Date: Fri, 10 Dec 2010 11:47:43 +0100 Subject: QmlDebugger: Instantiation of deferred objects moved to the debugger engine Reviewed-by: Kai Koehne --- src/declarative/qml/qdeclarativecompiler.cpp | 6 +----- src/declarative/qml/qdeclarativeenginedebug.cpp | 22 ++++++++++++++++------ src/declarative/qml/qdeclarativeenginedebug_p.h | 1 + 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index b375b27..4749bf8 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -65,7 +65,6 @@ #include "private/qdeclarativebinding_p.h" #include "private/qdeclarativecompiledbindings_p.h" #include "private/qdeclarativeglobalscriptclass_p.h" -#include "private/qdeclarativedebugservice_p.h" #include #include @@ -755,10 +754,7 @@ bool QDeclarativeCompiler::buildObject(Object *obj, const BindingContext &ctxt) QList customProps; // Fetch the list of deferred properties - QStringList deferredList; - if (!QDeclarativeDebugService::isDebuggingEnabled()) { - deferredList = deferredProperties(obj); - } + QStringList deferredList = deferredProperties(obj); // Must do id property first. This is to ensure that the id given to any // id reference created matches the order in which the objects are diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp index bffe681..5f338db 100644 --- a/src/declarative/qml/qdeclarativeenginedebug.cpp +++ b/src/declarative/qml/qdeclarativeenginedebug.cpp @@ -192,11 +192,6 @@ void QDeclarativeEngineDebugServer::buildObjectDump(QDataStream &message, { message << objectData(object); - // Some children aren't added to an object until particular properties are read - // - e.g. child state objects aren't added until the 'states' property is read - - // but this should only affect internal objects that aren't shown by the - // debugger anyway. - QObjectList children = object->children(); int childrenCount = children.count(); @@ -257,6 +252,18 @@ void QDeclarativeEngineDebugServer::buildObjectDump(QDataStream &message, message << fakeProperties[ii]; } +void QDeclarativeEngineDebugServer::prepareDeferredObjects(QObject *obj) +{ + qmlExecuteDeferred(obj); + + QObjectList children = obj->children(); + for (int ii = 0; ii < children.count(); ++ii) { + QObject *child = children.at(ii); + prepareDeferredObjects(child); + } + +} + void QDeclarativeEngineDebugServer::buildObjectList(QDataStream &message, QDeclarativeContext *ctxt) { QDeclarativeContextData *p = QDeclarativeContextData::get(ctxt); @@ -393,8 +400,11 @@ void QDeclarativeEngineDebugServer::messageReceived(const QByteArray &message) QDataStream rs(&reply, QIODevice::WriteOnly); rs << QByteArray("FETCH_OBJECT_R") << queryId; - if (object) + if (object) { + if (recurse) + prepareDeferredObjects(object); buildObjectDump(rs, object, recurse, dumpProperties); + } sendMessage(reply); } else if (type == "WATCH_OBJECT") { diff --git a/src/declarative/qml/qdeclarativeenginedebug_p.h b/src/declarative/qml/qdeclarativeenginedebug_p.h index 97b8121..dc8bc85 100644 --- a/src/declarative/qml/qdeclarativeenginedebug_p.h +++ b/src/declarative/qml/qdeclarativeenginedebug_p.h @@ -105,6 +105,7 @@ private Q_SLOTS: void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value); private: + void prepareDeferredObjects(QObject *); void buildObjectList(QDataStream &, QDeclarativeContext *); void buildObjectDump(QDataStream &, QObject *, bool, bool); QDeclarativeObjectData objectData(QObject *); -- cgit v0.12 From 3006bdd1eab665d3a0e666975246d2fb20b578af Mon Sep 17 00:00:00 2001 From: Christopher Ham Date: Mon, 13 Dec 2010 09:34:04 +1000 Subject: Adding documentation for borderImage Documentation describing the read-only behaviour of property sourceSize Task-number: QTBUG-15703 Reviewed-by: Martin Jones --- src/declarative/graphicsitems/qdeclarativeborderimage.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp index d9ba2bd..63b2b9a 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp @@ -236,6 +236,16 @@ QDeclarativeBorderImage::~QDeclarativeBorderImage() \sa QDeclarativeImageProvider */ + +/*! + \qmlproperty QSize BorderImage::sourceSize + + This property holds the actual width and height of the loaded image. + + In BorderImage, this property is read-only. + + \sa Image::sourceSize +*/ void QDeclarativeBorderImage::setSource(const QUrl &url) { Q_D(QDeclarativeBorderImage); -- cgit v0.12 From 409f60f0f6fd2c2bad6125d0463c812ba1b1180a Mon Sep 17 00:00:00 2001 From: Joona Petrell Date: Mon, 13 Dec 2010 15:34:23 +1000 Subject: Document TextInput property maximumLength Task-number: Reviewed-by: Martin Jones --- src/declarative/graphicsitems/qdeclarativetextinput.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index 0deacf8..2fb7ace 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -361,6 +361,14 @@ void QDeclarativeTextInput::setReadOnly(bool ro) emit readOnlyChanged(ro); } +/*! + \qmlproperty int TextInput::maximumLength + The maximum permitted length of the text in the TextInput. + + If the text is too long, it is truncated at the limit. + + By default, this property contains a value of 32767. +*/ int QDeclarativeTextInput::maxLength() const { Q_D(const QDeclarativeTextInput); -- cgit v0.12 From b3666a5ac8ee295adc86d8d20f5452eaad3063aa Mon Sep 17 00:00:00 2001 From: Joona Petrell Date: Mon, 13 Dec 2010 17:05:45 +1000 Subject: Revert "Add mirroring-positioners.qml example" that was accidentally pushed This reverts commit 18b940539d0633f30ae055feedb48aeb15969814. --- .../positioners/mirroring-positioners.qml | 70 ---------------------- 1 file changed, 70 deletions(-) delete mode 100644 examples/declarative/positioners/mirroring-positioners.qml diff --git a/examples/declarative/positioners/mirroring-positioners.qml b/examples/declarative/positioners/mirroring-positioners.qml deleted file mode 100644 index 0db95dd..0000000 --- a/examples/declarative/positioners/mirroring-positioners.qml +++ /dev/null @@ -1,70 +0,0 @@ -import QtQuick 1.0 - -Rectangle { - width: column.width+10 - height: column.height+10 - property bool arabic: false - Column { - id: column - spacing: 10 - anchors.centerIn: parent - Text { - text: "Row" - anchors.horizontalCenter: parent.horizontalCenter - } - Row { - flow: arabic ? Row.RightToLeft : Row.LeftToRight - spacing: 10 - Repeater { - model: 4 - Loader { - property int value: index - sourceComponent: delegate - } - } - } - Text { - text: "Grid" - anchors.horizontalCenter: parent.horizontalCenter - } - Grid { - flow: arabic ? Grid.RightToLeft : Grid.LeftToRight - spacing: 10; columns: 4 - Repeater { - model: 11 - Loader { - property int value: index - sourceComponent: delegate - } - } - } - Rectangle { - height: 50; width: parent.width - color: mouseArea.pressed ? "black" : "gray" - Text { - text: arabic ? "RTL" : "LTR" - color: "white" - font.pixelSize: 20 - anchors.centerIn: parent - } - MouseArea { - id: mouseArea - onClicked: arabic = !arabic - anchors.fill: parent - } - } - } - Component { - id: delegate - Rectangle { - width: 50; height: 50 - color: Qt.rgba(0.8/(parent.value+1),0.8/(parent.value+1),0.8/(parent.value+1),1.0) - Text { - text: parent.parent.value+1 - color: "white" - font.pixelSize: 20 - anchors.centerIn: parent - } - } - } -} -- cgit v0.12 From 7618adbd60f0aaeac63a1ac65e733fc8962a1cd9 Mon Sep 17 00:00:00 2001 From: Christiaan Janssen Date: Mon, 13 Dec 2010 13:26:56 +0100 Subject: QmlDebugger: setting bindings in states Reviewied-by: Kai Koehne --- src/declarative/qml/qdeclarativeenginedebug.cpp | 110 +++++++++++++++++---- src/declarative/qml/qdeclarativeenginedebug_p.h | 5 + .../qdeclarativedebug/tst_qdeclarativedebug.cpp | 101 ++++++++++++++++++- 3 files changed, 196 insertions(+), 20 deletions(-) diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp index 5f338db..4d6e50c 100644 --- a/src/declarative/qml/qdeclarativeenginedebug.cpp +++ b/src/declarative/qml/qdeclarativeenginedebug.cpp @@ -52,6 +52,7 @@ #include "private/qdeclarativevaluetype_p.h" #include "private/qdeclarativevmemetaobject_p.h" #include "private/qdeclarativeexpression_p.h" +#include "private/qdeclarativepropertychanges_p.h" #include #include @@ -304,6 +305,35 @@ void QDeclarativeEngineDebugServer::buildObjectList(QDataStream &message, QDecla } } +void QDeclarativeEngineDebugServer::buildStatesList(QDeclarativeContext *ctxt, bool cleanList=false) +{ + if (cleanList) + m_allStates.clear(); + + QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(ctxt); + for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) { + buildStatesList(ctxtPriv->instances.at(ii)); + } + + QDeclarativeContextData *child = QDeclarativeContextData::get(ctxt)->childContexts; + while (child) { + buildStatesList(child->asQDeclarativeContext()); + child = child->nextChild; + } +} + +void QDeclarativeEngineDebugServer::buildStatesList(QObject *obj) +{ + if (QDeclarativeState *state = dynamic_cast(obj)) { + m_allStates.append(state); + } + + QObjectList children = obj->children(); + for (int ii = 0; ii < children.count(); ++ii) { + buildStatesList(children.at(ii)); + } +} + QDeclarativeEngineDebugServer::QDeclarativeObjectData QDeclarativeEngineDebugServer::objectData(QObject *object) { @@ -382,8 +412,10 @@ void QDeclarativeEngineDebugServer::messageReceived(const QByteArray &message) QDataStream rs(&reply, QIODevice::WriteOnly); rs << QByteArray("LIST_OBJECTS_R") << queryId; - if (engine) + if (engine) { buildObjectList(rs, engine->rootContext()); + buildStatesList(engine->rootContext(), true); + } sendMessage(reply); } else if (type == "FETCH_OBJECT") { @@ -504,26 +536,66 @@ void QDeclarativeEngineDebugServer::setBinding(int objectId, { QObject *object = objectForId(objectId); QDeclarativeContext *context = qmlContext(object); + QByteArray propertyNameArray = propertyName.toUtf8(); if (object && context) { - QDeclarativeProperty property(object, propertyName, context); - if (isLiteralValue) { - property.write(expression); - } else if (hasValidSignal(object, propertyName)) { - QDeclarativeExpression *declarativeExpression = new QDeclarativeExpression(context, object, expression.toString()); - QDeclarativeExpression *oldExpression = QDeclarativePropertyPrivate::setSignalExpression(property, declarativeExpression); - declarativeExpression->setSourceLocation(oldExpression->sourceFile(), oldExpression->lineNumber()); - } else if (property.isProperty()) { - QDeclarativeBinding *binding = new QDeclarativeBinding(expression.toString(), object, context); - binding->setTarget(property); - binding->setNotifyOnValueChanged(true); - QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(property, binding); - if (oldBinding) - oldBinding->destroy(); - binding->update(); + if (property.isValid()) { + + bool inBaseState = true; + + foreach(QWeakPointer statePointer, m_allStates) { + if (QDeclarativeState *state = statePointer.data()) { + // here we assume that the revert list on itself defines the base state + if ( state->isStateActive() && state->containsPropertyInRevertList(object, propertyNameArray) ) { + inBaseState = false; + + QDeclarativeBinding *newBinding = 0; + if (!isLiteralValue) { + newBinding = new QDeclarativeBinding(expression.toString(), object, context); + newBinding->setTarget(property); + newBinding->setNotifyOnValueChanged(true); + } + + state->changeBindingInRevertList(object,propertyNameArray, newBinding); + + if (isLiteralValue) + state->changeValueInRevertList(object, propertyNameArray, expression); + } + } + } + + if (inBaseState) { + if (isLiteralValue) { + property.write(expression); + } else if (hasValidSignal(object, propertyName)) { + QDeclarativeExpression *declarativeExpression = new QDeclarativeExpression(context, object, expression.toString()); + QDeclarativeExpression *oldExpression = QDeclarativePropertyPrivate::setSignalExpression(property, declarativeExpression); + declarativeExpression->setSourceLocation(oldExpression->sourceFile(), oldExpression->lineNumber()); + } else if (property.isProperty()) { + QDeclarativeBinding *binding = new QDeclarativeBinding(expression.toString(), object, context); + binding->setTarget(property); + binding->setNotifyOnValueChanged(true); + QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(property, binding); + if (oldBinding) + oldBinding->destroy(); + binding->update(); + } else { + qWarning() << "QDeclarativeEngineDebugServer::setBinding: unable to set property" << propertyName << "on object" << object; + } + } + } else { - qWarning() << "QDeclarativeEngineDebugServer::setBinding: unable to set property" << propertyName << "on object" << object; + // not a valid property + if (QDeclarativePropertyChanges *propertyChanges = dynamic_cast(object)) { + if (isLiteralValue) { + propertyChanges->changeValue(propertyName.toUtf8(),expression); + } else { + propertyChanges->changeExpression(propertyName.toUtf8(),expression.toString()); + } + } else { + qWarning() << "QDeclarativeEngineDebugServer::setBinding: unable to set property" << propertyName << "on object" << object; + } } } } @@ -546,6 +618,10 @@ void QDeclarativeEngineDebugServer::resetBinding(int objectId, const QString &pr property.reset(); } } + } else { + if (QDeclarativePropertyChanges *propertyChanges = dynamic_cast(object)) { + propertyChanges->removeProperty(propertyName.toUtf8()); + } } } } diff --git a/src/declarative/qml/qdeclarativeenginedebug_p.h b/src/declarative/qml/qdeclarativeenginedebug_p.h index dc8bc85..65eb1ff 100644 --- a/src/declarative/qml/qdeclarativeenginedebug_p.h +++ b/src/declarative/qml/qdeclarativeenginedebug_p.h @@ -57,6 +57,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -64,6 +65,7 @@ class QDeclarativeEngine; class QDeclarativeContext; class QDeclarativeWatcher; class QDataStream; +class QDeclarativeState; class QDeclarativeEngineDebugServer : public QDeclarativeDebugService { @@ -108,6 +110,8 @@ private: void prepareDeferredObjects(QObject *); void buildObjectList(QDataStream &, QDeclarativeContext *); void buildObjectDump(QDataStream &, QObject *, bool, bool); + void buildStatesList(QDeclarativeContext *, bool); + void buildStatesList(QObject *obj); QDeclarativeObjectData objectData(QObject *); QDeclarativeObjectProperty propertyData(QObject *, int); QVariant valueContents(const QVariant &defaultValue) const; @@ -117,6 +121,7 @@ private: QList m_engines; QDeclarativeWatcher *m_watch; + QList > m_allStates; }; Q_DECLARATIVE_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QDeclarativeEngineDebugServer::QDeclarativeObjectData &); Q_DECLARATIVE_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QDeclarativeEngineDebugServer::QDeclarativeObjectData &); diff --git a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp index 20a3fa6..fac32d7 100644 --- a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp +++ b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp @@ -72,7 +72,7 @@ class tst_QDeclarativeDebug : public QObject Q_OBJECT private: - QDeclarativeDebugObjectReference findRootObject(int context = 0); + QDeclarativeDebugObjectReference findRootObject(int context = 0, bool recursive = false); QDeclarativeDebugPropertyReference findProperty(const QList &props, const QString &name) const; void waitForQuery(QDeclarativeDebugQuery *query); @@ -115,9 +115,10 @@ private slots: void setMethodBody(); void queryObjectTree(); + void setBindingInStates(); }; -QDeclarativeDebugObjectReference tst_QDeclarativeDebug::findRootObject(int context) +QDeclarativeDebugObjectReference tst_QDeclarativeDebug::findRootObject(int context, bool recursive) { QDeclarativeDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this); waitForQuery(q_engines); @@ -129,7 +130,9 @@ QDeclarativeDebugObjectReference tst_QDeclarativeDebug::findRootObject(int conte if (q_context->rootContext().objects().count() == 0) return QDeclarativeDebugObjectReference(); - QDeclarativeDebugObjectQuery *q_obj = m_dbg->queryObject(q_context->rootContext().objects()[context], this); + QDeclarativeDebugObjectQuery *q_obj = recursive ? + m_dbg->queryObjectRecursive(q_context->rootContext().objects()[context], this) : + m_dbg->queryObject(q_context->rootContext().objects()[context], this); waitForQuery(q_obj); QDeclarativeDebugObjectReference result = q_obj->object(); @@ -926,6 +929,98 @@ void tst_QDeclarativeDebug::tst_QDeclarativeDebugPropertyReference() compareProperties(r, ref); } +void tst_QDeclarativeDebug::setBindingInStates() +{ + // Check if changing bindings of propertychanges works + + const int sourceIndex = 3; + + QDeclarativeDebugObjectReference obj = findRootObject(sourceIndex); + + QVERIFY(obj.debugId() != -1); + QVERIFY(obj.children().count() >= 2); + + // We are going to switch state a couple of times, we need to get rid of the transition before + QDeclarativeDebugExpressionQuery *q_deleteTransition = m_dbg->queryExpressionResult(obj.debugId(),QString("transitions = []"),this); + waitForQuery(q_deleteTransition); + delete q_deleteTransition; + + + // check initial value of the property that is changing + QDeclarativeDebugExpressionQuery *q_setState; + q_setState = m_dbg->queryExpressionResult(obj.debugId(),QString("state=\"state1\""),this); + waitForQuery(q_setState); + delete q_setState; + + obj = findRootObject(sourceIndex); + QCOMPARE(findProperty(obj.properties(),"width").value().toInt(),200); + + + q_setState = m_dbg->queryExpressionResult(obj.debugId(),QString("state=\"\""),this); + waitForQuery(q_setState); + delete q_setState; + + + obj = findRootObject(sourceIndex, true); + QCOMPARE(findProperty(obj.properties(),"width").value().toInt(),100); + + + // change the binding + QDeclarativeDebugObjectReference state = obj.children()[0]; + QCOMPARE(state.className(), QString("State")); + QVERIFY(state.children().count() > 0); + + QDeclarativeDebugObjectReference propertyChange = state.children()[0]; + QVERIFY(propertyChange.debugId() != -1); + + QVERIFY( m_dbg->setBindingForObject(propertyChange.debugId(), "width",QVariant(300),true) ); + + // check properties changed in state + obj = findRootObject(sourceIndex); + QCOMPARE(findProperty(obj.properties(),"width").value().toInt(),100); + + + q_setState = m_dbg->queryExpressionResult(obj.debugId(),QString("state=\"state1\""),this); + waitForQuery(q_setState); + delete q_setState; + + obj = findRootObject(sourceIndex); + QCOMPARE(findProperty(obj.properties(),"width").value().toInt(),300); + + // check changing properties of base state from within a state + QVERIFY(m_dbg->setBindingForObject(obj.debugId(),"width","height*2",false)); + QVERIFY(m_dbg->setBindingForObject(obj.debugId(),"height","200",true)); + + obj = findRootObject(sourceIndex); + QCOMPARE(findProperty(obj.properties(),"width").value().toInt(),300); + + q_setState = m_dbg->queryExpressionResult(obj.debugId(),QString("state=\"\""),this); + waitForQuery(q_setState); + delete q_setState; + + obj = findRootObject(sourceIndex); + QCOMPARE(findProperty(obj.properties(),"width").value().toInt(), 400); + + // reset binding while in a state + q_setState = m_dbg->queryExpressionResult(obj.debugId(),QString("state=\"state1\""),this); + waitForQuery(q_setState); + delete q_setState; + + obj = findRootObject(sourceIndex); + QCOMPARE(findProperty(obj.properties(),"width").value().toInt(), 300); + + m_dbg->resetBindingForObject(propertyChange.debugId(), "width"); + + obj = findRootObject(sourceIndex); + QCOMPARE(findProperty(obj.properties(),"width").value().toInt(), 400); + + // re-add binding + m_dbg->setBindingForObject(propertyChange.debugId(), "width", "300", true); + + obj = findRootObject(sourceIndex); + QCOMPARE(findProperty(obj.properties(),"width").value().toInt(), 300); +} + void tst_QDeclarativeDebug::queryObjectTree() { const int sourceIndex = 3; -- cgit v0.12 From d1139664012718f9bbf54e283ef7c370d98c48a8 Mon Sep 17 00:00:00 2001 From: Christiaan Janssen Date: Thu, 16 Dec 2010 12:33:21 +0100 Subject: QmlDebugger: reset properties to default value Reviewed-by: Kai Koehne --- src/declarative/qml/qdeclarativeenginedebug.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp index 4d6e50c..6c013de 100644 --- a/src/declarative/qml/qdeclarativeenginedebug.cpp +++ b/src/declarative/qml/qdeclarativeenginedebug.cpp @@ -613,9 +613,25 @@ void QDeclarativeEngineDebugServer::resetBinding(int objectId, const QString &pr QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::setBinding(property, 0); if (oldBinding) oldBinding->destroy(); + } + if (property.isResettable()) { + // Note: this will reset the property in any case, without regard to states + // Right now almost no QDeclarativeItem has reset methods for its properties (with the + // notable exception of QDeclarativeAnchors), so this is not a big issue + // later on, setBinding does take states into account + property.reset(); } else { - if (property.isResettable()) { - property.reset(); + // overwrite with default value + if (QDeclarativeType *objType = QDeclarativeMetaType::qmlType(object->metaObject())) { + if (QObject *emptyObject = objType->create()) { + if (emptyObject->property(propertyName.toLatin1()).isValid()) { + QVariant defaultValue = QDeclarativeProperty(emptyObject, propertyName).read(); + if (defaultValue.isValid()) { + setBinding(objectId, propertyName, defaultValue, true); + } + } + delete emptyObject; + } } } } else { -- cgit v0.12 From c54443507edf98832c67d727746ae4a130a14571 Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Fri, 17 Dec 2010 15:55:50 +1000 Subject: Support for justification in Text and TextEdit elements. Task-number: QTBUG-13242 Reviewed-by: Michael Brasser --- src/declarative/graphicsitems/qdeclarativetext.cpp | 11 +++++++---- src/declarative/graphicsitems/qdeclarativetext_p.h | 3 ++- .../graphicsitems/qdeclarativetextedit.cpp | 1 + .../graphicsitems/qdeclarativetextedit_p.h | 3 ++- .../qdeclarativetext/align/data-MAC/justify.0.png | Bin 0 -> 7233 bytes .../qdeclarativetext/align/data-MAC/justify.qml | 11 +++++++++++ .../qmlvisual/qdeclarativetext/align/justify.qml | 22 +++++++++++++++++++++ .../qdeclarativetextedit/data-MAC/justify.0.png | Bin 0 -> 7233 bytes .../qdeclarativetextedit/data-MAC/justify.qml | 11 +++++++++++ .../qmlvisual/qdeclarativetextedit/justify.qml | 22 +++++++++++++++++++++ 10 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativetext/align/data-MAC/justify.0.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativetext/align/data-MAC/justify.qml create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativetext/align/justify.qml create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativetextedit/data-MAC/justify.0.png create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativetextedit/data-MAC/justify.qml create mode 100644 tests/auto/declarative/qmlvisual/qdeclarativetextedit/justify.qml diff --git a/src/declarative/graphicsitems/qdeclarativetext.cpp b/src/declarative/graphicsitems/qdeclarativetext.cpp index 303b21c..cf11be6 100644 --- a/src/declarative/graphicsitems/qdeclarativetext.cpp +++ b/src/declarative/graphicsitems/qdeclarativetext.cpp @@ -297,6 +297,8 @@ QSize QDeclarativeTextPrivate::setupTextLayout() lineWidth = q->width(); QTextOption textOption = layout.textOption(); + if (hAlign == QDeclarativeText::AlignJustify) + textOption.setAlignment(Qt::Alignment(hAlign)); textOption.setWrapMode(QTextOption::WrapMode(wrapMode)); layout.setTextOption(textOption); @@ -325,7 +327,7 @@ QSize QDeclarativeTextPrivate::setupTextLayout() height += line.height(); if (!cacheAllTextAsImage) { - if (hAlign == QDeclarativeText::AlignLeft) { + if ((hAlign == QDeclarativeText::AlignLeft) || (hAlign == QDeclarativeText::AlignJustify)) { x = 0; } else if (hAlign == QDeclarativeText::AlignRight) { x = layoutWidth - line.naturalTextWidth(); @@ -351,7 +353,7 @@ QPixmap QDeclarativeTextPrivate::textLayoutImage(bool drawStyle) qreal x = 0; for (int i = 0; i < layout.lineCount(); ++i) { QTextLine line = layout.lineAt(i); - if (hAlign == QDeclarativeText::AlignLeft) { + if ((hAlign == QDeclarativeText::AlignLeft) || (hAlign == QDeclarativeText::AlignJustify)) { x = 0; } else if (hAlign == QDeclarativeText::AlignRight) { x = size.width() - line.naturalTextWidth(); @@ -898,8 +900,8 @@ void QDeclarativeText::setStyleColor(const QColor &color) Sets the horizontal and vertical alignment of the text within the Text items width and height. By default, the text is top-left aligned. - The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight and - \c Text.AlignHCenter. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom + The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and + \c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom and \c Text.AlignVCenter. Note that for a single line of text, the size of the text is the area of the text. In this common case, @@ -1117,6 +1119,7 @@ QRectF QDeclarativeText::boundingRect() const switch (d->hAlign) { case AlignLeft: + case AlignJustify: x = 0; break; case AlignRight: diff --git a/src/declarative/graphicsitems/qdeclarativetext_p.h b/src/declarative/graphicsitems/qdeclarativetext_p.h index 51434d5..49bff14 100644 --- a/src/declarative/graphicsitems/qdeclarativetext_p.h +++ b/src/declarative/graphicsitems/qdeclarativetext_p.h @@ -82,7 +82,8 @@ public: enum HAlignment { AlignLeft = Qt::AlignLeft, AlignRight = Qt::AlignRight, - AlignHCenter = Qt::AlignHCenter }; + AlignHCenter = Qt::AlignHCenter, + AlignJustify = Qt::AlignJustify }; // ### VERSIONING: Only in QtQuick 1.1 enum VAlignment { AlignTop = Qt::AlignTop, AlignBottom = Qt::AlignBottom, AlignVCenter = Qt::AlignVCenter }; diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp index e05f4e4..f37fa62 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp @@ -442,6 +442,7 @@ void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color) \o TextEdit.AlignLeft (default) \o TextEdit.AlignRight \o TextEdit.AlignHCenter + \o TextEdit.AlignJustify \endlist Valid values for \c verticalAlignment are: diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p.h index 68fde3d..7f12c85 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextedit_p.h @@ -97,7 +97,8 @@ public: enum HAlignment { AlignLeft = Qt::AlignLeft, AlignRight = Qt::AlignRight, - AlignHCenter = Qt::AlignHCenter + AlignHCenter = Qt::AlignHCenter, + AlignJustify = Qt::AlignJustify // ### VERSIONING: Only in QtQuick 1.1 }; enum VAlignment { diff --git a/tests/auto/declarative/qmlvisual/qdeclarativetext/align/data-MAC/justify.0.png b/tests/auto/declarative/qmlvisual/qdeclarativetext/align/data-MAC/justify.0.png new file mode 100644 index 0000000..74c6934 Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativetext/align/data-MAC/justify.0.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativetext/align/data-MAC/justify.qml b/tests/auto/declarative/qmlvisual/qdeclarativetext/align/data-MAC/justify.qml new file mode 100644 index 0000000..e4dbeb1 --- /dev/null +++ b/tests/auto/declarative/qmlvisual/qdeclarativetext/align/data-MAC/justify.qml @@ -0,0 +1,11 @@ +import Qt.VisualTest 4.7 + +VisualTest { + Frame { + msec: 0 + } + Frame { + msec: 16 + image: "justify.0.png" + } +} diff --git a/tests/auto/declarative/qmlvisual/qdeclarativetext/align/justify.qml b/tests/auto/declarative/qmlvisual/qdeclarativetext/align/justify.qml new file mode 100644 index 0000000..c3a7aaa --- /dev/null +++ b/tests/auto/declarative/qmlvisual/qdeclarativetext/align/justify.qml @@ -0,0 +1,22 @@ +import QtQuick 1.0 +import "../../shared" 1.0 + +Rectangle { + width: 450 + height: 250 + + TestText { + anchors.fill: parent + anchors { leftMargin: 10; rightMargin: 10; topMargin:10; bottomMargin: 10 } + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignJustify + + text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin a aliquet massa. Integer id velit a nibh imperdiet sagittis. Cras fringilla enim non nulla porta bibendum. Integer risus urna, hendrerit non interdum ut, dapibus id velit. Nullam fermentum viverra pellentesque. In molestie scelerisque lorem molestie ultrices. Curabitur dolor arcu, tristique in sodales in, varius sed diam. Quisque magna velit, tincidunt sed ullamcorper sit amet, ornare adipiscing ligula. In hac habitasse platea dictumst. Ut tincidunt urna vel mauris fermentum ornare quis a ligula. Suspendisse cursus volutpat sapien eget cursus." + + Rectangle { + anchors.fill: parent + color: "transparent" + border.color: "red" + } + } +} diff --git a/tests/auto/declarative/qmlvisual/qdeclarativetextedit/data-MAC/justify.0.png b/tests/auto/declarative/qmlvisual/qdeclarativetextedit/data-MAC/justify.0.png new file mode 100644 index 0000000..74c6934 Binary files /dev/null and b/tests/auto/declarative/qmlvisual/qdeclarativetextedit/data-MAC/justify.0.png differ diff --git a/tests/auto/declarative/qmlvisual/qdeclarativetextedit/data-MAC/justify.qml b/tests/auto/declarative/qmlvisual/qdeclarativetextedit/data-MAC/justify.qml new file mode 100644 index 0000000..e4dbeb1 --- /dev/null +++ b/tests/auto/declarative/qmlvisual/qdeclarativetextedit/data-MAC/justify.qml @@ -0,0 +1,11 @@ +import Qt.VisualTest 4.7 + +VisualTest { + Frame { + msec: 0 + } + Frame { + msec: 16 + image: "justify.0.png" + } +} diff --git a/tests/auto/declarative/qmlvisual/qdeclarativetextedit/justify.qml b/tests/auto/declarative/qmlvisual/qdeclarativetextedit/justify.qml new file mode 100644 index 0000000..4aeb58c --- /dev/null +++ b/tests/auto/declarative/qmlvisual/qdeclarativetextedit/justify.qml @@ -0,0 +1,22 @@ +import QtQuick 1.0 +import "../shared" 1.0 + +Rectangle { + width: 450 + height: 250 + + TestTextEdit { + anchors.fill: parent + anchors { leftMargin: 10; rightMargin: 10; topMargin:10; bottomMargin: 10 } + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignJustify + + text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin a aliquet massa. Integer id velit a nibh imperdiet sagittis. Cras fringilla enim non nulla porta bibendum. Integer risus urna, hendrerit non interdum ut, dapibus id velit. Nullam fermentum viverra pellentesque. In molestie scelerisque lorem molestie ultrices. Curabitur dolor arcu, tristique in sodales in, varius sed diam. Quisque magna velit, tincidunt sed ullamcorper sit amet, ornare adipiscing ligula. In hac habitasse platea dictumst. Ut tincidunt urna vel mauris fermentum ornare quis a ligula. Suspendisse cursus volutpat sapien eget cursus." + + Rectangle { + anchors.fill: parent + color: "transparent" + border.color: "red" + } + } +} -- cgit v0.12 From cdd9209590f9c970ea6f9e0c734f0729610ede2a Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 14 Dec 2010 08:54:25 +1000 Subject: Optimization for photoviewer demo. --- demos/declarative/photoviewer/PhotoViewerCore/PhotoDelegate.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/declarative/photoviewer/PhotoViewerCore/PhotoDelegate.qml b/demos/declarative/photoviewer/PhotoViewerCore/PhotoDelegate.qml index 856a2c7..6248745 100644 --- a/demos/declarative/photoviewer/PhotoViewerCore/PhotoDelegate.qml +++ b/demos/declarative/photoviewer/PhotoViewerCore/PhotoDelegate.qml @@ -61,7 +61,7 @@ Package { BorderImage { anchors { - fill: border.visible ? border : placeHolder + fill: originalImage.status == Image.Ready ? border : placeHolder leftMargin: -6; topMargin: -6; rightMargin: -8; bottomMargin: -8 } source: 'images/box-shadow.png'; smooth: true -- cgit v0.12 From 139ecc0e74af2795faa55cfd532aeb10c631049e Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 14 Dec 2010 10:20:57 +1000 Subject: Optimize construction of QDeclarativeProperty in state operations. Reviewed-by: Martin Jones --- src/declarative/util/qdeclarativestate.cpp | 2 +- .../util/qdeclarativestateoperations.cpp | 63 ++++++++++++---------- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/declarative/util/qdeclarativestate.cpp b/src/declarative/util/qdeclarativestate.cpp index 3915485..6925e03 100644 --- a/src/declarative/util/qdeclarativestate.cpp +++ b/src/declarative/util/qdeclarativestate.cpp @@ -66,7 +66,7 @@ QDeclarativeAction::QDeclarativeAction() QDeclarativeAction::QDeclarativeAction(QObject *target, const QString &propertyName, const QVariant &value) : restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false), - property(target, propertyName), toValue(value), + property(target, propertyName, qmlEngine(target)), toValue(value), fromBinding(0), event(0), specifiedObject(target), specifiedProperty(propertyName) { diff --git a/src/declarative/util/qdeclarativestateoperations.cpp b/src/declarative/util/qdeclarativestateoperations.cpp index d1d7822..82360b2 100644 --- a/src/declarative/util/qdeclarativestateoperations.cpp +++ b/src/declarative/util/qdeclarativestateoperations.cpp @@ -367,16 +367,18 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() a.event = this; actions << a; + QDeclarativeContext *ctxt = qmlContext(this); + if (d->xString.isValid()) { bool ok = false; QString script = d->xString.value.script(); qreal x = script.toFloat(&ok); if (ok) { - QDeclarativeAction xa(d->target, QLatin1String("x"), x); + QDeclarativeAction xa(d->target, QLatin1String("x"), ctxt, x); actions << xa; } else { - QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this)); - newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("x"))); + QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, ctxt); + newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("x"), ctxt)); QDeclarativeAction xa; xa.property = newBinding->property(); xa.toBinding = newBinding; @@ -391,11 +393,11 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() QString script = d->yString.value.script(); qreal y = script.toFloat(&ok); if (ok) { - QDeclarativeAction ya(d->target, QLatin1String("y"), y); + QDeclarativeAction ya(d->target, QLatin1String("y"), ctxt, y); actions << ya; } else { - QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this)); - newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("y"))); + QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, ctxt); + newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("y"), ctxt)); QDeclarativeAction ya; ya.property = newBinding->property(); ya.toBinding = newBinding; @@ -410,11 +412,11 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() QString script = d->scaleString.value.script(); qreal scale = script.toFloat(&ok); if (ok) { - QDeclarativeAction sa(d->target, QLatin1String("scale"), scale); + QDeclarativeAction sa(d->target, QLatin1String("scale"), ctxt, scale); actions << sa; } else { - QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this)); - newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("scale"))); + QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, ctxt); + newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("scale"), ctxt)); QDeclarativeAction sa; sa.property = newBinding->property(); sa.toBinding = newBinding; @@ -429,11 +431,11 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() QString script = d->rotationString.value.script(); qreal rotation = script.toFloat(&ok); if (ok) { - QDeclarativeAction ra(d->target, QLatin1String("rotation"), rotation); + QDeclarativeAction ra(d->target, QLatin1String("rotation"), ctxt, rotation); actions << ra; } else { - QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this)); - newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("rotation"))); + QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, ctxt); + newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("rotation"), ctxt)); QDeclarativeAction ra; ra.property = newBinding->property(); ra.toBinding = newBinding; @@ -448,11 +450,11 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() QString script = d->widthString.value.script(); qreal width = script.toFloat(&ok); if (ok) { - QDeclarativeAction wa(d->target, QLatin1String("width"), width); + QDeclarativeAction wa(d->target, QLatin1String("width"), ctxt, width); actions << wa; } else { - QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this)); - newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("width"))); + QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, ctxt); + newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("width"), ctxt)); QDeclarativeAction wa; wa.property = newBinding->property(); wa.toBinding = newBinding; @@ -467,11 +469,11 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() QString script = d->heightString.value.script(); qreal height = script.toFloat(&ok); if (ok) { - QDeclarativeAction ha(d->target, QLatin1String("height"), height); + QDeclarativeAction ha(d->target, QLatin1String("height"), ctxt, height); actions << ha; } else { - QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, qmlContext(this)); - newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("height"))); + QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, ctxt); + newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("height"), ctxt)); QDeclarativeAction ha; ha.property = newBinding->property(); ha.toBinding = newBinding; @@ -1075,32 +1077,34 @@ QDeclarativeAnchorChanges::ActionList QDeclarativeAnchorChanges::actions() d->vCenterProp = QDeclarativeProperty(d->target, QLatin1String("anchors.verticalCenter")); d->baselineProp = QDeclarativeProperty(d->target, QLatin1String("anchors.baseline")); + QDeclarativeContext *ctxt = qmlContext(this); + if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::LeftAnchor) { - d->leftBinding = new QDeclarativeBinding(d->anchorSet->d_func()->leftScript.script(), d->target, qmlContext(this)); + d->leftBinding = new QDeclarativeBinding(d->anchorSet->d_func()->leftScript.script(), d->target, ctxt); d->leftBinding->setTarget(d->leftProp); } if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::RightAnchor) { - d->rightBinding = new QDeclarativeBinding(d->anchorSet->d_func()->rightScript.script(), d->target, qmlContext(this)); + d->rightBinding = new QDeclarativeBinding(d->anchorSet->d_func()->rightScript.script(), d->target, ctxt); d->rightBinding->setTarget(d->rightProp); } if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::HCenterAnchor) { - d->hCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->hCenterScript.script(), d->target, qmlContext(this)); + d->hCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->hCenterScript.script(), d->target, ctxt); d->hCenterBinding->setTarget(d->hCenterProp); } if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::TopAnchor) { - d->topBinding = new QDeclarativeBinding(d->anchorSet->d_func()->topScript.script(), d->target, qmlContext(this)); + d->topBinding = new QDeclarativeBinding(d->anchorSet->d_func()->topScript.script(), d->target, ctxt); d->topBinding->setTarget(d->topProp); } if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::BottomAnchor) { - d->bottomBinding = new QDeclarativeBinding(d->anchorSet->d_func()->bottomScript.script(), d->target, qmlContext(this)); + d->bottomBinding = new QDeclarativeBinding(d->anchorSet->d_func()->bottomScript.script(), d->target, ctxt); d->bottomBinding->setTarget(d->bottomProp); } if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::VCenterAnchor) { - d->vCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->vCenterScript.script(), d->target, qmlContext(this)); + d->vCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->vCenterScript.script(), d->target, ctxt); d->vCenterBinding->setTarget(d->vCenterProp); } if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::BaselineAnchor) { - d->baselineBinding = new QDeclarativeBinding(d->anchorSet->d_func()->baselineScript.script(), d->target, qmlContext(this)); + d->baselineBinding = new QDeclarativeBinding(d->anchorSet->d_func()->baselineScript.script(), d->target, ctxt); d->baselineBinding->setTarget(d->baselineProp); } @@ -1380,24 +1384,25 @@ QList QDeclarativeAnchorChanges::additionalActions() bool vChange = combined & QDeclarativeAnchors::Vertical_Mask; if (d->target) { + QDeclarativeContext *ctxt = qmlContext(this); QDeclarativeAction a; if (hChange && d->fromX != d->toX) { - a.property = QDeclarativeProperty(d->target, QLatin1String("x")); + a.property = QDeclarativeProperty(d->target, QLatin1String("x"), ctxt); a.toValue = d->toX; extra << a; } if (vChange && d->fromY != d->toY) { - a.property = QDeclarativeProperty(d->target, QLatin1String("y")); + a.property = QDeclarativeProperty(d->target, QLatin1String("y"), ctxt); a.toValue = d->toY; extra << a; } if (hChange && d->fromWidth != d->toWidth) { - a.property = QDeclarativeProperty(d->target, QLatin1String("width")); + a.property = QDeclarativeProperty(d->target, QLatin1String("width"), ctxt); a.toValue = d->toWidth; extra << a; } if (vChange && d->fromHeight != d->toHeight) { - a.property = QDeclarativeProperty(d->target, QLatin1String("height")); + a.property = QDeclarativeProperty(d->target, QLatin1String("height"), ctxt); a.toValue = d->toHeight; extra << a; } -- cgit v0.12 From 488e616b50707e5b37162e6d0cfc71a1ffdf9bef Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 15 Dec 2010 12:08:13 +1000 Subject: Rewrite/cache bindings created by PropertyChanges. This provides a significant optimization for initial evaluation of bindings specified in a PropertyChanges. Reviewed-by: Aaron Kennedy --- src/declarative/qml/qdeclarativebinding.cpp | 14 +++++++++++ src/declarative/qml/qdeclarativebinding_p.h | 3 +++ src/declarative/qml/qdeclarativecompiler.cpp | 29 ++++++++++++++++++++++ src/declarative/qml/qdeclarativecompiler_p.h | 1 + src/declarative/qml/qdeclarativecontext_p.h | 1 - src/declarative/qml/qdeclarativecustomparser.cpp | 9 +++++++ src/declarative/qml/qdeclarativecustomparser_p.h | 3 +++ .../util/qdeclarativepropertychanges.cpp | 26 ++++++++++++++++--- 8 files changed, 82 insertions(+), 4 deletions(-) diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index 309d372..1ead6ce 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -46,6 +46,7 @@ #include "qdeclarativecontext.h" #include "qdeclarativeinfo.h" #include "private/qdeclarativecontext_p.h" +#include "private/qdeclarativecompiler_p.h" #include "private/qdeclarativedata_p.h" #include "private/qdeclarativestringconverters_p.h" #include "private/qdeclarativestate_p_p.h" @@ -233,6 +234,19 @@ QDeclarativeBinding::QDeclarativeBinding(void *data, QDeclarativeRefCount *rc, Q setNotifyOnValueChanged(true); } +QDeclarativeBinding * +QDeclarativeBinding::createBinding(Identifier id, QObject *obj, QDeclarativeContext *ctxt, + const QString &url, int lineNumber, QObject *parent) +{ + QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(ctxt); + + QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(qmlEngine(obj)); + QDeclarativeCompiledData *cdata = 0; + if (engine && ctxtdata && !ctxtdata->url.isEmpty()) + cdata = engine->typeLoader.get(ctxtdata->url)->compiledData(); + return cdata ? new QDeclarativeBinding((void*)cdata->datas.at(id).constData(), cdata, obj, ctxtdata, url, lineNumber, parent) : 0; +} + QDeclarativeBinding::QDeclarativeBinding(const QString &str, QObject *obj, QDeclarativeContext *ctxt, QObject *parent) : QDeclarativeExpression(QDeclarativeContextData::get(ctxt), obj, str, *new QDeclarativeBindingPrivate) diff --git a/src/declarative/qml/qdeclarativebinding_p.h b/src/declarative/qml/qdeclarativebinding_p.h index 7823a3d..787a3b9 100644 --- a/src/declarative/qml/qdeclarativebinding_p.h +++ b/src/declarative/qml/qdeclarativebinding_p.h @@ -162,6 +162,9 @@ public: virtual void update(QDeclarativePropertyPrivate::WriteFlags flags); virtual QString expression() const; + typedef int Identifier; + static QDeclarativeBinding *createBinding(Identifier, QObject *, QDeclarativeContext *, const QString &, int, QObject *parent=0); + public Q_SLOTS: void update() { update(QDeclarativePropertyPrivate::DontRemoveBinding); } diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 4749bf8..4f4ad3f 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -2262,6 +2262,35 @@ const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) con return qmltype->metaObject(); } +// similar to logic of completeComponentBuild, but also sticks data +// into datas at the end +int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name) +{ + QDeclarativeRewrite::RewriteBinding rewriteBinding; + rewriteBinding.setName('$' + name); + bool isSharable = false; + QString rewrite = rewriteBinding(expression, 0, &isSharable); + + quint32 length = rewrite.length(); + quint32 pc; + + if (isSharable) { + pc = output->cachedClosures.count(); + pc |= 0x80000000; + output->cachedClosures.append(0); + } else { + pc = output->cachedPrograms.length(); + output->cachedPrograms.append(0); + } + + QByteArray compiledData = + QByteArray((const char *)&pc, sizeof(quint32)) + + QByteArray((const char *)&length, sizeof(quint32)) + + QByteArray((const char *)rewrite.constData(), + rewrite.length() * sizeof(QChar)); + + return output->indexForByteArray(compiledData); +} // Ensures that the dynamic meta specification on obj is valid bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeParser::Object *obj) diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h index 7d76ad9..bface8f 100644 --- a/src/declarative/qml/qdeclarativecompiler_p.h +++ b/src/declarative/qml/qdeclarativecompiler_p.h @@ -161,6 +161,7 @@ public: int evaluateEnum(const QByteArray& script) const; // for QDeclarativeCustomParser::evaluateEnum const QMetaObject *resolveType(const QByteArray& name) const; // for QDeclarativeCustomParser::resolveType + int rewriteBinding(const QString& expression, const QByteArray& name); // for QDeclarativeCustomParser::rewriteBinding private: static void reset(QDeclarativeCompiledData *); diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h index 6c14feb..6b71381 100644 --- a/src/declarative/qml/qdeclarativecontext_p.h +++ b/src/declarative/qml/qdeclarativecontext_p.h @@ -77,7 +77,6 @@ class QDeclarativeEngine; class QDeclarativeExpression; class QDeclarativeExpressionPrivate; class QDeclarativeAbstractExpression; -class QDeclarativeBinding_Id; class QDeclarativeCompiledBindings; class QDeclarativeContextData; diff --git a/src/declarative/qml/qdeclarativecustomparser.cpp b/src/declarative/qml/qdeclarativecustomparser.cpp index 97a6a00..58ffc56 100644 --- a/src/declarative/qml/qdeclarativecustomparser.cpp +++ b/src/declarative/qml/qdeclarativecustomparser.cpp @@ -304,5 +304,14 @@ const QMetaObject *QDeclarativeCustomParser::resolveType(const QByteArray& name) return compiler->resolveType(name); } +/*! + Rewrites \a expression and returns an identifier that can be + used to construct the binding later. \a name + is used as the name of the rewritten function. +*/ +QDeclarativeBinding::Identifier QDeclarativeCustomParser::rewriteBinding(const QString& expression, const QByteArray& name) +{ + return compiler->rewriteBinding(expression, name); +} QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativecustomparser_p.h b/src/declarative/qml/qdeclarativecustomparser_p.h index c3f9dd2..9b419c2 100644 --- a/src/declarative/qml/qdeclarativecustomparser_p.h +++ b/src/declarative/qml/qdeclarativecustomparser_p.h @@ -56,6 +56,7 @@ #include "private/qdeclarativemetatype_p.h" #include "qdeclarativeerror.h" #include "private/qdeclarativeparser_p.h" +#include "private/qdeclarativebinding_p.h" #include #include @@ -140,6 +141,8 @@ protected: const QMetaObject *resolveType(const QByteArray&) const; + QDeclarativeBinding::Identifier rewriteBinding(const QString&, const QByteArray&); + private: QList exceptions; QDeclarativeCompiler *compiler; diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp index 8d01b80..400803e 100644 --- a/src/declarative/util/qdeclarativepropertychanges.cpp +++ b/src/declarative/util/qdeclarativepropertychanges.cpp @@ -42,6 +42,9 @@ #include "private/qdeclarativepropertychanges_p.h" #include "private/qdeclarativeopenmetaobject_p.h" +#include "private/qdeclarativerewrite_p.h" +#include "private/qdeclarativeengine_p.h" +#include "private/qdeclarativecompiler_p.h" #include #include @@ -219,6 +222,7 @@ public: QList > properties; QList > expressions; + QList ids; QList signalReplacements; QDeclarativeProperty property(const QByteArray &); @@ -267,6 +271,7 @@ QDeclarativePropertyChangesParser::compile(const QList(data.at(ii).second); QVariant var; bool isScript = v.isScript(); + QDeclarativeBinding::Identifier id; switch(v.type()) { case QDeclarativeParser::Variant::Boolean: var = QVariant(v.asBoolean()); @@ -280,10 +285,17 @@ QDeclarativePropertyChangesParser::compile(const QList> name; ds >> isScript; ds >> data; + if (isScript) + ds >> id; QDeclarativeProperty prop = property(name); //### better way to check for signal property? if (prop.type() & QDeclarativeProperty::SignalProperty) { @@ -323,6 +338,7 @@ void QDeclarativePropertyChangesPrivate::decode() if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber); expressions << qMakePair(name, expression); + ids << id; } else { properties << qMakePair(name, data); } @@ -452,10 +468,14 @@ QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions() a.toValue = d->expressions.at(ii).second->evaluate(); } else { QDeclarativeExpression *e = d->expressions.at(ii).second; - QDeclarativeBinding *newBinding = - new QDeclarativeBinding(e->expression(), object(), qmlContext(this)); + + QDeclarativeBinding::Identifier id = d->ids.at(ii); + QDeclarativeBinding *newBinding = QDeclarativeBinding::createBinding(id, object(), qmlContext(this), e->sourceFile(), e->lineNumber()); + if (!newBinding) { + newBinding = new QDeclarativeBinding(e->expression(), object(), qmlContext(this)); + newBinding->setSourceLocation(e->sourceFile(), e->lineNumber()); + } newBinding->setTarget(prop); - newBinding->setSourceLocation(e->sourceFile(), e->lineNumber()); a.toBinding = newBinding; a.deletableToBinding = true; } -- cgit v0.12 From 24b8dcee5bd51784c341acc708ce3985d85d430a Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Thu, 16 Dec 2010 14:54:28 +1000 Subject: ParentChange optimizations. The QDeclarativeScriptStrings used for the properties are unlikely to change, so we immediately attempt to convert to a real value, rather than converting every time actions() is called. Task-number: QTBUG-15331 Reviewed-by: Martin Jones --- .../util/qdeclarativestateoperations.cpp | 77 ++++++++++++---------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/src/declarative/util/qdeclarativestateoperations.cpp b/src/declarative/util/qdeclarativestateoperations.cpp index 82360b2..b606ff3 100644 --- a/src/declarative/util/qdeclarativestateoperations.cpp +++ b/src/declarative/util/qdeclarativestateoperations.cpp @@ -83,6 +83,13 @@ public: QDeclarativeNullableValue scaleString; QDeclarativeNullableValue rotationString; + QDeclarativeNullableValue x; + QDeclarativeNullableValue y; + QDeclarativeNullableValue width; + QDeclarativeNullableValue height; + QDeclarativeNullableValue scale; + QDeclarativeNullableValue rotation; + void doChange(QDeclarativeItem *targetParent, QDeclarativeItem *stackBefore = 0); }; @@ -213,10 +220,21 @@ QDeclarativeScriptString QDeclarativeParentChange::x() const return d->xString.value; } +void tryReal(QDeclarativeNullableValue &value, const QString &string) +{ + bool ok = false; + qreal realValue = string.toFloat(&ok); + if (ok) + value = realValue; + else + value.invalidate(); +} + void QDeclarativeParentChange::setX(QDeclarativeScriptString x) { Q_D(QDeclarativeParentChange); d->xString = x; + tryReal(d->x, x.script()); } bool QDeclarativeParentChange::xIsSet() const @@ -235,6 +253,7 @@ void QDeclarativeParentChange::setY(QDeclarativeScriptString y) { Q_D(QDeclarativeParentChange); d->yString = y; + tryReal(d->y, y.script()); } bool QDeclarativeParentChange::yIsSet() const @@ -253,6 +272,7 @@ void QDeclarativeParentChange::setWidth(QDeclarativeScriptString width) { Q_D(QDeclarativeParentChange); d->widthString = width; + tryReal(d->width, width.script()); } bool QDeclarativeParentChange::widthIsSet() const @@ -271,6 +291,7 @@ void QDeclarativeParentChange::setHeight(QDeclarativeScriptString height) { Q_D(QDeclarativeParentChange); d->heightString = height; + tryReal(d->height, height.script()); } bool QDeclarativeParentChange::heightIsSet() const @@ -289,6 +310,7 @@ void QDeclarativeParentChange::setScale(QDeclarativeScriptString scale) { Q_D(QDeclarativeParentChange); d->scaleString = scale; + tryReal(d->scale, scale.script()); } bool QDeclarativeParentChange::scaleIsSet() const @@ -307,6 +329,7 @@ void QDeclarativeParentChange::setRotation(QDeclarativeScriptString rotation) { Q_D(QDeclarativeParentChange); d->rotationString = rotation; + tryReal(d->rotation, rotation.script()); } bool QDeclarativeParentChange::rotationIsSet() const @@ -370,14 +393,11 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() QDeclarativeContext *ctxt = qmlContext(this); if (d->xString.isValid()) { - bool ok = false; - QString script = d->xString.value.script(); - qreal x = script.toFloat(&ok); - if (ok) { - QDeclarativeAction xa(d->target, QLatin1String("x"), ctxt, x); + if (d->x.isValid()) { + QDeclarativeAction xa(d->target, QLatin1String("x"), ctxt, d->x.value); actions << xa; } else { - QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, ctxt); + QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->xString.value.script(), d->target, ctxt); newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("x"), ctxt)); QDeclarativeAction xa; xa.property = newBinding->property(); @@ -389,14 +409,11 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() } if (d->yString.isValid()) { - bool ok = false; - QString script = d->yString.value.script(); - qreal y = script.toFloat(&ok); - if (ok) { - QDeclarativeAction ya(d->target, QLatin1String("y"), ctxt, y); + if (d->y.isValid()) { + QDeclarativeAction ya(d->target, QLatin1String("y"), ctxt, d->y.value); actions << ya; } else { - QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, ctxt); + QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->yString.value.script(), d->target, ctxt); newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("y"), ctxt)); QDeclarativeAction ya; ya.property = newBinding->property(); @@ -408,14 +425,11 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() } if (d->scaleString.isValid()) { - bool ok = false; - QString script = d->scaleString.value.script(); - qreal scale = script.toFloat(&ok); - if (ok) { - QDeclarativeAction sa(d->target, QLatin1String("scale"), ctxt, scale); + if (d->scale.isValid()) { + QDeclarativeAction sa(d->target, QLatin1String("scale"), ctxt, d->scale.value); actions << sa; } else { - QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, ctxt); + QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->scaleString.value.script(), d->target, ctxt); newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("scale"), ctxt)); QDeclarativeAction sa; sa.property = newBinding->property(); @@ -427,14 +441,11 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() } if (d->rotationString.isValid()) { - bool ok = false; - QString script = d->rotationString.value.script(); - qreal rotation = script.toFloat(&ok); - if (ok) { - QDeclarativeAction ra(d->target, QLatin1String("rotation"), ctxt, rotation); + if (d->rotation.isValid()) { + QDeclarativeAction ra(d->target, QLatin1String("rotation"), ctxt, d->rotation.value); actions << ra; } else { - QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, ctxt); + QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->rotationString.value.script(), d->target, ctxt); newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("rotation"), ctxt)); QDeclarativeAction ra; ra.property = newBinding->property(); @@ -446,14 +457,11 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() } if (d->widthString.isValid()) { - bool ok = false; - QString script = d->widthString.value.script(); - qreal width = script.toFloat(&ok); - if (ok) { - QDeclarativeAction wa(d->target, QLatin1String("width"), ctxt, width); + if (d->width.isValid()) { + QDeclarativeAction wa(d->target, QLatin1String("width"), ctxt, d->width.value); actions << wa; } else { - QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, ctxt); + QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->widthString.value.script(), d->target, ctxt); newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("width"), ctxt)); QDeclarativeAction wa; wa.property = newBinding->property(); @@ -465,14 +473,11 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions() } if (d->heightString.isValid()) { - bool ok = false; - QString script = d->heightString.value.script(); - qreal height = script.toFloat(&ok); - if (ok) { - QDeclarativeAction ha(d->target, QLatin1String("height"), ctxt, height); + if (d->height.isValid()) { + QDeclarativeAction ha(d->target, QLatin1String("height"), ctxt, d->height.value); actions << ha; } else { - QDeclarativeBinding *newBinding = new QDeclarativeBinding(script, d->target, ctxt); + QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->heightString.value.script(), d->target, ctxt); newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("height"), ctxt)); QDeclarativeAction ha; ha.property = newBinding->property(); -- cgit v0.12 From 9536b35d63716e88482baeed34d11509ed724606 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 17 Dec 2010 16:32:24 +1000 Subject: Fix PropertyChange's binding rewriting for 'dot' properties. For cases like PropertyChanges { font.pixelSize: myPixelSize } it was attempting to rewrite the function name as font.pixelSize, which is not syntactically correct. We now rewrite the function name as pixelSize. --- src/declarative/qml/qdeclarativecompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 4f4ad3f..b2b0990 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -2267,7 +2267,7 @@ const QMetaObject *QDeclarativeCompiler::resolveType(const QByteArray& name) con int QDeclarativeCompiler::rewriteBinding(const QString& expression, const QByteArray& name) { QDeclarativeRewrite::RewriteBinding rewriteBinding; - rewriteBinding.setName('$' + name); + rewriteBinding.setName('$' + name.mid(name.lastIndexOf('.') + 1)); bool isSharable = false; QString rewrite = rewriteBinding(expression, 0, &isSharable); -- cgit v0.12 From 84456ce081fa3c2e2f10b5162c70566f98124b0f Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 18 Nov 2010 10:32:36 +0100 Subject: QDeclarativeDebug: Rename member variable 'client' points to the QDeclarativeDebugConnection object, so better name it 'connection' then. Reviewed-by: Christiaan Janssen --- .../debugger/qdeclarativedebugclient.cpp | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/declarative/debugger/qdeclarativedebugclient.cpp b/src/declarative/debugger/qdeclarativedebugclient.cpp index f5c5751..204ca4f 100644 --- a/src/declarative/debugger/qdeclarativedebugclient.cpp +++ b/src/declarative/debugger/qdeclarativedebugclient.cpp @@ -61,7 +61,7 @@ public: QDeclarativeDebugClientPrivate(); QString name; - QDeclarativeDebugConnection *client; + QDeclarativeDebugConnection *connection; }; class QDeclarativeDebugConnectionPrivate : public QObject @@ -202,7 +202,7 @@ QDeclarativeDebugConnection::~QDeclarativeDebugConnection() { QHash::iterator iter = d->plugins.begin(); for (; iter != d->plugins.end(); ++iter) { - iter.value()->d_func()->client = 0; + iter.value()->d_func()->connection = 0; iter.value()->statusChanged(QDeclarativeDebugClient::NotConnected); } } @@ -213,7 +213,7 @@ bool QDeclarativeDebugConnection::isConnected() const } QDeclarativeDebugClientPrivate::QDeclarativeDebugClientPrivate() -: client(0) +: connection(0) { } @@ -223,26 +223,26 @@ QDeclarativeDebugClient::QDeclarativeDebugClient(const QString &name, { Q_D(QDeclarativeDebugClient); d->name = name; - d->client = parent; + d->connection = parent; - if (!d->client) + if (!d->connection) return; - if (d->client->d->plugins.contains(name)) { + if (d->connection->d->plugins.contains(name)) { qWarning() << "QDeclarativeDebugClient: Conflicting plugin name" << name; - d->client = 0; + d->connection = 0; } else { - d->client->d->plugins.insert(name, this); - d->client->d->advertisePlugins(); + d->connection->d->plugins.insert(name, this); + d->connection->d->advertisePlugins(); } } QDeclarativeDebugClient::~QDeclarativeDebugClient() { Q_D(const QDeclarativeDebugClient); - if (d->client && d->client->d) { - d->client->d->plugins.remove(d->name); - d->client->d->advertisePlugins(); + if (d->connection && d->connection->d) { + d->connection->d->plugins.remove(d->name); + d->connection->d->advertisePlugins(); } } @@ -255,12 +255,12 @@ QString QDeclarativeDebugClient::name() const QDeclarativeDebugClient::Status QDeclarativeDebugClient::status() const { Q_D(const QDeclarativeDebugClient); - if (!d->client - || !d->client->isConnected() - || !d->client->d->gotHello) + if (!d->connection + || !d->connection->isConnected() + || !d->connection->d->gotHello) return NotConnected; - if (d->client->d->serverPlugins.contains(d->name)) + if (d->connection->d->serverPlugins.contains(d->name)) return Enabled; return Unavailable; @@ -275,8 +275,8 @@ void QDeclarativeDebugClient::sendMessage(const QByteArray &message) QPacket pack; pack << d->name << message; - d->client->d->protocol->send(pack); - d->client->d->q->flush(); + d->connection->d->protocol->send(pack); + d->connection->d->q->flush(); } void QDeclarativeDebugClient::statusChanged(Status) -- cgit v0.12 From 5d251ef253065d68967ae3263b3cf7f1d93d7a00 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 18 Nov 2010 14:54:24 +0100 Subject: QDeclarativeDebug: Decouple QDDServer, QDDService classes Move QDeclarativeDebugServer class into it's own files and make the classes less interdependent. --- src/declarative/debugger/debugger.pri | 7 +- .../debugger/qdeclarativedebugserver.cpp | 366 +++++++++++++++++++++ .../debugger/qdeclarativedebugserver_p.h | 89 +++++ .../debugger/qdeclarativedebugservice.cpp | 319 +----------------- .../debugger/qdeclarativedebugservice_p_p.h | 71 ++++ 5 files changed, 541 insertions(+), 311 deletions(-) create mode 100644 src/declarative/debugger/qdeclarativedebugserver.cpp create mode 100644 src/declarative/debugger/qdeclarativedebugserver_p.h create mode 100644 src/declarative/debugger/qdeclarativedebugservice_p_p.h diff --git a/src/declarative/debugger/debugger.pri b/src/declarative/debugger/debugger.pri index 25f7687..144d896 100644 --- a/src/declarative/debugger/debugger.pri +++ b/src/declarative/debugger/debugger.pri @@ -7,13 +7,16 @@ SOURCES += \ $$PWD/qdeclarativedebugclient.cpp \ $$PWD/qdeclarativedebug.cpp \ $$PWD/qdeclarativedebugtrace.cpp \ - $$PWD/qdeclarativedebughelper.cpp + $$PWD/qdeclarativedebughelper.cpp \ + $$PWD/qdeclarativedebugserver.cpp HEADERS += \ $$PWD/qdeclarativedebuggerstatus_p.h \ $$PWD/qpacketprotocol_p.h \ $$PWD/qdeclarativedebugservice_p.h \ + $$PWD/qdeclarativedebugservice_p_p.h \ $$PWD/qdeclarativedebugclient_p.h \ $$PWD/qdeclarativedebug_p.h \ $$PWD/qdeclarativedebugtrace_p.h \ - $$PWD/qdeclarativedebughelper_p.h + $$PWD/qdeclarativedebughelper_p.h \ + $$PWD/qdeclarativedebugserver_p.h diff --git a/src/declarative/debugger/qdeclarativedebugserver.cpp b/src/declarative/debugger/qdeclarativedebugserver.cpp new file mode 100644 index 0000000..4bb4e2c --- /dev/null +++ b/src/declarative/debugger/qdeclarativedebugserver.cpp @@ -0,0 +1,366 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qdeclarativedebugserver_p.h" +#include "private/qdeclarativedebugservice_p.h" +#include "private/qdeclarativedebugservice_p_p.h" +#include "private/qdeclarativeengine_p.h" + +#include "private/qpacketprotocol_p.h" + +#include + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +/* + QDeclarativeDebug Protocol (Version 1): + + handshake: + 1. Client sends + "QDeclarativeDebugServer" 0 version pluginNames + version: an int representing the highest protocol version the client knows + pluginNames: plugins available on client side + 2. Server sends + "QDeclarativeDebugClient" 0 version pluginNames + version: an int representing the highest protocol version the client & server know + pluginNames: plugins available on server side. plugins both in the client and server message are enabled. + client plugin advertisement + 1. Client sends + "QDeclarativeDebugServer" 1 pluginNames + server plugin advertisement + 1. Server sends + "QDeclarativeDebugClient" 1 pluginNames + plugin communication: + Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin. + */ + +const int protocolVersion = 1; + + +class QDeclarativeDebugServerPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QDeclarativeDebugServer) +public: + QDeclarativeDebugServerPrivate(); + + void advertisePlugins(); + + int port; + QTcpSocket *connection; + QPacketProtocol *protocol; + QHash plugins; + QStringList clientPlugins; + QTcpServer *tcpServer; + bool gotHello; +}; + +QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate() +: connection(0), protocol(0), gotHello(false) +{ +} + +void QDeclarativeDebugServerPrivate::advertisePlugins() +{ + if (!connection + || connection->state() != QTcpSocket::ConnectedState + || !gotHello) + return; + + QPacket pack; + pack << QString(QLatin1String("QDeclarativeDebugClient")) << 1 << plugins.keys(); + protocol->send(pack); + connection->flush(); +} + +void QDeclarativeDebugServer::listen() +{ + Q_D(QDeclarativeDebugServer); + + d->tcpServer = new QTcpServer(this); + QObject::connect(d->tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); + if (d->tcpServer->listen(QHostAddress::Any, d->port)) + qWarning("QDeclarativeDebugServer: Waiting for connection on port %d...", d->port); + else + qWarning("QDeclarativeDebugServer: Unable to listen on port %d", d->port); +} + +void QDeclarativeDebugServer::waitForConnection() +{ + Q_D(QDeclarativeDebugServer); + d->tcpServer->waitForNewConnection(-1); +} + +void QDeclarativeDebugServer::newConnection() +{ + Q_D(QDeclarativeDebugServer); + + if (d->connection) { + qWarning("QDeclarativeDebugServer error: another client is already connected"); + QTcpSocket *faultyConnection = d->tcpServer->nextPendingConnection(); + delete faultyConnection; + return; + } + + d->connection = d->tcpServer->nextPendingConnection(); + d->connection->setParent(this); + d->protocol = new QPacketProtocol(d->connection, this); + QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); +} + +bool QDeclarativeDebugServer::hasDebuggingClient() const +{ + Q_D(const QDeclarativeDebugServer); + return d->connection + && (d->connection->state() == QTcpSocket::ConnectedState) + && d->gotHello; +} + +QDeclarativeDebugServer *QDeclarativeDebugServer::instance() +{ + static bool commandLineTested = false; + static QDeclarativeDebugServer *server = 0; + + if (!commandLineTested) { + commandLineTested = true; + +#ifndef QDECLARATIVE_NO_DEBUG_PROTOCOL + QApplicationPrivate *appD = static_cast(QObjectPrivate::get(qApp)); + // ### remove port definition when protocol is changed + int port = 0; + bool block = false; + bool ok = false; + + // format: qmljsdebugger=port:3768[,block] + if (!appD->qmljsDebugArgumentsString().isEmpty()) { + if (!QDeclarativeEnginePrivate::qml_debugging_enabled) { + const QString message = + QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". " + "Debugging has not been enabled.").arg( + appD->qmljsDebugArgumentsString()); + qWarning("%s", qPrintable(message)); + return 0; + } + + if (appD->qmljsDebugArgumentsString().indexOf(QLatin1String("port:")) == 0) { + int separatorIndex = appD->qmljsDebugArgumentsString().indexOf(QLatin1Char(',')); + port = appD->qmljsDebugArgumentsString().mid(5, separatorIndex - 5).toInt(&ok); + } + block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block")); + + if (ok) { + server = new QDeclarativeDebugServer(port); + server->listen(); + if (block) { + server->waitForConnection(); + } + } else { + qWarning(QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". " + "Format is -qmljsdebugger=port:[,block]").arg( + appD->qmljsDebugArgumentsString()).toAscii().constData()); + } + } +#endif + } + + return server; +} + +QDeclarativeDebugServer::QDeclarativeDebugServer(int port) +: QObject(*(new QDeclarativeDebugServerPrivate)) +{ + Q_D(QDeclarativeDebugServer); + d->port = port; +} + +void QDeclarativeDebugServer::readyRead() +{ + Q_D(QDeclarativeDebugServer); + + if (!d->gotHello) { + QPacket hello = d->protocol->read(); + + QString name; + int op; + hello >> name >> op; + + if (name != QLatin1String("QDeclarativeDebugServer") + || op != 0) { + qWarning("QDeclarativeDebugServer: Invalid hello message"); + QObject::disconnect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); + d->protocol->deleteLater(); + d->protocol = 0; + d->connection->deleteLater(); + d->connection = 0; + return; + } + + int version; + hello >> version >> d->clientPlugins; + + QHash::Iterator iter = d->plugins.begin(); + for (; iter != d->plugins.end(); ++iter) { + QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable; + if (d->clientPlugins.contains(iter.key())) + newStatus = QDeclarativeDebugService::Enabled; + iter.value()->d_func()->status = newStatus; + iter.value()->statusChanged(newStatus); + } + + QPacket helloAnswer; + helloAnswer << QString(QLatin1String("QDeclarativeDebugClient")) << 0 << protocolVersion << d->plugins.keys(); + d->protocol->send(helloAnswer); + d->connection->flush(); + + d->gotHello = true; + qWarning("QDeclarativeDebugServer: Connection established"); + } + + QString debugServer(QLatin1String("QDeclarativeDebugServer")); + + while (d->protocol->packetsAvailable()) { + QPacket pack = d->protocol->read(); + + QString name; + pack >> name; + + if (name == debugServer) { + int op = -1; + pack >> op; + + if (op == 1) { + // Service Discovery + QStringList oldClientPlugins = d->clientPlugins; + pack >> d->clientPlugins; + + QHash::Iterator iter = d->plugins.begin(); + for (; iter != d->plugins.end(); ++iter) { + const QString pluginName = iter.key(); + QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable; + if (d->clientPlugins.contains(pluginName)) + newStatus = QDeclarativeDebugService::Enabled; + + if (oldClientPlugins.contains(pluginName) + != d->clientPlugins.contains(pluginName)) { + iter.value()->d_func()->status = newStatus; + iter.value()->statusChanged(newStatus); + } + } + } else { + qWarning("QDeclarativeDebugServer: Invalid control message %d", op); + } + } else { + QByteArray message; + pack >> message; + + QHash::Iterator iter = + d->plugins.find(name); + if (iter == d->plugins.end()) { + qWarning() << "QDeclarativeDebugServer: Message received for missing plugin" << name; + } else { + (*iter)->messageReceived(message); + } + } + } +} + + +QList QDeclarativeDebugServer::services() const +{ + const Q_D(QDeclarativeDebugServer); + return d->plugins.values(); +} + +QStringList QDeclarativeDebugServer::serviceNames() const +{ + const Q_D(QDeclarativeDebugServer); + return d->plugins.keys(); +} + +bool QDeclarativeDebugServer::addService(QDeclarativeDebugService *service) +{ + Q_D(QDeclarativeDebugServer); + if (!service || d->plugins.contains(service->name())) + return false; + + d->plugins.insert(service->name(), service); + d->advertisePlugins(); + + QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable; + if (d->clientPlugins.contains(service->name())) + newStatus = QDeclarativeDebugService::Enabled; + service->d_func()->status = newStatus; + service->statusChanged(newStatus); + return true; +} + +bool QDeclarativeDebugServer::removeService(QDeclarativeDebugService *service) +{ + Q_D(QDeclarativeDebugServer); + if (!service || !d->plugins.contains(service->name())) + return false; + + d->plugins.remove(service->name()); + d->advertisePlugins(); + + QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::NotConnected; + service->d_func()->server = 0; + service->d_func()->status = newStatus; + service->statusChanged(newStatus); + return true; +} + +void QDeclarativeDebugServer::sendMessage(QDeclarativeDebugService *service, + const QByteArray &message) +{ + Q_D(QDeclarativeDebugServer); + QPacket pack; + pack << service->name() << message; + d->protocol->send(pack); + d->connection->flush(); +} + +QT_END_NAMESPACE diff --git a/src/declarative/debugger/qdeclarativedebugserver_p.h b/src/declarative/debugger/qdeclarativedebugserver_p.h new file mode 100644 index 0000000..6840d63 --- /dev/null +++ b/src/declarative/debugger/qdeclarativedebugserver_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEDEBUGSERVER_H +#define QDECLARATIVEDEBUGSERVER_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeDebugService; + +class QDeclarativeDebugServerPrivate; +class QDeclarativeDebugServer : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QDeclarativeDebugServer) + Q_DISABLE_COPY(QDeclarativeDebugServer) +public: + static QDeclarativeDebugServer *instance(); + void listen(); + void waitForConnection(); + bool hasDebuggingClient() const; + + QList services() const; + QStringList serviceNames() const; + + bool addService(QDeclarativeDebugService *service); + bool removeService(QDeclarativeDebugService *service); + + void sendMessage(QDeclarativeDebugService *service, const QByteArray &message); + +private Q_SLOTS: + void readyRead(); + void newConnection(); + +private: + friend class QDeclarativeDebugService; + friend class QDeclarativeDebugServicePrivate; + QDeclarativeDebugServer(int); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEDEBUGSERVICE_H diff --git a/src/declarative/debugger/qdeclarativedebugservice.cpp b/src/declarative/debugger/qdeclarativedebugservice.cpp index 849df73..9d321da 100644 --- a/src/declarative/debugger/qdeclarativedebugservice.cpp +++ b/src/declarative/debugger/qdeclarativedebugservice.cpp @@ -40,301 +40,14 @@ ****************************************************************************/ #include "private/qdeclarativedebugservice_p.h" +#include "private/qdeclarativedebugservice_p_p.h" +#include "private/qdeclarativedebugserver_p.h" -#include "private/qpacketprotocol_p.h" -#include "private/qdeclarativeengine_p.h" - -#include -#include -#include -#include - -#include -#include -#include +#include +#include QT_BEGIN_NAMESPACE -/* - QDeclarativeDebug Protocol (Version 1): - - handshake: - 1. Client sends - "QDeclarativeDebugServer" 0 version pluginNames - version: an int representing the highest protocol version the client knows - pluginNames: plugins available on client side - 2. Server sends - "QDeclarativeDebugClient" 0 version pluginNames - version: an int representing the highest protocol version the client & server know - pluginNames: plugins available on server side. plugins both in the client and server message are enabled. - client plugin advertisement - 1. Client sends - "QDeclarativeDebugServer" 1 pluginNames - server plugin advertisement - 1. Server sends - "QDeclarativeDebugClient" 1 pluginNames - plugin communication: - Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin. - */ - -const int protocolVersion = 1; - -class QDeclarativeDebugServerPrivate; -class QDeclarativeDebugServer : public QObject -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QDeclarativeDebugServer) - Q_DISABLE_COPY(QDeclarativeDebugServer) -public: - static QDeclarativeDebugServer *instance(); - void listen(); - void waitForConnection(); - bool hasDebuggingClient() const; - -private Q_SLOTS: - void readyRead(); - void newConnection(); - -private: - friend class QDeclarativeDebugService; - friend class QDeclarativeDebugServicePrivate; - QDeclarativeDebugServer(int); -}; - -class QDeclarativeDebugServerPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QDeclarativeDebugServer) -public: - QDeclarativeDebugServerPrivate(); - - void advertisePlugins(); - - int port; - QTcpSocket *connection; - QPacketProtocol *protocol; - QHash plugins; - QStringList clientPlugins; - QTcpServer *tcpServer; - bool gotHello; -}; - -class QDeclarativeDebugServicePrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QDeclarativeDebugService) -public: - QDeclarativeDebugServicePrivate(); - - QString name; - QDeclarativeDebugServer *server; -}; - -QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate() -: connection(0), protocol(0), gotHello(false) -{ -} - -void QDeclarativeDebugServerPrivate::advertisePlugins() -{ - if (!connection - || connection->state() != QTcpSocket::ConnectedState - || !gotHello) - return; - - QPacket pack; - pack << QString(QLatin1String("QDeclarativeDebugClient")) << 1 << plugins.keys(); - protocol->send(pack); - connection->flush(); -} - -void QDeclarativeDebugServer::listen() -{ - Q_D(QDeclarativeDebugServer); - - d->tcpServer = new QTcpServer(this); - QObject::connect(d->tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); - if (d->tcpServer->listen(QHostAddress::Any, d->port)) - qWarning("QDeclarativeDebugServer: Waiting for connection on port %d...", d->port); - else - qWarning("QDeclarativeDebugServer: Unable to listen on port %d", d->port); -} - -void QDeclarativeDebugServer::waitForConnection() -{ - Q_D(QDeclarativeDebugServer); - d->tcpServer->waitForNewConnection(-1); -} - -void QDeclarativeDebugServer::newConnection() -{ - Q_D(QDeclarativeDebugServer); - - if (d->connection) { - qWarning("QDeclarativeDebugServer error: another client is already connected"); - QTcpSocket *faultyConnection = d->tcpServer->nextPendingConnection(); - delete faultyConnection; - return; - } - - d->connection = d->tcpServer->nextPendingConnection(); - d->connection->setParent(this); - d->protocol = new QPacketProtocol(d->connection, this); - QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); -} - -bool QDeclarativeDebugServer::hasDebuggingClient() const -{ - Q_D(const QDeclarativeDebugServer); - return d->connection - && (d->connection->state() == QTcpSocket::ConnectedState) - && d->gotHello; -} - -QDeclarativeDebugServer *QDeclarativeDebugServer::instance() -{ - static bool commandLineTested = false; - static QDeclarativeDebugServer *server = 0; - - if (!commandLineTested) { - commandLineTested = true; - -#ifndef QDECLARATIVE_NO_DEBUG_PROTOCOL - QApplicationPrivate *appD = static_cast(QObjectPrivate::get(qApp)); - // ### remove port definition when protocol is changed - int port = 0; - bool block = false; - bool ok = false; - - // format: qmljsdebugger=port:3768[,block] - if (!appD->qmljsDebugArgumentsString().isEmpty()) { - if (!QDeclarativeEnginePrivate::qml_debugging_enabled) { - qWarning() << QString::fromLatin1("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". " - "Debugging has not been enabled.").arg( - appD->qmljsDebugArgumentsString()).toAscii().constData(); - return 0; - } - - if (appD->qmljsDebugArgumentsString().indexOf(QLatin1String("port:")) == 0) { - int separatorIndex = appD->qmljsDebugArgumentsString().indexOf(QLatin1Char(',')); - port = appD->qmljsDebugArgumentsString().mid(5, separatorIndex - 5).toInt(&ok); - } - block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block")); - - if (ok) { - server = new QDeclarativeDebugServer(port); - server->listen(); - if (block) { - server->waitForConnection(); - } - } else { - const QString message = - QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". " - "Format is -qmljsdebugger=port:[,block]"). - arg(appD->qmljsDebugArgumentsString()); - qWarning("%s", qPrintable(message)); - } - } -#endif - } - - return server; -} - -QDeclarativeDebugServer::QDeclarativeDebugServer(int port) -: QObject(*(new QDeclarativeDebugServerPrivate)) -{ - Q_D(QDeclarativeDebugServer); - d->port = port; -} - -void QDeclarativeDebugServer::readyRead() -{ - Q_D(QDeclarativeDebugServer); - - if (!d->gotHello) { - QPacket hello = d->protocol->read(); - - QString name; - int op; - hello >> name >> op; - - if (name != QLatin1String("QDeclarativeDebugServer") - || op != 0) { - qWarning("QDeclarativeDebugServer: Invalid hello message"); - QObject::disconnect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); - d->protocol->deleteLater(); - d->protocol = 0; - d->connection->deleteLater(); - d->connection = 0; - return; - } - - int version; - hello >> version >> d->clientPlugins; - - QHash::Iterator iter = d->plugins.begin(); - for (; iter != d->plugins.end(); ++iter) { - QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable; - if (d->clientPlugins.contains(iter.key())) - newStatus = QDeclarativeDebugService::Enabled; - iter.value()->statusChanged(newStatus); - } - - QPacket helloAnswer; - helloAnswer << QString(QLatin1String("QDeclarativeDebugClient")) << 0 << protocolVersion << d->plugins.keys(); - d->protocol->send(helloAnswer); - d->connection->flush(); - - d->gotHello = true; - qWarning("QDeclarativeDebugServer: Connection established"); - } - - QString debugServer(QLatin1String("QDeclarativeDebugServer")); - - while (d->protocol->packetsAvailable()) { - QPacket pack = d->protocol->read(); - - QString name; - pack >> name; - - if (name == debugServer) { - int op = -1; - pack >> op; - - if (op == 1) { - // Service Discovery - QStringList oldClientPlugins = d->clientPlugins; - pack >> d->clientPlugins; - - QHash::Iterator iter = d->plugins.begin(); - for (; iter != d->plugins.end(); ++iter) { - const QString pluginName = iter.key(); - QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable; - if (d->clientPlugins.contains(pluginName)) - newStatus = QDeclarativeDebugService::Enabled; - - if (oldClientPlugins.contains(pluginName) - != d->clientPlugins.contains(pluginName)) { - iter.value()->statusChanged(newStatus); - } - } - } else { - qWarning("QDeclarativeDebugServer: Invalid control message %d", op); - } - } else { - QByteArray message; - pack >> message; - - QHash::Iterator iter = - d->plugins.find(name); - if (iter == d->plugins.end()) { - qWarning() << "QDeclarativeDebugServer: Message received for missing plugin" << name; - } else { - (*iter)->messageReceived(message); - } - } - } -} - QDeclarativeDebugServicePrivate::QDeclarativeDebugServicePrivate() : server(0) { @@ -346,16 +59,16 @@ QDeclarativeDebugService::QDeclarativeDebugService(const QString &name, QObject Q_D(QDeclarativeDebugService); d->name = name; d->server = QDeclarativeDebugServer::instance(); + d->status = QDeclarativeDebugService::NotConnected; if (!d->server) return; - if (d->server->d_func()->plugins.contains(name)) { + if (d->server->serviceNames().contains(name)) { qWarning() << "QDeclarativeDebugService: Conflicting plugin name" << name; d->server = 0; } else { - d->server->d_func()->plugins.insert(name, this); - d->server->d_func()->advertisePlugins(); + d->server->addService(this); } } @@ -363,8 +76,7 @@ QDeclarativeDebugService::~QDeclarativeDebugService() { Q_D(const QDeclarativeDebugService); if (d->server) { - d->server->d_func()->plugins.remove(d->name); - d->server->d_func()->advertisePlugins(); + d->server->removeService(this); } } @@ -377,13 +89,7 @@ QString QDeclarativeDebugService::name() const QDeclarativeDebugService::Status QDeclarativeDebugService::status() const { Q_D(const QDeclarativeDebugService); - if (!d->server - || !d->server->hasDebuggingClient()) - return NotConnected; - if (d->server->d_func()->clientPlugins.contains(d->name)) - return Enabled; - - return Unavailable; + return d->status; } namespace { @@ -500,10 +206,7 @@ void QDeclarativeDebugService::sendMessage(const QByteArray &message) if (status() != Enabled) return; - QPacket pack; - pack << d->name << message; - d->server->d_func()->protocol->send(pack); - d->server->d_func()->connection->flush(); + d->server->sendMessage(this, message); } void QDeclarativeDebugService::statusChanged(Status) @@ -515,5 +218,3 @@ void QDeclarativeDebugService::messageReceived(const QByteArray &) } QT_END_NAMESPACE - -#include diff --git a/src/declarative/debugger/qdeclarativedebugservice_p_p.h b/src/declarative/debugger/qdeclarativedebugservice_p_p.h new file mode 100644 index 0000000..d2c8dda --- /dev/null +++ b/src/declarative/debugger/qdeclarativedebugservice_p_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEDEBUGSERVICE_P_H +#define QDECLARATIVEDEBUGSERVICE_P_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeDebugServer; + +class QDeclarativeDebugServicePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QDeclarativeDebugService) +public: + QDeclarativeDebugServicePrivate(); + + QString name; + QDeclarativeDebugServer *server; + QDeclarativeDebugService::Status status; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEDEBUGSERVICE_P_H -- cgit v0.12 From 5336e1838a95d97d34863b668ff797582c226e79 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 24 Nov 2010 19:50:09 +0100 Subject: QDeclarativeDebug: Move networking code out of QDeclarativeDebugServer Move socket handling code out of QDeclarativeDebugServer into a QDeclarativeDebugServer(Tcp)Connection class. Reviewed-by: Christiaan Janssen --- src/declarative/debugger/debugger.pri | 8 +- .../debugger/qdeclarativedebugserver.cpp | 131 ++++++----------- .../debugger/qdeclarativedebugserver_p.h | 13 +- .../debugger/qdeclarativedebugserverconnection_p.h | 68 +++++++++ .../debugger/qdeclarativedebugserverplugin_p.h | 0 .../qdeclarativedebugservertcpconnection.cpp | 163 +++++++++++++++++++++ .../qdeclarativedebugservertcpconnection_p.h | 86 +++++++++++ src/declarative/debugger/qpacketprotocol.cpp | 8 + src/declarative/debugger/qpacketprotocol_p.h | 1 + 9 files changed, 383 insertions(+), 95 deletions(-) create mode 100644 src/declarative/debugger/qdeclarativedebugserverconnection_p.h create mode 100644 src/declarative/debugger/qdeclarativedebugserverplugin_p.h create mode 100644 src/declarative/debugger/qdeclarativedebugservertcpconnection.cpp create mode 100644 src/declarative/debugger/qdeclarativedebugservertcpconnection_p.h diff --git a/src/declarative/debugger/debugger.pri b/src/declarative/debugger/debugger.pri index 144d896..e7354dc 100644 --- a/src/declarative/debugger/debugger.pri +++ b/src/declarative/debugger/debugger.pri @@ -8,7 +8,8 @@ SOURCES += \ $$PWD/qdeclarativedebug.cpp \ $$PWD/qdeclarativedebugtrace.cpp \ $$PWD/qdeclarativedebughelper.cpp \ - $$PWD/qdeclarativedebugserver.cpp + $$PWD/qdeclarativedebugserver.cpp \ + $$PWD/qdeclarativedebugservertcpconnection.cpp HEADERS += \ $$PWD/qdeclarativedebuggerstatus_p.h \ @@ -19,4 +20,7 @@ HEADERS += \ $$PWD/qdeclarativedebug_p.h \ $$PWD/qdeclarativedebugtrace_p.h \ $$PWD/qdeclarativedebughelper_p.h \ - $$PWD/qdeclarativedebugserver_p.h + $$PWD/qdeclarativedebugserverplugin_p.h \ + $$PWD/qdeclarativedebugserver_p.h \ + $$PWD/qdeclarativedebugservertcpconnection_p.h \ + debugger/qdeclarativedebugserverconnection_p.h diff --git a/src/declarative/debugger/qdeclarativedebugserver.cpp b/src/declarative/debugger/qdeclarativedebugserver.cpp index 4bb4e2c..6085e3e 100644 --- a/src/declarative/debugger/qdeclarativedebugserver.cpp +++ b/src/declarative/debugger/qdeclarativedebugserver.cpp @@ -42,15 +42,11 @@ #include "private/qdeclarativedebugserver_p.h" #include "private/qdeclarativedebugservice_p.h" #include "private/qdeclarativedebugservice_p_p.h" +#include "private/qdeclarativedebugservertcpconnection_p.h" #include "private/qdeclarativeengine_p.h" -#include "private/qpacketprotocol_p.h" - #include -#include -#include - #include #include @@ -89,73 +85,36 @@ public: void advertisePlugins(); - int port; - QTcpSocket *connection; - QPacketProtocol *protocol; + QDeclarativeDebugServerConnection *connection; QHash plugins; QStringList clientPlugins; - QTcpServer *tcpServer; bool gotHello; }; -QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate() -: connection(0), protocol(0), gotHello(false) +QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate() : + connection(0), + gotHello(false) { } void QDeclarativeDebugServerPrivate::advertisePlugins() { - if (!connection - || connection->state() != QTcpSocket::ConnectedState - || !gotHello) + if (!gotHello) return; - QPacket pack; - pack << QString(QLatin1String("QDeclarativeDebugClient")) << 1 << plugins.keys(); - protocol->send(pack); - connection->flush(); -} - -void QDeclarativeDebugServer::listen() -{ - Q_D(QDeclarativeDebugServer); - - d->tcpServer = new QTcpServer(this); - QObject::connect(d->tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); - if (d->tcpServer->listen(QHostAddress::Any, d->port)) - qWarning("QDeclarativeDebugServer: Waiting for connection on port %d...", d->port); - else - qWarning("QDeclarativeDebugServer: Unable to listen on port %d", d->port); -} - -void QDeclarativeDebugServer::waitForConnection() -{ - Q_D(QDeclarativeDebugServer); - d->tcpServer->waitForNewConnection(-1); -} - -void QDeclarativeDebugServer::newConnection() -{ - Q_D(QDeclarativeDebugServer); - - if (d->connection) { - qWarning("QDeclarativeDebugServer error: another client is already connected"); - QTcpSocket *faultyConnection = d->tcpServer->nextPendingConnection(); - delete faultyConnection; - return; + QByteArray message; + { + QDataStream out(&message, QIODevice::WriteOnly); + out << QString(QLatin1String("QDeclarativeDebugClient")) << 1 << plugins.keys(); } - - d->connection = d->tcpServer->nextPendingConnection(); - d->connection->setParent(this); - d->protocol = new QPacketProtocol(d->connection, this); - QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); + connection->send(message); } bool QDeclarativeDebugServer::hasDebuggingClient() const { Q_D(const QDeclarativeDebugServer); return d->connection - && (d->connection->state() == QTcpSocket::ConnectedState) + && d->connection->isConnected() && d->gotHello; } @@ -192,11 +151,17 @@ QDeclarativeDebugServer *QDeclarativeDebugServer::instance() block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block")); if (ok) { - server = new QDeclarativeDebugServer(port); - server->listen(); + server = new QDeclarativeDebugServer(); + + QDeclarativeDebugServerTcpConnection *tcpConnection + = new QDeclarativeDebugServerTcpConnection(port, server); + + tcpConnection->listen(); if (block) { - server->waitForConnection(); + tcpConnection->waitForConnection(); } + + server->d_func()->connection = tcpConnection; } else { qWarning(QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". " "Format is -qmljsdebugger=port:[,block]").arg( @@ -209,37 +174,31 @@ QDeclarativeDebugServer *QDeclarativeDebugServer::instance() return server; } -QDeclarativeDebugServer::QDeclarativeDebugServer(int port) +QDeclarativeDebugServer::QDeclarativeDebugServer() : QObject(*(new QDeclarativeDebugServerPrivate)) { - Q_D(QDeclarativeDebugServer); - d->port = port; } -void QDeclarativeDebugServer::readyRead() +void QDeclarativeDebugServer::receiveMessage(const QByteArray &message) { Q_D(QDeclarativeDebugServer); + QDataStream in(message); if (!d->gotHello) { - QPacket hello = d->protocol->read(); QString name; int op; - hello >> name >> op; + in >> name >> op; if (name != QLatin1String("QDeclarativeDebugServer") || op != 0) { qWarning("QDeclarativeDebugServer: Invalid hello message"); - QObject::disconnect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); - d->protocol->deleteLater(); - d->protocol = 0; - d->connection->deleteLater(); - d->connection = 0; + d->connection->disconnect(); return; } int version; - hello >> version >> d->clientPlugins; + in >> version >> d->clientPlugins; QHash::Iterator iter = d->plugins.begin(); for (; iter != d->plugins.end(); ++iter) { @@ -250,31 +209,30 @@ void QDeclarativeDebugServer::readyRead() iter.value()->statusChanged(newStatus); } - QPacket helloAnswer; - helloAnswer << QString(QLatin1String("QDeclarativeDebugClient")) << 0 << protocolVersion << d->plugins.keys(); - d->protocol->send(helloAnswer); - d->connection->flush(); + QByteArray helloAnswer; + { + QDataStream out(&helloAnswer, QIODevice::WriteOnly); + out << QString(QLatin1String("QDeclarativeDebugClient")) << 0 << protocolVersion << d->plugins.keys(); + } + d->connection->send(helloAnswer); d->gotHello = true; qWarning("QDeclarativeDebugServer: Connection established"); - } + } else { - QString debugServer(QLatin1String("QDeclarativeDebugServer")); - - while (d->protocol->packetsAvailable()) { - QPacket pack = d->protocol->read(); + QString debugServer(QLatin1String("QDeclarativeDebugServer")); QString name; - pack >> name; + in >> name; if (name == debugServer) { int op = -1; - pack >> op; + in >> op; if (op == 1) { // Service Discovery QStringList oldClientPlugins = d->clientPlugins; - pack >> d->clientPlugins; + in >> d->clientPlugins; QHash::Iterator iter = d->plugins.begin(); for (; iter != d->plugins.end(); ++iter) { @@ -294,7 +252,7 @@ void QDeclarativeDebugServer::readyRead() } } else { QByteArray message; - pack >> message; + in >> message; QHash::Iterator iter = d->plugins.find(name); @@ -307,7 +265,6 @@ void QDeclarativeDebugServer::readyRead() } } - QList QDeclarativeDebugServer::services() const { const Q_D(QDeclarativeDebugServer); @@ -357,10 +314,12 @@ void QDeclarativeDebugServer::sendMessage(QDeclarativeDebugService *service, const QByteArray &message) { Q_D(QDeclarativeDebugServer); - QPacket pack; - pack << service->name() << message; - d->protocol->send(pack); - d->connection->flush(); + QByteArray msg; + { + QDataStream out(&msg, QIODevice::WriteOnly); + out << service->name() << message; + } + d->connection->send(msg); } QT_END_NAMESPACE diff --git a/src/declarative/debugger/qdeclarativedebugserver_p.h b/src/declarative/debugger/qdeclarativedebugserver_p.h index 6840d63..93ab10b 100644 --- a/src/declarative/debugger/qdeclarativedebugserver_p.h +++ b/src/declarative/debugger/qdeclarativedebugserver_p.h @@ -43,6 +43,7 @@ #define QDECLARATIVEDEBUGSERVER_H #include +#include QT_BEGIN_HEADER @@ -60,8 +61,9 @@ class QDeclarativeDebugServer : public QObject Q_DISABLE_COPY(QDeclarativeDebugServer) public: static QDeclarativeDebugServer *instance(); - void listen(); - void waitForConnection(); + + void setConnection(QDeclarativeDebugServerConnection *connection); + bool hasDebuggingClient() const; QList services() const; @@ -71,15 +73,12 @@ public: bool removeService(QDeclarativeDebugService *service); void sendMessage(QDeclarativeDebugService *service, const QByteArray &message); - -private Q_SLOTS: - void readyRead(); - void newConnection(); + void receiveMessage(const QByteArray &message); private: friend class QDeclarativeDebugService; friend class QDeclarativeDebugServicePrivate; - QDeclarativeDebugServer(int); + QDeclarativeDebugServer(); }; QT_END_NAMESPACE diff --git a/src/declarative/debugger/qdeclarativedebugserverconnection_p.h b/src/declarative/debugger/qdeclarativedebugserverconnection_p.h new file mode 100644 index 0000000..4175126 --- /dev/null +++ b/src/declarative/debugger/qdeclarativedebugserverconnection_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEDEBUGSERVERCONNECTION_H +#define QDECLARATIVEDEBUGSERVERCONNECTION_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeDebugServerConnection +{ +public: + QDeclarativeDebugServerConnection() {} + virtual ~QDeclarativeDebugServerConnection() {} + + virtual bool isConnected() const = 0; + virtual void send(const QByteArray &message) = 0; + virtual void disconnect() = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEDEBUGSERVERCONNECTION_H diff --git a/src/declarative/debugger/qdeclarativedebugserverplugin_p.h b/src/declarative/debugger/qdeclarativedebugserverplugin_p.h new file mode 100644 index 0000000..e69de29 diff --git a/src/declarative/debugger/qdeclarativedebugservertcpconnection.cpp b/src/declarative/debugger/qdeclarativedebugservertcpconnection.cpp new file mode 100644 index 0000000..223c875 --- /dev/null +++ b/src/declarative/debugger/qdeclarativedebugservertcpconnection.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdeclarativedebugservertcpconnection_p.h" + +#include "qdeclarativedebugserver_p.h" +#include "private/qpacketprotocol_p.h" + +#include +#include + + +QT_BEGIN_NAMESPACE + +class QDeclarativeDebugServerTcpConnectionPrivate { +public: + QDeclarativeDebugServerTcpConnectionPrivate(); + + int port; + QTcpSocket *socket; + QPacketProtocol *protocol; + QTcpServer *tcpServer; + + QDeclarativeDebugServer *debugServer; +}; + +QDeclarativeDebugServerTcpConnectionPrivate::QDeclarativeDebugServerTcpConnectionPrivate() : + port(0), + socket(0), + protocol(0), + tcpServer(0), + debugServer(0) +{ +} + +QDeclarativeDebugServerTcpConnection::QDeclarativeDebugServerTcpConnection(int port, QDeclarativeDebugServer *server) : + QObject(server), + d_ptr(new QDeclarativeDebugServerTcpConnectionPrivate) +{ + Q_D(QDeclarativeDebugServerTcpConnection); + d->port = port; + d->debugServer = server; +} + +QDeclarativeDebugServerTcpConnection::~QDeclarativeDebugServerTcpConnection() +{ + delete d_ptr; +} + +bool QDeclarativeDebugServerTcpConnection::isConnected() const +{ + Q_D(const QDeclarativeDebugServerTcpConnection); + return d->socket && d->socket->state() == QTcpSocket::ConnectedState; +} + +void QDeclarativeDebugServerTcpConnection::send(const QByteArray &message) +{ + Q_D(QDeclarativeDebugServerTcpConnection); + + if (!isConnected()) + return; + + QPacket pack; + pack.writeRawData(message.data(), message.length()); + + d->protocol->send(pack); + d->socket->flush(); +} + +void QDeclarativeDebugServerTcpConnection::disconnect() +{ + Q_D(QDeclarativeDebugServerTcpConnection); + + delete d->protocol; + d->protocol = 0; + delete d->socket; + d->socket = 0; +} + +void QDeclarativeDebugServerTcpConnection::listen() +{ + Q_D(QDeclarativeDebugServerTcpConnection); + + d->tcpServer = new QTcpServer(this); + QObject::connect(d->tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); + if (d->tcpServer->listen(QHostAddress::Any, d->port)) + qWarning("QDeclarativeDebugServer: Waiting for connection on port %d...", d->port); + else + qWarning("QDeclarativeDebugServer: Unable to listen on port %d", d->port); +} + +void QDeclarativeDebugServerTcpConnection::waitForConnection() +{ + Q_D(QDeclarativeDebugServerTcpConnection); + d->tcpServer->waitForNewConnection(-1); +} + +void QDeclarativeDebugServerTcpConnection::readyRead() +{ + Q_D(QDeclarativeDebugServerTcpConnection); + QPacket packet = d->protocol->read(); + + QByteArray content = packet.data(); + d->debugServer->receiveMessage(content); +} + +void QDeclarativeDebugServerTcpConnection::newConnection() +{ + Q_D(QDeclarativeDebugServerTcpConnection); + + if (d->socket) { + qWarning("QDeclarativeDebugServer error: another client is already connected"); + QTcpSocket *faultyConnection = d->tcpServer->nextPendingConnection(); + delete faultyConnection; + return; + } + + d->socket = d->tcpServer->nextPendingConnection(); + d->socket->setParent(this); + d->protocol = new QPacketProtocol(d->socket, this); + QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); +} + + +QT_END_NAMESPACE diff --git a/src/declarative/debugger/qdeclarativedebugservertcpconnection_p.h b/src/declarative/debugger/qdeclarativedebugservertcpconnection_p.h new file mode 100644 index 0000000..f1c749ef --- /dev/null +++ b/src/declarative/debugger/qdeclarativedebugservertcpconnection_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEDEBUGSERVERTCPCONNECTION_H +#define QDECLARATIVEDEBUGSERVERTCPCONNECTION_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +#include + +class QDeclarativeDebugServer; +class QDeclarativeDebugServerTcpConnectionPrivate; +class QDeclarativeDebugServerTcpConnection : public QObject, public QDeclarativeDebugServerConnection +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QDeclarativeDebugServerTcpConnection) + Q_DISABLE_COPY(QDeclarativeDebugServerTcpConnection) + +public: + QDeclarativeDebugServerTcpConnection(int port, QDeclarativeDebugServer *server); + ~QDeclarativeDebugServerTcpConnection(); + + bool isConnected() const; + void send(const QByteArray &message); + void disconnect(); + + void listen(); + void waitForConnection(); + +private Q_SLOTS: + void readyRead(); + void newConnection(); + +private: + QDeclarativeDebugServerTcpConnectionPrivate *d_ptr; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDECLARATIVEDEBUGSERVERTCPCONNECTION_H diff --git a/src/declarative/debugger/qpacketprotocol.cpp b/src/declarative/debugger/qpacketprotocol.cpp index c2f7709..ad1e767 100644 --- a/src/declarative/debugger/qpacketprotocol.cpp +++ b/src/declarative/debugger/qpacketprotocol.cpp @@ -452,6 +452,14 @@ bool QPacket::isEmpty() const } /*! + Returns raw packet data. + */ +QByteArray QPacket::data() const +{ + return b; +} + +/*! Clears data in the packet. This is useful for reusing one writable packet. For example \code diff --git a/src/declarative/debugger/qpacketprotocol_p.h b/src/declarative/debugger/qpacketprotocol_p.h index d153833..99fded5 100644 --- a/src/declarative/debugger/qpacketprotocol_p.h +++ b/src/declarative/debugger/qpacketprotocol_p.h @@ -98,6 +98,7 @@ public: void clear(); bool isEmpty() const; + QByteArray data() const; protected: friend class QPacketProtocol; -- cgit v0.12 From 21016c3b28674029a2a205da38f54e362e3635b9 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 26 Nov 2010 16:22:47 +0100 Subject: QDeclarativeDebug: Move Tcp server to separate plugin Reviewed-by: Christiaan Janssen --- src/declarative/debugger/debugger.pri | 4 +- .../debugger/qdeclarativedebugserver.cpp | 50 +++++- .../debugger/qdeclarativedebugserver_p.h | 2 +- .../debugger/qdeclarativedebugserverconnection_p.h | 9 +- .../qdeclarativedebugservertcpconnection.cpp | 163 ------------------- .../qdeclarativedebugservertcpconnection_p.h | 86 ---------- src/declarative/debugger/qpacketprotocol_p.h | 4 +- src/plugins/plugins.pro | 3 +- src/plugins/qmldebugging/qmldebugging.pro | 4 + .../tcpserver/qtcpserverconnection.cpp | 173 +++++++++++++++++++++ .../qmldebugging/tcpserver/qtcpserverconnection.h | 84 ++++++++++ src/plugins/qmldebugging/tcpserver/tcpserver.pro | 18 +++ 12 files changed, 334 insertions(+), 266 deletions(-) delete mode 100644 src/declarative/debugger/qdeclarativedebugservertcpconnection.cpp delete mode 100644 src/declarative/debugger/qdeclarativedebugservertcpconnection_p.h create mode 100644 src/plugins/qmldebugging/qmldebugging.pro create mode 100644 src/plugins/qmldebugging/tcpserver/qtcpserverconnection.cpp create mode 100644 src/plugins/qmldebugging/tcpserver/qtcpserverconnection.h create mode 100644 src/plugins/qmldebugging/tcpserver/tcpserver.pro diff --git a/src/declarative/debugger/debugger.pri b/src/declarative/debugger/debugger.pri index e7354dc..9152677 100644 --- a/src/declarative/debugger/debugger.pri +++ b/src/declarative/debugger/debugger.pri @@ -8,8 +8,7 @@ SOURCES += \ $$PWD/qdeclarativedebug.cpp \ $$PWD/qdeclarativedebugtrace.cpp \ $$PWD/qdeclarativedebughelper.cpp \ - $$PWD/qdeclarativedebugserver.cpp \ - $$PWD/qdeclarativedebugservertcpconnection.cpp + $$PWD/qdeclarativedebugserver.cpp HEADERS += \ $$PWD/qdeclarativedebuggerstatus_p.h \ @@ -22,5 +21,4 @@ HEADERS += \ $$PWD/qdeclarativedebughelper_p.h \ $$PWD/qdeclarativedebugserverplugin_p.h \ $$PWD/qdeclarativedebugserver_p.h \ - $$PWD/qdeclarativedebugservertcpconnection_p.h \ debugger/qdeclarativedebugserverconnection_p.h diff --git a/src/declarative/debugger/qdeclarativedebugserver.cpp b/src/declarative/debugger/qdeclarativedebugserver.cpp index 6085e3e..a269984 100644 --- a/src/declarative/debugger/qdeclarativedebugserver.cpp +++ b/src/declarative/debugger/qdeclarativedebugserver.cpp @@ -42,9 +42,10 @@ #include "private/qdeclarativedebugserver_p.h" #include "private/qdeclarativedebugservice_p.h" #include "private/qdeclarativedebugservice_p_p.h" -#include "private/qdeclarativedebugservertcpconnection_p.h" #include "private/qdeclarativeengine_p.h" +#include +#include #include #include @@ -89,6 +90,8 @@ public: QHash plugins; QStringList clientPlugins; bool gotHello; + + static QDeclarativeDebugServerConnection *loadConnectionPlugin(); }; QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate() : @@ -110,6 +113,36 @@ void QDeclarativeDebugServerPrivate::advertisePlugins() connection->send(message); } +QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectionPlugin() +{ + QStringList pluginCandidates; + const QStringList paths = QCoreApplication::libraryPaths(); + foreach (const QString &libPath, paths) { + const QDir dir(libPath + QLatin1String("/qmldebugging")); + if (dir.exists()) { + QStringList plugins(dir.entryList(QDir::Files)); + foreach (const QString &pluginPath, plugins) { + pluginCandidates << dir.absoluteFilePath(pluginPath); + } + } + } + + foreach (const QString &pluginPath, pluginCandidates) { + QPluginLoader loader(pluginPath); + if (!loader.load()) { + continue; + } + QDeclarativeDebugServerConnection *connection = 0; + if (QObject *instance = loader.instance()) + connection = qobject_cast(instance); + + if (connection) + return connection; + loader.unload(); + } + return 0; +} + bool QDeclarativeDebugServer::hasDebuggingClient() const { Q_D(const QDeclarativeDebugServer); @@ -153,15 +186,18 @@ QDeclarativeDebugServer *QDeclarativeDebugServer::instance() if (ok) { server = new QDeclarativeDebugServer(); - QDeclarativeDebugServerTcpConnection *tcpConnection - = new QDeclarativeDebugServerTcpConnection(port, server); + QDeclarativeDebugServerConnection *connection + = QDeclarativeDebugServerPrivate::loadConnectionPlugin(); + if (connection) { + server->d_func()->connection = connection; - tcpConnection->listen(); - if (block) { - tcpConnection->waitForConnection(); + connection->setServer(server); + connection->setPort(port, block); + } else { + qWarning() << QString::fromAscii("QDeclarativeDebugServer: Ignoring\"-qmljsdebugger=%1\". " + "Remote debugger plugin has not been found.").arg(appD->qmljsDebugArgumentsString()); } - server->d_func()->connection = tcpConnection; } else { qWarning(QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". " "Format is -qmljsdebugger=port:[,block]").arg( diff --git a/src/declarative/debugger/qdeclarativedebugserver_p.h b/src/declarative/debugger/qdeclarativedebugserver_p.h index 93ab10b..ec3e60f 100644 --- a/src/declarative/debugger/qdeclarativedebugserver_p.h +++ b/src/declarative/debugger/qdeclarativedebugserver_p.h @@ -54,7 +54,7 @@ QT_MODULE(Declarative) class QDeclarativeDebugService; class QDeclarativeDebugServerPrivate; -class QDeclarativeDebugServer : public QObject +class Q_DECLARATIVE_EXPORT QDeclarativeDebugServer : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(QDeclarativeDebugServer) diff --git a/src/declarative/debugger/qdeclarativedebugserverconnection_p.h b/src/declarative/debugger/qdeclarativedebugserverconnection_p.h index 4175126..631da74 100644 --- a/src/declarative/debugger/qdeclarativedebugserverconnection_p.h +++ b/src/declarative/debugger/qdeclarativedebugserverconnection_p.h @@ -42,7 +42,7 @@ #ifndef QDECLARATIVEDEBUGSERVERCONNECTION_H #define QDECLARATIVEDEBUGSERVERCONNECTION_H -#include +#include QT_BEGIN_HEADER @@ -50,17 +50,22 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QDeclarativeDebugServerConnection +class QDeclarativeDebugServer; +class Q_DECLARATIVE_EXPORT QDeclarativeDebugServerConnection { public: QDeclarativeDebugServerConnection() {} virtual ~QDeclarativeDebugServerConnection() {} + virtual void setServer(QDeclarativeDebugServer *server) = 0; + virtual void setPort(int port, bool bock) = 0; virtual bool isConnected() const = 0; virtual void send(const QByteArray &message) = 0; virtual void disconnect() = 0; }; +Q_DECLARE_INTERFACE(QDeclarativeDebugServerConnection, "com.trolltech.Qt.QDeclarativeDebugServerConnection/1.0") + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/declarative/debugger/qdeclarativedebugservertcpconnection.cpp b/src/declarative/debugger/qdeclarativedebugservertcpconnection.cpp deleted file mode 100644 index 223c875..0000000 --- a/src/declarative/debugger/qdeclarativedebugservertcpconnection.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativedebugservertcpconnection_p.h" - -#include "qdeclarativedebugserver_p.h" -#include "private/qpacketprotocol_p.h" - -#include -#include - - -QT_BEGIN_NAMESPACE - -class QDeclarativeDebugServerTcpConnectionPrivate { -public: - QDeclarativeDebugServerTcpConnectionPrivate(); - - int port; - QTcpSocket *socket; - QPacketProtocol *protocol; - QTcpServer *tcpServer; - - QDeclarativeDebugServer *debugServer; -}; - -QDeclarativeDebugServerTcpConnectionPrivate::QDeclarativeDebugServerTcpConnectionPrivate() : - port(0), - socket(0), - protocol(0), - tcpServer(0), - debugServer(0) -{ -} - -QDeclarativeDebugServerTcpConnection::QDeclarativeDebugServerTcpConnection(int port, QDeclarativeDebugServer *server) : - QObject(server), - d_ptr(new QDeclarativeDebugServerTcpConnectionPrivate) -{ - Q_D(QDeclarativeDebugServerTcpConnection); - d->port = port; - d->debugServer = server; -} - -QDeclarativeDebugServerTcpConnection::~QDeclarativeDebugServerTcpConnection() -{ - delete d_ptr; -} - -bool QDeclarativeDebugServerTcpConnection::isConnected() const -{ - Q_D(const QDeclarativeDebugServerTcpConnection); - return d->socket && d->socket->state() == QTcpSocket::ConnectedState; -} - -void QDeclarativeDebugServerTcpConnection::send(const QByteArray &message) -{ - Q_D(QDeclarativeDebugServerTcpConnection); - - if (!isConnected()) - return; - - QPacket pack; - pack.writeRawData(message.data(), message.length()); - - d->protocol->send(pack); - d->socket->flush(); -} - -void QDeclarativeDebugServerTcpConnection::disconnect() -{ - Q_D(QDeclarativeDebugServerTcpConnection); - - delete d->protocol; - d->protocol = 0; - delete d->socket; - d->socket = 0; -} - -void QDeclarativeDebugServerTcpConnection::listen() -{ - Q_D(QDeclarativeDebugServerTcpConnection); - - d->tcpServer = new QTcpServer(this); - QObject::connect(d->tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); - if (d->tcpServer->listen(QHostAddress::Any, d->port)) - qWarning("QDeclarativeDebugServer: Waiting for connection on port %d...", d->port); - else - qWarning("QDeclarativeDebugServer: Unable to listen on port %d", d->port); -} - -void QDeclarativeDebugServerTcpConnection::waitForConnection() -{ - Q_D(QDeclarativeDebugServerTcpConnection); - d->tcpServer->waitForNewConnection(-1); -} - -void QDeclarativeDebugServerTcpConnection::readyRead() -{ - Q_D(QDeclarativeDebugServerTcpConnection); - QPacket packet = d->protocol->read(); - - QByteArray content = packet.data(); - d->debugServer->receiveMessage(content); -} - -void QDeclarativeDebugServerTcpConnection::newConnection() -{ - Q_D(QDeclarativeDebugServerTcpConnection); - - if (d->socket) { - qWarning("QDeclarativeDebugServer error: another client is already connected"); - QTcpSocket *faultyConnection = d->tcpServer->nextPendingConnection(); - delete faultyConnection; - return; - } - - d->socket = d->tcpServer->nextPendingConnection(); - d->socket->setParent(this); - d->protocol = new QPacketProtocol(d->socket, this); - QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); -} - - -QT_END_NAMESPACE diff --git a/src/declarative/debugger/qdeclarativedebugservertcpconnection_p.h b/src/declarative/debugger/qdeclarativedebugservertcpconnection_p.h deleted file mode 100644 index f1c749ef..0000000 --- a/src/declarative/debugger/qdeclarativedebugservertcpconnection_p.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEDEBUGSERVERTCPCONNECTION_H -#define QDECLARATIVEDEBUGSERVERTCPCONNECTION_H - -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -#include - -class QDeclarativeDebugServer; -class QDeclarativeDebugServerTcpConnectionPrivate; -class QDeclarativeDebugServerTcpConnection : public QObject, public QDeclarativeDebugServerConnection -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QDeclarativeDebugServerTcpConnection) - Q_DISABLE_COPY(QDeclarativeDebugServerTcpConnection) - -public: - QDeclarativeDebugServerTcpConnection(int port, QDeclarativeDebugServer *server); - ~QDeclarativeDebugServerTcpConnection(); - - bool isConnected() const; - void send(const QByteArray &message); - void disconnect(); - - void listen(); - void waitForConnection(); - -private Q_SLOTS: - void readyRead(); - void newConnection(); - -private: - QDeclarativeDebugServerTcpConnectionPrivate *d_ptr; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QDECLARATIVEDEBUGSERVERTCPCONNECTION_H diff --git a/src/declarative/debugger/qpacketprotocol_p.h b/src/declarative/debugger/qpacketprotocol_p.h index 99fded5..1c69cdd 100644 --- a/src/declarative/debugger/qpacketprotocol_p.h +++ b/src/declarative/debugger/qpacketprotocol_p.h @@ -59,7 +59,7 @@ class QPacket; class QPacketAutoSend; class QPacketProtocolPrivate; -class Q_DECLARATIVE_PRIVATE_EXPORT QPacketProtocol : public QObject +class Q_DECLARATIVE_EXPORT QPacketProtocol : public QObject { Q_OBJECT public: @@ -89,7 +89,7 @@ private: }; -class Q_DECLARATIVE_PRIVATE_EXPORT QPacket : public QDataStream +class Q_DECLARATIVE_EXPORT QPacket : public QDataStream { public: QPacket(); diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 722979d..07825d9 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -14,5 +14,4 @@ embedded:SUBDIRS *= gfxdrivers decorations mousedrivers kbddrivers symbian:SUBDIRS += s60 contains(QT_CONFIG, phonon): SUBDIRS *= phonon contains(QT_CONFIG, multimedia): SUBDIRS *= audio - - +contains(QT_CONFIG, declarative): SUBDIRS *= qmldebugging diff --git a/src/plugins/qmldebugging/qmldebugging.pro b/src/plugins/qmldebugging/qmldebugging.pro new file mode 100644 index 0000000..01cf1a9 --- /dev/null +++ b/src/plugins/qmldebugging/qmldebugging.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs + +SUBDIRS = tcpserver + diff --git a/src/plugins/qmldebugging/tcpserver/qtcpserverconnection.cpp b/src/plugins/qmldebugging/tcpserver/qtcpserverconnection.cpp new file mode 100644 index 0000000..69c1ef5 --- /dev/null +++ b/src/plugins/qmldebugging/tcpserver/qtcpserverconnection.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtcpserverconnection.h" + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QTcpServerConnectionPrivate { +public: + QTcpServerConnectionPrivate(); + + int port; + QTcpSocket *socket; + QPacketProtocol *protocol; + QTcpServer *tcpServer; + + QDeclarativeDebugServer *debugServer; +}; + +QTcpServerConnectionPrivate::QTcpServerConnectionPrivate() : + port(0), + socket(0), + protocol(0), + tcpServer(0), + debugServer(0) +{ +} + +QTcpServerConnection::QTcpServerConnection() : + d_ptr(new QTcpServerConnectionPrivate) +{ + +} + +QTcpServerConnection::~QTcpServerConnection() +{ + delete d_ptr; +} + +void QTcpServerConnection::setServer(QDeclarativeDebugServer *server) +{ + Q_D(QTcpServerConnection); + d->debugServer = server; +} + +bool QTcpServerConnection::isConnected() const +{ + Q_D(const QTcpServerConnection); + return d->socket && d->socket->state() == QTcpSocket::ConnectedState; +} + +void QTcpServerConnection::send(const QByteArray &message) +{ + Q_D(QTcpServerConnection); + + if (!isConnected()) + return; + + QPacket pack; + pack.writeRawData(message.data(), message.length()); + + d->protocol->send(pack); + d->socket->flush(); +} + +void QTcpServerConnection::disconnect() +{ + Q_D(QTcpServerConnection); + + delete d->protocol; + d->protocol = 0; + delete d->socket; + d->socket = 0; +} + +void QTcpServerConnection::setPort(int port, bool block) +{ + Q_D(QTcpServerConnection); + d->port = port; + + listen(); + if (block) + d->tcpServer->waitForNewConnection(-1); +} + +void QTcpServerConnection::listen() +{ + Q_D(QTcpServerConnection); + + d->tcpServer = new QTcpServer(this); + QObject::connect(d->tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); + if (d->tcpServer->listen(QHostAddress::Any, d->port)) + qWarning("QDeclarativeDebugServer: Waiting for connection on port %d...", d->port); + else + qWarning("QDeclarativeDebugServer: Unable to listen on port %d", d->port); +} + + +void QTcpServerConnection::readyRead() +{ + Q_D(QTcpServerConnection); + QPacket packet = d->protocol->read(); + + QByteArray content = packet.data(); + d->debugServer->receiveMessage(content); +} + +void QTcpServerConnection::newConnection() +{ + Q_D(QTcpServerConnection); + + if (d->socket) { + qWarning("QDeclarativeDebugServer: Another client is already connected"); + QTcpSocket *faultyConnection = d->tcpServer->nextPendingConnection(); + delete faultyConnection; + return; + } + + d->socket = d->tcpServer->nextPendingConnection(); + d->socket->setParent(this); + d->protocol = new QPacketProtocol(d->socket, this); + QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); +} + + +Q_EXPORT_PLUGIN2(tcpserver, QTcpServerConnection) + +QT_END_NAMESPACE + diff --git a/src/plugins/qmldebugging/tcpserver/qtcpserverconnection.h b/src/plugins/qmldebugging/tcpserver/qtcpserverconnection.h new file mode 100644 index 0000000..a6e17e6 --- /dev/null +++ b/src/plugins/qmldebugging/tcpserver/qtcpserverconnection.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCPSERVERCONNECTION_H +#define QTCPSERVERCONNECTION_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDeclarativeDebugServer; +class QTcpServerConnectionPrivate; +class QTcpServerConnection : public QObject, public QDeclarativeDebugServerConnection +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QTcpServerConnection) + Q_DISABLE_COPY(QTcpServerConnection) + Q_INTERFACES(QDeclarativeDebugServerConnection) + + +public: + QTcpServerConnection(); + ~QTcpServerConnection(); + + void setServer(QDeclarativeDebugServer *server); + void setPort(int port, bool bock); + + bool isConnected() const; + void send(const QByteArray &message); + void disconnect(); + + void listen(); + void waitForConnection(); + +private Q_SLOTS: + void readyRead(); + void newConnection(); + +private: + QTcpServerConnectionPrivate *d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QTCPSERVERCONNECTION_H diff --git a/src/plugins/qmldebugging/tcpserver/tcpserver.pro b/src/plugins/qmldebugging/tcpserver/tcpserver.pro new file mode 100644 index 0000000..e90fb34 --- /dev/null +++ b/src/plugins/qmldebugging/tcpserver/tcpserver.pro @@ -0,0 +1,18 @@ +TARGET = tcpserver +QT += declarative network + +include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/qmldebugging +QTDIR_build:REQUIRES += "contains(QT_CONFIG, declarative)" + +SOURCES += \ + qtcpserverconnection.cpp + +HEADERS += \ + qtcpserverconnection.h + +target.path += $$[QT_INSTALL_PLUGINS]/qmldebugging +INSTALLS += target + +symbian:TARGET.UID3=0x20031E90 \ No newline at end of file -- cgit v0.12 From 35ae0b8146bca7a61203ee347654aed27951439c Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 9 Dec 2010 13:06:08 +0100 Subject: QDeclarativeDebug: Include debugger plugin in qmlviewer.sis Developers that want to debug qml on their device have to now install qmlviewer.sis. Reviewed-by: Christiaan Janssen --- tools/qml/qml.pro | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/qml/qml.pro b/tools/qml/qml.pro index bdac6e3..9b07ebe 100644 --- a/tools/qml/qml.pro +++ b/tools/qml/qml.pro @@ -43,6 +43,11 @@ symbian { contains(QT_CONFIG, s60): { LIBS += -lavkon -lcone } + + # Deploy plugin for remote debugging + qmldebuggingplugin.sources = $$QT_BUILD_TREE/plugins/qmldebugging/tcpserver$${QT_LIBINFIX}.dll + qmldebuggingplugin.path = c:$$QT_PLUGINS_BASE_DIR/qmldebugging + DEPLOYMENT += qmldebuggingplugin } mac { QMAKE_INFO_PLIST=Info_mac.plist -- cgit v0.12 From 3290135e88bd8a01e20842c9d1cdca5fe569bf62 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 16 Dec 2010 14:39:15 +0100 Subject: Symbian compile fix armv5 complained that the call to QChar::category() was ambiguous, because there is a version taking an uint, and a version taking ushort as argument. Reviewed-by: Christiaan Janssen --- src/script/bridge/qscriptdeclarativeclass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index 92248a0..13736bc 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -473,7 +473,7 @@ bool QScriptDeclarativeClass::startsWithUpper(const Identifier &identifier) JSC::UString::Rep *r = (JSC::UString::Rep *)identifier; if (r->size() < 1) return false; - return QChar::category(r->data()[0]) == QChar::Letter_Uppercase; + return QChar::category((ushort)(r->data()[0])) == QChar::Letter_Uppercase; } quint32 QScriptDeclarativeClass::toArrayIndex(const Identifier &identifier, bool *ok) -- cgit v0.12 From 3fe6eab1e6e451457b9c060b6b643b86d3f82557 Mon Sep 17 00:00:00 2001 From: Joona Petrell Date: Mon, 20 Dec 2010 12:07:22 +1000 Subject: Fix spelling in declarative autotests Task-number: Reviewed-by: Martin Jones --- .../qdeclarativeecmascript/data/nonExistantAttachedObject.qml | 5 ----- .../qdeclarativeecmascript/data/nonExistentAttachedObject.qml | 5 +++++ .../qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp | 8 ++++---- .../qdeclarativeinstruction/tst_qdeclarativeinstruction.cpp | 2 +- .../declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) delete mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/nonExistantAttachedObject.qml create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/nonExistentAttachedObject.qml diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/nonExistantAttachedObject.qml b/tests/auto/declarative/qdeclarativeecmascript/data/nonExistantAttachedObject.qml deleted file mode 100644 index f9585db..0000000 --- a/tests/auto/declarative/qdeclarativeecmascript/data/nonExistantAttachedObject.qml +++ /dev/null @@ -1,5 +0,0 @@ -import Qt.test 1.0 - -MyQmlObject { - stringProperty: MyQmlContainer.prop -} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/nonExistentAttachedObject.qml b/tests/auto/declarative/qdeclarativeecmascript/data/nonExistentAttachedObject.qml new file mode 100644 index 0000000..f9585db --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/nonExistentAttachedObject.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +MyQmlObject { + stringProperty: MyQmlContainer.prop +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 77fab91..4228bc4 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -105,7 +105,7 @@ private slots: void constantsOverrideBindings(); void outerBindingOverridesInnerBinding(); void aliasPropertyAndBinding(); - void nonExistantAttachedObject(); + void nonExistentAttachedObject(); void scope(); void signalParameterTypes(); void objectsCompareAsEqual(); @@ -643,7 +643,7 @@ void tst_qdeclarativeecmascript::attachedProperties() void tst_qdeclarativeecmascript::enums() { - // Existant enums + // Existent enums { QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml")); QObject *object = component.create(); @@ -785,9 +785,9 @@ Access a non-existent attached object. Tests for a regression where this used to crash. */ -void tst_qdeclarativeecmascript::nonExistantAttachedObject() +void tst_qdeclarativeecmascript::nonExistentAttachedObject() { - QDeclarativeComponent component(&engine, TEST_FILE("nonExistantAttachedObject.qml")); + QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml")); QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); diff --git a/tests/auto/declarative/qdeclarativeinstruction/tst_qdeclarativeinstruction.cpp b/tests/auto/declarative/qdeclarativeinstruction/tst_qdeclarativeinstruction.cpp index 4470d65..304ce61 100644 --- a/tests/auto/declarative/qdeclarativeinstruction/tst_qdeclarativeinstruction.cpp +++ b/tests/auto/declarative/qdeclarativeinstruction/tst_qdeclarativeinstruction.cpp @@ -512,7 +512,7 @@ void tst_qdeclarativeinstruction::dump() { QDeclarativeInstruction i; i.line = 50; - i.type = (QDeclarativeInstruction::Type)(1234); // Non-existant + i.type = (QDeclarativeInstruction::Type)(1234); // Non-existent data->bytecode << i; } diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp index 50463b7..6410853 100644 --- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp +++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp @@ -947,7 +947,7 @@ void tst_qdeclarativelanguage::aliasProperties() object->setProperty("value", QVariant(13)); QCOMPARE(object->property("valueAlias").toInt(), 13); - // Write throught alias + // Write through alias object->setProperty("valueAlias", QVariant(19)); QCOMPARE(object->property("valueAlias").toInt(), 19); QCOMPARE(object->property("value").toInt(), 19); @@ -1109,7 +1109,7 @@ void tst_qdeclarativelanguage::aliasProperties() object->setProperty("rectProperty", QVariant(QRect(33, 12, 99, 100))); QCOMPARE(object->property("valueAlias").toRect(), QRect(33, 12, 99, 100)); - // Write throught alias + // Write through alias object->setProperty("valueAlias", QVariant(QRect(3, 3, 4, 9))); QCOMPARE(object->property("valueAlias").toRect(), QRect(3, 3, 4, 9)); QCOMPARE(object->property("rectProperty").toRect(), QRect(3, 3, 4, 9)); @@ -1129,7 +1129,7 @@ void tst_qdeclarativelanguage::aliasProperties() object->setProperty("rectProperty", QVariant(QRect(33, 8, 102, 111))); QCOMPARE(object->property("aliasProperty").toInt(), 33); - // Write throught alias + // Write through alias object->setProperty("aliasProperty", QVariant(4)); QCOMPARE(object->property("aliasProperty").toInt(), 4); QCOMPARE(object->property("rectProperty").toRect(), QRect(4, 8, 102, 111)); -- cgit v0.12 From ee4a2417950dc9b411660fa229908619eff956a2 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 20 Dec 2010 15:42:52 +1000 Subject: Add copyright header --- .../touchinteraction/pincharea/flickresize.qml | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/examples/declarative/touchinteraction/pincharea/flickresize.qml b/examples/declarative/touchinteraction/pincharea/flickresize.qml index 8034e29..8f29d6d 100644 --- a/examples/declarative/touchinteraction/pincharea/flickresize.qml +++ b/examples/declarative/touchinteraction/pincharea/flickresize.qml @@ -1,3 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + import QtQuick 1.1 Rectangle { -- cgit v0.12 From 6b37f71b318445a338c4afe5ba8a5ccaff573518 Mon Sep 17 00:00:00 2001 From: Joona Petrell Date: Mon, 20 Dec 2010 17:04:41 +1000 Subject: Update Minehunt demo warning message The message was talking about a C++ plugin when the demo is nowadays in a form of a standalone executable. Task-number: Reviewed-by: Bea Lam --- demos/declarative/minehunt/minehunt.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/declarative/minehunt/minehunt.qml b/demos/declarative/minehunt/minehunt.qml index eb67b06..88ecd6d 100644 --- a/demos/declarative/minehunt/minehunt.qml +++ b/demos/declarative/minehunt/minehunt.qml @@ -104,7 +104,7 @@ Item { anchors.centerIn: parent; width: parent.width - 20 horizontalAlignment: Text.AlignHCenter wrapMode: Text.WordWrap - text: "Minehunt will not run properly if the C++ plugin is not compiled.\n\nPlease see README." + text: "Minehunt demo has to be compiled to run.\n\nPlease see README." color: "white"; font.bold: true; font.pixelSize: 14 visible: tiles == undefined } -- cgit v0.12 From 1476bf8d45b4f1ab6c56770939eb81c4c1b390ad Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Mon, 20 Dec 2010 14:29:19 +1000 Subject: Optimize name lookup for QDeclarativeProperty. If the property is constructed by passing in the property name (and we've verified that it is valid), we can cache that name immediately rather than reconstructing it on the first call to name(). Task-number: QTBUG-15331 Reviewed-by: Martin Jones --- src/declarative/qml/qdeclarativeproperty.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp index 60edd64..8eaa98b 100644 --- a/src/declarative/qml/qdeclarativeproperty.cpp +++ b/src/declarative/qml/qdeclarativeproperty.cpp @@ -315,6 +315,8 @@ void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name if (property && !(property->flags & QDeclarativePropertyCache::Data::IsFunction)) { object = currentObject; core = *property; + nameCache = terminal; + isNameCached = true; } } -- cgit v0.12 From a764a0b5d66e13fb69a5b69330c5edfecf89ee8b Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 21 Dec 2010 08:53:00 +1000 Subject: Optimize QByteArray to QString conversion in PropertyChanges. Perform the conversion once at compile time, rather than many times later. Task-number: QTBUG-15331 Reviewed-by: Martin Jones --- .../util/qdeclarativepropertychanges.cpp | 72 +++++++++++----------- .../util/qdeclarativepropertychanges_p.h | 18 +++--- src/declarative/util/qdeclarativestate.cpp | 24 ++++---- src/declarative/util/qdeclarativestate_p.h | 12 ++-- 4 files changed, 62 insertions(+), 64 deletions(-) diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp index 400803e..6737382 100644 --- a/src/declarative/util/qdeclarativepropertychanges.cpp +++ b/src/declarative/util/qdeclarativepropertychanges.cpp @@ -220,12 +220,12 @@ public: void decode(); - QList > properties; - QList > expressions; + QList > properties; + QList > expressions; QList ids; QList signalReplacements; - QDeclarativeProperty property(const QByteArray &); + QDeclarativeProperty property(const QString &); }; void @@ -293,7 +293,7 @@ QDeclarativePropertyChangesParser::compile(const QList> count; for (int ii = 0; ii < count; ++ii) { - QByteArray name; + QString name; bool isScript; QVariant data; QDeclarativeBinding::Identifier id; @@ -405,15 +405,15 @@ void QDeclarativePropertyChanges::setRestoreEntryValues(bool v) } QDeclarativeProperty -QDeclarativePropertyChangesPrivate::property(const QByteArray &property) +QDeclarativePropertyChangesPrivate::property(const QString &property) { Q_Q(QDeclarativePropertyChanges); - QDeclarativeProperty prop(object, QString::fromUtf8(property), qmlContext(q)); + QDeclarativeProperty prop(object, property, qmlContext(q)); if (!prop.isValid()) { - qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to non-existent property \"%1\"").arg(QString::fromUtf8(property)); + qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to non-existent property \"%1\"").arg(property); return QDeclarativeProperty(); } else if (!(prop.type() & QDeclarativeProperty::SignalProperty) && !prop.isWritable()) { - qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to read-only property \"%1\"").arg(QString::fromUtf8(property)); + qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to read-only property \"%1\"").arg(property); return QDeclarativeProperty(); } return prop; @@ -429,9 +429,7 @@ QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions() for (int ii = 0; ii < d->properties.count(); ++ii) { - QByteArray property = d->properties.at(ii).first; - - QDeclarativeAction a(d->object, QString::fromUtf8(property), + QDeclarativeAction a(d->object, d->properties.at(ii).first, qmlContext(this), d->properties.at(ii).second); if (a.property.isValid()) { @@ -453,7 +451,7 @@ QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions() for (int ii = 0; ii < d->expressions.count(); ++ii) { - QByteArray property = d->expressions.at(ii).first; + const QString &property = d->expressions.at(ii).first; QDeclarativeProperty prop = d->property(property); if (prop.isValid()) { @@ -462,7 +460,7 @@ QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions() a.property = prop; a.fromValue = a.property.read(); a.specifiedObject = d->object; - a.specifiedProperty = QString::fromUtf8(property); + a.specifiedProperty = property; if (d->isExplicit) { a.toValue = d->expressions.at(ii).second->evaluate(); @@ -518,10 +516,10 @@ void QDeclarativePropertyChanges::setIsExplicit(bool e) d->isExplicit = e; } -bool QDeclarativePropertyChanges::containsValue(const QByteArray &name) const +bool QDeclarativePropertyChanges::containsValue(const QString &name) const { Q_D(const QDeclarativePropertyChanges); - typedef QPair PropertyEntry; + typedef QPair PropertyEntry; QListIterator propertyIterator(d->properties); while (propertyIterator.hasNext()) { @@ -534,10 +532,10 @@ bool QDeclarativePropertyChanges::containsValue(const QByteArray &name) const return false; } -bool QDeclarativePropertyChanges::containsExpression(const QByteArray &name) const +bool QDeclarativePropertyChanges::containsExpression(const QString &name) const { Q_D(const QDeclarativePropertyChanges); - typedef QPair ExpressionEntry; + typedef QPair ExpressionEntry; QListIterator expressionIterator(d->expressions); while (expressionIterator.hasNext()) { @@ -550,16 +548,16 @@ bool QDeclarativePropertyChanges::containsExpression(const QByteArray &name) con return false; } -bool QDeclarativePropertyChanges::containsProperty(const QByteArray &name) const +bool QDeclarativePropertyChanges::containsProperty(const QString &name) const { return containsValue(name) || containsExpression(name); } -void QDeclarativePropertyChanges::changeValue(const QByteArray &name, const QVariant &value) +void QDeclarativePropertyChanges::changeValue(const QString &name, const QVariant &value) { Q_D(QDeclarativePropertyChanges); - typedef QPair PropertyEntry; - typedef QPair ExpressionEntry; + typedef QPair PropertyEntry; + typedef QPair ExpressionEntry; QMutableListIterator expressionIterator(d->expressions); while (expressionIterator.hasNext()) { @@ -596,7 +594,7 @@ void QDeclarativePropertyChanges::changeValue(const QByteArray &name, const QVar action.property = d->property(name); action.fromValue = action.property.read(); action.specifiedObject = object(); - action.specifiedProperty = QString::fromUtf8(name); + action.specifiedProperty = name; action.toValue = value; propertyIterator.insert(PropertyEntry(name, value)); @@ -609,11 +607,11 @@ void QDeclarativePropertyChanges::changeValue(const QByteArray &name, const QVar } } -void QDeclarativePropertyChanges::changeExpression(const QByteArray &name, const QString &expression) +void QDeclarativePropertyChanges::changeExpression(const QString &name, const QString &expression) { Q_D(QDeclarativePropertyChanges); - typedef QPair PropertyEntry; - typedef QPair ExpressionEntry; + typedef QPair PropertyEntry; + typedef QPair ExpressionEntry; bool hadValue = false; @@ -667,7 +665,7 @@ void QDeclarativePropertyChanges::changeExpression(const QByteArray &name, const action.property = d->property(name); action.fromValue = action.property.read(); action.specifiedObject = object(); - action.specifiedProperty = QString::fromUtf8(name); + action.specifiedProperty = name; if (d->isExplicit) { @@ -690,11 +688,11 @@ void QDeclarativePropertyChanges::changeExpression(const QByteArray &name, const // what about the signal handler? } -QVariant QDeclarativePropertyChanges::property(const QByteArray &name) const +QVariant QDeclarativePropertyChanges::property(const QString &name) const { Q_D(const QDeclarativePropertyChanges); - typedef QPair PropertyEntry; - typedef QPair ExpressionEntry; + typedef QPair PropertyEntry; + typedef QPair ExpressionEntry; QListIterator propertyIterator(d->properties); while (propertyIterator.hasNext()) { @@ -715,11 +713,11 @@ QVariant QDeclarativePropertyChanges::property(const QByteArray &name) const return QVariant(); } -void QDeclarativePropertyChanges::removeProperty(const QByteArray &name) +void QDeclarativePropertyChanges::removeProperty(const QString &name) { Q_D(QDeclarativePropertyChanges); - typedef QPair PropertyEntry; - typedef QPair ExpressionEntry; + typedef QPair PropertyEntry; + typedef QPair ExpressionEntry; QMutableListIterator expressionIterator(d->expressions); while (expressionIterator.hasNext()) { @@ -742,10 +740,10 @@ void QDeclarativePropertyChanges::removeProperty(const QByteArray &name) } } -QVariant QDeclarativePropertyChanges::value(const QByteArray &name) const +QVariant QDeclarativePropertyChanges::value(const QString &name) const { Q_D(const QDeclarativePropertyChanges); - typedef QPair PropertyEntry; + typedef QPair PropertyEntry; QListIterator propertyIterator(d->properties); while (propertyIterator.hasNext()) { @@ -758,10 +756,10 @@ QVariant QDeclarativePropertyChanges::value(const QByteArray &name) const return QVariant(); } -QString QDeclarativePropertyChanges::expression(const QByteArray &name) const +QString QDeclarativePropertyChanges::expression(const QString &name) const { Q_D(const QDeclarativePropertyChanges); - typedef QPair ExpressionEntry; + typedef QPair ExpressionEntry; QListIterator expressionIterator(d->expressions); while (expressionIterator.hasNext()) { diff --git a/src/declarative/util/qdeclarativepropertychanges_p.h b/src/declarative/util/qdeclarativepropertychanges_p.h index 449574c..1a98cec 100644 --- a/src/declarative/util/qdeclarativepropertychanges_p.h +++ b/src/declarative/util/qdeclarativepropertychanges_p.h @@ -75,19 +75,19 @@ public: virtual ActionList actions(); - bool containsProperty(const QByteArray &name) const; - bool containsValue(const QByteArray &name) const; - bool containsExpression(const QByteArray &name) const; - void changeValue(const QByteArray &name, const QVariant &value); - void changeExpression(const QByteArray &name, const QString &expression); - void removeProperty(const QByteArray &name); - QVariant value(const QByteArray &name) const; - QString expression(const QByteArray &name) const; + bool containsProperty(const QString &name) const; + bool containsValue(const QString &name) const; + bool containsExpression(const QString &name) const; + void changeValue(const QString &name, const QVariant &value); + void changeExpression(const QString &name, const QString &expression); + void removeProperty(const QString &name); + QVariant value(const QString &name) const; + QString expression(const QString &name) const; void detachFromState(); void attachToState(); - QVariant property(const QByteArray &name) const; + QVariant property(const QString &name) const; }; class QDeclarativePropertyChangesParser : public QDeclarativeCustomParser diff --git a/src/declarative/util/qdeclarativestate.cpp b/src/declarative/util/qdeclarativestate.cpp index 6925e03..cde6f00 100644 --- a/src/declarative/util/qdeclarativestate.cpp +++ b/src/declarative/util/qdeclarativestate.cpp @@ -370,7 +370,7 @@ void QDeclarativeAction::deleteFromBinding() } } -bool QDeclarativeState::containsPropertyInRevertList(QObject *target, const QByteArray &name) const +bool QDeclarativeState::containsPropertyInRevertList(QObject *target, const QString &name) const { Q_D(const QDeclarativeState); @@ -379,7 +379,7 @@ bool QDeclarativeState::containsPropertyInRevertList(QObject *target, const QByt while (revertListIterator.hasNext()) { const QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); - if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name) + if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) return true; } } @@ -387,7 +387,7 @@ bool QDeclarativeState::containsPropertyInRevertList(QObject *target, const QByt return false; } -bool QDeclarativeState::changeValueInRevertList(QObject *target, const QByteArray &name, const QVariant &revertValue) +bool QDeclarativeState::changeValueInRevertList(QObject *target, const QString &name, const QVariant &revertValue) { Q_D(QDeclarativeState); @@ -396,7 +396,7 @@ bool QDeclarativeState::changeValueInRevertList(QObject *target, const QByteArra while (revertListIterator.hasNext()) { QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); - if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name) { + if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) { simpleAction.setValue(revertValue); return true; } @@ -406,7 +406,7 @@ bool QDeclarativeState::changeValueInRevertList(QObject *target, const QByteArra return false; } -bool QDeclarativeState::changeBindingInRevertList(QObject *target, const QByteArray &name, QDeclarativeAbstractBinding *binding) +bool QDeclarativeState::changeBindingInRevertList(QObject *target, const QString &name, QDeclarativeAbstractBinding *binding) { Q_D(QDeclarativeState); @@ -415,7 +415,7 @@ bool QDeclarativeState::changeBindingInRevertList(QObject *target, const QByteAr while (revertListIterator.hasNext()) { QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); - if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name) { + if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) { if (simpleAction.binding()) simpleAction.binding()->destroy(); @@ -428,7 +428,7 @@ bool QDeclarativeState::changeBindingInRevertList(QObject *target, const QByteAr return false; } -bool QDeclarativeState::removeEntryFromRevertList(QObject *target, const QByteArray &name) +bool QDeclarativeState::removeEntryFromRevertList(QObject *target, const QString &name) { Q_D(QDeclarativeState); @@ -437,7 +437,7 @@ bool QDeclarativeState::removeEntryFromRevertList(QObject *target, const QByteAr while (revertListIterator.hasNext()) { QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); - if (simpleAction.property().object() == target && simpleAction.property().name().toUtf8() == name) { + if (simpleAction.property().object() == target && simpleAction.property().name() == name) { QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property()); if (oldBinding) { QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0); @@ -517,7 +517,7 @@ void QDeclarativeState::addEntriesToRevertList(const QList & } } -QVariant QDeclarativeState::valueInRevertList(QObject *target, const QByteArray &name) const +QVariant QDeclarativeState::valueInRevertList(QObject *target, const QString &name) const { Q_D(const QDeclarativeState); @@ -526,7 +526,7 @@ QVariant QDeclarativeState::valueInRevertList(QObject *target, const QByteArray while (revertListIterator.hasNext()) { const QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); - if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name) + if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) return simpleAction.value(); } } @@ -534,7 +534,7 @@ QVariant QDeclarativeState::valueInRevertList(QObject *target, const QByteArray return QVariant(); } -QDeclarativeAbstractBinding *QDeclarativeState::bindingInRevertList(QObject *target, const QByteArray &name) const +QDeclarativeAbstractBinding *QDeclarativeState::bindingInRevertList(QObject *target, const QString &name) const { Q_D(const QDeclarativeState); @@ -543,7 +543,7 @@ QDeclarativeAbstractBinding *QDeclarativeState::bindingInRevertList(QObject *tar while (revertListIterator.hasNext()) { const QDeclarativeSimpleAction &simpleAction = revertListIterator.next(); - if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty().toUtf8() == name) + if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) return simpleAction.binding(); } } diff --git a/src/declarative/util/qdeclarativestate_p.h b/src/declarative/util/qdeclarativestate_p.h index 7b9c18a..dd43a50 100644 --- a/src/declarative/util/qdeclarativestate_p.h +++ b/src/declarative/util/qdeclarativestate_p.h @@ -180,15 +180,15 @@ public: QDeclarativeStateGroup *stateGroup() const; void setStateGroup(QDeclarativeStateGroup *); - bool containsPropertyInRevertList(QObject *target, const QByteArray &name) const; - bool changeValueInRevertList(QObject *target, const QByteArray &name, const QVariant &revertValue); - bool changeBindingInRevertList(QObject *target, const QByteArray &name, QDeclarativeAbstractBinding *binding); - bool removeEntryFromRevertList(QObject *target, const QByteArray &name); + bool containsPropertyInRevertList(QObject *target, const QString &name) const; + bool changeValueInRevertList(QObject *target, const QString &name, const QVariant &revertValue); + bool changeBindingInRevertList(QObject *target, const QString &name, QDeclarativeAbstractBinding *binding); + bool removeEntryFromRevertList(QObject *target, const QString &name); void addEntryToRevertList(const QDeclarativeAction &action); void removeAllEntriesFromRevertList(QObject *target); void addEntriesToRevertList(const QList &actions); - QVariant valueInRevertList(QObject *target, const QByteArray &name) const; - QDeclarativeAbstractBinding *bindingInRevertList(QObject *target, const QByteArray &name) const; + QVariant valueInRevertList(QObject *target, const QString &name) const; + QDeclarativeAbstractBinding *bindingInRevertList(QObject *target, const QString &name) const; bool isStateActive() const; -- cgit v0.12 From 3468ee1a47bc646fe2af5de38425ee917ea92f59 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 21 Dec 2010 13:52:44 +1000 Subject: Fix potential crash in PropertyChanges binding rewrite handling. This fixes the autotest regression for tst_qdeclarativestates::editProperties introduced by 488e616b50707e5b37162e6d0cfc71a1ffdf9bef. Reviewed-by: Joona Petrell --- src/declarative/qml/qdeclarativebinding.cpp | 5 ++ src/declarative/qml/qdeclarativebinding_p.h | 1 + .../util/qdeclarativepropertychanges.cpp | 63 ++++++++++++---------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index 1ead6ce..223d057 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -209,6 +209,8 @@ void QDeclarativeAbstractBinding::setEnabled(bool enabled, QDeclarativePropertyP if (enabled) update(flags); } +QDeclarativeBinding::Identifier QDeclarativeBinding::Invalid = -1; + void QDeclarativeBindingPrivate::refresh() { Q_Q(QDeclarativeBinding); @@ -238,6 +240,9 @@ QDeclarativeBinding * QDeclarativeBinding::createBinding(Identifier id, QObject *obj, QDeclarativeContext *ctxt, const QString &url, int lineNumber, QObject *parent) { + if (id < 0) + return 0; + QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(ctxt); QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(qmlEngine(obj)); diff --git a/src/declarative/qml/qdeclarativebinding_p.h b/src/declarative/qml/qdeclarativebinding_p.h index 787a3b9..69931d9 100644 --- a/src/declarative/qml/qdeclarativebinding_p.h +++ b/src/declarative/qml/qdeclarativebinding_p.h @@ -163,6 +163,7 @@ public: virtual QString expression() const; typedef int Identifier; + static Identifier Invalid; static QDeclarativeBinding *createBinding(Identifier, QObject *, QDeclarativeContext *, const QString &, int, QObject *parent=0); public Q_SLOTS: diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp index 6737382..47f03a1 100644 --- a/src/declarative/util/qdeclarativepropertychanges.cpp +++ b/src/declarative/util/qdeclarativepropertychanges.cpp @@ -220,9 +220,19 @@ public: void decode(); + class ExpressionChange { + public: + ExpressionChange(const QString &_name, + QDeclarativeBinding::Identifier _id, + QDeclarativeExpression *_expr) + : name(_name), id(_id), expression(_expr) {} + QString name; + QDeclarativeBinding::Identifier id; + QDeclarativeExpression *expression; + }; + QList > properties; - QList > expressions; - QList ids; + QList expressions; QList signalReplacements; QDeclarativeProperty property(const QString &); @@ -315,7 +325,7 @@ void QDeclarativePropertyChangesPrivate::decode() QString name; bool isScript; QVariant data; - QDeclarativeBinding::Identifier id; + QDeclarativeBinding::Identifier id = QDeclarativeBinding::Invalid; ds >> name; ds >> isScript; ds >> data; @@ -337,8 +347,7 @@ void QDeclarativePropertyChangesPrivate::decode() QDeclarativeData *ddata = QDeclarativeData::get(q); if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber); - expressions << qMakePair(name, expression); - ids << id; + expressions << ExpressionChange(name, id, expression); } else { properties << qMakePair(name, data); } @@ -366,7 +375,7 @@ QDeclarativePropertyChanges::~QDeclarativePropertyChanges() { Q_D(QDeclarativePropertyChanges); for(int ii = 0; ii < d->expressions.count(); ++ii) - delete d->expressions.at(ii).second; + delete d->expressions.at(ii).expression; for(int ii = 0; ii < d->signalReplacements.count(); ++ii) delete d->signalReplacements.at(ii); } @@ -451,7 +460,7 @@ QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions() for (int ii = 0; ii < d->expressions.count(); ++ii) { - const QString &property = d->expressions.at(ii).first; + const QString &property = d->expressions.at(ii).name; QDeclarativeProperty prop = d->property(property); if (prop.isValid()) { @@ -463,12 +472,12 @@ QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions() a.specifiedProperty = property; if (d->isExplicit) { - a.toValue = d->expressions.at(ii).second->evaluate(); + a.toValue = d->expressions.at(ii).expression->evaluate(); } else { - QDeclarativeExpression *e = d->expressions.at(ii).second; + QDeclarativeExpression *e = d->expressions.at(ii).expression; - QDeclarativeBinding::Identifier id = d->ids.at(ii); - QDeclarativeBinding *newBinding = QDeclarativeBinding::createBinding(id, object(), qmlContext(this), e->sourceFile(), e->lineNumber()); + QDeclarativeBinding::Identifier id = d->expressions.at(ii).id; + QDeclarativeBinding *newBinding = id != QDeclarativeBinding::Invalid ? QDeclarativeBinding::createBinding(id, object(), qmlContext(this), e->sourceFile(), e->lineNumber()) : 0; if (!newBinding) { newBinding = new QDeclarativeBinding(e->expression(), object(), qmlContext(this)); newBinding->setSourceLocation(e->sourceFile(), e->lineNumber()); @@ -535,12 +544,12 @@ bool QDeclarativePropertyChanges::containsValue(const QString &name) const bool QDeclarativePropertyChanges::containsExpression(const QString &name) const { Q_D(const QDeclarativePropertyChanges); - typedef QPair ExpressionEntry; + typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry; QListIterator expressionIterator(d->expressions); while (expressionIterator.hasNext()) { const ExpressionEntry &entry = expressionIterator.next(); - if (entry.first == name) { + if (entry.name == name) { return true; } } @@ -557,12 +566,12 @@ void QDeclarativePropertyChanges::changeValue(const QString &name, const QVarian { Q_D(QDeclarativePropertyChanges); typedef QPair PropertyEntry; - typedef QPair ExpressionEntry; + typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry; QMutableListIterator expressionIterator(d->expressions); while (expressionIterator.hasNext()) { const ExpressionEntry &entry = expressionIterator.next(); - if (entry.first == name) { + if (entry.name == name) { expressionIterator.remove(); if (state() && state()->isStateActive()) { QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name)); @@ -611,7 +620,7 @@ void QDeclarativePropertyChanges::changeExpression(const QString &name, const QS { Q_D(QDeclarativePropertyChanges); typedef QPair PropertyEntry; - typedef QPair ExpressionEntry; + typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry; bool hadValue = false; @@ -628,8 +637,8 @@ void QDeclarativePropertyChanges::changeExpression(const QString &name, const QS QMutableListIterator expressionIterator(d->expressions); while (expressionIterator.hasNext()) { const ExpressionEntry &entry = expressionIterator.next(); - if (entry.first == name) { - entry.second->setExpression(expression); + if (entry.name == name) { + entry.expression->setExpression(expression); if (state() && state()->isStateActive()) { QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name)); if (oldBinding) { @@ -646,7 +655,7 @@ void QDeclarativePropertyChanges::changeExpression(const QString &name, const QS } QDeclarativeExpression *newExpression = new QDeclarativeExpression(qmlContext(this), d->object, expression); - expressionIterator.insert(ExpressionEntry(name, newExpression)); + expressionIterator.insert(ExpressionEntry(name, QDeclarativeBinding::Invalid, newExpression)); if (state() && state()->isStateActive()) { if (hadValue) { @@ -692,7 +701,7 @@ QVariant QDeclarativePropertyChanges::property(const QString &name) const { Q_D(const QDeclarativePropertyChanges); typedef QPair PropertyEntry; - typedef QPair ExpressionEntry; + typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry; QListIterator propertyIterator(d->properties); while (propertyIterator.hasNext()) { @@ -705,8 +714,8 @@ QVariant QDeclarativePropertyChanges::property(const QString &name) const QListIterator expressionIterator(d->expressions); while (expressionIterator.hasNext()) { const ExpressionEntry &entry = expressionIterator.next(); - if (entry.first == name) { - return QVariant(entry.second->expression()); + if (entry.name == name) { + return QVariant(entry.expression->expression()); } } @@ -717,12 +726,12 @@ void QDeclarativePropertyChanges::removeProperty(const QString &name) { Q_D(QDeclarativePropertyChanges); typedef QPair PropertyEntry; - typedef QPair ExpressionEntry; + typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry; QMutableListIterator expressionIterator(d->expressions); while (expressionIterator.hasNext()) { const ExpressionEntry &entry = expressionIterator.next(); - if (entry.first == name) { + if (entry.name == name) { expressionIterator.remove(); state()->removeEntryFromRevertList(object(), name); return; @@ -759,13 +768,13 @@ QVariant QDeclarativePropertyChanges::value(const QString &name) const QString QDeclarativePropertyChanges::expression(const QString &name) const { Q_D(const QDeclarativePropertyChanges); - typedef QPair ExpressionEntry; + typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry; QListIterator expressionIterator(d->expressions); while (expressionIterator.hasNext()) { const ExpressionEntry &entry = expressionIterator.next(); - if (entry.first == name) { - return entry.second->expression(); + if (entry.name == name) { + return entry.expression->expression(); } } -- cgit v0.12 From 956c026be3f0a701024aaa466e158a3744284a83 Mon Sep 17 00:00:00 2001 From: Christopher Ham Date: Tue, 21 Dec 2010 17:05:04 +1000 Subject: ContentX and ContentY reset on flow change The gridView should be visible when the flow is changed, regardless of the content position before the flow change. Task-number: QTBUG-16230 Reviewed-by: Martin Jones --- src/declarative/graphicsitems/qdeclarativegridview.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index 4a6a9dc..5aa88b5 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -1606,6 +1606,8 @@ void QDeclarativeGridView::setFlow(Flow flow) setContentHeight(-1); setFlickableDirection(QDeclarativeFlickable::HorizontalFlick); } + setContentX(0); + setContentY(0); d->clear(); d->updateGrid(); refill(); -- cgit v0.12 From 5af714b2f1ec9dd85707809397751128c95a93bf Mon Sep 17 00:00:00 2001 From: Christopher Ham Date: Tue, 21 Dec 2010 17:23:46 +1000 Subject: Adding autotest coverage to QDecalarativeGridView Tests added for snapping, and adding coverage for TopToBottom flow Reviewed-by: Martin Jones --- .../tst_qdeclarativegridview.cpp | 92 ++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp index fd5d140..bd9885d 100644 --- a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp +++ b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp @@ -78,6 +78,7 @@ private slots: void componentChanges(); void modelChanges(); void positionViewAtIndex(); + void snapping(); void resetModel(); void enforceRange(); void QTBUG_8456(); @@ -993,6 +994,7 @@ void tst_QDeclarativeGridView::positionViewAtIndex() // Position on a currently visible item gridview->positionViewAtIndex(4, QDeclarativeGridView::Beginning); + QTRY_COMPARE(gridview->indexAt(120, 90), 4); QTRY_COMPARE(gridview->contentY(), 60.); // Confirm items positioned correctly @@ -1007,6 +1009,7 @@ void tst_QDeclarativeGridView::positionViewAtIndex() // Position on an item beyond the visible items gridview->positionViewAtIndex(21, QDeclarativeGridView::Beginning); + QTRY_COMPARE(gridview->indexAt(40, 450), 21); QTRY_COMPARE(gridview->contentY(), 420.); // Confirm items positioned correctly @@ -1021,6 +1024,7 @@ void tst_QDeclarativeGridView::positionViewAtIndex() // Position on an item that would leave empty space if positioned at the top gridview->positionViewAtIndex(31, QDeclarativeGridView::Beginning); + QTRY_COMPARE(gridview->indexAt(120, 630), 31); QTRY_COMPARE(gridview->contentY(), 520.); // Confirm items positioned correctly @@ -1035,6 +1039,9 @@ void tst_QDeclarativeGridView::positionViewAtIndex() // Position at the beginning again gridview->positionViewAtIndex(0, QDeclarativeGridView::Beginning); + QTRY_COMPARE(gridview->indexAt(0, 0), 0); + QTRY_COMPARE(gridview->indexAt(40, 30), 0); + QTRY_COMPARE(gridview->indexAt(80, 60), 4); QTRY_COMPARE(gridview->contentY(), 0.); // Confirm items positioned correctly @@ -1088,6 +1095,82 @@ void tst_QDeclarativeGridView::positionViewAtIndex() gridview->positionViewAtIndex(20, QDeclarativeGridView::Contain); QTRY_COMPARE(gridview->contentY(), 100.); + // Test for Top To Bottom layout + ctxt->setContextProperty("testTopToBottom", QVariant(true)); + + // Confirm items positioned correctly + itemCount = findItems(contentItem, "wrapper").count(); + for (int i = 0; i < model.count() && i < itemCount-1; ++i) { + QDeclarativeItem *item = findItem(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QTRY_VERIFY(item); + QTRY_COMPARE(item->x(), (i/5)*80.); + QTRY_COMPARE(item->y(), (i%5)*60.); + } + + // Position at End + gridview->positionViewAtIndex(30, QDeclarativeGridView::End); + QTRY_COMPARE(gridview->contentX(), 320.); + QTRY_COMPARE(gridview->contentY(), 0.); + + // Position in Center + gridview->positionViewAtIndex(15, QDeclarativeGridView::Center); + QTRY_COMPARE(gridview->contentX(), 160.); + + // Ensure at least partially visible + gridview->positionViewAtIndex(15, QDeclarativeGridView::Visible); + QTRY_COMPARE(gridview->contentX(), 160.); + + gridview->setContentX(170); + gridview->positionViewAtIndex(25, QDeclarativeGridView::Visible); + QTRY_COMPARE(gridview->contentX(), 170.); + + gridview->positionViewAtIndex(30, QDeclarativeGridView::Visible); + QTRY_COMPARE(gridview->contentX(), 320.); + + gridview->setContentX(170); + gridview->positionViewAtIndex(25, QDeclarativeGridView::Contain); + QTRY_COMPARE(gridview->contentX(), 240.); + + delete canvas; +} + +void tst_QDeclarativeGridView::snapping() +{ + QDeclarativeView *canvas = createView(); + + TestModel model; + for (int i = 0; i < 40; i++) + model.addItem("Item" + QString::number(i), ""); + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testTopToBottom", QVariant(false)); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); + qApp->processEvents(); + + QDeclarativeGridView *gridview = findItem(canvas->rootObject(), "grid"); + QTRY_VERIFY(gridview != 0); + + gridview->setHeight(220); + QCOMPARE(gridview->height(), 220.); + + gridview->positionViewAtIndex(12, QDeclarativeGridView::Visible); + QCOMPARE(gridview->contentY(), 80.); + + gridview->setContentY(0); + QCOMPARE(gridview->contentY(), 0.); + + gridview->setSnapMode(QDeclarativeGridView::SnapToRow); + QCOMPARE(gridview->snapMode(), QDeclarativeGridView::SnapToRow); + + gridview->positionViewAtIndex(12, QDeclarativeGridView::Visible); + QCOMPARE(gridview->contentY(), 60.); + + gridview->positionViewAtIndex(15, QDeclarativeGridView::End); + QCOMPARE(gridview->contentY(), 120.); + delete canvas; } @@ -1231,6 +1314,15 @@ void tst_QDeclarativeGridView::manualHighlight() QTRY_COMPARE(gridview->currentItem(), findItem(contentItem, "wrapper", 2)); QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y()); QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x()); + + gridview->setFlow(QDeclarativeGridView::TopToBottom); + QTRY_COMPARE(gridview->flow(), QDeclarativeGridView::TopToBottom); + + gridview->setCurrentIndex(0); + QTRY_COMPARE(gridview->currentIndex(), 0); + QTRY_COMPARE(gridview->currentItem(), findItem(contentItem, "wrapper", 0)); + QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y()); + QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x()); } void tst_QDeclarativeGridView::footer() -- cgit v0.12 From 111e306c9991a0d89b0001b476e466891974945f Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Tue, 21 Dec 2010 09:12:58 +0100 Subject: QDeclarativeDebug: Remove unused file Got added in 5336e1838a95d97. --- src/declarative/debugger/debugger.pri | 1 - src/declarative/debugger/qdeclarativedebugserverplugin_p.h | 0 2 files changed, 1 deletion(-) delete mode 100644 src/declarative/debugger/qdeclarativedebugserverplugin_p.h diff --git a/src/declarative/debugger/debugger.pri b/src/declarative/debugger/debugger.pri index 9152677..75287b4 100644 --- a/src/declarative/debugger/debugger.pri +++ b/src/declarative/debugger/debugger.pri @@ -19,6 +19,5 @@ HEADERS += \ $$PWD/qdeclarativedebug_p.h \ $$PWD/qdeclarativedebugtrace_p.h \ $$PWD/qdeclarativedebughelper_p.h \ - $$PWD/qdeclarativedebugserverplugin_p.h \ $$PWD/qdeclarativedebugserver_p.h \ debugger/qdeclarativedebugserverconnection_p.h diff --git a/src/declarative/debugger/qdeclarativedebugserverplugin_p.h b/src/declarative/debugger/qdeclarativedebugserverplugin_p.h deleted file mode 100644 index e69de29..0000000 -- cgit v0.12 From 042e797a21a88ccafbaf54bbcfbf1e8d75b33740 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 22 Dec 2010 10:29:43 +1000 Subject: Optimization: make QDeclarativePropertyPrivate shared. Task-number: QTBUG-15331 Reviewed-by: Aaron Kennedy --- src/declarative/qml/qdeclarativeproperty.cpp | 98 +++++++++++++++++----------- src/declarative/qml/qdeclarativeproperty_p.h | 13 +--- 2 files changed, 64 insertions(+), 47 deletions(-) diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp index 8eaa98b..d7cf6cc 100644 --- a/src/declarative/qml/qdeclarativeproperty.cpp +++ b/src/declarative/qml/qdeclarativeproperty.cpp @@ -106,15 +106,16 @@ qWarning() << "Pixel size should now be 24:" << property.read().toInt(); Create an invalid QDeclarativeProperty. */ QDeclarativeProperty::QDeclarativeProperty() -: d(new QDeclarativePropertyPrivate) +: d(0) { - d->q = this; } /*! \internal */ QDeclarativeProperty::~QDeclarativeProperty() { - delete d; d = 0; + if (d) + d->release(); + d = 0; } /*! @@ -124,7 +125,6 @@ QDeclarativeProperty::~QDeclarativeProperty() QDeclarativeProperty::QDeclarativeProperty(QObject *obj) : d(new QDeclarativePropertyPrivate) { - d->q = this; d->initDefault(obj); } @@ -137,7 +137,6 @@ QDeclarativeProperty::QDeclarativeProperty(QObject *obj) QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeContext *ctxt) : d(new QDeclarativePropertyPrivate) { - d->q = this; d->context = ctxt?QDeclarativeContextData::get(ctxt):0; d->engine = ctxt?ctxt->engine():0; d->initDefault(obj); @@ -152,7 +151,6 @@ QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeContext *ct QDeclarativeProperty::QDeclarativeProperty(QObject *obj, QDeclarativeEngine *engine) : d(new QDeclarativePropertyPrivate) { - d->q = this; d->context = 0; d->engine = engine; d->initDefault(obj); @@ -178,7 +176,6 @@ void QDeclarativePropertyPrivate::initDefault(QObject *obj) QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name) : d(new QDeclarativePropertyPrivate) { - d->q = this; d->initProperty(obj, name); if (!isValid()) d->object = 0; } @@ -190,7 +187,6 @@ QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name) QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeContext *ctxt) : d(new QDeclarativePropertyPrivate) { - d->q = this; d->context = ctxt?QDeclarativeContextData::get(ctxt):0; d->engine = ctxt?ctxt->engine():0; d->initProperty(obj, name); @@ -205,7 +201,6 @@ QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QD QDeclarativeProperty::QDeclarativeProperty(QObject *obj, const QString &name, QDeclarativeEngine *engine) : d(new QDeclarativePropertyPrivate) { - d->q = this; d->context = 0; d->engine = engine; d->initProperty(obj, name); @@ -324,9 +319,10 @@ void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name Create a copy of \a other. */ QDeclarativeProperty::QDeclarativeProperty(const QDeclarativeProperty &other) -: d(new QDeclarativePropertyPrivate(*other.d)) { - d->q = this; + d = other.d; + if (d) + d->addref(); } /*! @@ -355,13 +351,13 @@ QDeclarativeProperty::QDeclarativeProperty(const QDeclarativeProperty &other) */ QDeclarativeProperty::PropertyTypeCategory QDeclarativeProperty::propertyTypeCategory() const { - return d->propertyTypeCategory(); + return d ? d->propertyTypeCategory() : InvalidCategory; } QDeclarativeProperty::PropertyTypeCategory QDeclarativePropertyPrivate::propertyTypeCategory() const { - uint type = q->type(); + uint type = this->type(); if (isValueType()) { return QDeclarativeProperty::Normal; @@ -388,6 +384,8 @@ QDeclarativePropertyPrivate::propertyTypeCategory() const */ const char *QDeclarativeProperty::propertyTypeName() const { + if (!d) + return 0; if (d->isValueType()) { QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context); @@ -414,6 +412,8 @@ const char *QDeclarativeProperty::propertyTypeName() const */ bool QDeclarativeProperty::operator==(const QDeclarativeProperty &other) const { + if (!d || !other.d) + return false; // category is intentially omitted here as it is generated // from the other members return d->object == other.d->object && @@ -427,7 +427,7 @@ bool QDeclarativeProperty::operator==(const QDeclarativeProperty &other) const */ int QDeclarativeProperty::propertyType() const { - return d->propertyType(); + return d ? d->propertyType() : QVariant::Invalid; } bool QDeclarativePropertyPrivate::isValueType() const @@ -437,7 +437,7 @@ bool QDeclarativePropertyPrivate::isValueType() const int QDeclarativePropertyPrivate::propertyType() const { - uint type = q->type(); + uint type = this->type(); if (isValueType()) { return valueType.valueTypePropType; } else if (type & QDeclarativeProperty::Property) { @@ -450,17 +450,22 @@ int QDeclarativePropertyPrivate::propertyType() const } } +QDeclarativeProperty::Type QDeclarativePropertyPrivate::type() const +{ + if (core.flags & QDeclarativePropertyCache::Data::IsFunction) + return QDeclarativeProperty::SignalProperty; + else if (core.isValid()) + return QDeclarativeProperty::Property; + else + return QDeclarativeProperty::Invalid; +} + /*! Returns the type of the property. */ QDeclarativeProperty::Type QDeclarativeProperty::type() const { - if (d->core.flags & QDeclarativePropertyCache::Data::IsFunction) - return SignalProperty; - else if (d->core.isValid()) - return Property; - else - return Invalid; + return d ? d->type() : Invalid; } /*! @@ -484,7 +489,7 @@ bool QDeclarativeProperty::isSignalProperty() const */ QObject *QDeclarativeProperty::object() const { - return d->object; + return d ? d->object : 0; } /*! @@ -492,15 +497,11 @@ QObject *QDeclarativeProperty::object() const */ QDeclarativeProperty &QDeclarativeProperty::operator=(const QDeclarativeProperty &other) { - d->context = other.d->context; - d->engine = other.d->engine; - d->object = other.d->object; - - d->isNameCached = other.d->isNameCached; - d->core = other.d->core; - d->nameCache = other.d->nameCache; - - d->valueType = other.d->valueType; + if (d) + d->release(); + d = other.d; + if (d) + d->addref(); return *this; } @@ -510,6 +511,8 @@ QDeclarativeProperty &QDeclarativeProperty::operator=(const QDeclarativeProperty */ bool QDeclarativeProperty::isWritable() const { + if (!d) + return false; if (!d->object) return false; if (d->core.flags & QDeclarativePropertyCache::Data::IsQList) //list @@ -527,6 +530,8 @@ bool QDeclarativeProperty::isWritable() const */ bool QDeclarativeProperty::isDesignable() const { + if (!d) + return false; if (type() & Property && d->core.isValid() && d->object) return d->object->metaObject()->property(d->core.coreIndex).isDesignable(); else @@ -538,6 +543,8 @@ bool QDeclarativeProperty::isDesignable() const */ bool QDeclarativeProperty::isResettable() const { + if (!d) + return false; if (type() & Property && d->core.isValid() && d->object) return d->core.flags & QDeclarativePropertyCache::Data::IsResettable; else @@ -550,6 +557,8 @@ bool QDeclarativeProperty::isResettable() const */ bool QDeclarativeProperty::isValid() const { + if (!d) + return false; return type() != Invalid; } @@ -558,6 +567,8 @@ bool QDeclarativeProperty::isValid() const */ QString QDeclarativeProperty::name() const { + if (!d) + return QString(); if (!d->isNameCached) { // ### if (!d->object) { @@ -594,6 +605,8 @@ QString QDeclarativeProperty::name() const */ QMetaProperty QDeclarativeProperty::property() const { + if (!d) + return QMetaProperty(); if (type() & Property && d->core.isValid() && d->object) return d->object->metaObject()->property(d->core.coreIndex); else @@ -606,6 +619,8 @@ QMetaProperty QDeclarativeProperty::property() const */ QMetaMethod QDeclarativeProperty::method() const { + if (!d) + return QMetaMethod(); if (type() & SignalProperty && d->object) return d->object->metaObject()->method(d->core.coreIndex); else @@ -619,7 +634,7 @@ QMetaMethod QDeclarativeProperty::method() const QDeclarativeAbstractBinding * QDeclarativePropertyPrivate::binding(const QDeclarativeProperty &that) { - if (!that.isProperty() || !that.d->object) + if (!that.d || !that.isProperty() || !that.d->object) return 0; return binding(that.d->object, that.d->core.coreIndex, that.d->valueType.valueTypeCoreIdx); @@ -643,7 +658,7 @@ QDeclarativePropertyPrivate::setBinding(const QDeclarativeProperty &that, QDeclarativeAbstractBinding *newBinding, WriteFlags flags) { - if (!that.isProperty() || !that.d->object) { + if (!that.d || !that.isProperty() || !that.d->object) { if (newBinding) newBinding->destroy(); return 0; @@ -893,6 +908,8 @@ QDeclarativePropertyPrivate::setSignalExpression(const QDeclarativeProperty &tha */ QVariant QDeclarativeProperty::read() const { + if (!d) + return QVariant(); if (!d->object) return QVariant(); @@ -1034,8 +1051,10 @@ bool QDeclarativePropertyPrivate::writeEnumProperty(const QMetaProperty &prop, i bool QDeclarativePropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags) { // Remove any existing bindings on this property - if (!(flags & DontRemoveBinding)) { - QDeclarativeAbstractBinding *binding = setBinding(*q, 0); + if (!(flags & DontRemoveBinding) && + (type() & QDeclarativeProperty::Property) && object) { + QDeclarativeAbstractBinding *binding = setBinding(object, core.coreIndex, + valueType.valueTypeCoreIdx, 0, flags); if (binding) binding->destroy(); } @@ -1314,6 +1333,8 @@ bool QDeclarativeProperty::reset() const bool QDeclarativePropertyPrivate::write(const QDeclarativeProperty &that, const QVariant &value, WriteFlags flags) { + if (!that.d) + return false; if (that.d->object && that.type() & QDeclarativeProperty::Property && that.d->core.isValid() && that.isWritable()) return that.d->writeValueProperty(value, flags); @@ -1392,12 +1413,12 @@ bool QDeclarativeProperty::connectNotifySignal(QObject *dest, const char *slot) */ int QDeclarativeProperty::index() const { - return d->core.coreIndex; + return d ? d->core.coreIndex : -1; } int QDeclarativePropertyPrivate::valueTypeCoreIndex(const QDeclarativeProperty &that) { - return that.d->valueType.valueTypeCoreIdx; + return that.d ? that.d->valueType.valueTypeCoreIdx : -1; } /*! @@ -1406,6 +1427,8 @@ int QDeclarativePropertyPrivate::valueTypeCoreIndex(const QDeclarativeProperty & */ int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativeProperty &that) { + if (!that.d) + return -1; int rv = that.d->core.coreIndex; if (rv != -1 && that.d->valueType.valueTypeCoreIdx != -1) rv = rv | (that.d->valueType.valueTypeCoreIdx << 24); @@ -1457,6 +1480,7 @@ QDeclarativePropertyPrivate::restore(const QByteArray &data, QObject *object, QD if (data.isEmpty()) return prop; + prop.d = new QDeclarativePropertyPrivate; prop.d->object = object; prop.d->context = ctxt; prop.d->engine = ctxt->engine; diff --git a/src/declarative/qml/qdeclarativeproperty_p.h b/src/declarative/qml/qdeclarativeproperty_p.h index 6392f88..f7d24f1 100644 --- a/src/declarative/qml/qdeclarativeproperty_p.h +++ b/src/declarative/qml/qdeclarativeproperty_p.h @@ -65,23 +65,15 @@ QT_BEGIN_NAMESPACE class QDeclarativeContext; class QDeclarativeEnginePrivate; class QDeclarativeExpression; -class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativePropertyPrivate +class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativePropertyPrivate : public QDeclarativeRefCount { public: enum WriteFlag { BypassInterceptor = 0x01, DontRemoveBinding = 0x02, RemoveBindingOnAliasWrite = 0x04 }; Q_DECLARE_FLAGS(WriteFlags, WriteFlag) QDeclarativePropertyPrivate() - : q(0), context(0), engine(0), object(0), isNameCached(false) {} - + : context(0), engine(0), object(0), isNameCached(false) {} - QDeclarativePropertyPrivate(const QDeclarativePropertyPrivate &other) - : q(0), context(other.context), engine(other.engine), object(other.object), - isNameCached(other.isNameCached), - core(other.core), nameCache(other.nameCache), - valueType(other.valueType) {} - - QDeclarativeProperty *q; QDeclarativeContextData *context; QDeclarativeEngine *engine; QDeclarativeGuard object; @@ -98,6 +90,7 @@ public: bool isValueType() const; int propertyType() const; + QDeclarativeProperty::Type type() const; QDeclarativeProperty::PropertyTypeCategory propertyTypeCategory() const; QVariant readValueProperty(); -- cgit v0.12 From 2de60ba30f86a9dd338359f7269b62ca5d0a2c46 Mon Sep 17 00:00:00 2001 From: Joona Petrell Date: Thu, 30 Dec 2010 17:16:16 +1000 Subject: Forward qmlviewer traces to system's default message handler on Symbian Task-number: QTBUG-16353 Reviewed-by: Christopher Ham --- tools/qml/main.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index b9513b9..2df96c0 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -88,6 +88,9 @@ void myMessageOutput(QtMsgType type, const char *msg) ::write(fd, "\n", 1); ::fsync(fd); + if (systemMsgOutput) + systemMsgOutput(type, msg); + switch (type) { case QtFatalMsg: abort(); @@ -529,11 +532,7 @@ QDeclarativeViewer *openFile(const QString &fileName) int main(int argc, char ** argv) { -#if defined (Q_OS_SYMBIAN) - qInstallMsgHandler(myMessageOutput); -#else systemMsgOutput = qInstallMsgHandler(myMessageOutput); -#endif #if defined (Q_WS_X11) || defined (Q_WS_MAC) //### default to using raster graphics backend for now -- cgit v0.12 From 22daf9fbdfaa859db6414d39d9354e7d46f63005 Mon Sep 17 00:00:00 2001 From: Joona Petrell Date: Thu, 30 Dec 2010 17:52:30 +1000 Subject: Add convenience deselect() functions to TextInput and TextEdit Task-number: QTBUG-16059 Reviewed-by: Christopher Ham --- src/declarative/graphicsitems/qdeclarativetextedit.cpp | 13 +++++++++++++ src/declarative/graphicsitems/qdeclarativetextedit_p.h | 1 + src/declarative/graphicsitems/qdeclarativetextinput.cpp | 11 +++++++++++ src/declarative/graphicsitems/qdeclarativetextinput_p.h | 1 + .../qdeclarativetextedit/tst_qdeclarativetextedit.cpp | 7 +++++++ .../qdeclarativetextinput/tst_qdeclarativetextinput.cpp | 7 +++++++ 6 files changed, 40 insertions(+) diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp index f37fa62..c1314ff 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp @@ -996,6 +996,19 @@ void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus) } /*! + \qmlmethod void TextEdit::deselect() + + Removes active text selection. +*/ +void QDeclarativeTextEdit::deselect() +{ + Q_D(QDeclarativeTextEdit); + QTextCursor c = d->control->textCursor(); + c.clearSelection(); + d->control->setTextCursor(c); +} + +/*! \qmlmethod void TextEdit::selectAll() Causes all text to be selected. diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p.h index 7f12c85..691d995 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextedit_p.h @@ -223,6 +223,7 @@ Q_SIGNALS: void selectByMouseChanged(bool selectByMouse); public Q_SLOTS: + void deselect(); void selectAll(); void selectWord(); void select(int start, int end); diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index 4649be8..4e1c297 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -1166,6 +1166,17 @@ QVariant QDeclarativeTextInput::inputMethodQuery(Qt::InputMethodQuery property) } /*! + \qmlmethod void TextInput::deselect() + + Removes active text selection. +*/ +void QDeclarativeTextInput::deselect() +{ + Q_D(QDeclarativeTextInput); + d->control->deselect(); +} + +/*! \qmlmethod void TextInput::selectAll() Causes all text to be selected. diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p.h index 06f77e5..878f040 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p.h @@ -231,6 +231,7 @@ protected: void focusInEvent(QFocusEvent *event); public Q_SLOTS: + void deselect(); void selectAll(); void selectWord(); void select(int start, int end); diff --git a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp index a7971cc..c0bb46e 100644 --- a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -689,6 +689,13 @@ void tst_qdeclarativetextedit::selection() QVERIFY(textEditObject->selectedText().size() == 10); textEditObject->select(0,100); QVERIFY(textEditObject->selectedText().size() == 10); + + textEditObject->deselect(); + QVERIFY(textEditObject->selectedText().isNull()); + textEditObject->select(0,10); + QVERIFY(textEditObject->selectedText().size() == 10); + textEditObject->deselect(); + QVERIFY(textEditObject->selectedText().isNull()); } void tst_qdeclarativetextedit::mouseSelection_data() diff --git a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index 76e0102..589ffa6 100644 --- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -392,6 +392,13 @@ void tst_qdeclarativetextinput::selection() textinputObject->select(0,100); QVERIFY(textinputObject->selectedText().size() == 10); + textinputObject->deselect(); + QVERIFY(textinputObject->selectedText().isNull()); + textinputObject->select(0,10); + QVERIFY(textinputObject->selectedText().size() == 10); + textinputObject->deselect(); + QVERIFY(textinputObject->selectedText().isNull()); + delete textinputObject; } -- cgit v0.12 From e8b736c44426fd4ae832e82a9e624c9737a40213 Mon Sep 17 00:00:00 2001 From: Joona Petrell Date: Fri, 31 Dec 2010 11:28:08 +1000 Subject: Use deselect() function in text selection example Task-number: QTBUG-16059 Reviewed-by: Christopher Ham --- examples/declarative/text/textselection/textselection.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/declarative/text/textselection/textselection.qml b/examples/declarative/text/textselection/textselection.qml index f343be5..c6f44a0 100644 --- a/examples/declarative/text/textselection/textselection.qml +++ b/examples/declarative/text/textselection/textselection.qml @@ -265,7 +265,7 @@ Rectangle { anchors.fill: parent onClicked: { edit.cursorPosition = edit.selectionEnd; - edit.select(edit.cursorPosition, edit.cursorPosition); + edit.deselect(); editor.state = "" } } -- cgit v0.12 From 59ec08d255b7d7bd8975bdbfd0b0a42c1b6ed2a0 Mon Sep 17 00:00:00 2001 From: Joona Petrell Date: Fri, 31 Dec 2010 15:49:48 +1000 Subject: Provide qmlviewer warning window also on Symbian Task-number: QTBUG-10800 Reviewed-by: Christopher Ham --- tools/qml/loggerwidget.cpp | 9 +++++++++ tools/qml/main.cpp | 49 ++++++++++++++++++---------------------------- tools/qml/qmlruntime.cpp | 8 +++++++- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/tools/qml/loggerwidget.cpp b/tools/qml/loggerwidget.cpp index 8aa029f..f601d95 100644 --- a/tools/qml/loggerwidget.cpp +++ b/tools/qml/loggerwidget.cpp @@ -64,6 +64,14 @@ LoggerWidget::LoggerWidget(QWidget *parent) : m_plainTextEdit = new QPlainTextEdit(); +#if defined(Q_OS_SYMBIAN) + m_plainTextEdit->setReadOnly(true); + QAction* backAction = new QAction( tr("Back"), this ); + backAction->setSoftKeyRole( QAction::NegativeSoftKey ); + connect(backAction, SIGNAL(triggered()), this, SLOT(hide())); + addAction( backAction ); +#endif + #ifdef Q_WS_MAEMO_5 new TextEditAutoResizer(m_plainTextEdit); setAttribute(Qt::WA_Maemo5StackedWindow); @@ -74,6 +82,7 @@ LoggerWidget::LoggerWidget(QWidget *parent) : #else setCentralWidget(m_plainTextEdit); #endif + readSettings(); setupPreferencesMenu(); } diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index 2df96c0..b5a4fd0 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -72,36 +72,15 @@ void exitApp(int i) exit(i); } +QWeakPointer logger; +static QAtomicInt recursiveLock(0); + #if defined (Q_OS_SYMBIAN) #include #include #include #include - -void myMessageOutput(QtMsgType type, const char *msg) -{ - static int fd = -1; - if (fd == -1) - fd = ::open("E:\\qml.log", O_WRONLY | O_CREAT); - - ::write(fd, msg, strlen(msg)); - ::write(fd, "\n", 1); - ::fsync(fd); - - if (systemMsgOutput) - systemMsgOutput(type, msg); - - switch (type) { - case QtFatalMsg: - abort(); - } -} - -#else // !defined (Q_OS_SYMBIAN) - -QWeakPointer logger; - -static QAtomicInt recursiveLock(0); +#endif void myMessageOutput(QtMsgType type, const char *msg) { @@ -118,7 +97,21 @@ void myMessageOutput(QtMsgType type, const char *msg) warnings += QLatin1Char('\n'); } } - if (systemMsgOutput) { // Windows +#if defined (Q_OS_SYMBIAN) + static int fd = -1; + if (fd == -1) + fd = ::open("E:\\qml.log", O_WRONLY | O_CREAT); + + ::write(fd, msg, strlen(msg)); + ::write(fd, "\n", 1); + ::fsync(fd); + switch (type) { + case QtFatalMsg: + abort(); + } +#endif + + if (systemMsgOutput) { systemMsgOutput(type, msg); } else { // Unix fprintf(stderr, "%s\n", msg); @@ -126,8 +119,6 @@ void myMessageOutput(QtMsgType type, const char *msg) } } -#endif - static QDeclarativeViewer* globalViewer = 0; // The qml file that is shown if the user didn't specify a QML file @@ -472,7 +463,6 @@ static QDeclarativeViewer *createViewer() viewer->setScript(opts.script); } -#if !defined(Q_OS_SYMBIAN) logger = viewer->warningsWidget(); if (opts.warningsConfig == ShowWarnings) { logger.data()->setDefaultVisibility(LoggerWidget::ShowWarnings); @@ -480,7 +470,6 @@ static QDeclarativeViewer *createViewer() } else if (opts.warningsConfig == HideWarnings){ logger.data()->setDefaultVisibility(LoggerWidget::HideWarnings); } -#endif if (opts.experimentalGestures) viewer->enableExperimentalGestures(); diff --git a/tools/qml/qmlruntime.cpp b/tools/qml/qmlruntime.cpp index 142e4c5..b829528 100644 --- a/tools/qml/qmlruntime.cpp +++ b/tools/qml/qmlruntime.cpp @@ -742,8 +742,10 @@ void QDeclarativeViewer::createMenu() connect(slowAction, SIGNAL(triggered(bool)), this, SLOT(setSlowMode(bool))); showWarningsWindow = new QAction(tr("Show Warnings"), this); +#if !defined(Q_OS_SYMBIAN) showWarningsWindow->setCheckable((true)); showWarningsWindow->setChecked(loggerWindow->isVisible()); +#endif connect(showWarningsWindow, SIGNAL(triggered(bool)), this, SLOT(showWarnings(bool))); QAction *proxyAction = new QAction(tr("HTTP &Proxy..."), this); @@ -826,11 +828,11 @@ void QDeclarativeViewer::createMenu() QMenu *recordMenu = menu->addMenu(tr("&Recording")); recordMenu->addAction(snapshotAction); recordMenu->addAction(recordAction); +#endif // ! Q_OS_SYMBIAN QMenu *debugMenu = menu->addMenu(tr("&Debugging")); debugMenu->addAction(slowAction); debugMenu->addAction(showWarningsWindow); -#endif // ! Q_OS_SYMBIAN QMenu *settingsMenu = menu->addMenu(tr("&Settings")); settingsMenu->addAction(proxyAction); @@ -914,7 +916,11 @@ void QDeclarativeViewer::toggleFullScreen() void QDeclarativeViewer::showWarnings(bool show) { +#if defined(Q_OS_SYMBIAN) + loggerWindow->showMaximized(); +#else loggerWindow->setVisible(show); +#endif } void QDeclarativeViewer::warningsWidgetOpened() -- cgit v0.12 From 086f33dd4c70be03adcbc1703997afa27add920b Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 4 Jan 2011 15:03:53 +1000 Subject: Fix results of number() queries for zero and non-number values Use xs:string() to test whether a value is empty, instead of using a simple boolean check which fails for zero-type values. This fix also means 'NaN' is returned for non-number (including empty) values. Task-number: QTBUG-16423, QTBUG-16265 Reviewed-by: Michael Brasser --- src/declarative/util/qdeclarativexmllistmodel.cpp | 2 +- .../qdeclarativexmllistmodel/data/model2.qml | 11 ---- .../tst_qdeclarativexmllistmodel.cpp | 76 ++++++++++++++++++---- 3 files changed, 64 insertions(+), 25 deletions(-) delete mode 100644 tests/auto/declarative/qdeclarativexmllistmodel/data/model2.qml diff --git a/src/declarative/util/qdeclarativexmllistmodel.cpp b/src/declarative/util/qdeclarativexmllistmodel.cpp index 49a12b1..f5c3ad4 100644 --- a/src/declarative/util/qdeclarativexmllistmodel.cpp +++ b/src/declarative/util/qdeclarativexmllistmodel.cpp @@ -382,7 +382,7 @@ void QDeclarativeXmlQuery::doSubQueryJob() for (int i = 0; i < queries.size(); ++i) { QList resultList; if (!queries[i].isEmpty()) { - subquery.setQuery(m_prefix + QLatin1String("(let $v := ") + queries[i] + QLatin1String(" return if ($v) then ") + queries[i] + QLatin1String(" else \"\")")); + subquery.setQuery(m_prefix + QLatin1String("(let $v := string(") + queries[i] + QLatin1String(") return if ($v) then ") + queries[i] + QLatin1String(" else \"\")")); if (subquery.isValid()) { QXmlResultItems resultItems; subquery.evaluateTo(&resultItems); diff --git a/tests/auto/declarative/qdeclarativexmllistmodel/data/model2.qml b/tests/auto/declarative/qdeclarativexmllistmodel/data/model2.qml deleted file mode 100644 index e56aafa..0000000 --- a/tests/auto/declarative/qdeclarativexmllistmodel/data/model2.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 1.0 - -XmlListModel { - source: "model.xml" - query: "/Pets/Pet" - XmlRole { name: "name"; query: "name/string()" } - XmlRole { name: "type"; query: "type/string()" } - XmlRole { name: "age"; query: "age/number()" } - XmlRole { name: "size"; query: "size/string()" } - XmlRole { name: "tricks"; query: "tricks/string()" } -} diff --git a/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp b/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp index a14f942..3e81c53 100644 --- a/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp +++ b/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp @@ -38,6 +38,12 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include + +#include +#include +#include + #include #include #include @@ -75,7 +81,8 @@ private slots: } void buildModel(); - void missingFields(); + void testTypes(); + void testTypes_data(); void cdata(); void attributes(); void roles(); @@ -158,27 +165,70 @@ void tst_qdeclarativexmllistmodel::buildModel() delete model; } -void tst_qdeclarativexmllistmodel::missingFields() +void tst_qdeclarativexmllistmodel::testTypes() { - QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/model2.qml")); + QFETCH(QString, xml); + QFETCH(QString, roleName); + QFETCH(QVariant, expectedValue); + + QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/testtypes.qml")); QDeclarativeXmlListModel *model = qobject_cast(component.create()); QVERIFY(model != 0); - QTRY_COMPARE(model->count(), 9); + model->setXml(xml.toUtf8()); + model->reload(); + QTRY_COMPARE(model->count(), 1); - QList roles; - roles << Qt::UserRole << Qt::UserRole + 1 << Qt::UserRole + 2 << Qt::UserRole + 3 << Qt::UserRole + 4; - QHash data = model->data(5, roles); - QVERIFY(data.count() == 5); - QCOMPARE(data.value(Qt::UserRole+3).toString(), QLatin1String("")); - QCOMPARE(data.value(Qt::UserRole+4).toString(), QLatin1String("")); + int role = -1; + foreach (int i, model->roles()) { + if (model->toString(i) == roleName) { + role = i; + break; + } + } + QVERIFY(role >= 0); - data = model->data(7, roles); - QVERIFY(data.count() == 5); - QCOMPARE(data.value(Qt::UserRole+2).toString(), QLatin1String("")); + if (expectedValue.toString() == "nan") + QVERIFY(qIsNaN(model->data(0, role).toDouble())); + else + QCOMPARE(model->data(0, role), expectedValue); delete model; } +void tst_qdeclarativexmllistmodel::testTypes_data() +{ + QTest::addColumn("xml"); + QTest::addColumn("roleName"); + QTest::addColumn("expectedValue"); + + QTest::newRow("missing string field") << "" + << "stringValue" << QVariant(""); + QTest::newRow("empty string") << "" + << "stringValue" << QVariant(""); + QTest::newRow("1-char string") << "5" + << "stringValue" << QVariant("5"); + QTest::newRow("string ok") << "abc def g" + << "stringValue" << QVariant("abc def g"); + + QTest::newRow("missing number field") << "" + << "numberValue" << QVariant(""); + double nan = qQNaN(); + QTest::newRow("empty number field") << "" + << "numberValue" << QVariant(nan); + QTest::newRow("number field with string") << "a string" + << "numberValue" << QVariant(nan); + QTest::newRow("-1") << "-1" + << "numberValue" << QVariant("-1"); + QTest::newRow("-1.5") << "-1.5" + << "numberValue" << QVariant("-1.5"); + QTest::newRow("0") << "0" + << "numberValue" << QVariant("0"); + QTest::newRow("+1") << "1" + << "numberValue" << QVariant("1"); + QTest::newRow("+1.5") << "1.5" + << "numberValue" << QVariant("1.5"); +} + void tst_qdeclarativexmllistmodel::cdata() { QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/recipes.qml")); -- cgit v0.12 From 31460847fed4bc0867c3fd78466fed32e407fafb Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 4 Jan 2011 14:21:26 +1000 Subject: Fix translation in Connections element. Provide the component's file name to the expression as the translation context. Task-number: QTBUG-10300 Reviewed-by: Martin Jones --- src/declarative/util/qdeclarativeconnections.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/declarative/util/qdeclarativeconnections.cpp b/src/declarative/util/qdeclarativeconnections.cpp index 15e5ac5..e102f2c 100644 --- a/src/declarative/util/qdeclarativeconnections.cpp +++ b/src/declarative/util/qdeclarativeconnections.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -257,7 +258,11 @@ void QDeclarativeConnections::connectSignals() if (prop.isValid() && (prop.type() & QDeclarativeProperty::SignalProperty)) { QDeclarativeBoundSignal *signal = new QDeclarativeBoundSignal(target(), prop.method(), this); - signal->setExpression(new QDeclarativeExpression(qmlContext(this), 0, script)); + QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(this), 0, script); + QDeclarativeData *ddata = QDeclarativeData::get(this); + if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) + expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber); + signal->setExpression(expression); d->boundsignals += signal; } else { if (!d->ignoreUnknownSignals) -- cgit v0.12 From 7a979f8dab64c33a7088b70ca5bff69b881ee55d Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 5 Jan 2011 10:40:47 +1000 Subject: Add clarifications to QML SQL docs. Reviewed-by: Bea Lam --- doc/src/declarative/globalobject.qdoc | 7 ++++--- src/declarative/qml/qdeclarativesqldatabase.cpp | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/src/declarative/globalobject.qdoc b/doc/src/declarative/globalobject.qdoc index ffc84f9..ef8de5e 100644 --- a/doc/src/declarative/globalobject.qdoc +++ b/doc/src/declarative/globalobject.qdoc @@ -141,8 +141,9 @@ using the Offline Storage API. \section3 db = openDatabaseSync(identifier, version, description, estimated_size, callback(db)) Returns the database identified by \e identifier. If the database does not already exist, it -is created with the properties \e description and \e estimated_size and the function \e callback -is called with the database as a parameter. +is created, and the function \e callback is called with the database as a parameter. \e description +and \e estimated_size are written to the INI file (described below), but are otherwise currently +unused. May throw exception with code property SQLException.DATABASE_ERR, or SQLException.VERSION_ERR. @@ -153,7 +154,7 @@ When a database is first created, an INI file is also created specifying its cha \row \o Name \o The name of the database passed to \c openDatabase() \row \o Version \o The version of the database passed to \c openDatabase() \row \o Description \o The description of the database passed to \c openDatabase() -\row \o EstimatedSize \o The estimated size of the database passed to \c openDatabase() +\row \o EstimatedSize \o The estimated size (in bytes) of the database passed to \c openDatabase() \row \o Driver \o Currently "QSQLITE" \endtable diff --git a/src/declarative/qml/qdeclarativesqldatabase.cpp b/src/declarative/qml/qdeclarativesqldatabase.cpp index bda02a5..a774c02 100644 --- a/src/declarative/qml/qdeclarativesqldatabase.cpp +++ b/src/declarative/qml/qdeclarativesqldatabase.cpp @@ -351,7 +351,7 @@ static QScriptValue qmlsqldatabase_read_transaction(QScriptContext *context, QSc } /* - Currently documented in doc/src/declarastive/globalobject.qdoc + Currently documented in doc/src/declarative/globalobject.qdoc */ static QScriptValue qmlsqldatabase_open_sync(QScriptContext *context, QScriptEngine *engine) { -- cgit v0.12 From 3f80a24c5d375dd173d18c2a4227301f1afba2e3 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 6 Dec 2010 14:23:47 +1000 Subject: Allow a revision to be associated with properties and methods. Allows a revision to be associated with properties via: Q_PROPERTY(int prop READ prop1 REVISION 1) Allows a revision to be associated with methods via either: public slots Q_REVISION(1): void method1(); or: public slots: Q_REVISION void method1(); Private revision() methods are added to QMetaProperty and QMetaMethod to access the revision info. This is private API for use by QML for now. Task-number: QTBUG-13451 Reviewed-by: Kent Hansen --- src/corelib/kernel/qmetaobject.cpp | 48 +++++++++++++ src/corelib/kernel/qmetaobject.h | 3 + src/corelib/kernel/qmetaobject_p.h | 6 +- src/corelib/kernel/qobjectdefs.h | 2 + src/tools/moc/generator.cpp | 36 +++++++++- src/tools/moc/generator.h | 1 + src/tools/moc/keywords.cpp | 20 ++++-- src/tools/moc/moc.cpp | 82 ++++++++++++++++++++-- src/tools/moc/moc.h | 13 +++- src/tools/moc/token.cpp | 1 + src/tools/moc/token.h | 1 + src/tools/moc/util/generate_keywords.cpp | 1 + tests/auto/moc/tst_moc.cpp | 113 +++++++++++++++++++++++++++++++ 13 files changed, 311 insertions(+), 16 deletions(-) diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 9854e68..dd5f231 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -1369,6 +1369,25 @@ int QMetaMethod::methodIndex() const } /*! + \internal + + Returns the method revision if one was + specified by Q_REVISION, otherwise returns 0. + */ +int QMetaMethod::revision() const +{ + if (!mobj) + return 0; + if ((QMetaMethod::Access)(mobj->d.data[handle + 4] & MethodRevisioned)) { + int offset = priv(mobj->d.data)->methodData + + priv(mobj->d.data)->methodCount * 5 + + (handle - priv(mobj->d.data)->methodData) / 5; + return mobj->d.data[offset]; + } + return 0; +} + +/*! Returns the access specification of this method (private, protected, or public). @@ -2389,6 +2408,35 @@ int QMetaProperty::notifySignalIndex() const } /*! + \internal + + Returns the property revision if one was + specified by REVISION, otherwise returns 0. + */ +int QMetaProperty::revision() const +{ + if (!mobj) + return 0; + int flags = mobj->d.data[handle + 2]; + if (flags & Revisioned) { + int offset = priv(mobj->d.data)->propertyData + + priv(mobj->d.data)->propertyCount * 3 + idx; + // Revision data is placed after NOTIFY data, if present. + // Iterate through properties to discover whether we have NOTIFY signals. + for (int i = 0; i < priv(mobj->d.data)->propertyCount; ++i) { + int handle = priv(mobj->d.data)->propertyData + 3*i; + if (mobj->d.data[handle + 2] & Notify) { + offset += priv(mobj->d.data)->propertyCount; + break; + } + } + return mobj->d.data[offset]; + } else { + return 0; + } +} + +/*! Returns true if this property is writable; otherwise returns false. diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h index b700351..1ab08ee 100644 --- a/src/corelib/kernel/qmetaobject.h +++ b/src/corelib/kernel/qmetaobject.h @@ -70,6 +70,7 @@ public: enum Attributes { Compatibility = 0x1, Cloned = 0x2, Scriptable = 0x4 }; int attributes() const; int methodIndex() const; + int revision() const; inline const QMetaObject *enclosingMetaObject() const { return mobj; } @@ -200,6 +201,8 @@ public: QMetaMethod notifySignal() const; int notifySignalIndex() const; + int revision() const; + QVariant read(const QObject *obj) const; bool write(QObject *obj, const QVariant &value) const; bool reset(QObject *obj) const; diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index 4a03874..7b103e2 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -78,7 +78,8 @@ enum PropertyFlags { ResolveEditable = 0x00080000, User = 0x00100000, ResolveUser = 0x00200000, - Notify = 0x00400000 + Notify = 0x00400000, + Revisioned = 0x00800000 }; enum MethodFlags { @@ -95,7 +96,8 @@ enum MethodFlags { MethodCompatibility = 0x10, MethodCloned = 0x20, - MethodScriptable = 0x40 + MethodScriptable = 0x40, + MethodRevisioned = 0x80 }; enum MetaObjectFlags { diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index 555a1f5..d1a8f06 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -79,6 +79,7 @@ class QString; #define Q_INTERFACES(x) #define Q_PROPERTY(text) #define Q_PRIVATE_PROPERTY(d, text) +#define Q_REVISION(v) #define Q_OVERRIDE(text) #define Q_ENUMS(x) #define Q_FLAGS(x) @@ -180,6 +181,7 @@ private: #define Q_INTERFACES(x) Q_INTERFACES(x) #define Q_PROPERTY(text) Q_PROPERTY(text) #define Q_PRIVATE_PROPERTY(d, text) Q_PRIVATE_PROPERTY(d, text) +#define Q_REVISION(v) Q_REVISION(v) #define Q_OVERRIDE(text) Q_OVERRIDE(text) #define Q_ENUMS(x) Q_ENUMS(x) #define Q_FLAGS(x) Q_FLAGS(x) diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index c3bbba1..ea5b474 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -181,10 +181,14 @@ void Generator::generateCode() int methodCount = cdef->signalList.count() + cdef->slotList.count() + cdef->methodList.count(); fprintf(out, " %4d, %4d, // methods\n", methodCount, methodCount ? index : 0); index += methodCount * 5; + if (cdef->revisionedMethods) + index += methodCount; fprintf(out, " %4d, %4d, // properties\n", cdef->propertyList.count(), cdef->propertyList.count() ? index : 0); index += cdef->propertyList.count() * 3; if(cdef->notifyableProperties) index += cdef->propertyList.count(); + if (cdef->revisionedProperties) + index += cdef->propertyList.count(); fprintf(out, " %4d, %4d, // enums/sets\n", cdef->enumList.count(), cdef->enumList.count() ? index : 0); int enumsIndex = index; @@ -217,6 +221,14 @@ void Generator::generateCode() // generateFunctions(cdef->methodList, "method", MethodMethod); +// +// Build method version arrays +// + if (cdef->revisionedMethods) { + generateFunctionRevisions(cdef->signalList, "signal"); + generateFunctionRevisions(cdef->slotList, "slot"); + generateFunctionRevisions(cdef->methodList, "method"); + } // // Build property array @@ -456,7 +468,7 @@ void Generator::generateFunctions(QList& list, const char *functype } sig += ')'; - char flags = type; + unsigned char flags = type; if (f.access == FunctionDef::Private) flags |= AccessPrivate; else if (f.access == FunctionDef::Public) @@ -475,11 +487,23 @@ void Generator::generateFunctions(QList& list, const char *functype flags |= MethodCloned; if (f.isScriptable) flags |= MethodScriptable; + if (f.revision > 0) + flags |= MethodRevisioned; fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n", strreg(sig), strreg(arguments), strreg(f.normalizedType), strreg(f.tag), flags); } } +void Generator::generateFunctionRevisions(QList& list, const char *functype) +{ + if (list.count()) + fprintf(out, "\n // %ss: revision\n", functype); + for (int i = 0; i < list.count(); ++i) { + const FunctionDef &f = list.at(i); + fprintf(out, " %4d,\n", f.revision); + } +} + void Generator::generateProperties() { // @@ -537,6 +561,9 @@ void Generator::generateProperties() if (p.notifyId != -1) flags |= Notify; + if (p.revision > 0) + flags |= Revisioned; + if (p.constant) flags |= Constant; if (p.final) @@ -562,6 +589,13 @@ void Generator::generateProperties() p.notifyId); } } + if (cdef->revisionedProperties) { + fprintf(out, "\n // properties: revision\n"); + for (int i = 0; i < cdef->propertyList.count(); ++i) { + const PropertyDef &p = cdef->propertyList.at(i); + fprintf(out, " %4d,\n", p.revision); + } + } } void Generator::generateEnums(int index) diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h index fb6ad747..72b2b17 100644 --- a/src/tools/moc/generator.h +++ b/src/tools/moc/generator.h @@ -58,6 +58,7 @@ public: private: void generateClassInfos(); void generateFunctions(QList &list, const char *functype, int type); + void generateFunctionRevisions(QList& list, const char *functype); void generateEnums(int index); void generateProperties(); void generateMetacall(); diff --git a/src/tools/moc/keywords.cpp b/src/tools/moc/keywords.cpp index df1ba0d..7b84fd7 100644 --- a/src/tools/moc/keywords.cpp +++ b/src/tools/moc/keywords.cpp @@ -43,12 +43,12 @@ // DO NOT EDIT. static const short keyword_trans[][128] = { - {0,0,0,0,0,0,0,0,0,533,530,0,0,0,0,0, + {0,0,0,0,0,0,0,0,0,541,538,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 533,252,531,534,0,38,239,532,25,26,236,234,30,235,27,237, + 541,252,539,542,0,38,239,540,25,26,236,234,30,235,27,237, 22,22,22,22,22,22,22,22,22,22,34,41,23,39,24,43, 0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,21,8,8,8,8,8,8,8,8,8,31,535,32,238,8, + 8,21,8,8,8,8,8,8,8,8,8,31,543,32,238,8, 0,1,2,3,4,5,6,7,8,9,8,8,10,11,12,13, 14,8,15,16,17,18,19,20,8,8,8,36,245,37,248,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -190,7 +190,7 @@ static const short keyword_trans[][128] = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,42,0,0,0,28,0, - 538,538,538,538,538,538,538,538,538,538,0,0,0,0,0,0, + 546,546,546,546,546,546,546,546,546,546,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -349,7 +349,7 @@ static const short keyword_trans[][128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,537,0,0,0,0,536, + 0,0,0,0,0,0,0,0,0,0,545,0,0,0,0,544, 0,0,0,0,0,0,0,0,0,0,0,0,0,258,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -392,7 +392,7 @@ static const short keyword_trans[][128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,439,388,378,383,364,0,448,0,0,0,0,0,358, - 370,0,0,436,0,0,0,0,0,0,0,0,0,0,0,0, + 370,0,530,436,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -983,6 +983,14 @@ static const struct {CHARACTER, 0, 84, 528, CHARACTER}, {CHARACTER, 0, 89, 529, CHARACTER}, {Q_PRIVATE_PROPERTY_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 69, 531, CHARACTER}, + {CHARACTER, 0, 86, 532, CHARACTER}, + {CHARACTER, 0, 73, 533, CHARACTER}, + {CHARACTER, 0, 83, 534, CHARACTER}, + {CHARACTER, 0, 73, 535, CHARACTER}, + {CHARACTER, 0, 79, 536, CHARACTER}, + {CHARACTER, 0, 78, 537, CHARACTER}, + {Q_REVISION_TOKEN, 0, 0, 0, CHARACTER}, {NEWLINE, 0, 0, 0, NOTOKEN}, {QUOTE, 0, 0, 0, NOTOKEN}, {SINGLEQUOTE, 0, 0, 0, NOTOKEN}, diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 2c24165..b8b823c 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -335,6 +335,23 @@ bool Moc::testFunctionAttribute(Token tok, FunctionDef *def) return false; } +bool Moc::testFunctionRevision(FunctionDef *def) +{ + if (test(Q_REVISION_TOKEN)) { + next(LPAREN); + QByteArray revision = lexemUntil(RPAREN); + revision.remove(0, 1); + revision.chop(1); + bool ok = false; + def->revision = revision.toInt(&ok); + if (!ok || def->revision < 0) + error("Invalid revision"); + return true; + } + + return false; +} + // returns false if the function should be ignored bool Moc::parseFunction(FunctionDef *def, bool inMacro) { @@ -342,7 +359,7 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro) //skip modifiers and attributes while (test(INLINE) || test(STATIC) || (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual - || testFunctionAttribute(def)) {} + || testFunctionAttribute(def) || testFunctionRevision(def)) {} bool templateFunction = (lookup() == TEMPLATE); def->type = parseType(); if (def->type.name.isEmpty()) { @@ -433,7 +450,7 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def) //skip modifiers and attributes while (test(EXPLICIT) || test(INLINE) || test(STATIC) || (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual - || testFunctionAttribute(def)) {} + || testFunctionAttribute(def) || testFunctionRevision(def)) {} bool tilde = test(TILDE); def->type = parseType(); if (def->type.name.isEmpty()) @@ -694,6 +711,8 @@ void Moc::parse() funcDef.arguments.removeLast(); def.slotList += funcDef; } + if (funcDef.revision > 0) + ++def.revisionedMethods; } else if (funcDef.isSignal) { def.signalList += funcDef; while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) { @@ -701,6 +720,8 @@ void Moc::parse() funcDef.arguments.removeLast(); def.signalList += funcDef; } + if (funcDef.revision > 0) + ++def.revisionedMethods; } else if (funcDef.isInvokable) { def.methodList += funcDef; while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) { @@ -708,6 +729,8 @@ void Moc::parse() funcDef.arguments.removeLast(); def.methodList += funcDef; } + if (funcDef.revision > 0) + ++def.revisionedMethods; } } } else { @@ -806,6 +829,18 @@ QList Moc::generate(bool ignoreProperties) void Moc::parseSlots(ClassDef *def, FunctionDef::Access access) { + int defaultRevision = -1; + if (test(Q_REVISION_TOKEN)) { + next(LPAREN); + QByteArray revision = lexemUntil(RPAREN); + revision.remove(0, 1); + revision.chop(1); + bool ok = false; + defaultRevision = revision.toInt(&ok); + if (!ok || defaultRevision < 0) + error("Invalid revision"); + } + next(COLON); while (inClass(def) && hasNext()) { switch (next()) { @@ -831,6 +866,12 @@ void Moc::parseSlots(ClassDef *def, FunctionDef::Access access) funcDef.access = access; if (!parseFunction(&funcDef)) continue; + if (funcDef.revision > 0) { + ++def->revisionedMethods; + } else if (defaultRevision != -1) { + funcDef.revision = defaultRevision; + ++def->revisionedMethods; + } def->slotList += funcDef; while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) { funcDef.wasCloned = true; @@ -842,6 +883,18 @@ void Moc::parseSlots(ClassDef *def, FunctionDef::Access access) void Moc::parseSignals(ClassDef *def) { + int defaultRevision = -1; + if (test(Q_REVISION_TOKEN)) { + next(LPAREN); + QByteArray revision = lexemUntil(RPAREN); + revision.remove(0, 1); + revision.chop(1); + bool ok = false; + defaultRevision = revision.toInt(&ok); + if (!ok || defaultRevision < 0) + error("Invalid revision"); + } + next(COLON); while (inClass(def) && hasNext()) { switch (next()) { @@ -869,6 +922,12 @@ void Moc::parseSignals(ClassDef *def) warning("Signals cannot be declared virtual"); if (funcDef.inlineCode) error("Not a signal declaration"); + if (funcDef.revision > 0) { + ++def->revisionedMethods; + } else if (defaultRevision != -1) { + funcDef.revision = defaultRevision; + ++def->revisionedMethods; + } def->signalList += funcDef; while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) { funcDef.wasCloned = true; @@ -911,7 +970,6 @@ void Moc::createPropertyDef(PropertyDef &propDef) propDef.name = lexem(); while (test(IDENTIFIER)) { QByteArray l = lexem(); - if (l[0] == 'C' && l == "CONSTANT") { propDef.constant = true; continue; @@ -923,6 +981,10 @@ void Moc::createPropertyDef(PropertyDef &propDef) QByteArray v, v2; if (test(LPAREN)) { v = lexemUntil(RPAREN); + } else if (test(INTEGER_LITERAL)) { + v = lexem(); + if (l != "REVISION") + error(1); } else { next(IDENTIFIER); v = lexem(); @@ -937,7 +999,12 @@ void Moc::createPropertyDef(PropertyDef &propDef) propDef.read = v; else if (l == "RESET") propDef.reset = v + v2; - else + else if (l == "REVISION") { + bool ok = false; + propDef.revision = v.toInt(&ok); + if (!ok || propDef.revision < 0) + error(1); + } else error(2); break; case 'S': @@ -1002,6 +1069,8 @@ void Moc::parseProperty(ClassDef *def) if(!propDef.notify.isEmpty()) def->notifyableProperties++; + if (propDef.revision > 0) + ++def->revisionedProperties; def->propertyList += propDef; } @@ -1028,6 +1097,8 @@ void Moc::parsePrivateProperty(ClassDef *def) if(!propDef.notify.isEmpty()) def->notifyableProperties++; + if (propDef.revision > 0) + ++def->revisionedProperties; def->propertyList += propDef; } @@ -1177,6 +1248,9 @@ void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access) funcDef.arguments.removeLast(); def->slotList += funcDef; } + if (funcDef.revision > 0) + ++def->revisionedMethods; + } QByteArray Moc::lexemUntil(Token target) diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index 5e47d9a..c07ec0b 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -86,7 +86,7 @@ struct FunctionDef FunctionDef(): returnTypeIsVolatile(false), access(Private), isConst(false), isVirtual(false), inlineCode(false), wasCloned(false), isCompat(false), isInvokable(false), isScriptable(false), isSlot(false), isSignal(false), - isConstructor(false), isDestructor(false), isAbstract(false) {} + isConstructor(false), isDestructor(false), isAbstract(false), revision(0) {} Type type; QByteArray normalizedType; QByteArray tag; @@ -111,11 +111,13 @@ struct FunctionDef bool isConstructor; bool isDestructor; bool isAbstract; + + int revision; }; struct PropertyDef { - PropertyDef():notifyId(-1), constant(false), final(false), gspec(ValueSpec){} + PropertyDef():notifyId(-1), constant(false), final(false), gspec(ValueSpec), revision(0){} QByteArray name, type, read, write, reset, designable, scriptable, editable, stored, user, notify, inPrivateClass; int notifyId; bool constant; @@ -128,6 +130,7 @@ struct PropertyDef s += name.mid(1); return (s == write); } + int revision; }; @@ -139,7 +142,8 @@ struct ClassInfoDef struct ClassDef { ClassDef(): - hasQObject(false), hasQGadget(false), notifyableProperties(0), begin(0), end(0){} + hasQObject(false), hasQGadget(false), notifyableProperties(0) + , revisionedMethods(0), revisionedProperties(0), begin(0), end(0){} QByteArray classname; QByteArray qualified; QList > superclassList; @@ -164,6 +168,8 @@ struct ClassDef { QMap enumDeclarations; QList enumList; QMap flagAliases; + int revisionedMethods; + int revisionedProperties; int begin; int end; @@ -236,6 +242,7 @@ public: // in FunctionDef accordingly bool testFunctionAttribute(FunctionDef *def); bool testFunctionAttribute(Token tok, FunctionDef *def); + bool testFunctionRevision(FunctionDef *def); void checkSuperClasses(ClassDef *def); void checkProperties(ClassDef* cdef); diff --git a/src/tools/moc/token.cpp b/src/tools/moc/token.cpp index 3da9446..27d5146 100644 --- a/src/tools/moc/token.cpp +++ b/src/tools/moc/token.cpp @@ -180,6 +180,7 @@ const char *tokenTypeName(Token t) case Q_SLOT_TOKEN: return "Q_SLOT_TOKEN"; case Q_PRIVATE_SLOT_TOKEN: return "Q_PRIVATE_SLOT_TOKEN"; case Q_PRIVATE_PROPERTY_TOKEN: return "Q_PRIVATE_PROPERTY_TOKEN"; + case Q_REVISION_TOKEN: return "Q_REVISION_TOKEN"; case SPECIAL_TREATMENT_MARK: return "SPECIAL_TREATMENT_MARK"; case MOC_INCLUDE_BEGIN: return "MOC_INCLUDE_BEGIN"; case MOC_INCLUDE_END: return "MOC_INCLUDE_END"; diff --git a/src/tools/moc/token.h b/src/tools/moc/token.h index 6ca3d84..8b72eb6 100644 --- a/src/tools/moc/token.h +++ b/src/tools/moc/token.h @@ -186,6 +186,7 @@ enum Token { Q_INVOKABLE_TOKEN, Q_SCRIPTABLE_TOKEN, Q_PRIVATE_PROPERTY_TOKEN, + Q_REVISION_TOKEN, Q_META_TOKEN_END, SPECIAL_TREATMENT_MARK = Q_META_TOKEN_END, MOC_INCLUDE_BEGIN, diff --git a/src/tools/moc/util/generate_keywords.cpp b/src/tools/moc/util/generate_keywords.cpp index 88f187d..e9463e1 100644 --- a/src/tools/moc/util/generate_keywords.cpp +++ b/src/tools/moc/util/generate_keywords.cpp @@ -249,6 +249,7 @@ static const Keyword keywords[] = { { "Q_SLOT", "Q_SLOT_TOKEN" }, { "Q_SCRIPTABLE", "Q_SCRIPTABLE_TOKEN" }, { "Q_PRIVATE_PROPERTY", "Q_PRIVATE_PROPERTY_TOKEN" }, + { "Q_REVISION", "Q_REVISION_TOKEN" }, { "\n", "NEWLINE" }, { "\"", "QUOTE" }, { "\'", "SINGLEQUOTE" }, diff --git a/tests/auto/moc/tst_moc.cpp b/tests/auto/moc/tst_moc.cpp index bb23f49..a634349 100644 --- a/tests/auto/moc/tst_moc.cpp +++ b/tests/auto/moc/tst_moc.cpp @@ -493,6 +493,7 @@ private slots: void QTBUG5590_dummyProperty(); void QTBUG12260_defaultTemplate(); void notifyError(); + void revisions(); signals: void sigWithUnsignedArg(unsigned foo); void sigWithSignedArg(signed foo); @@ -507,6 +508,7 @@ private: bool user2() { return false; }; bool user3() { return false; }; bool userFunction(){ return false; }; + template void revisions_T(); private: QString qtIncludePath; @@ -1384,6 +1386,117 @@ void tst_Moc::notifyError() #endif } +// If changed, update VersionTestNotify below +class VersionTest : public QObject +{ + Q_OBJECT + Q_PROPERTY(int prop1 READ foo) + Q_PROPERTY(int prop2 READ foo REVISION 2) + Q_ENUMS(TestEnum); + +public: + int foo() const { return 0; } + + Q_INVOKABLE void method1() {} + Q_INVOKABLE Q_REVISION(4) void method2() {} + + enum TestEnum { One, Two }; + +public slots: + void slot1() {} + Q_REVISION(3) void slot2() {} + +signals: + void signal1(); + Q_REVISION(5) void signal2(); + +public slots Q_REVISION(6): + void slot3() {} + void slot4() {} + +signals Q_REVISION(7): + void signal3(); + void signal4(); +}; + +// If changed, update VersionTest above +class VersionTestNotify : public QObject +{ + Q_OBJECT + Q_PROPERTY(int prop1 READ foo NOTIFY fooChanged) + Q_PROPERTY(int prop2 READ foo REVISION 2) + Q_ENUMS(TestEnum); + +public: + int foo() const { return 0; } + + Q_INVOKABLE void method1() {} + Q_INVOKABLE Q_REVISION(4) void method2() {} + + enum TestEnum { One, Two }; + +public slots: + void slot1() {} + Q_REVISION(3) void slot2() {} + +signals: + void fooChanged(); + void signal1(); + Q_REVISION(5) void signal2(); + +public slots Q_REVISION(6): + void slot3() {} + void slot4() {} + +signals Q_REVISION(7): + void signal3(); + void signal4(); +}; + +template +void tst_Moc::revisions_T() +{ + int idx = T::staticMetaObject.indexOfProperty("prop1"); + QVERIFY(T::staticMetaObject.property(idx).revision() == 0); + idx = T::staticMetaObject.indexOfProperty("prop2"); + QVERIFY(T::staticMetaObject.property(idx).revision() == 2); + + idx = T::staticMetaObject.indexOfMethod("method1()"); + QVERIFY(T::staticMetaObject.method(idx).revision() == 0); + idx = T::staticMetaObject.indexOfMethod("method2()"); + QVERIFY(T::staticMetaObject.method(idx).revision() == 4); + + idx = T::staticMetaObject.indexOfSlot("slot1()"); + QVERIFY(T::staticMetaObject.method(idx).revision() == 0); + idx = T::staticMetaObject.indexOfSlot("slot2()"); + QVERIFY(T::staticMetaObject.method(idx).revision() == 3); + + idx = T::staticMetaObject.indexOfSlot("slot3()"); + QVERIFY(T::staticMetaObject.method(idx).revision() == 6); + idx = T::staticMetaObject.indexOfSlot("slot4()"); + QVERIFY(T::staticMetaObject.method(idx).revision() == 6); + + idx = T::staticMetaObject.indexOfSignal("signal1()"); + QVERIFY(T::staticMetaObject.method(idx).revision() == 0); + idx = T::staticMetaObject.indexOfSignal("signal2()"); + QVERIFY(T::staticMetaObject.method(idx).revision() == 5); + + idx = T::staticMetaObject.indexOfSignal("signal3()"); + QVERIFY(T::staticMetaObject.method(idx).revision() == 7); + idx = T::staticMetaObject.indexOfSignal("signal4()"); + QVERIFY(T::staticMetaObject.method(idx).revision() == 7); + + idx = T::staticMetaObject.indexOfEnumerator("TestEnum"); + QCOMPARE(T::staticMetaObject.enumerator(idx).keyCount(), 2); + QCOMPARE(T::staticMetaObject.enumerator(idx).key(0), "One"); +} + +// test using both class that has properties with and without NOTIFY signals +void tst_Moc::revisions() +{ + revisions_T(); + revisions_T(); +} QTEST_APPLESS_MAIN(tst_Moc) #include "tst_moc.moc" -- cgit v0.12 From ffd499eb6ff64df1833625f64dbbf92e0e0746d4 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 5 Jan 2011 13:57:17 +1000 Subject: Support property/method versions in QML Use metaobject revisioning to exclude properties/revisions added in later versions from interfering with earlier versions. Task-number: QTBUG-13451 Reviewed-by: Aaron Kennedy --- src/declarative/qml/qdeclarative.h | 77 +++++++++- .../qml/qdeclarativecompiledbindings.cpp | 4 + src/declarative/qml/qdeclarativecompiler.cpp | 17 ++- src/declarative/qml/qdeclarativedata_p.h | 5 +- src/declarative/qml/qdeclarativeinstruction_p.h | 1 + src/declarative/qml/qdeclarativemetatype.cpp | 83 ++++++++++- src/declarative/qml/qdeclarativemetatype_p.h | 5 + .../qml/qdeclarativeobjectscriptclass.cpp | 14 ++ src/declarative/qml/qdeclarativeprivate.h | 1 + src/declarative/qml/qdeclarativepropertycache.cpp | 3 +- src/declarative/qml/qdeclarativepropertycache_p.h | 4 +- src/declarative/qml/qdeclarativescriptparser.cpp | 1 - src/declarative/qml/qdeclarativevaluetype.cpp | 1 + src/declarative/qml/qdeclarativevme.cpp | 4 + src/declarative/qml/qmetaobjectbuilder.cpp | 33 +---- src/declarative/qml/qmetaobjectbuilder_p.h | 2 - .../util/qdeclarativeopenmetaobject.cpp | 1 - .../data/metaobjectRevision.qml | 7 + .../data/metaobjectRevision2.qml | 9 ++ .../data/metaobjectRevision3.qml | 8 + .../data/metaobjectRevisionErrors.qml | 14 ++ .../data/metaobjectRevisionErrors2.qml | 24 +++ .../data/metaobjectRevisionErrors3.qml | 36 +++++ .../qdeclarativeecmascript/testtypes.cpp | 9 ++ .../declarative/qdeclarativeecmascript/testtypes.h | 161 ++++++++++++++++++++ .../tst_qdeclarativeecmascript.cpp | 82 +++++++++++ .../data/metaobjectRevision.1.errors.txt | 1 + .../data/metaobjectRevision.1.qml | 8 + .../data/metaobjectRevision.2.errors.txt | 1 + .../data/metaobjectRevision.2.qml | 7 + .../data/metaobjectRevision.3.errors.txt | 1 + .../data/metaobjectRevision.3.qml | 10 ++ .../qdeclarativelanguage/data/revisions10.qml | 8 + .../qdeclarativelanguage/data/revisions11.qml | 10 ++ .../data/revisionsbasesub11.qml | 16 ++ .../qdeclarativelanguage/data/revisionssub10.qml | 10 ++ .../qdeclarativelanguage/data/revisionssub11.qml | 12 ++ .../declarative/qdeclarativelanguage/testtypes.cpp | 9 ++ .../declarative/qdeclarativelanguage/testtypes.h | 163 +++++++++++++++++++++ .../tst_qdeclarativelanguage.cpp | 62 ++++++++ .../qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp | 12 +- 41 files changed, 883 insertions(+), 53 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/metaobjectRevision.qml create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/metaobjectRevision2.qml create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/metaobjectRevision3.qml create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/metaobjectRevisionErrors.qml create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/metaobjectRevisionErrors2.qml create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/metaobjectRevisionErrors3.qml create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/metaobjectRevision.1.errors.txt create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/metaobjectRevision.1.qml create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/metaobjectRevision.2.errors.txt create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/metaobjectRevision.2.qml create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/metaobjectRevision.3.errors.txt create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/metaobjectRevision.3.qml create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/revisions10.qml create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/revisions11.qml create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/revisionsbasesub11.qml create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/revisionssub10.qml create mode 100644 tests/auto/declarative/qdeclarativelanguage/data/revisionssub11.qml diff --git a/src/declarative/qml/qdeclarative.h b/src/declarative/qml/qdeclarative.h index f0c62f4..8a6d068 100644 --- a/src/declarative/qml/qdeclarative.h +++ b/src/declarative/qml/qdeclarative.h @@ -113,6 +113,7 @@ int qmlRegisterType() 0, 0, + 0, 0 }; @@ -148,6 +149,7 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin 0, 0, + 0, 0 }; @@ -181,12 +183,82 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c 0, 0, + 0, 0 }; return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); } +template +int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QDeclarativeListProperty<" + name + ">"); + + QDeclarativePrivate::RegisterType type = { + 1, + + qRegisterMetaType(pointerName.constData()), + qRegisterMetaType >(listName.constData()), + sizeof(T), QDeclarativePrivate::createInto, + QString(), + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + QDeclarativePrivate::attachedPropertiesFunc(), + QDeclarativePrivate::attachedPropertiesMetaObject(), + + QDeclarativePrivate::StaticCastSelector::cast(), + QDeclarativePrivate::StaticCastSelector::cast(), + QDeclarativePrivate::StaticCastSelector::cast(), + + 0, 0, + + 0, + metaObjectRevision + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); +} + +template +int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor) +{ + QByteArray name(T::staticMetaObject.className()); + + QByteArray pointerName(name + '*'); + QByteArray listName("QDeclarativeListProperty<" + name + ">"); + + QDeclarativePrivate::RegisterType type = { + 1, + + qRegisterMetaType(pointerName.constData()), + qRegisterMetaType >(listName.constData()), + sizeof(T), QDeclarativePrivate::createInto, + QString(), + + uri, versionMajor, versionMinor, 0, &T::staticMetaObject, + + QDeclarativePrivate::attachedPropertiesFunc(), + QDeclarativePrivate::attachedPropertiesMetaObject(), + + QDeclarativePrivate::StaticCastSelector::cast(), + QDeclarativePrivate::StaticCastSelector::cast(), + QDeclarativePrivate::StaticCastSelector::cast(), + + 0, 0, + + 0, + metaObjectRevision + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); +} + + template int qmlRegisterExtendedType() { @@ -214,6 +286,7 @@ int qmlRegisterExtendedType() QDeclarativePrivate::createParent, &E::staticMetaObject, + 0, 0 }; @@ -255,6 +328,7 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, QDeclarativePrivate::createParent, &E::staticMetaObject, + 0, 0 }; @@ -309,7 +383,8 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, 0, 0, - parser + parser, + 0 }; return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); diff --git a/src/declarative/qml/qdeclarativecompiledbindings.cpp b/src/declarative/qml/qdeclarativecompiledbindings.cpp index 48f8b84..619016b 100644 --- a/src/declarative/qml/qdeclarativecompiledbindings.cpp +++ b/src/declarative/qml/qdeclarativecompiledbindings.cpp @@ -2527,6 +2527,10 @@ bool QDeclarativeBindingCompilerPrivate::fetch(Result &rv, const QMetaObject *mo rv.metaObject = 0; rv.type = 0; + //XXX binding optimizer doesn't handle properties with a revision + if (prop.revision() > 0) + return false; + int fastFetchIndex = fastProperties()->accessorIndexForProperty(mo, idx); Instr fetch; diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index b2b0990..0c56165 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -902,6 +902,7 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj) create.line = obj->location.start.line; create.createSimple.create = output->types.at(obj->type).type->createFunction(); create.createSimple.typeSize = output->types.at(obj->type).type->createSize(); + create.createSimple.type = obj->type; create.createSimple.column = obj->location.start.column; output->bytecode << create; @@ -1351,7 +1352,8 @@ bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDecl if(name[0] >= 'A' && name[0] <= 'Z') name[0] = name[0] - 'A' + 'a'; - int sigIdx = QDeclarativePropertyPrivate::findSignalByName(obj->metaObject(), name).methodIndex(); + QMetaMethod method = QDeclarativePropertyPrivate::findSignalByName(obj->metaObject(), name); + int sigIdx = method.methodIndex(); if (sigIdx == -1) { @@ -1364,6 +1366,13 @@ bool QDeclarativeCompiler::buildSignal(QDeclarativeParser::Property *prop, QDecl if (prop->value || prop->values.count() != 1) COMPILE_EXCEPTION(prop, tr("Incorrectly specified signal assignment")); + if (method.revision() > 0) { + QDeclarativeType *type = output->types.at(obj->type).type; + if (!type->isMethodAvailable(sigIdx, method.revision())) { + COMPILE_EXCEPTION(prop, tr("Signal \"%1\" not available in %2 %3.%4").arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type->qmlTypeName())).arg(obj->majorVersion).arg(obj->minorVersion)); + } + } + prop->index = sigIdx; obj->addSignalProperty(prop); @@ -1481,6 +1490,12 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop, // successful index resolution if (p.name()) { prop->type = p.userType(); + if (p.revision() > 0) { + QDeclarativeType *type = output->types.at(obj->type).type; + if (!type->isPropertyAvailable(prop->index, p.revision())) { + COMPILE_EXCEPTION(prop, tr("Property \"%1\" not available in %2 %3.%4").arg(QString::fromUtf8(prop->name)).arg(QString::fromUtf8(type->qmlTypeName())).arg(obj->majorVersion).arg(obj->minorVersion)); + } + } } // Check if this is an alias diff --git a/src/declarative/qml/qdeclarativedata_p.h b/src/declarative/qml/qdeclarativedata_p.h index 4767169..81f279c 100644 --- a/src/declarative/qml/qdeclarativedata_p.h +++ b/src/declarative/qml/qdeclarativedata_p.h @@ -66,6 +66,7 @@ class QDeclarativePropertyCache; class QDeclarativeContextData; class QDeclarativeNotifier; class QDeclarativeDataExtended; +class QDeclarativeType; // This class is structured in such a way, that simply zero'ing it is the // default state for elemental object allocations. This is crucial in the // workings of the QDeclarativeInstruction::CreateSimpleObject instruction. @@ -77,7 +78,7 @@ public: : ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), context(0), outerContext(0), bindings(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0), lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0), - scriptValue(0), objectDataRefCount(0), propertyCache(0), guards(0), extendedData(0) { + scriptValue(0), objectDataRefCount(0), propertyCache(0), guards(0), type(0), extendedData(0) { init(); } @@ -136,6 +137,8 @@ public: QDeclarativeGuard *guards; + const QDeclarativeType *type; + static QDeclarativeData *get(const QObject *object, bool create = false) { QObjectPrivate *priv = QObjectPrivate::get(const_cast(object)); if (priv->wasDeleted) { diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h index 94676fc..4030bab 100644 --- a/src/declarative/qml/qdeclarativeinstruction_p.h +++ b/src/declarative/qml/qdeclarativeinstruction_p.h @@ -182,6 +182,7 @@ public: struct CreateSimpleInstruction { void (*create)(void *); int typeSize; + int type; ushort column; }; struct StoreMetaInstruction { diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp index 7a78a1f..1f387c4 100644 --- a/src/declarative/qml/qdeclarativemetatype.cpp +++ b/src/declarative/qml/qdeclarativemetatype.cpp @@ -134,10 +134,13 @@ public: bool m_isInterface : 1; const char *m_iid; + QByteArray m_module; QByteArray m_name; int m_version_maj; int m_version_min; int m_typeId; int m_listId; + int m_revision; + mutable QDeclarativeType *m_superType; int m_allocationSize; void (*m_newFunc)(void *); @@ -155,6 +158,7 @@ public: int m_index; QDeclarativeCustomParser *m_customParser; mutable volatile bool m_isSetup:1; + mutable bool m_haveSuperType : 1; mutable QList m_metaObjects; static QHash m_attachedPropertyIds; @@ -163,10 +167,10 @@ public: QHash QDeclarativeTypePrivate::m_attachedPropertyIds; QDeclarativeTypePrivate::QDeclarativeTypePrivate() -: m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), +: m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_revision(0), m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1), m_propertyValueInterceptorCast(-1), - m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0), m_isSetup(false) + m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0), m_isSetup(false), m_haveSuperType(false) { } @@ -192,9 +196,11 @@ QDeclarativeType::QDeclarativeType(int index, const QDeclarativePrivate::Registe if (type.uri) name += '/'; name += type.elementName; + d->m_module = type.uri; d->m_name = name; d->m_version_maj = type.versionMajor; d->m_version_min = type.versionMinor; + d->m_revision = type.revision; d->m_typeId = type.typeId; d->m_listId = type.listId; d->m_allocationSize = type.objectSize; @@ -243,6 +249,56 @@ bool QDeclarativeType::availableInVersion(int vmajor, int vminor) const return vmajor > d->m_version_maj || (vmajor == d->m_version_maj && vminor >= d->m_version_min); } +bool QDeclarativeType::availableInVersion(const QByteArray &module, int vmajor, int vminor) const +{ + return module == d->m_module && (vmajor > d->m_version_maj || (vmajor == d->m_version_maj && vminor >= d->m_version_min)); +} + +// returns the nearest _registered_ super class +QDeclarativeType *QDeclarativeType::superType() const +{ + if (!d->m_haveSuperType) { + const QMetaObject *mo = d->m_baseMetaObject->superClass(); + while (mo && !d->m_superType) { + d->m_superType = QDeclarativeMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min); + mo = mo->superClass(); + } + d->m_haveSuperType = true; + } + + return d->m_superType; +} + +bool QDeclarativeType::isPropertyAvailable(int index, int revision) const +{ + if (revision == 0) + return true; + + if (index < d->m_baseMetaObject->propertyOffset()) { + if (QDeclarativeType *super = superType()) + return super->isPropertyAvailable(index, revision); + } else if (index < d->m_baseMetaObject->propertyOffset() + d->m_baseMetaObject->propertyCount()) { + return d->m_revision >= revision; + } + + return false; +} + +bool QDeclarativeType::isMethodAvailable(int index, int revision) const +{ + if (revision == 0) + return true; + + if (index < d->m_baseMetaObject->methodOffset()) { + if (QDeclarativeType *super = superType()) + return super->isMethodAvailable(index, revision); + } else if (index < d->m_baseMetaObject->methodOffset() + d->m_baseMetaObject->methodCount()) { + return d->m_revision >= revision; + } + + return false; +} + static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd) { @@ -572,7 +628,7 @@ int registerType(const QDeclarativePrivate::RegisterType &type) if (!dtype->qmlTypeName().isEmpty()) data->nameToType.insertMulti(dtype->qmlTypeName(), dtype); - data->metaObjectToType.insert(dtype->baseMetaObject(), dtype); + data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype); if (data->objects.size() <= type.typeId) data->objects.resize(type.typeId + 16); @@ -862,6 +918,27 @@ QDeclarativeType *QDeclarativeMetaType::qmlType(const QMetaObject *metaObject) } /*! + Returns the type (if any) that corresponds to the \a metaObject in version specified + by \a version_major and \a version_minor in module specified by \a uri. Returns null if no + type is registered. +*/ +QDeclarativeType *QDeclarativeMetaType::qmlType(const QMetaObject *metaObject, const QByteArray &module, int version_major, int version_minor) +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + + QDeclarativeMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.find(metaObject); + while (it != data->metaObjectToType.end() && it.key() == metaObject) { + QDeclarativeType *t = *it; + if (version_major < 0 || t->availableInVersion(module, version_major,version_minor)) + return t; + ++it; + } + + return 0; +} + +/*! Returns the type (if any) that corresponds to the QVariant::Type \a userType. Returns null if no type is registered. */ diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h index 9c486d3..d9a3795 100644 --- a/src/declarative/qml/qdeclarativemetatype_p.h +++ b/src/declarative/qml/qdeclarativemetatype_p.h @@ -76,6 +76,7 @@ public: static QDeclarativeType *qmlType(const QByteArray &, int, int); static QDeclarativeType *qmlType(const QMetaObject *); + static QDeclarativeType *qmlType(const QMetaObject *metaObject, const QByteArray &module, int version_major, int version_minor); static QDeclarativeType *qmlType(int); static QMetaProperty defaultProperty(const QMetaObject *); @@ -115,6 +116,9 @@ public: int majorVersion() const; int minorVersion() const; bool availableInVersion(int vmajor, int vminor) const; + bool availableInVersion(const QByteArray &module, int vmajor, int vminor) const; + bool isPropertyAvailable(int index, int revision) const; + bool isMethodAvailable(int index, int revision) const; QObject *create() const; void create(QObject **, void **, size_t) const; @@ -149,6 +153,7 @@ public: int index() const; private: + QDeclarativeType *superType() const; friend class QDeclarativeTypePrivate; friend struct QDeclarativeMetaTypeData; friend int registerType(const QDeclarativePrivate::RegisterType &); diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index b0bc5bb..090eeda 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -166,6 +166,20 @@ QDeclarativeObjectScriptClass::queryProperty(QObject *obj, const Identifier &nam QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine); lastData = QDeclarativePropertyCache::property(engine, obj, name, local); + if (lastData && lastData->revision > 0 && (hints & ImplicitObject)) { + QDeclarativeData *data = QDeclarativeData::get(obj); + if (data) { + if (!data->type) { + lastData = 0; + } else if (lastData->flags & QDeclarativePropertyCache::Data::IsFunction) { + if (!data->type->isMethodAvailable(lastData->coreIndex, lastData->revision)) + lastData = 0; + } else if (!data->type->isPropertyAvailable(lastData->coreIndex, lastData->revision)) { + lastData = 0; + } + } + } + if (lastData) return QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess; diff --git a/src/declarative/qml/qdeclarativeprivate.h b/src/declarative/qml/qdeclarativeprivate.h index 388c92e..a4fc4c1 100644 --- a/src/declarative/qml/qdeclarativeprivate.h +++ b/src/declarative/qml/qdeclarativeprivate.h @@ -214,6 +214,7 @@ namespace QDeclarativePrivate const QMetaObject *extensionMetaObject; QDeclarativeCustomParser *customParser; + int revision; }; struct RegisterInterface { diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp index dd9a224..76c9eb9 100644 --- a/src/declarative/qml/qdeclarativepropertycache.cpp +++ b/src/declarative/qml/qdeclarativepropertycache.cpp @@ -88,6 +88,7 @@ void QDeclarativePropertyCache::Data::load(const QMetaProperty &p, QDeclarativeE coreIndex = p.propertyIndex(); notifyIndex = p.notifySignalIndex(); flags = flagsForProperty(p, engine); + revision = p.revision(); } void QDeclarativePropertyCache::Data::load(const QMetaMethod &m) @@ -106,6 +107,7 @@ void QDeclarativePropertyCache::Data::load(const QMetaMethod &m) QList params = m.parameterTypes(); if (!params.isEmpty()) flags |= Data::HasArguments; + revision = m.revision(); } @@ -235,7 +237,6 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb Data::Flag propertyFlags, Data::Flag methodFlags, Data::Flag signalFlags) { QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); - int methodCount = metaObject->methodCount(); // 3 to block the destroyed signal and the deleteLater() slot int methodOffset = qMax(3, metaObject->methodOffset()); diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h index f7c5daa..3f7f9ef 100644 --- a/src/declarative/qml/qdeclarativepropertycache_p.h +++ b/src/declarative/qml/qdeclarativepropertycache_p.h @@ -110,6 +110,7 @@ public: int notifyIndex; // When !IsFunction int relatedIndex; // When IsFunction }; + int revision; static Flags flagsForProperty(const QMetaProperty &, QDeclarativeEngine *engine = 0); void load(const QMetaProperty &, QDeclarativeEngine *engine = 0); @@ -176,7 +177,8 @@ bool QDeclarativePropertyCache::Data::operator==(const QDeclarativePropertyCache return flags == other.flags && propType == other.propType && coreIndex == other.coreIndex && - notifyIndex == other.notifyIndex; + notifyIndex == other.notifyIndex && + revision == other.revision; } QDeclarativePropertyCache::Data * diff --git a/src/declarative/qml/qdeclarativescriptparser.cpp b/src/declarative/qml/qdeclarativescriptparser.cpp index 57cc9ab..e32a3d2 100644 --- a/src/declarative/qml/qdeclarativescriptparser.cpp +++ b/src/declarative/qml/qdeclarativescriptparser.cpp @@ -307,7 +307,6 @@ ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName, obj->location = location; if (propertyCount) { - Property *prop = currentProperty(); Value *v = new Value; v->object = obj; diff --git a/src/declarative/qml/qdeclarativevaluetype.cpp b/src/declarative/qml/qdeclarativevaluetype.cpp index 5dc6ffd..bf02de8 100644 --- a/src/declarative/qml/qdeclarativevaluetype.cpp +++ b/src/declarative/qml/qdeclarativevaluetype.cpp @@ -71,6 +71,7 @@ int qmlRegisterValueTypeEnums(const char *uri, int versionMajor, int versionMino 0, 0, + 0, 0 }; diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index c742dec..6ee653b 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -194,6 +194,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack &stack, QDeclarativeData *ddata = QDeclarativeDa