diff options
author | Charles Yin <charles.yin@nokia.com> | 2011-11-14 10:35:51 +1000 |
---|---|---|
committer | Charles Yin <charles.yin@nokia.com> | 2011-11-14 10:35:51 +1000 |
commit | fc54db69809a16f613f65a2761fab55d5911b02c (patch) | |
tree | a00d9284eb13f81f5b195f8a4c6cfee03edb4f17 | |
parent | 35275892ca8a7046451b8e943985dd779fee4794 (diff) | |
parent | 2557ff5a940242b398dee65c3c79cec088164e32 (diff) | |
download | qtdeclarative-fc54db69809a16f613f65a2761fab55d5911b02c.tar.gz |
Merge branch 'master' into animation-refactor
Conflicts:
tools/qmlviewer/qdeclarativetester.cpp
tools/qmlviewer/qmlruntime.cpp
Change-Id: I48f0eb02df27e4b524f45927939b4c257452b0aa
448 files changed, 14917 insertions, 5344 deletions
diff --git a/doc/src/declarative/basictypes.qdoc b/doc/src/declarative/basictypes.qdoc index 1bc13739fa..5e4ce9aedd 100644 --- a/doc/src/declarative/basictypes.qdoc +++ b/doc/src/declarative/basictypes.qdoc @@ -449,21 +449,22 @@ } \endqml - It is important to note that properties of JavaScript objects cannot - be bound to: + It is important to note that changes in regular properties of JavaScript + objects assigned to a var property will \bold{not} trigger updates of bindings + that access them. The example below will display "The car has 4 wheels" as + the change to the wheels property will not cause the reevaluation of the + binding assigned to the "text" property: \qml Item { - property var car: new vehicle(4) - property int wheelCount: car.wheels + property var car: new Object({wheels: 4}) - function vehicle(wheels) { - this.wheels = wheels; - this.talk = function() { print("I have " + this.wheels + " wheels!"); } + Text { + text: "The car has " + car.wheels + " wheels"; } Component.onCompleted: { - car.wheels = 6; // wheelCount will _not_ be updated + car.wheels = 6; } } \endqml diff --git a/doc/src/declarative/extending.qdoc b/doc/src/declarative/extending.qdoc index 0563f65cc0..d26549ac96 100644 --- a/doc/src/declarative/extending.qdoc +++ b/doc/src/declarative/extending.qdoc @@ -116,6 +116,10 @@ Person { \l {Extending QML - Adding Types Example} shows the complete code used to create the \c Person type. +If you wish to provide functionality to clients without requiring them to +instantiate an element, consider providing a module API instead of registering +a type; see qmlRegisterModuleApi() for more information. + \section1 QML Type Versioning In C++ adding a new method or property cannot break old applications. @@ -236,6 +240,36 @@ The \c guest property declaration looks like this: \l {Extending QML - Object and List Property Types Example} shows the complete code used to create the \c BirthdayParty type. +\section1 Sequence Types + +Certain C++ sequence types are supported transparently in QML as JavaScript Array types. +In particular, QML currently supports: +\list + \o \c {QList<int>} + \o \c {QList<qreal>} + \o \c {QList<bool>} + \o \c {QList<QString>} + \o \c {QList<QUrl>} +\endlist + +These sequence types are implemented directly in terms of the underlying C++ sequence. +There are two ways in which such sequences can be exposed to QML: as a Q_PROPERTY of +the given sequence type; or as the return type of a Q_INVOKABLE method. There are some +differences in the way these are implemented, which are important to note. + +If the sequence is exposed as a Q_PROPERTY, accessing any value in the sequence by index +will cause the sequence data to be read from the QObject's property, then a read to occur. +Similarly, modifying any value in the sequence will cause the sequence data to be read, +and then the modification will be performed and the modified sequence will be written back +to the QObject's property. + +If the sequence is returned from a Q_INVOKABLE function, access and mutation is much cheaper, +as no QObject property read or write occurs; instead, the C++ sequence data is accessed and +modified directly. + +Other sequence types are not supported transparently, and instead an instance of any other +sequence type will be passed between QML and C++ as an opaque QVariantList. + \section1 Inheritance and Coercion \snippet examples/declarative/cppextensions/referenceexamples/coercion/example.qml 0 diff --git a/doc/src/declarative/globalobject.qdoc b/doc/src/declarative/globalobject.qdoc index f4e9d0df8f..ced797b14a 100644 --- a/doc/src/declarative/globalobject.qdoc +++ b/doc/src/declarative/globalobject.qdoc @@ -203,7 +203,7 @@ May throw exception with code property SQLException.DATABASE_ERR, SQLException.S \section1 Logging -\c console.log() and \c console.debug() can be used to print information +\c console.log(), \c console.debug(), \c console.time(), and \c console.timeEnd() can be used to print information to the console. See \l{Debugging QML} for more information. */ diff --git a/doc/src/declarative/particles.qdoc b/doc/src/declarative/particles.qdoc index 94b1c2b347..31adc91f6b 100644 --- a/doc/src/declarative/particles.qdoc +++ b/doc/src/declarative/particles.qdoc @@ -35,6 +35,8 @@ For a simple overview of how the system can be used, see \l{qml-particlesystem.html}{Using the Qt Quick Particle System}. + For details on the performance characteristics see \l{qml-particlesystem-performance.html}{Qt Quick Particle System Performance}. + */ /*! @@ -78,14 +80,14 @@ Emitters emit logical particles into the system. These particles have a trajectory and lifespan, but no visualization. These particles are emitted from the location of the Emitter. - FollowEmitters are a special type of emitter which emits particles from the location of other logicial particles. Any logical - particle of the followed type within the bounds of a FollowEmitter will cause particle emission from its location, as if there - were an Emitter on it with the same properties as the FollowEmitter. + TrailEmitters are a special type of emitter which emits particles from the location of other logicial particles. Any logical + particle of the followed type within the bounds of a TrailEmitter will cause particle emission from its location, as if there + were an Emitter on it with the same properties as the TrailEmitter. \section1 ParticlePainters Painters are the elements that visualize logical particles. For each logical particle in the groups assigned to it, which are within its bounds (or outside, if you do not set the clip property on the element) it will be visualized - in a manner dependant on the type of ParticlePainter. The base type of ParticlePainter does not draw anything. + in a manner dependent on the type of ParticlePainter. The base type of ParticlePainter does not draw anything. ImageParticle renders an image at the particle location. CustomParticle allows you to write your own shaders to render the particles, passing in the logical particle state as vertex data. ItemParticle allows you to visualize logical particles using arbitrary QML delegates. ModelParticle is similar, but coordinates model data amongst the delegates @@ -108,7 +110,7 @@ Directions can be specified by angle and magnitude, or by x and y components. While any direction can be specified with either method, there is a significant difference between varying the x and y components and varying the angle and magnitude. Varying the x and y components will lead to a rectangular area around the specified point, while varying the angle will lead - to an arc centered on the specfied point. + to an arc centered on the specified point. \section2 Shapes The particle system contains several elements which represent shapes. These elements do not visualize shapes, and are used @@ -116,3 +118,26 @@ and 0 height shape (which is the default). Otherwise you can use the shape elements provides to specify an area, so that the result can use a random point selected from that area. */ + +/*! + \page qml-particlesystem-performance.html + \title Qt Quick Particle System Performance Guide + + The performance of the particle system scales with the number of particles it is maintaining. After prototyping the desired + effect, performance can be improved by lowering the particle count. Conversely, if performance is well withing acceptable + bounds you can increase the number of particles until you hit that point (should that improve the effect). + + Note that particle count is often estimated by the particle system, and in some cases explicitly providing hints as to how + many particles will be needed will improve performance. You can do this by setting maximumEmitted on an Emitter, and it is + generally useful for Emitters which do not continuously emit particles. + + Like ShaderEffect, the performance of the particle system is largely dependent on the graphics hardware it is running on. + The exception to this is Affectors. For systems not including Affectors, the majority of the performance cost of particles + will be on the GPU. Since the GPU is better at parallelizing large numbers of operations more particles can be drawn at 60FPS + when Affectors are not used. + + Affectors, particularly if modifying the particles in javascript, can be relatively slow as well as increasing the CPU cost + of using particles. Avoid using them in high-volume systems where possible. Some easy cases where Affectors can be avoided + are using timed ParticleGroup transitions instead of time-triggered Affectors, or setting acceleration due to gravity in the + acceleration property of the Emitter instead of with a Gravity Affector. +*/ diff --git a/doc/src/declarative/qdeclarativedebugging.qdoc b/doc/src/declarative/qdeclarativedebugging.qdoc index 189d4449e5..a34c2faa62 100644 --- a/doc/src/declarative/qdeclarativedebugging.qdoc +++ b/doc/src/declarative/qdeclarativedebugging.qdoc @@ -43,6 +43,20 @@ Rectangle { } \endqml +\c console.time and console.timeEnd log the time (in milliseconds) that was spent between +the calls. Both take a string argument that identifies the measurement. For example: + +\qml +function f() { + console.time("wholeFunction"); + console.time("firstPart"); + // first part + console.timeEnd("firstPart"); + // second part + console.timeEnd("wholeFunction"); +} +\endqml + \section1 Debugging Transitions When a transition doesn't look quite right, it can be helpful to view it in slow diff --git a/doc/src/declarative/qtdeclarative.qdoc b/doc/src/declarative/qtdeclarative.qdoc index e83641d4c6..1570ed74ff 100644 --- a/doc/src/declarative/qtdeclarative.qdoc +++ b/doc/src/declarative/qtdeclarative.qdoc @@ -211,3 +211,127 @@ Returns the QML type id. */ + +/*! + \fn int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, QJSValue (*callback)(QDeclarativeEngine *, QJSEngine *)) + \relates QDeclarativeEngine + + This function may be used to register a module API provider \a callback in a particular \a uri + with a version specified in \a versionMajor and \a versionMinor. + + Installing a module API into a uri allows developers to provide arbitrary functionality + (methods and properties) in a namespace that doesn't necessarily contain elements. + + A module API may be either a QObject or a QJSValue. Only one module API provider + may be registered into any given namespace (combination of \a uri, \a versionMajor and \a versionMinor). + This function should be used to register a module API provider function which returns a QJSValue as a module API. + + \bold{NOTE:} QJSValue module API properties will \bold{not} trigger binding re-evaluation if changed. + + Usage: + \code + // first, define the module API provider function (callback). + static QJSValue *example_qjsvalue_module_api_provider(QDeclarativeEngine *engine, QJSEngine *scriptEngine) + { + Q_UNUSED(engine) + + static int seedValue = 5; + QJSValue example = scriptEngine->newObject(); + example.setProperty("someProperty", seedValue++); + return example; + } + + // second, register the module API provider with QML by calling this function in an initialization function. + ... + qmlRegisterModuleApi("Qt.example.qjsvalueApi", 1, 0, example_qjsvalue_module_api_provider); + ... + \endcode + + In order to use the registered module API in QML, you must import the module API. + \qml + import QtQuick 2.0 + import Qt.example.qjsvalueApi 1.0 as ExampleApi + Item { + id: root + property int someValue: ExampleApi.someProperty + } + \endqml + */ + +/*! + \fn int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, QObject *(*callback)(QDeclarativeEngine *, QJSEngine *)) + \relates QDeclarativeEngine + + This function may be used to register a module API provider \a callback in a particular \a uri + with a version specified in \a versionMajor and \a versionMinor. + + Installing a module API into a uri allows developers to provide arbitrary functionality + (methods and properties) in a namespace that doesn't necessarily contain elements. + + A module API may be either a QObject or a QJSValue. Only one module API provider + may be registered into any given namespace (combination of \a uri, \a versionMajor and \a versionMinor). + This function should be used to register a module API provider function which returns a QObject as a module API. + + A QObject module API must be imported with a qualifier, and that qualifier may be used as + the target in a \l Connections element or otherwise used as any other element id would. + One exception to this is that a QObject module API property may not be aliased (because the + module API qualifier does not identify an object within the same component as any other item). + + Usage: + \code + // first, define your QObject which provides the functionality. + class ModuleApiExample : public QObject + { + Q_OBJECT + Q_PROPERTY (int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged) + + public: + ModuleApiExample(QObject* parent = 0) + : QObject(parent), m_someProperty(0) + { + } + + ~ModuleApiExample() {} + + Q_INVOKABLE int doSomething() { setSomeProperty(5); return m_someProperty; } + + int someProperty() const { return m_someProperty; } + void setSomeProperty(int val) { m_someProperty = val; emit somePropertyChanged(val); } + + signals: + void somePropertyChanged(int newValue); + + private: + int m_someProperty; + }; + + // second, define the module API provider function (callback). + static QObject *example_qobject_module_api_provider(QDeclarativeEngine *engine, QJSEngine *scriptEngine) + { + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + ModuleApiExample *example = new ModuleApiExample(); + return example; + } + + // third, register the module API provider with QML by calling this function in an initialization function. + ... + qmlRegisterModuleApi("Qt.example.qobjectApi", 1, 0, example_qobject_module_api_provider); + ... + \endcode + + In order to use the registered module API in QML, you must import the module API. + \qml + import QtQuick 2.0 + import Qt.example.qobjectApi 1.0 as ExampleApi + Item { + id: root + property int someValue: ExampleApi.someProperty + + Component.onCompleted: { + someValue = ExampleApi.doSomething() + } + } + \endqml + */ diff --git a/doc/src/snippets/declarative/multipointtoucharea/multipointtoucharea.qml b/doc/src/snippets/declarative/multipointtoucharea/multipointtoucharea.qml new file mode 100644 index 0000000000..9530adb485 --- /dev/null +++ b/doc/src/snippets/declarative/multipointtoucharea/multipointtoucharea.qml @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation 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$ +** +****************************************************************************/ +//![0] +import QtQuick 2.0 + +Rectangle { + width: 400; height: 400 + MultiPointTouchArea { + anchors.fill: parent + touchPoints: [ + TouchPoint { id: point1 }, + TouchPoint { id: point2 } + ] + } + + Rectangle { + width: 30; height: 30 + color: "green" + x: point1.x + y: point1.y + } + + Rectangle { + width: 30; height: 30 + color: "yellow" + x: point2.x + y: point2.y + } +} +//![0] diff --git a/examples/declarative/cppextensions/imageprovider/imageprovider.pro b/examples/declarative/cppextensions/imageprovider/imageprovider.pro index eaa48cd901..cfa7923128 100644 --- a/examples/declarative/cppextensions/imageprovider/imageprovider.pro +++ b/examples/declarative/cppextensions/imageprovider/imageprovider.pro @@ -18,12 +18,3 @@ ImageProviderCore_sources.path = $$[QT_INSTALL_EXAMPLES]/qtdeclarative/declarati INSTALLS = sources ImageProviderCore_sources target -symbian:{ - CONFIG += qt_example - TARGET.EPOCALLOWDLLDATA = 1 - - importFiles.files = ImageProviderCore/qmlimageproviderplugin.dll ImageProviderCore/qmldir - importFiles.path = ImageProviderCore - DEPLOYMENT += importFiles -} -maemo5: CONFIG += qt_example diff --git a/examples/declarative/cppextensions/plugins/plugins.pro b/examples/declarative/cppextensions/plugins/plugins.pro index 03f7294131..bdcb62ca8a 100644 --- a/examples/declarative/cppextensions/plugins/plugins.pro +++ b/examples/declarative/cppextensions/plugins/plugins.pro @@ -23,8 +23,3 @@ target.path += $$[QT_INSTALL_EXAMPLES]/qtdeclarative/declarative/plugins/com/nok INSTALLS += qdeclarativesources sources target -symbian { - CONFIG += qt_example - TARGET.EPOCALLOWDLLDATA = 1 -} -maemo5: CONFIG += qt_example diff --git a/examples/declarative/declarative.pro b/examples/declarative/declarative.pro index d3683fe376..883c0afe2d 100644 --- a/examples/declarative/declarative.pro +++ b/examples/declarative/declarative.pro @@ -9,9 +9,6 @@ SUBDIRS = \ tutorials \ script -# plugins uses a 'Time' class that conflicts with symbian e32std.h also defining a class of the same name -symbian:SUBDIRS -= plugins - # These examples contain no C++ and can simply be copied sources.files = \ animation \ diff --git a/examples/declarative/painteditem/smile/main.cpp b/examples/declarative/painteditem/smile/main.cpp index 1f0b3a3cb8..dc76e71185 100644 --- a/examples/declarative/painteditem/smile/main.cpp +++ b/examples/declarative/painteditem/smile/main.cpp @@ -43,16 +43,24 @@ #include <QtDeclarative/qdeclarative.h> #include <QtDeclarative/qquickview.h> #include <QtDeclarative/qquickpainteditem.h> - class MyPaintItem : public QQuickPaintedItem { Q_OBJECT + Q_PROPERTY(QString face READ face WRITE setFace NOTIFY faceChanged) public: - MyPaintItem() : QQuickPaintedItem() + MyPaintItem() + : QQuickPaintedItem() + , m_face(QLatin1String(":-)")) { setAntialiasing(true); } - + QString face() const {return m_face;} + void setFace(const QString &face) { + if (m_face != face) { + m_face = face; + emit faceChanged(); + } + } virtual void paint(QPainter *p) { QRectF rect(0, 0, width(), height()); @@ -62,8 +70,12 @@ public: p->drawEllipse(rect); p->setPen(Qt::black); p->setFont(QFont(QLatin1String("Times"), qRound(rect.height() / 2))); - p->drawText(rect, Qt::AlignCenter, QLatin1String(":-)")); + p->drawText(rect, Qt::AlignCenter, m_face); } +signals: + void faceChanged(); +private: + QString m_face; }; int main(int argc, char ** argv) diff --git a/examples/declarative/painteditem/smile/smile.pro b/examples/declarative/painteditem/smile/smile.pro index 5d7b9df074..3b9e4e0f62 100644 --- a/examples/declarative/painteditem/smile/smile.pro +++ b/examples/declarative/painteditem/smile/smile.pro @@ -9,6 +9,3 @@ SOURCES += main.cpp CONFIG += console -symbian { - TARGET.EPOCHEAPSIZE = 0x20000 0x5000000 -} diff --git a/examples/declarative/painteditem/smile/smile.qml b/examples/declarative/painteditem/smile/smile.qml index bc4bd2664b..e09d9b1fa8 100644 --- a/examples/declarative/painteditem/smile/smile.qml +++ b/examples/declarative/painteditem/smile/smile.qml @@ -42,16 +42,91 @@ import QtQuick 2.0 import MyModule 1.0 Rectangle { - width: 480 - height: 480 + width: 500 + height: 500 gradient: Gradient { GradientStop { position: 0.0; color: "#00249a" } GradientStop { position: 0.7; color: "#ffd94f" } GradientStop { position: 1.0; color: "#ffa322" } } MyPaintItem { - anchors.fill: parent + renderTarget:PaintedItem.Image + clip:true + width:240 + height:240 + anchors.left : parent.left + anchors.top :parent.top anchors.margins: 10 smooth: true + MouseArea { + anchors.fill:parent + onClicked: { + if (parent.face == ":-)") + parent.face = ":-("; + else + parent.face = ":-)"; + parent.update() + } + } } -} + MyPaintItem { + clip:true + renderTarget:PaintedItem.Image + width:240 + height:240 + anchors.right : parent.right + anchors.top :parent.top + anchors.margins: 10 + smooth: true + MouseArea { + anchors.fill:parent + onClicked: { + if (parent.face == ":-)") + parent.face = ":-("; + else + parent.face = ":-)"; + parent.update() + } + } + } + MyPaintItem { + clip:true + renderTarget:PaintedItem.Image + width:240 + height:240 + anchors.left : parent.left + anchors.bottom :parent.bottom + anchors.margins: 10 + smooth: true + MouseArea { + anchors.fill:parent + onClicked: { + if (parent.face == ":-)") + parent.face = ":-("; + else + parent.face = ":-)"; + parent.update() + } + } + } + MyPaintItem { + clip:true + renderTarget:PaintedItem.Image + width:240 + height:240 + anchors.right : parent.right + anchors.bottom :parent.bottom + anchors.margins: 10 + smooth: true + MouseArea { + anchors.fill:parent + onClicked: { + if (parent.face == ":-)") + parent.face = ":-("; + else + parent.face = ":-)"; + parent.update() + } + } + } +}
\ No newline at end of file diff --git a/examples/declarative/particles/affectors/customaffector.qml b/examples/declarative/particles/affectors/customaffector.qml index f3c14e2bb3..0defa54a62 100644 --- a/examples/declarative/particles/affectors/customaffector.qml +++ b/examples/declarative/particles/affectors/customaffector.qml @@ -124,7 +124,7 @@ Item { particle.vx = 0; else particle.vx = (particle.vx / xslow); - particle.update = 1; + particle.update = true; } } } diff --git a/examples/declarative/particles/affectors/gravity.qml b/examples/declarative/particles/affectors/gravity.qml index dc55324f3a..7509b119b0 100644 --- a/examples/declarative/particles/affectors/gravity.qml +++ b/examples/declarative/particles/affectors/gravity.qml @@ -84,7 +84,7 @@ Item { ParticleSystem { id: sys } Gravity { system: sys - acceleration: 32 + magnitude: 32 angle: ground.rotation + 90 } Emitter { diff --git a/examples/declarative/particles/imageparticle/sprites.qml b/examples/declarative/particles/imageparticle/sprites.qml index dfc4447e45..aba6454072 100644 --- a/examples/declarative/particles/imageparticle/sprites.qml +++ b/examples/declarative/particles/imageparticle/sprites.qml @@ -57,7 +57,8 @@ Rectangle { width: 250 height: 250 x: 20 - y: 20 + anchors.bottom: parent.bottom + anchors.bottomMargin: 20 z:4 } diff --git a/examples/declarative/script/shell/shell.pro b/examples/declarative/script/shell/shell.pro index 7ddc06b3c4..00191ab3d0 100644 --- a/examples/declarative/script/shell/shell.pro +++ b/examples/declarative/script/shell/shell.pro @@ -2,7 +2,6 @@ QT += declarative win32: CONFIG += console mac:CONFIG -= app_bundle -symbian: CONFIG += qt_example SOURCES += main.cpp diff --git a/examples/declarative/text/styledtext-layout.qml b/examples/declarative/text/styledtext-layout.qml new file mode 100644 index 0000000000..9ef30ef1ca --- /dev/null +++ b/examples/declarative/text/styledtext-layout.qml @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + id: main + width: 1024; height: 1024 + focus: true + + property real offset: 0 + property real margin: 15 + + Keys.onLeftPressed: myText.horizontalAlignment = Text.AlignLeft + Keys.onUpPressed: myText.horizontalAlignment = Text.AlignHCenter + Keys.onRightPressed: myText.horizontalAlignment = Text.AlignRight + Keys.onDownPressed: myText.horizontalAlignment = Text.AlignJustify + + Text { + id: myText + anchors.fill: parent + anchors.margins: 20 + wrapMode: Text.WordWrap + font.family: "Times New Roman" + font.pixelSize: 18 + textFormat: Text.StyledText + horizontalAlignment: Text.AlignJustify + + text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at ante dui sed eu egestas est facilis <a href=\"www.nokia.com\">www.nokia.com</a>.<br/>Curabitur ante est, pulvinar quis adipiscing a, iaculis id ipsum. Phasellus id neque id velit facilisis cursus ac sit amet nibh. Donec enim arcu, pharetra non semper nec, iaculis eget elit. Nunc blandit condimentum odio vel egestas.<br><ul type=\"bullet\"><li>Coffee<ol type=\"a\"><li>Espresso<li><b>Cappuccino</b><li><i>Flat White</i><li>Latte</ol><li>Juice<ol type=\"1\"><li>Orange</li><li>Apple</li><li>Pineapple</li><li>Tomato</li></ol></li></ul><p><font color=\"#434343\"><i>Proin consectetur <b>sapien</b> in ipsum lacinia sit amet mattis orci interdum. Quisque vitae accumsan lectus. Ut nisi turpis, sollicitudin ut dignissim id, fermentum ac est. Maecenas nec libero leo. Sed ac leo eget ipsum ultricies viverra sit amet eu orci. Praesent et tortor risus, viverra accumsan sapien. Sed faucibus eleifend lectus, sed euismod urna porta eu. Aenean ultricies lectus ut orci dictum quis convallis nisi ultrices. Nunc elit mi, iaculis a porttitor rutrum, venenatis malesuada nisi. Suspendisse turpis quam, euismod non imperdiet et, rutrum nec ligula. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam semper tristique metus eu sodales. Integer eget risus ipsum. Quisque ut risus ut nulla tristique volutpat at sit amet nisl. Aliquam pulvinar auctor diam nec bibendum. Quisque luctus sapien id arcu volutpat pharetra. Praesent pretium imperdiet euismod. Integer fringilla rhoncus condimentum. Quisque sit amet ornare nulla. Cras sapien augue, sagittis a dictum id, suscipit et nunc. Cras vitae augue in enim elementum venenatis sed nec risus. Sed nisi quam, mollis quis auctor ac, vestibulum in neque. Vivamus eu justo risus. Suspendisse vel mollis est. Vestibulum gravida interdum mi, in molestie neque gravida in.</i></font><br><br> Donec nibh odio, mattis facilisis vulputate et, scelerisque ut felis. Sed ornare eros nec odio aliquam eu varius augue adipiscing. Vivamus sit amet massa dapibus sapien pulvinar consectetur a sit amet felis. Cras non mi id libero dictum iaculis id dignissim eros. Praesent eget enim dui, sed bibendum neque. Ut interdum nisl id leo malesuada ornare.<br><br>Pellentesque id nisl eu odio volutpat posuere et at massa. Pellentesque nec lorem justo. Integer sem urna, pharetra sed sagittis vitae, condimentum ac felis. Ut vitae sapien ac tortor adipiscing pharetra. Cras tristique urna tempus ante volutpat eleifend non eu ligula. Mauris sodales nisl et lorem tristique sodales. Mauris arcu orci, vehicula semper cursus ac, dapibus ut mi. Cras orci ligula, lacinia non laoreet non, feugiat eget lorem. Duis commodo urna nunc. Ut eu diam quis magna volutpat auctor. Duis non nibh non leo aliquet gravida. <font color=\"green\">Aenean diam velit, eleifend sed porta eu, malesuada sed erat.</font> In hac habitasse platea dictumst. Ut nulla ligula, tincidunt ac volutpat nec, accumsan at risus. Donec eget ipsum sit amet nulla tempus auctor ut non massa. Donec enim purus, consectetur viverra congue vitae, vehicula eu sapien. Ut aliquam iaculis metus, a bibendum nisi fringilla ut. Maecenas ut libero augue, vitae tristique diam. Vivamus nec rhoncus ipsum. Maecenas rutrum, libero sit amet ultrices cursus, elit massa laoreet odio, in luctus elit quam eu quam. Sed non diam urna. Maecenas fringilla feugiat malesuada. In tellus nibh, gravida vitae cursus mollis, tincidunt eu urna. Cras turpis lorem, dictum in feugiat id, gravida eu nulla. In ultricies nisl in sapien consectetur eu ultricies nisl facilisis. Nam id mauris a leo pretium facilisis eget quis est. Fusce fermentum quam in metus facilisis semper." + + + onLineLaidOut: { + line.width = width / 2 - (2 * margin) + if (line.number === 40) { + main.offset = line.y + } + if (line.number >= 40) { + line.x = width / 2 + margin + line.y -= main.offset + } + if ((line.y + line.height) > rect.y && line.y < (rect.y + rect.height)) { + if (line.number < 40) + line.width = Math.min((rect.x - line.x), line.width) + else { + line.x = Math.max((rect.x + rect.width), width / 2 + margin) + line.width = Math.min((width - margin - line.x), line.width) + } + } + } + + Item { + id: rect + x: 280; y: 200 + width: 300; height: 300 + + Rectangle { + anchors { fill: parent; leftMargin: 15; rightMargin: 15 } + color: "lightsteelblue"; opacity: 0.3 + } + + MouseArea { + anchors.fill: parent + drag.target: rect + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: mouse.button == Qt.RightButton ? myText.font.pixelSize -= 1 : myText.font.pixelSize += 1 + onPositionChanged: myText.doLayout() + } + } + } + +} diff --git a/examples/embedded/qmlcalculator/deployment.pri b/examples/embedded/qmlcalculator/deployment.pri index a97498e91f..a3627b8fa2 100644 --- a/examples/embedded/qmlcalculator/deployment.pri +++ b/examples/embedded/qmlcalculator/deployment.pri @@ -1,8 +1,4 @@ qmlcalculator_src = $$PWD/../../declarative/calculator -symbian { - load(data_caging_paths) - qmlcalculator_uid3 = A000E3FB - qmlcalculator_files.path = $$APP_PRIVATE_DIR_BASE/$$qmlcalculator_uid3 -} + qmlcalculator_files.files = $$qmlcalculator_src/calculator.qml $$qmlcalculator_src/Core DEPLOYMENT += qmlcalculator_files diff --git a/examples/embedded/qmlcalculator/qmlcalculator.cpp b/examples/embedded/qmlcalculator/qmlcalculator.cpp index bed579726c..94cb00f4a2 100644 --- a/examples/embedded/qmlcalculator/qmlcalculator.cpp +++ b/examples/embedded/qmlcalculator/qmlcalculator.cpp @@ -44,13 +44,6 @@ #include <QtDeclarative/QDeclarativeView> #include <QtDeclarative/QDeclarativeEngine> -#if defined(Q_OS_SYMBIAN) -#include <eikenv.h> -#include <eikappui.h> -#include <aknenv.h> -#include <aknappui.h> -#endif // Q_OS_SYMBIAN - int main(int argc, char *argv[]) { QApplication application(argc, argv); @@ -60,21 +53,11 @@ int main(int argc, char *argv[]) view.setSource(QUrl(mainQmlApp)); view.setResizeMode(QDeclarativeView::SizeRootObjectToView); QObject::connect(view.engine(), SIGNAL(quit()), &application, SLOT(quit())); - + #if defined(QT_KEYPAD_NAVIGATION) QApplication::setNavigationMode(Qt::NavigationModeCursorAuto); #endif // QT_KEYPAD_NAVIGATION -#if defined(Q_OS_SYMBIAN) - CAknAppUi* appUi = dynamic_cast<CAknAppUi*> (CEikonEnv::Static()->AppUi()); - TRAPD(error, - if (appUi) - appUi->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait) - ) - view.showFullScreen(); -#else // Q_OS_SYMBIAN view.show(); -#endif // Q_OS_SYMBIAN - return application.exec(); } diff --git a/examples/embedded/qmlcalculator/qmlcalculator.pro b/examples/embedded/qmlcalculator/qmlcalculator.pro index 72f45f56d1..25c16ca78a 100644 --- a/examples/embedded/qmlcalculator/qmlcalculator.pro +++ b/examples/embedded/qmlcalculator/qmlcalculator.pro @@ -1,12 +1,5 @@ -!symbian:!wince*:warning("DEPLOYMENT support required. This project only works on Symbian and WinCE.") +!wince*:warning("DEPLOYMENT support required. This project only works on WinCE.") QT += declarative SOURCES += $$PWD/qmlcalculator.cpp include($$PWD/deployment.pri) - -symbian { - TARGET.UID3 = 0x$$qmlcalculator_uid3 # defined in deployment.pri - CONFIG += qt_example - TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 - LIBS += -lcone -leikcore -lavkon # Screen orientation -} diff --git a/examples/embedded/qmlclocks/deployment.pri b/examples/embedded/qmlclocks/deployment.pri index 6c6704ccc7..771a4dba76 100644 --- a/examples/embedded/qmlclocks/deployment.pri +++ b/examples/embedded/qmlclocks/deployment.pri @@ -1,8 +1,4 @@ qmlclocks_src = $$PWD/../../../examples/declarative/toys/clocks -symbian { - load(data_caging_paths) - qmlclocks_uid3 = A000E3FC - qmlclocks_files.path = $$APP_PRIVATE_DIR_BASE/$$qmlclocks_uid3 -} + qmlclocks_files.files = $$qmlclocks_src/clocks.qml $$qmlclocks_src/content DEPLOYMENT += qmlclocks_files diff --git a/examples/embedded/qmlclocks/qmlclocks.cpp b/examples/embedded/qmlclocks/qmlclocks.cpp index 75d0be0874..04366aa0ab 100644 --- a/examples/embedded/qmlclocks/qmlclocks.cpp +++ b/examples/embedded/qmlclocks/qmlclocks.cpp @@ -44,13 +44,6 @@ #include <QtDeclarative/QDeclarativeView> #include <QtDeclarative/QDeclarativeEngine> -#if defined(Q_OS_SYMBIAN) -#include <eikenv.h> -#include <eikappui.h> -#include <aknenv.h> -#include <aknappui.h> -#endif // Q_OS_SYMBIAN - int main(int argc, char *argv[]) { QApplication application(argc, argv); @@ -65,16 +58,6 @@ int main(int argc, char *argv[]) QApplication::setNavigationMode(Qt::NavigationModeCursorAuto); #endif // QT_KEYPAD_NAVIGATION -#if defined(Q_OS_SYMBIAN) - CAknAppUi* appUi = dynamic_cast<CAknAppUi*> (CEikonEnv::Static()->AppUi()); - TRAPD(error, - if (appUi) - appUi->SetOrientationL(CAknAppUi::EAppUiOrientationLandscape) - ) - view.showFullScreen(); -#else // Q_OS_SYMBIAN view.show(); -#endif // Q_OS_SYMBIAN - return application.exec(); } diff --git a/examples/embedded/qmlclocks/qmlclocks.pro b/examples/embedded/qmlclocks/qmlclocks.pro index 1b6cdad6be..8e9dcdf87c 100644 --- a/examples/embedded/qmlclocks/qmlclocks.pro +++ b/examples/embedded/qmlclocks/qmlclocks.pro @@ -1,12 +1,5 @@ -!symbian:!wince*:warning("DEPLOYMENT support required. This project only works on Symbian and WinCE.") +!wince*:warning("DEPLOYMENT support required. This project only works on WinCE.") QT += declarative SOURCES += $$PWD/qmlclocks.cpp include($$PWD/deployment.pri) - -symbian { - TARGET.UID3 = 0x$$qmlclocks_uid3 # defined in deployment.pri - CONFIG += qt_example - TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 - LIBS += -lcone -leikcore -lavkon # Screen orientation -} diff --git a/examples/embedded/qmldialcontrol/deployment.pri b/examples/embedded/qmldialcontrol/deployment.pri index a9784439a4..d845120923 100644 --- a/examples/embedded/qmldialcontrol/deployment.pri +++ b/examples/embedded/qmldialcontrol/deployment.pri @@ -1,8 +1,4 @@ qmldialcontrol_src = $$PWD/../../../examples/declarative/ui-components/dialcontrol -symbian { - load(data_caging_paths) - qmldialcontrol_uid3 = A000E3FD - qmldialcontrol_files.path = $$APP_PRIVATE_DIR_BASE/$$qmldialcontrol_uid3 -} + qmldialcontrol_files.files = $$qmldialcontrol_src/dialcontrol.qml $$qmldialcontrol_src/content DEPLOYMENT += qmldialcontrol_files diff --git a/examples/embedded/qmldialcontrol/qmldialcontrol.cpp b/examples/embedded/qmldialcontrol/qmldialcontrol.cpp index 7cc4ed6668..6f9b0e574a 100644 --- a/examples/embedded/qmldialcontrol/qmldialcontrol.cpp +++ b/examples/embedded/qmldialcontrol/qmldialcontrol.cpp @@ -58,11 +58,6 @@ int main(int argc, char *argv[]) QApplication::setNavigationMode(Qt::NavigationModeCursorAuto); #endif // QT_KEYPAD_NAVIGATION -#if defined(Q_OS_SYMBIAN) - view.showFullScreen(); -#else // Q_OS_SYMBIAN view.show(); -#endif // Q_OS_SYMBIAN - return application.exec(); } diff --git a/examples/embedded/qmldialcontrol/qmldialcontrol.pro b/examples/embedded/qmldialcontrol/qmldialcontrol.pro index 3b2e88649e..08f876b926 100644 --- a/examples/embedded/qmldialcontrol/qmldialcontrol.pro +++ b/examples/embedded/qmldialcontrol/qmldialcontrol.pro @@ -1,11 +1,5 @@ -!symbian:!wince*:warning("DEPLOYMENT support required. This project only works on Symbian and WinCE.") +!wince*:warning("DEPLOYMENT support required. This project only works on WinCE.") QT += declarative SOURCES += $$PWD/qmldialcontrol.cpp include($$PWD/deployment.pri) - -symbian { - TARGET.UID3 = 0x$$qmldialcontrol_uid3 # defined in deployment.pri - CONFIG += qt_example - TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 -} diff --git a/examples/embedded/qmleasing/deployment.pri b/examples/embedded/qmleasing/deployment.pri index 946fcd9d89..7a5d0401cb 100644 --- a/examples/embedded/qmleasing/deployment.pri +++ b/examples/embedded/qmleasing/deployment.pri @@ -1,8 +1,4 @@ qmleasing_src = $$PWD/../../../examples/declarative/animation/easing -symbian { - load(data_caging_paths) - qmleasing_uid3 = A000E3FE - qmleasing_files.path = $$APP_PRIVATE_DIR_BASE/$$qmleasing_uid3 -} + qmleasing_files.files = $$qmleasing_src/easing.qml $$qmleasing_src/content DEPLOYMENT += qmleasing_files diff --git a/examples/embedded/qmleasing/qmleasing.cpp b/examples/embedded/qmleasing/qmleasing.cpp index 38c457d376..3e24546b4a 100644 --- a/examples/embedded/qmleasing/qmleasing.cpp +++ b/examples/embedded/qmleasing/qmleasing.cpp @@ -58,11 +58,6 @@ int main(int argc, char *argv[]) QApplication::setNavigationMode(Qt::NavigationModeCursorAuto); #endif // QT_KEYPAD_NAVIGATION -#if defined(Q_OS_SYMBIAN) - view.showFullScreen(); -#else // Q_OS_SYMBIAN view.show(); -#endif // Q_OS_SYMBIAN - return application.exec(); } diff --git a/examples/embedded/qmleasing/qmleasing.pro b/examples/embedded/qmleasing/qmleasing.pro index bf332aa07d..c9f008d42e 100644 --- a/examples/embedded/qmleasing/qmleasing.pro +++ b/examples/embedded/qmleasing/qmleasing.pro @@ -1,11 +1,5 @@ -!symbian:!wince*:warning("DEPLOYMENT support required. This project only works on Symbian and WinCE.") +!wince*:warning("DEPLOYMENT support required. This project only works on WinCE.") QT += declarative SOURCES += $$PWD/qmleasing.cpp include($$PWD/deployment.pri) - -symbian { - TARGET.UID3 = 0x$$qmleasing_uid3 # defined in deployment.pri - CONFIG += qt_example - TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 -} diff --git a/examples/embedded/qmlflickr/deployment.pri b/examples/embedded/qmlflickr/deployment.pri index a38dc95f8c..0d76ddc1db 100644 --- a/examples/embedded/qmlflickr/deployment.pri +++ b/examples/embedded/qmlflickr/deployment.pri @@ -1,8 +1,4 @@ qmlflickr_src = $$PWD/../../declarative/flickr -symbian { - load(data_caging_paths) - qmlflickr_uid3 = A000E3FF - qmlflickr_files.path = $$APP_PRIVATE_DIR_BASE/$$qmlflickr_uid3 -} + qmlflickr_files.files = $$qmlflickr_src/flickr.qml $$qmlflickr_src/common $$qmlflickr_src/mobile DEPLOYMENT += qmlflickr_files diff --git a/examples/embedded/qmlflickr/qmlflickr.cpp b/examples/embedded/qmlflickr/qmlflickr.cpp index 052d11c48a..dc7b5ee397 100644 --- a/examples/embedded/qmlflickr/qmlflickr.cpp +++ b/examples/embedded/qmlflickr/qmlflickr.cpp @@ -97,13 +97,8 @@ int main(int argc, char *argv[]) view.setSource(QUrl(mainQmlApp)); view.setResizeMode(QDeclarativeView::SizeRootObjectToView); QObject::connect(view.engine(), SIGNAL(quit()), &application, SLOT(quit())); - -#if defined(Q_OS_SYMBIAN) - view.showFullScreen(); -#else // Q_OS_SYMBIAN view.setGeometry(QRect(100, 100, 360, 640)); view.show(); -#endif // Q_OS_SYMBIAN return application.exec(); } diff --git a/examples/embedded/qmlflickr/qmlflickr.pro b/examples/embedded/qmlflickr/qmlflickr.pro index 60abe31333..869d651b05 100644 --- a/examples/embedded/qmlflickr/qmlflickr.pro +++ b/examples/embedded/qmlflickr/qmlflickr.pro @@ -1,13 +1,5 @@ -!symbian:!wince*:warning("DEPLOYMENT support required. This project only works on Symbian and WinCE.") +!wince*:warning("DEPLOYMENT support required. This project only works on WinCE.") QT += declarative network SOURCES += $$PWD/qmlflickr.cpp include($$PWD/deployment.pri) - -symbian { - TARGET.UID3 = 0x$$qmlflickr_uid3 # defined in deployment.pri - CONFIG += qt_example - TARGET.CAPABILITY = NetworkServices - # Maximum heap size set to 128 MB in order to allow loading large images. - TARGET.EPOCHEAPSIZE = 0x20000 0x8000000 -} diff --git a/examples/embedded/qmlphotoviewer/deployment.pri b/examples/embedded/qmlphotoviewer/deployment.pri index 23882e3686..504373914a 100644 --- a/examples/embedded/qmlphotoviewer/deployment.pri +++ b/examples/embedded/qmlphotoviewer/deployment.pri @@ -1,8 +1,4 @@ qmlphotoviewer_src = $$PWD/../../declarative/photoviewer -symbian { - load(data_caging_paths) - qmlphotoviewer_uid3 = A000E400 - qmlphotoviewer_files.path = $$APP_PRIVATE_DIR_BASE/$$qmlphotoviewer_uid3 -} + qmlphotoviewer_files.files = $$qmlphotoviewer_src/photoviewer.qml $$qmlphotoviewer_src/PhotoViewerCore DEPLOYMENT += qmlphotoviewer_files diff --git a/examples/embedded/qmlphotoviewer/qmlphotoviewer.cpp b/examples/embedded/qmlphotoviewer/qmlphotoviewer.cpp index 89a0902373..16135a7851 100644 --- a/examples/embedded/qmlphotoviewer/qmlphotoviewer.cpp +++ b/examples/embedded/qmlphotoviewer/qmlphotoviewer.cpp @@ -97,13 +97,8 @@ int main(int argc, char *argv[]) view.setResizeMode(QDeclarativeView::SizeRootObjectToView); QObject::connect(view.engine(), SIGNAL(quit()), &application, SLOT(quit())); - -#if defined(Q_OS_SYMBIAN) - view.showFullScreen(); -#else // Q_OS_SYMBIAN view.setGeometry(QRect(100, 100, 360, 640)); view.show(); -#endif // Q_OS_SYMBIAN return application.exec(); } diff --git a/examples/embedded/qmlphotoviewer/qmlphotoviewer.pro b/examples/embedded/qmlphotoviewer/qmlphotoviewer.pro index b97bf269d3..9941b2e226 100644 --- a/examples/embedded/qmlphotoviewer/qmlphotoviewer.pro +++ b/examples/embedded/qmlphotoviewer/qmlphotoviewer.pro @@ -1,12 +1,5 @@ -!symbian:!wince*:warning("DEPLOYMENT support required. This project only works on Symbian and WinCE.") +!wince*:warning("DEPLOYMENT support required. This project only works on WinCE.") QT += declarative network SOURCES += $$PWD/qmlphotoviewer.cpp include($$PWD/deployment.pri) - -symbian { - TARGET.UID3 = 0x$$qmlphotoviewer_uid3 # defined in deployment.pri - CONFIG += qt_example - TARGET.CAPABILITY = NetworkServices - TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 -} diff --git a/examples/embedded/qmltwitter/deployment.pri b/examples/embedded/qmltwitter/deployment.pri index 3edc0e527c..a3c045ca54 100644 --- a/examples/embedded/qmltwitter/deployment.pri +++ b/examples/embedded/qmltwitter/deployment.pri @@ -1,8 +1,4 @@ qmltwitter_src = $$PWD/../../declarative/twitter -symbian { - load(data_caging_paths) - qmltwitter_uid3 = A000E401 - qmltwitter_files.path = $$APP_PRIVATE_DIR_BASE/$$qmltwitter_uid3 -} + qmltwitter_files.files = $$qmltwitter_src/twitter.qml $$qmltwitter_src/TwitterCore DEPLOYMENT += qmltwitter_files diff --git a/examples/embedded/qmltwitter/qmltwitter.cpp b/examples/embedded/qmltwitter/qmltwitter.cpp index f63f9055ef..5485028aff 100644 --- a/examples/embedded/qmltwitter/qmltwitter.cpp +++ b/examples/embedded/qmltwitter/qmltwitter.cpp @@ -96,13 +96,8 @@ int main(int argc, char *argv[]) view.setSource(QUrl(mainQmlApp)); view.setResizeMode(QDeclarativeView::SizeRootObjectToView); QObject::connect(view.engine(), SIGNAL(quit()), &application, SLOT(quit())); - -#if defined(Q_OS_SYMBIAN) - view.showFullScreen(); -#else // Q_OS_SYMBIAN view.setGeometry(QRect(100, 100, 360, 640)); view.show(); -#endif // Q_OS_SYMBIAN return application.exec(); } diff --git a/examples/embedded/qmltwitter/qmltwitter.pro b/examples/embedded/qmltwitter/qmltwitter.pro index 79e25de287..ce40cd7489 100644 --- a/examples/embedded/qmltwitter/qmltwitter.pro +++ b/examples/embedded/qmltwitter/qmltwitter.pro @@ -1,12 +1,5 @@ -!symbian:!wince*:warning("DEPLOYMENT support required. This project only works on Symbian and WinCE.") +!wince*:warning("DEPLOYMENT support required. This project only works on WinCE.") QT += declarative network SOURCES += $$PWD/qmltwitter.cpp include($$PWD/deployment.pri) - -symbian { - TARGET.UID3 = 0x$$qmltwitter_uid3 # defined in deployment.pri - CONFIG += qt_example - TARGET.CAPABILITY = NetworkServices - TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 -} diff --git a/src/declarative/debugger/debugger.pri b/src/declarative/debugger/debugger.pri index 5bc0a2d92e..4128771492 100644 --- a/src/declarative/debugger/debugger.pri +++ b/src/declarative/debugger/debugger.pri @@ -1,5 +1,4 @@ SOURCES += \ - $$PWD/qdeclarativedebuggerstatus.cpp \ $$PWD/qpacketprotocol.cpp \ $$PWD/qdeclarativedebugservice.cpp \ $$PWD/qdeclarativedebugclient.cpp \ @@ -13,7 +12,6 @@ SOURCES += \ $$PWD/qdeclarativeenginedebugservice.cpp HEADERS += \ - $$PWD/qdeclarativedebuggerstatus_p.h \ $$PWD/qpacketprotocol_p.h \ $$PWD/qdeclarativedebugservice_p.h \ $$PWD/qdeclarativedebugservice_p_p.h \ diff --git a/src/declarative/debugger/qdeclarativedebugserver.cpp b/src/declarative/debugger/qdeclarativedebugserver.cpp index 5a888c7dc1..a4f5bd28f0 100644 --- a/src/declarative/debugger/qdeclarativedebugserver.cpp +++ b/src/declarative/debugger/qdeclarativedebugserver.cpp @@ -77,6 +77,8 @@ QT_BEGIN_NAMESPACE const int protocolVersion = 1; +// print detailed information about loading of plugins +DEFINE_BOOL_CONFIG_OPTION(qmlDebugVerbose, QML_DEBUGGER_VERBOSE) class QDeclarativeDebugServerPrivate : public QObjectPrivate { @@ -137,16 +139,29 @@ QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectio } foreach (const QString &pluginPath, pluginCandidates) { + if (qmlDebugVerbose()) + qDebug() << "QDeclarativeDebugServer: Trying to load plugin " << pluginPath << "..."; + QPluginLoader loader(pluginPath); if (!loader.load()) { + if (qmlDebugVerbose()) + qDebug() << "QDeclarativeDebugServer: Error while loading: " << loader.errorString(); continue; } QDeclarativeDebugServerConnection *connection = 0; if (QObject *instance = loader.instance()) connection = qobject_cast<QDeclarativeDebugServerConnection*>(instance); - if (connection) + if (connection) { + if (qmlDebugVerbose()) + qDebug() << "QDeclarativeDebugServer: Plugin successfully loaded."; + return connection; + } + + if (qmlDebugVerbose()) + qDebug() << "QDeclarativeDebugServer: Plugin does not implement interface QDeclarativeDebugServerConnection."; + loader.unload(); } #endif diff --git a/src/declarative/debugger/qdeclarativedebugtrace.cpp b/src/declarative/debugger/qdeclarativedebugtrace.cpp index 7d63849383..b497f6a6ee 100644 --- a/src/declarative/debugger/qdeclarativedebugtrace.cpp +++ b/src/declarative/debugger/qdeclarativedebugtrace.cpp @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE 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 +// use of QDataStream can skew results // (see tst_qdeclarativedebugtrace::trace() benchmark) QByteArray QDeclarativeDebugData::toByteArray() const { @@ -75,7 +75,7 @@ QByteArray QDeclarativeDebugData::toByteArray() const QDeclarativeDebugTrace::QDeclarativeDebugTrace() : QDeclarativeDebugService(QLatin1String("CanvasFrameRate")), - m_enabled(false), m_deferredSend(true), m_messageReceived(false) + m_enabled(false), m_messageReceived(false) { m_timer.start(); if (status() == Enabled) { @@ -89,17 +89,15 @@ QDeclarativeDebugTrace::QDeclarativeDebugTrace() QDeclarativeDebugTrace::~QDeclarativeDebugTrace() { - // unregister the callback - QUnifiedTimer::instance()->registerProfilerCallback( 0 ); } -void QDeclarativeDebugTrace::addEngine(QDeclarativeEngine * /*engine*/) +void QDeclarativeDebugTrace::addEngine(QDeclarativeEngine *) { // just make sure that the service is properly registered traceInstance(); } -void QDeclarativeDebugTrace::removeEngine(QDeclarativeEngine */*engine*/) +void QDeclarativeDebugTrace::removeEngine(QDeclarativeEngine *) { } @@ -237,11 +235,7 @@ void QDeclarativeDebugTrace::animationFrameImpl(qint64 delta) void QDeclarativeDebugTrace::processMessage(const QDeclarativeDebugData &message) { QMutexLocker locker(&m_mutex); - if (m_deferredSend - || (QThread::currentThread() != QCoreApplication::instance()->thread())) - m_data.append(message); - else - sendMessage(message.toByteArray()); + m_data.append(message); } /* @@ -249,19 +243,17 @@ void QDeclarativeDebugTrace::processMessage(const QDeclarativeDebugData &message */ void QDeclarativeDebugTrace::sendMessages() { - if (m_deferredSend) { - QMutexLocker locker(&m_mutex); - //### this is a suboptimal way to send batched messages - for (int i = 0; i < m_data.count(); ++i) - sendMessage(m_data.at(i).toByteArray()); - m_data.clear(); - - //indicate completion - QByteArray data; - QDataStream ds(&data, QIODevice::WriteOnly); - ds << (qint64)-1 << (int)Complete; - sendMessage(data); - } + QMutexLocker locker(&m_mutex); + //### this is a suboptimal way to send batched messages + for (int i = 0; i < m_data.count(); ++i) + sendMessage(m_data.at(i).toByteArray()); + m_data.clear(); + + //indicate completion + QByteArray data; + QDataStream ds(&data, QIODevice::WriteOnly); + ds << (qint64)-1 << (int)Complete; + sendMessage(data); } void QDeclarativeDebugTrace::messageReceived(const QByteArray &message) @@ -269,15 +261,20 @@ void QDeclarativeDebugTrace::messageReceived(const QByteArray &message) QByteArray rwData = message; QDataStream stream(&rwData, QIODevice::ReadOnly); - stream >> m_enabled; + bool enabled; + stream >> enabled; m_messageReceived = true; - if (!m_enabled) { - m_enabled = true; - addEvent(EndTrace); - m_enabled = false; - sendMessages(); + if (m_enabled != enabled) { + if (enabled) { + m_enabled = true; + addEventImpl(StartTrace); + } else { + addEventImpl(EndTrace); + m_enabled = false; + sendMessages(); + } } } diff --git a/src/declarative/debugger/qdeclarativedebugtrace_p.h b/src/declarative/debugger/qdeclarativedebugtrace_p.h index 26535e1676..07af0004dd 100644 --- a/src/declarative/debugger/qdeclarativedebugtrace_p.h +++ b/src/declarative/debugger/qdeclarativedebugtrace_p.h @@ -62,7 +62,7 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -struct QDeclarativeDebugData +struct Q_AUTOTEST_EXPORT QDeclarativeDebugData { qint64 time; int messageType; @@ -102,6 +102,7 @@ public: Key, AnimationFrame, EndTrace, + StartTrace, MaximumEventType }; @@ -146,7 +147,6 @@ private: void sendMessages(); QElapsedTimer m_timer; bool m_enabled; - bool m_deferredSend; bool m_messageReceived; QVector<QDeclarativeDebugData> m_data; QMutex m_mutex; diff --git a/src/declarative/debugger/qdeclarativeenginedebugservice.cpp b/src/declarative/debugger/qdeclarativeenginedebugservice.cpp index 7fa577d7d9..a1b02abe8e 100644 --- a/src/declarative/debugger/qdeclarativeenginedebugservice.cpp +++ b/src/declarative/debugger/qdeclarativeenginedebugservice.cpp @@ -674,8 +674,8 @@ void QDeclarativeEngineDebugService::setMethodBody(int objectId, const QString & if (!contextData) return; - QDeclarativePropertyCache::Data dummy; - QDeclarativePropertyCache::Data *prop = + QDeclarativePropertyData dummy; + QDeclarativePropertyData *prop = QDeclarativePropertyCache::property(context->engine(), object, method, dummy); if (!prop || !prop->isVMEFunction()) diff --git a/src/declarative/debugger/qdeclarativeinspectorinterface_p.h b/src/declarative/debugger/qdeclarativeinspectorinterface_p.h index d4cd783b16..dd30427277 100644 --- a/src/declarative/debugger/qdeclarativeinspectorinterface_p.h +++ b/src/declarative/debugger/qdeclarativeinspectorinterface_p.h @@ -67,8 +67,12 @@ public: QDeclarativeInspectorInterface() {} virtual ~QDeclarativeInspectorInterface() {} - virtual void activate() = 0; + virtual bool canHandleView(QObject *view) = 0; + + virtual void activate(QObject *view) = 0; virtual void deactivate() = 0; + + virtual void clientMessage(const QByteArray &message) = 0; }; Q_DECLARE_INTERFACE(QDeclarativeInspectorInterface, "com.trolltech.Qt.QDeclarativeInspectorInterface/1.0") diff --git a/src/declarative/debugger/qdeclarativeinspectorservice.cpp b/src/declarative/debugger/qdeclarativeinspectorservice.cpp index 56441ae606..c3f90d2cab 100644 --- a/src/declarative/debugger/qdeclarativeinspectorservice.cpp +++ b/src/declarative/debugger/qdeclarativeinspectorservice.cpp @@ -48,13 +48,16 @@ #include <QtCore/QDir> #include <QtCore/QPluginLoader> +// print detailed information about loading of plugins +DEFINE_BOOL_CONFIG_OPTION(qmlDebugVerbose, QML_DEBUGGER_VERBOSE) + QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QDeclarativeInspectorService, serviceInstance) QDeclarativeInspectorService::QDeclarativeInspectorService() : QDeclarativeDebugService(QLatin1String("QDeclarativeObserverMode")) - , m_inspectorPlugin(0) + , m_currentInspectorPlugin(0) { } @@ -91,34 +94,50 @@ void QDeclarativeInspectorService::statusChanged(Status /*status*/) void QDeclarativeInspectorService::updateStatus() { if (m_views.isEmpty()) { - if (m_inspectorPlugin) - m_inspectorPlugin->deactivate(); + if (m_currentInspectorPlugin) { + m_currentInspectorPlugin->deactivate(); + m_currentInspectorPlugin = 0; + } return; } if (status() == Enabled) { - if (!m_inspectorPlugin) - m_inspectorPlugin = loadInspectorPlugin(); + if (m_inspectorPlugins.isEmpty()) + loadInspectorPlugins(); - if (!m_inspectorPlugin) { - qWarning() << "Error while loading inspector plugin"; + if (m_inspectorPlugins.isEmpty()) { + qWarning() << "QDeclarativeInspector: No plugins found."; QDeclarativeDebugServer::instance()->removeService(this); return; } - m_inspectorPlugin->activate(); + foreach (QDeclarativeInspectorInterface *inspector, m_inspectorPlugins) { + if (inspector->canHandleView(m_views.first())) { + m_currentInspectorPlugin = inspector; + break; + } + } + + if (!m_currentInspectorPlugin) { + qWarning() << "QDeclarativeInspector: No plugin available for view '" << m_views.first()->metaObject()->className() << "'."; + return; + } + m_currentInspectorPlugin->activate(m_views.first()); } else { - if (m_inspectorPlugin) - m_inspectorPlugin->deactivate(); + if (m_currentInspectorPlugin) { + m_currentInspectorPlugin->deactivate(); + m_currentInspectorPlugin = 0; + } } } void QDeclarativeInspectorService::messageReceived(const QByteArray &message) { - emit gotMessage(message); + if (m_currentInspectorPlugin) + m_currentInspectorPlugin->clientMessage(message); } -QDeclarativeInspectorInterface *QDeclarativeInspectorService::loadInspectorPlugin() +void QDeclarativeInspectorService::loadInspectorPlugins() { QStringList pluginCandidates; const QStringList paths = QCoreApplication::libraryPaths(); @@ -130,18 +149,30 @@ QDeclarativeInspectorInterface *QDeclarativeInspectorService::loadInspectorPlugi } foreach (const QString &pluginPath, pluginCandidates) { + if (qmlDebugVerbose()) + qDebug() << "QDeclarativeInspector: Trying to load plugin " << pluginPath << "..."; + QPluginLoader loader(pluginPath); - if (!loader.load()) + if (!loader.load()) { + if (qmlDebugVerbose()) + qDebug() << "QDeclarativeInspector: Error while loading: " << loader.errorString(); + continue; + } QDeclarativeInspectorInterface *inspector = qobject_cast<QDeclarativeInspectorInterface*>(loader.instance()); - - if (inspector) - return inspector; - loader.unload(); + if (inspector) { + if (qmlDebugVerbose()) + qDebug() << "QDeclarativeInspector: Plugin successfully loaded."; + m_inspectorPlugins << inspector; + } else { + if (qmlDebugVerbose()) + qDebug() << "QDeclarativeInspector: Plugin does not implement interface QDeclarativeInspectorInterface."; + + loader.unload(); + } } - return 0; } QT_END_NAMESPACE diff --git a/src/declarative/debugger/qdeclarativeinspectorservice_p.h b/src/declarative/debugger/qdeclarativeinspectorservice_p.h index df51ab8bfe..9aa71ae953 100644 --- a/src/declarative/debugger/qdeclarativeinspectorservice_p.h +++ b/src/declarative/debugger/qdeclarativeinspectorservice_p.h @@ -76,23 +76,20 @@ public: void addView(QObject *); void removeView(QObject *); - QList<QObject*> views() const { return m_views; } void sendMessage(const QByteArray &message); -Q_SIGNALS: - void gotMessage(const QByteArray &message); - protected: virtual void statusChanged(Status status); virtual void messageReceived(const QByteArray &); private: void updateStatus(); - static QDeclarativeInspectorInterface *loadInspectorPlugin(); + void loadInspectorPlugins(); QList<QObject*> m_views; - QDeclarativeInspectorInterface *m_inspectorPlugin; + QDeclarativeInspectorInterface *m_currentInspectorPlugin; + QList<QDeclarativeInspectorInterface*> m_inspectorPlugins; }; QT_END_NAMESPACE diff --git a/src/declarative/debugger/qv8debugservice.cpp b/src/declarative/debugger/qv8debugservice.cpp index 49091529a0..2f7ca348fd 100644 --- a/src/declarative/debugger/qv8debugservice.cpp +++ b/src/declarative/debugger/qv8debugservice.cpp @@ -124,6 +124,13 @@ QV8DebugService::QV8DebugService(QObject *parent) { Q_D(QV8DebugService); v8::Debug::SetMessageHandler2(DebugMessageHandler); + + // This call forces the debugger context to be loaded and made resident. + // Without this the debugger is loaded/unloaded whenever required, which + // has a very significant effect on the timing reported in the QML + // profiler in Qt Creator. + v8::Debug::GetDebugContext(); + if (status() == Enabled) { // ,block mode, client attached while (!d->initialized) { @@ -258,9 +265,65 @@ void QV8DebugService::messageReceived(const QByteArray &message) if (debugCommand == QLatin1String("connect")) { d->initialized = true; + //Prepare the response string + //Create a json message using v8 debugging protocol + //and send it to client + + // { "type" : "response", + // "request_seq" : <number>, + // "command" : "connect", + // "running" : <is the VM running after sending this response> + // "success" : true + // } + { + v8::Isolate::Scope i_scope(d->isolate); + const QString obj(QLatin1String("{}")); + QJSValue parser = d->engine->evaluate(QLatin1String("JSON.parse")); + QJSValue jsonVal = parser.call(QJSValue(), QJSValueList() << obj); + jsonVal.setProperty(QLatin1String("type"), QJSValue(QLatin1String("response"))); + + const int sequence = reqMap.value(QLatin1String("seq")).toInt(); + jsonVal.setProperty(QLatin1String("request_seq"), QJSValue(sequence)); + jsonVal.setProperty(QLatin1String("command"), QJSValue(debugCommand)); + jsonVal.setProperty(QLatin1String("success"), QJSValue(true)); + jsonVal.setProperty(QLatin1String("running"), QJSValue(!d->loop.isRunning())); + + QJSValue stringify = d->engine->evaluate(QLatin1String("JSON.stringify")); + QJSValue json = stringify.call(QJSValue(), QJSValueList() << jsonVal); + debugMessageHandler(json.toString()); + + } } else if (debugCommand == QLatin1String("interrupt")) { v8::Debug::DebugBreak(); + //Prepare the response string + //Create a json message using v8 debugging protocol + //and send it to client + + // { "type" : "response", + // "request_seq" : <number>, + // "command" : "connect", + // "running" : <is the VM running after sending this response> + // "success" : true + // } + { + v8::Isolate::Scope i_scope(d->isolate); + const QString obj(QLatin1String("{}")); + QJSValue parser = d->engine->evaluate(QLatin1String("JSON.parse")); + QJSValue jsonVal = parser.call(QJSValue(), QJSValueList() << obj); + jsonVal.setProperty(QLatin1String("type"), QJSValue(QLatin1String("response"))); + + const int sequence = reqMap.value(QLatin1String("seq")).toInt(); + jsonVal.setProperty(QLatin1String("request_seq"), QJSValue(sequence)); + jsonVal.setProperty(QLatin1String("command"), QJSValue(debugCommand)); + jsonVal.setProperty(QLatin1String("success"), QJSValue(true)); + jsonVal.setProperty(QLatin1String("running"), QJSValue(!d->loop.isRunning())); + + QJSValue stringify = d->engine->evaluate(QLatin1String("JSON.stringify")); + QJSValue json = stringify.call(QJSValue(), QJSValueList() << jsonVal); + debugMessageHandler(json.toString()); + + } } else { bool forwardRequestToV8 = true; @@ -363,7 +426,10 @@ void QV8DebugService::messageReceived(const QByteArray &message) d->handlersList.remove(bp); forwardRequestToV8 = false; } + } else if (debugCommand == QLatin1String("disconnect")) { + v8::Debug::CancelDebugBreak(); } + if (forwardRequestToV8) d->sendDebugMessage(request); } diff --git a/src/declarative/debugger/qv8profilerservice.cpp b/src/declarative/debugger/qv8profilerservice.cpp index 92a191688c..48d2d1365d 100644 --- a/src/declarative/debugger/qv8profilerservice.cpp +++ b/src/declarative/debugger/qv8profilerservice.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE -Q_GLOBAL_STATIC(QV8ProfilerService, v8ServiceInstance) +Q_GLOBAL_STATIC(QV8ProfilerService, v8ProfilerInstance) class ByteArrayOutputStream : public v8::OutputStream { @@ -115,7 +115,7 @@ QV8ProfilerService::~QV8ProfilerService() QV8ProfilerService *QV8ProfilerService::instance() { - return v8ServiceInstance(); + return v8ProfilerInstance(); } void QV8ProfilerService::addEngine(QDeclarativeEngine *engine) @@ -149,13 +149,12 @@ void QV8ProfilerService::messageReceived(const QByteArray &message) if (command == "V8PROFILER") { ds >> title; if (option == "start") { - d->initialized = true; startProfiling(QString::fromUtf8(title)); } else if (option == "stop") { stopProfiling(QString::fromUtf8(title)); - // Send messages to client - d->sendMessages(); + sendProfilingData(); } + d->initialized = true; } if (command == "V8SNAPSHOT") { @@ -184,9 +183,18 @@ void QV8ProfilerService::stopProfiling(const QString &title) v8::HandleScope handle_scope; v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size()); const v8::CpuProfile *cpuProfile = v8::CpuProfiler::StopProfiling(v8title); - const v8::CpuProfileNode *rootNode = cpuProfile->GetTopDownRoot(); + if (cpuProfile) { + // can happen at start + const v8::CpuProfileNode *rootNode = cpuProfile->GetTopDownRoot(); + d->printProfileTree(rootNode); + } +} - d->printProfileTree(rootNode); +void QV8ProfilerService::sendProfilingData() +{ + Q_D(QV8ProfilerService); + // Send messages to client + d->sendMessages(); } void QV8ProfilerServicePrivate::printProfileTree(const v8::CpuProfileNode *node, int level) diff --git a/src/declarative/debugger/qv8profilerservice_p.h b/src/declarative/debugger/qv8profilerservice_p.h index ea5119cd50..f2d517b6df 100644 --- a/src/declarative/debugger/qv8profilerservice_p.h +++ b/src/declarative/debugger/qv8profilerservice_p.h @@ -100,6 +100,8 @@ public: void startProfiling(const QString &title); void stopProfiling(const QString &title); + void sendProfilingData(); + protected: void messageReceived(const QByteArray &); diff --git a/src/declarative/declarative.pro b/src/declarative/declarative.pro index 22530188e0..1de91d8dbf 100644 --- a/src/declarative/declarative.pro +++ b/src/declarative/declarative.pro @@ -10,6 +10,7 @@ QT = core-private gui gui-private network sql v8-private DEFINES += QT_BUILD_DECLARATIVE_LIB QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000 +win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 unix|win32-g++*:QMAKE_PKGCONFIG_REQUIRES = QtCore QtGui @@ -36,18 +37,6 @@ include(particles/particles.pri) include(designer/designer.pri) include(animations/animations.pri) -symbian: { - TARGET.UID3=0x2001E623 - LIBS += -lefsrv - - contains(QT_CONFIG, freetype) { - DEFINES += QT_NO_FONTCONFIG - INCLUDEPATH += \ - ../3rdparty/freetype/src \ - ../3rdparty/freetype/include - } -} - linux-g++-maemo:DEFINES += QDECLARATIVEVIEW_NOBACKGROUND DEFINES += QT_NO_OPENTYPE diff --git a/src/declarative/designer/designersupport.h b/src/declarative/designer/designersupport.h index 8b9df689d0..7654363276 100644 --- a/src/declarative/designer/designersupport.h +++ b/src/declarative/designer/designersupport.h @@ -58,6 +58,8 @@ #include <QtCore/QHash> #include <QtCore/QRectF> +QT_BEGIN_HEADER + QT_BEGIN_NAMESPACE QT_MODULE(Declarative) @@ -146,4 +148,6 @@ private: QT_END_NAMESPACE +QT_END_HEADER + #endif // DESIGNERSUPPORT_H diff --git a/src/declarative/items/context2d/qquickcontext2d.cpp b/src/declarative/items/context2d/qquickcontext2d.cpp index ade890d943..2297f53769 100644 --- a/src/declarative/items/context2d/qquickcontext2d.cpp +++ b/src/declarative/items/context2d/qquickcontext2d.cpp @@ -120,6 +120,7 @@ QColor qt_color_from_string(v8::Local<v8::Value> name) return QColor(p); else { bool isRgb(false), isHsl(false), hasAlpha(false); + Q_UNUSED(isHsl) while (isspace(*p)) p++; if (strncmp(p, "rgb", 3) == 0) diff --git a/src/declarative/items/items.pri b/src/declarative/items/items.pri index c3d6a2ab73..f83c65c203 100644 --- a/src/declarative/items/items.pri +++ b/src/declarative/items/items.pri @@ -64,6 +64,7 @@ HEADERS += \ $$PWD/qquickspriteimage_p.h \ $$PWD/qquickdrag_p.h \ $$PWD/qquickdroparea_p.h \ + $$PWD/qquickmultipointtoucharea_p.h \ $$PWD/qquickitemview_p.h \ $$PWD/qquickitemview_p_p.h @@ -110,6 +111,7 @@ SOURCES += \ $$PWD/qquickspriteimage.cpp \ $$PWD/qquickdrag.cpp \ $$PWD/qquickdroparea.cpp \ + $$PWD/qquickmultipointtoucharea.cpp \ $$PWD/qquickitemview.cpp SOURCES += \ diff --git a/src/declarative/items/qquickanimatedimage.cpp b/src/declarative/items/qquickanimatedimage.cpp index d4b08dd4f4..3a11bb4f64 100644 --- a/src/declarative/items/qquickanimatedimage.cpp +++ b/src/declarative/items/qquickanimatedimage.cpp @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE a way to play animations stored as images containing a series of frames, such as those stored in GIF files. - Information about the current frame and totla length of the animation can be + Information about the current frame and total length of the animation can be obtained using the \l currentFrame and \l frameCount properties. You can start, pause and stop the animation by changing the values of the \l playing and \l paused properties. @@ -110,7 +110,7 @@ QT_BEGIN_NAMESPACE Note that this property is only valid for images read from the local filesystem. Images loaded via a network resource (e.g. HTTP) - are always loaded asynchonously. + are always loaded asynchronously. */ /*! diff --git a/src/declarative/items/qquickborderimage.cpp b/src/declarative/items/qquickborderimage.cpp index 3f8e093639..4e713c02d4 100644 --- a/src/declarative/items/qquickborderimage.cpp +++ b/src/declarative/items/qquickborderimage.cpp @@ -161,7 +161,7 @@ QT_BEGIN_NAMESPACE Note that this property is only valid for images read from the local filesystem. Images loaded via a network resource (e.g. HTTP) - are always loaded asynchonously. + are always loaded asynchronously. */ QQuickBorderImage::QQuickBorderImage(QQuickItem *parent) : QQuickImageBase(*(new QQuickBorderImagePrivate), parent) diff --git a/src/declarative/items/qquickcanvas.cpp b/src/declarative/items/qquickcanvas.cpp index b39c9721bf..d191e8fd15 100644 --- a/src/declarative/items/qquickcanvas.cpp +++ b/src/declarative/items/qquickcanvas.cpp @@ -132,9 +132,13 @@ public: : updatePending(false) , animationRunning(false) { - qWarning("QQuickCanvas: using non-threaded render loop. Be very sure to not access scene graph " - "objects outside the QQuickItem::updatePaintNode() call. Failing to do so will cause " - "your code to crash on other platforms!"); + static bool warningMessage = false; + if (!warningMessage) { + warningMessage = true; + qWarning("QQuickCanvas: using non-threaded render loop. Be very sure to not access scene " + "graph objects outside the QQuickItem::updatePaintNode() call. Failing to do so " + "will cause your code to crash on other platforms!"); + } } virtual void paint() { @@ -495,6 +499,12 @@ void QQuickCanvasPrivate::init(QQuickCanvas *c) rootItemPrivate->canvas = q; rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope; + // In the absence of a focus in event on some platforms assume the window will + // be activated immediately and set focus on the rootItem + // ### Remove when QTBUG-22415 is resolved. + //It is important that this call happens after the rootItem has a canvas.. + rootItem->setFocus(true); + bool threaded = !qmlNoThreadedRenderer(); if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL)) { @@ -633,13 +643,13 @@ void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, F } if (!(options & DontChangeFocusProperty)) { - if (item != rootItem || QGuiApplication::focusWindow() == q) { +// if (item != rootItem || QGuiApplication::focusWindow() == q) { // QTBUG-22415 itemPrivate->focus = true; changed << item; - } +// } } - if (newActiveFocusItem && QGuiApplication::focusWindow() == q) { + if (newActiveFocusItem && rootItem->hasFocus()) { activeFocusItem = newActiveFocusItem; QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true; @@ -783,6 +793,9 @@ void QQuickCanvasPrivate::updateInputMethodData() qApp->inputPanel()->setInputItem(inputItem); } +/*! + Queries the Input Method. +*/ QVariant QQuickCanvas::inputMethodQuery(Qt::InputMethodQuery query) const { Q_D(const QQuickCanvas); @@ -818,6 +831,19 @@ void QQuickCanvasPrivate::cleanup(QSGNode *n) } +/*! + \class QQuickCanvas + \since QtQuick 2.0 + \brief The QQuickCanvas class provides the canvas for displaying a graphical QML scene + + QQuickCanvas provides the graphical scene management needed to interact with and display + a scene of QQuickItems. + + A QQuickCanvas always has a single invisible root item. To add items to this canvas, + reparent the items to the root item or to an existing item in the scene. + + For easily displaying a scene from a QML file, see \l{QQuickView}. +*/ QQuickCanvas::QQuickCanvas(QWindow *parent) : QWindow(*(new QQuickCanvasPrivate), parent) { @@ -853,6 +879,12 @@ QQuickCanvas::~QQuickCanvas() d->cleanupNodes(); } +/*! + Returns the invisible root item of the scene. + + A QQuickCanvas always has a single invisible root item. To add items to this canvas, + reparent the items to the root item or to an existing item in the scene. +*/ QQuickItem *QQuickCanvas::rootItem() const { Q_D(const QQuickCanvas); @@ -860,6 +892,9 @@ QQuickItem *QQuickCanvas::rootItem() const return d->rootItem; } +/*! + Returns the item which currently has active focus. +*/ QQuickItem *QQuickCanvas::activeFocusItem() const { Q_D(const QQuickCanvas); @@ -867,6 +902,9 @@ QQuickItem *QQuickCanvas::activeFocusItem() const return d->activeFocusItem; } +/*! + Returns the item which currently has the mouse grab. +*/ QQuickItem *QQuickCanvas::mouseGrabberItem() const { Q_D(const QQuickCanvas); @@ -1496,7 +1534,7 @@ bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte return accepted; } -bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QMouseEvent *event) +bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event) { if (!target) return false; @@ -1512,6 +1550,9 @@ bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem return false; } +/*! + Propagates an event to a QQuickItem on the canvas +*/ bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e) { Q_D(QQuickCanvas); @@ -1550,12 +1591,9 @@ bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e) case QEvent::MouseButtonDblClick: case QEvent::MouseMove: // XXX todo - should sendEvent be doing this? how does it relate to forwarded events? - { - QMouseEvent *se = static_cast<QMouseEvent *>(e); - if (!d->sendFilteredMouseEvent(item->parentItem(), item, se)) { - se->accept(); - QQuickItemPrivate::get(item)->deliverMouseEvent(se); - } + if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) { + e->accept(); + QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e)); } break; case QEvent::Wheel: @@ -1569,7 +1607,11 @@ bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e) case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: - QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e)); + // XXX todo - should sendEvent be doing this? how does it relate to forwarded events? + if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) { + e->accept(); + QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e)); + } break; case QEvent::DragEnter: case QEvent::DragMove: @@ -1591,6 +1633,30 @@ void QQuickCanvasPrivate::cleanupNodes() cleanupNodeList.clear(); } +void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item) +{ + QQuickItemPrivate *p = QQuickItemPrivate::get(item); + if (p->itemNodeInstance) { + delete p->itemNodeInstance; + p->itemNodeInstance = 0; + p->opacityNode = 0; + p->clipNode = 0; + p->groupNode = 0; + p->paintNode = 0; + } + + for (int ii = 0; ii < p->childItems.count(); ++ii) + cleanupNodesOnShutdown(p->childItems.at(ii)); +} + +// This must be called from the render thread, with the main thread frozen +void QQuickCanvasPrivate::cleanupNodesOnShutdown() +{ + cleanupNodes(); + + cleanupNodesOnShutdown(rootItem); +} + void QQuickCanvasPrivate::updateDirtyNodes() { #ifdef DIRTY_DEBUG @@ -1937,7 +2003,8 @@ QImage QQuickCanvas::grabFrameBuffer() /*! Returns an incubation controller that splices incubation between frames - for this canvas. QQuickView automatically installs this controller for you. + for this canvas. QQuickView automatically installs this controller for you, + otherwise you will need to install it yourself using \l{QDeclarativeEngine::setIncubationController} The controller is owned by the canvas and will be destroyed when the canvas is deleted. @@ -2094,6 +2161,11 @@ void QQuickCanvasRenderThread::run() } #ifdef THREAD_DEBUG + printf(" RenderThread: deleting all outstanding nodes\n"); +#endif + cleanupNodesOnShutdown(); + +#ifdef THREAD_DEBUG printf(" RenderThread: render loop exited... Good Night!\n"); #endif diff --git a/src/declarative/items/qquickcanvas_p.h b/src/declarative/items/qquickcanvas_p.h index 7dbe4d06f3..c5981b3a4f 100644 --- a/src/declarative/items/qquickcanvas_p.h +++ b/src/declarative/items/qquickcanvas_p.h @@ -110,7 +110,7 @@ public: static void transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform); bool deliverInitialMousePressEvent(QQuickItem *, QMouseEvent *); bool deliverMouseEvent(QMouseEvent *); - bool sendFilteredMouseEvent(QQuickItem *, QQuickItem *, QMouseEvent *); + bool sendFilteredMouseEvent(QQuickItem *, QQuickItem *, QEvent *); bool deliverWheelEvent(QQuickItem *, QWheelEvent *); bool deliverTouchPoints(QQuickItem *, QTouchEvent *, const QList<QTouchEvent::TouchPoint> &, QSet<int> *, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *); @@ -152,6 +152,7 @@ public: void updateDirtyNodes(); void cleanupNodes(); + void cleanupNodesOnShutdown(); bool updateEffectiveOpacity(QQuickItem *); void updateEffectiveOpacityRoot(QQuickItem *, qreal); void updateDirtyNode(QQuickItem *); @@ -171,6 +172,8 @@ public: QHash<int, QQuickItem *> itemForTouchPointId; mutable QQuickCanvasIncubationController *incubationController; +private: + static void cleanupNodesOnShutdown(QQuickItem *); }; class QQuickCanvasRenderLoop @@ -205,6 +208,7 @@ public: protected: void initializeSceneGraph() { d->initializeSceneGraph(); } void syncSceneGraph() { d->syncSceneGraph(); } + void cleanupNodesOnShutdown() { d->cleanupNodesOnShutdown(); } void renderSceneGraph(const QSize &size) { d->renderSceneGraph(size); } void polishItems() { d->polishItems(); } QAnimationDriver2 *animationDriver() const { return d->animationDriver; } diff --git a/src/declarative/items/qquickdrag.cpp b/src/declarative/items/qquickdrag.cpp index d3439b08bf..9dcc4ac7fe 100644 --- a/src/declarative/items/qquickdrag.cpp +++ b/src/declarative/items/qquickdrag.cpp @@ -105,7 +105,7 @@ public: \snippet doc/src/snippets/declarative/drag.qml 0 - A drag can be terminated either by cancelling it with Drag.cancel() or setting + A drag can be terminated either by canceling it with Drag.cancel() or setting Drag.active to false, or it can be terminated with a drop event by calling Drag.drop(). If the drop event is accepted Drag.drop() will return the \l {supportedActions}{drop action} chosen by the recipient of the event, @@ -217,7 +217,7 @@ void QQuickDragAttached::resetSource() When a drag is not active this property holds the object that accepted the drop event that ended the drag, if no object accepted the drop or - the drag was cancelled the target will then be null. + the drag was canceled the target will then be null. */ QObject *QQuickDragAttached::target() const diff --git a/src/declarative/items/qquickflickable.cpp b/src/declarative/items/qquickflickable.cpp index 655472004d..0c24aa35b4 100644 --- a/src/declarative/items/qquickflickable.cpp +++ b/src/declarative/items/qquickflickable.cpp @@ -684,7 +684,7 @@ qreal QQuickFlickable::verticalVelocity() const \qmlproperty bool QtQuick2::Flickable::atYEnd These properties are true if the flickable view is positioned at the beginning, - or end respecively. + or end respectively. */ bool QQuickFlickable::isAtXEnd() const { @@ -1315,7 +1315,7 @@ QDeclarativeListProperty<QQuickItem> QQuickFlickable::flickableChildren() /*! \qmlproperty enumeration QtQuick2::Flickable::boundsBehavior This property holds whether the surface may be dragged - beyond the Fickable's boundaries, or overshoot the + beyond the Flickable's boundaries, or overshoot the Flickable's boundaries when flicked. This enables the feeling that the edges of the view are soft, diff --git a/src/declarative/items/qquickgridview.cpp b/src/declarative/items/qquickgridview.cpp index 4d715a9cb2..1d258b1fa6 100644 --- a/src/declarative/items/qquickgridview.cpp +++ b/src/declarative/items/qquickgridview.cpp @@ -182,6 +182,7 @@ public: virtual void setPosition(qreal pos); virtual void layoutVisibleItems(); bool applyInsertionChange(const QDeclarativeChangeSet::Insert &, FxViewItem *, InsertionsResult *); + virtual bool needsRefillForAddedOrRemovedIndex(int index) const; virtual qreal headerSize() const; virtual qreal footerSize() const; @@ -340,9 +341,6 @@ qreal QQuickGridViewPrivate::snapPosAt(qreal pos) const qreal snapPos = 0; if (!visibleItems.isEmpty()) { qreal highlightStart = highlightRangeStart; - if (isRightToLeftTopToBottom()) - highlightStart = highlightRangeEndValid ? -size() + highlightRangeEnd : -size(); - pos += highlightStart; pos += rowSize()/2; snapPos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize(); @@ -351,8 +349,8 @@ qreal QQuickGridViewPrivate::snapPosAt(qreal pos) const qreal maxExtent; qreal minExtent; if (isRightToLeftTopToBottom()) { - maxExtent = q->minXExtent(); - minExtent = q->maxXExtent(); + maxExtent = q->minXExtent()-size(); + minExtent = q->maxXExtent()-size(); } else { maxExtent = flow == QQuickGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent(); minExtent = flow == QQuickGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent(); @@ -1861,6 +1859,13 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In return insertResult->addedItems.count() > prevAddedCount; } +bool QQuickGridViewPrivate::needsRefillForAddedOrRemovedIndex(int modelIndex) const +{ + // If we add or remove items before visible items, a layout may be + // required to ensure item 0 is in the first column. + return modelIndex < visibleIndex; +} + /*! \qmlmethod QtQuick2::GridView::positionViewAtIndex(int index, PositionMode mode) diff --git a/src/declarative/items/qquickimage.cpp b/src/declarative/items/qquickimage.cpp index 073795768c..5f706aceb3 100644 --- a/src/declarative/items/qquickimage.cpp +++ b/src/declarative/items/qquickimage.cpp @@ -64,7 +64,7 @@ public: QSGTexture *texture() const { - if (m_texture->isAtlasTexture()) + if (m_texture && m_texture->isAtlasTexture()) const_cast<QQuickImageTextureProvider *>(this)->m_texture = m_texture->removedFromAtlas(); if (m_texture) { @@ -404,7 +404,7 @@ qreal QQuickImage::paintedHeight() const other dimension is set in proportion to preserve the source image's aspect ratio. (The \l fillMode is independent of this.) - If the source is an instrinsically scalable image (eg. SVG), this property + If the source is an intrinsically scalable image (eg. SVG), this property determines the size of the loaded image regardless of intrinsic size. Avoid changing this property dynamically; rendering an SVG is \e slow compared to an image. @@ -442,7 +442,7 @@ qreal QQuickImage::paintedHeight() const Note that this property is only valid for images read from the local filesystem. Images loaded via a network resource (e.g. HTTP) - are always loaded asynchonously. + are always loaded asynchronously. */ /*! diff --git a/src/declarative/items/qquickitem.cpp b/src/declarative/items/qquickitem.cpp index b6951d9a77..91e6831ff7 100644 --- a/src/declarative/items/qquickitem.cpp +++ b/src/declarative/items/qquickitem.cpp @@ -2185,7 +2185,7 @@ QQuickItemPrivate::QQuickItemPrivate() : _anchors(0), _contents(0), baselineOffset(0), _anchorLines(0), _stateGroup(0), origin(QQuickItem::Center), flags(0), widthValid(false), heightValid(false), componentComplete(true), - keepMouse(false), hoverEnabled(false), smooth(false), focus(false), activeFocus(false), notifiedFocus(false), + keepMouse(false), keepTouch(false), hoverEnabled(false), smooth(false), focus(false), activeFocus(false), notifiedFocus(false), notifiedActiveFocus(false), filtersChildMouseEvents(false), explicitVisible(true), effectiveVisible(true), explicitEnable(true), effectiveEnable(true), polishScheduled(false), inheritedLayoutMirror(false), effectiveLayoutMirror(false), isMirrorImplicit(true), @@ -2856,6 +2856,11 @@ void QQuickItem::mouseUngrabEvent() // XXX todo } +void QQuickItem::touchUngrabEvent() +{ + // XXX todo +} + void QQuickItem::wheelEvent(QWheelEvent *event) { event->ignore(); @@ -4529,11 +4534,99 @@ void QQuickItem::setKeepMouseGrab(bool keep) } /*! + Grabs the touch points specified by \a ids. + + These touch points will be owned by the item until + they are released. Alternatively, the grab can be stolen + by a filtering item like Flickable. Use setKeepTouchGrab() + to prevent the grab from being stolen. + + \sa ungrabTouchPoints(), setKeepTouchGrab() +*/ +void QQuickItem::grabTouchPoints(const QList<int> &ids) +{ + Q_D(QQuickItem); + if (!d->canvas) + return; + QQuickCanvasPrivate *canvasPriv = QQuickCanvasPrivate::get(d->canvas); + + QSet<QQuickItem*> ungrab; + for (int i = 0; i < ids.count(); ++i) { + QQuickItem *oldGrabber = canvasPriv->itemForTouchPointId.value(ids.at(i)); + if (oldGrabber == this) + return; + + canvasPriv->itemForTouchPointId[ids.at(i)] = this; + if (oldGrabber) + ungrab.insert(oldGrabber); + } + foreach (QQuickItem *oldGrabber, ungrab) + oldGrabber->touchUngrabEvent(); +} + +/*! + Ungrabs the touch points owned by this item. + + \sa grabTouchPoints() +*/ +void QQuickItem::ungrabTouchPoints() +{ + Q_D(QQuickItem); + if (!d->canvas) + return; + QQuickCanvasPrivate *canvasPriv = QQuickCanvasPrivate::get(d->canvas); + + QMutableHashIterator<int, QQuickItem*> i(canvasPriv->itemForTouchPointId); + while (i.hasNext()) { + i.next(); + if (i.value() == this) + i.remove(); + } + touchUngrabEvent(); +} + +/*! + Returns a value indicating whether the touch points grabbed by this item + should remain with this item exclusively. + + \sa setKeepTouchGrab(), keepMouseGrab() +*/ +bool QQuickItem::keepTouchGrab() const +{ + Q_D(const QQuickItem); + return d->keepTouch; +} + +/*! + The flag indicating whether the touch points grabbed + by this item should remain with this item is set to \a keep. + + This is useful for items that wish to grab and keep specific touch + points following a predefined gesture. For example, + an item that is interested in horizontal touch point movement + may set setKeepTouchGrab to true once a threshold has been + exceeded. Once setKeepTouchGrab has been set to true, filtering + items will not react to the relevant touch points. + + If the item does not indicate that it wishes to retain touch point grab, + a filtering item may steal the grab. For example, Flickable may attempt + to steal a touch point grab if it detects that the user has begun to + move the viewport. + + \sa keepTouchGrab(), setKeepMouseGrab() + */ +void QQuickItem::setKeepTouchGrab(bool keep) +{ + Q_D(QQuickItem); + d->keepTouch = keep; +} + +/*! \qmlmethod object QtQuick2::Item::mapFromItem(Item item, real x, real y) Maps the point (\a x, \a y), which is in \a item's coordinate system, to this item's coordinate system, and returns an object with \c x and \c y - properties matching the mapped cooordinate. + properties matching the mapped coordinate. If \a item is a \c null value, this maps the point from the coordinate system of the root QML view. @@ -4543,7 +4636,7 @@ void QQuickItem::setKeepMouseGrab(bool keep) Maps the point (\a x, \a y), which is in this item's coordinate system, to \a item's coordinate system, and returns an object with \c x and \c y - properties matching the mapped cooordinate. + properties matching the mapped coordinate. If \a item is a \c null value, this maps \a x and \a y to the coordinate system of the root QML view. diff --git a/src/declarative/items/qquickitem.h b/src/declarative/items/qquickitem.h index be50677bf1..0cbcfb890d 100644 --- a/src/declarative/items/qquickitem.h +++ b/src/declarative/items/qquickitem.h @@ -282,6 +282,11 @@ public: bool filtersChildMouseEvents() const; void setFiltersChildMouseEvents(bool filter); + void grabTouchPoints(const QList<int> &ids); + void ungrabTouchPoints(); + bool keepTouchGrab() const; + void setKeepTouchGrab(bool); + QTransform itemTransform(QQuickItem *, bool *) const; QPointF mapToItem(const QQuickItem *item, const QPointF &point) const; QPointF mapToScene(const QPointF &point) const; @@ -368,6 +373,7 @@ protected: virtual void mouseReleaseEvent(QMouseEvent *event); virtual void mouseDoubleClickEvent(QMouseEvent *event); virtual void mouseUngrabEvent(); // XXX todo - params? + virtual void touchUngrabEvent(); virtual void wheelEvent(QWheelEvent *event); virtual void touchEvent(QTouchEvent *event); virtual void hoverEnterEvent(QHoverEvent *event); diff --git a/src/declarative/items/qquickitem_p.h b/src/declarative/items/qquickitem_p.h index 94b195f2d8..47f86c48aa 100644 --- a/src/declarative/items/qquickitem_p.h +++ b/src/declarative/items/qquickitem_p.h @@ -237,6 +237,7 @@ public: bool heightValid:1; bool componentComplete:1; bool keepMouse:1; + bool keepTouch:1; bool hoverEnabled:1; bool smooth:1; bool focus:1; @@ -255,7 +256,6 @@ public: bool inheritMirrorFromParent:1; bool inheritMirrorFromItem:1; bool childrenDoNotOverlap:1; - quint32 dummy:1; QQuickCanvas *canvas; QSGContext *sceneGraphContext() const { Q_ASSERT(canvas); return static_cast<QQuickCanvasPrivate *>(QObjectPrivate::get(canvas))->context; } diff --git a/src/declarative/items/qquickitemsmodule.cpp b/src/declarative/items/qquickitemsmodule.cpp index 38b5a91e56..0a04e884ae 100644 --- a/src/declarative/items/qquickitemsmodule.cpp +++ b/src/declarative/items/qquickitemsmodule.cpp @@ -80,6 +80,7 @@ #include "qquickspriteimage_p.h" #include "qquickdrag_p.h" #include "qquickdroparea_p.h" +#include "qquickmultipointtoucharea_p.h" static QDeclarativePrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject *parent) { @@ -201,6 +202,10 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickDropEvent>(); qmlRegisterType<QQuickDropAreaDrag>(); qmlRegisterUncreatableType<QQuickDrag>("QtQuick", 2, 0, "Drag", QQuickDragAttached::tr("Drag is only available via attached properties")); + + qmlRegisterType<QQuickMultiPointTouchArea>("QtQuick", 2, 0, "MultiPointTouchArea"); + qmlRegisterType<QQuickTouchPoint>("QtQuick", 2, 0, "TouchPoint"); + qmlRegisterType<QQuickGrabGestureEvent>(); } void QQuickItemsModule::defineModule() diff --git a/src/declarative/items/qquickitemview.cpp b/src/declarative/items/qquickitemview.cpp index b3429ded7c..79787d777c 100644 --- a/src/declarative/items/qquickitemview.cpp +++ b/src/declarative/items/qquickitemview.cpp @@ -1146,7 +1146,6 @@ qreal QQuickItemViewPrivate::endPosition() const qreal QQuickItemViewPrivate::contentStartPosition() const { - Q_Q(const QQuickItemView); qreal pos = -headerSize(); if (layoutOrientation() == Qt::Vertical) pos -= vData.startMargin; @@ -1414,7 +1413,7 @@ bool QQuickItemViewPrivate::applyModelChanges() moveReason = QQuickItemViewPrivate::Other; int prevCount = itemCount; - bool removedVisible = false; + bool visibleAffected = false; bool viewportChanged = !currentChanges.pendingChanges.removes().isEmpty() || !currentChanges.pendingChanges.inserts().isEmpty(); @@ -1433,8 +1432,8 @@ bool QQuickItemViewPrivate::applyModelChanges() FxViewItem *item = *it; if (item->index == -1 || item->index < removals[i].index) { // already removed, or before removed items - if (item->index < removals[i].index && !removedVisible) - removedVisible = true; + if (!visibleAffected && item->index < removals[i].index) + visibleAffected = true; ++it; } else if (item->index >= removals[i].index + removals[i].count) { // after removed items @@ -1442,7 +1441,7 @@ bool QQuickItemViewPrivate::applyModelChanges() ++it; } else { // removed item - removedVisible = true; + visibleAffected = true; if (!removals[i].isMove()) item->attached->emitRemove(); @@ -1464,20 +1463,22 @@ bool QQuickItemViewPrivate::applyModelChanges() } } } - + if (!visibleAffected && needsRefillForAddedOrRemovedIndex(removals[i].index)) + visibleAffected = true; } if (!removals.isEmpty()) updateVisibleIndex(); const QVector<QDeclarativeChangeSet::Insert> &insertions = currentChanges.pendingChanges.inserts(); - bool addedVisible = false; InsertionsResult insertResult; bool allInsertionsBeforeVisible = true; for (int i=0; i<insertions.count(); i++) { bool wasEmpty = visibleItems.isEmpty(); if (applyInsertionChange(insertions[i], firstVisible, &insertResult)) - addedVisible = true; + visibleAffected = true; + if (!visibleAffected && needsRefillForAddedOrRemovedIndex(insertions[i].index)) + visibleAffected = true; if (insertions[i].index >= visibleIndex) allInsertionsBeforeVisible = false; if (wasEmpty && !visibleItems.isEmpty()) @@ -1543,7 +1544,8 @@ bool QQuickItemViewPrivate::applyModelChanges() if (prevCount != itemCount) emit q->countChanged(); - bool visibleAffected = removedVisible || addedVisible || !currentChanges.pendingChanges.changes().isEmpty(); + if (!visibleAffected) + visibleAffected = !currentChanges.pendingChanges.changes().isEmpty(); if (!visibleAffected && viewportChanged) updateViewport(); diff --git a/src/declarative/items/qquickitemview_p_p.h b/src/declarative/items/qquickitemview_p_p.h index 398de84c25..ca4c0ceba9 100644 --- a/src/declarative/items/qquickitemview_p_p.h +++ b/src/declarative/items/qquickitemview_p_p.h @@ -240,6 +240,7 @@ protected: virtual void layoutVisibleItems() = 0; virtual void changedVisibleIndex(int newIndex) = 0; virtual bool applyInsertionChange(const QDeclarativeChangeSet::Insert &, FxViewItem *, InsertionsResult *) = 0; + virtual bool needsRefillForAddedOrRemovedIndex(int) const { return false; } virtual void initializeViewItem(FxViewItem *) {} virtual void initializeCurrentItem() {} diff --git a/src/declarative/items/qquicklistview.cpp b/src/declarative/items/qquicklistview.cpp index 78a813a45f..004ac53595 100644 --- a/src/declarative/items/qquicklistview.cpp +++ b/src/declarative/items/qquicklistview.cpp @@ -1677,7 +1677,7 @@ QQuickListView::~QQuickListView() The ListView will lay out the items based on the size of the root item in the delegate. - It is recommended that the delagate's size be a whole number to avoid sub-pixel + It is recommended that the delegate's size be a whole number to avoid sub-pixel alignment of items. \note Delegates are instantiated as needed and may be destroyed at any time. @@ -2325,8 +2325,6 @@ void QQuickListView::updateSections() bool QQuickListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Insert &change, FxViewItem *firstVisible, InsertionsResult *insertResult) { - Q_Q(QQuickListView); - int modelIndex = change.index; int count = change.count; diff --git a/src/declarative/items/qquickloader.cpp b/src/declarative/items/qquickloader.cpp index cef98a6f7c..73f57073d2 100644 --- a/src/declarative/items/qquickloader.cpp +++ b/src/declarative/items/qquickloader.cpp @@ -428,7 +428,7 @@ void QQuickLoader::loadFromSourceComponent() the \a source component will be created with the initial \a properties set. Setting the initial property values of an instance of a component in this manner - will \e not trigger any associated \l{Behavior}s. + will \bold{not} trigger any associated \l{Behavior}s. Note that the cached \a properties will be cleared if the \l source or \l sourceComponent is changed after calling this function but prior to setting the loader \l active. diff --git a/src/declarative/items/qquickmultipointtoucharea.cpp b/src/declarative/items/qquickmultipointtoucharea.cpp new file mode 100644 index 0000000000..f7fdf97fb7 --- /dev/null +++ b/src/declarative/items/qquickmultipointtoucharea.cpp @@ -0,0 +1,729 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickmultipointtoucharea_p.h" +#include <qquickcanvas.h> +#include <QEvent> +#include <QMouseEvent> +#include <math.h> +#include <QDebug> + +QT_BEGIN_NAMESPACE + +/*! + \qmlclass TouchPoint QQuickTouchPoint + \inqmlmodule QtQuick 2 + \ingroup qml-event-elements + \brief The TouchPoint element describes a touch point in a MultiPointTouchArea. + + The TouchPoint element contains information about a touch point, such as the current + position, pressure, and area. +*/ + +/*! + \qmlproperty int QtQuick2::TouchPoint::pointId + + This property holds the point id of the touch point. + + Each touch point within a MultiPointTouchArea will have a unique id. +*/ +void QQuickTouchPoint::setPointId(int id) +{ + if (_id == id) + return; + _id = id; + emit pointIdChanged(); +} + +/*! + \qmlproperty real QtQuick2::TouchPoint::x + \qmlproperty real QtQuick2::TouchPoint::y + + These properties hold the current position of the touch point. +*/ + +void QQuickTouchPoint::setX(qreal x) +{ + if (_x == x) + return; + _x = x; + emit xChanged(); +} + +void QQuickTouchPoint::setY(qreal y) +{ + if (_y == y) + return; + _y = y; + emit yChanged(); +} + +/*! + \qmlproperty real QtQuick2::TouchPoint::pressure + \qmlproperty rectangle QtQuick2::TouchPoint::area + + These properties hold additional information about the current state of the touch point. + + \list + \i \c pressure is a value in the range of 0.0 to 1.0. + \i \c area is a rectangle covering the area of the touch point, centered on the current position of the touch point. + \endlist +*/ +void QQuickTouchPoint::setPressure(qreal pressure) +{ + if (_pressure == pressure) + return; + _pressure = pressure; + emit pressureChanged(); +} + +void QQuickTouchPoint::setArea(const QRectF &area) +{ + if (_area == area) + return; + _area = area; + emit areaChanged(); +} + +/*! + \qmlproperty bool QtQuick2::TouchPoint::valid + + This property holds whether the touch point is valid. + + An invalid touch point is one that has not yet been pressed, + or has already been released. +*/ +void QQuickTouchPoint::setValid(bool valid) +{ + if (_valid == valid) + return; + _valid = valid; + emit validityChanged(); +} + +/*! + \qmlproperty real QtQuick2::TouchPoint::startX + \qmlproperty real QtQuick2::TouchPoint::startY + + These properties hold the starting position of the touch point. +*/ + +void QQuickTouchPoint::setStartX(qreal startX) +{ + if (_startX == startX) + return; + _startX = startX; + emit startXChanged(); +} + +void QQuickTouchPoint::setStartY(qreal startY) +{ + if (_startY == startY) + return; + _startY = startY; + emit startYChanged(); +} + +/*! + \qmlproperty real QtQuick2::TouchPoint::previousX + \qmlproperty real QtQuick2::TouchPoint::previousY + + These properties hold the previous position of the touch point. +*/ +void QQuickTouchPoint::setPreviousX(qreal previousX) +{ + if (_previousX == previousX) + return; + _previousX = previousX; + emit previousXChanged(); +} + +void QQuickTouchPoint::setPreviousY(qreal previousY) +{ + if (_previousY == previousY) + return; + _previousY = previousY; + emit previousYChanged(); +} + +/*! + \qmlproperty real QtQuick2::TouchPoint::sceneX + \qmlproperty real QtQuick2::TouchPoint::sceneY + + These properties hold the current position of the touch point in scene coordinates. +*/ + +void QQuickTouchPoint::setSceneX(qreal sceneX) +{ + if (_sceneX == sceneX) + return; + _sceneX = sceneX; + emit sceneXChanged(); +} + +void QQuickTouchPoint::setSceneY(qreal sceneY) +{ + if (_sceneY == sceneY) + return; + _sceneY = sceneY; + emit sceneYChanged(); +} + +/*! + \qmlclass MultiPointTouchArea QQuickMultiPointTouchArea + \inqmlmodule QtQuick 2 + \brief The MultiPointTouchArea item enables handling of multiple touch points. + \inherits Item + + A MultiPointTouchArea is an invisible item that is used to track multiple touch points. + + The \l enabled property is used to enable and disable touch handling. When disabled, + the touch area becomes transparent to mouse/touch events. + + MultiPointTouchArea can be used in two ways: + + \list + \o setting \c touchPoints to provide touch point objects with properties that can be bound to + \o using the onTouchUpdated or onTouchPointsPressed, onTouchPointsUpdated and onTouchPointsReleased handlers + \endlist + + While a MultiPointTouchArea \i can take exclusive ownership of certain touch points, it is also possible to have + multiple MultiPointTouchAreas active at the same time, each operating on a different set of touch points. + + \sa TouchPoint +*/ + +/*! + \qmlsignal QtQuick2::MultiPointTouchArea::touchPointsPressed(list<TouchPoint> touchPoints) + + This handler is called when new touch points are added. \a touchPoints is a list of these new points. + + If minimumTouchPoints is set to a value greater than one, this handler will not be called until the minimum number + of required touch points has been reached. At that point, touchPointsPressed will be called with all the current touch points. +*/ + +/*! + \qmlsignal QtQuick2::MultiPointTouchArea::touchPointsUpdated(list<TouchPoint> touchPoints) + + This handler is called when existing touch points are updated. \a touchPoints is a list of these updated points. +*/ + +/*! + \qmlsignal QtQuick2::MultiPointTouchArea::touchPointsReleased(list<TouchPoint> touchPoints) + + This handler is called when existing touch points are removed. \a touchPoints is a list of these removed points. +*/ + +/*! + \qmlsignal QtQuick2::MultiPointTouchArea::touchPointsCanceled(list<TouchPoint> touchPoints) + + This handler is called when new touch events have been canceled because another element stole the touch event handling. + + This signal is for advanced use: it is useful when there is more than one MultiPointTouchArea + that is handling input, or when there is a MultiPointTouchArea inside a \l Flickable. In the latter + case, if you execute some logic on the touchPointsPressed signal and then start dragging, the + \l Flickable may steal the touch handling from the MultiPointTouchArea. In these cases, to reset + the logic when the MultiPointTouchArea has lost the touch handling to the \l Flickable, + \c onTouchPointsCanceled should be used in addition to onTouchPointsReleased. + + \a touchPoints is the list of canceled points. +*/ + +/*! + \qmlsignal QtQuick2::MultiPointTouchArea::gestureStarted(GestureEvent gesture) + + This handler is called when the global drag threshold has been reached. + + This function is typically used when a MultiPointTouchAreas has been nested in a Flickable or another MultiPointTouchArea. + Wnen the threshold has been reached, and the handler called, you can determine whether or not the touch + area should grab the current touch points. By default they will not be grabbed; to grab them call \c gesture.grab(). If the + gesture is not grabbed, the nesting Flickable, for example, would also have an opportunity to grab. + + The gesture object also includes information on the current set of \c touchPoints and the \c dragThreshold. +*/ + +/*! + \qmlsignal QtQuick2::MultiPointTouchArea::touchUpdated(list<TouchPoint> touchPoints) + + This handler is called when the touch points handled by the MultiPointTouchArea change. This includes adding new touch points, + removing previous touch points, as well as updating current touch point data. \a touchPoints is the list of all current touch + points. +*/ + +/*! + \qmlproperty list<TouchPoint> QtQuick2::MultiPointTouchArea::touchPoints + + This property holds a set of user-defined touch point objects that can be bound to. + + In the following example, we have two small rectangles that follow our touch points. + + \snippet doc/src/snippets/declarative/multipointtoucharea/multipointtoucharea.qml 0 + + By default this property holds an empty list. + + \sa TouchPoint +*/ + +QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent) + : QQuickItem(parent), + _minimumTouchPoints(0), + _maximumTouchPoints(INT_MAX), + _stealMouse(false) +{ + setAcceptedMouseButtons(Qt::LeftButton); + setFiltersChildMouseEvents(true); +} + +QQuickMultiPointTouchArea::~QQuickMultiPointTouchArea() +{ + clearTouchLists(); + foreach (QObject *obj, _touchPoints) { + QQuickTouchPoint *dtp = static_cast<QQuickTouchPoint*>(obj); + if (!dtp->isQmlDefined()) + delete dtp; + } +} + +/*! + \qmlproperty int QtQuick2::MultiPointTouchArea::minimumTouchPoints + \qmlproperty int QtQuick2::MultiPointTouchArea::maximumTouchPoints + + These properties hold the range of touch points to be handled by the touch area. + + These are convenience that allow you to, for example, have nested MultiPointTouchAreas, + one handling two finger touches, and another handling three finger touches. + + By default, all touch points within the touch area are handled. +*/ + +int QQuickMultiPointTouchArea::minimumTouchPoints() const +{ + return _minimumTouchPoints; +} + +void QQuickMultiPointTouchArea::setMinimumTouchPoints(int num) +{ + if (_minimumTouchPoints == num) + return; + _minimumTouchPoints = num; + emit minimumTouchPointsChanged(); +} + +int QQuickMultiPointTouchArea::maximumTouchPoints() const +{ + return _maximumTouchPoints; +} + +void QQuickMultiPointTouchArea::setMaximumTouchPoints(int num) +{ + if (_maximumTouchPoints == num) + return; + _maximumTouchPoints = num; + emit maximumTouchPointsChanged(); +} + +void QQuickMultiPointTouchArea::touchEvent(QTouchEvent *event) +{ + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: { + //if e.g. a parent Flickable has the mouse grab, don't process the touch events + QQuickCanvas *c = canvas(); + QQuickItem *grabber = c ? c->mouseGrabberItem() : 0; + if (grabber && grabber != this && grabber->keepMouseGrab() && grabber->isEnabled()) { + QQuickItem *item = this; + while ((item = item->parentItem())) { + if (item == grabber) + return; + } + } + updateTouchData(event); + if (event->type() == QEvent::TouchEnd) { + //TODO: move to canvas + _stealMouse = false; + setKeepMouseGrab(false); + QQuickCanvas *c = canvas(); + if (c && c->mouseGrabberItem() == this) + ungrabMouse(); + setKeepTouchGrab(false); + ungrabTouchPoints(); + } + break; + } + default: + QQuickItem::touchEvent(event); + break; + } +} + +void QQuickMultiPointTouchArea::grabGesture() +{ + _stealMouse = true; + + grabMouse(); + setKeepMouseGrab(true); + + grabTouchPoints(_touchPoints.keys()); + setKeepTouchGrab(true); +} + +void QQuickMultiPointTouchArea::updateTouchData(QEvent *event) +{ + bool ended = false; + bool moved = false; + bool started = false; + + clearTouchLists(); + QTouchEvent *e = static_cast<QTouchEvent*>(event); + QList<QTouchEvent::TouchPoint> touchPoints = e->touchPoints(); + int numTouchPoints = touchPoints.count(); + //always remove released touches, and make sure we handle all releases before adds. + foreach (QTouchEvent::TouchPoint p, touchPoints) { + Qt::TouchPointState touchPointState = p.state(); + int id = p.id(); + if (touchPointState & Qt::TouchPointReleased) { + QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id)); + if (!dtp) + continue; + _releasedTouchPoints.append(dtp); + _touchPoints.remove(id); + ended = true; + } + } + if (numTouchPoints >= _minimumTouchPoints && numTouchPoints <= _maximumTouchPoints) { + foreach (QTouchEvent::TouchPoint p, touchPoints) { + Qt::TouchPointState touchPointState = p.state(); + int id = p.id(); + if (touchPointState & Qt::TouchPointReleased) { + //handled above + } else if (!_touchPoints.contains(id)) { //could be pressed, moved, or stationary + addTouchPoint(&p); + started = true; + } else if (touchPointState & Qt::TouchPointMoved) { + QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints[id]); + Q_ASSERT(dtp); + _movedTouchPoints.append(dtp); + updateTouchPoint(dtp,&p); + moved = true; + } else { + QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints[id]); + Q_ASSERT(dtp); + updateTouchPoint(dtp,&p); + } + } + + //see if we should be grabbing the gesture + if (!_stealMouse /* !ignoring gesture*/) { + bool offerGrab = false; + const int dragThreshold = qApp->styleHints()->startDragDistance(); + foreach (const QTouchEvent::TouchPoint &p, touchPoints) { + if (p.state() == Qt::TouchPointReleased) + continue; + const QPointF ¤tPos = p.scenePos(); + const QPointF &startPos = p.startScenePos(); + if (qAbs(currentPos.x() - startPos.x()) > dragThreshold) + offerGrab = true; + else if (qAbs(currentPos.y() - startPos.y()) > dragThreshold) + offerGrab = true; + if (offerGrab) + break; + } + + if (offerGrab) { + QQuickGrabGestureEvent event; + event._touchPoints = _touchPoints.values(); + emit gestureStarted(&event); + if (event.wantsGrab()) + grabGesture(); + } + } + + if (ended) emit(touchPointsReleased(_releasedTouchPoints)); + if (moved) emit(touchPointsUpdated(_movedTouchPoints)); + if (started) emit(touchPointsPressed(_pressedTouchPoints)); + if (!_touchPoints.isEmpty()) emit touchUpdated(_touchPoints.values()); + } +} + +void QQuickMultiPointTouchArea::clearTouchLists() +{ + foreach (QObject *obj, _releasedTouchPoints) { + QQuickTouchPoint *dtp = static_cast<QQuickTouchPoint*>(obj); + if (!dtp->isQmlDefined()) + delete dtp; + else + dtp->setValid(false); + } + _releasedTouchPoints.clear(); + _pressedTouchPoints.clear(); + _movedTouchPoints.clear(); +} + +void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p) +{ + QQuickTouchPoint *dtp = 0; + foreach (QQuickTouchPoint* tp, _touchPrototypes) { + if (!tp->isValid()) { + tp->setValid(true); + dtp = tp; + break; + } + } + + if (dtp == 0) + dtp = new QQuickTouchPoint(false); + dtp->setPointId(p->id()); + updateTouchPoint(dtp,p); + _touchPoints.insert(p->id(),dtp); + //we may have just obtained enough points to start tracking them -- in that case moved or stationary count as newly pressed + if (p->state() & Qt::TouchPointPressed || p->state() & Qt::TouchPointMoved || p->state() & Qt::TouchPointStationary) + _pressedTouchPoints.append(dtp); +} + +void QQuickMultiPointTouchArea::addTouchPrototype(QQuickTouchPoint *prototype) +{ + int id = _touchPrototypes.count(); + prototype->setPointId(id); + _touchPrototypes.insert(id, prototype); +} + +void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QTouchEvent::TouchPoint *p) +{ + //TODO: if !qmlDefined, could bypass setters. + // also, should only emit signals after all values have been set + dtp->setX(p->pos().x()); + dtp->setY(p->pos().y()); + dtp->setPressure(p->pressure()); + dtp->setArea(p->rect()); + dtp->setStartX(p->startPos().x()); + dtp->setStartY(p->startPos().y()); + dtp->setPreviousX(p->lastPos().x()); + dtp->setPreviousY(p->lastPos().y()); + dtp->setSceneX(p->scenePos().x()); + dtp->setSceneY(p->scenePos().y()); +} + +void QQuickMultiPointTouchArea::mousePressEvent(QMouseEvent *event) +{ + if (!isEnabled()) { + QQuickItem::mousePressEvent(event); + return; + } + + _stealMouse = false; + setKeepMouseGrab(false); + event->setAccepted(true); +} + +void QQuickMultiPointTouchArea::mouseMoveEvent(QMouseEvent *event) +{ + if (!isEnabled()) { + QQuickItem::mouseMoveEvent(event); + return; + } + + //do nothing +} + +void QQuickMultiPointTouchArea::mouseReleaseEvent(QMouseEvent *event) +{ + _stealMouse = false; + if (!isEnabled()) { + QQuickItem::mouseReleaseEvent(event); + return; + } + QQuickCanvas *c = canvas(); + if (c && c->mouseGrabberItem() == this) + ungrabMouse(); + setKeepMouseGrab(false); +} + +void QQuickMultiPointTouchArea::ungrab() +{ + if (_touchPoints.count()) { + QQuickCanvas *c = canvas(); + if (c && c->mouseGrabberItem() == this) { + _stealMouse = false; + setKeepMouseGrab(false); + } + setKeepTouchGrab(false); + emit touchPointsCanceled(_touchPoints.values()); + clearTouchLists(); + foreach (QObject *obj, _touchPoints) { + QQuickTouchPoint *dtp = static_cast<QQuickTouchPoint*>(obj); + if (!dtp->isQmlDefined()) + delete dtp; + else + dtp->setValid(false); + } + _touchPoints.clear(); + } +} + +void QQuickMultiPointTouchArea::mouseUngrabEvent() +{ + ungrab(); +} + +void QQuickMultiPointTouchArea::touchUngrabEvent() +{ + ungrab(); +} + +bool QQuickMultiPointTouchArea::sendMouseEvent(QMouseEvent *event) +{ + QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height())); + + QQuickCanvas *c = canvas(); + QQuickItem *grabber = c ? c->mouseGrabberItem() : 0; + bool stealThisEvent = _stealMouse; + if ((stealThisEvent || myRect.contains(event->windowPos())) && (!grabber || !grabber->keepMouseGrab())) { + QMouseEvent mouseEvent(event->type(), mapFromScene(event->windowPos()), event->windowPos(), event->screenPos(), + event->button(), event->buttons(), event->modifiers()); + mouseEvent.setAccepted(false); + + switch (mouseEvent.type()) { + case QEvent::MouseMove: + mouseMoveEvent(&mouseEvent); + break; + case QEvent::MouseButtonPress: + mousePressEvent(&mouseEvent); + break; + case QEvent::MouseButtonRelease: + mouseReleaseEvent(&mouseEvent); + break; + default: + break; + } + grabber = c->mouseGrabberItem(); + if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) + grabMouse(); + + return stealThisEvent; + } + if (event->type() == QEvent::MouseButtonRelease) { + _stealMouse = false; + if (c && c->mouseGrabberItem() == this) + ungrabMouse(); + setKeepMouseGrab(false); + } + return false; +} + +bool QQuickMultiPointTouchArea::childMouseEventFilter(QQuickItem *i, QEvent *event) +{ + if (!isEnabled() || !isVisible()) + return QQuickItem::childMouseEventFilter(i, event); + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + return sendMouseEvent(static_cast<QMouseEvent *>(event)); + break; + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + if (!shouldFilter(event)) + return false; + updateTouchData(event); + return _stealMouse; + case QEvent::TouchEnd: { + if (!shouldFilter(event)) + return false; + updateTouchData(event); + //TODO: verify this behavior + _stealMouse = false; + setKeepMouseGrab(false); + QQuickCanvas *c = canvas(); + if (c && c->mouseGrabberItem() == this) + ungrabMouse(); + setKeepTouchGrab(false); + ungrabTouchPoints(); + } + break; + default: + break; + } + return QQuickItem::childMouseEventFilter(i, event); +} + +bool QQuickMultiPointTouchArea::shouldFilter(QEvent *event) +{ + QQuickCanvas *c = canvas(); + QQuickItem *grabber = c ? c->mouseGrabberItem() : 0; + bool disabledItem = grabber && !grabber->isEnabled(); + bool stealThisEvent = _stealMouse; + bool contains = false; + if (!stealThisEvent) { + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: { + QMouseEvent *me = static_cast<QMouseEvent*>(event); + QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height())); + contains = myRect.contains(me->windowPos()); + } + break; + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: { + QTouchEvent *te = static_cast<QTouchEvent*>(event); + QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height())); + foreach (const QTouchEvent::TouchPoint &point, te->touchPoints()) { + if (myRect.contains(point.scenePos())) { + contains = true; + break; + } + } + } + break; + default: + break; + } + } + if ((stealThisEvent || contains) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) { + return true; + } + ungrab(); + return false; +} + +QT_END_NAMESPACE diff --git a/src/declarative/items/qquickmultipointtoucharea_p.h b/src/declarative/items/qquickmultipointtoucharea_p.h new file mode 100644 index 0000000000..dac70453c5 --- /dev/null +++ b/src/declarative/items/qquickmultipointtoucharea_p.h @@ -0,0 +1,267 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKMULTIPOINTTOUCHAREA_H +#define QQUICKMULTIPOINTTOUCHAREA_H + +#include "qquickitem.h" +#include "qevent.h" + +#include <QMap> +#include <QList> +#include <QtGui/qguiapplication.h> +#include <QtGui/qstylehints.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QQuickMultiPointTouchArea; +class Q_AUTOTEST_EXPORT QQuickTouchPoint : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool valid READ isValid NOTIFY validityChanged) + Q_PROPERTY(int pointId READ pointId NOTIFY pointIdChanged) + Q_PROPERTY(qreal x READ x NOTIFY xChanged) + Q_PROPERTY(qreal y READ y NOTIFY yChanged) + Q_PROPERTY(qreal pressure READ pressure NOTIFY pressureChanged) + Q_PROPERTY(QRectF area READ area NOTIFY areaChanged) + + Q_PROPERTY(qreal startX READ startX NOTIFY startXChanged) + Q_PROPERTY(qreal startY READ startY NOTIFY startYChanged) + Q_PROPERTY(qreal previousX READ previousX NOTIFY previousXChanged) + Q_PROPERTY(qreal previousY READ previousY NOTIFY previousYChanged) + Q_PROPERTY(qreal sceneX READ sceneX NOTIFY sceneXChanged) + Q_PROPERTY(qreal sceneY READ sceneY NOTIFY sceneYChanged) + +public: + QQuickTouchPoint(bool qmlDefined = true) + : _id(0), + _x(0.0), _y(0.0), + _pressure(0.0), + _qmlDefined(qmlDefined), + _valid(!qmlDefined), + _previousX(0.0), _previousY(0.0), + _sceneX(0.0), _sceneY(0.0) + {} + + int pointId() const { return _id; } + void setPointId(int id); + + qreal x() const { return _x; } + void setX(qreal x); + + qreal y() const { return _y; } + void setY(qreal y); + + qreal pressure() const { return _pressure; } + void setPressure(qreal pressure); + + QRectF area() const { return _area; } + void setArea(const QRectF &area); + + bool isQmlDefined() { return _qmlDefined; } + + bool isValid() { return _valid; } + void setValid(bool valid); + + qreal startX() const { return _startX; } + void setStartX(qreal startX); + + qreal startY() const { return _startY; } + void setStartY(qreal startY); + + qreal previousX() const { return _previousX; } + void setPreviousX(qreal previousX); + + qreal previousY() const { return _previousY; } + void setPreviousY(qreal previousY); + + qreal sceneX() const { return _sceneX; } + void setSceneX(qreal sceneX); + + qreal sceneY() const { return _sceneY; } + void setSceneY(qreal sceneY); + + +Q_SIGNALS: + void pointIdChanged(); + void xChanged(); + void yChanged(); + void pressureChanged(); + void areaChanged(); + void validityChanged(); + void startXChanged(); + void startYChanged(); + void previousXChanged(); + void previousYChanged(); + void sceneXChanged(); + void sceneYChanged(); + +private: + friend class QQuickMultiPointTouchArea; + int _id; + qreal _x; + qreal _y; + qreal _pressure; + QRectF _area; + bool _qmlDefined; + bool _valid; + qreal _startX; + qreal _startY; + qreal _previousX; + qreal _previousY; + qreal _sceneX; + qreal _sceneY; +}; + +class QQuickGrabGestureEvent : public QObject +{ + Q_OBJECT + Q_PROPERTY(QDeclarativeListProperty<QObject> touchPoints READ touchPoints) + Q_PROPERTY(qreal dragThreshold READ dragThreshold) +public: + QQuickGrabGestureEvent() : _grab(false), _dragThreshold(qApp->styleHints()->startDragDistance()) {} + + Q_INVOKABLE void grab() { _grab = true; } + bool wantsGrab() const { return _grab; } + + QDeclarativeListProperty<QObject> touchPoints() { + return QDeclarativeListProperty<QObject>(this, _touchPoints); + } + qreal dragThreshold() const { return _dragThreshold; } + +private: + friend class QQuickMultiPointTouchArea; + bool _grab; + qreal _dragThreshold; + QList<QObject*> _touchPoints; +}; + +class Q_AUTOTEST_EXPORT QQuickMultiPointTouchArea : public QQuickItem +{ + Q_OBJECT + + Q_PROPERTY(QDeclarativeListProperty<QQuickTouchPoint> touchPoints READ touchPoints) + Q_PROPERTY(int minimumTouchPoints READ minimumTouchPoints WRITE setMinimumTouchPoints NOTIFY minimumTouchPointsChanged) + Q_PROPERTY(int maximumTouchPoints READ maximumTouchPoints WRITE setMaximumTouchPoints NOTIFY maximumTouchPointsChanged) + +public: + QQuickMultiPointTouchArea(QQuickItem *parent=0); + ~QQuickMultiPointTouchArea(); + + int minimumTouchPoints() const; + void setMinimumTouchPoints(int num); + int maximumTouchPoints() const; + void setMaximumTouchPoints(int num); + + QDeclarativeListProperty<QQuickTouchPoint> touchPoints() { + return QDeclarativeListProperty<QQuickTouchPoint>(this, 0, QQuickMultiPointTouchArea::touchPoint_append, QQuickMultiPointTouchArea::touchPoint_count, QQuickMultiPointTouchArea::touchPoint_at, 0); + } + + static void touchPoint_append(QDeclarativeListProperty<QQuickTouchPoint> *list, QQuickTouchPoint* touch) { + QQuickMultiPointTouchArea *q = static_cast<QQuickMultiPointTouchArea*>(list->object); + q->addTouchPrototype(touch); + } + + static int touchPoint_count(QDeclarativeListProperty<QQuickTouchPoint> *list) { + QQuickMultiPointTouchArea *q = static_cast<QQuickMultiPointTouchArea*>(list->object); + return q->_touchPrototypes.count(); + } + + static QQuickTouchPoint* touchPoint_at(QDeclarativeListProperty<QQuickTouchPoint> *list, int index) { + QQuickMultiPointTouchArea *q = static_cast<QQuickMultiPointTouchArea*>(list->object); + return q->_touchPrototypes[index]; + } + +Q_SIGNALS: + void touchPointsPressed(const QList<QObject*> &touchPoints); + void touchPointsUpdated(const QList<QObject*> &touchPoints); + void touchPointsReleased(const QList<QObject*> &touchPoints); + void touchPointsCanceled(const QList<QObject*> &touchPoints); + void gestureStarted(QQuickGrabGestureEvent *gesture); + void touchUpdated(const QList<QObject*> &touchPoints); + void minimumTouchPointsChanged(); + void maximumTouchPointsChanged(); + +protected: + void touchEvent(QTouchEvent *); + bool childMouseEventFilter(QQuickItem *i, QEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseUngrabEvent(); + void touchUngrabEvent(); + + void addTouchPrototype(QQuickTouchPoint* prototype); + void addTouchPoint(const QTouchEvent::TouchPoint *p); + void clearTouchLists(); + + void updateTouchPoint(QQuickTouchPoint*, const QTouchEvent::TouchPoint*); + void updateTouchData(QEvent*); + + bool sendMouseEvent(QMouseEvent *event); + bool shouldFilter(QEvent *event); + void grabGesture(); + +private: + void ungrab(); + QMap<int,QQuickTouchPoint*> _touchPrototypes; //TouchPoints defined in QML + QMap<int,QObject*> _touchPoints; //All current touch points + QList<QObject*> _releasedTouchPoints; + QList<QObject*> _pressedTouchPoints; + QList<QObject*> _movedTouchPoints; + int _minimumTouchPoints; + int _maximumTouchPoints; + bool _stealMouse; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickTouchPoint) +QML_DECLARE_TYPE(QQuickGrabGestureEvent) +QML_DECLARE_TYPE(QQuickMultiPointTouchArea) + +QT_END_HEADER + +#endif // QQUICKMULTIPOINTTOUCHAREA_H diff --git a/src/declarative/items/qquickpainteditem.cpp b/src/declarative/items/qquickpainteditem.cpp index ac67f6a8d0..4d96da2e1a 100644 --- a/src/declarative/items/qquickpainteditem.cpp +++ b/src/declarative/items/qquickpainteditem.cpp @@ -123,8 +123,6 @@ QQuickPaintedItemPrivate::QQuickPaintedItemPrivate() , fillColor(Qt::transparent) , renderTarget(QQuickPaintedItem::Image) , performanceHints(0) - , geometryDirty(false) - , contentsDirty(false) , opaquePainting(false) , antialiasing(false) , mipmap(false) @@ -171,7 +169,6 @@ QQuickPaintedItem::~QQuickPaintedItem() void QQuickPaintedItem::update(const QRect &rect) { Q_D(QQuickPaintedItem); - d->contentsDirty = true; if (rect.isNull() && !d->dirtyRect.isNull()) d->dirtyRect = contentsBoundingRect().toAlignedRect(); @@ -492,17 +489,6 @@ void QQuickPaintedItem::setRenderTarget(RenderTarget target) */ /*! - This function is called after the item's geometry has changed. -*/ -void QQuickPaintedItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) -{ - Q_D(QQuickPaintedItem); - d->geometryDirty = true; - QQuickItem::geometryChanged(newGeometry, oldGeometry); -} - - -/*! This function is called when the Scene Graph node associated to the item needs to be updated. */ @@ -531,11 +517,9 @@ QSGNode *QQuickPaintedItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat node->setOpaquePainting(d->opaquePainting); node->setFillColor(d->fillColor); node->setContentsScale(d->contentsScale); - node->setDirty(d->contentsDirty || d->geometryDirty, d->dirtyRect); + node->setDirty(d->dirtyRect); node->update(); - d->contentsDirty = false; - d->geometryDirty = false; d->dirtyRect = QRect(); return node; diff --git a/src/declarative/items/qquickpainteditem.h b/src/declarative/items/qquickpainteditem.h index 1ddfa25c5e..b2da9e6c7a 100644 --- a/src/declarative/items/qquickpainteditem.h +++ b/src/declarative/items/qquickpainteditem.h @@ -114,7 +114,6 @@ Q_SIGNALS: protected: QQuickPaintedItem(QQuickPaintedItemPrivate &dd, QQuickItem *parent = 0); - virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); private: diff --git a/src/declarative/items/qquickpainteditem_p.h b/src/declarative/items/qquickpainteditem_p.h index 00061d9977..b847b0a4ef 100644 --- a/src/declarative/items/qquickpainteditem_p.h +++ b/src/declarative/items/qquickpainteditem_p.h @@ -61,8 +61,6 @@ public: QRect dirtyRect; - bool geometryDirty : 1; - bool contentsDirty : 1; bool opaquePainting: 1; bool antialiasing: 1; bool mipmap: 1; diff --git a/src/declarative/items/qquickpathview.cpp b/src/declarative/items/qquickpathview.cpp index dc73bf2dd3..c4da6f5a4c 100644 --- a/src/declarative/items/qquickpathview.cpp +++ b/src/declarative/items/qquickpathview.cpp @@ -494,7 +494,7 @@ void QQuickPathView::setModel(const QVariant &model) disconnect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*))); for (int i=0; i<d->items.count(); i++){ QQuickItem *p = d->items[i]; - d->model->release(p); + d->releaseItem(p); } d->items.clear(); } @@ -1537,9 +1537,12 @@ void QQuickPathView::modelUpdated(const QDeclarativeChangeSet &changeSet, bool r if (d->modelCount) { if (moveId == -1 && i.index <= d->currentIndex) { d->currentIndex += i.count; + currentChanged = true; } else if (d->offset != 0) { - if (moveId != -1 && moveId == i.moveId) + if (moveId != -1 && moveId == i.moveId) { d->currentIndex = i.index + moveOffset; + currentChanged = true; + } d->offset += i.count; d->offsetAdj += i.count; } @@ -1558,13 +1561,20 @@ void QQuickPathView::modelUpdated(const QDeclarativeChangeSet &changeSet, bool r d->tl.reset(d->moveOffset); } else if (removed) { d->regenerate(); - d->updateCurrent(); - if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) - d->snapToCurrent(); + if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) { + qreal targetOffset = qmlMod(d->modelCount - d->currentIndex, d->modelCount); + if (targetOffset != d->offset) + d->tl.set(d->moveOffset, targetOffset); + } } else if (inserted) { d->firstIndex = -1; d->updateMappedRange(); d->scheduleLayout(); + if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) { + qreal targetOffset = qmlMod(d->modelCount - d->currentIndex, d->modelCount); + if (targetOffset != d->offset) + d->tl.set(d->moveOffset, targetOffset); + } } if (changedOffset) emit offsetChanged(); @@ -1698,6 +1708,9 @@ void QQuickPathViewPrivate::snapToCurrent() qreal targetOffset = qmlMod(modelCount - currentIndex, modelCount); + if (offset == targetOffset) + return; + moveReason = Other; offsetAdj = 0.0; tl.reset(moveOffset); diff --git a/src/declarative/items/qquickpincharea.cpp b/src/declarative/items/qquickpincharea.cpp index c1f60ae640..beacbe32bf 100644 --- a/src/declarative/items/qquickpincharea.cpp +++ b/src/declarative/items/qquickpincharea.cpp @@ -194,7 +194,7 @@ QQuickPinchAreaPrivate::~QQuickPinchAreaPrivate() 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. + will be canceled and no further events will be sent. */ /*! diff --git a/src/declarative/items/qquickpositioners.cpp b/src/declarative/items/qquickpositioners.cpp index 15cd35c2f0..8d204931ef 100644 --- a/src/declarative/items/qquickpositioners.cpp +++ b/src/declarative/items/qquickpositioners.cpp @@ -616,7 +616,7 @@ void QQuickColumn::reportConflictingAnchors() will not change. If you manually change the x or y properties in script, bind the x or y properties, use anchors on a child of a positioner, or have the width of a child depend on the position of a child, then the - positioner may exhibit strange behaviour. If you need to perform any of these + positioner may exhibit strange behavior. If you need to perform any of these actions, consider positioning the items without the use of a Row. Items with a width or height of 0 will not be positioned. @@ -851,7 +851,7 @@ void QQuickRow::reportConflictingAnchors() will not change. If you manually change the x or y properties in script, bind the x or y properties, use anchors on a child of a positioner, or have the width or height of a child depend on the position of a child, then the - positioner may exhibit strange behaviour. If you need to perform any of these + positioner may exhibit strange behavior. If you need to perform any of these actions, consider positioning the items without the use of a Grid. Items with a width or height of 0 will not be positioned. @@ -1282,7 +1282,7 @@ void QQuickGrid::reportConflictingAnchors() will not change. If you manually change the x or y properties in script, bind the x or y properties, use anchors on a child of a positioner, or have the width or height of a child depend on the position of a child, then the - positioner may exhibit strange behaviour. If you need to perform any of these + positioner may exhibit strange behavior. If you need to perform any of these actions, consider positioning the items without the use of a Flow. Items with a width or height of 0 will not be positioned. diff --git a/src/declarative/items/qquickrectangle.cpp b/src/declarative/items/qquickrectangle.cpp index a7f592eac3..c3cbaaa00e 100644 --- a/src/declarative/items/qquickrectangle.cpp +++ b/src/declarative/items/qquickrectangle.cpp @@ -294,7 +294,7 @@ int QQuickRectanglePrivate::doUpdateSlotIdx = -1; the gradient is used. You can add an optional border to a rectangle with its own color and thickness - by settting the \l border.color and \l border.width properties. + by setting the \l border.color and \l border.width properties. You can also create rounded rectangles using the \l radius property. Since this introduces curved edges to the corners of a rectangle, it may be appropriate to @@ -492,7 +492,8 @@ QSGNode *QQuickRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData Q_UNUSED(data); Q_D(QQuickRectangle); - if (width() <= 0 || height() <= 0) { + if (width() <= 0 || height() <= 0 + || (d->color.alpha() == 0 && (!d->pen || d->pen->width() == 0 || d->pen->color().alpha() == 0))) { delete oldNode; return 0; } @@ -542,7 +543,7 @@ QSGNode *QQuickRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData filtering at the beginning of the animation and reenable it at the conclusion. \image rect-smooth.png - On this image, smooth is turned off on the top half and on on the bottom half. + On this image, smooth is turned off for the top half and on for the bottom half. */ QRectF QQuickRectangle::boundingRect() const diff --git a/src/declarative/items/qquickshadereffect.cpp b/src/declarative/items/qquickshadereffect.cpp index a3b57be1eb..03247f9956 100644 --- a/src/declarative/items/qquickshadereffect.cpp +++ b/src/declarative/items/qquickshadereffect.cpp @@ -229,6 +229,7 @@ void QQuickShaderEffect::setFragmentShader(const QByteArray &code) if (isComponentComplete()) { reset(); updateProperties(); + update(); } emit fragmentShaderChanged(); } @@ -250,6 +251,7 @@ void QQuickShaderEffect::setVertexShader(const QByteArray &code) if (isComponentComplete()) { reset(); updateProperties(); + update(); } emit vertexShaderChanged(); } @@ -632,7 +634,7 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa } for (int i = 0; i < m_sources.size(); ++i) { const SourceData &source = m_sources.at(i); - QSGTextureProvider *t = source.sourceObject->textureProvider(); + QSGTextureProvider *t = source.sourceObject ? source.sourceObject->textureProvider() : 0; textures.append(qMakePair(source.name, t)); if (t) connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection); diff --git a/src/declarative/items/qquickshadereffectmesh.cpp b/src/declarative/items/qquickshadereffectmesh.cpp index 79b37d40bd..7709bed614 100644 --- a/src/declarative/items/qquickshadereffectmesh.cpp +++ b/src/declarative/items/qquickshadereffectmesh.cpp @@ -76,6 +76,7 @@ QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, const QVector if (!geometry) { bool error = true; + Q_UNUSED(error) switch (attrCount) { case 0: qWarning("QQuickGridMesh:: No attributes specified."); diff --git a/src/declarative/items/qquickshadereffectnode.cpp b/src/declarative/items/qquickshadereffectnode.cpp index 67ca124c91..923a180a1b 100644 --- a/src/declarative/items/qquickshadereffectnode.cpp +++ b/src/declarative/items/qquickshadereffectnode.cpp @@ -117,7 +117,7 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri continue; } } - qWarning("ShaderEffectItem: source or provider missing when binding textures"); + qWarning("ShaderEffect: source or provider missing when binding textures"); glBindTexture(GL_TEXTURE_2D, 0); } diff --git a/src/declarative/items/qquickshadereffectsource.cpp b/src/declarative/items/qquickshadereffectsource.cpp index 587f7bad98..351ea34bbc 100644 --- a/src/declarative/items/qquickshadereffectsource.cpp +++ b/src/declarative/items/qquickshadereffectsource.cpp @@ -216,7 +216,7 @@ void QQuickShaderEffectTexture::scheduleUpdate() return; m_grab = true; if (m_dirtyTexture) - emit textureChanged(); + emit updateRequested(); } void QQuickShaderEffectTexture::setRecursive(bool recursive) @@ -228,7 +228,7 @@ void QQuickShaderEffectTexture::markDirtyTexture() { m_dirtyTexture = true; if (m_live || m_grab) - emit textureChanged(); + emit updateRequested(); } void QQuickShaderEffectTexture::grab() @@ -238,6 +238,8 @@ void QQuickShaderEffectTexture::grab() delete m_secondaryFbo; m_fbo = m_secondaryFbo = 0; m_dirtyTexture = false; + if (m_grab) + emit scheduledUpdateCompleted(); return; } QSGNode *root = m_item; @@ -246,16 +248,9 @@ void QQuickShaderEffectTexture::grab() if (root->type() != QSGNode::RootNodeType) return; - if (m_size.isEmpty()) { - delete m_fbo; - delete m_secondaryFbo; - m_secondaryFbo = m_fbo = 0; - return; - } - if (!m_renderer) { m_renderer = m_context->createRenderer(); - connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture()), Qt::DirectConnection); + connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture())); } m_renderer->setRootNode(static_cast<QSGRootNode *>(root)); @@ -388,6 +383,9 @@ void QQuickShaderEffectTexture::grab() #endif if (m_recursive) markDirtyTexture(); // Continuously update if 'live' and 'recursive'. + + if (m_grab) + emit scheduledUpdateCompleted(); } QImage QQuickShaderEffectTexture::toImage() const @@ -516,7 +514,8 @@ void QQuickShaderEffectSource::ensureTexture() "Cannot be used outside the rendering thread"); m_texture = new QQuickShaderEffectTexture(this); - connect(m_texture, SIGNAL(textureChanged()), this, SLOT(update())); + connect(m_texture, SIGNAL(updateRequested()), this, SLOT(update())); + connect(m_texture, SIGNAL(scheduledUpdateCompleted()), this, SIGNAL(scheduledUpdateCompleted())); } QSGTextureProvider *QQuickShaderEffectSource::textureProvider() const @@ -529,9 +528,8 @@ QSGTextureProvider *QQuickShaderEffectSource::textureProvider() const "QQuickShaderEffectSource::textureProvider", "Cannot be used outside the rendering thread"); const_cast<QQuickShaderEffectSource *>(this)->m_provider = new QQuickShaderEffectSourceTextureProvider(); - const_cast<QQuickShaderEffectSource *>(this)->ensureTexture(); - connect(m_texture, SIGNAL(textureChanged()), m_provider, SIGNAL(textureChanged()), Qt::DirectConnection); + connect(m_texture, SIGNAL(updateRequested()), m_provider, SIGNAL(textureChanged())); m_provider->sourceTexture = m_texture; } return m_provider; @@ -884,7 +882,7 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint if (!node) { node = new QQuickShaderEffectSourceNode; node->setTexture(m_texture); - connect(m_texture, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection); + connect(m_texture, SIGNAL(updateRequested()), node, SLOT(markDirtyTexture())); } // If live and recursive, update continuously. diff --git a/src/declarative/items/qquickshadereffectsource_p.h b/src/declarative/items/qquickshadereffectsource_p.h index 8117c06b9c..b61170ace8 100644 --- a/src/declarative/items/qquickshadereffectsource_p.h +++ b/src/declarative/items/qquickshadereffectsource_p.h @@ -119,7 +119,8 @@ public: QImage toImage() const; Q_SIGNALS: - void textureChanged(); + void updateRequested(); + void scheduledUpdateCompleted(); public Q_SLOTS: void markDirtyTexture(); @@ -226,7 +227,7 @@ Q_SIGNALS: void mipmapChanged(); void recursiveChanged(); - void textureChanged(); + void scheduledUpdateCompleted(); protected: virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); diff --git a/src/declarative/items/qquickspriteengine.cpp b/src/declarative/items/qquickspriteengine.cpp index 9cf21eb2d9..c25ccf3487 100644 --- a/src/declarative/items/qquickspriteengine.cpp +++ b/src/declarative/items/qquickspriteengine.cpp @@ -48,9 +48,9 @@ QT_BEGIN_NAMESPACE -/* TODO: Split out image logic from stochastic state logic - Also make sharable - Also solve the state data initialization/transfer issue so as to not need to make friends +/* TODO: + make sharable? + solve the state data initialization/transfer issue so as to not need to make friends */ QQuickStochasticEngine::QQuickStochasticEngine(QObject *parent) : @@ -177,7 +177,8 @@ int QQuickSpriteEngine::spriteCount()//TODO: Actually image state count, need to void QQuickStochasticEngine::setGoal(int state, int sprite, bool jump) { - if (sprite >= m_things.count() || state >= m_states.count()) + if (sprite >= m_things.count() || state >= m_states.count() + || sprite < 0 || state < 0) return; if (!jump){ m_goals[sprite] = state; diff --git a/src/declarative/items/qquickspriteengine_p.h b/src/declarative/items/qquickspriteengine_p.h index 44f82044da..1040140a28 100644 --- a/src/declarative/items/qquickspriteengine_p.h +++ b/src/declarative/items/qquickspriteengine_p.h @@ -212,8 +212,6 @@ public: int count() const {return m_things.count();} void setCount(int c); - - void setGoal(int state, int sprite=0, bool jump=false); void start(int index=0, int state=0); void stop(int index=0); @@ -221,6 +219,13 @@ public: QQuickStochasticState* state(int idx){return m_states[idx];} int stateIndex(QQuickStochasticState* s){return m_states.indexOf(s);} + int stateIndex(const QString& s) { + for (int i=0; i<m_states.count(); i++) + if (m_states[i]->name() == s) + return i; + return -1; + } + int stateCount() {return m_states.count();} private: signals: diff --git a/src/declarative/items/qquickspriteimage.cpp b/src/declarative/items/qquickspriteimage.cpp index 36ab73490c..1bfb80944c 100644 --- a/src/declarative/items/qquickspriteimage.cpp +++ b/src/declarative/items/qquickspriteimage.cpp @@ -151,7 +151,7 @@ QQuickSpriteMaterial::~QQuickSpriteMaterial() class SpriteMaterialData : public QSGMaterialShader { public: - SpriteMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0) + SpriteMaterialData(const char * /* vertexFile */ = 0, const char * /* fragmentFile */ = 0) { } @@ -250,6 +250,24 @@ struct SpriteVertices { Default is true. */ /*! + \qmlproperty string QtQuick2::SpriteImage::goalState + + The name of the Sprite which the animation should move to. + + Sprite states have defined durations and transitions between them, setting goalState + will cause it to disregard any path weightings (including 0) and head down the path + which will reach the goalState quickest (fewest animations). It will pass through + intermediate states on that path, and animate them for their duration. + + If it is possible to return to the goalState from the starting point of the goalState + it will continue to do so until goalState is set to "" or an unreachable state. +*/ +/*! \qmlmethod void QtQuick2::SpriteImage::jumpTo(string sprite) + + This function causes the sprite to jump to the specified state immediately, intermediate + states are not played. +*/ +/*! \qmlproperty list<Sprite> QtQuick2::SpriteImage::sprites The sprite or sprites to draw. Sprites will be scaled to the size of this element. @@ -270,6 +288,22 @@ QQuickSpriteImage::QQuickSpriteImage(QQuickItem *parent) : this, SLOT(update())); } +void QQuickSpriteImage::jumpTo(const QString &sprite) +{ + if (!m_spriteEngine) + return; + m_spriteEngine->setGoal(m_spriteEngine->stateIndex(sprite), 0, true); +} + +void QQuickSpriteImage::setGoalState(const QString &sprite) +{ + if (m_goalState != sprite){ + m_goalState = sprite; + emit goalStateChanged(sprite); + m_spriteEngine->setGoal(m_spriteEngine->stateIndex(sprite)); + } +} + QDeclarativeListProperty<QQuickSprite> QQuickSpriteImage::sprites() { return QDeclarativeListProperty<QQuickSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear); @@ -404,7 +438,6 @@ void QQuickSpriteImage::prepareNextFrame() m_material->interpolate = m_interpolate; //Advance State - SpriteVertices *p = (SpriteVertices *) m_node->geometry()->vertexData(); m_spriteEngine->updateSprites(timeInt); int curY = m_spriteEngine->spriteY(); if (curY != m_material->animY){ diff --git a/src/declarative/items/qquickspriteimage_p.h b/src/declarative/items/qquickspriteimage_p.h index 1ffc95d952..39384cedca 100644 --- a/src/declarative/items/qquickspriteimage_p.h +++ b/src/declarative/items/qquickspriteimage_p.h @@ -56,11 +56,12 @@ class QQuickSprite; class QQuickSpriteEngine; class QSGGeometryNode; class QQuickSpriteMaterial; -class QQuickSpriteImage : public QQuickItem +class Q_AUTOTEST_EXPORT QQuickSpriteImage : public QQuickItem { Q_OBJECT Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged) Q_PROPERTY(bool interpolate READ interpolate WRITE setInterpolate NOTIFY interpolateChanged) + Q_PROPERTY(QString goalState READ goalState WRITE setGoalState NOTIFY goalStateChanged) //###try to share similar spriteEngines for less overhead? Q_PROPERTY(QDeclarativeListProperty<QQuickSprite> sprites READ sprites) Q_CLASSINFO("DefaultProperty", "sprites") @@ -80,28 +81,37 @@ public: return m_interpolate; } + QString goalState() const + { + return m_goalState; + } + signals: void runningChanged(bool arg); void interpolateChanged(bool arg); + void goalStateChanged(QString arg); public slots: -void setRunning(bool arg) -{ - if (m_running != arg) { - m_running = arg; - emit runningChanged(arg); + void jumpTo(const QString &sprite); + void setGoalState(const QString &sprite); + + void setRunning(bool arg) + { + if (m_running != arg) { + m_running = arg; + emit runningChanged(arg); + } } -} -void setInterpolate(bool arg) -{ - if (m_interpolate != arg) { - m_interpolate = arg; - emit interpolateChanged(arg); + void setInterpolate(bool arg) + { + if (m_interpolate != arg) { + m_interpolate = arg; + emit interpolateChanged(arg); + } } -} private slots: void createEngine(); @@ -120,6 +130,7 @@ private: bool m_pleaseReset; bool m_running; bool m_interpolate; + QString m_goalState; }; QT_END_NAMESPACE diff --git a/src/declarative/items/qquicktext.cpp b/src/declarative/items/qquicktext.cpp index bf736e6a10..26f95438cb 100644 --- a/src/declarative/items/qquicktext.cpp +++ b/src/declarative/items/qquicktext.cpp @@ -683,14 +683,14 @@ QPixmap QQuickTextPrivate::textLayoutImage(bool drawStyle) QPixmap img(size); if (!size.isEmpty()) { img.fill(Qt::transparent); -#ifdef Q_WS_MAC +/*#ifdef Q_OS_MAC // Fails on CocoaX64 bool oldSmooth = qt_applefontsmoothing_enabled; qt_applefontsmoothing_enabled = false; -#endif +#endif*/ QPainter p(&img); -#ifdef Q_WS_MAC +/*#ifdef Q_OS_MAC // Fails on CocoaX64 qt_applefontsmoothing_enabled = oldSmooth; -#endif +#endif*/ drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle); } return img; @@ -723,14 +723,14 @@ QPixmap QQuickTextPrivate::textDocumentImage(bool drawStyle) //paint text QPixmap img(size); img.fill(Qt::transparent); -#ifdef Q_WS_MAC +/*#ifdef Q_OS_MAC // Fails on CocoaX64 bool oldSmooth = qt_applefontsmoothing_enabled; qt_applefontsmoothing_enabled = false; -#endif +#endif*/ QPainter p(&img); -#ifdef Q_WS_MAC +/*#ifdef Q_OS_MAC // Fails on CocoaX64 qt_applefontsmoothing_enabled = oldSmooth; -#endif +#endif*/ QAbstractTextDocumentLayout::PaintContext context; @@ -1728,7 +1728,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data if (d->richText) { d->ensureDoc(); - node->addTextDocument(bounds.topLeft(), d->doc, QColor(), d->style, d->styleColor); + node->addTextDocument(bounds.topLeft(), d->doc, d->color, d->style, d->styleColor); } else { node->addTextLayout(QPoint(0, bounds.y()), &d->layout, d->color, d->style, d->styleColor); diff --git a/src/declarative/items/qquicktextedit.cpp b/src/declarative/items/qquicktextedit.cpp index 75f60bc08c..18d2cb8ede 100644 --- a/src/declarative/items/qquicktextedit.cpp +++ b/src/declarative/items/qquicktextedit.cpp @@ -550,7 +550,15 @@ bool QQuickTextEditPrivate::determineHorizontalAlignment() { Q_Q(QQuickTextEdit); if (hAlignImplicit && q->isComponentComplete()) { - bool alignToRight = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText; + bool alignToRight; + if (text.isEmpty()) { + const QString preeditText = control->textCursor().block().layout()->preeditAreaText(); + alignToRight = preeditText.isEmpty() + ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft + : preeditText.isRightToLeft(); + } else { + alignToRight = rightToLeftText; + } return setHAlign(alignToRight ? QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft); } return false; @@ -717,7 +725,7 @@ int QQuickTextEdit::positionAt(int x, int y) const \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at the previous cursor position) to the specified position. \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all - words between the specified postion and the previous cursor position. Words partially in the + words between the specified position and the previous cursor position. Words partially in the range are included. \endlist @@ -1396,7 +1404,6 @@ void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event) void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value) { - Q_D(QQuickTextEdit); if (change == ItemActiveFocusHasChanged) { setCursorVisible(value.boolValue); // ### refactor: focus handling && d->canvas && d->canvas->hasFocus()); } @@ -1490,7 +1497,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * } else if (oldNode == 0 || d->documentDirty) { d->documentDirty = false; -#if defined(Q_WS_MAC) +#if defined(Q_OS_MAC) // Make sure document is relayouted in the paint node on Mac // to avoid crashes due to the font engines created in the // shaping process @@ -1519,7 +1526,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * selectionEnd() - 1); // selectionEnd() returns first char after // selection -#if defined(Q_WS_MAC) +#if defined(Q_OS_MAC) // We also need to make sure the document layout is redone when // control is returned to the main thread, as all the font engines // are now owned by the rendering thread @@ -1873,9 +1880,7 @@ void QQuickTextEditPrivate::updateDefaultTextOption() customizing when you want the input keyboard to be shown and hidden in your application. - By default the opening of input panels follows the platform style. On Symbian^1 and - Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms - the panels are automatically opened when TextEdit element gains active focus. Input panels are + By default the opening of input panels follows the platform style. Input panels are always closed if no editor has active focus. You can disable the automatic behavior by setting the property \c activeFocusOnPress to false @@ -1918,9 +1923,7 @@ void QQuickTextEdit::openSoftwareInputPanel() for customizing when you want the input keyboard to be shown and hidden in your application. - By default the opening of input panels follows the platform style. On Symbian^1 and - Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms - the panels are automatically opened when TextEdit element gains active focus. Input panels are + By default the opening of input panels follows the platform style. Input panels are always closed if no editor has active focus. You can disable the automatic behavior by setting the property \c activeFocusOnPress to false diff --git a/src/declarative/items/qquicktextinput.cpp b/src/declarative/items/qquicktextinput.cpp index e28832ed4e..69f699446a 100644 --- a/src/declarative/items/qquicktextinput.cpp +++ b/src/declarative/items/qquicktextinput.cpp @@ -871,7 +871,7 @@ void QQuickTextInputPrivate::updateInputMethodHints() Specifies how the text should be displayed in the TextInput. \list \o TextInput.Normal - Displays the text as it is. (Default) - \o TextInput.Password - Displays asterixes instead of characters. + \o TextInput.Password - Displays asterisks instead of characters. \o TextInput.NoEcho - Displays nothing. \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered while editing, otherwise displays asterisks. @@ -1162,16 +1162,9 @@ void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event) bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event) { #if !defined QT_NO_IM - if (control->composeMode() && event->type() == QEvent::KeyRelease) { + if (control->composeMode() && event->type() == QEvent::MouseButtonRelease) { int tmp_cursor = xToPos(event->localPos().x()); int mousePos = tmp_cursor - control->cursor(); - if (mousePos < 0 || mousePos > control->preeditAreaText().length()) { - mousePos = -1; - // don't send move events outside the preedit area - if (event->type() == QEvent::MouseMove) - return true; - } - // may be causing reset() in some input methods qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos); if (!control->preeditAreaText().isEmpty()) @@ -1616,7 +1609,7 @@ void QQuickTextInput::moveCursorSelection(int position) \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at the previous cursor position) to the specified position. \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all - words between the specified postion and the previous cursor position. Words partially in the + words between the specified position and the previous cursor position. Words partially in the range are included. \endlist @@ -1699,12 +1692,10 @@ void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode) customizing when you want the input keyboard to be shown and hidden in your application. - By default the opening of input panels follows the platform style. On Symbian^1 and - Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms - the panels are automatically opened when TextInput element gains active focus. Input panels are + By default the opening of input panels follows the platform style. Input panels are always closed if no editor has active focus. - . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false + You can disable the automatic behavior by setting the property \c activeFocusOnPress to false and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement the behavior you want. @@ -1744,12 +1735,10 @@ void QQuickTextInput::openSoftwareInputPanel() for customizing when you want the input keyboard to be shown and hidden in your application. - By default the opening of input panels follows the platform style. On Symbian^1 and - Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms - the panels are automatically opened when TextInput element gains active focus. Input panels are + By default the opening of input panels follows the platform style. Input panels are always closed if no editor has active focus. - . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false + You can disable the automatic behavior by setting the property \c activeFocusOnPress to false and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement the behavior you want. @@ -1826,9 +1815,6 @@ bool QQuickTextInput::isInputMethodComposing() const void QQuickTextInputPrivate::init() { Q_Q(QQuickTextInput); -#if defined(Q_WS_MAC) - control->setThreadChecks(true); -#endif control->setParent(q);//Now mandatory due to accessibility changes control->setCursorWidth(1); control->setPasswordCharacter(QLatin1Char('*')); diff --git a/src/declarative/items/qquicktextnode.cpp b/src/declarative/items/qquicktextnode.cpp index fab592ffdc..5cc372f9e1 100644 --- a/src/declarative/items/qquicktextnode.cpp +++ b/src/declarative/items/qquicktextnode.cpp @@ -1174,8 +1174,10 @@ void QQuickTextNode::addTextDocument(const QPointF &, QTextDocument *textDocumen } textPos += text.length(); } else { - if (!textColor.isValid()) + if (charFormat.foreground().style() != Qt::NoBrush) engine.setTextColor(charFormat.foreground().color()); + else + engine.setTextColor(textColor); int fragmentEnd = textPos + fragment.length(); if (preeditPosition >= 0 diff --git a/src/declarative/items/qquickview.cpp b/src/declarative/items/qquickview.cpp index cc87b775a5..bf01a895a6 100644 --- a/src/declarative/items/qquickview.cpp +++ b/src/declarative/items/qquickview.cpp @@ -54,12 +54,8 @@ #include <QtCore/qbasictimer.h> -// XXX todo - This whole class should probably be merged with QDeclarativeView for -// maximum seamlessness QT_BEGIN_NAMESPACE -DEFINE_BOOL_CONFIG_OPTION(frameRateDebug, QML_SHOW_FRAMERATE) - void QQuickViewPrivate::init() { Q_Q(QQuickView); @@ -73,7 +69,7 @@ void QQuickViewPrivate::init() } QQuickViewPrivate::QQuickViewPrivate() - : root(0), component(0), resizeMode(QQuickView::SizeViewToRootObject), initialSize(0,0), resized(false) + : root(0), component(0), resizeMode(QQuickView::SizeViewToRootObject), initialSize(0,0) { } @@ -117,6 +113,48 @@ void QQuickViewPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRectF QQuickItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry); } +/*! + \class QQuickView + \since QtQuick 2.0 + \brief The QQuickView class provides a window for displaying a Qt Quick user interface. + + This is a convenience subclass of QQuickCanvas which + will automatically load and display a QML scene when given the URL of the main source file. Alternatively, + you can instantiate your own objects using QDeclarativeComponent and place them in a manually setup QQuickCanvas. + + Typical usage: + + \code + QQuickView *view = new QQuickView; + view->setSource(QUrl::fromLocalFile("myqmlfile.qml")); + view->show(); + \endcode + + To receive errors related to loading and executing QML with QQuickView, + you can connect to the statusChanged() signal and monitor for QQuickView::Error. + The errors are available via QQuickView::errors(). + + \sa {Using QML Bindings in C++ Applications} +*/ + + +/*! \fn void QQuickView::sceneResized(QSize size) + This signal is emitted when the view is resized to \a size. +*/ + +/*! \fn void QQuickView::statusChanged(QQuickView::Status status) + This signal is emitted when the component's current \a status changes. +*/ + +/*! \fn void QQuickView::initialSizeChanged(QSize size) + \internal +*/ + +/*! + \fn QQuickView::QQuickView(QWindow *parent) + + Constructs a QQuickView with the given \a parent. +*/ QQuickView::QQuickView(QWindow *parent, Qt::WindowFlags f) : QQuickCanvas(*(new QQuickViewPrivate), parent) { @@ -124,6 +162,11 @@ QQuickView::QQuickView(QWindow *parent, Qt::WindowFlags f) d_func()->init(); } +/*! + \fn QQuickView::QQuickView(const QUrl &source, QWidget *parent) + + Constructs a QQuickView with the given QML \a source and \a parent. +*/ QQuickView::QQuickView(const QUrl &source, QWindow *parent, Qt::WindowFlags f) : QQuickCanvas(*(new QQuickViewPrivate), parent) { @@ -136,6 +179,24 @@ QQuickView::~QQuickView() { } +/*! \property QQuickView::source + \brief The URL of the source of the QML component. + + Changing this property causes the QML component to be reloaded. + + Ensure that the URL provided is full and correct, in particular, use + \l QUrl::fromLocalFile() when loading a file from the local filesystem. + */ + +/*! + Sets the source to the \a url, loads the QML component and instantiates it. + + Ensure that the URL provided is full and correct, in particular, use + \l QUrl::fromLocalFile() when loading a file from the local filesystem. + + Calling this methods multiple times with the same url will result + in the QML being reloaded. + */ void QQuickView::setSource(const QUrl& url) { Q_D(QQuickView); @@ -143,24 +204,64 @@ void QQuickView::setSource(const QUrl& url) d->execute(); } +/*! + Returns the source URL, if set. + + \sa setSource() + */ QUrl QQuickView::source() const { Q_D(const QQuickView); return d->source; } +/*! + Returns a pointer to the QDeclarativeEngine used for instantiating + QML Components. + */ QDeclarativeEngine* QQuickView::engine() const { Q_D(const QQuickView); return const_cast<QDeclarativeEngine *>(&d->engine); } +/*! + This function returns the root of the context hierarchy. Each QML + component is instantiated in a QDeclarativeContext. QDeclarativeContext's are + essential for passing data to QML components. In QML, contexts are + arranged hierarchically and this hierarchy is managed by the + QDeclarativeEngine. + */ QDeclarativeContext* QQuickView::rootContext() const { Q_D(const QQuickView); return d->engine.rootContext(); } +/*! + \enum QQuickView::Status + Specifies the loading status of the QQuickView. + + \value Null This QQuickView has no source set. + \value Ready This QQuickView has loaded and created the QML component. + \value Loading This QQuickView is loading network data. + \value Error One or more errors has occurred. Call errors() to retrieve a list + of errors. +*/ + +/*! \enum QQuickView::ResizeMode + + This enum specifies how to resize the view. + + \value SizeViewToRootObject The view resizes with the root item in the QML. + \value SizeRootObjectToView The view will automatically resize the root item to the size of the view. +*/ + +/*! + \property QQuickView::status + The component's current \l{QQuickView::Status} {status}. +*/ + QQuickView::Status QQuickView::status() const { Q_D(const QQuickView); @@ -170,6 +271,10 @@ QQuickView::Status QQuickView::status() const return QQuickView::Status(d->component->status()); } +/*! + Return the list of errors that occurred during the last compile or create + operation. When the status is not Error, an empty list is returned. +*/ QList<QDeclarativeError> QQuickView::errors() const { Q_D(const QQuickView); @@ -178,6 +283,21 @@ QList<QDeclarativeError> QQuickView::errors() const return QList<QDeclarativeError>(); } +/*! + \property QQuickView::resizeMode + \brief whether the view should resize the canvas contents + + If this property is set to SizeViewToRootObject (the default), the view + resizes with the root item in the QML. + + If this property is set to SizeRootObjectToView, the view will + automatically resize the root item. + + Regardless of this property, the sizeHint of the view + is the initial size of the root item. Note though that + since QML may load dynamically, that size may change. +*/ + void QQuickView::setResizeMode(ResizeMode mode) { Q_D(QQuickView); @@ -313,11 +433,9 @@ void QQuickViewPrivate::setRootObject(QObject *obj) } if (root) { initialSize = rootObjectSize(); - if ((resizeMode == QQuickView::SizeViewToRootObject || !resized) // ### refactor: || !q->testAttribute(Qt::WA_Resized) - && initialSize != q->size()) { - + if ((resizeMode == QQuickView::SizeViewToRootObject || !q->width() || !q->height()) + && initialSize != q->size()) { q->resize(initialSize); - resized = true; } initResize(); } @@ -352,12 +470,18 @@ QSize QQuickView::sizeHint() const } } +/*! + Returns the initial size of the root object +*/ QSize QQuickView::initialSize() const { Q_D(const QQuickView); return d->initialSize; } +/*! + Returns the view's root \l {QQuickItem} {item}. + */ QQuickItem *QQuickView::rootObject() const { Q_D(const QQuickView); diff --git a/src/declarative/items/qquickview_p.h b/src/declarative/items/qquickview_p.h index 12be09bab9..8c835268f5 100644 --- a/src/declarative/items/qquickview_p.h +++ b/src/declarative/items/qquickview_p.h @@ -96,8 +96,6 @@ public: QQuickView::ResizeMode resizeMode; QSize initialSize; QElapsedTimer frameTimer; - - bool resized; }; QT_END_NAMESPACE diff --git a/src/declarative/items/qquickvisualadaptormodel.cpp b/src/declarative/items/qquickvisualadaptormodel.cpp index 28ea830db4..25baee6e29 100644 --- a/src/declarative/items/qquickvisualadaptormodel.cpp +++ b/src/declarative/items/qquickvisualadaptormodel.cpp @@ -688,7 +688,7 @@ QString QQuickVisualAdaptorModel::stringValue(int index, const QString &name) QDeclarativeData *ddata = QDeclarativeData::get(data); if (ddata && ddata->propertyCache) { - QDeclarativePropertyCache::Data *prop = ddata->propertyCache->property(name); + QDeclarativePropertyData *prop = ddata->propertyCache->property(name); if (prop) { if (prop->propType == QVariant::String) { void *args[] = { &val, 0 }; diff --git a/src/declarative/items/qquickvisualdatamodel.cpp b/src/declarative/items/qquickvisualdatamodel.cpp index 1a24e168d6..5cf2d6c9b3 100644 --- a/src/declarative/items/qquickvisualdatamodel.cpp +++ b/src/declarative/items/qquickvisualdatamodel.cpp @@ -766,7 +766,7 @@ QQuickVisualDataGroup *QQuickVisualDataModelPrivate::group_at( { QQuickVisualDataModelPrivate *d = static_cast<QQuickVisualDataModelPrivate *>(property->data); return index >= 0 && index < d->m_groupCount - 1 - ? d->m_groups[index - 1] + ? d->m_groups[index + 1] : 0; } @@ -998,7 +998,7 @@ QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index } cacheItem->attached = QQuickVisualDataModelAttached::properties(cacheItem->object); - cacheItem->attached->m_cacheItem = cacheItem; + cacheItem->attached->setCacheItem(cacheItem); new QQuickVisualDataModelAttachedMetaObject(cacheItem->attached, m_cacheMetaType); cacheItem->attached->emitChanges(); @@ -1728,6 +1728,13 @@ int QQuickVisualDataModelAttachedMetaObject::metaCall(QMetaObject::Call call, in return attached->qt_metacall(call, _id, arguments); } +void QQuickVisualDataModelAttached::setCacheItem(QQuickVisualDataModelCacheItem *item) +{ + m_cacheItem = item; + for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) + m_previousIndex[i] = m_cacheItem->index[i]; +} + /*! \qmlattachedproperty int QtQuick2::VisualDataModel::model @@ -1858,7 +1865,7 @@ void QQuickVisualDataGroupPrivate::emitChanges(QV8Engine *engine) { Q_Q(QQuickVisualDataGroup); static int idx = signalIndex("changed(QDeclarativeV8Handle,QDeclarativeV8Handle)"); - if (isSignalConnected(idx)) { + if (isSignalConnected(idx) && !changeSet.isEmpty()) { v8::HandleScope handleScope; v8::Context::Scope contextScope(engine->context()); v8::Local<v8::Array> removed = QQuickVisualDataModelPrivate::buildChangeList(changeSet.removes()); @@ -2365,10 +2372,13 @@ void QQuickVisualPartsModel::updateFilterGroup() if (!model->m_cacheMetaType) return; - if (m_inheritGroup) - return; + if (m_inheritGroup) { + if (m_filterGroup == model->m_filterGroup) + return; + m_filterGroup = model->m_filterGroup; + } - QDeclarativeListCompositor::Group previousGroup = model->m_compositorGroup; + QDeclarativeListCompositor::Group previousGroup = m_compositorGroup; m_compositorGroup = Compositor::Default; QQuickVisualDataGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this); for (int i = 1; i < model->m_groupCount; ++i) { @@ -2470,8 +2480,10 @@ QQuickVisualModel::ReleaseFlags QQuickVisualPartsModel::release(QQuickItem *item m_packaged.erase(it); if (!m_packaged.contains(item)) flags &= ~Referenced; - if (flags & Destroyed) + if (flags & Destroyed) { QQuickVisualDataModelPrivate::get(m_model)->emitDestroyingPackage(package); + item->setParentItem(0); + } } return flags; } diff --git a/src/declarative/items/qquickvisualdatamodel_p.h b/src/declarative/items/qquickvisualdatamodel_p.h index 331255199e..60b04ab9f2 100644 --- a/src/declarative/items/qquickvisualdatamodel_p.h +++ b/src/declarative/items/qquickvisualdatamodel_p.h @@ -199,6 +199,8 @@ public: {} ~QQuickVisualDataModelAttached() { attachedProperties.remove(parent()); } + void setCacheItem(QQuickVisualDataModelCacheItem *item); + QQuickVisualDataModel *model() const; QStringList groups() const; diff --git a/src/declarative/particles/qquickgravity.cpp b/src/declarative/particles/qquickgravity.cpp index 010fcb8d44..fd2fb92a53 100644 --- a/src/declarative/particles/qquickgravity.cpp +++ b/src/declarative/particles/qquickgravity.cpp @@ -47,11 +47,11 @@ const qreal CONV = 0.017453292520444443; \qmlclass Gravity QQuickGravityAffector \inqmlmodule QtQuick.Particles 2 \inherits Affector - \brief The Gravity element allows you to set a constant accleration in an angle + \brief The Gravity element allows you to set an accleration in an angle - This element will set the acceleration of all affected particles to a vector of - the specified magnitude in the specified angle. If the angle or acceleration is - not varying, it is more efficient to set the specified acceleration on the Emitter. + This element will accelerate all affected particles to a vector of + the specified magnitude in the specified angle. If the angle and acceleration do + not vary, it is more efficient to set the specified acceleration on the Emitter. This element models the gravity of a massive object whose center of gravity is far away (and thus the gravitational pull is effectively constant @@ -60,45 +60,38 @@ const qreal CONV = 0.017453292520444443; */ /*! - \qmlproperty real QtQuick.Particles2::Gravity::acceleration + \qmlproperty real QtQuick.Particles2::Gravity::magnitude Pixels per second that objects will be accelerated by. */ /*! + \qmlproperty real QtQuick.Particles2::Gravity::acceleration + + Name changed to magnitude, will be removed soon. +*/ +/*! \qmlproperty real QtQuick.Particles2::Gravity::angle Angle of acceleration. */ QQuickGravityAffector::QQuickGravityAffector(QQuickItem *parent) : - QQuickParticleAffector(parent), m_acceleration(-10), m_angle(90), m_xAcc(0), m_yAcc(0) + QQuickParticleAffector(parent), m_magnitude(-10), m_angle(90), m_needRecalc(true) { - connect(this, SIGNAL(accelerationChanged(qreal)), - this, SLOT(recalc())); - connect(this, SIGNAL(angleChanged(qreal)), - this, SLOT(recalc())); - recalc(); -} - -void QQuickGravityAffector::recalc() -{ - qreal theta = m_angle * CONV; - m_xAcc = m_acceleration * cos(theta); - m_yAcc = m_acceleration * sin(theta); } bool QQuickGravityAffector::affectParticle(QQuickParticleData *d, qreal dt) { - Q_UNUSED(dt); - bool changed = false; - if (d->ax != m_xAcc){ - d->setInstantaneousAX(m_xAcc); - changed = true; + if (!m_magnitude) + return false; + if (m_needRecalc) { + m_needRecalc = false; + m_dx = m_magnitude * cos(m_angle * CONV); + m_dy = m_magnitude * sin(m_angle * CONV); } - if (d->ay != m_yAcc){ - d->setInstantaneousAY(m_yAcc); - changed = true; - } - return changed; + + d->setInstantaneousVX(d->curVX() + m_dx*dt); + d->setInstantaneousVY(d->curVY() + m_dy*dt); + return true; } QT_END_NAMESPACE diff --git a/src/declarative/particles/qquickgravity_p.h b/src/declarative/particles/qquickgravity_p.h index b02eb49a7c..65f8e5a19d 100644 --- a/src/declarative/particles/qquickgravity_p.h +++ b/src/declarative/particles/qquickgravity_p.h @@ -53,13 +53,14 @@ QT_MODULE(Declarative) class QQuickGravityAffector : public QQuickParticleAffector { Q_OBJECT - Q_PROPERTY(qreal acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged) + Q_PROPERTY(qreal magnitude READ magnitude WRITE setMagnitude NOTIFY magnitudeChanged) + Q_PROPERTY(qreal acceleration READ magnitude WRITE setAcceleration NOTIFY magnitudeChanged) Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged) public: explicit QQuickGravityAffector(QQuickItem *parent = 0); - qreal acceleration() const + qreal magnitude() const { - return m_acceleration; + return m_magnitude; } qreal angle() const @@ -70,16 +71,27 @@ protected: virtual bool affectParticle(QQuickParticleData *d, qreal dt); signals: - void accelerationChanged(qreal arg); + void magnitudeChanged(qreal arg); void angleChanged(qreal arg); public slots: void setAcceleration(qreal arg) { - if (m_acceleration != arg) { - m_acceleration = arg; - emit accelerationChanged(arg); + qWarning() << "Gravity::acceleration has been renamed Gravity::magnitude"; + if (m_magnitude != arg) { + m_magnitude = arg; + m_needRecalc = true; + emit magnitudeChanged(arg); + } +} + +void setMagnitude(qreal arg) +{ + if (m_magnitude != arg) { + m_magnitude = arg; + m_needRecalc = true; + emit magnitudeChanged(arg); } } @@ -87,18 +99,18 @@ void setAngle(qreal arg) { if (m_angle != arg) { m_angle = arg; + m_needRecalc = true; emit angleChanged(arg); } } -private slots: - void recalc(); private: - qreal m_acceleration; + qreal m_magnitude; qreal m_angle; - qreal m_xAcc; - qreal m_yAcc; + bool m_needRecalc; + qreal m_dx; + qreal m_dy; }; QT_END_NAMESPACE diff --git a/src/declarative/particles/qquickimageparticle.cpp b/src/declarative/particles/qquickimageparticle.cpp index 4c9e2662a1..0847d06b6d 100644 --- a/src/declarative/particles/qquickimageparticle.cpp +++ b/src/declarative/particles/qquickimageparticle.cpp @@ -150,10 +150,16 @@ static const char vertexShaderCode[] = " else if (entry == 2.)\n" " currentSize = currentSize * fadeIn * fadeOut;\n" "\n" - " if (currentSize <= 0)//Sizes too small look jittery as they move\n" - " currentSize = 0;\n" - " else if (currentSize < 3)\n" - " currentSize = 3;\n" + " if (currentSize <= 0.){\n" + "#ifdef DEFORM //Not point sprites\n" + " gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0., 1.);\n" + "#else\n" + " gl_PointSize = 0.;\n" + "#endif\n" + " return;\n" + " }\n" + " if (currentSize < 3.)//Sizes too small look jittery as they move\n" + " currentSize = 3.;\n" "\n" " highp vec2 pos;\n" "#ifdef DEFORM\n" @@ -1114,11 +1120,15 @@ void QQuickImageParticle::createEngine() { if (m_spriteEngine) delete m_spriteEngine; - if (m_sprites.count()) + if (m_sprites.count()) { m_spriteEngine = new QQuickSpriteEngine(m_sprites, this); - else + connect(m_spriteEngine, SIGNAL(stateChanged(int)), + this, SLOT(spriteAdvance(int))); + m_explicitAnimation = true; + } else { m_spriteEngine = 0; - m_explicitAnimation = true; + m_explicitAnimation = false; + } reset(); } @@ -1329,6 +1339,7 @@ QSGGeometryNode* QQuickImageParticle::buildParticleNodes() m_nodes.insert(gIdx, node); m_idxStarts.insert(gIdx, m_lastIdxStart); + m_startsIdx.append(qMakePair<int,int>(m_lastIdxStart, gIdx)); m_lastIdxStart += count; //Create Particle Geometry @@ -1404,6 +1415,7 @@ QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *) m_nodes.clear(); m_idxStarts.clear(); + m_startsIdx.clear(); m_lastIdxStart = 0; m_material = 0; @@ -1448,26 +1460,6 @@ void QQuickImageParticle::prepareNextFrame() case Sprites: //Advance State m_spriteEngine->updateSprites(timeStamp); - foreach (const QString &str, m_groups){ - int gIdx = m_system->groupIds[str]; - int count = m_system->groupData[gIdx]->size(); - - Vertices<SpriteVertex>* particles = (Vertices<SpriteVertex> *) m_nodes[gIdx]->geometry()->vertexData(); - for (int i=0; i < count; i++){ - int spriteIdx = m_idxStarts[gIdx] + i; - Vertices<SpriteVertex> &p = particles[i]; - int curY = m_spriteEngine->spriteY(spriteIdx);//Y is fixed per sprite row, used to distinguish rows here - if (curY != p.v1.animY){ - p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0; - p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(spriteIdx); - p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(spriteIdx); - p.v1.animX = p.v2.animX = p.v3.animX = p.v4.animX = m_spriteEngine->spriteX(spriteIdx); - p.v1.animY = p.v2.animY = p.v3.animY = p.v4.animY = m_spriteEngine->spriteY(spriteIdx); - p.v1.animWidth = p.v2.animWidth = p.v3.animWidth = p.v4.animWidth = m_spriteEngine->spriteWidth(spriteIdx); - p.v1.animHeight = p.v2.animHeight = p.v3.animHeight = p.v4.animHeight = m_spriteEngine->spriteHeight(spriteIdx); - } - } - } case Tabled: case Deformable: case Colored: @@ -1481,6 +1473,38 @@ void QQuickImageParticle::prepareNextFrame() node->markDirty(QSGNode::DirtyMaterial); } +void QQuickImageParticle::spriteAdvance(int spriteIdx) +{ + if (!m_startsIdx.count())//Probably overly defensive + return; + + int gIdx = -1; + int i; + for (i = 0; i<m_startsIdx.count(); i++) { + if (spriteIdx < m_startsIdx[i].first) { + gIdx = m_startsIdx[i-1].second; + break; + } + } + if (gIdx == -1) + gIdx = m_startsIdx[i-1].second; + int pIdx = spriteIdx - m_startsIdx[i-1].first; + + QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx]; + QQuickParticleData* d = (datum->animationOwner == this ? datum : getShadowDatum(datum)); + + d->animIdx = m_spriteEngine->spriteState(spriteIdx); + Vertices<SpriteVertex>* particles = (Vertices<SpriteVertex> *) m_nodes[gIdx]->geometry()->vertexData(); + Vertices<SpriteVertex> &p = particles[pIdx]; + d->animT = p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0; + d->frameCount = p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(spriteIdx); + d->frameDuration = p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(spriteIdx); + d->animX = p.v1.animX = p.v2.animX = p.v3.animX = p.v4.animX = m_spriteEngine->spriteX(spriteIdx); + d->animY = p.v1.animY = p.v2.animY = p.v3.animY = p.v4.animY = m_spriteEngine->spriteY(spriteIdx); + d->animWidth = p.v1.animWidth = p.v2.animWidth = p.v3.animWidth = p.v4.animWidth = m_spriteEngine->spriteWidth(spriteIdx); + d->animHeight = p.v1.animHeight = p.v2.animHeight = p.v3.animHeight = p.v4.animHeight = m_spriteEngine->spriteHeight(spriteIdx); +} + void QQuickImageParticle::reloadColor(const Color4ub &c, QQuickParticleData* d) { d->color = c; @@ -1494,7 +1518,13 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) qreal redVariation = m_color_variation + m_redVariation; qreal greenVariation = m_color_variation + m_greenVariation; qreal blueVariation = m_color_variation + m_blueVariation; - int spriteIdx = m_idxStarts[gIdx] + datum->index; + int spriteIdx = 0; + if (m_spriteEngine) { + spriteIdx = m_idxStarts[gIdx] + datum->index; + if (spriteIdx >= m_spriteEngine->count()) + m_spriteEngine->setCount(spriteIdx+1); + } + float rotation; float rotationSpeed; float autoRotate; @@ -1518,7 +1548,8 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) }else{ writeTo->frameCount = 1; writeTo->frameDuration = 9999; - writeTo->animX = writeTo->animY = writeTo->animWidth = writeTo->animHeight = 0; + writeTo->animX = writeTo->animY = 0; + writeTo->animWidth = writeTo->animHeight = 1; } } case Tabled: diff --git a/src/declarative/particles/qquickimageparticle_p.h b/src/declarative/particles/qquickimageparticle_p.h index 760c64af0a..4cbe33bb07 100644 --- a/src/declarative/particles/qquickimageparticle_p.h +++ b/src/declarative/particles/qquickimageparticle_p.h @@ -348,6 +348,7 @@ protected: private slots: void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty + void spriteAdvance(int spriteIndex); private: QUrl m_image_name; QUrl m_colortable_name; @@ -362,6 +363,8 @@ private: QSGGeometryNode *m_rootNode; QHash<int, QSGGeometryNode *> m_nodes; QHash<int, int> m_idxStarts;//TODO: Proper resizing will lead to needing a spriteEngine per particle - do this after sprite engine gains transparent sharing? + QList<QPair<int, int> > m_startsIdx;//Same data, optimized for alternate retrieval + int m_lastIdxStart; QSGMaterial *m_material; diff --git a/src/declarative/particles/qquickparticleaffector.cpp b/src/declarative/particles/qquickparticleaffector.cpp index f50efc55e7..5bfc699548 100644 --- a/src/declarative/particles/qquickparticleaffector.cpp +++ b/src/declarative/particles/qquickparticleaffector.cpp @@ -220,7 +220,8 @@ void QQuickParticleAffector::affectSystem(qreal dt) m_system->timeInt -= myDt * 1000.0; while (myDt > simulationDelta) { m_system->timeInt += simulationDelta * 1000.0; - affected = affectParticle(d, simulationDelta) || affected; + if (d->alive())//Only affect during the parts it was alive for + affected = affectParticle(d, simulationDelta) || affected; myDt -= simulationDelta; } m_system->timeInt = realTime; diff --git a/src/declarative/particles/qquickparticlepainter.cpp b/src/declarative/particles/qquickparticlepainter.cpp index cc0b4da181..6d44e9a944 100644 --- a/src/declarative/particles/qquickparticlepainter.cpp +++ b/src/declarative/particles/qquickparticlepainter.cpp @@ -91,9 +91,9 @@ void QQuickParticlePainter::setSystem(QQuickParticleSystem *arg) void QQuickParticlePainter::load(QQuickParticleData* d) { + initialize(d->group, d->index); if (m_pleaseReset) return; - initialize(d->group, d->index); m_pendingCommits << qMakePair<int, int>(d->group, d->index); } diff --git a/src/declarative/particles/qquickparticlesystem.cpp b/src/declarative/particles/qquickparticlesystem.cpp index 51b6e18019..e6f1f937c9 100644 --- a/src/declarative/particles/qquickparticlesystem.cpp +++ b/src/declarative/particles/qquickparticlesystem.cpp @@ -580,6 +580,14 @@ bool QQuickParticleData::stillAlive() return (t + lifeSpan - EPSILON) > ((qreal)system->timeInt/1000.0); } +bool QQuickParticleData::alive() +{ + if (!system) + return false; + qreal st = ((qreal)system->timeInt/1000.0); + return (t + EPSILON) < st && (t + lifeSpan - EPSILON) > st; +} + float QQuickParticleData::curSize() { if (!system || !lifeSpan) diff --git a/src/declarative/particles/qquickparticlesystem_p.h b/src/declarative/particles/qquickparticlesystem_p.h index 9bfb817c61..c63b0085de 100644 --- a/src/declarative/particles/qquickparticlesystem_p.h +++ b/src/declarative/particles/qquickparticlesystem_p.h @@ -120,7 +120,7 @@ public: QVector<QQuickParticleData*> data; QQuickParticleDataHeap dataHeap; QSet<int> reusableIndexes; - bool recycle(); //Force recycling round, reutrns true if all indexes are now reusable + bool recycle(); //Force recycling round, returns true if all indexes are now reusable void initList(); void kill(QQuickParticleData* d); @@ -219,7 +219,8 @@ public: QQuickImageParticle* animationOwner; void debugDump(); - bool stillAlive(); + bool stillAlive();//Only checks end, because usually that's all you need and it's a little faster. + bool alive(); float lifeLeft(); float curSize(); void clone(const QQuickParticleData& other);//Not =, leaves meta-data like index diff --git a/src/declarative/particles/qquickv8particledata.cpp b/src/declarative/particles/qquickv8particledata.cpp index 61d70395ef..80ce355cd7 100644 --- a/src/declarative/particles/qquickv8particledata.cpp +++ b/src/declarative/particles/qquickv8particledata.cpp @@ -174,13 +174,86 @@ QT_BEGIN_NAMESPACE \qmlproperty real QtQuick.Particles2::Particle::rotationSpeed Degrees clockwise per second that the particle image is rotated at while alive. */ - /*! - \qmlproperty real QtQuick.Particles2::Particle::autoRotate - If autoRotate == 1.0, then the particle's rotation will be + \qmlproperty bool QtQuick.Particles2::Particle::autoRotate + If autoRotate is true, then the particle's rotation will be set so that it faces the direction of travel, plus any rotation from the rotation or rotationSpeed properties. */ + +/*! + \qmlproperty bool QtQuick.Particles2::Particle::update + + Inside an Affector, the changes made to the particle will only be + applied if update is set to true. +*/ +/*! + \qmlproperty real QtQuick.Particles2::Particle::xDeformationVectorX + + The x component of the deformation vector along the X axis. ImageParticle + can draw particles across non-square shapes. It will draw the texture rectangle + across the parallelogram drawn with the x and y deformation vectors. +*/ + +/*! + \qmlproperty real QtQuick.Particles2::Particle::yDeformationVectorX + + The y component of the deformation vector along the X axis. ImageParticle + can draw particles across non-square shapes. It will draw the texture rectangle + across the parallelogram drawn with the x and y deformation vectors. +*/ + +/*! + \qmlproperty real QtQuick.Particles2::Particle::xDeformationVectorY + + The x component of the deformation vector along the X axis. ImageParticle + can draw particles across non-square shapes. It will draw the texture rectangle + across the parallelogram drawn with the x and y deformation vectors. +*/ + +/*! + \qmlproperty real QtQuick.Particles2::Particle::yDeformationVectorY + + The y component of the deformation vector along the Y axis. ImageParticle + can draw particles across non-square shapes. It will draw the texture rectangle + across the parallelogram drawn with the x and y deformation vectors. +*/ + +/*! + \qmlproperty real QtQuick.Particles2::Particle::red + + ImageParticle can draw colorized particles. When it does so, red is used + as the red channel of the color applied to the source image. + + Values are from 0.0 to 1.0. +*/ + +/*! + \qmlproperty real QtQuick.Particles2::Particle::green + + ImageParticle can draw colorized particles. When it does so, green is used + as the green channel of the color applied to the source image. + + Values are from 0.0 to 1.0. +*/ + +/*! + \qmlproperty real QtQuick.Particles2::Particle::blue + + ImageParticle can draw colorized particles. When it does so, blue is used + as the blue channel of the color applied to the source image. + + Values are from 0.0 to 1.0. +*/ + +/*! + \qmlproperty real QtQuick.Particles2::Particle::alpha + + ImageParticle can draw colorized particles. When it does so, alpha is used + as the alpha channel of the color applied to the source image. + + Values are from 0.0 to 1.0. +*/ /*! \qmlmethod real QtQuick.Particles2::Particle::lifeLeft The time in seconds that the particle has left to live at @@ -239,6 +312,42 @@ static v8::Handle<v8::Value> particleData_curSize(const v8::Arguments &args) return v8::Number::New(r->datum->curSize()); } +#define COLOR_GETTER_AND_SETTER(VAR, NAME) static v8::Handle<v8::Value> particleData_get_ ## NAME (v8::Local<v8::String>, const v8::AccessorInfo &info) \ +{ \ + QV8ParticleDataResource *r = v8_resource_cast<QV8ParticleDataResource>(info.This()); \ + if (!r || !r->datum) \ + V8THROW_ERROR("Not a valid ParticleData object"); \ +\ + return v8::Number::New((r->datum->color. VAR )/255.0);\ +}\ +\ +static void particleData_set_ ## NAME (v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)\ +{\ + QV8ParticleDataResource *r = v8_resource_cast<QV8ParticleDataResource>(info.This());\ + if (!r || !r->datum)\ + V8THROW_ERROR_SETTER("Not a valid ParticleData object");\ +\ + r->datum->color. VAR = qMin(255, qMax(0, (int)floor(value->NumberValue() * 255.0)));\ +} + + +#define SEMIBOOL_GETTER_AND_SETTER(VARIABLE) static v8::Handle<v8::Value> particleData_get_ ## VARIABLE (v8::Local<v8::String>, const v8::AccessorInfo &info) \ +{ \ + QV8ParticleDataResource *r = v8_resource_cast<QV8ParticleDataResource>(info.This()); \ + if (!r || !r->datum) \ + V8THROW_ERROR("Not a valid ParticleData object"); \ +\ + return v8::Boolean::New(r->datum-> VARIABLE);\ +}\ +\ +static void particleData_set_ ## VARIABLE (v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)\ +{\ + QV8ParticleDataResource *r = v8_resource_cast<QV8ParticleDataResource>(info.This());\ + if (!r || !r->datum)\ + V8THROW_ERROR_SETTER("Not a valid ParticleData object");\ +\ + r->datum-> VARIABLE = value->BooleanValue() ? 1.0 : 0.0;\ +} #define FLOAT_GETTER_AND_SETTER(VARIABLE) static v8::Handle<v8::Value> particleData_get_ ## VARIABLE (v8::Local<v8::String>, const v8::AccessorInfo &info) \ { \ @@ -276,8 +385,14 @@ static void particleData_set_ ## VARIABLE (v8::Local<v8::String>, v8::Local<v8:: r->datum-> SETTER ( value->NumberValue() );\ } -#define FLOAT_REGISTER_ACCESSOR(FT, ENGINE, VARIABLE, NAME) FT ->PrototypeTemplate()->SetAccessor( v8::String::New( #NAME ), particleData_get_ ## VARIABLE , particleData_set_ ## VARIABLE , v8::External::Wrap(ENGINE)) +#define REGISTER_ACCESSOR(FT, ENGINE, VARIABLE, NAME) FT ->PrototypeTemplate()->SetAccessor( v8::String::New( #NAME ), particleData_get_ ## VARIABLE , particleData_set_ ## VARIABLE , v8::External::Wrap(ENGINE)) +COLOR_GETTER_AND_SETTER(r, red) +COLOR_GETTER_AND_SETTER(g, green) +COLOR_GETTER_AND_SETTER(b, blue) +COLOR_GETTER_AND_SETTER(a, alpha) +SEMIBOOL_GETTER_AND_SETTER(autoRotate) +SEMIBOOL_GETTER_AND_SETTER(update) FLOAT_GETTER_AND_SETTER(x) FLOAT_GETTER_AND_SETTER(y) FLOAT_GETTER_AND_SETTER(t) @@ -290,15 +405,15 @@ FLOAT_GETTER_AND_SETTER(ax) FLOAT_GETTER_AND_SETTER(ay) FLOAT_GETTER_AND_SETTER(xx) FLOAT_GETTER_AND_SETTER(xy) +FLOAT_GETTER_AND_SETTER(yx) +FLOAT_GETTER_AND_SETTER(yy) FLOAT_GETTER_AND_SETTER(rotation) FLOAT_GETTER_AND_SETTER(rotationSpeed) -FLOAT_GETTER_AND_SETTER(autoRotate) FLOAT_GETTER_AND_SETTER(animIdx) FLOAT_GETTER_AND_SETTER(frameDuration) FLOAT_GETTER_AND_SETTER(frameCount) FLOAT_GETTER_AND_SETTER(animT) FLOAT_GETTER_AND_SETTER(r) -FLOAT_GETTER_AND_SETTER(update) FAKE_FLOAT_GETTER_AND_SETTER(curX, curX, setInstantaneousX) FAKE_FLOAT_GETTER_AND_SETTER(curVX, curVX, setInstantaneousVX) FAKE_FLOAT_GETTER_AND_SETTER(curAX, curAX, setInstantaneousAX) @@ -306,8 +421,6 @@ FAKE_FLOAT_GETTER_AND_SETTER(curY, curY, setInstantaneousY) FAKE_FLOAT_GETTER_AND_SETTER(curVY, curVY, setInstantaneousVY) FAKE_FLOAT_GETTER_AND_SETTER(curAY, curAY, setInstantaneousAY) -//TODO: Non-floats (color, update?) once floats are working well - QV8ParticleDataDeletable::QV8ParticleDataDeletable(QV8Engine *engine) { v8::HandleScope handle_scope; @@ -318,33 +431,39 @@ QV8ParticleDataDeletable::QV8ParticleDataDeletable(QV8Engine *engine) ft->PrototypeTemplate()->Set(v8::String::New("discard"), V8FUNCTION(particleData_discard, engine)); ft->PrototypeTemplate()->Set(v8::String::New("lifeLeft"), V8FUNCTION(particleData_lifeLeft, engine)); ft->PrototypeTemplate()->Set(v8::String::New("currentSize"), V8FUNCTION(particleData_curSize, engine)); - FLOAT_REGISTER_ACCESSOR(ft, engine, x, initialX); - FLOAT_REGISTER_ACCESSOR(ft, engine, y, initialY); - FLOAT_REGISTER_ACCESSOR(ft, engine, t, t); - FLOAT_REGISTER_ACCESSOR(ft, engine, lifeSpan, lifeSpan); - FLOAT_REGISTER_ACCESSOR(ft, engine, size, startSize); - FLOAT_REGISTER_ACCESSOR(ft, engine, endSize, endSize); - FLOAT_REGISTER_ACCESSOR(ft, engine, vx, initialVX); - FLOAT_REGISTER_ACCESSOR(ft, engine, vy, initialVY); - FLOAT_REGISTER_ACCESSOR(ft, engine, ax, initialAX); - FLOAT_REGISTER_ACCESSOR(ft, engine, ay, initialAY); - FLOAT_REGISTER_ACCESSOR(ft, engine, xx, xDeformationVector); - FLOAT_REGISTER_ACCESSOR(ft, engine, xy, yDeformationVector); - FLOAT_REGISTER_ACCESSOR(ft, engine, rotation, rotation); - FLOAT_REGISTER_ACCESSOR(ft, engine, rotationSpeed, rotationSpeed); - FLOAT_REGISTER_ACCESSOR(ft, engine, autoRotate, autoRotate); - FLOAT_REGISTER_ACCESSOR(ft, engine, animIdx, animationIndex); - FLOAT_REGISTER_ACCESSOR(ft, engine, frameDuration, frameDuration); - FLOAT_REGISTER_ACCESSOR(ft, engine, frameCount, frameCount); - FLOAT_REGISTER_ACCESSOR(ft, engine, animT, animationT); - FLOAT_REGISTER_ACCESSOR(ft, engine, r, r); - FLOAT_REGISTER_ACCESSOR(ft, engine, update, update); - FLOAT_REGISTER_ACCESSOR(ft, engine, curX, x); - FLOAT_REGISTER_ACCESSOR(ft, engine, curVX, vx); - FLOAT_REGISTER_ACCESSOR(ft, engine, curAX, ax); - FLOAT_REGISTER_ACCESSOR(ft, engine, curY, y); - FLOAT_REGISTER_ACCESSOR(ft, engine, curVY, vy); - FLOAT_REGISTER_ACCESSOR(ft, engine, curAY, ay); + REGISTER_ACCESSOR(ft, engine, x, initialX); + REGISTER_ACCESSOR(ft, engine, y, initialY); + REGISTER_ACCESSOR(ft, engine, t, t); + REGISTER_ACCESSOR(ft, engine, lifeSpan, lifeSpan); + REGISTER_ACCESSOR(ft, engine, size, startSize); + REGISTER_ACCESSOR(ft, engine, endSize, endSize); + REGISTER_ACCESSOR(ft, engine, vx, initialVX); + REGISTER_ACCESSOR(ft, engine, vy, initialVY); + REGISTER_ACCESSOR(ft, engine, ax, initialAX); + REGISTER_ACCESSOR(ft, engine, ay, initialAY); + REGISTER_ACCESSOR(ft, engine, xx, xDeformationVectorX); + REGISTER_ACCESSOR(ft, engine, xy, xDeformationVectorY); + REGISTER_ACCESSOR(ft, engine, yx, yDeformationVectorX); + REGISTER_ACCESSOR(ft, engine, yy, yDeformationVectorY); + REGISTER_ACCESSOR(ft, engine, rotation, rotation); + REGISTER_ACCESSOR(ft, engine, rotationSpeed, rotationSpeed); + REGISTER_ACCESSOR(ft, engine, autoRotate, autoRotate); + REGISTER_ACCESSOR(ft, engine, animIdx, animationIndex); + REGISTER_ACCESSOR(ft, engine, frameDuration, frameDuration); + REGISTER_ACCESSOR(ft, engine, frameCount, frameCount); + REGISTER_ACCESSOR(ft, engine, animT, animationT); + REGISTER_ACCESSOR(ft, engine, r, r); + REGISTER_ACCESSOR(ft, engine, update, update); + REGISTER_ACCESSOR(ft, engine, curX, x); + REGISTER_ACCESSOR(ft, engine, curVX, vx); + REGISTER_ACCESSOR(ft, engine, curAX, ax); + REGISTER_ACCESSOR(ft, engine, curY, y); + REGISTER_ACCESSOR(ft, engine, curVY, vy); + REGISTER_ACCESSOR(ft, engine, curAY, ay); + REGISTER_ACCESSOR(ft, engine, red, red); + REGISTER_ACCESSOR(ft, engine, green, green); + REGISTER_ACCESSOR(ft, engine, blue, blue); + REGISTER_ACCESSOR(ft, engine, alpha, alpha); constructor = qPersistentNew(ft->GetFunction()); } diff --git a/src/declarative/qml/ftw/ftw.pri b/src/declarative/qml/ftw/ftw.pri index c7750468d9..9d114e2b05 100644 --- a/src/declarative/qml/ftw/ftw.pri +++ b/src/declarative/qml/ftw/ftw.pri @@ -11,6 +11,8 @@ HEADERS += \ $$PWD/qdeclarativethread_p.h \ $$PWD/qfinitestack_p.h \ $$PWD/qrecursionwatcher_p.h \ + $$PWD/qdeletewatcher_p.h \ + $$PWD/qrecyclepool_p.h \ SOURCES += \ $$PWD/qintrusivelist.cpp \ diff --git a/src/declarative/debugger/qdeclarativedebuggerstatus_p.h b/src/declarative/qml/ftw/qdeletewatcher_p.h index 385301e62d..34ef46bc17 100644 --- a/src/declarative/debugger/qdeclarativedebuggerstatus_p.h +++ b/src/declarative/qml/ftw/qdeletewatcher_p.h @@ -39,8 +39,8 @@ ** ****************************************************************************/ -#ifndef QDECLARATIVEDEBUGGERSTATUS_P_H -#define QDECLARATIVEDEBUGGERSTATUS_P_H +#ifndef QDELETEWATCHER_P_H +#define QDELETEWATCHER_P_H // // W A R N I N G @@ -53,27 +53,61 @@ // We mean it. // -#include <QtCore/qobject.h> - -#include <private/qdeclarativeglobal_p.h> - -QT_BEGIN_HEADER +#include <QtCore/qglobal.h> QT_BEGIN_NAMESPACE -QT_MODULE(Declarative) - -class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebuggerStatus +class QDeleteWatchable { public: - virtual ~QDeclarativeDebuggerStatus(); + inline QDeleteWatchable(); + inline ~QDeleteWatchable(); +private: + friend class QDeleteWatcher; + bool *_w; +}; - virtual void setSelectedState(bool); +class QDeleteWatcher { +public: + inline QDeleteWatcher(QDeleteWatchable *data); + inline ~QDeleteWatcher(); + inline bool wasDeleted() const; +private: + void *operator new(size_t); + bool *_w; + bool _s; + QDeleteWatchable *m_d; }; -Q_DECLARE_INTERFACE(QDeclarativeDebuggerStatus, "com.trolltech.qml.QDeclarativeDebuggerStatus") -QT_END_NAMESPACE +QDeleteWatchable::QDeleteWatchable() +: _w(0) +{ +} + +QDeleteWatchable::~QDeleteWatchable() +{ + if (_w) *_w = true; +} + +QDeleteWatcher::QDeleteWatcher(QDeleteWatchable *data) +: _s(false), m_d(data) +{ + if (!m_d->_w) + m_d->_w = &_s; + _w = m_d->_w; +} + +QDeleteWatcher::~QDeleteWatcher() +{ + if (false == *_w && &_s == m_d->_w) + m_d->_w = 0; +} + +bool QDeleteWatcher::wasDeleted() const +{ + return *_w; +} -QT_END_HEADER +QT_END_NAMESPACE -#endif // QLMDEBUGGERSTATUS_P_H +#endif // QDELETEWATCHER_P_H diff --git a/src/declarative/qml/ftw/qfastmetabuilder.cpp b/src/declarative/qml/ftw/qfastmetabuilder.cpp index 20c5e08499..e4ce35fbd7 100644 --- a/src/declarative/qml/ftw/qfastmetabuilder.cpp +++ b/src/declarative/qml/ftw/qfastmetabuilder.cpp @@ -40,6 +40,9 @@ ****************************************************************************/ #include "qfastmetabuilder_p.h" +#include "qvariant.h" + +#include <QtCore/qmetaobject.h> QT_BEGIN_NAMESPACE diff --git a/src/declarative/qml/ftw/qfastmetabuilder_p.h b/src/declarative/qml/ftw/qfastmetabuilder_p.h index e9457b5943..a2074672d8 100644 --- a/src/declarative/qml/ftw/qfastmetabuilder_p.h +++ b/src/declarative/qml/ftw/qfastmetabuilder_p.h @@ -55,11 +55,13 @@ #include <QtCore/qglobal.h> #include <QtCore/qmetatype.h> +#include <QtCore/qmetaobject.h> #include <private/qhashedstring_p.h> QT_BEGIN_NAMESPACE +class QMetaObject; class QFastMetaBuilder { public: diff --git a/src/declarative/qml/ftw/qfieldlist_p.h b/src/declarative/qml/ftw/qfieldlist_p.h index f0efd16a20..c6b432324c 100644 --- a/src/declarative/qml/ftw/qfieldlist_p.h +++ b/src/declarative/qml/ftw/qfieldlist_p.h @@ -107,6 +107,7 @@ N *QFieldList<N, nextMember>::takeFirst() Q_ASSERT(_first == 0); _last = 0; } + value->*nextMember = 0; --_count; } return value; diff --git a/src/declarative/qml/ftw/qrecyclepool_p.h b/src/declarative/qml/ftw/qrecyclepool_p.h new file mode 100644 index 0000000000..f349996a22 --- /dev/null +++ b/src/declarative/qml/ftw/qrecyclepool_p.h @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRECYCLEPOOL_P_H +#define QRECYCLEPOOL_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. +// + +QT_BEGIN_NAMESPACE + +#define QRECYCLEPOOLCOOKIE 0x33218ADF + +template<typename T, int Step> +class QRecyclePoolPrivate +{ +public: + QRecyclePoolPrivate() + : recyclePoolHold(true), outstandingItems(0), cookie(QRECYCLEPOOLCOOKIE), + currentPage(0), nextAllocated(0) + { + } + + bool recyclePoolHold; + int outstandingItems; + quint32 cookie; + + struct PoolType : public T { + union { + QRecyclePoolPrivate<T, Step> *pool; + PoolType *nextAllocated; + }; + }; + + struct Page { + Page *nextPage; + unsigned int free; + union { + char array[Step * sizeof(PoolType)]; + qint64 q_for_alignment_1; + double q_for_alignment_2; + }; + }; + + Page *currentPage; + PoolType *nextAllocated; + + inline T *allocate(); + static inline void dispose(T *); + inline void releaseIfPossible(); +}; + +template<typename T, int Step = 1024> +class QRecyclePool +{ +public: + inline QRecyclePool(); + inline ~QRecyclePool(); + + inline T *New(); + template<typename T1> + inline T *New(const T1 &); + template<typename T1> + inline T *New(T1 &); + + static inline void Delete(T *); + +private: + QRecyclePoolPrivate<T, Step> *d; +}; + +template<typename T, int Step> +QRecyclePool<T, Step>::QRecyclePool() +: d(new QRecyclePoolPrivate<T, Step>()) +{ +} + +template<typename T, int Step> +QRecyclePool<T, Step>::~QRecyclePool() +{ + d->recyclePoolHold = false; + d->releaseIfPossible(); +} + +template<typename T, int Step> +T *QRecyclePool<T, Step>::New() +{ + T *rv = d->allocate(); + new (rv) T; + return rv; +} + +template<typename T, int Step> +template<typename T1> +T *QRecyclePool<T, Step>::New(const T1 &a) +{ + T *rv = d->allocate(); + new (rv) T(a); + return rv; +} + +template<typename T, int Step> +template<typename T1> +T *QRecyclePool<T, Step>::New(T1 &a) +{ + T *rv = d->allocate(); + new (rv) T(a); + return rv; +} + +template<typename T, int Step> +void QRecyclePool<T, Step>::Delete(T *t) +{ + t->~T(); + QRecyclePoolPrivate<T, Step>::dispose(t); +} + +template<typename T, int Step> +void QRecyclePoolPrivate<T, Step>::releaseIfPossible() +{ + if (recyclePoolHold || outstandingItems) + return; + + Page *p = currentPage; + while (p) { + Page *n = p->nextPage; + qFree(p); + p = n; + } + + delete this; +} + +template<typename T, int Step> +T *QRecyclePoolPrivate<T, Step>::allocate() +{ + PoolType *rv = 0; + if (nextAllocated) { + rv = nextAllocated; + nextAllocated = rv->nextAllocated; + } else if (currentPage && currentPage->free) { + rv = (PoolType *)(currentPage->array + (Step - currentPage->free) * sizeof(PoolType)); + currentPage->free--; + } else { + Page *p = (Page *)qMalloc(sizeof(Page)); + p->nextPage = currentPage; + p->free = Step; + currentPage = p; + + rv = (PoolType *)currentPage->array; + currentPage->free--; + } + + rv->pool = this; + ++outstandingItems; + return rv; +} + +template<typename T, int Step> +void QRecyclePoolPrivate<T, Step>::dispose(T *t) +{ + PoolType *pt = static_cast<PoolType *>(t); + Q_ASSERT(pt->pool && pt->pool->cookie == QRECYCLEPOOLCOOKIE); + + QRecyclePoolPrivate<T, Step> *This = pt->pool; + pt->nextAllocated = This->nextAllocated; + This->nextAllocated = pt; + --This->outstandingItems; + This->releaseIfPossible(); +} + +QT_END_NAMESPACE + +#endif // QRECYCLEPOOL_P_H diff --git a/src/declarative/qml/qdeclarative.h b/src/declarative/qml/qdeclarative.h index 566a420b9d..b98899be0e 100644 --- a/src/declarative/qml/qdeclarative.h +++ b/src/declarative/qml/qdeclarative.h @@ -413,48 +413,6 @@ QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true) // For the use of QtQuick1 module Q_DECLARATIVE_EXPORT void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor); -/*! - This function may be used to register a module API provider \a callback in a particular \a uri - with a version specified in \a versionMajor and \a versionMinor. - - Installing a module API into a uri allows developers to provide arbitrary functionality - (methods and properties) in a namespace that doesn't necessarily contain elements. - - A module API may be either a QObject or a QJSValue. Only one module API provider - may be registered into any given namespace (combination of \a uri, \a majorVersion and \a minorVersion). - This function should be used to register a module API provider function which returns a QJSValue as a module API. - - \e NOTE: QJSValue module API properties will \e not trigger binding re-evaluation if changed. - - Usage: - \code - // first, define the module API provider function (callback). - static QJSValue *example_qjsvalue_module_api_provider(QDeclarativeEngine *engine, QJSEngine *scriptEngine) - { - Q_UNUSED(engine) - - static int seedValue = 5; - QJSValue example = scriptEngine->newObject(); - example.setProperty("someProperty", seedValue++); - return example; - } - - // second, register the module API provider with QML by calling this function in an initialization function. - ... - qmlRegisterModuleApi("Qt.example.qjsvalueApi", 1, 0, example_qjsvalue_module_api_provider); - ... - \endcode - - In order to use the registered module API in QML, you must import the module API. - \qml - import QtQuick 2.0 - import Qt.example.qjsvalueApi 1.0 as ExampleApi - Item { - id: root - property int someValue: ExampleApi.someProperty - } - \endqml - */ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, QJSValue (*callback)(QDeclarativeEngine *, QJSEngine *)) { @@ -469,80 +427,6 @@ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMi return QDeclarativePrivate::qmlregister(QDeclarativePrivate::ModuleApiRegistration, &api); } -/*! - This function may be used to register a module API provider \a callback in a particular \a uri - with a version specified in \a versionMajor and \a versionMinor. - - Installing a module API into a uri allows developers to provide arbitrary functionality - (methods and properties) in a namespace that doesn't necessarily contain elements. - - A module API may be either a QObject or a QJSValue. Only one module API provider - may be registered into any given namespace (combination of \a uri, \a majorVersion and \a minorVersion). - This function should be used to register a module API provider function which returns a QObject as a module API. - - A QObject module API must be imported with a qualifier, and that qualifier may be used as - the target in a \l Connections element or otherwise used as any other element id would. - One exception to this is that a QObject module API property may not be aliased (because the - module API qualifier does not identify an object within the same component as any other item). - - Usage: - \code - // first, define your QObject which provides the functionality. - class ModuleApiExample : public QObject - { - Q_OBJECT - Q_PROPERTY (int someProperty READ someProperty WRITE setSomeProperty NOTIFY somePropertyChanged) - - public: - ModuleApiExample(QObject* parent = 0) - : QObject(parent), m_someProperty(0) - { - } - - ~ModuleApiExample() {} - - Q_INVOKABLE int doSomething() { setSomeProperty(5); return m_someProperty; } - - int someProperty() const { return m_someProperty; } - void setSomeProperty(int val) { m_someProperty = val; emit somePropertyChanged(val); } - - signals: - void somePropertyChanged(int newValue); - - private: - int m_someProperty; - }; - - // second, define the module API provider function (callback). - static QObject *example_qobject_module_api_provider(QDeclarativeEngine *engine, QJSEngine *scriptEngine) - { - Q_UNUSED(engine) - Q_UNUSED(scriptEngine) - - ModuleApiExample *example = new ModuleApiExample(); - return example; - } - - // third, register the module API provider with QML by calling this function in an initialization function. - ... - qmlRegisterModuleApi("Qt.example.qobjectApi", 1, 0, example_qobject_module_api_provider); - ... - \endcode - - In order to use the registered module API in QML, you must import the module API. - \qml - import QtQuick 2.0 - import Qt.example.qobjectApi 1.0 as ExampleApi - Item { - id: root - property int someValue: ExampleApi.someProperty - - Component.onCompleted: { - someValue = ExampleApi.doSomething() - } - } - \endqml - */ inline int qmlRegisterModuleApi(const char *uri, int versionMajor, int versionMinor, QObject *(*callback)(QDeclarativeEngine *, QJSEngine *)) { diff --git a/src/declarative/qml/qdeclarativebinding.cpp b/src/declarative/qml/qdeclarativebinding.cpp index 531842a695..9a3a7e005c 100644 --- a/src/declarative/qml/qdeclarativebinding.cpp +++ b/src/declarative/qml/qdeclarativebinding.cpp @@ -345,7 +345,7 @@ void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags) QDeclarativeBindingProfiler prof(this); d->updating = true; - QDeclarativeDeleteWatcher watcher(d); + QDeleteWatcher watcher(d); if (d->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) { diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 5762f427c5..fb98a8c0ec 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -208,7 +208,7 @@ bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *p { const QDeclarativeScript::Variant &value = v->value; - if (!prop->core.isWritable()) + if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); if (prop->core.isEnum()) { @@ -303,7 +303,7 @@ bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *p case QVariant::PointF: { bool ok; - QPointF point = QDeclarativeStringConverters::pointFFromString(value.asString(), &ok); + QDeclarativeStringConverters::pointFFromString(value.asString(), &ok); if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: point expected")); } break; @@ -311,7 +311,7 @@ bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *p case QVariant::SizeF: { bool ok; - QSizeF size = QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok); + QDeclarativeStringConverters::sizeFFromString(value.asString(), &ok); if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: size expected")); } break; @@ -319,7 +319,7 @@ bool QDeclarativeCompiler::testLiteralAssignment(QDeclarativeScript::Property *p case QVariant::RectF: { bool ok; - QRectF rect = QDeclarativeStringConverters::rectFFromString(value.asString(), &ok); + QDeclarativeStringConverters::rectFFromString(value.asString(), &ok); if (!ok) COMPILE_EXCEPTION(v, tr("Invalid property assignment: rect expected")); } break; @@ -1125,8 +1125,8 @@ void QDeclarativeCompiler::genObject(QDeclarativeScript::Object *obj) reinterpret_cast<const QDeclarativeVMEMetaData *>(obj->synthdata.constData()); for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) { int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii; - QDeclarativePropertyCache::Data *data = propertyCache->property(index); - data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias); + QDeclarativePropertyData *data = propertyCache->property(index); + data->setFlags(data->getFlags() | QDeclarativePropertyData::IsAlias); } } @@ -1529,7 +1529,7 @@ bool QDeclarativeCompiler::buildSignal(QDeclarativeScript::Property *prop, QDecl bool notInRevision = false; - QDeclarativePropertyCache::Data *sig = signal(obj, QStringRef(&name), ¬InRevision); + QDeclarativePropertyData *sig = signal(obj, QStringRef(&name), ¬InRevision); if (sig == 0) { @@ -1634,7 +1634,7 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeScript::Property *prop, } else { // Setup regular property data bool notInRevision = false; - QDeclarativePropertyCache::Data *d = + QDeclarativePropertyData *d = prop->name().isEmpty()?0:property(obj, prop->name(), ¬InRevision); if (d == 0 && notInRevision) { @@ -1650,7 +1650,7 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeScript::Property *prop, prop->core = *d; } else if (prop->isDefault) { QMetaProperty p = QDeclarativeMetaType::defaultProperty(metaObject); - QDeclarativePropertyCache::Data defaultPropertyData; + QDeclarativePropertyData defaultPropertyData; defaultPropertyData.load(p, engine); if (p.name()) prop->setName(QLatin1String(p.name())); @@ -2004,7 +2004,7 @@ bool QDeclarativeCompiler::buildGroupedProperty(QDeclarativeScript::Property *pr } } - if (!obj->metaObject()->property(prop->index).isWritable()) { + if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) { COMPILE_EXCEPTION(prop, tr( "Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); } @@ -2056,7 +2056,7 @@ bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type, for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { - QDeclarativePropertyCache::Data *d = property(obj, prop->name()); + QDeclarativePropertyData *d = property(obj, prop->name()); if (d == 0) COMPILE_EXCEPTION(prop, tr("Cannot assign to non-existent property \"%1\"").arg(prop->name().toString())); @@ -2082,8 +2082,7 @@ bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type, bool isEnumAssignment = false; if (prop->core.isEnum()) - COMPILE_CHECK(testQualifiedEnumAssignment(obj->metatype->property(prop->index), obj, - value, &isEnumAssignment)); + COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment)); if (isEnumAssignment) { value->type = Value::Literal; @@ -2222,7 +2221,7 @@ bool QDeclarativeCompiler::buildPropertyObjectAssignment(QDeclarativeScript::Pro Q_ASSERT(prop->index != -1); Q_ASSERT(v->object->type != -1); - if (!obj->metaObject()->property(prop->index).isWritable()) + if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); if (QDeclarativeMetaType::isInterface(prop->type)) { @@ -2303,7 +2302,9 @@ bool QDeclarativeCompiler::buildPropertyOnAssignment(QDeclarativeScript::Propert Q_ASSERT(prop->index != -1); Q_ASSERT(v->object->type != -1); - if (!obj->metaObject()->property(prop->index).isWritable()) + Q_UNUSED(obj); + + if (!prop->core.isWritable()) COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); @@ -2350,8 +2351,7 @@ bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Pr //optimization for <Type>.<EnumValue> enum assignments if (prop->core.isEnum()) { bool isEnumAssignment = false; - COMPILE_CHECK(testQualifiedEnumAssignment(obj->metaObject()->property(prop->index), obj, - v, &isEnumAssignment)); + COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment)); if (isEnumAssignment) { v->type = Value::Literal; return true; @@ -2372,17 +2372,19 @@ bool QDeclarativeCompiler::buildPropertyLiteralAssignment(QDeclarativeScript::Pr return true; } -bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop, +bool QDeclarativeCompiler::testQualifiedEnumAssignment(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj, QDeclarativeScript::Value *v, bool *isAssignment) { *isAssignment = false; - if (!prop.isEnumType()) + if (!prop->core.isEnum()) return true; - if (!prop.isWritable()) - COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(QString::fromUtf8(prop.name()))); + QMetaProperty mprop = obj->metaObject()->property(prop->index); + + if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) + COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); QString string = v->value.asString(); if (!string.at(0).isUpper()) @@ -2413,10 +2415,10 @@ bool QDeclarativeCompiler::testQualifiedEnumAssignment(const QMetaProperty &prop if (objTypeName == type->qmlTypeName()) { // When these two match, we can short cut the search - if (prop.isFlagType()) { - value = prop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok); + if (mprop.isFlagType()) { + value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok); } else { - value = prop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok); + value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok); } } else { // Otherwise we have to search the whole type @@ -2571,7 +2573,8 @@ bool QDeclarativeCompiler::checkDynamicMeta(QDeclarativeScript::Object *obj) bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object *obj) { - for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { if (!p->defaultValue || p->type == Object::DynamicProperty::Alias) continue; @@ -2585,6 +2588,9 @@ bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeScript::Object COMPILE_EXCEPTION(property, tr("Property value set multiple times")); } + if (p->isReadOnly) + property->isReadOnlyDeclaration = true; + if (property->value) COMPILE_EXCEPTION(property, tr("Invalid property nesting")); @@ -2627,7 +2633,7 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, Dyn if (!resolveAlias) { // No point doing this for both the alias and non alias cases - QDeclarativePropertyCache::Data *d = property(obj, p->name); + QDeclarativePropertyData *d = property(obj, p->name); if (d && d->isFinal()) COMPILE_EXCEPTION(p, tr("Cannot override FINAL property")); } @@ -2755,6 +2761,9 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, Dyn if (p->type == Object::DynamicProperty::Var) continue; + if (p->isReadOnly) + readonly = true; + if (buildData) { VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data(); vmd->propertyCount++; @@ -2790,8 +2799,10 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, Dyn (vmd->propertyData() + effectivePropertyIndex)->propertyType = -1; } - builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, (QMetaType::Type)-1, - QFastMetaBuilder::Writable, effectivePropertyIndex); + builder.setProperty(effectivePropertyIndex, p->nameRef, typeRef, + (QMetaType::Type)-1, + p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, + effectivePropertyIndex); p->changedSignatureRef = builder.newString(p->name.utf8length() + strlen("Changed()")); builder.setSignal(effectivePropertyIndex, p->changedSignatureRef); @@ -2988,16 +2999,16 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeScript::Object *obj, Dyn if (obj->type != -1) { QDeclarativePropertyCache *cache = output->types[obj->type].createPropertyCache(engine)->copy(); cache->append(engine, &obj->extObject, - QDeclarativePropertyCache::Data::NoFlags, - QDeclarativePropertyCache::Data::IsVMEFunction, - QDeclarativePropertyCache::Data::IsVMESignal); + QDeclarativePropertyData::NoFlags, + QDeclarativePropertyData::IsVMEFunction, + QDeclarativePropertyData::IsVMESignal); // now we modify the flags appropriately for var properties. int propertyOffset = obj->extObject.propertyOffset(); - QDeclarativePropertyCache::Data *currPropData = 0; + QDeclarativePropertyData *currPropData = 0; for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) { currPropData = cache->property(pvi + propertyOffset); - currPropData->setFlags(currPropData->getFlags() | QDeclarativePropertyCache::Data::IsVMEProperty); + currPropData->setFlags(currPropData->getFlags() | QDeclarativePropertyData::IsVMEProperty); } obj->synthCache = cache; @@ -3098,8 +3109,8 @@ bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder, if (!aliasProperty.isScriptable()) COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); - writable = aliasProperty.isWritable(); - resettable = aliasProperty.isResettable(); + writable = aliasProperty.isWritable() && !prop.isReadOnly; + resettable = aliasProperty.isResettable() && !prop.isReadOnly; if (aliasProperty.type() < QVariant::UserType) type = aliasProperty.type(); @@ -3175,7 +3186,7 @@ bool QDeclarativeCompiler::buildBinding(QDeclarativeScript::Value *value, Q_ASSERT(prop->parent); Q_ASSERT(prop->parent->metaObject()); - if (!prop->core.isWritable() && !prop->core.isQList()) + if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration) COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); BindingReference *reference = pool->New<BindingReference>(); @@ -3275,7 +3286,7 @@ int QDeclarativeCompiler::genContextCache() return output->contextCaches.count() - 1; } -QDeclarativePropertyCache::Data +QDeclarativePropertyData QDeclarativeCompiler::genValueTypeData(QDeclarativeScript::Property *valueTypeProp, QDeclarativeScript::Property *prop) { @@ -3498,7 +3509,7 @@ QStringList QDeclarativeCompiler::deferredProperties(QDeclarativeScript::Object return rv; } -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * QDeclarativeCompiler::property(QDeclarativeScript::Object *object, int index) { QDeclarativePropertyCache *cache = 0; @@ -3513,7 +3524,7 @@ QDeclarativeCompiler::property(QDeclarativeScript::Object *object, int index) return cache->property(index); } -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * QDeclarativeCompiler::property(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision) { if (notInRevision) *notInRevision = false; @@ -3527,7 +3538,7 @@ QDeclarativeCompiler::property(QDeclarativeScript::Object *object, const QHashed else cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject()); - QDeclarativePropertyCache::Data *d = cache->property(name); + QDeclarativePropertyData *d = cache->property(name); // Find the first property while (d && d->isFunction()) @@ -3542,7 +3553,7 @@ QDeclarativeCompiler::property(QDeclarativeScript::Object *object, const QHashed } // This code must match the semantics of QDeclarativePropertyPrivate::findSignalByName -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * QDeclarativeCompiler::signal(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision) { if (notInRevision) *notInRevision = false; @@ -3557,7 +3568,7 @@ QDeclarativeCompiler::signal(QDeclarativeScript::Object *object, const QHashedSt cache = QDeclarativeEnginePrivate::get(engine)->cache(object->metaObject()); - QDeclarativePropertyCache::Data *d = cache->property(name); + QDeclarativePropertyData *d = cache->property(name); if (notInRevision) *notInRevision = false; while (d && !(d->isFunction())) @@ -3585,7 +3596,7 @@ QDeclarativeCompiler::signal(QDeclarativeScript::Object *object, const QHashedSt int QDeclarativeCompiler::indexOfSignal(QDeclarativeScript::Object *object, const QString &name, bool *notInRevision) { - QDeclarativePropertyCache::Data *d = signal(object, QStringRef(&name), notInRevision); + QDeclarativePropertyData *d = signal(object, QStringRef(&name), notInRevision); return d?d->coreIndex:-1; } @@ -3598,7 +3609,7 @@ int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, co int QDeclarativeCompiler::indexOfProperty(QDeclarativeScript::Object *object, const QHashedStringRef &name, bool *notInRevision) { - QDeclarativePropertyCache::Data *d = property(object, name, notInRevision); + QDeclarativePropertyData *d = property(object, name, notInRevision); return d?d->coreIndex:-1; } diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h index ef37335ad8..f6229bc666 100644 --- a/src/declarative/qml/qdeclarativecompiler_p.h +++ b/src/declarative/qml/qdeclarativecompiler_p.h @@ -336,7 +336,7 @@ private: bool doesPropertyExist(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj); bool testLiteralAssignment(QDeclarativeScript::Property *prop, QDeclarativeScript::Value *value); - bool testQualifiedEnumAssignment(const QMetaProperty &prop, + bool testQualifiedEnumAssignment(QDeclarativeScript::Property *prop, QDeclarativeScript::Object *obj, QDeclarativeScript::Value *value, bool *isAssignment); @@ -373,8 +373,8 @@ private: QDeclarativeScript::Property *valueTypeProperty = 0); int genContextCache(); - QDeclarativePropertyCache::Data genValueTypeData(QDeclarativeScript::Property *prop, - QDeclarativeScript::Property *valueTypeProp); + QDeclarativePropertyData genValueTypeData(QDeclarativeScript::Property *prop, + QDeclarativeScript::Property *valueTypeProp); int componentTypeRef(); @@ -385,11 +385,11 @@ private: QStringList deferredProperties(QDeclarativeScript::Object *); - QDeclarativePropertyCache::Data *property(QDeclarativeScript::Object *, int); - QDeclarativePropertyCache::Data *property(QDeclarativeScript::Object *, const QHashedStringRef &, - bool *notInRevision = 0); - QDeclarativePropertyCache::Data *signal(QDeclarativeScript::Object *, const QHashedStringRef &, - bool *notInRevision = 0); + QDeclarativePropertyData *property(QDeclarativeScript::Object *, int); + QDeclarativePropertyData *property(QDeclarativeScript::Object *, const QHashedStringRef &, + bool *notInRevision = 0); + QDeclarativePropertyData *signal(QDeclarativeScript::Object *, const QHashedStringRef &, + bool *notInRevision = 0); int indexOfProperty(QDeclarativeScript::Object *, const QHashedStringRef &, bool *notInRevision = 0); int indexOfProperty(QDeclarativeScript::Object *, const QString &, bool *notInRevision = 0); int indexOfSignal(QDeclarativeScript::Object *, const QString &, bool *notInRevision = 0); diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp index d4662cf43a..1723603d29 100644 --- a/src/declarative/qml/qdeclarativecontext.cpp +++ b/src/declarative/qml/qdeclarativecontext.cpp @@ -381,8 +381,8 @@ QVariant QDeclarativeContext::contextProperty(const QString &name) const QByteArray utf8Name = name.toUtf8(); if (data->contextObject) { QObject *obj = data->contextObject; - QDeclarativePropertyCache::Data local; - QDeclarativePropertyCache::Data *property = + QDeclarativePropertyData local; + QDeclarativePropertyData *property = QDeclarativePropertyCache::property(data->engine, obj, name, local); if (property) value = obj->metaObject()->property(property->coreIndex).read(obj); @@ -511,18 +511,18 @@ QObject *QDeclarativeContextPrivate::context_at(QDeclarativeListProperty<QObject QDeclarativeContextData::QDeclarativeContextData() : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), - isPragmaLibraryContext(false), publicContext(0), activeVME(0), propertyNames(0), contextObject(0), - imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0), - contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), componentAttached(0), - v4bindings(0), v8bindings(0) + isPragmaLibraryContext(false), unresolvedNames(false), publicContext(0), activeVMEData(0), + propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), + expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), + componentAttached(0), v4bindings(0), v8bindings(0) { } QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt) : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), - isPragmaLibraryContext(false), publicContext(ctxt), activeVME(0), propertyNames(0), - contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), - contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), + isPragmaLibraryContext(false), unresolvedNames(false), publicContext(ctxt), activeVMEData(0), + propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), + expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), componentAttached(0), v4bindings(0), v8bindings(0) { } @@ -653,23 +653,89 @@ void QDeclarativeContextData::setParent(QDeclarativeContextData *p, bool parentT } } -/* -Refreshes all expressions that could possibly depend on this context. Refreshing flushes all -context-tree dependent caches in the expressions, and should occur every time the context tree - *structure* (not values) changes. -*/ -void QDeclarativeContextData::refreshExpressions() +void QDeclarativeContextData::refreshExpressionsRecursive(QDeclarativeAbstractExpression *expression) { - QDeclarativeContextData *child = childContexts; - while (child) { - child->refreshExpressions(); - child = child->nextChild; - } + QDeleteWatcher w(expression); - QDeclarativeAbstractExpression *expression = expressions; - while (expression) { + if (expression->m_nextExpression) + refreshExpressionsRecursive(expression->m_nextExpression); + + if (!w.wasDeleted()) expression->refresh(); - expression = expression->m_nextExpression; +} + +static inline bool expressions_to_run(QDeclarativeContextData *ctxt, bool isGlobalRefresh) +{ + return ctxt->expressions && (!isGlobalRefresh || ctxt->unresolvedNames); +} + +void QDeclarativeContextData::refreshExpressionsRecursive(bool isGlobal) +{ + // For efficiency, we try and minimize the number of guards we have to create + if (expressions_to_run(this, isGlobal) && (nextChild || childContexts)) { + QDeclarativeGuardedContextData guard(this); + + if (childContexts) + childContexts->refreshExpressionsRecursive(isGlobal); + + if (guard.isNull()) return; + + if (nextChild) + nextChild->refreshExpressionsRecursive(isGlobal); + + if (guard.isNull()) return; + + if (expressions_to_run(this, isGlobal)) + refreshExpressionsRecursive(expressions); + + } else if (expressions_to_run(this, isGlobal)) { + + refreshExpressionsRecursive(expressions); + + } else if (nextChild && childContexts) { + + QDeclarativeGuardedContextData guard(this); + + childContexts->refreshExpressionsRecursive(isGlobal); + + if (!guard.isNull() && nextChild) + nextChild->refreshExpressionsRecursive(isGlobal); + + } else if (nextChild) { + + nextChild->refreshExpressionsRecursive(isGlobal); + + } else if (childContexts) { + + childContexts->refreshExpressionsRecursive(isGlobal); + + } +} + +// Refreshes all expressions that could possibly depend on this context. Refreshing flushes all +// context-tree dependent caches in the expressions, and should occur every time the context tree +// *structure* (not values) changes. +void QDeclarativeContextData::refreshExpressions() +{ + bool isGlobal = (parent == 0); + + // For efficiency, we try and minimize the number of guards we have to create + if (expressions_to_run(this, isGlobal) && childContexts) { + QDeclarativeGuardedContextData guard(this); + + childContexts->refreshExpressionsRecursive(isGlobal); + + if (!guard.isNull() && expressions_to_run(this, isGlobal)) + refreshExpressionsRecursive(expressions); + + } else if (expressions_to_run(this, isGlobal)) { + + refreshExpressionsRecursive(expressions); + + } else if (childContexts) { + + childContexts->refreshExpressionsRecursive(isGlobal); + } } diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h index ba4edb8e15..fb6473cb7a 100644 --- a/src/declarative/qml/qdeclarativecontext_p.h +++ b/src/declarative/qml/qdeclarativecontext_p.h @@ -143,12 +143,12 @@ public: quint32 ownedByParent:1; // unrelated to isInternal; parent context deletes children if true. quint32 isJSContext:1; quint32 isPragmaLibraryContext:1; + quint32 unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name quint32 dummy:28; QDeclarativeContext *publicContext; - // VME that is constructing this context if any - // XXX remove if possible - QDeclarativeVME *activeVME; + // VME data that is constructing this context if any + void *activeVMEData; // Property name cache QDeclarativeIntegerCache *propertyNames; @@ -217,6 +217,8 @@ public: } private: + void refreshExpressionsRecursive(bool isGlobal); + void refreshExpressionsRecursive(QDeclarativeAbstractExpression *); ~QDeclarativeContextData() {} }; diff --git a/src/declarative/qml/qdeclarativedata_p.h b/src/declarative/qml/qdeclarativedata_p.h index 1bebee5ef0..a4972579b7 100644 --- a/src/declarative/qml/qdeclarativedata_p.h +++ b/src/declarative/qml/qdeclarativedata_p.h @@ -187,7 +187,7 @@ QDeclarativeNotifierEndpoint *QDeclarativeData::notify(int index) { Q_ASSERT(index <= 0xFFFF); - if (!notifyList || !(notifyList->connectionMask & (1 << (quint64(index) % 64)))) { + if (!notifyList || !(notifyList->connectionMask & (1ULL << quint64(index % 64)))) { return 0; } else if (index < notifyList->notifiesSize) { return notifyList->notifies[index]; diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 673ac42095..1323669fc7 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -332,7 +332,7 @@ the same object as is returned from the Qt.include() call. QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e) -: captureProperties(false), rootContext(0), isDebugging(false), +: propertyCapture(0), rootContext(0), isDebugging(false), outputWarningsToStdErr(true), sharedContext(0), sharedScope(0), cleanup(0), erroredBindings(0), inProgressCreations(0), workerScriptEngine(0), activeVME(0), @@ -542,6 +542,9 @@ QDeclarativeEngine::~QDeclarativeEngine() // ensure we clean up QObjects with JS ownership d->v8engine()->gc(); + + if (d->incubationController) + d->incubationController->d = 0; } /*! \fn void QDeclarativeEngine::quit() @@ -1111,7 +1114,7 @@ void QDeclarativeData::addNotify(int index, QDeclarativeNotifierEndpoint *endpoi Q_ASSERT(!endpoint->isConnected()); index = qMin(index, 0xFFFF - 1); - notifyList->connectionMask |= (1 << (quint64(index) % 64)); + notifyList->connectionMask |= (1ULL << quint64(index % 64)); if (index < notifyList->notifiesSize) { @@ -1659,12 +1662,12 @@ QDeclarativePropertyCache *QDeclarativeEnginePrivate::createCache(QDeclarativeTy !overloadError && iter != raw->stringCache.end(); ++iter) { - QDeclarativePropertyCache::Data *d = *iter; + QDeclarativePropertyData *d = *iter; if (raw->isAllowedInRevision(d)) continue; // Not excluded - no problems // check that a regular "name" overload isn't happening - QDeclarativePropertyCache::Data *current = d; + QDeclarativePropertyData *current = d; while (!overloadError && current) { current = d->overrideData(current); if (current && raw->isAllowedInRevision(current)) diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h index 88eda390e3..a678a4588c 100644 --- a/src/declarative/qml/qdeclarativeengine_p.h +++ b/src/declarative/qml/qdeclarativeengine_p.h @@ -69,6 +69,7 @@ #include "qdeclarativemetatype_p.h" #include "qdeclarativedirparser_p.h" #include <private/qintrusivelist_p.h> +#include <private/qrecyclepool_p.h> #include <QtCore/qlist.h> #include <QtCore/qpair.h> @@ -103,6 +104,21 @@ class QSGTexture; class QDeclarativeIncubator; class QSGContext; +// This needs to be declared here so that the pool for it can live in QDeclarativeEnginePrivate. +// The inline method definitions are in qdeclarativeexpression_p.h +class QDeclarativeJavaScriptExpressionGuard : public QDeclarativeNotifierEndpoint +{ +public: + inline QDeclarativeJavaScriptExpressionGuard(QDeclarativeJavaScriptExpression *); + + static inline void endpointCallback(QDeclarativeNotifierEndpoint *); + static inline QDeclarativeJavaScriptExpressionGuard *New(QDeclarativeJavaScriptExpression *e); + inline void Delete(); + + QDeclarativeJavaScriptExpression *expression; + QDeclarativeJavaScriptExpressionGuard *next; +}; + class Q_DECLARATIVE_EXPORT QDeclarativeEnginePrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QDeclarativeEngine) @@ -112,19 +128,18 @@ public: void init(); - struct CapturedProperty { - CapturedProperty(QObject *o, int c, int n) - : object(o), coreIndex(c), notifier(0), notifyIndex(n) {} - CapturedProperty(QDeclarativeNotifier *n) - : object(0), coreIndex(-1), notifier(n), notifyIndex(-1) {} - - QObject *object; - int coreIndex; - QDeclarativeNotifier *notifier; - int notifyIndex; + class PropertyCapture { + public: + inline virtual ~PropertyCapture() {} + virtual void captureProperty(QDeclarativeNotifier *) = 0; + virtual void captureProperty(QObject *, int, int) = 0; }; - bool captureProperties; - QPODVector<CapturedProperty> capturedProperties; + + PropertyCapture *propertyCapture; + inline void captureProperty(QDeclarativeNotifier *); + inline void captureProperty(QObject *, int, int); + + QRecyclePool<QDeclarativeJavaScriptExpressionGuard> jsExpressionGuardPool; QDeclarativeContext *rootContext; bool isDebugging; @@ -492,6 +507,18 @@ QDeclarativeEngine *QDeclarativeEnginePrivate::get(QDeclarativeEnginePrivate *p) return p->q_func(); } +void QDeclarativeEnginePrivate::captureProperty(QDeclarativeNotifier *n) +{ + if (propertyCapture) + propertyCapture->captureProperty(n); +} + +void QDeclarativeEnginePrivate::captureProperty(QObject *o, int c, int n) +{ + if (propertyCapture) + propertyCapture->captureProperty(o, c, n); +} + QT_END_NAMESPACE #endif // QDECLARATIVEENGINE_P_H diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp index d3ba92ab42..0895ffa1ec 100644 --- a/src/declarative/qml/qdeclarativeexpression.cpp +++ b/src/declarative/qml/qdeclarativeexpression.cpp @@ -70,12 +70,14 @@ bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e) QDeclarativeJavaScriptExpression::QDeclarativeJavaScriptExpression() : m_requiresThisObject(0), m_useSharedContext(0), m_notifyOnValueChanged(0), - m_scopeObject(0) + m_scopeObject(0), guardCapture(0) { } QDeclarativeJavaScriptExpression::~QDeclarativeJavaScriptExpression() { + if (guardCapture) guardCapture->expression = 0; + clearGuards(); } QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate() @@ -149,6 +151,7 @@ QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObje v8::TryCatch tc; v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope); v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, filename, line); + if (tc.HasCaught()) return v8::Persistent<v8::Function>(); v8::Local<v8::Value> result = script->Run(scopeobject); if (tc.HasCaught()) return v8::Persistent<v8::Function>(); if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject); @@ -396,12 +399,12 @@ void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle<v8::Message> mes void QDeclarativeJavaScriptExpression::setNotifyOnValueChanged(bool v) { m_notifyOnValueChanged = v; - if (!v) guardList.clear(); + if (!v) clearGuards(); } void QDeclarativeJavaScriptExpression::resetNotifyOnValueChanged() { - guardList.clear(); + clearGuards(); } v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::Function> function, bool *isUndefined) @@ -415,12 +418,15 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine); - bool lastCaptureProperties = ep->captureProperties; - QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties; - ep->captureProperties = notifyOnValueChanged(); + Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty()); + GuardCapture capture(this); + + QDeclarativeEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture; + ep->propertyCapture = notifyOnValueChanged()?&capture:0; + - if (ep->capturedProperties.count()) - ep->capturedProperties.copyAndClear(lastCapturedProperties); + if (notifyOnValueChanged()) + capture.guards.copyAndClear(activeGuards); QDeclarativeContextData *lastSharedContext = 0; QObject *lastSharedScope = 0; @@ -429,7 +435,7 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F // All code that follows must check with watcher before it accesses data members // incase we have been deleted. - QDeclarativeDeleteWatcher watcher(this); + QDeleteWatcher watcher(this); if (sharedContext) { lastSharedContext = ep->sharedContext; @@ -471,80 +477,90 @@ v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::F ep->sharedScope = lastSharedScope; } - if (!watcher.wasDeleted() && notifyOnValueChanged()) { - guardList.updateGuards(this, ep->capturedProperties); + if (capture.errorString) { + for (int ii = 0; ii < capture.errorString->count(); ++ii) + qWarning("%s", qPrintable(capture.errorString->at(ii))); + delete capture.errorString; + capture.errorString = 0; } - if (lastCapturedProperties.count()) - lastCapturedProperties.copyAndClear(ep->capturedProperties); - else - ep->capturedProperties.clear(); + while (Guard *g = capture.guards.takeFirst()) + g->Delete(); - ep->captureProperties = lastCaptureProperties; + ep->propertyCapture = lastPropertyCapture; return result; } -void -QDeclarativeJavaScriptExpression::GuardList::updateGuards(QDeclarativeJavaScriptExpression *expression, - const CapturedProperties &properties) +void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QDeclarativeNotifier *n) { - if (properties.count() == 0) { - clear(); - return; - } + if (expression) { - if (properties.count() != length) { - Endpoint *newGuardList = new Endpoint[properties.count()]; + // Try and find a matching guard + while (!guards.isEmpty() && !guards.first()->isConnected(n)) + guards.takeFirst()->Delete(); - for (int ii = 0; ii < qMin(length, properties.count()); ++ii) - endpoints[ii].copyAndClear(newGuardList[ii]); + Guard *g = 0; + if (!guards.isEmpty()) { + g = guards.takeFirst(); + g->cancelNotify(); + Q_ASSERT(g->isConnected(n)); + } else { + g = Guard::New(expression); + g->connect(n); + } - delete [] endpoints; - endpoints = newGuardList; - length = properties.count(); + expression->activeGuards.append(g); } +} - bool outputWarningHeader = false; - bool noChanges = true; - for (int ii = 0; ii < properties.count(); ++ii) { - Endpoint &guard = endpoints[ii]; - const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii); - - guard.expression = expression; - - if (property.notifier != 0) { - - if (guard.isConnected(property.notifier)) { - guard.cancelNotify(); - } else { - guard.connect(property.notifier); +void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n) +{ + if (expression) { + if (n == -1) { + if (!errorString) { + errorString = new QStringList; + QString preamble = QLatin1String("QDeclarativeExpression: Expression ") + + expression->expressionIdentifier() + + QLatin1String(" depends on non-NOTIFYable properties:"); + errorString->append(preamble); } - } else if (property.notifyIndex != -1) { - - if (guard.isConnected(property.object, property.notifyIndex)) { - guard.cancelNotify(); - } else { - guard.connect(property.object, property.notifyIndex); - } + const QMetaObject *metaObj = o->metaObject(); + QMetaProperty metaProp = metaObj->property(c); + QString error = QLatin1String(" ") + + QString::fromUtf8(metaObj->className()) + + QLatin1String("::") + + QString::fromUtf8(metaProp.name()); + errorString->append(error); } else { - if (!outputWarningHeader) { - QString e = expression->expressionIdentifier(); - outputWarningHeader = true; - qWarning() << "QDeclarativeExpression: Expression" << qPrintable(e) - << "depends on non-NOTIFYable properties:"; - } - const QMetaObject *metaObj = property.object->metaObject(); - QMetaProperty metaProp = metaObj->property(property.coreIndex); + // Try and find a matching guard + while (!guards.isEmpty() && !guards.first()->isConnected(o, n)) + guards.takeFirst()->Delete(); + + Guard *g = 0; + if (!guards.isEmpty()) { + g = guards.takeFirst(); + g->cancelNotify(); + Q_ASSERT(g->isConnected(o, n)); + } else { + g = Guard::New(expression); + g->connect(o, n); + } - qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name(); + expression->activeGuards.append(g); } } } +void QDeclarativeJavaScriptExpression::clearGuards() +{ + while (Guard *g = activeGuards.takeFirst()) + g->Delete(); +} + // Must be called with a valid handle scope v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined) { diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h index 4e31efb806..bfe031fbc8 100644 --- a/src/declarative/qml/qdeclarativeexpression_p.h +++ b/src/declarative/qml/qdeclarativeexpression_p.h @@ -55,14 +55,15 @@ #include "qdeclarativeexpression.h" -#include <private/qdeclarativeengine_p.h> -#include <private/qdeclarativeguard_p.h> - #include <private/qv8engine_p.h> +#include <private/qfieldlist_p.h> +#include <private/qdeletewatcher_p.h> +#include <private/qdeclarativeguard_p.h> +#include <private/qdeclarativeengine_p.h> QT_BEGIN_NAMESPACE -class QDeclarativeAbstractExpression +class QDeclarativeAbstractExpression : public QDeleteWatchable { public: QDeclarativeAbstractExpression(); @@ -107,31 +108,8 @@ private: QDeclarativeDelayedError **prevError; }; -class QDeclarativeDeleteWatchable -{ -public: - inline QDeclarativeDeleteWatchable(); - inline ~QDeclarativeDeleteWatchable(); -private: - friend class QDeclarativeDeleteWatcher; - bool *m_wasDeleted; -}; - -class QDeclarativeDeleteWatcher { -public: - inline QDeclarativeDeleteWatcher(QDeclarativeDeleteWatchable *data); - inline ~QDeclarativeDeleteWatcher(); - inline bool wasDeleted() const; -private: - void *operator new(size_t); - bool *m_wasDeleted; - bool m_wasDeletedStorage; - QDeclarativeDeleteWatchable *m_d; -}; - class QDeclarativeJavaScriptExpression : public QDeclarativeAbstractExpression, - public QDeclarativeDelayedError, - public QDeclarativeDeleteWatchable + public QDeclarativeDelayedError { public: QDeclarativeJavaScriptExpression(); @@ -164,28 +142,28 @@ private: QObject *m_scopeObject; - class GuardList { - public: - inline GuardList(); - inline ~GuardList(); - void inline clear(); - - typedef QPODVector<QDeclarativeEnginePrivate::CapturedProperty> CapturedProperties; - void updateGuards(QDeclarativeJavaScriptExpression *, const CapturedProperties &properties); - - private: - struct Endpoint : public QDeclarativeNotifierEndpoint { - Endpoint() : expression(0) { callback = &endpointCallback; } - static void endpointCallback(QDeclarativeNotifierEndpoint *e) { - static_cast<Endpoint *>(e)->expression->expressionChanged(); - } - QDeclarativeJavaScriptExpression *expression; - }; - - Endpoint *endpoints; - int length; + typedef QDeclarativeJavaScriptExpressionGuard Guard; + + struct GuardCapture : public QDeclarativeEnginePrivate::PropertyCapture { + GuardCapture(QDeclarativeJavaScriptExpression *e) : expression(e), errorString(0) { + } + ~GuardCapture() { + Q_ASSERT(guards.isEmpty()); + Q_ASSERT(errorString == 0); + } + + virtual void captureProperty(QDeclarativeNotifier *); + virtual void captureProperty(QObject *, int, int); + + QDeclarativeJavaScriptExpression *expression; + QFieldList<Guard, &Guard::next> guards; + QStringList *errorString; }; - GuardList guardList; + + QFieldList<Guard, &Guard::next> activeGuards; + GuardCapture *guardCapture; + + void clearGuards(); }; class QDeclarativeExpression; @@ -233,35 +211,6 @@ public: QDeclarativeRefCount *dataRef; }; -QDeclarativeDeleteWatchable::QDeclarativeDeleteWatchable() -: m_wasDeleted(0) -{ -} - -QDeclarativeDeleteWatchable::~QDeclarativeDeleteWatchable() -{ - if (m_wasDeleted) *m_wasDeleted = true; -} - -QDeclarativeDeleteWatcher::QDeclarativeDeleteWatcher(QDeclarativeDeleteWatchable *data) -: m_wasDeletedStorage(false), m_d(data) -{ - if (!m_d->m_wasDeleted) - m_d->m_wasDeleted = &m_wasDeletedStorage; - m_wasDeleted = m_d->m_wasDeleted; -} - -QDeclarativeDeleteWatcher::~QDeclarativeDeleteWatcher() -{ - if (false == *m_wasDeleted && m_wasDeleted == m_d->m_wasDeleted) - m_d->m_wasDeleted = 0; -} - -bool QDeclarativeDeleteWatcher::wasDeleted() const -{ - return *m_wasDeleted; -} - bool QDeclarativeJavaScriptExpression::requiresThisObject() const { return m_requiresThisObject; @@ -302,36 +251,42 @@ QString QDeclarativeJavaScriptExpression::expressionIdentifier() return QString(); } -QDeclarativeJavaScriptExpression::GuardList::GuardList() -: endpoints(0), length(0) +QDeclarativeExpressionPrivate *QDeclarativeExpressionPrivate::get(QDeclarativeExpression *expr) { + return static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr)); } -QDeclarativeJavaScriptExpression::GuardList::~GuardList() -{ - clear(); +QDeclarativeExpression *QDeclarativeExpressionPrivate::get(QDeclarativeExpressionPrivate *expr) +{ + return expr->q_func(); } -void QDeclarativeJavaScriptExpression::GuardList::clear() +QString QDeclarativeExpressionPrivate::expressionIdentifier() +{ + return QLatin1String("\"") + expression + QLatin1String("\""); +} + +QDeclarativeJavaScriptExpressionGuard::QDeclarativeJavaScriptExpressionGuard(QDeclarativeJavaScriptExpression *e) +: expression(e), next(0) { - delete [] endpoints; - endpoints = 0; - length = 0; + callback = &endpointCallback; } -QDeclarativeExpressionPrivate *QDeclarativeExpressionPrivate::get(QDeclarativeExpression *expr) +void QDeclarativeJavaScriptExpressionGuard::endpointCallback(QDeclarativeNotifierEndpoint *e) { - return static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr)); + static_cast<QDeclarativeJavaScriptExpressionGuard *>(e)->expression->expressionChanged(); } -QDeclarativeExpression *QDeclarativeExpressionPrivate::get(QDeclarativeExpressionPrivate *expr) +QDeclarativeJavaScriptExpressionGuard * +QDeclarativeJavaScriptExpressionGuard::New(QDeclarativeJavaScriptExpression *e) { - return expr->q_func(); + Q_ASSERT(e); + return QDeclarativeEnginePrivate::get(e->context()->engine)->jsExpressionGuardPool.New(e); } -QString QDeclarativeExpressionPrivate::expressionIdentifier() +void QDeclarativeJavaScriptExpressionGuard::Delete() { - return QLatin1String("\"") + expression + QLatin1String("\""); + QRecyclePool<QDeclarativeJavaScriptExpressionGuard>::Delete(this); } QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativeglobal_p.h b/src/declarative/qml/qdeclarativeglobal_p.h index cc0a4b6b1d..c6caa1e354 100644 --- a/src/declarative/qml/qdeclarativeglobal_p.h +++ b/src/declarative/qml/qdeclarativeglobal_p.h @@ -90,11 +90,7 @@ QT_MODULE(Declarative) QMetaObject::connect(sender, signalIdx, receiver, methodIdx, Qt::DirectConnection); \ } -#ifdef Q_OS_SYMBIAN -#define Q_DECLARATIVE_PRIVATE_EXPORT Q_AUTOTEST_EXPORT -#else #define Q_DECLARATIVE_PRIVATE_EXPORT Q_DECLARATIVE_EXPORT -#endif struct QDeclarativeGraphics_DerivedObject : public QObject { diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp index f94e9e4bae..0a03443acc 100644 --- a/src/declarative/qml/qdeclarativeimport.cpp +++ b/src/declarative/qml/qdeclarativeimport.cpp @@ -51,10 +51,6 @@ #include <private/qdeclarativetypenamecache_p.h> #include <private/qdeclarativeengine_p.h> -#ifdef Q_OS_SYMBIAN -#include <private/qcore_symbian_p.h> -#endif - QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE) @@ -382,13 +378,6 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath foreach (const QDeclarativeDirParser::Plugin &plugin, qmldirParser->plugins()) { QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name); -#if defined(QT_LIBINFIX) && defined(Q_OS_SYMBIAN) - if (resolvedFilePath.isEmpty()) { - // In case of libinfixed build, attempt to load libinfixed version, too. - QString infixedPluginName = plugin.name + QLatin1String(QT_LIBINFIX); - resolvedFilePath = database->resolvePlugin(dir, plugin.path, infixedPluginName); - } -#endif if (!resolvedFilePath.isEmpty()) { if (!database->importPlugin(resolvedFilePath, uri, errors)) { if (errors) { @@ -751,38 +740,13 @@ QDeclarativeImportDatabase::QDeclarativeImportDatabase(QDeclarativeEngine *e) #ifndef QT_NO_SETTINGS QString installImportsPath = QLibraryInfo::location(QLibraryInfo::ImportsPath); - -#if defined(Q_OS_SYMBIAN) - // Append imports path for all available drives in Symbian - if (installImportsPath.at(1) != QChar(QLatin1Char(':'))) { - QString tempPath = installImportsPath; - if (tempPath.at(tempPath.length() - 1) != QDir::separator()) { - tempPath += QDir::separator(); - } - RFs& fs = qt_s60GetRFs(); - TPtrC tempPathPtr(reinterpret_cast<const TText*> (tempPath.constData())); - TFindFile finder(fs); - TInt err = finder.FindByDir(tempPathPtr, tempPathPtr); - while (err == KErrNone) { - QString foundDir(reinterpret_cast<const QChar *>(finder.File().Ptr()), - finder.File().Length()); - foundDir = QDir(foundDir).canonicalPath(); - addImportPath(foundDir); - err = finder.Find(); - } - } else { - addImportPath(installImportsPath); - } -#else addImportPath(installImportsPath); -#endif - #endif // QT_NO_SETTINGS // env import paths QByteArray envImportPath = qgetenv("QML_IMPORT_PATH"); if (!envImportPath.isEmpty()) { -#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) +#if defined(Q_OS_WIN) QLatin1Char pathSep(';'); #else QLatin1Char pathSep(':'); @@ -899,7 +863,6 @@ QString QDeclarativeImportDatabase::resolvePlugin(QDeclarativeTypeLoader *typeLo \row \i AIX \i \c .a \row \i HP-UX \i \c .sl, \c .so (HP-UXi) \row \i Mac OS X \i \c .dylib, \c .bundle, \c .so - \row \i Symbian \i \c .dll \endtable Version number on unix are ignored. @@ -915,11 +878,6 @@ QString QDeclarativeImportDatabase::resolvePlugin(QDeclarativeTypeLoader *typeLo << QLatin1String("d.dll") // try a qmake-style debug build first # endif << QLatin1String(".dll")); -#elif defined(Q_OS_SYMBIAN) - return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, - QStringList() - << QLatin1String(".dll") - << QLatin1String(".qtplugin")); #else # if defined(Q_OS_DARWIN) diff --git a/src/declarative/qml/qdeclarativeincubator.cpp b/src/declarative/qml/qdeclarativeincubator.cpp index 05c73da3a2..80bdfac24a 100644 --- a/src/declarative/qml/qdeclarativeincubator.cpp +++ b/src/declarative/qml/qdeclarativeincubator.cpp @@ -65,8 +65,8 @@ void QDeclarativeEnginePrivate::incubate(QDeclarativeIncubator &i, QDeclarativeC QDeclarativeIncubatorPrivate *parentIncubator = 0; QDeclarativeContextData *cctxt = forContext; while (cctxt) { - if (cctxt->activeVME) { - parentIncubator = (QDeclarativeIncubatorPrivate *)cctxt->activeVME->data; + if (cctxt->activeVMEData) { + parentIncubator = (QDeclarativeIncubatorPrivate *)cctxt->activeVMEData; break; } cctxt = cctxt->parent; @@ -113,6 +113,8 @@ and it does not take ownership of it. void QDeclarativeEngine::setIncubationController(QDeclarativeIncubationController *controller) { Q_D(QDeclarativeEngine); + if (d->incubationController) + d->incubationController->d = 0; d->incubationController = controller; if (controller) controller->d = d; } @@ -155,6 +157,10 @@ void QDeclarativeIncubatorPrivate::clear() component->release(); component = 0; } + if (!rootContext.isNull()) { + rootContext->activeVMEData = 0; + rootContext = 0; + } if (nextWaitingFor.isInList()) { Q_ASSERT(waitingOnMe); @@ -250,6 +256,8 @@ void QDeclarativeIncubationController::incubatingObjectCountChanged(int incubati void QDeclarativeIncubatorPrivate::incubate(QDeclarativeVME::Interrupt &i) { + if (!component) + return; typedef QDeclarativeIncubatorPrivate IP; QRecursionWatcher<IP, &IP::recursion> watcher(this); @@ -311,7 +319,9 @@ void QDeclarativeIncubatorPrivate::incubate(QDeclarativeVME::Interrupt &i) if (watcher.hasRecursed()) return; - if (vme.complete(i)) { + QDeclarativeContextData *ctxt = vme.complete(i); + if (ctxt) { + rootContext = ctxt; progress = QDeclarativeIncubatorPrivate::Completed; goto finishIncubate; } @@ -570,7 +580,6 @@ void QDeclarativeIncubator::forceCompletion() if (Loading == status()) d->incubate(i); } - } /*! diff --git a/src/declarative/qml/qdeclarativeincubator_p.h b/src/declarative/qml/qdeclarativeincubator_p.h index eaa4ce5ecb..ebabbae1d2 100644 --- a/src/declarative/qml/qdeclarativeincubator_p.h +++ b/src/declarative/qml/qdeclarativeincubator_p.h @@ -46,6 +46,7 @@ #include <private/qdeclarativevme_p.h> #include <private/qrecursionwatcher_p.h> #include <private/qdeclarativeengine_p.h> +#include <private/qdeclarativecontext_p.h> // // W A R N I N G @@ -83,6 +84,7 @@ public: Progress progress; QObject *result; + QDeclarativeGuardedContextData rootContext; QDeclarativeCompiledData *component; QDeclarativeVME vme; QDeclarativeVMEGuard vmeGuard; diff --git a/src/declarative/qml/qdeclarativeinstruction_p.h b/src/declarative/qml/qdeclarativeinstruction_p.h index 7b36c9a87e..8940e99b96 100644 --- a/src/declarative/qml/qdeclarativeinstruction_p.h +++ b/src/declarative/qml/qdeclarativeinstruction_p.h @@ -211,13 +211,13 @@ union QDeclarativeInstruction }; struct instr_assignValueSource { QML_INSTR_HEADER - QDeclarativePropertyCache::RawData property; + QDeclarativePropertyRawData property; int owner; int castValue; }; struct instr_assignValueInterceptor { QML_INSTR_HEADER - QDeclarativePropertyCache::RawData property; + QDeclarativePropertyRawData property; int owner; int castValue; }; @@ -238,7 +238,7 @@ union QDeclarativeInstruction }; struct instr_assignBinding { QML_INSTR_HEADER - QDeclarativePropertyCache::RawData property; + QDeclarativePropertyRawData property; int value; short context; short owner; diff --git a/src/declarative/qml/qdeclarativelist.cpp b/src/declarative/qml/qdeclarativelist.cpp index 04cef6c737..c717ed0509 100644 --- a/src/declarative/qml/qdeclarativelist.cpp +++ b/src/declarative/qml/qdeclarativelist.cpp @@ -135,8 +135,8 @@ QDeclarativeListReference::QDeclarativeListReference(QObject *object, const char { if (!object || !property) return; - QDeclarativePropertyCache::Data local; - QDeclarativePropertyCache::Data *data = + QDeclarativePropertyData local; + QDeclarativePropertyData *data = QDeclarativePropertyCache::property(engine, object, QLatin1String(property), local); if (!data || !data->isQList()) return; diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp index 5577993fc5..9e178c630e 100644 --- a/src/declarative/qml/qdeclarativemetatype.cpp +++ b/src/declarative/qml/qdeclarativemetatype.cpp @@ -1056,6 +1056,21 @@ QDeclarativeMetaType::moduleApi(const QString &uri, int versionMajor, int versio return ModuleApi(); } +QHash<QString, QList<QDeclarativeMetaType::ModuleApi> > QDeclarativeMetaType::moduleApis() +{ + QReadLocker lock(metaTypeDataLock()); + QDeclarativeMetaTypeData *data = metaTypeData(); + + QHash<QString, QList<ModuleApi> > moduleApis; + QHashIterator<QString, QDeclarativeMetaTypeData::ModuleApiList> it(data->moduleApis); + while (it.hasNext()) { + it.next(); + moduleApis[it.key()] = it.value().moduleApis; + } + + return moduleApis; +} + QObject *QDeclarativeMetaType::toQObject(const QVariant &v, bool *ok) { if (!isQObject(v.userType())) { diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h index 39e8b850d0..4488600de1 100644 --- a/src/declarative/qml/qdeclarativemetatype_p.h +++ b/src/declarative/qml/qdeclarativemetatype_p.h @@ -129,6 +129,7 @@ public: QObject *(*qobject)(QDeclarativeEngine *, QJSEngine *); }; static ModuleApi moduleApi(const QString &, int, int); + static QHash<QString, QList<ModuleApi> > moduleApis(); }; class QHashedStringRef; diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp index 9e4770f3f4..d6a2776b32 100644 --- a/src/declarative/qml/qdeclarativeproperty.cpp +++ b/src/declarative/qml/qdeclarativeproperty.cpp @@ -266,8 +266,8 @@ void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name } - QDeclarativePropertyCache::Data local; - QDeclarativePropertyCache::Data *property = + QDeclarativePropertyData local; + QDeclarativePropertyData *property = QDeclarativePropertyCache::property(engine, obj, pathName, local); if (!property) return; // Not a property @@ -285,7 +285,7 @@ void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name QMetaProperty vtProp = typeObject->metaObject()->property(idx); - typedef QDeclarativePropertyCache::Data PCD; + typedef QDeclarativePropertyData PCD; Q_ASSERT(PCD::flagsForProperty(vtProp) <= PCD::ValueTypeFlagMask); Q_ASSERT(vtProp.userType() <= 0xFF); @@ -330,8 +330,8 @@ void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name } // Property - QDeclarativePropertyCache::Data local; - QDeclarativePropertyCache::Data *property = + QDeclarativePropertyData local; + QDeclarativePropertyData *property = QDeclarativePropertyCache::property(engine, currentObject, terminal, local); if (property && !property->isFunction()) { object = currentObject; @@ -707,7 +707,7 @@ QDeclarativePropertyPrivate::binding(QObject *object, int coreIndex, int valueTy if (!data) return 0; - QDeclarativePropertyCache::Data *propertyData = + QDeclarativePropertyData *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; if (propertyData && propertyData->isAlias()) { const QDeclarativeVMEMetaObject *vme = @@ -748,7 +748,7 @@ void QDeclarativePropertyPrivate::findAliasTarget(QObject *object, int bindingIn QDeclarativeData *data = QDeclarativeData::get(object, false); if (data) { - QDeclarativePropertyCache::Data *propertyData = + QDeclarativePropertyData *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; if (propertyData && propertyData->isAlias()) { const QDeclarativeVMEMetaObject *vme = @@ -782,7 +782,7 @@ QDeclarativePropertyPrivate::setBinding(QObject *object, int coreIndex, int valu QDeclarativeAbstractBinding *binding = 0; if (data) { - QDeclarativePropertyCache::Data *propertyData = + QDeclarativePropertyData *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; if (propertyData && propertyData->isAlias()) { const QDeclarativeVMEMetaObject *vme = @@ -836,7 +836,7 @@ QDeclarativePropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, QDeclarativeAbstractBinding *binding = 0; if (data) { - QDeclarativePropertyCache::Data *propertyData = + QDeclarativePropertyData *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; if (propertyData && propertyData->isAlias()) { const QDeclarativeVMEMetaObject *vme = @@ -1089,7 +1089,7 @@ bool QDeclarativePropertyPrivate::writeValueProperty(const QVariant &value, Writ bool QDeclarativePropertyPrivate::writeValueProperty(QObject *object, QDeclarativeEngine *engine, - const QDeclarativePropertyCache::Data &core, + const QDeclarativePropertyData &core, const QVariant &value, QDeclarativeContextData *context, WriteFlags flags) { @@ -1114,8 +1114,8 @@ QDeclarativePropertyPrivate::writeValueProperty(QObject *object, QDeclarativeEng writeBack->read(object, core.coreIndex); - QDeclarativePropertyCache::Data data = core; - data.setFlags(QDeclarativePropertyCache::Data::Flag(core.valueTypeFlags)); + QDeclarativePropertyData data = core; + data.setFlags(QDeclarativePropertyData::Flag(core.valueTypeFlags)); data.coreIndex = core.valueTypeCoreIndex; data.propType = core.valueTypePropType; @@ -1134,7 +1134,7 @@ QDeclarativePropertyPrivate::writeValueProperty(QObject *object, QDeclarativeEng } bool QDeclarativePropertyPrivate::write(QObject *object, - const QDeclarativePropertyCache::Data &property, + const QDeclarativePropertyData &property, const QVariant &value, QDeclarativeContextData *context, WriteFlags flags) { @@ -1298,7 +1298,7 @@ bool QDeclarativePropertyPrivate::write(QObject *object, // Returns true if successful, false if an error description was set on expression bool QDeclarativePropertyPrivate::writeBinding(QObject *object, - const QDeclarativePropertyCache::Data &core, + const QDeclarativePropertyData &core, QDeclarativeJavaScriptExpression *expression, v8::Handle<v8::Value> result, bool isUndefined, WriteFlags flags) @@ -1348,7 +1348,7 @@ bool QDeclarativePropertyPrivate::writeBinding(QObject *object, int type = core.isValueTypeVirtual()?core.valueTypePropType:core.propType; - QDeclarativeDeleteWatcher watcher(expression); + QDeleteWatcher watcher(expression); QVariant value; bool isVmeProperty = core.isVMEProperty(); @@ -1606,7 +1606,7 @@ int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativeProperty &that) return bindingIndex(that.d->core); } -int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativePropertyCache::Data &that) +int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativePropertyData &that) { int rv = that.coreIndex; if (rv != -1 && that.isValueTypeVirtual()) @@ -1614,18 +1614,17 @@ int QDeclarativePropertyPrivate::bindingIndex(const QDeclarativePropertyCache::D return rv; } -QDeclarativePropertyCache::Data +QDeclarativePropertyData QDeclarativePropertyPrivate::saveValueType(const QMetaObject *metaObject, int index, const QMetaObject *subObject, int subIndex, QDeclarativeEngine *) { - QMetaProperty prop = metaObject->property(index); QMetaProperty subProp = subObject->property(subIndex); - QDeclarativePropertyCache::Data core; + QDeclarativePropertyData core; core.load(metaObject->property(index)); - core.setFlags(core.getFlags() | QDeclarativePropertyCache::Data::IsValueTypeVirtual); - core.valueTypeFlags = QDeclarativePropertyCache::Data::flagsForProperty(subProp); + core.setFlags(core.getFlags() | QDeclarativePropertyData::IsValueTypeVirtual); + core.valueTypeFlags = QDeclarativePropertyData::flagsForProperty(subProp); core.valueTypeCoreIndex = subIndex; core.valueTypePropType = subProp.userType(); @@ -1633,7 +1632,7 @@ QDeclarativePropertyPrivate::saveValueType(const QMetaObject *metaObject, int in } QDeclarativeProperty -QDeclarativePropertyPrivate::restore(const QDeclarativePropertyCache::Data &data, +QDeclarativePropertyPrivate::restore(const QDeclarativePropertyData &data, QObject *object, QDeclarativeContextData *ctxt) { QDeclarativeProperty prop; @@ -1737,7 +1736,7 @@ static inline void flush_vme_signal(const QObject *object, int index) { QDeclarativeData *data = static_cast<QDeclarativeData *>(QObjectPrivate::get(const_cast<QObject *>(object))->declarativeData); if (data && data->propertyCache) { - QDeclarativePropertyCache::Data *property = data->propertyCache->method(index); + QDeclarativePropertyData *property = data->propertyCache->method(index); if (property && property->isVMESignal()) { const QMetaObject *metaObject = object->metaObject(); diff --git a/src/declarative/qml/qdeclarativeproperty_p.h b/src/declarative/qml/qdeclarativeproperty_p.h index 5bfbf47c0d..f2e86dda19 100644 --- a/src/declarative/qml/qdeclarativeproperty_p.h +++ b/src/declarative/qml/qdeclarativeproperty_p.h @@ -81,7 +81,7 @@ public: QDeclarativeGuard<QObject> object; bool isNameCached:1; - QDeclarativePropertyCache::Data core; + QDeclarativePropertyData core; QString nameCache; void initProperty(QObject *obj, const QString &name); @@ -99,10 +99,10 @@ public: static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags); static bool writeValueProperty(QObject *, QDeclarativeEngine *, - const QDeclarativePropertyCache::Data &, + const QDeclarativePropertyData &, const QVariant &, QDeclarativeContextData *, WriteFlags flags = 0); - static bool write(QObject *, const QDeclarativePropertyCache::Data &, const QVariant &, + static bool write(QObject *, const QDeclarativePropertyData &, const QVariant &, QDeclarativeContextData *, WriteFlags flags = 0); static void findAliasTarget(QObject *, int, QObject **, int *); static QDeclarativeAbstractBinding *setBinding(QObject *, int coreIndex, int valueTypeIndex /* -1 */, @@ -112,10 +112,10 @@ public: QDeclarativeAbstractBinding *); static QDeclarativeAbstractBinding *binding(QObject *, int coreIndex, int valueTypeIndex /* -1 */); - static QDeclarativePropertyCache::Data saveValueType(const QMetaObject *, int, - const QMetaObject *, int, - QDeclarativeEngine *); - static QDeclarativeProperty restore(const QDeclarativePropertyCache::Data &, + static QDeclarativePropertyData saveValueType(const QMetaObject *, int, + const QMetaObject *, int, + QDeclarativeEngine *); + static QDeclarativeProperty restore(const QDeclarativePropertyData &, QObject *, QDeclarativeContextData *); @@ -138,13 +138,13 @@ public: QDeclarativeJavaScriptExpression *expression, v8::Handle<v8::Value> result, bool isUndefined, WriteFlags flags); - static bool writeBinding(QObject *, const QDeclarativePropertyCache::Data &, + static bool writeBinding(QObject *, const QDeclarativePropertyData &, QDeclarativeJavaScriptExpression *expression, v8::Handle<v8::Value> result, bool isUndefined, WriteFlags flags); static int valueTypeCoreIndex(const QDeclarativeProperty &that); static int bindingIndex(const QDeclarativeProperty &that); - static int bindingIndex(const QDeclarativePropertyCache::Data &that); + static int bindingIndex(const QDeclarativePropertyData &that); static QMetaMethod findSignalByName(const QMetaObject *mo, const QByteArray &); static bool connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp index 134c588538..d99731955b 100644 --- a/src/declarative/qml/qdeclarativepropertycache.cpp +++ b/src/declarative/qml/qdeclarativepropertycache.cpp @@ -54,60 +54,67 @@ Q_DECLARE_METATYPE(QDeclarativeV8Handle); QT_BEGIN_NAMESPACE +class QDeclarativePropertyCacheMethodArguments +{ +public: + QDeclarativePropertyCacheMethodArguments *next; + int arguments[0]; +}; + // Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick // to load -static QDeclarativePropertyCache::Data::Flags fastFlagsForProperty(const QMetaProperty &p) +static QDeclarativePropertyData::Flags fastFlagsForProperty(const QMetaProperty &p) { - QDeclarativePropertyCache::Data::Flags flags; + QDeclarativePropertyData::Flags flags; if (p.isConstant()) - flags |= QDeclarativePropertyCache::Data::IsConstant; + flags |= QDeclarativePropertyData::IsConstant; if (p.isWritable()) - flags |= QDeclarativePropertyCache::Data::IsWritable; + flags |= QDeclarativePropertyData::IsWritable; if (p.isResettable()) - flags |= QDeclarativePropertyCache::Data::IsResettable; + flags |= QDeclarativePropertyData::IsResettable; if (p.isFinal()) - flags |= QDeclarativePropertyCache::Data::IsFinal; + flags |= QDeclarativePropertyData::IsFinal; if (p.isEnumType()) - flags |= QDeclarativePropertyCache::Data::IsEnumType; + flags |= QDeclarativePropertyData::IsEnumType; return flags; } // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to // load -static QDeclarativePropertyCache::Data::Flags flagsForPropertyType(int propType, QDeclarativeEngine *engine) +static QDeclarativePropertyData::Flags flagsForPropertyType(int propType, QDeclarativeEngine *engine) { - QDeclarativePropertyCache::Data::Flags flags; + QDeclarativePropertyData::Flags flags; if (propType < QMetaType::User && propType != QMetaType::QObjectStar && propType != QMetaType::QWidgetStar) { } else if (propType == qMetaTypeId<QDeclarativeBinding *>()) { - flags |= QDeclarativePropertyCache::Data::IsQmlBinding; + flags |= QDeclarativePropertyData::IsQmlBinding; } else if (propType == qMetaTypeId<QJSValue>()) { - flags |= QDeclarativePropertyCache::Data::IsQJSValue; + flags |= QDeclarativePropertyData::IsQJSValue; } else if (propType == qMetaTypeId<QDeclarativeV8Handle>()) { - flags |= QDeclarativePropertyCache::Data::IsV8Handle; + flags |= QDeclarativePropertyData::IsV8Handle; } else { QDeclarativeMetaType::TypeCategory cat = engine ? QDeclarativeEnginePrivate::get(engine)->typeCategory(propType) : QDeclarativeMetaType::typeCategory(propType); if (cat == QDeclarativeMetaType::Object) - flags |= QDeclarativePropertyCache::Data::IsQObjectDerived; + flags |= QDeclarativePropertyData::IsQObjectDerived; else if (cat == QDeclarativeMetaType::List) - flags |= QDeclarativePropertyCache::Data::IsQList; + flags |= QDeclarativePropertyData::IsQList; } return flags; } -QDeclarativePropertyCache::Data::Flags -QDeclarativePropertyCache::Data::flagsForProperty(const QMetaProperty &p, QDeclarativeEngine *engine) +QDeclarativePropertyData::Flags +QDeclarativePropertyData::flagsForProperty(const QMetaProperty &p, QDeclarativeEngine *engine) { return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine); } -void QDeclarativePropertyCache::Data::lazyLoad(const QMetaProperty &p, QDeclarativeEngine *engine) +void QDeclarativePropertyData::lazyLoad(const QMetaProperty &p, QDeclarativeEngine *engine) { Q_UNUSED(engine); @@ -120,16 +127,16 @@ void QDeclarativePropertyCache::Data::lazyLoad(const QMetaProperty &p, QDeclarat int type = p.type(); if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) { propType = type; - flags |= QDeclarativePropertyCache::Data::IsQObjectDerived; + flags |= QDeclarativePropertyData::IsQObjectDerived; } else if (type == QVariant::UserType || type == -1) { propTypeName = p.typeName(); - flags |= QDeclarativePropertyCache::Data::NotFullyResolved; + flags |= QDeclarativePropertyData::NotFullyResolved; } else { propType = type; } } -void QDeclarativePropertyCache::Data::load(const QMetaProperty &p, QDeclarativeEngine *engine) +void QDeclarativePropertyData::load(const QMetaProperty &p, QDeclarativeEngine *engine) { propType = p.userType(); if (QVariant::Type(propType) == QVariant::LastType) @@ -140,13 +147,13 @@ void QDeclarativePropertyCache::Data::load(const QMetaProperty &p, QDeclarativeE revision = p.revision(); } -void QDeclarativePropertyCache::Data::load(const QMetaMethod &m) +void QDeclarativePropertyData::load(const QMetaMethod &m) { coreIndex = m.methodIndex(); - relatedIndex = -1; - flags |= Data::IsFunction; + arguments = 0; + flags |= IsFunction; if (m.methodType() == QMetaMethod::Signal) - flags |= Data::IsSignal; + flags |= IsSignal; propType = QVariant::Invalid; const char *returnType = m.typeName(); @@ -158,28 +165,28 @@ void QDeclarativePropertyCache::Data::load(const QMetaMethod &m) ++signature; if (*signature != ')') { - flags |= Data::HasArguments; + flags |= HasArguments; if (0 == ::strcmp(signature, "QDeclarativeV8Function*)")) { - flags |= Data::IsV8Function; + flags |= IsV8Function; } } revision = m.revision(); } -void QDeclarativePropertyCache::Data::lazyLoad(const QMetaMethod &m) +void QDeclarativePropertyData::lazyLoad(const QMetaMethod &m) { coreIndex = m.methodIndex(); - relatedIndex = -1; - flags |= Data::IsFunction; + arguments = 0; + flags |= IsFunction; if (m.methodType() == QMetaMethod::Signal) - flags |= Data::IsSignal; + flags |= IsSignal; propType = QVariant::Invalid; const char *returnType = m.typeName(); if (returnType && *returnType) { propTypeName = returnType; - flags |= Data::NotFullyResolved; + flags |= NotFullyResolved; } const char *signature = m.signature(); @@ -187,9 +194,9 @@ void QDeclarativePropertyCache::Data::lazyLoad(const QMetaMethod &m) ++signature; if (*signature != ')') { - flags |= Data::HasArguments; + flags |= HasArguments; if (0 == ::strcmp(signature, "QDeclarativeV8Function*)")) { - flags |= Data::IsV8Function; + flags |= IsV8Function; } } @@ -200,7 +207,8 @@ void QDeclarativePropertyCache::Data::lazyLoad(const QMetaMethod &m) Creates a new empty QDeclarativePropertyCache. */ QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e) -: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0) +: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), metaObject(0), + argumentsCache(0) { Q_ASSERT(engine); } @@ -209,7 +217,8 @@ QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e) Creates a new QDeclarativePropertyCache of \a metaObject. */ QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e, const QMetaObject *metaObject) -: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0) +: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), metaObject(0), + argumentsCache(0) { Q_ASSERT(engine); Q_ASSERT(metaObject); @@ -221,6 +230,13 @@ QDeclarativePropertyCache::~QDeclarativePropertyCache() { clear(); + QDeclarativePropertyCacheMethodArguments *args = argumentsCache; + while (args) { + QDeclarativePropertyCacheMethodArguments *next = args->next; + qFree(args); + args = next; + } + if (parent) parent->release(); parent = 0; engine = 0; @@ -243,12 +259,12 @@ void QDeclarativePropertyCache::clear() engine = 0; } -QDeclarativePropertyCache::Data QDeclarativePropertyCache::create(const QMetaObject *metaObject, - const QString &property) +QDeclarativePropertyData QDeclarativePropertyCache::create(const QMetaObject *metaObject, + const QString &property) { Q_ASSERT(metaObject); - QDeclarativePropertyCache::Data rv; + QDeclarativePropertyData rv; { const QMetaObject *cmo = metaObject; const QByteArray propertyName = property.toUtf8(); @@ -298,6 +314,7 @@ QDeclarativePropertyCache *QDeclarativePropertyCache::copy(int reserve) cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart; cache->stringCache.copyAndReserve(stringCache, reserve); cache->allowedRevisionCache = allowedRevisionCache; + cache->metaObject = metaObject; // We specifically do *NOT* copy the constructor @@ -305,18 +322,24 @@ QDeclarativePropertyCache *QDeclarativePropertyCache::copy(int reserve) } void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaObject *metaObject, - Data::Flag propertyFlags, Data::Flag methodFlags, Data::Flag signalFlags) + QDeclarativePropertyData::Flag propertyFlags, + QDeclarativePropertyData::Flag methodFlags, + QDeclarativePropertyData::Flag signalFlags) { append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags); } void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaObject *metaObject, int revision, - Data::Flag propertyFlags, Data::Flag methodFlags, Data::Flag signalFlags) + QDeclarativePropertyData::Flag propertyFlags, + QDeclarativePropertyData::Flag methodFlags, + QDeclarativePropertyData::Flag signalFlags) { Q_UNUSED(revision); Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache + this->metaObject = metaObject; + bool dynamicMetaObject = isDynamicMetaObject(metaObject); allowedRevisionCache.append(0); @@ -345,8 +368,8 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb ++cptr; } - Data *data = &methodIndexCache[ii - methodIndexCacheStart]; - Data *sigdata = 0; + QDeclarativePropertyData *data = &methodIndexCache[ii - methodIndexCacheStart]; + QDeclarativePropertyData *sigdata = 0; data->lazyLoad(m); @@ -356,21 +379,21 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb data->flags |= methodFlags; if (!dynamicMetaObject) - data->flags |= Data::IsDirect; + data->flags |= QDeclarativePropertyData::IsDirect; data->metaObjectOffset = allowedRevisionCache.count() - 1; if (data->isSignal()) { sigdata = &signalHandlerIndexCache[signalHandlerIndex]; *sigdata = *data; - sigdata->flags |= Data::IsSignalHandler; + sigdata->flags |= QDeclarativePropertyData::IsSignalHandler; } - Data *old = 0; + QDeclarativePropertyData *old = 0; if (utf8) { QHashedString methodName(QString::fromUtf8(signature, cptr - signature)); - if (Data **it = stringCache.value(methodName)) + if (QDeclarativePropertyData **it = stringCache.value(methodName)) old = *it; stringCache.insert(methodName, data); @@ -381,7 +404,7 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb } } else { QHashedCStringRef methodName(signature, cptr - signature); - if (Data **it = stringCache.value(methodName)) + if (QDeclarativePropertyData **it = stringCache.value(methodName)) old = *it; stringCache.insert(methodName, data); @@ -404,9 +427,9 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb if (old) { // We only overload methods in the same class, exactly like C++ - if (old->flags & Data::IsFunction && old->coreIndex >= methodOffset) - data->relatedIndex = old->coreIndex; - data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction); + if (old->isFunction() && old->coreIndex >= methodOffset) + data->flags |= QDeclarativePropertyData::IsOverload; + data->overrideIndexIsProperty = !old->isFunction(); data->overrideIndex = old->coreIndex; } } @@ -428,38 +451,38 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb ++cptr; } - Data *data = &propertyIndexCache[ii - propertyIndexCacheStart]; + QDeclarativePropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart]; data->lazyLoad(p, engine); data->flags |= propertyFlags; if (!dynamicMetaObject) - data->flags |= Data::IsDirect; + data->flags |= QDeclarativePropertyData::IsDirect; data->metaObjectOffset = allowedRevisionCache.count() - 1; - Data *old = 0; + QDeclarativePropertyData *old = 0; if (utf8) { QHashedString propName(QString::fromUtf8(str, cptr - str)); - if (Data **it = stringCache.value(propName)) + if (QDeclarativePropertyData **it = stringCache.value(propName)) old = *it; stringCache.insert(propName, data); } else { QHashedCStringRef propName(str, cptr - str); - if (Data **it = stringCache.value(propName)) + if (QDeclarativePropertyData **it = stringCache.value(propName)) old = *it; stringCache.insert(propName, data); } if (old) { - data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction); + data->overrideIndexIsProperty = !old->isFunction(); data->overrideIndex = old->coreIndex; } } } -void QDeclarativePropertyCache::resolve(Data *data) const +void QDeclarativePropertyCache::resolve(QDeclarativePropertyData *data) const { Q_ASSERT(data->notFullyResolved()); @@ -468,10 +491,10 @@ void QDeclarativePropertyCache::resolve(Data *data) const data->propType = qMetaTypeId<QVariant>(); - if (!(data->flags & Data::IsFunction)) + if (!data->isFunction()) data->flags |= flagsForPropertyType(data->propType, engine); - data->flags &= ~Data::NotFullyResolved; + data->flags &= ~QDeclarativePropertyData::NotFullyResolved; } void QDeclarativePropertyCache::updateRecur(QDeclarativeEngine *engine, const QMetaObject *metaObject) @@ -501,7 +524,7 @@ void QDeclarativePropertyCache::update(QDeclarativeEngine *engine, const QMetaOb updateRecur(engine,metaObject); } -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * QDeclarativePropertyCache::property(int index) const { if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count())) @@ -510,12 +533,12 @@ QDeclarativePropertyCache::property(int index) const if (index < propertyIndexCacheStart) return parent->property(index); - Data *rv = const_cast<Data *>(&propertyIndexCache.at(index - propertyIndexCacheStart)); + QDeclarativePropertyData *rv = const_cast<QDeclarativePropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart)); if (rv->notFullyResolved()) resolve(rv); return rv; } -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * QDeclarativePropertyCache::method(int index) const { if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) @@ -524,36 +547,36 @@ QDeclarativePropertyCache::method(int index) const if (index < methodIndexCacheStart) return parent->method(index); - Data *rv = const_cast<Data *>(&methodIndexCache.at(index - methodIndexCacheStart)); + QDeclarativePropertyData *rv = const_cast<QDeclarativePropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart)); if (rv->notFullyResolved()) resolve(rv); return rv; } -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * QDeclarativePropertyCache::property(const QHashedStringRef &str) const { - QDeclarativePropertyCache::Data **rv = stringCache.value(str); + QDeclarativePropertyData **rv = stringCache.value(str); if (rv && (*rv)->notFullyResolved()) resolve(*rv); return rv?*rv:0; } -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * QDeclarativePropertyCache::property(const QHashedCStringRef &str) const { - QDeclarativePropertyCache::Data **rv = stringCache.value(str); + QDeclarativePropertyData **rv = stringCache.value(str); if (rv && (*rv)->notFullyResolved()) resolve(*rv); return rv?*rv:0; } -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * QDeclarativePropertyCache::property(const QString &str) const { - QDeclarativePropertyCache::Data **rv = stringCache.value(str); + QDeclarativePropertyData **rv = stringCache.value(str); if (rv && (*rv)->notFullyResolved()) resolve(*rv); return rv?*rv:0; } -QString QDeclarativePropertyCache::Data::name(QObject *object) +QString QDeclarativePropertyData::name(QObject *object) { if (!object) return QString(); @@ -561,7 +584,7 @@ QString QDeclarativePropertyCache::Data::name(QObject *object) return name(object->metaObject()); } -QString QDeclarativePropertyCache::Data::name(const QMetaObject *metaObject) +QString QDeclarativePropertyData::name(const QMetaObject *metaObject) { if (!metaObject || coreIndex == -1) return QString(); @@ -588,9 +611,97 @@ QStringList QDeclarativePropertyCache::propertyNames() const return keys; } -QDeclarativePropertyCache::Data * +static int EnumType(const QMetaObject *meta, const QByteArray &str) +{ + QByteArray scope; + QByteArray name; + int scopeIdx = str.lastIndexOf("::"); + if (scopeIdx != -1) { + scope = str.left(scopeIdx); + name = str.mid(scopeIdx + 2); + } else { + name = str; + } + for (int i = meta->enumeratorCount() - 1; i >= 0; --i) { + QMetaEnum m = meta->enumerator(i); + if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) + return QVariant::Int; + } + return QVariant::Invalid; +} + +// Returns an array of the arguments for method \a index. The first entry in the array +// is the number of arguments. +int *QDeclarativePropertyCache::methodParameterTypes(QObject *object, int index, + QVarLengthArray<int, 9> &dummy, + QByteArray *unknownTypeError) +{ + Q_ASSERT(object && index >= 0); + + QDeclarativeData *ddata = QDeclarativeData::get(object, false); + + if (ddata && ddata->propertyCache) { + typedef QDeclarativePropertyCacheMethodArguments A; + + QDeclarativePropertyCache *c = ddata->propertyCache; + Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count()); + + while (index < c->methodIndexCacheStart) + c = c->parent; + + QDeclarativePropertyData *rv = const_cast<QDeclarativePropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart)); + + if (rv->arguments) + return static_cast<A *>(rv->arguments)->arguments; + + const QMetaObject *metaObject = object->metaObject(); + QMetaMethod m = metaObject->method(index); + QList<QByteArray> argTypeNames = m.parameterTypes(); + + A *args = static_cast<A *>(qMalloc(sizeof(A) + (argTypeNames.count() + 1) * sizeof(int))); + args->arguments[0] = argTypeNames.count(); + + for (int ii = 0; ii < argTypeNames.count(); ++ii) { + int type = QMetaType::type(argTypeNames.at(ii)); + if (type == QVariant::Invalid) + type = EnumType(object->metaObject(), argTypeNames.at(ii)); + if (type == QVariant::Invalid) { + if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); + qFree(args); + return 0; + } + args->arguments[ii + 1] = type; + } + + rv->arguments = args; + args->next = c->argumentsCache; + c->argumentsCache = args; + return static_cast<A *>(rv->arguments)->arguments; + + } else { + QMetaMethod m = object->metaObject()->method(index); + QList<QByteArray> argTypeNames = m.parameterTypes(); + dummy.resize(argTypeNames.count() + 1); + dummy[0] = argTypeNames.count(); + + for (int ii = 0; ii < argTypeNames.count(); ++ii) { + int type = QMetaType::type(argTypeNames.at(ii)); + if (type == QVariant::Invalid) + type = EnumType(object->metaObject(), argTypeNames.at(ii)); + if (type == QVariant::Invalid) { + if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); + return 0; + } + dummy[ii + 1] = type; + } + + return dummy.data(); + } +} + +QDeclarativePropertyData * QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, - const QHashedV8String &name, Data &local) + const QHashedV8String &name, QDeclarativePropertyData &local) { // XXX Optimize for worker script case where engine isn't available QDeclarativePropertyCache *cache = 0; @@ -606,7 +717,7 @@ QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, } } - QDeclarativePropertyCache::Data *rv = 0; + QDeclarativePropertyData *rv = 0; if (cache) { rv = cache->property(name); @@ -621,11 +732,11 @@ QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, return rv; } -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, - const QString &name, Data &local) + const QString &name, QDeclarativePropertyData &local) { - QDeclarativePropertyCache::Data *rv = 0; + QDeclarativePropertyData *rv = 0; if (!engine) { local = QDeclarativePropertyCache::create(obj->metaObject(), name); diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h index 068db589bd..fc4a24ca9c 100644 --- a/src/declarative/qml/qdeclarativepropertycache_p.h +++ b/src/declarative/qml/qdeclarativepropertycache_p.h @@ -58,6 +58,7 @@ #include "qdeclarativenotifier_p.h" #include <private/qhashedstring_p.h> +#include <QtCore/qvarlengtharray.h> #include <QtCore/qvector.h> QT_BEGIN_NAMESPACE @@ -66,162 +67,177 @@ class QDeclarativeEngine; class QMetaProperty; class QV8Engine; class QV8QObjectWrapper; +class QDeclarativePropertyCacheMethodArguments; +class QDeclarativePropertyData; -class Q_DECLARATIVE_EXPORT QDeclarativePropertyCache : public QDeclarativeRefCount, public QDeclarativeCleanup +// We have this somewhat aweful split between RawData and Data so that RawData can be +// used in unions. In normal code, you should always use Data which initializes RawData +// to an invalid state on construction. +class QDeclarativePropertyRawData { public: - QDeclarativePropertyCache(QDeclarativeEngine *); - QDeclarativePropertyCache(QDeclarativeEngine *, const QMetaObject *); - virtual ~QDeclarativePropertyCache(); - - // We have this somewhat aweful split between RawData and Data so that RawData can be - // used in unions. In normal code, you should always use Data which initializes RawData - // to an invalid state on construction. - struct Data; - struct RawData { - enum Flag { - NoFlags = 0x00000000, - ValueTypeFlagMask = 0x0000FFFF, // Flags in valueTypeFlags must fit in this mask - - // Can apply to all properties, except IsFunction - IsConstant = 0x00000001, // Has CONST flag - IsWritable = 0x00000002, // Has WRITE function - IsResettable = 0x00000004, // Has RESET function - IsAlias = 0x00000008, // Is a QML alias to another property - IsFinal = 0x00000010, // Has FINAL flag - IsDirect = 0x00000020, // Exists on a C++ QMetaObject - - // These are mutualy exclusive - IsFunction = 0x00000040, // Is an invokable - IsQObjectDerived = 0x00000080, // Property type is a QObject* derived type - IsEnumType = 0x00000100, // Property type is an enum - IsQList = 0x00000200, // Property type is a QML list - IsQmlBinding = 0x00000400, // Property type is a QDeclarativeBinding* - IsQJSValue = 0x00000800, // Property type is a QScriptValue - IsV8Handle = 0x00001000, // Property type is a QDeclarativeV8Handle - IsVMEProperty = 0x00002000, // Property type is a "var" property of VMEMO - IsValueTypeVirtual = 0x00004000, // Property is a value type "virtual" property - - // Apply only to IsFunctions - IsVMEFunction = 0x00008000, // Function was added by QML - HasArguments = 0x00010000, // Function takes arguments - IsSignal = 0x00020000, // Function is a signal - IsVMESignal = 0x00040000, // Signal was added by QML - IsV8Function = 0x00080000, // Function takes QDeclarativeV8Function* args - IsSignalHandler = 0x00100000, // Function is a signal handler - - // Internal QDeclarativePropertyCache flags - NotFullyResolved = 0x00200000 // True if the type data is to be lazily resolved - }; - Q_DECLARE_FLAGS(Flags, Flag) - - Flags getFlags() const { return Flag(flags); } - void setFlags(Flags f) { flags = f; } - - bool isValid() const { return coreIndex != -1; } - - bool isConstant() const { return flags & IsConstant; } - bool isWritable() const { return flags & IsWritable; } - bool isResettable() const { return flags & IsResettable; } - bool isAlias() const { return flags & IsAlias; } - bool isFinal() const { return flags & IsFinal; } - bool isDirect() const { return flags & IsDirect; } - bool isFunction() const { return flags & IsFunction; } - bool isQObject() const { return flags & IsQObjectDerived; } - bool isEnum() const { return flags & IsEnumType; } - bool isQList() const { return flags & IsQList; } - bool isQmlBinding() const { return flags & IsQmlBinding; } - bool isQJSValue() const { return flags & IsQJSValue; } - bool isV8Handle() const { return flags & IsV8Handle; } - bool isVMEProperty() const { return flags & IsVMEProperty; } - bool isValueTypeVirtual() const { return flags & IsValueTypeVirtual; } - bool isVMEFunction() const { return flags & IsVMEFunction; } - bool hasArguments() const { return flags & HasArguments; } - bool isSignal() const { return flags & IsSignal; } - bool isVMESignal() const { return flags & IsVMESignal; } - bool isV8Function() const { return flags & IsV8Function; } - bool isSignalHandler() const { return flags & IsSignalHandler; } - - union { - int propType; // When !NotFullyResolved - const char *propTypeName; // When NotFullyResolved - }; - int coreIndex; - union { - int notifyIndex; // When !IsFunction - int relatedIndex; // When IsFunction + enum Flag { + NoFlags = 0x00000000, + ValueTypeFlagMask = 0x0000FFFF, // Flags in valueTypeFlags must fit in this mask + + // Can apply to all properties, except IsFunction + IsConstant = 0x00000001, // Has CONST flag + IsWritable = 0x00000002, // Has WRITE function + IsResettable = 0x00000004, // Has RESET function + IsAlias = 0x00000008, // Is a QML alias to another property + IsFinal = 0x00000010, // Has FINAL flag + IsDirect = 0x00000020, // Exists on a C++ QMetaObject + + // These are mutualy exclusive + IsFunction = 0x00000040, // Is an invokable + IsQObjectDerived = 0x00000080, // Property type is a QObject* derived type + IsEnumType = 0x00000100, // Property type is an enum + IsQList = 0x00000200, // Property type is a QML list + IsQmlBinding = 0x00000400, // Property type is a QDeclarativeBinding* + IsQJSValue = 0x00000800, // Property type is a QScriptValue + IsV8Handle = 0x00001000, // Property type is a QDeclarativeV8Handle + IsVMEProperty = 0x00002000, // Property type is a "var" property of VMEMO + IsValueTypeVirtual = 0x00004000, // Property is a value type "virtual" property + + // Apply only to IsFunctions + IsVMEFunction = 0x00008000, // Function was added by QML + HasArguments = 0x00010000, // Function takes arguments + IsSignal = 0x00020000, // Function is a signal + IsVMESignal = 0x00040000, // Signal was added by QML + IsV8Function = 0x00080000, // Function takes QDeclarativeV8Function* args + IsSignalHandler = 0x00100000, // Function is a signal handler + IsOverload = 0x00200000, // Function is an overload of another function + + // Internal QDeclarativePropertyCache flags + NotFullyResolved = 0x00400000 // True if the type data is to be lazily resolved + }; + Q_DECLARE_FLAGS(Flags, Flag) + + Flags getFlags() const { return Flag(flags); } + void setFlags(Flags f) { flags = f; } + + bool isValid() const { return coreIndex != -1; } + + bool isConstant() const { return flags & IsConstant; } + bool isWritable() const { return flags & IsWritable; } + bool isResettable() const { return flags & IsResettable; } + bool isAlias() const { return flags & IsAlias; } + bool isFinal() const { return flags & IsFinal; } + bool isDirect() const { return flags & IsDirect; } + bool isFunction() const { return flags & IsFunction; } + bool isQObject() const { return flags & IsQObjectDerived; } + bool isEnum() const { return flags & IsEnumType; } + bool isQList() const { return flags & IsQList; } + bool isQmlBinding() const { return flags & IsQmlBinding; } + bool isQJSValue() const { return flags & IsQJSValue; } + bool isV8Handle() const { return flags & IsV8Handle; } + bool isVMEProperty() const { return flags & IsVMEProperty; } + bool isValueTypeVirtual() const { return flags & IsValueTypeVirtual; } + bool isVMEFunction() const { return flags & IsVMEFunction; } + bool hasArguments() const { return flags & HasArguments; } + bool isSignal() const { return flags & IsSignal; } + bool isVMESignal() const { return flags & IsVMESignal; } + bool isV8Function() const { return flags & IsV8Function; } + bool isSignalHandler() const { return flags & IsSignalHandler; } + bool isOverload() const { return flags & IsOverload; } + + union { + int propType; // When !NotFullyResolved + const char *propTypeName; // When NotFullyResolved + }; + int coreIndex; + union { + int notifyIndex; // When !IsFunction + void *arguments; // When IsFunction && HasArguments + }; + union { + struct { // When !IsValueTypeVirtual + uint overrideIndexIsProperty : 1; + signed int overrideIndex : 31; }; - union { - struct { // When !IsValueTypeVirtual - uint overrideIndexIsProperty : 1; - signed int overrideIndex : 31; - }; - struct { // When IsValueTypeVirtual - quint16 valueTypeFlags; // flags of the access property on the value type proxy object - quint8 valueTypePropType; // The QVariant::Type of access property on the value type - // proxy object - quint8 valueTypeCoreIndex; // The prop index of the access property on the value type - //proxy object - }; + struct { // When IsValueTypeVirtual + quint16 valueTypeFlags; // flags of the access property on the value type proxy object + quint8 valueTypePropType; // The QVariant::Type of access property on the value type + // proxy object + quint8 valueTypeCoreIndex; // The prop index of the access property on the value type + //proxy object }; - int revision; - int metaObjectOffset; - - private: - friend struct Data; - friend class QDeclarativePropertyCache; - quint32 flags; }; + int revision; + int metaObjectOffset; + +private: + friend class QDeclarativePropertyData; + friend class QDeclarativePropertyCache; + quint32 flags; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePropertyRawData::Flags); - struct Data : public RawData { - inline Data(); - inline Data(const RawData &); +class QDeclarativePropertyData : public QDeclarativePropertyRawData +{ +public: + inline QDeclarativePropertyData(); + inline QDeclarativePropertyData(const QDeclarativePropertyRawData &); - inline bool operator==(const RawData &); + inline bool operator==(const QDeclarativePropertyRawData &); - static Flags flagsForProperty(const QMetaProperty &, QDeclarativeEngine *engine = 0); - void load(const QMetaProperty &, QDeclarativeEngine *engine = 0); - void load(const QMetaMethod &); - QString name(QObject *); - QString name(const QMetaObject *); + static Flags flagsForProperty(const QMetaProperty &, QDeclarativeEngine *engine = 0); + void load(const QMetaProperty &, QDeclarativeEngine *engine = 0); + void load(const QMetaMethod &); + QString name(QObject *); + QString name(const QMetaObject *); - // Returns -1 if not a value type virtual property - inline int getValueTypeCoreIndex() const; + // Returns -1 if not a value type virtual property + inline int getValueTypeCoreIndex() const; - private: - friend class QDeclarativePropertyCache; - void lazyLoad(const QMetaProperty &, QDeclarativeEngine *engine = 0); - void lazyLoad(const QMetaMethod &); - bool notFullyResolved() const { return flags & NotFullyResolved; } - }; +private: + friend class QDeclarativePropertyCache; + void lazyLoad(const QMetaProperty &, QDeclarativeEngine *engine = 0); + void lazyLoad(const QMetaMethod &); + bool notFullyResolved() const { return flags & NotFullyResolved; } +}; + +class Q_DECLARATIVE_EXPORT QDeclarativePropertyCache : public QDeclarativeRefCount, public QDeclarativeCleanup +{ +public: + QDeclarativePropertyCache(QDeclarativeEngine *); + QDeclarativePropertyCache(QDeclarativeEngine *, const QMetaObject *); + virtual ~QDeclarativePropertyCache(); void update(QDeclarativeEngine *, const QMetaObject *); QDeclarativePropertyCache *copy(int reserve = 0); - void append(QDeclarativeEngine *, const QMetaObject *, Data::Flag propertyFlags = Data::NoFlags, - Data::Flag methodFlags = Data::NoFlags, Data::Flag signalFlags = Data::NoFlags); - void append(QDeclarativeEngine *, const QMetaObject *, int revision, Data::Flag propertyFlags = Data::NoFlags, - Data::Flag methodFlags = Data::NoFlags, Data::Flag signalFlags = Data::NoFlags); - - static Data create(const QMetaObject *, const QString &); - - inline Data *property(const QHashedV8String &) const; - Data *property(const QHashedStringRef &) const; - Data *property(const QHashedCStringRef &) const; - Data *property(const QString &) const; - Data *property(int) const; - Data *method(int) const; + void append(QDeclarativeEngine *, const QMetaObject *, + QDeclarativePropertyData::Flag propertyFlags = QDeclarativePropertyData::NoFlags, + QDeclarativePropertyData::Flag methodFlags = QDeclarativePropertyData::NoFlags, + QDeclarativePropertyData::Flag signalFlags = QDeclarativePropertyData::NoFlags); + void append(QDeclarativeEngine *, const QMetaObject *, int revision, + QDeclarativePropertyData::Flag propertyFlags = QDeclarativePropertyData::NoFlags, + QDeclarativePropertyData::Flag methodFlags = QDeclarativePropertyData::NoFlags, + QDeclarativePropertyData::Flag signalFlags = QDeclarativePropertyData::NoFlags); + + static QDeclarativePropertyData create(const QMetaObject *, const QString &); + + inline QDeclarativePropertyData *property(const QHashedV8String &) const; + QDeclarativePropertyData *property(const QHashedStringRef &) const; + QDeclarativePropertyData *property(const QHashedCStringRef &) const; + QDeclarativePropertyData *property(const QString &) const; + QDeclarativePropertyData *property(int) const; + QDeclarativePropertyData *method(int) const; QStringList propertyNames() const; - inline Data *overrideData(Data *) const; - inline bool isAllowedInRevision(Data *) const; + inline QDeclarativePropertyData *overrideData(QDeclarativePropertyData *) const; + inline bool isAllowedInRevision(QDeclarativePropertyData *) const; inline QDeclarativeEngine *qmlEngine() const; - static Data *property(QDeclarativeEngine *, QObject *, const QString &, Data &); - static Data *property(QDeclarativeEngine *, QObject *, const QHashedV8String &, Data &); + static QDeclarativePropertyData *property(QDeclarativeEngine *, QObject *, const QString &, + QDeclarativePropertyData &); + static QDeclarativePropertyData *property(QDeclarativeEngine *, QObject *, const QHashedV8String &, + QDeclarativePropertyData &); + static int *methodParameterTypes(QObject *, int index, QVarLengthArray<int, 9> &dummy, + QByteArray *unknownTypeError); static bool isDynamicMetaObject(const QMetaObject *); - protected: virtual void destroy(); virtual void clear(); @@ -233,11 +249,11 @@ private: // Implemented in v8/qv8qobjectwrapper.cpp v8::Local<v8::Object> newQObject(QObject *, QV8Engine *); - typedef QVector<Data> IndexCache; - typedef QStringHash<Data *> StringCache; + typedef QVector<QDeclarativePropertyData> IndexCache; + typedef QStringHash<QDeclarativePropertyData *> StringCache; typedef QVector<int> AllowedRevisionCache; - void resolve(Data *) const; + void resolve(QDeclarativePropertyData *) const; void updateRecur(QDeclarativeEngine *, const QMetaObject *); QDeclarativeEngine *engine; @@ -252,10 +268,12 @@ private: StringCache stringCache; AllowedRevisionCache allowedRevisionCache; v8::Persistent<v8::Function> constructor; + + const QMetaObject *metaObject; + QDeclarativePropertyCacheMethodArguments *argumentsCache; }; -Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePropertyCache::Data::Flags); -QDeclarativePropertyCache::Data::Data() +QDeclarativePropertyData::QDeclarativePropertyData() { propType = 0; coreIndex = -1; @@ -267,12 +285,12 @@ QDeclarativePropertyCache::Data::Data() flags = 0; } -QDeclarativePropertyCache::Data::Data(const QDeclarativePropertyCache::RawData &d) +QDeclarativePropertyData::QDeclarativePropertyData(const QDeclarativePropertyRawData &d) { - *(static_cast<RawData *>(this)) = d; + *(static_cast<QDeclarativePropertyRawData *>(this)) = d; } -bool QDeclarativePropertyCache::Data::operator==(const QDeclarativePropertyCache::RawData &other) +bool QDeclarativePropertyData::operator==(const QDeclarativePropertyRawData &other) { return flags == other.flags && propType == other.propType && @@ -284,13 +302,13 @@ bool QDeclarativePropertyCache::Data::operator==(const QDeclarativePropertyCache valueTypePropType == other.valueTypePropType)); } -int QDeclarativePropertyCache::Data::getValueTypeCoreIndex() const +int QDeclarativePropertyData::getValueTypeCoreIndex() const { return isValueTypeVirtual()?valueTypeCoreIndex:-1; } -QDeclarativePropertyCache::Data * -QDeclarativePropertyCache::overrideData(Data *data) const +QDeclarativePropertyData * +QDeclarativePropertyCache::overrideData(QDeclarativePropertyData *data) const { if (data->overrideIndex < 0) return 0; @@ -301,7 +319,7 @@ QDeclarativePropertyCache::overrideData(Data *data) const return method(data->overrideIndex); } -bool QDeclarativePropertyCache::isAllowedInRevision(Data *data) const +bool QDeclarativePropertyCache::isAllowedInRevision(QDeclarativePropertyData *data) const { return (data->metaObjectOffset == -1 && data->revision == 0) || (allowedRevisionCache[data->metaObjectOffset] >= data->revision); @@ -312,9 +330,9 @@ QDeclarativeEngine *QDeclarativePropertyCache::qmlEngine() const return engine; } -QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(const QHashedV8String &str) const +QDeclarativePropertyData *QDeclarativePropertyCache::property(const QHashedV8String &str) const { - QDeclarativePropertyCache::Data **rv = stringCache.value(str); + QDeclarativePropertyData **rv = stringCache.value(str); if (rv && (*rv)->notFullyResolved()) resolve(*rv); return rv?*rv:0; } diff --git a/src/declarative/qml/qdeclarativescript.cpp b/src/declarative/qml/qdeclarativescript.cpp index fb4f26a781..9d18cb3889 100644 --- a/src/declarative/qml/qdeclarativescript.cpp +++ b/src/declarative/qml/qdeclarativescript.cpp @@ -182,7 +182,7 @@ Property *QDeclarativeScript::Object::getProperty(const QString &name, bool crea } QDeclarativeScript::Object::DynamicProperty::DynamicProperty() -: isDefaultProperty(false), type(Variant), defaultValue(0), nextProperty(0), +: isDefaultProperty(false), isReadOnly(false), type(Variant), defaultValue(0), nextProperty(0), resolvedCustomTypeName(0) { } @@ -225,8 +225,8 @@ int QDeclarativeScript::Object::DynamicSlot::parameterNamesLength() const QDeclarativeScript::Property::Property() : parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false), - isValueTypeSubProperty(false), isAlias(false), scriptStringScope(-1), - nextMainProperty(0), nextProperty(0) + isValueTypeSubProperty(false), isAlias(false), isReadOnlyDeclaration(false), + scriptStringScope(-1), nextMainProperty(0), nextProperty(0) { } @@ -1028,18 +1028,9 @@ bool ProcessAST::visit(AST::UiPublicMember *node) return false; } - if (node->isReadonlyMember) { - QDeclarativeError error; - error.setDescription(QCoreApplication::translate("QDeclarativeParser","Readonly not yet supported")); - error.setLine(node->readonlyToken.startLine); - error.setColumn(node->readonlyToken.startColumn); - _parser->_errors << error; - return false; - - } - Object::DynamicProperty *property = _parser->_pool.New<Object::DynamicProperty>(); property->isDefaultProperty = node->isDefaultMember; + property->isReadOnly = node->isReadonlyMember; property->type = type; if (type >= Object::DynamicProperty::Custom) { QDeclarativeScript::TypeReference *typeRef = diff --git a/src/declarative/qml/qdeclarativescript_p.h b/src/declarative/qml/qdeclarativescript_p.h index c5b9a7e3f6..a83cd9f8f0 100644 --- a/src/declarative/qml/qdeclarativescript_p.h +++ b/src/declarative/qml/qdeclarativescript_p.h @@ -250,7 +250,7 @@ public: // The core data in the case of a regular property. // XXX This has to be a value now as the synthCache may change during // compilation which invalidates pointers. We should fix this. - QDeclarativePropertyCache::Data core; + QDeclarativePropertyData core; // Returns true if this is an empty property - both value and values // are unset. @@ -279,6 +279,8 @@ public: // True if this property is a property alias. Set by the // QDeclarativeCompiler bool isAlias; + // True if this is a readonly property declaration + bool isReadOnlyDeclaration; // Used for scriptStringProperties int scriptStringScope; @@ -388,7 +390,9 @@ public: enum Type { Var, Variant, Int, Bool, Real, String, Url, Color, Time, Date, DateTime, Alias, Custom, CustomList }; - bool isDefaultProperty; + quint32 isDefaultProperty:1; + quint32 isReadOnly:1; + Type type; QHashedStringRef customType; diff --git a/src/declarative/qml/qdeclarativesqldatabase.cpp b/src/declarative/qml/qdeclarativesqldatabase.cpp index 920f835d19..80464fa8a3 100644 --- a/src/declarative/qml/qdeclarativesqldatabase.cpp +++ b/src/declarative/qml/qdeclarativesqldatabase.cpp @@ -217,7 +217,7 @@ static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV8Eng static v8::Handle<v8::Value> qmlsqldatabase_rows_index(QV8SqlDatabaseResource *r, uint32_t index) { - if (r->query.at() == index || r->query.seek(index)) { + if (r->query.at() == (int)index || r->query.seek(index)) { QSqlRecord record = r->query.record(); // XXX optimize diff --git a/src/declarative/qml/qdeclarativevaluetype.cpp b/src/declarative/qml/qdeclarativevaluetype.cpp index 9f43d0ef72..9a941e63f9 100644 --- a/src/declarative/qml/qdeclarativevaluetype.cpp +++ b/src/declarative/qml/qdeclarativevaluetype.cpp @@ -92,7 +92,7 @@ QDeclarativeValueTypeFactory::~QDeclarativeValueTypeFactory() bool QDeclarativeValueTypeFactory::isValueType(int idx) { - if ((uint)idx < QVariant::UserType) + if ((uint)idx < QVariant::UserType && (uint)idx != QVariant::StringList) return true; return false; } diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index b7abef4aef..52095e34f3 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -310,7 +310,7 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors, } if (states.count() == 1) { rootContext = CTXT; - rootContext->activeVME = this; + rootContext->activeVMEData = data; } if (states.count() == 1 && !creationContext.isNull()) { // A component that is logically created within another component instance shares the @@ -1207,7 +1207,7 @@ void QDeclarativeVME::reset() delete objects.at(0); if (!rootContext.isNull()) - rootContext->activeVME = 0; + rootContext->activeVMEData = 0; // Remove the QDeclarativeParserStatus and QDeclarativeAbstractBinding back pointers blank(parserStatus); @@ -1342,7 +1342,7 @@ void **QDeclarativeVME::instructionJumpTable() } #endif -bool QDeclarativeVME::complete(const Interrupt &interrupt) +QDeclarativeContextData *QDeclarativeVME::complete(const Interrupt &interrupt) { Q_ASSERT(engine || (bindValues.isEmpty() && @@ -1352,7 +1352,7 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt) finalizeCallbacks.isEmpty())); if (!engine) - return true; + return 0; ActiveVMERestorer restore(this, QDeclarativeEnginePrivate::get(engine)); QRecursionWatcher<QDeclarativeVME, &QDeclarativeVME::recursion> watcher(this); @@ -1367,7 +1367,7 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt) } if (watcher.hasRecursed() || interrupt.shouldInterrupt()) - return false; + return 0; } bindValues.deallocate(); @@ -1380,10 +1380,22 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt) } if (watcher.hasRecursed() || interrupt.shouldInterrupt()) - return false; + return 0; } parserStatus.deallocate(); + for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) { + QDeclarativeEnginePrivate::FinalizeCallback callback = finalizeCallbacks.at(ii); + QObject *obj = callback.first; + if (obj) { + void *args[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args); + } + if (watcher.hasRecursed()) + return 0; + } + finalizeCallbacks.clear(); + while (componentAttached) { QDeclarativeComponentAttached *a = componentAttached; a->rem(); @@ -1394,27 +1406,16 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt) emit a->completed(); if (watcher.hasRecursed() || interrupt.shouldInterrupt()) - return false; + return 0; } - if (!rootContext.isNull()) - rootContext->activeVME = 0; - - for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) { - QDeclarativeEnginePrivate::FinalizeCallback callback = finalizeCallbacks.at(ii); - QObject *obj = callback.first; - if (obj) { - void *args[] = { 0 }; - QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, callback.second, args); - } - if (watcher.hasRecursed()) - return false; - } - finalizeCallbacks.clear(); + QDeclarativeContextData *rv = rootContext; reset(); - return true; + if (rv) rv->activeVMEData = data; + + return rv; } void QDeclarativeVME::blank(QFiniteStack<QDeclarativeAbstractBinding *> &bs) diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h index b74bc547bf..4edceb283a 100644 --- a/src/declarative/qml/qdeclarativevme_p.h +++ b/src/declarative/qml/qdeclarativevme_p.h @@ -125,7 +125,7 @@ public: void reset(); QObject *execute(QList<QDeclarativeError> *errors, const Interrupt & = Interrupt()); - bool complete(const Interrupt & = Interrupt()); + QDeclarativeContextData *complete(const Interrupt & = Interrupt()); private: friend class QDeclarativeVMEGuard; diff --git a/src/declarative/qml/qdeclarativevmemetaobject_p.h b/src/declarative/qml/qdeclarativevmemetaobject_p.h index 400961b27f..6076dcfe61 100644 --- a/src/declarative/qml/qdeclarativevmemetaobject_p.h +++ b/src/declarative/qml/qdeclarativevmemetaobject_p.h @@ -84,6 +84,8 @@ struct QDeclarativeVMEMetaData short aliasCount; short signalCount; short methodCount; + short dummyForAlignment; // Add padding to ensure that the following + // AliasData/PropertyData/MethodData is int aligned. struct AliasData { int contextIdx; diff --git a/src/declarative/qml/qdeclarativexmlhttprequest.cpp b/src/declarative/qml/qdeclarativexmlhttprequest.cpp index 0009163036..e64088b754 100644 --- a/src/declarative/qml/qdeclarativexmlhttprequest.cpp +++ b/src/declarative/qml/qdeclarativexmlhttprequest.cpp @@ -820,7 +820,7 @@ v8::Handle<v8::Value> NamedNodeMap::indexed(uint32_t index, const v8::AccessorIn if (!r || !r->list) return v8::Undefined(); QV8Engine *engine = V8ENGINE(); - if (index < r->list->count()) { + if ((int)index < r->list->count()) { return Node::create(engine, r->list->at(index)); } else { return v8::Undefined(); @@ -876,7 +876,7 @@ v8::Handle<v8::Value> NodeList::indexed(uint32_t index, const v8::AccessorInfo& if (!r) return v8::Undefined(); QV8Engine *engine = V8ENGINE(); - if (index < r->d->children.count()) { + if ((int)index < r->d->children.count()) { return Node::create(engine, r->d->children.at(index)); } else { return v8::Undefined(); diff --git a/src/declarative/qml/v4/qv4compiler.cpp b/src/declarative/qml/v4/qv4compiler.cpp index a9d2338307..31a0a1e63f 100644 --- a/src/declarative/qml/v4/qv4compiler.cpp +++ b/src/declarative/qml/v4/qv4compiler.cpp @@ -59,6 +59,7 @@ DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER) DEFINE_BOOL_CONFIG_OPTION(qmlBindingsTestEnv, QML_BINDINGS_TEST) static bool qmlBindingsTest = false; +static bool qmlEnableV4 = true; using namespace QDeclarativeJS; QV4CompilerPrivate::QV4CompilerPrivate() @@ -310,7 +311,8 @@ void QV4CompilerPrivate::visitName(IR::Name *e) attached.output = currentReg; attached.reg = currentReg; attached.exceptionId = exceptionId(e->line, e->column); - Q_ASSERT(e->declarativeType->attachedPropertiesId() != -1); + if (e->declarativeType->attachedPropertiesId() == -1) + discard(); attached.id = e->declarativeType->attachedPropertiesId(); gen(attached); } break; @@ -1219,7 +1221,7 @@ int QV4Compiler::compile(const Expression &expression, QDeclarativeEnginePrivate if (!qmlExperimental() && expression.property->isValueTypeSubProperty) return -1; - if (qmlDisableOptimizer()) + if (qmlDisableOptimizer() || !qmlEnableV4) return -1; d->expression = &expression; @@ -1341,4 +1343,9 @@ void QV4Compiler::enableBindingsTest(bool e) qmlBindingsTest = qmlBindingsTestEnv(); } +void QV4Compiler::enableV4(bool e) +{ + qmlEnableV4 = e; +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/v4/qv4compiler_p.h b/src/declarative/qml/v4/qv4compiler_p.h index 9fafaf95af..cb5225a9cf 100644 --- a/src/declarative/qml/v4/qv4compiler_p.h +++ b/src/declarative/qml/v4/qv4compiler_p.h @@ -92,6 +92,7 @@ public: static void dump(const QByteArray &); static void enableBindingsTest(bool); + static void enableV4(bool); private: QV4CompilerPrivate *d; }; diff --git a/src/declarative/qml/v4/qv4irbuilder.cpp b/src/declarative/qml/v4/qv4irbuilder.cpp index cfe77217fd..258627a079 100644 --- a/src/declarative/qml/v4/qv4irbuilder.cpp +++ b/src/declarative/qml/v4/qv4irbuilder.cpp @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE using namespace QDeclarativeJS; -static IR::Type irTypeFromVariantType(int t, QDeclarativeEnginePrivate *engine, const QMetaObject *meta) +static IR::Type irTypeFromVariantType(int t, QDeclarativeEnginePrivate *engine, const QMetaObject * /* meta */) { switch (t) { case QMetaType::Bool: @@ -74,8 +74,7 @@ static IR::Type irTypeFromVariantType(int t, QDeclarativeEnginePrivate *engine, return IR::AnchorLineType; else if (t == qMetaTypeId<QQuickAnchorLine>()) return IR::SGAnchorLineType; - else if (const QMetaObject *m = engine->metaObjectForType(t)) { - meta = m; + else if (engine->metaObjectForType(t)) { return IR::ObjectType; } @@ -456,7 +455,7 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast) const QMetaObject *metaObject = m_expression->context->metaObject(); if (!cache) cache = m_engine->cache(metaObject); - QDeclarativePropertyCache::Data *data = cache->property(name); + QDeclarativePropertyData *data = cache->property(name); if (data && data->revision != 0) { if (qmlVerboseCompiler()) @@ -477,7 +476,7 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast) const QMetaObject *metaObject = m_expression->component->metaObject(); if (!cache) cache = m_engine->cache(metaObject); - QDeclarativePropertyCache::Data *data = cache->property(name); + QDeclarativePropertyData *data = cache->property(name); if (data && data->revision != 0) { if (qmlVerboseCompiler()) @@ -603,7 +602,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast) << (*baseName->id + QLatin1String(".") + ast->name.toString()); } else if(const QMetaObject *attachedMeta = baseName->declarativeType->attachedPropertiesType()) { QDeclarativePropertyCache *cache = m_engine->cache(attachedMeta); - QDeclarativePropertyCache::Data *data = cache->property(name); + QDeclarativePropertyData *data = cache->property(name); if (!data || data->isFunction()) return false; // Don't support methods (or non-existing properties ;) @@ -625,7 +624,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast) QDeclarativePropertyCache *cache = idObject->synthCache?idObject->synthCache:m_engine->cache(idObject->metaObject()); - QDeclarativePropertyCache::Data *data = cache->property(name); + QDeclarativePropertyData *data = cache->property(name); if (!data || data->isFunction()) return false; // Don't support methods (or non-existing properties ;) @@ -649,7 +648,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast) m_engine->metaObjectForType(baseName->meta->property(baseName->index).userType()); QDeclarativePropertyCache *cache = m_engine->cache(m); - QDeclarativePropertyCache::Data *data = cache->property(name); + QDeclarativePropertyData *data = cache->property(name); if (!data || data->isFunction()) return false; // Don't support methods (or non-existing properties ;) diff --git a/src/declarative/qml/v8/qdeclarativebuiltinfunctions.cpp b/src/declarative/qml/v8/qdeclarativebuiltinfunctions.cpp index 96c51da0ef..fed0569039 100644 --- a/src/declarative/qml/v8/qdeclarativebuiltinfunctions.cpp +++ b/src/declarative/qml/v8/qdeclarativebuiltinfunctions.cpp @@ -66,6 +66,65 @@ QT_BEGIN_NAMESPACE namespace QDeclarativeBuiltinFunctions { +enum ConsoleLogTypes { + Log, + Warn, + Error +}; + +v8::Handle<v8::Value> console(ConsoleLogTypes logType, const v8::Arguments &args) +{ + int line = -1; + QString scriptName; + v8::HandleScope handleScope; + + { + v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(1); + if (stackTrace->GetFrameCount()) { + v8::Local<v8::StackFrame> currentStackFrame = stackTrace->GetFrame(0); + line = currentStackFrame->GetLineNumber(); + scriptName = V8ENGINE()->toString(currentStackFrame->GetScriptName()); + } + } + + QString result; + for (int i = 0; i < args.Length(); ++i) { + if (i != 0) + result.append(QLatin1Char(' ')); + + v8::Local<v8::Value> value = args[i]; + //Check for Object Type + if (value->IsObject() && !value->IsFunction() + && !value->IsArray() && !value->IsDate() + && !value->IsRegExp()) { + result = QLatin1String("Object"); + } else { + v8::Local<v8::String> jsstr = value->ToString(); + result.append(V8ENGINE()->toString(jsstr)); + if (value->IsArray()) + result = QString(QLatin1String("[%1]")).arg(result); + } + } + + QString log = QString(QLatin1String("%1 (%2:%3)")).arg(result).arg(scriptName).arg(line); + + switch (logType) { + case Log: + qDebug("%s", qPrintable(log)); + break; + case Warn: + qWarning("%s", qPrintable(log)); + break; + case Error: + qCritical("%s", qPrintable(log)); + break; + default: + break; + } + + return v8::Undefined(); +} + v8::Handle<v8::Value> gc(const v8::Arguments &args) { Q_UNUSED(args); @@ -73,25 +132,46 @@ v8::Handle<v8::Value> gc(const v8::Arguments &args) return v8::Undefined(); } -v8::Handle<v8::Value> print(const v8::Arguments &args) +v8::Handle<v8::Value> consoleTime(const v8::Arguments &args) { - QString result; - for (int i = 0; i < args.Length(); ++i) { - if (i != 0) - result.append(QLatin1Char(' ')); + if (args.Length() != 1) + V8THROW_ERROR("console.time(): Invalid arguments"); + QString name = V8ENGINE()->toString(args[0]); + V8ENGINE()->startTimer(name); + return v8::Undefined(); +} - v8::Local<v8::String> jsstr = args[i]->ToString(); - if (!jsstr.IsEmpty()) { - QString qstr; - qstr.resize(jsstr->Length()); - jsstr->Write((uint16_t*)qstr.data()); - result.append(qstr); - } +v8::Handle<v8::Value> consoleTimeEnd(const v8::Arguments &args) +{ + if (args.Length() != 1) + V8THROW_ERROR("console.time(): Invalid arguments"); + QString name = V8ENGINE()->toString(args[0]); + bool wasRunning; + qint64 elapsed = V8ENGINE()->stopTimer(name, &wasRunning); + if (wasRunning) { + qDebug("%s: %llims", qPrintable(name), elapsed); } - qDebug("%s", qPrintable(result)); return v8::Undefined(); } +v8::Handle<v8::Value> consoleLog(const v8::Arguments &args) +{ + //console.log + //console.debug + //print + return console(Log, args); +} + +v8::Handle<v8::Value> consoleWarn(const v8::Arguments &args) +{ + return console(Warn, args); +} + +v8::Handle<v8::Value> consoleError(const v8::Arguments &args) +{ + return console(Error, args); +} + v8::Handle<v8::Value> stringArg(const v8::Arguments &args) { QString value = V8ENGINE()->toString(args.This()->ToString()); @@ -654,12 +734,12 @@ v8::Handle<v8::Value> resolvedUrl(const v8::Arguments &args) if (p) { QDeclarativeContextData *ctxt = V8ENGINE()->callingContext(); if (ctxt) - return V8ENGINE()->fromVariant(ctxt->resolvedUrl(url)); + return V8ENGINE()->toString(ctxt->resolvedUrl(url).toString()); else - return V8ENGINE()->fromVariant(url); + return V8ENGINE()->toString(url.toString()); } - return V8ENGINE()->fromVariant(e->baseUrl().resolved(url)); + return V8ENGINE()->toString(e->baseUrl().resolved(url).toString()); } /*! diff --git a/src/declarative/qml/v8/qdeclarativebuiltinfunctions_p.h b/src/declarative/qml/v8/qdeclarativebuiltinfunctions_p.h index 847dc66e37..8810f77df4 100644 --- a/src/declarative/qml/v8/qdeclarativebuiltinfunctions_p.h +++ b/src/declarative/qml/v8/qdeclarativebuiltinfunctions_p.h @@ -61,7 +61,11 @@ QT_BEGIN_NAMESPACE namespace QDeclarativeBuiltinFunctions { v8::Handle<v8::Value> gc(const v8::Arguments &args); -v8::Handle<v8::Value> print(const v8::Arguments &args); +v8::Handle<v8::Value> consoleLog(const v8::Arguments &args); +v8::Handle<v8::Value> consoleWarn(const v8::Arguments &args); +v8::Handle<v8::Value> consoleError(const v8::Arguments &args); +v8::Handle<v8::Value> consoleTime(const v8::Arguments &args); +v8::Handle<v8::Value> consoleTimeEnd(const v8::Arguments &args); v8::Handle<v8::Value> isQtObject(const v8::Arguments &args); v8::Handle<v8::Value> rgba(const v8::Arguments &args); v8::Handle<v8::Value> hsla(const v8::Arguments &args); diff --git a/src/declarative/qml/v8/qv8bindings.cpp b/src/declarative/qml/v8/qv8bindings.cpp index e1a0f4c0a2..271267d851 100644 --- a/src/declarative/qml/v8/qv8bindings.cpp +++ b/src/declarative/qml/v8/qv8bindings.cpp @@ -85,7 +85,7 @@ void QV8Bindings::Binding::update(QDeclarativePropertyPrivate::WriteFlags flags) bool isUndefined = false; - QDeclarativeDeleteWatcher watcher(this); + QDeleteWatcher watcher(this); ep->referenceScarceResources(); v8::HandleScope handle_scope; @@ -182,7 +182,7 @@ QV8Bindings::~QV8Bindings() } QDeclarativeAbstractBinding *QV8Bindings::configBinding(int index, QObject *target, QObject *scope, - const QDeclarativePropertyCache::Data &p, + const QDeclarativePropertyData &p, int line) { QV8Bindings::Binding *rv = bindings + index; diff --git a/src/declarative/qml/v8/qv8bindings_p.h b/src/declarative/qml/v8/qv8bindings_p.h index f7581a41aa..904062551d 100644 --- a/src/declarative/qml/v8/qv8bindings_p.h +++ b/src/declarative/qml/v8/qv8bindings_p.h @@ -74,7 +74,7 @@ public: virtual ~QV8Bindings(); QDeclarativeAbstractBinding *configBinding(int index, QObject *target, QObject *scope, - const QDeclarativePropertyCache::Data &prop, + const QDeclarativePropertyData &prop, int line); private: @@ -101,7 +101,7 @@ private: bool updating:1; int line; QObject *object; - QDeclarativePropertyCache::Data property; + QDeclarativePropertyData property; QV8Bindings *parent; }; diff --git a/src/declarative/qml/v8/qv8contextwrapper.cpp b/src/declarative/qml/v8/qv8contextwrapper.cpp index 29857b2585..20e479b28a 100644 --- a/src/declarative/qml/v8/qv8contextwrapper.cpp +++ b/src/declarative/qml/v8/qv8contextwrapper.cpp @@ -258,6 +258,7 @@ v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property, // Its possible we could delay the calculation of the "actual" context (in the case // of sub contexts) until it is definately needed. QDeclarativeContextData *context = resource->getContext(); + QDeclarativeContextData *expressionContext = context; if (!context) return v8::Undefined(); @@ -317,21 +318,17 @@ v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property, int propertyIdx = context->propertyNames->value(propertystring); if (propertyIdx != -1) { - typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty; if (propertyIdx < context->idValueCount) { - if (ep->captureProperties) - ep->capturedProperties << CapturedProperty(&context->idValues[propertyIdx].bindings); - + ep->captureProperty(&context->idValues[propertyIdx].bindings); return engine->newQObject(context->idValues[propertyIdx]); } else { QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate(); - if (ep->captureProperties) - ep->capturedProperties << CapturedProperty(context->asQDeclarativeContext(), -1, - propertyIdx + cp->notifyIndex); + ep->captureProperty(context->asQDeclarativeContext(), -1, + propertyIdx + cp->notifyIndex); const QVariant &value = cp->propertyValues.at(propertyIdx); if (value.userType() == qMetaTypeId<QList<QObject*> >()) { @@ -366,6 +363,8 @@ v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property, context = context->parent; } + expressionContext->unresolvedNames = true; + QString error = QLatin1String("Can't find variable: ") + engine->toString(property); v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error))); return v8::Undefined(); @@ -398,6 +397,7 @@ v8::Handle<v8::Value> QV8ContextWrapper::Setter(v8::Local<v8::String> property, // Its possible we could delay the calculation of the "actual" context (in the case // of sub contexts) until it is definately needed. QDeclarativeContextData *context = resource->getContext(); + QDeclarativeContextData *expressionContext = context; if (!context) return v8::Undefined(); @@ -440,6 +440,8 @@ v8::Handle<v8::Value> QV8ContextWrapper::Setter(v8::Local<v8::String> property, context = context->parent; } + expressionContext->unresolvedNames = true; + if (!resource->readOnly) { return v8::Handle<v8::Value>(); } else { diff --git a/src/declarative/qml/v8/qv8engine.cpp b/src/declarative/qml/v8/qv8engine.cpp index 62abbbe59b..791c972c0b 100644 --- a/src/declarative/qml/v8/qv8engine.cpp +++ b/src/declarative/qml/v8/qv8engine.cpp @@ -45,6 +45,7 @@ #include "qv8contextwrapper_p.h" #include "qv8valuetypewrapper_p.h" #include "qv8gccallback_p.h" +#include "qv8sequencewrapper_p.h" #include "qv8include_p.h" #include "../../../3rdparty/javascriptcore/DateMath.h" @@ -82,6 +83,7 @@ static bool ObjectComparisonCallback(v8::Local<v8::Object> lhs, v8::Local<v8::Ob switch (lhst) { case QV8ObjectResource::ValueTypeType: + // a value type might be equal to a variant or another value type if (rhst == QV8ObjectResource::ValueTypeType) { return lhsr->engine->valueTypeWrapper()->isEqual(lhsr, lhsr->engine->valueTypeWrapper()->toVariant(rhsr)); } else if (rhst == QV8ObjectResource::VariantType) { @@ -89,6 +91,7 @@ static bool ObjectComparisonCallback(v8::Local<v8::Object> lhs, v8::Local<v8::Ob } break; case QV8ObjectResource::VariantType: + // a variant might be equal to a value type or other variant. if (rhst == QV8ObjectResource::VariantType) { return lhsr->engine->variantWrapper()->toVariant(lhsr) == lhsr->engine->variantWrapper()->toVariant(rhsr); @@ -96,6 +99,12 @@ static bool ObjectComparisonCallback(v8::Local<v8::Object> lhs, v8::Local<v8::Ob return rhsr->engine->valueTypeWrapper()->isEqual(rhsr, rhsr->engine->variantWrapper()->toVariant(lhsr)); } break; + case QV8ObjectResource::SequenceType: + // a sequence might be equal to itself. + if (rhst == QV8ObjectResource::SequenceType) { + return lhsr->engine->sequenceWrapper()->isEqual(lhsr, rhsr); + } + break; default: break; } @@ -135,6 +144,7 @@ QV8Engine::QV8Engine(QJSEngine* qq, QJSEngine::ContextOwnership ownership) m_listWrapper.init(this); m_variantWrapper.init(this); m_valueTypeWrapper.init(this); + m_sequenceWrapper.init(this); QV8GCCallback::registerGcPrologueCallback(); @@ -164,6 +174,7 @@ QV8Engine::~QV8Engine() invalidateAllValues(); clearExceptions(); + m_sequenceWrapper.destroy(); m_valueTypeWrapper.destroy(); m_variantWrapper.destroy(); m_listWrapper.destroy(); @@ -226,25 +237,33 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint) return m_variantWrapper.toVariant(r); case QV8ObjectResource::ValueTypeType: return m_valueTypeWrapper.toVariant(r); + case QV8ObjectResource::SequenceType: + return m_sequenceWrapper.toVariant(r); } } } - if (typeHint == qMetaTypeId<QList<QObject *> >() && value->IsArray()) { + if (value->IsArray()) { v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value); - - QList<QObject *> list; - uint32_t length = array->Length(); - for (uint32_t ii = 0; ii < length; ++ii) { - v8::Local<v8::Value> arrayItem = array->Get(ii); - if (arrayItem->IsObject()) { - list << toQObject(arrayItem->ToObject()); - } else { - list << 0; + if (typeHint == qMetaTypeId<QList<QObject *> >()) { + QList<QObject *> list; + uint32_t length = array->Length(); + for (uint32_t ii = 0; ii < length; ++ii) { + v8::Local<v8::Value> arrayItem = array->Get(ii); + if (arrayItem->IsObject()) { + list << toQObject(arrayItem->ToObject()); + } else { + list << 0; + } } + + return qVariantFromValue<QList<QObject*> >(list); } - return qVariantFromValue<QList<QObject*> >(list); + bool succeeded = false; + QVariant retn = m_sequenceWrapper.toVariant(array, typeHint, &succeeded); + if (succeeded) + return retn; } return toBasicVariant(value); @@ -325,8 +344,14 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant) case QMetaType::QObjectStar: case QMetaType::QWidgetStar: return newQObject(*reinterpret_cast<QObject* const *>(ptr)); - case QMetaType::QStringList: + case QMetaType::QStringList: + { + bool succeeded = false; + v8::Handle<v8::Value> retn = m_sequenceWrapper.fromVariant(variant, &succeeded); + if (succeeded) + return retn; return arrayFromStringList(this, *reinterpret_cast<const QStringList *>(ptr)); + } case QMetaType::QVariantList: return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr)); case QMetaType::QVariantMap: @@ -369,6 +394,11 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant) QObject *obj = QDeclarativeMetaType::toQObject(variant, &objOk); if (objOk) return newQObject(obj); + + bool succeeded = false; + v8::Handle<v8::Value> retn = m_sequenceWrapper.fromVariant(variant, &succeeded); + if (succeeded) + return retn; } // XXX TODO: To be compatible, we still need to handle: @@ -459,7 +489,6 @@ QVariant QV8Engine::toBasicVariant(v8::Handle<v8::Value> value) int length = array->Length(); for (int ii = 0; ii < length; ++ii) rv << toVariant(array->Get(ii), -1); - return rv; } if (!value->IsFunction()) { @@ -489,11 +518,19 @@ struct StaticQtMetaObject : public QObject void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global) { using namespace QDeclarativeBuiltinFunctions; - v8::Local<v8::Function> printFn = V8FUNCTION(print, this); v8::Local<v8::Object> console = v8::Object::New(); - console->Set(v8::String::New("log"), printFn); - console->Set(v8::String::New("debug"), printFn); + v8::Local<v8::Function> consoleLogFn = V8FUNCTION(consoleLog, this); + v8::Local<v8::Function> consoleWarnFn = V8FUNCTION(consoleWarn, this); + v8::Local<v8::Function> consoleErrorFn = V8FUNCTION(consoleError, this); + v8::Local<v8::Function> consoleTimeFn = V8FUNCTION(consoleTime, this); + v8::Local<v8::Function> consoleTimeEndFn = V8FUNCTION(consoleTimeEnd, this); + console->Set(v8::String::New("log"), consoleLogFn); + console->Set(v8::String::New("debug"), consoleLogFn); + console->Set(v8::String::New("warn"), consoleWarnFn); + console->Set(v8::String::New("error"), consoleErrorFn); + console->Set(v8::String::New("time"), consoleTimeFn); + console->Set(v8::String::New("timeEnd"), consoleTimeEndFn); v8::Local<v8::Object> qt = v8::Object::New(); @@ -546,7 +583,7 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global) global->Set(v8::String::New("qsTrId"), V8FUNCTION(qsTrId, this)); global->Set(v8::String::New("QT_TRID_NOOP"), V8FUNCTION(qsTrIdNoOp, this)); - global->Set(v8::String::New("print"), printFn); + global->Set(v8::String::New("print"), consoleLogFn); global->Set(v8::String::New("console"), console); global->Set(v8::String::New("Qt"), qt); global->Set(v8::String::New("gc"), V8FUNCTION(QDeclarativeBuiltinFunctions::gc, this)); @@ -1369,6 +1406,24 @@ void QV8Engine::emitSignalHandlerException() emit q->signalHandlerException(scriptValueFromInternal(uncaughtException())); } +void QV8Engine::startTimer(const QString &timerName) +{ + if (!m_time.isValid()) + m_time.start(); + m_startedTimers[timerName] = m_time.elapsed(); +} + +qint64 QV8Engine::stopTimer(const QString &timerName, bool *wasRunning) +{ + if (!m_startedTimers.contains(timerName)) { + *wasRunning = false; + return 0; + } + *wasRunning = true; + qint64 startedAt = m_startedTimers.take(timerName); + return m_time.elapsed() - startedAt; +} + QThreadStorage<QV8GCCallback::ThreadData *> QV8GCCallback::threadData; void QV8GCCallback::initializeThreadData() { diff --git a/src/declarative/qml/v8/qv8engine_p.h b/src/declarative/qml/v8/qv8engine_p.h index 79a77c2ac1..7b85cfcc31 100644 --- a/src/declarative/qml/v8/qv8engine_p.h +++ b/src/declarative/qml/v8/qv8engine_p.h @@ -59,6 +59,7 @@ #include <QtCore/qmutex.h> #include <QtCore/qstack.h> #include <QtCore/qstringlist.h> +#include <QtCore/QElapsedTimer> #include <private/qv8_p.h> #include <qjsengine.h> @@ -77,6 +78,7 @@ #include "qv8listwrapper_p.h" #include "qv8variantwrapper_p.h" #include "qv8valuetypewrapper_p.h" +#include "qv8sequencewrapper_p.h" QT_BEGIN_NAMESPACE @@ -136,7 +138,8 @@ public: enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType, ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType, ListModelType, Context2DType, Context2DStyleType, Context2DPixelArrayType, - ParticleDataType, SignalHandlerType, IncubatorType, VisualDataItemType }; + ParticleDataType, SignalHandlerType, IncubatorType, VisualDataItemType, + SequenceType }; virtual ResourceType resourceType() const = 0; QV8Engine *engine; @@ -279,6 +282,7 @@ public: QV8ListWrapper *listWrapper() { return &m_listWrapper; } QV8VariantWrapper *variantWrapper() { return &m_variantWrapper; } QV8ValueTypeWrapper *valueTypeWrapper() { return &m_valueTypeWrapper; } + QV8SequenceWrapper *sequenceWrapper() { return &m_sequenceWrapper; } void *xmlHttpRequestData() { return m_xmlHttpRequestData; } void *sqlDatabaseData() { return m_sqlDatabaseData; } @@ -326,6 +330,9 @@ public: inline v8::Handle<v8::Value> newValueType(QObject *, int coreIndex, QDeclarativeValueType *); inline v8::Handle<v8::Value> newValueType(const QVariant &, QDeclarativeValueType *); + // Create a new sequence type object + inline v8::Handle<v8::Value> newSequence(int sequenceType, QObject *, int coreIndex, bool *succeeded); + // Create a new QVariant object. This doesn't examine the type of the variant, but always returns // a QVariant wrapper inline v8::Handle<v8::Value> newQVariant(const QVariant &); @@ -399,6 +406,10 @@ public: void emitSignalHandlerException(); + // used for console.time(), console.timeEnd() + void startTimer(const QString &timerName); + qint64 stopTimer(const QString &timerName, bool *wasRunning); + QObject *qtObjectFromJS(v8::Handle<v8::Value> value); QSet<int> visitedConversionObjects; protected: @@ -415,6 +426,7 @@ protected: QV8ListWrapper m_listWrapper; QV8VariantWrapper m_variantWrapper; QV8ValueTypeWrapper m_valueTypeWrapper; + QV8SequenceWrapper m_sequenceWrapper; v8::Persistent<v8::Function> m_getOwnPropertyNames; v8::Persistent<v8::Function> m_freezeObject; @@ -429,6 +441,9 @@ protected: Exception m_exception; + QElapsedTimer m_time; + QHash<QString, qint64> m_startedTimers; + QVariant toBasicVariant(v8::Handle<v8::Value>); void initializeGlobal(v8::Handle<v8::Object>); @@ -545,6 +560,11 @@ v8::Handle<v8::Value> QV8Engine::newValueType(const QVariant &value, QDeclarativ return m_valueTypeWrapper.newValueType(value, type); } +v8::Handle<v8::Value> QV8Engine::newSequence(int sequenceType, QObject *object, int property, bool *succeeded) +{ + return m_sequenceWrapper.newSequence(sequenceType, object, property, succeeded); +} + // XXX Can this be made more optimal? It is called prior to resolving each and every // unqualified name in QV8ContextWrapper. bool QV8Engine::startsWithUpper(v8::Handle<v8::String> string) diff --git a/src/declarative/qml/v8/qv8listwrapper.cpp b/src/declarative/qml/v8/qv8listwrapper.cpp index 777ce78686..aa0b82b3ad 100644 --- a/src/declarative/qml/v8/qv8listwrapper.cpp +++ b/src/declarative/qml/v8/qv8listwrapper.cpp @@ -69,11 +69,11 @@ void QV8ListWrapper::init(QV8Engine *engine) { m_engine = engine; v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(); - ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter); + ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter, 0, 0, Enumerator); ft->InstanceTemplate()->SetIndexedPropertyHandler(IndexedGetter); ft->InstanceTemplate()->SetAccessor(v8::String::New("length"), LengthGetter, 0, v8::Handle<v8::Value>(), v8::DEFAULT, - v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete)); + v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum)); ft->InstanceTemplate()->SetHasExternalResource(true); m_constructor = qPersistentNew<v8::Function>(ft->GetFunction()); } @@ -175,4 +175,20 @@ v8::Handle<v8::Value> QV8ListWrapper::LengthGetter(v8::Local<v8::String> propert return v8::Integer::NewFromUnsigned(count); } +v8::Handle<v8::Array> QV8ListWrapper::Enumerator(const v8::AccessorInfo &info) +{ + QV8ListResource *resource = v8_resource_cast<QV8ListResource>(info.This()); + + if (!resource || resource->object.isNull()) return v8::Array::New(); + + quint32 count = resource->property.count?resource->property.count(&resource->property):0; + + v8::Local<v8::Array> rv = v8::Array::New(count); + + for (uint ii = 0; ii < count; ++ii) + rv->Set(ii, v8::Number::New(ii)); + + return rv; +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/v8/qv8listwrapper_p.h b/src/declarative/qml/v8/qv8listwrapper_p.h index 8cbc7db0b8..e18d1eef21 100644 --- a/src/declarative/qml/v8/qv8listwrapper_p.h +++ b/src/declarative/qml/v8/qv8listwrapper_p.h @@ -85,6 +85,7 @@ private: const v8::AccessorInfo &info); static v8::Handle<v8::Value> LengthGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info); + static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo &info); QV8Engine *m_engine; v8::Persistent<v8::Function> m_constructor; diff --git a/src/declarative/qml/v8/qv8qobjectwrapper.cpp b/src/declarative/qml/v8/qv8qobjectwrapper.cpp index 1dc3db7d29..6a9f583b0f 100644 --- a/src/declarative/qml/v8/qv8qobjectwrapper.cpp +++ b/src/declarative/qml/v8/qv8qobjectwrapper.cpp @@ -229,10 +229,8 @@ static v8::Handle<v8::Value> name ## ValueGetter(v8::Local<v8::String>, const v8 if (notify == 0x0FFF) notify = -1; \ \ QDeclarativeEnginePrivate *ep = resource->engine->engine()?QDeclarativeEnginePrivate::get(resource->engine->engine()):0; \ - if (ep && notify /* 0 means constant */ && ep->captureProperties) { \ - typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty; \ - ep->capturedProperties << CapturedProperty(object, index, notify); \ - } \ + if (ep && notify /* 0 means constant */ ) \ + ep->captureProperty(object, index, notify); \ \ cpptype value = defaultvalue; \ void *args[] = { &value, 0 }; \ @@ -255,10 +253,8 @@ static v8::Handle<v8::Value> name ## ValueGetterDirect(v8::Local<v8::String>, co if (notify == 0x0FFF) notify = -1; \ \ QDeclarativeEnginePrivate *ep = resource->engine->engine()?QDeclarativeEnginePrivate::get(resource->engine->engine()):0; \ - if (ep && notify /* 0 means constant */ && ep->captureProperties) { \ - typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty; \ - ep->capturedProperties << CapturedProperty(object, index, notify); \ - } \ + if (ep && notify /* 0 means constant */ ) \ + ep->captureProperty(object, index, notify); \ \ cpptype value = defaultvalue; \ void *args[] = { &value, 0 }; \ @@ -302,7 +298,8 @@ void QV8QObjectWrapper::init(QV8Engine *engine) } { v8::ScriptOrigin origin(m_hiddenObject); // Hack to allow us to identify these functions - v8::Local<v8::Script> script = v8::Script::New(v8::String::New(CREATE_FUNCTION), &origin); + v8::Local<v8::Script> script = v8::Script::New(v8::String::New(CREATE_FUNCTION), &origin, 0, + v8::Handle<v8::String>(), v8::Script::NativeMode); v8::Local<v8::Function> fn = v8::Local<v8::Function>::Cast(script->Run()); v8::Handle<v8::Value> invokeFn = v8::FunctionTemplate::New(Invoke)->GetFunction(); v8::Handle<v8::Value> args[] = { invokeFn }; @@ -348,7 +345,7 @@ QObject *QV8QObjectWrapper::toQObject(QV8ObjectResource *r) // Load value properties static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object, - const QDeclarativePropertyCache::Data &property) + const QDeclarativePropertyData &property) { Q_ASSERT(!property.isFunction()); @@ -385,7 +382,13 @@ static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object, QDeclarativeValueType *valueType = ep->valueTypes[property.propType]; if (valueType) return engine->newValueType(object, property.coreIndex, valueType); - } + } else { + // see if it's a sequence type + bool succeeded = false; + v8::Handle<v8::Value> retn = engine->newSequence(property.propType, object, property.coreIndex, &succeeded); + if (succeeded) + return retn; + } QVariant var = object->metaObject()->property(property.coreIndex).read(object); return engine->fromVariant(var); @@ -394,7 +397,7 @@ static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object, } static v8::Handle<v8::Value> LoadPropertyDirect(QV8Engine *engine, QObject *object, - const QDeclarativePropertyCache::Data &property) + const QDeclarativePropertyData &property) { Q_ASSERT(!property.isFunction()); @@ -425,13 +428,18 @@ static v8::Handle<v8::Value> LoadPropertyDirect(QV8Engine *engine, QObject *obje void *args[] = { &handle, 0 }; object->qt_metacall(QMetaObject::ReadProperty, property.coreIndex, args); return handle.toHandle(); - } else if (QDeclarativeValueTypeFactory::isValueType((uint)property.propType) - && engine->engine()) { + } else if (engine->engine() && QDeclarativeValueTypeFactory::isValueType((uint)property.propType)) { QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine()); QDeclarativeValueType *valueType = ep->valueTypes[property.propType]; if (valueType) return engine->newValueType(object, property.coreIndex, valueType); - } + } else { + // see if it's a sequence type + bool success = false; + v8::Handle<v8::Value> retn = engine->newSequence(property.propType, object, property.coreIndex, &success); + if (success) + return retn; + } QVariant var = object->metaObject()->property(property.coreIndex).read(object); return engine->fromVariant(var); @@ -478,8 +486,8 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject } } - QDeclarativePropertyCache::Data local; - QDeclarativePropertyCache::Data *result = 0; + QDeclarativePropertyData local; + QDeclarativePropertyData *result = 0; { QDeclarativeData *ddata = QDeclarativeData::get(object, false); if (ddata && ddata->propertyCache) @@ -497,8 +505,6 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject return v8::Handle<v8::Value>(); } - typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty; - if (result->isFunction()) { if (result->isVMEFunction()) { return ((QDeclarativeVMEMetaObject *)(object->metaObject()))->vmeMethod(result->coreIndex); @@ -515,11 +521,11 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject } QDeclarativeEnginePrivate *ep = engine->engine()?QDeclarativeEnginePrivate::get(engine->engine()):0; - if (ep && ep->captureProperties && !result->isConstant()) { + if (ep && !result->isConstant()) { if (result->coreIndex == 0) - ep->capturedProperties << CapturedProperty(QDeclarativeData::get(object, true)->objectNameNotifier()); + ep->captureProperty(QDeclarativeData::get(object, true)->objectNameNotifier()); else - ep->capturedProperties << CapturedProperty(object, result->coreIndex, result->notifyIndex); + ep->captureProperty(object, result->coreIndex, result->notifyIndex); } if (result->isVMEProperty()) @@ -533,7 +539,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject } // Setter for writable properties. Shared between the interceptor and fast property accessor -static inline void StoreProperty(QV8Engine *engine, QObject *object, QDeclarativePropertyCache::Data *property, +static inline void StoreProperty(QV8Engine *engine, QObject *object, QDeclarativePropertyData *property, v8::Handle<v8::Value> value) { QDeclarativeBinding *newBinding = 0; @@ -601,7 +607,6 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QDeclarativ v = engine->toVariant(value, property->propType); QDeclarativeContextData *context = engine->callingContext(); - if (!QDeclarativePropertyPrivate::write(object, *property, v, context)) { const char *valueType = 0; if (v.userType() == QVariant::Invalid) valueType = "null"; @@ -623,8 +628,8 @@ bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QH engine->qobjectWrapper()->m_destroyString == property) return true; - QDeclarativePropertyCache::Data local; - QDeclarativePropertyCache::Data *result = 0; + QDeclarativePropertyData local; + QDeclarativePropertyData *result = 0; result = QDeclarativePropertyCache::property(engine->engine(), object, property, local); if (!result) @@ -730,8 +735,8 @@ v8::Handle<v8::Integer> QV8QObjectWrapper::Query(v8::Local<v8::String> property, QHashedV8String propertystring(property); - QDeclarativePropertyCache::Data local; - QDeclarativePropertyCache::Data *result = 0; + QDeclarativePropertyData local; + QDeclarativePropertyData *result = 0; result = QDeclarativePropertyCache::property(engine->engine(), object, propertystring, local); if (!result) @@ -811,7 +816,7 @@ static void FastValueSetter(v8::Local<v8::String>, v8::Local<v8::Value> value, Q_ASSERT(ddata); Q_ASSERT(ddata->propertyCache); - QDeclarativePropertyCache::Data *pdata = ddata->propertyCache->property(index); + QDeclarativePropertyData *pdata = ddata->propertyCache->property(index); Q_ASSERT(pdata); Q_ASSERT(pdata->isWritable() || pdata->isQList()); @@ -881,7 +886,7 @@ v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8 // performance, but the cost of setting up this structure hasn't been measured so // its not guarenteed that this is a win overall. We need to try and measure the cost. for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) { - Data *property = *iter; + QDeclarativePropertyData *property = *iter; if (property->isFunction() || property->coreIndex >= 0x7FFF || property->notifyIndex >= 0x0FFF || property->coreIndex == 0) @@ -1173,20 +1178,17 @@ int QV8QObjectConnectionList::qt_metacall(QMetaObject::Call method, int index, v QList<Connection> connections = connectionList; - QMetaMethod method = data()->metaObject()->method(index); - Q_ASSERT(method.methodType() == QMetaMethod::Signal); - // XXX TODO: We should figure out a way to cache the parameter types to avoid resolving - // them each time. - QList<QByteArray> params = method.parameterTypes(); + QVarLengthArray<int, 9> dummy; + int *argsTypes = QDeclarativePropertyCache::methodParameterTypes(data(), index, dummy, 0); v8::HandleScope handle_scope; v8::Context::Scope scope(engine->context()); - QVarLengthArray<v8::Handle<v8::Value> > args(params.count()); - int argCount = params.count(); + int argCount = argsTypes?argsTypes[0]:0; + QVarLengthArray<v8::Handle<v8::Value>, 9> args(argCount); for (int ii = 0; ii < argCount; ++ii) { - int type = QMetaType::type(params.at(ii).constData()); + int type = argsTypes[ii + 1]; if (type == qMetaTypeId<QVariant>()) { args[ii] = engine->fromVariant(*((QVariant *)metaArgs[ii + 1])); } else { @@ -1350,6 +1352,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Disconnect(const v8::Arguments &args) // Match! if (connections.connectionsInUse) { connection.needsDestroy = true; + connections.connectionsNeedClean = true; } else { connection.dispose(); connections.removeAt(ii); @@ -1369,6 +1372,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Disconnect(const v8::Arguments &args) // Match! if (connections.connectionsInUse) { connection.needsDestroy = true; + connections.connectionsNeedClean = true; } else { connection.dispose(); connections.removeAt(ii); @@ -1452,34 +1456,13 @@ static v8::Handle<v8::Value> CallMethod(QObject *object, int index, int returnTy } } -static int EnumType(const QMetaObject *meta, const QString &strname) -{ - QByteArray str = strname.toUtf8(); - QByteArray scope; - QByteArray name; - int scopeIdx = str.lastIndexOf("::"); - if (scopeIdx != -1) { - scope = str.left(scopeIdx); - name = str.mid(scopeIdx + 2); - } else { - name = str; - } - for (int i = meta->enumeratorCount() - 1; i >= 0; --i) { - QMetaEnum m = meta->enumerator(i); - if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) - return QVariant::Int; - } - return QVariant::Invalid; -} - /*! Returns the match score for converting \a actual to be of type \a conversionType. A zero score means "perfect match" whereas a higher score is worse. The conversion table is copied out of the QtScript callQtMethod() function. */ -static int MatchScore(v8::Handle<v8::Value> actual, int conversionType, - const QByteArray &conversionTypeName) +static int MatchScore(v8::Handle<v8::Value> actual, int conversionType) { if (actual->IsNumber()) { switch (conversionType) { @@ -1551,11 +1534,13 @@ static int MatchScore(v8::Handle<v8::Value> actual, int conversionType, case QMetaType::VoidStar: case QMetaType::QObjectStar: return 0; - default: - if (!conversionTypeName.endsWith('*')) - return 10; - else + default: { + const char *typeName = QMetaType::typeName(conversionType); + if (typeName && typeName[strlen(typeName) - 1] == '*') return 0; + else + return 10; + } } } else if (actual->IsObject()) { v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(actual); @@ -1610,33 +1595,37 @@ static QByteArray QMetaMethod_name(const QMetaMethod &m) /*! Returns the next related method, if one, or 0. */ -static const QDeclarativePropertyCache::Data * RelatedMethod(QObject *object, - const QDeclarativePropertyCache::Data *current, - QDeclarativePropertyCache::Data &dummy) +static const QDeclarativePropertyData * RelatedMethod(QObject *object, + const QDeclarativePropertyData *current, + QDeclarativePropertyData &dummy) { QDeclarativePropertyCache *cache = QDeclarativeData::get(object)->propertyCache; - if (current->relatedIndex == -1) + if (!current->isOverload()) return 0; + Q_ASSERT(!current->overrideIndexIsProperty); + if (cache) { - return cache->method(current->relatedIndex); + return cache->method(current->overrideIndex); } else { const QMetaObject *mo = object->metaObject(); int methodOffset = mo->methodCount() - QMetaObject_methods(mo); - while (methodOffset > current->relatedIndex) { + while (methodOffset > current->overrideIndex) { mo = mo->superClass(); methodOffset -= QMetaObject_methods(mo); } - QMetaMethod method = mo->method(current->relatedIndex); + QMetaMethod method = mo->method(current->overrideIndex); dummy.load(method); // Look for overloaded methods QByteArray methodName = QMetaMethod_name(method); - for (int ii = current->relatedIndex - 1; ii >= methodOffset; --ii) { + for (int ii = current->overrideIndex - 1; ii >= methodOffset; --ii) { if (methodName == QMetaMethod_name(mo->method(ii))) { - dummy.relatedIndex = ii; + dummy.setFlags(dummy.getFlags() | QDeclarativePropertyData::IsOverload); + dummy.overrideIndexIsProperty = 0; + dummy.overrideIndex = ii; return &dummy; } } @@ -1645,35 +1634,32 @@ static const QDeclarativePropertyCache::Data * RelatedMethod(QObject *object, } } -static v8::Handle<v8::Value> CallPrecise(QObject *object, const QDeclarativePropertyCache::Data &data, +static v8::Handle<v8::Value> CallPrecise(QObject *object, const QDeclarativePropertyData &data, QV8Engine *engine, CallArgs &callArgs) { if (data.hasArguments()) { - QMetaMethod m = object->metaObject()->method(data.coreIndex); - QList<QByteArray> argTypeNames = m.parameterTypes(); - QVarLengthArray<int, 9> argTypes(argTypeNames.count()); - - // ### Cache - for (int ii = 0; ii < argTypeNames.count(); ++ii) { - argTypes[ii] = QMetaType::type(argTypeNames.at(ii)); - if (argTypes[ii] == QVariant::Invalid) - argTypes[ii] = EnumType(object->metaObject(), QString::fromLatin1(argTypeNames.at(ii))); - if (argTypes[ii] == QVariant::Invalid) { - QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(QLatin1String(argTypeNames.at(ii))); - v8::ThrowException(v8::Exception::Error(engine->toString(error))); - return v8::Handle<v8::Value>(); - } + int *args = 0; + QVarLengthArray<int, 9> dummy; + QByteArray unknownTypeError; + + args = QDeclarativePropertyCache::methodParameterTypes(object, data.coreIndex, dummy, + &unknownTypeError); + + if (!args) { + QString typeName = QString::fromLatin1(unknownTypeError); + QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName); + v8::ThrowException(v8::Exception::Error(engine->toString(error))); + return v8::Handle<v8::Value>(); } - if (argTypes.count() > callArgs.Length()) { + if (args[0] > callArgs.Length()) { QString error = QLatin1String("Insufficient arguments"); v8::ThrowException(v8::Exception::Error(engine->toString(error))); return v8::Handle<v8::Value>(); } - return CallMethod(object, data.coreIndex, data.propType, argTypes.count(), - argTypes.data(), engine, callArgs); + return CallMethod(object, data.coreIndex, data.propType, args[0], args + 1, engine, callArgs); } else { @@ -1695,25 +1681,31 @@ Resolve the overloaded method to call. The algorithm works conceptually like th If two or more overloads have the same match score, call the last one. The match score is constructed by adding the matchScore() result for each of the parameters. */ -static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativePropertyCache::Data &data, +static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativePropertyData &data, QV8Engine *engine, CallArgs &callArgs) { int argumentCount = callArgs.Length(); - const QDeclarativePropertyCache::Data *best = 0; + const QDeclarativePropertyData *best = 0; int bestParameterScore = INT_MAX; int bestMatchScore = INT_MAX; - QDeclarativePropertyCache::Data dummy; - const QDeclarativePropertyCache::Data *attempt = &data; + QDeclarativePropertyData dummy; + const QDeclarativePropertyData *attempt = &data; do { - QList<QByteArray> methodArgTypeNames; - - if (attempt->hasArguments()) - methodArgTypeNames = object->metaObject()->method(attempt->coreIndex).parameterTypes(); + QVarLengthArray<int, 9> dummy; + int methodArgumentCount = 0; + int *methodArgTypes = 0; + if (attempt->hasArguments()) { + typedef QDeclarativePropertyCache PC; + int *args = PC::methodParameterTypes(object, attempt->coreIndex, dummy, 0); + if (!args) // Must be an unknown argument + continue; - int methodArgumentCount = methodArgTypeNames.count(); + methodArgumentCount = args[0]; + methodArgTypes = args + 1; + } if (methodArgumentCount > argumentCount) continue; // We don't have sufficient arguments to call this method @@ -1723,22 +1715,8 @@ static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativeP continue; // We already have a better option int methodMatchScore = 0; - QVarLengthArray<int, 9> methodArgTypes(methodArgumentCount); - - bool unknownArgument = false; - for (int ii = 0; ii < methodArgumentCount; ++ii) { - methodArgTypes[ii] = QMetaType::type(methodArgTypeNames.at(ii)); - if (methodArgTypes[ii] == QVariant::Invalid) - methodArgTypes[ii] = EnumType(object->metaObject(), - QString::fromLatin1(methodArgTypeNames.at(ii))); - if (methodArgTypes[ii] == QVariant::Invalid) { - unknownArgument = true; - break; - } - methodMatchScore += MatchScore(callArgs[ii], methodArgTypes[ii], methodArgTypeNames.at(ii)); - } - if (unknownArgument) - continue; // We don't understand all the parameters + for (int ii = 0; ii < methodArgumentCount; ++ii) + methodMatchScore += MatchScore(callArgs[ii], methodArgTypes[ii]); if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) { best = attempt; @@ -1755,7 +1733,7 @@ static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativeP return CallPrecise(object, *best, engine, callArgs); } else { QString error = QLatin1String("Unable to determine callable overload. Candidates are:"); - const QDeclarativePropertyCache::Data *candidate = &data; + const QDeclarativePropertyData *candidate = &data; while (candidate) { error += QLatin1String("\n ") + QString::fromUtf8(object->metaObject()->method(candidate->coreIndex).signature()); @@ -1851,11 +1829,11 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Invoke(const v8::Arguments &args) } } - QDeclarativePropertyCache::Data method; + QDeclarativePropertyData method; if (QDeclarativeData *ddata = static_cast<QDeclarativeData *>(QObjectPrivate::get(object)->declarativeData)) { if (ddata->propertyCache) { - QDeclarativePropertyCache::Data *d = ddata->propertyCache->method(index); + QDeclarativePropertyData *d = ddata->propertyCache->method(index); if (!d) return v8::Undefined(); method = *d; @@ -1863,7 +1841,6 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Invoke(const v8::Arguments &args) } if (method.coreIndex == -1) { - QMetaMethod mm = object->metaObject()->method(index); method.load(object->metaObject()->method(index)); if (method.coreIndex == -1) @@ -1887,7 +1864,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Invoke(const v8::Arguments &args) } CallArgs callArgs(argCount, &arguments); - if (method.relatedIndex == -1) { + if (!method.isOverload()) { return CallPrecise(object, method, resource->engine, callArgs); } else { return CallOverloaded(object, method, resource->engine, callArgs); diff --git a/src/declarative/qml/v8/qv8qobjectwrapper_p.h b/src/declarative/qml/v8/qv8qobjectwrapper_p.h index be118a9c34..564510f15d 100644 --- a/src/declarative/qml/v8/qv8qobjectwrapper_p.h +++ b/src/declarative/qml/v8/qv8qobjectwrapper_p.h @@ -83,7 +83,7 @@ public: v8::Handle<v8::Value> newQObject(QObject *object); bool isQObject(v8::Handle<v8::Object>); QObject *toQObject(v8::Handle<v8::Object>); - QObject *toQObject(QV8ObjectResource *); + static QObject *toQObject(QV8ObjectResource *); enum RevisionMode { IgnoreRevision, CheckRevision }; inline v8::Handle<v8::Value> getProperty(QObject *, const QHashedV8String &, RevisionMode); diff --git a/src/declarative/qml/v8/qv8sequencewrapper.cpp b/src/declarative/qml/v8/qv8sequencewrapper.cpp new file mode 100644 index 0000000000..f63b5da4ea --- /dev/null +++ b/src/declarative/qml/v8/qv8sequencewrapper.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtDeclarative/qdeclarative.h> + +#include "qv8sequencewrapper_p.h" +#include "qv8sequencewrapper_p_p.h" +#include "qv8engine_p.h" + +QT_BEGIN_NAMESPACE + +QV8SequenceWrapper::QV8SequenceWrapper() + : m_engine(0) +{ +} + +QV8SequenceWrapper::~QV8SequenceWrapper() +{ +} + +#define REGISTER_QML_SEQUENCE_METATYPE(unused, unused2, SequenceType, unused3) qRegisterMetaType<SequenceType>(); +void QV8SequenceWrapper::init(QV8Engine *engine) +{ + FOREACH_QML_SEQUENCE_TYPE(REGISTER_QML_SEQUENCE_METATYPE) + + m_engine = engine; + m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction()); + m_valueOf = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ValueOf)->GetFunction()); + v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(); + ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter); + ft->InstanceTemplate()->SetIndexedPropertyHandler(IndexedGetter, IndexedSetter, 0, 0, IndexedEnumerator); + ft->InstanceTemplate()->SetAccessor(v8::String::New("length"), LengthGetter, 0, + v8::Handle<v8::Value>(), v8::DEFAULT, + v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0, + m_toString, v8::DEFAULT, + v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0, + m_valueOf, v8::DEFAULT, + v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum)); + ft->InstanceTemplate()->SetHasExternalResource(true); + ft->InstanceTemplate()->MarkAsUseUserObjectComparison(); + m_constructor = qPersistentNew<v8::Function>(ft->GetFunction()); +} +#undef REGISTER_QML_SEQUENCE_METATYPE + +void QV8SequenceWrapper::destroy() +{ + qPersistentDispose(m_toString); + qPersistentDispose(m_valueOf); + qPersistentDispose(m_constructor); +} + +bool QV8SequenceWrapper::isEqual(QV8ObjectResource *lhs, QV8ObjectResource *rhs) +{ + Q_ASSERT(lhs && rhs && lhs->resourceType() == QV8ObjectResource::SequenceType && rhs->resourceType() == QV8ObjectResource::SequenceType); + QV8SequenceResource *lr = static_cast<QV8SequenceResource *>(lhs); + QV8SequenceResource *rr = static_cast<QV8SequenceResource *>(rhs); + return lr->isEqual(rr); +} + +quint32 QV8SequenceWrapper::sequenceLength(QV8ObjectResource *r) +{ + Q_ASSERT(r->resourceType() == QV8ObjectResource::SequenceType); + QV8SequenceResource *sr = static_cast<QV8SequenceResource *>(r); + Q_ASSERT(sr); + return sr->lengthGetter(); +} + +#define NEW_REFERENCE_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \ + if (sequenceType == qMetaTypeId<SequenceType>()) { \ + r = new QV8##ElementTypeName##SequenceResource(m_engine, object, propertyIndex); \ + } else + +v8::Local<v8::Object> QV8SequenceWrapper::newSequence(int sequenceType, QObject *object, int propertyIndex, bool *succeeded) +{ + // This function is called when the property is a QObject Q_PROPERTY of + // the given sequence type. Internally we store a typed-sequence + // (as well as object ptr + property index for updated-read and write-back) + // and so access/mutate avoids variant conversion. + *succeeded = true; + QV8SequenceResource *r = 0; + FOREACH_QML_SEQUENCE_TYPE(NEW_REFERENCE_SEQUENCE) { /* else */ *succeeded = false; return v8::Local<v8::Object>(); } + + v8::Local<v8::Object> rv = m_constructor->NewInstance(); + rv->SetExternalResource(r); + rv->SetPrototype(v8::Array::New(1)->GetPrototype()); + return rv; +} +#undef NEW_REFERENCE_SEQUENCE + +#define NEW_COPY_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \ + if (sequenceType == qMetaTypeId<SequenceType>()) { \ + r = new QV8##ElementTypeName##SequenceResource(m_engine, v.value<SequenceType>()); \ + } else + +v8::Local<v8::Object> QV8SequenceWrapper::fromVariant(const QVariant& v, bool *succeeded) +{ + // This function is called when assigning a sequence value to a normal JS var + // in a JS block. Internally, we store a sequence of the specified type. + // Access and mutation is extremely fast since it will not need to modify any + // QObject property. + int sequenceType = v.userType(); + *succeeded = true; + QV8SequenceResource *r = 0; + FOREACH_QML_SEQUENCE_TYPE(NEW_COPY_SEQUENCE) { /* else */ *succeeded = false; return v8::Local<v8::Object>(); } + + v8::Local<v8::Object> rv = m_constructor->NewInstance(); + rv->SetExternalResource(r); + rv->SetPrototype(v8::Array::New(1)->GetPrototype()); + return rv; +} +#undef NEW_COPY_SEQUENCE + +QVariant QV8SequenceWrapper::toVariant(QV8ObjectResource *r) +{ + Q_ASSERT(r->resourceType() == QV8ObjectResource::SequenceType); + QV8SequenceResource *resource = static_cast<QV8SequenceResource *>(r); + return resource->toVariant(); +} + +#define SEQUENCE_TO_VARIANT(ElementType, ElementTypeName, SequenceType, unused) \ + if (typeHint == qMetaTypeId<SequenceType>()) { \ + return QV8##ElementTypeName##SequenceResource::toVariant(m_engine, array, length, succeeded); \ + } else + +QVariant QV8SequenceWrapper::toVariant(v8::Handle<v8::Array> array, int typeHint, bool *succeeded) +{ + *succeeded = true; + uint32_t length = array->Length(); + FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_TO_VARIANT) { /* else */ *succeeded = false; return QVariant(); } +} +#undef SEQUENCE_TO_VARIANT + +v8::Handle<v8::Value> QV8SequenceWrapper::IndexedSetter(quint32 index, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This()); + Q_ASSERT(sr); + return sr->indexedSetter(index, value); +} + +v8::Handle<v8::Value> QV8SequenceWrapper::IndexedGetter(quint32 index, const v8::AccessorInfo &info) +{ + QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This()); + Q_ASSERT(sr); + return sr->indexedGetter(index); +} + +v8::Handle<v8::Array> QV8SequenceWrapper::IndexedEnumerator(const v8::AccessorInfo &info) +{ + QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This()); + Q_ASSERT(sr); + return sr->indexedEnumerator(); +} + +v8::Handle<v8::Value> QV8SequenceWrapper::LengthGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info) +{ + Q_UNUSED(property); + QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This()); + Q_ASSERT(sr); + return v8::Integer::NewFromUnsigned(sr->lengthGetter()); +} + +v8::Handle<v8::Value> QV8SequenceWrapper::ToStringGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info) +{ + Q_UNUSED(property); + return info.Data(); +} + +v8::Handle<v8::Value> QV8SequenceWrapper::ValueOfGetter(v8::Local<v8::String> property, + const v8::AccessorInfo &info) +{ + Q_UNUSED(property); + return info.Data(); +} + +v8::Handle<v8::Value> QV8SequenceWrapper::ToString(const v8::Arguments &args) +{ + QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(args.This()); + Q_ASSERT(sr); + return sr->toString(); +} + +v8::Handle<v8::Value> QV8SequenceWrapper::ValueOf(const v8::Arguments &args) +{ + QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(args.This()); + Q_ASSERT(sr); + v8::Handle<v8::Value> tostringValue = sr->toString(); + if (!tostringValue.IsEmpty()) + return tostringValue; + return v8::Integer::NewFromUnsigned(sr->lengthGetter()); +} + +v8::Handle<v8::Value> QV8SequenceWrapper::Getter(v8::Local<v8::String> property, + const v8::AccessorInfo &info) +{ + Q_UNUSED(property); + Q_UNUSED(info); + return v8::Handle<v8::Value>(); +} + +v8::Handle<v8::Value> QV8SequenceWrapper::Setter(v8::Local<v8::String> property, + v8::Local<v8::Value> value, + const v8::AccessorInfo &info) +{ + Q_UNUSED(property); + Q_UNUSED(info); + return value; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/v8/qv8sequencewrapper_p.h b/src/declarative/qml/v8/qv8sequencewrapper_p.h new file mode 100644 index 0000000000..da0f7eacca --- /dev/null +++ b/src/declarative/qml/v8/qv8sequencewrapper_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV8SEQUENCEWRAPPER_P_H +#define QV8SEQUENCEWRAPPER_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 <QtCore/qglobal.h> +#include <QtCore/qvariant.h> +#include <private/qv8_p.h> + +QT_BEGIN_NAMESPACE + +class QV8Engine; +class QV8ObjectResource; +class QV8SequenceWrapper +{ +public: + QV8SequenceWrapper(); + ~QV8SequenceWrapper(); + + void init(QV8Engine *); + void destroy(); + + bool isEqual(QV8ObjectResource *lhs, const QVariant &rhs); + bool isEqual(QV8ObjectResource *lhs, QV8ObjectResource *rhs); + quint32 sequenceLength(QV8ObjectResource *); + + v8::Local<v8::Object> newSequence(int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded); + v8::Local<v8::Object> fromVariant(const QVariant& v, bool *succeeded); + QVariant toVariant(QV8ObjectResource *); + QVariant toVariant(v8::Handle<v8::Array> array, int typeHint, bool *succeeded); + +private: + QV8Engine *m_engine; + + v8::Persistent<v8::Function> m_constructor; + v8::Persistent<v8::Function> m_toString; + v8::Persistent<v8::Function> m_valueOf; + + static v8::Handle<v8::Value> IndexedGetter(quint32 index, const v8::AccessorInfo &info); + static v8::Handle<v8::Value> IndexedSetter(quint32 index, v8::Local<v8::Value> value, const v8::AccessorInfo &info); + static v8::Handle<v8::Array> IndexedEnumerator(const v8::AccessorInfo &info); + static v8::Handle<v8::Value> LengthGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info); + static v8::Handle<v8::Value> ToStringGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info); + static v8::Handle<v8::Value> ToString(const v8::Arguments &args); + static v8::Handle<v8::Value> ValueOfGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info); + static v8::Handle<v8::Value> ValueOf(const v8::Arguments &args); + static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property, const v8::AccessorInfo &info); + static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo &info); +}; + + +QT_END_NAMESPACE + +#endif // QV8SEQUENCEWRAPPER_P_H diff --git a/src/declarative/qml/v8/qv8sequencewrapper_p_p.h b/src/declarative/qml/v8/qv8sequencewrapper_p_p.h new file mode 100644 index 0000000000..04814e9efe --- /dev/null +++ b/src/declarative/qml/v8/qv8sequencewrapper_p_p.h @@ -0,0 +1,376 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV8SEQUENCEWRAPPER_P_P_H +#define QV8SEQUENCEWRAPPER_P_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 <private/qdeclarativeengine_p.h> +#include <private/qdeclarativemetatype_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QV8SequenceResource + \brief The abstract base class of the external resource used in sequence type objects + + Every sequence type object returned by QV8SequenceWrapper::fromVariant() or + QV8SequenceWrapper::newSequence() has a type-specific QV8SequenceResource which + contains the type name, the meta type ids of the sequence and sequence element + types, as well as either the sequence data (copy) or object pointer and property + index (reference) data associated with the sequence. + */ +class QV8SequenceResource : public QV8ObjectResource +{ + V8_RESOURCE_TYPE(SequenceType); + +public: + virtual ~QV8SequenceResource() {} + + enum ObjectType { Reference, Copy }; + + virtual QVariant toVariant() = 0; + virtual bool isEqual(const QV8SequenceResource *v) = 0; + + virtual quint32 lengthGetter() = 0; + virtual v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) = 0; + virtual v8::Handle<v8::Value> indexedGetter(quint32 index) = 0; + virtual v8::Handle<v8::Array> indexedEnumerator() = 0; + virtual v8::Handle<v8::Value> toString() = 0; + + ObjectType objectType; + QByteArray typeName; + int sequenceMetaTypeId; + int elementMetaTypeId; + +protected: + QV8SequenceResource(QV8Engine *engine, ObjectType type, const QByteArray &name, int sequenceId, int elementId) + : QV8ObjectResource(engine), objectType(type), typeName(name), sequenceMetaTypeId(sequenceId), elementMetaTypeId(elementId) + { + } +}; + +static int convertV8ValueToInt(QV8Engine *, v8::Handle<v8::Value> v) +{ + return v->Int32Value(); +} + +static v8::Handle<v8::Value> convertIntToV8Value(QV8Engine *, int v) +{ + return v8::Integer::New(v); +} + +static QString convertIntToString(QV8Engine *, int v) +{ + return QString::number(v); +} + +static qreal convertV8ValueToReal(QV8Engine *, v8::Handle<v8::Value> v) +{ + return v->NumberValue(); +} + +static v8::Handle<v8::Value> convertRealToV8Value(QV8Engine *, qreal v) +{ + return v8::Number::New(v); +} + +static QString convertRealToString(QV8Engine *, qreal v) +{ + return QString::number(v); +} + +static bool convertV8ValueToBool(QV8Engine *, v8::Handle<v8::Value> v) +{ + return v->BooleanValue(); +} + +static v8::Handle<v8::Value> convertBoolToV8Value(QV8Engine *, bool v) +{ + return v8::Boolean::New(v); +} + +static QString convertBoolToString(QV8Engine *, bool v) +{ + if (v) + return QLatin1String("true"); + return QLatin1String("false"); +} + +static QString convertV8ValueToString(QV8Engine *e, v8::Handle<v8::Value> v) +{ + return e->toString(v->ToString()); +} + +static v8::Handle<v8::Value> convertStringToV8Value(QV8Engine *e, const QString &v) +{ + return e->toString(v); +} + +static QString convertStringToString(QV8Engine *, const QString &v) +{ + return v; +} + +static QString convertV8ValueToQString(QV8Engine *e, v8::Handle<v8::Value> v) +{ + return e->toString(v->ToString()); +} + +static v8::Handle<v8::Value> convertQStringToV8Value(QV8Engine *e, const QString &v) +{ + return e->toString(v); +} + +static QString convertQStringToString(QV8Engine *, const QString &v) +{ + return v; +} + +static QUrl convertV8ValueToUrl(QV8Engine *e, v8::Handle<v8::Value> v) +{ + return QUrl(e->toString(v->ToString())); +} + +static v8::Handle<v8::Value> convertUrlToV8Value(QV8Engine *e, const QUrl &v) +{ + return e->toString(v.toString()); +} + +static QString convertUrlToString(QV8Engine *, const QUrl &v) +{ + return v.toString(); +} + + +/* + \internal + \class QV8<Type>SequenceResource + \brief The external resource used in sequence type objects + + Every sequence type object returned by QV8SequenceWrapper::newSequence() has + a QV8<Type>SequenceResource which contains a property index and a pointer + to the object which contains the property. + + Every sequence type object returned by QV8SequenceWrapper::fromVariant() has + a QV8<Type>SequenceResource which contains a copy of the sequence value. + Operations on the sequence are implemented directly in terms of that sequence data. + + There exists one QV8<Type>SequenceResource instance for every JavaScript Object + (sequence) instance returned from QV8SequenceWrapper::newSequence() or + QV8SequenceWrapper::fromVariant(). + */ + +// F(elementType, elementTypeName, sequenceType, defaultValue) +#define FOREACH_QML_SEQUENCE_TYPE(F) \ + F(int, Int, QList<int>, 0) \ + F(qreal, Real, QList<qreal>, 0.0) \ + F(bool, Bool, QList<bool>, false) \ + F(QString, String, QList<QString>, QString()) \ + F(QString, QString, QStringList, QString()) \ + F(QUrl, Url, QList<QUrl>, QUrl()) + +#define QML_SEQUENCE_TYPE_RESOURCE(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue, ConversionToV8fn, ConversionFromV8fn, ToStringfn) \ + Q_DECLARE_METATYPE(SequenceType) \ + class QV8##SequenceElementTypeName##SequenceResource : public QV8SequenceResource { \ + public:\ + QV8##SequenceElementTypeName##SequenceResource(QV8Engine *engine, QObject *obj, int propIdx) \ + : QV8SequenceResource(engine, QV8SequenceResource::Reference, #SequenceType, qMetaTypeId<SequenceType>(), qMetaTypeId<SequenceElementType>()) \ + , object(obj), propertyIndex(propIdx) \ + { \ + } \ + QV8##SequenceElementTypeName##SequenceResource(QV8Engine *engine, const SequenceType &value) \ + : QV8SequenceResource(engine, QV8SequenceResource::Copy, #SequenceType, qMetaTypeId<SequenceType>(), qMetaTypeId<SequenceElementType>()) \ + , object(0), propertyIndex(-1), c(value) \ + { \ + } \ + ~QV8##SequenceElementTypeName##SequenceResource() \ + { \ + } \ + static QVariant toVariant(QV8Engine *e, v8::Handle<v8::Array> array, uint32_t length, bool *succeeded) \ + { \ + SequenceType list; \ + for (uint32_t ii = 0; ii < length; ++ii) { \ + list.append(ConversionFromV8fn(e, array->Get(ii))); \ + } \ + *succeeded = true; \ + return QVariant::fromValue<SequenceType>(list); \ + } \ + QVariant toVariant() \ + { \ + if (objectType == QV8SequenceResource::Reference) { \ + if (!object) \ + return QVariant(); \ + void *a[] = { &c, 0 }; \ + QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \ + } \ + return QVariant::fromValue<SequenceType>(c); \ + } \ + bool isEqual(const QV8SequenceResource *v) \ + { \ + /* Note: two different sequences can never be equal (even if they */ \ + /* contain the same elements in the same order) in order to */ \ + /* maintain JavaScript semantics. However, if they both reference */ \ + /* the same QObject+propertyIndex, they are equal. */ \ + if (objectType == QV8SequenceResource::Reference && v->objectType == QV8SequenceResource::Reference) { \ + if (sequenceMetaTypeId == v->sequenceMetaTypeId) { \ + const QV8##SequenceElementTypeName##SequenceResource *rhs = static_cast<const QV8##SequenceElementTypeName##SequenceResource *>(v); \ + return (object != 0 && object == rhs->object && propertyIndex == rhs->propertyIndex); \ + } \ + } else if (objectType == QV8SequenceResource::Copy && v->objectType == QV8SequenceResource::Copy) { \ + if (sequenceMetaTypeId == v->sequenceMetaTypeId) { \ + const QV8##SequenceElementTypeName##SequenceResource *rhs = static_cast<const QV8##SequenceElementTypeName##SequenceResource *>(v); \ + return (this == rhs); \ + } \ + } \ + return false; \ + } \ + quint32 lengthGetter() \ + { \ + if (objectType == QV8SequenceResource::Reference) { \ + if (!object) \ + return 0; \ + void *a[] = { &c, 0 }; \ + QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \ + } \ + return c.count(); \ + } \ + v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) \ + { \ + if (objectType == QV8SequenceResource::Reference) { \ + if (!object) \ + return v8::Undefined(); \ + void *a[] = { &c, 0 }; \ + QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \ + } \ + /* modify the sequence */ \ + SequenceElementType elementValue = ConversionFromV8fn(engine, value); \ + quint32 count = c.count(); \ + if (index == count) { \ + c.append(elementValue); \ + } else if (index < count) { \ + c[index] = elementValue; \ + } else { \ + /* according to ECMA262r3 we need to insert */ \ + /* the value at the given index, increasing length to index+1. */ \ + while (index > count++) { \ + c.append(DefaultValue); \ + } \ + c.append(elementValue); \ + } \ + if (objectType == QV8SequenceResource::Reference) { \ + /* write back. already checked that object is non-null, so skip that check here. */ \ + int status = -1; \ + QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::DontRemoveBinding; \ + void *a[] = { &c, 0, &status, &flags }; \ + QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \ + } \ + return value; \ + } \ + v8::Handle<v8::Value> indexedGetter(quint32 index) \ + { \ + if (objectType == QV8SequenceResource::Reference) { \ + if (!object) \ + return v8::Undefined(); \ + void *a[] = { &c, 0 }; \ + QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \ + } \ + quint32 count = c.count(); \ + if (index < count) \ + return ConversionToV8fn(engine, c.at(index)); \ + return v8::Undefined(); \ + } \ + v8::Handle<v8::Array> indexedEnumerator() \ + { \ + if (objectType == QV8SequenceResource::Reference) { \ + if (!object) \ + return v8::Handle<v8::Array>(); \ + void *a[] = { &c, 0 }; \ + QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \ + } \ + quint32 count = c.count(); \ + v8::Local<v8::Array> retn = v8::Array::New(count); \ + for (quint32 i = 0; i < count; ++i) { \ + retn->Set(i, v8::Integer::NewFromUnsigned(i)); \ + } \ + return retn; \ + } \ + v8::Handle<v8::Value> toString() \ + { \ + if (objectType == QV8SequenceResource::Reference) { \ + if (!object) \ + return v8::Undefined(); \ + void *a[] = { &c, 0 }; \ + QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \ + } \ + QString str; \ + quint32 count = c.count(); \ + for (quint32 i = 0; i < count; ++i) { \ + str += QString(QLatin1String("%1,")).arg(ToStringfn(engine, c[i])); \ + } \ + str.chop(1); \ + return engine->toString(str); \ + } \ + private: \ + QDeclarativeGuard<QObject> object; \ + int propertyIndex; \ + SequenceType c; \ + }; + +#define GENERATE_QML_SEQUENCE_TYPE_RESOURCE(ElementType, ElementTypeName, SequenceType, DefaultValue) \ + QML_SEQUENCE_TYPE_RESOURCE(ElementType, ElementTypeName, SequenceType, DefaultValue, convert##ElementTypeName##ToV8Value, convertV8ValueTo##ElementTypeName, convert##ElementTypeName##ToString) + +FOREACH_QML_SEQUENCE_TYPE(GENERATE_QML_SEQUENCE_TYPE_RESOURCE) +#undef GENERATE_QML_SEQUENCE_TYPE_RESOURCE +#undef QML_SEQUENCE_TYPE_RESOURCE + +#endif // QV8SEQUENCEWRAPPER_P_P_H diff --git a/src/declarative/qml/v8/qv8typewrapper.cpp b/src/declarative/qml/v8/qv8typewrapper.cpp index 0023afc858..1a3a349524 100644 --- a/src/declarative/qml/v8/qv8typewrapper.cpp +++ b/src/declarative/qml/v8/qv8typewrapper.cpp @@ -159,7 +159,6 @@ QVariant QV8TypeWrapper::toVariant(QV8ObjectResource *r) v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property, const v8::AccessorInfo &info) { - v8::Object::ExternalResource *r = info.This()->GetExternalResource(); QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This()); if (!resource) @@ -257,7 +256,6 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo &info) { - v8::Object::ExternalResource *r = info.This()->GetExternalResource(); QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This()); if (!resource) diff --git a/src/declarative/qml/v8/qv8valuetypewrapper.cpp b/src/declarative/qml/v8/qv8valuetypewrapper.cpp index 35037fad9f..2c46b77823 100644 --- a/src/declarative/qml/v8/qv8valuetypewrapper.cpp +++ b/src/declarative/qml/v8/qv8valuetypewrapper.cpp @@ -295,9 +295,9 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property QDeclarativeContextData *context = r->engine->callingContext(); v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value); - QDeclarativePropertyCache::Data cacheData; - cacheData.setFlags(QDeclarativePropertyCache::Data::IsWritable | - QDeclarativePropertyCache::Data::IsValueTypeVirtual); + QDeclarativePropertyData cacheData; + cacheData.setFlags(QDeclarativePropertyData::IsWritable | + QDeclarativePropertyData::IsValueTypeVirtual); cacheData.propType = reference->object->metaObject()->property(reference->property).userType(); cacheData.coreIndex = reference->property; cacheData.valueTypeFlags = 0; diff --git a/src/declarative/qml/v8/qv8variantwrapper_p.h b/src/declarative/qml/v8/qv8variantwrapper_p.h index 7e9924b3c0..8bb0bcc073 100644 --- a/src/declarative/qml/v8/qv8variantwrapper_p.h +++ b/src/declarative/qml/v8/qv8variantwrapper_p.h @@ -72,8 +72,8 @@ public: v8::Local<v8::Object> newVariant(const QVariant &); bool isVariant(v8::Handle<v8::Value>); - QVariant toVariant(v8::Handle<v8::Object>); - QVariant toVariant(QV8ObjectResource *); + static QVariant toVariant(v8::Handle<v8::Object>); + static QVariant toVariant(QV8ObjectResource *); QVariant &variantValue(v8::Handle<v8::Value>); private: diff --git a/src/declarative/qml/v8/qv8worker.cpp b/src/declarative/qml/v8/qv8worker.cpp index d6998849e2..f0d9906915 100644 --- a/src/declarative/qml/v8/qv8worker.cpp +++ b/src/declarative/qml/v8/qv8worker.cpp @@ -74,7 +74,8 @@ enum Type { WorkerNumber, WorkerDate, WorkerRegexp, - WorkerListModel + WorkerListModel, + WorkerSequence }; static inline quint32 valueheader(Type type, quint32 size = 0) @@ -252,6 +253,33 @@ void QV8Worker::serialize(QByteArray &data, v8::Handle<v8::Value> v, QV8Engine * // No other QObject's are allowed to be sent push(data, valueheader(WorkerUndefined)); } else { + // we can convert sequences, but not other types with external data. + if (v->IsObject()) { + v8::Handle<v8::Object> seqObj = v->ToObject(); + QV8ObjectResource *r = static_cast<QV8ObjectResource *>(seqObj->GetExternalResource()); + if (r->resourceType() == QV8ObjectResource::SequenceType) { + QVariant sequenceVariant = engine->sequenceWrapper()->toVariant(r); + if (!sequenceVariant.isNull()) { + // valid sequence. we generate a length (sequence length + 1 for the sequence type) + uint32_t seqLength = engine->sequenceWrapper()->sequenceLength(r); + uint32_t length = seqLength + 1; + if (length > 0xFFFFFF) { + push(data, valueheader(WorkerUndefined)); + return; + } + reserve(data, sizeof(quint32) + length * sizeof(quint32)); + push(data, valueheader(WorkerSequence, length)); + serialize(data, v8::Integer::New(sequenceVariant.userType()), engine); // sequence type + for (uint32_t ii = 0; ii < seqLength; ++ii) { + serialize(data, seqObj->Get(ii), engine); // sequence elements + } + + return; + } + } + } + + // not a sequence. push(data, valueheader(WorkerUndefined)); } } @@ -330,6 +358,18 @@ v8::Handle<v8::Value> QV8Worker::deserialize(const char *&data, QV8Engine *engin agent->setV8Engine(engine); return rv; } + case WorkerSequence: + { + bool succeeded = false; + quint32 length = headersize(header); + quint32 seqLength = length - 1; + int sequenceType = deserialize(data, engine)->Int32Value(); + v8::Local<v8::Array> array = v8::Array::New(seqLength); + for (quint32 ii = 0; ii < seqLength; ++ii) + array->Set(ii, deserialize(data, engine)); + QVariant seqVariant = engine->sequenceWrapper()->toVariant(array, sequenceType, &succeeded); + return engine->sequenceWrapper()->fromVariant(seqVariant, &succeeded); + } } Q_ASSERT(!"Unreachable"); return v8::Undefined(); diff --git a/src/declarative/qml/v8/v8.pri b/src/declarative/qml/v8/v8.pri index c4372ab82a..924602ec39 100644 --- a/src/declarative/qml/v8/v8.pri +++ b/src/declarative/qml/v8/v8.pri @@ -9,6 +9,8 @@ HEADERS += \ $$PWD/qv8stringwrapper_p.h \ $$PWD/qv8engine_p.h \ $$PWD/qv8gccallback_p.h \ + $$PWD/qv8sequencewrapper_p.h \ + $$PWD/qv8sequencewrapper_p_p.h \ $$PWD/qv8contextwrapper_p.h \ $$PWD/qv8qobjectwrapper_p.h \ $$PWD/qv8typewrapper_p.h \ @@ -26,6 +28,7 @@ HEADERS += \ SOURCES += \ $$PWD/qv8stringwrapper.cpp \ $$PWD/qv8engine.cpp \ + $$PWD/qv8sequencewrapper.cpp \ $$PWD/qv8contextwrapper.cpp \ $$PWD/qv8qobjectwrapper.cpp \ $$PWD/qv8typewrapper.cpp \ diff --git a/src/declarative/scenegraph/coreapi/qsgmaterial.cpp b/src/declarative/scenegraph/coreapi/qsgmaterial.cpp index 65ce9eec93..36b50e89b6 100644 --- a/src/declarative/scenegraph/coreapi/qsgmaterial.cpp +++ b/src/declarative/scenegraph/coreapi/qsgmaterial.cpp @@ -220,7 +220,7 @@ void QSGMaterialShader::deactivate() \sa activate(), deactivate() */ -void QSGMaterialShader::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) +void QSGMaterialShader::updateState(const RenderState & /* state */, QSGMaterial * /* newMaterial */, QSGMaterial * /* oldMaterial */) { } diff --git a/src/declarative/scenegraph/qsgcontext.cpp b/src/declarative/scenegraph/qsgcontext.cpp index 23765176de..03b190ce7c 100644 --- a/src/declarative/scenegraph/qsgcontext.cpp +++ b/src/declarative/scenegraph/qsgcontext.cpp @@ -413,7 +413,7 @@ QSGTexture *QSGContext::createTexture(const QImage &image) const QSize QSGContext::minimumFBOSize() const { -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC return QSize(33, 33); #else return QSize(1, 1); diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode.cpp b/src/declarative/scenegraph/qsgdefaultglyphnode.cpp index b8cd247908..f41fbe486a 100644 --- a/src/declarative/scenegraph/qsgdefaultglyphnode.cpp +++ b/src/declarative/scenegraph/qsgdefaultglyphnode.cpp @@ -65,7 +65,7 @@ void QSGDefaultGlyphNode::setColor(const QColor &color) m_color = color; if (m_material != 0) { m_material->setColor(color); - setMaterial(m_material); // Indicate the material state has changed + markDirty(DirtyMaterial); } } diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp b/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp index 649c5437f0..3476ab1665 100644 --- a/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp @@ -208,7 +208,7 @@ void QSGTextMaskMaterial::populate(const QPointF &p, for (int i=0; i<glyphIndexes.size(); ++i) { QFixed subPixelPosition; if (supportsSubPixelPositions) - subPixelPosition = cache->subPixelPositionForX(QFixed::fromReal(glyphPositions.at(i).x())); + subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPositions.at(i).x())); QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition); const QTextureGlyphCache::Coord &c = cache->coords.value(glyph); diff --git a/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp b/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp index fbd8e0e7ed..4753b6021e 100644 --- a/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp +++ b/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp @@ -77,13 +77,8 @@ QSGDefaultRectangleNode::QSGDefaultRectangleNode(QSGContext *context) QSGDefaultRectangleNode::~QSGDefaultRectangleNode() { - switch (m_material_type) { - case TypeFlat: - break; - case TypeVertexGradient: + if (m_material_type == TypeVertexGradient) delete material(); - break; - } delete m_border; } @@ -111,10 +106,10 @@ void QSGDefaultRectangleNode::setColor(const QColor &color) { if (color == m_fill_material.color()) return; + m_fill_material.setColor(color); if (m_gradient_stops.isEmpty()) { Q_ASSERT(m_material_type == TypeFlat); - m_fill_material.setColor(color); - setMaterial(&m_fill_material); // Indicate that the material state has changed. + markDirty(DirtyMaterial); } } @@ -123,7 +118,8 @@ void QSGDefaultRectangleNode::setPenColor(const QColor &color) if (color == m_border_material.color()) return; m_border_material.setColor(color); - border()->setMaterial(&m_border_material); // Indicate that the material state has changed. + if (m_border) + m_border->markDirty(DirtyMaterial); } void QSGDefaultRectangleNode::setPenWidth(qreal width) @@ -131,11 +127,10 @@ void QSGDefaultRectangleNode::setPenWidth(qreal width) if (width == m_pen_width) return; m_pen_width = width; - QSGNode *b = border(); - if (m_pen_width <= 0 && b->parent()) - removeChildNode(b); - else if (m_pen_width > 0 && !b->parent()) - appendChildNode(b); + if (m_pen_width <= 0 && m_border && m_border->parent()) + removeChildNode(m_border); + else if (m_pen_width > 0 && !border()->parent()) + appendChildNode(m_border); m_dirty_geometry = true; } @@ -154,10 +149,7 @@ void QSGDefaultRectangleNode::setGradientStops(const QGradientStops &stops) if (stops.isEmpty()) { // No gradient specified, use flat color. if (m_material_type != TypeFlat) { - delete material(); - delete opaqueMaterial(); - setOpaqueMaterial(0); setMaterial(&m_fill_material); m_material_type = TypeFlat; @@ -253,7 +245,7 @@ void QSGDefaultRectangleNode::updateGeometry() QSGGeometry *borderGeometry = 0; if (m_border) { - borderGeometry = border()->geometry(); + borderGeometry = m_border->geometry(); Q_ASSERT(borderGeometry->sizeOfVertex() == sizeof(Vertex)); } @@ -333,13 +325,21 @@ void QSGDefaultRectangleNode::updateGeometry() qreal c = 1 - part; qreal s = part; for (int i = 0; i <= segments; ++i) { - qreal y = (part ? innerRect.bottom() : innerRect.top()) - innerRadius * c; // current inner y-coordinate. - qreal lx = innerRect.left() - innerRadius * s; // current inner left x-coordinate. - qreal rx = innerRect.right() + innerRadius * s; // current inner right x-coordinate. + qreal y, lx, rx; + if (innerRadius > 0) { + y = (part ? innerRect.bottom() : innerRect.top()) - innerRadius * c; // current inner y-coordinate. + lx = innerRect.left() - innerRadius * s; // current inner left x-coordinate. + rx = innerRect.right() + innerRadius * s; // current inner right x-coordinate. + gradientPos = ((part ? innerRect.height() : 0) + radius - innerRadius * c) / (innerRect.height() + 2 * radius); + } else { + y = (part ? innerRect.bottom() + innerRadius : innerRect.top() - innerRadius); // current inner y-coordinate. + lx = innerRect.left() - innerRadius; // current inner left x-coordinate. + rx = innerRect.right() + innerRadius; // current inner right x-coordinate. + gradientPos = ((part ? innerRect.height() + innerRadius : -innerRadius) + radius) / (innerRect.height() + 2 * radius); + } qreal Y = (part ? innerRect.bottom() : innerRect.top()) - outerRadius * c; // current outer y-coordinate. qreal lX = innerRect.left() - outerRadius * s; // current outer left x-coordinate. qreal rX = innerRect.right() + outerRadius * s; // current outer right x-coordinate. - gradientPos = ((part ? innerRect.height() : 0) + radius - innerRadius * c) / (innerRect.height() + 2 * radius); while (nextGradientStop <= lastGradientStop && stops.at(nextGradientStop).first <= gradientPos) { // Insert vertices at gradient stops. diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp index 22aced9b2e..60e5bb7727 100644 --- a/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp +++ b/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp @@ -236,7 +236,7 @@ void drawTriangle(qint32 *bits, int width, int height, const QPoint *center, const int v2Frac = clip == Clip ? (y2 << 8) + 0xff - v2->y() : ~v1->y() & 0xff; const int centerFrac = clip == Clip ? (yC << 8) + 0xff - center->y() : ~center->y() & 0xff; - int dx1, x1, dx2, x2; + int dx1 = 0, x1 = 0, dx2 = 0, x2 = 0; qint32 dd1, d1, dd2, d2; if (v1->y() != center->y()) { dx1 = ((v1->x() - center->x()) << 8) / (v1->y() - center->y()); @@ -372,8 +372,8 @@ void drawRectangle(qint32 *bits, int width, int height, const int int1Frac = clip == Clip ? (yi1 << 8) + 0xff - int1->y() : ~int1->y() & 0xff; const int ext1Frac = clip == Clip ? (ye1 << 8) + 0xff - ext1->y() : ~ext1->y() & 0xff; - int dxC, dxE; // cap slope, edge slope - qint32 ddC; + int dxC = 0, dxE = 0; // cap slope, edge slope + qint32 ddC = 0; if (ext1->y() != int1->y()) { dxC = ((ext1->x() - int1->x()) << 8) / (ext1->y() - int1->y()); ddC = (extValue << 9) / (ext1->y() - int1->y()); diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp index 5426c3b40a..e25b1520a1 100644 --- a/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp +++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp @@ -79,7 +79,7 @@ void QSGDistanceFieldGlyphNode::setColor(const QColor &color) m_color = color; if (m_material != 0) { m_material->setColor(color); - setMaterial(m_material); // Indicate the material state has changed + markDirty(DirtyMaterial); } } diff --git a/src/declarative/scenegraph/util/qsgpainternode.cpp b/src/declarative/scenegraph/util/qsgpainternode.cpp index 1f44750f98..f3e5202241 100644 --- a/src/declarative/scenegraph/util/qsgpainternode.cpp +++ b/src/declarative/scenegraph/util/qsgpainternode.cpp @@ -75,33 +75,38 @@ QSGPainterTexture::QSGPainterTexture() void QSGPainterTexture::bind() { - if (m_dirty_rect.isNull() || m_texture_id == 0) { + if (m_dirty_rect.isNull()) { QSGPlainTexture::bind(); - } else { - glBindTexture(GL_TEXTURE_2D, m_texture_id); + return; + } - QImage subImage = m_image.copy(m_dirty_rect); + bool oldMipmapsGenerated = m_mipmaps_generated; + m_mipmaps_generated = true; + QSGPlainTexture::bind(); + m_mipmaps_generated = oldMipmapsGenerated; - int w = m_dirty_rect.width(); - int h = m_dirty_rect.height(); + QImage subImage = m_image.copy(m_dirty_rect); + + int w = m_dirty_rect.width(); + int h = m_dirty_rect.height(); #ifdef QT_OPENGL_ES - glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), m_dirty_rect.y(), w, h, - GL_RGBA, GL_UNSIGNED_BYTE, subImage.constBits()); + glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), m_dirty_rect.y(), w, h, + GL_RGBA, GL_UNSIGNED_BYTE, subImage.constBits()); #else - glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), m_dirty_rect.y(), w, h, - GL_BGRA, GL_UNSIGNED_BYTE, subImage.constBits()); + glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), m_dirty_rect.y(), w, h, + GL_BGRA, GL_UNSIGNED_BYTE, subImage.constBits()); #endif - if (m_has_mipmaps && !m_mipmaps_generated) { - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D); - m_mipmaps_generated = true; - } - - m_dirty_texture = false; - m_dirty_bind_options = false; + if (m_has_mipmaps && !m_mipmaps_generated) { + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D); + m_mipmaps_generated = true; } + + m_dirty_texture = false; + m_dirty_bind_options = false; + m_dirty_rect = QRect(); } @@ -373,9 +378,9 @@ void QSGPainterNode::setSize(const QSize &size) m_dirtyTexture = true; } -void QSGPainterNode::setDirty(bool d, const QRect &dirtyRect) +void QSGPainterNode::setDirty(const QRect &dirtyRect) { - m_dirtyContents = d; + m_dirtyContents = true; m_dirtyRect = dirtyRect; if (m_mipmapping) diff --git a/src/declarative/scenegraph/util/qsgpainternode_p.h b/src/declarative/scenegraph/util/qsgpainternode_p.h index c838ed1a0c..8e95107efc 100644 --- a/src/declarative/scenegraph/util/qsgpainternode_p.h +++ b/src/declarative/scenegraph/util/qsgpainternode_p.h @@ -83,7 +83,7 @@ public: void setSize(const QSize &size); QSize size() const { return m_size; } - void setDirty(bool d, const QRect &dirtyRect = QRect()); + void setDirty(const QRect &dirtyRect = QRect()); void setOpaquePainting(bool opaque); bool opaquePainting() const { return m_opaquePainting; } diff --git a/src/declarative/scenegraph/util/qsgtexture.h b/src/declarative/scenegraph/util/qsgtexture.h index 135c5e403f..1a49fb941e 100644 --- a/src/declarative/scenegraph/util/qsgtexture.h +++ b/src/declarative/scenegraph/util/qsgtexture.h @@ -119,7 +119,7 @@ QRectF QSGTexture::convertToNormalizedSourceRect(const QRectF &rect) const } -class QSGDynamicTexture : public QSGTexture +class Q_DECLARATIVE_EXPORT QSGDynamicTexture : public QSGTexture { Q_OBJECT public: diff --git a/src/declarative/util/qdeclarativebehavior.cpp b/src/declarative/util/qdeclarativebehavior.cpp index 633e620d8d..062cc05e14 100644 --- a/src/declarative/util/qdeclarativebehavior.cpp +++ b/src/declarative/util/qdeclarativebehavior.cpp @@ -63,7 +63,6 @@ public: , blockRunningChanged(false) {} QDeclarativeProperty property; - QVariant currentValue; QVariant targetValue; QDeclarativeGuard<QDeclarativeAbstractAnimation> animation; QAbstractAnimation2Pointer animationInstance; @@ -185,7 +184,7 @@ void QDeclarativeBehavior::write(const QVariant &value) if (d->animation->isRunning() && value == d->targetValue) return; - d->currentValue = d->property.read(); + const QVariant ¤tValue = d->property.read(); d->targetValue = value; if (d->animationInstance && d->animationInstance->duration() != -1 @@ -197,7 +196,7 @@ void QDeclarativeBehavior::write(const QVariant &value) QDeclarativeStateOperation::ActionList actions; QDeclarativeAction action; action.property = d->property; - action.fromValue = d->currentValue; + action.fromValue = currentValue; action.toValue = value; actions << action; @@ -217,7 +216,6 @@ void QDeclarativeBehavior::setTarget(const QDeclarativeProperty &property) { Q_D(QDeclarativeBehavior); d->property = property; - d->currentValue = property.read(); if (d->animation) d->animation->setDefaultTarget(property); diff --git a/src/declarative/util/qdeclarativeconnections.cpp b/src/declarative/util/qdeclarativeconnections.cpp index c57363fdfe..aa944f3622 100644 --- a/src/declarative/util/qdeclarativeconnections.cpp +++ b/src/declarative/util/qdeclarativeconnections.cpp @@ -203,6 +203,8 @@ QDeclarativeConnectionsParser::compile(const QList<QDeclarativeCustomParserPrope for(int ii = 0; ii < props.count(); ++ii) { QString propName = props.at(ii).name(); + int propLine = props.at(ii).location().line; + if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) { error(props.at(ii), QDeclarativeConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName)); return QByteArray(); @@ -224,6 +226,7 @@ QDeclarativeConnectionsParser::compile(const QList<QDeclarativeCustomParserPrope if (v.isScript()) { ds << propName; ds << v.asScript(); + ds << propLine; } else { error(props.at(ii), QDeclarativeConnections::tr("Connections: script expected")); return QByteArray(); @@ -256,6 +259,8 @@ void QDeclarativeConnections::connectSignals() ds >> propName; QString script; ds >> script; + int line; + ds >> line; QDeclarativeProperty prop(target(), propName); if (prop.isValid() && (prop.type() & QDeclarativeProperty::SignalProperty)) { QDeclarativeBoundSignal *signal = @@ -263,7 +268,7 @@ void QDeclarativeConnections::connectSignals() 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); + expression->setSourceLocation(ddata->outerContext->url.toString(), line); signal->setExpression(expression); d->boundsignals += signal; } else { diff --git a/src/declarative/util/qdeclarativelistcompositor.cpp b/src/declarative/util/qdeclarativelistcompositor.cpp index be0d543368..b8b4dbf054 100644 --- a/src/declarative/util/qdeclarativelistcompositor.cpp +++ b/src/declarative/util/qdeclarativelistcompositor.cpp @@ -55,7 +55,7 @@ static bool qt_verifyMinimal( bool minimal = true; int index = 0; - for (const QDeclarativeListCompositor::Range *range = begin->next; range != end; range = range->next, ++index) { + for (const QDeclarativeListCompositor::Range *range = begin->next; range != *end; range = range->next, ++index) { if (range->previous->list == range->list && range->previous->flags == (range->flags & ~QDeclarativeListCompositor::AppendFlag) && range->previous->end() == range->index) { @@ -154,22 +154,6 @@ static bool qt_verifyIntegrity( //#define QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(args) qDebug() << m_end.index[1] << m_end.index[0] << Q_FUNC_INFO args; #define QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(args) -QDeclarativeListCompositor::iterator &QDeclarativeListCompositor::iterator::operator ++() -{ - while (!(range->flags & groupFlag)) { - incrementIndexes(range->count - offset); - offset = 0; - range = range->next; - } - incrementIndexes(1); - if (++offset == range->count) { - while (!((range = range->next)->flags & groupFlag)) - incrementIndexes(range->count); - offset = 0; - } - return *this; -} - QDeclarativeListCompositor::iterator &QDeclarativeListCompositor::iterator::operator +=(int difference) { Q_ASSERT(difference >= 0); @@ -210,27 +194,10 @@ QDeclarativeListCompositor::iterator &QDeclarativeListCompositor::iterator::oper return *this; } -QDeclarativeListCompositor::insert_iterator &QDeclarativeListCompositor::insert_iterator::operator ++() -{ - while (!(range->flags & groupFlag)) { - incrementIndexes(range->count - offset); - offset = 0; - range = range->next; - } - incrementIndexes(1); - if (++offset == range->count && !range->append()) { - while (!((range = range->next)->flags & groupFlag) ){ - incrementIndexes(range->count); - } - offset = 0; - } - return *this; -} - QDeclarativeListCompositor::insert_iterator &QDeclarativeListCompositor::insert_iterator::operator +=(int difference) { Q_ASSERT(difference >= 0); - while (!(range->flags & groupFlag) && range->flags & GroupMask) { + while (!(range->flags & groupFlag) && (range->flags & (GroupMask | CacheFlag))) { incrementIndexes(range->count - offset); offset = 0; range = range->next; @@ -252,7 +219,7 @@ QDeclarativeListCompositor::insert_iterator &QDeclarativeListCompositor::insert_ QDeclarativeListCompositor::insert_iterator &QDeclarativeListCompositor::insert_iterator::operator -=(int difference) { Q_ASSERT(difference >= 0); - while (!(range->flags & groupFlag) && range->flags & GroupMask) { + while (!(range->flags & groupFlag) && (range->flags & (GroupMask | CacheFlag))) { decrementIndexes(offset); range = range->previous; offset = range->count; @@ -359,7 +326,7 @@ QDeclarativeListCompositor::insert_iterator QDeclarativeListCompositor::findInse Q_ASSERT(index >=0 && index <= count(group)); insert_iterator it; if (m_cacheIt == m_end) { - m_cacheIt = iterator(m_ranges.next, 0, group, m_groupCount); + it = iterator(m_ranges.next, 0, group, m_groupCount); it += index; } else { const int offset = index - m_cacheIt.index[group]; @@ -489,7 +456,12 @@ void QDeclarativeListCompositor::setFlags( from->previous->flags |= AppendFlag; *from = erase(*from)->previous; continue; + } else { + break; } + } else if (!insertFlags) { + from.incrementIndexes(from->count - difference); + continue; } else if (difference < from->count) { *from = insert(*from, from->list, from->index, difference, setFlags)->next; from->index += difference; @@ -707,6 +679,16 @@ void QDeclarativeListCompositor::move( if (fromIt->append()) fromIt->previous->flags |= AppendFlag; *fromIt = erase(*fromIt); + + if (*fromIt != m_ranges.next && fromIt->flags == PrependFlag + && fromIt->previous != &m_ranges + && fromIt->previous->flags == PrependFlag + && fromIt->previous->list == fromIt->list + && fromIt->previous->end() == fromIt->index) { + fromIt.incrementIndexes(fromIt->count); + fromIt->previous->count += fromIt->count; + *fromIt = erase(*fromIt); + } } else if (count > 0) { *fromIt = fromIt->next; } @@ -830,6 +812,14 @@ void QDeclarativeListCompositor::listItemsInserted( } if ((it->flags & ~AppendFlag) == flags) { it->count += insertion.count; + } else if (offset == 0 + && it->previous != &m_ranges + && it->previous->list == list + && it->previous->end() == insertion.index + && it->previous->flags == flags) { + it->previous->count += insertion.count; + it->index += insertion.count; + it.incrementIndexes(insertion.count); } else { if (offset > 0) { it.incrementIndexes(offset); @@ -976,6 +966,7 @@ void QDeclarativeListCompositor::listItemsRemoved( } else { *it = insert(*it, it->list, -1, removeCount, CacheFlag)->next; } + it.index[Cache] += removeCount; } if (removeFlags & GroupMask) translatedRemovals->append(translatedRemoval); @@ -988,16 +979,23 @@ void QDeclarativeListCompositor::listItemsRemoved( } } else if (relativeIndex < 0) { it->index -= itemsRemoved; + + if (it->previous != &m_ranges + && it->previous->list == it->list + && it->previous->end() == it->index + && it->previous->flags == (it->flags & ~AppendFlag)) { + it->previous->count += it->count; + it->previous->flags = it->flags; + it.incrementIndexes(it->count); + *it = erase(*it); + removed = true; + } } } - if (it->next != &m_ranges - && it->list == it->next->list - && (it->flags == CacheFlag || it->end() == it->next->index) - && it->flags == (it->next->flags & ~AppendFlag)) { + if (it->flags == CacheFlag && it->next->flags == CacheFlag && it->next->list == it->list) { + it.index[Cache] += it->next->count; it->count += it->next->count; - it->flags = it->next->flags; erase(it->next); - *it = it->previous; } else if (!removed) { it.incrementIndexes(it->count); } @@ -1025,7 +1023,6 @@ void QDeclarativeListCompositor::listItemsMoved( QVector<Remove> *translatedRemovals, QVector<Insert> *translatedInsertions) { - QT_DECLARATIVE_TRACE_LISTCOMPOSITOR(<< list << from << to << count) Q_ASSERT(count >= 0); diff --git a/src/declarative/util/qdeclarativelistcompositor_p.h b/src/declarative/util/qdeclarativelistcompositor_p.h index 60df819884..c808f6fe80 100644 --- a/src/declarative/util/qdeclarativelistcompositor_p.h +++ b/src/declarative/util/qdeclarativelistcompositor_p.h @@ -132,7 +132,6 @@ public: Range *operator ->() { return range; } const Range *operator ->() const { return range; } - iterator &operator ++(); iterator &operator +=(int difference); iterator &operator -=(int difference); @@ -168,7 +167,6 @@ public: inline insert_iterator(Range *, int, Group, int); inline ~insert_iterator() {} - insert_iterator &operator ++(); insert_iterator &operator +=(int difference); insert_iterator &operator -=(int difference); }; diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp index 4e67182048..dceb0045e3 100644 --- a/src/declarative/util/qdeclarativelistmodel.cpp +++ b/src/declarative/util/qdeclarativelistmodel.cpp @@ -59,141 +59,1137 @@ Q_DECLARE_METATYPE(QListModelInterface *) QT_BEGIN_NAMESPACE -QV8ListModelResource::QV8ListModelResource(FlatListModel *model, FlatNodeData *data, QV8Engine *engine) -: QV8ObjectResource(engine), model(model), nodeData(data) +// Set to 1024 as a debugging aid - easier to distinguish uids from indices of elements/models. +enum { MIN_LISTMODEL_UID = 1024 }; + +QAtomicInt ListModel::uidCounter(MIN_LISTMODEL_UID); + +template <typename T> +static bool isMemoryUsed(const char *mem) { - if (nodeData) nodeData->addData(this); + for (size_t i=0 ; i < sizeof(T) ; ++i) { + if (mem[i] != 0) + return true; + } + + return false; } -QV8ListModelResource::~QV8ListModelResource() +static QString roleTypeName(ListLayout::Role::DataType t) { - if (nodeData) nodeData->removeData(this); + QString result; + const char *roleTypeNames[] = { "String", "Number", "Bool", "List", "QObject" }; + + if (t > ListLayout::Role::Invalid && t < ListLayout::Role::MaxDataType) + result = QString::fromLatin1(roleTypeNames[t]); + + return result; } -class QDeclarativeListModelV8Data : public QV8Engine::Deletable +const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::DataType type) { -public: - QDeclarativeListModelV8Data(); - ~QDeclarativeListModelV8Data(); + QStringHash<Role *>::Node *node = roleHash.findNode(key); + if (node) { + const Role &r = *node->value; + if (type != r.type) + qmlInfo(0) << QString::fromLatin1("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); + return r; + } + + return createRole(key, type); +} - v8::Persistent<v8::Function> constructor; +const ListLayout::Role &ListLayout::getRoleOrCreate(v8::Handle<v8::String> key, Role::DataType type) +{ + QHashedV8String hashedKey(key); + QStringHash<Role *>::Node *node = roleHash.findNode(hashedKey); + if (node) { + const Role &r = *node->value; + if (type != r.type) + qmlInfo(0) << QString::fromLatin1("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); + return r; + } - static v8::Local<v8::Object> create(QV8Engine *); + QString qkey; + qkey.resize(key->Length()); + key->Write(reinterpret_cast<uint16_t*>(qkey.data())); - static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property, - const v8::AccessorInfo &info); - static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property, - v8::Local<v8::Value> value, - const v8::AccessorInfo &info); -}; + return createRole(qkey, type); +} -v8::Local<v8::Object> QDeclarativeListModelV8Data::create(QV8Engine *engine) +const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::Role::DataType type) { - if (!engine->listModelData()) { - QDeclarativeListModelV8Data *d = new QDeclarativeListModelV8Data; - engine->setListModelData(d); + const int dataSizes[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QDeclarativeGuard<QObject>), sizeof(QVariantMap) }; + const int dataAlignments[] = { sizeof(QString), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap) }; + + Role *r = new Role; + r->name = key; + r->type = type; + + if (type == Role::List) { + r->subLayout = new ListLayout; + } else { + r->subLayout = 0; + } + + int dataSize = dataSizes[type]; + int dataAlignment = dataAlignments[type]; + + int dataOffset = (currentBlockOffset + dataAlignment-1) & ~(dataAlignment-1); + if (dataOffset + dataSize > ListElement::BLOCK_SIZE) { + r->blockIndex = ++currentBlock; + r->blockOffset = 0; + currentBlockOffset = dataSize; + } else { + r->blockIndex = currentBlock; + r->blockOffset = dataOffset; + currentBlockOffset = dataOffset + dataSize; + } + + int roleIndex = roles.count(); + r->index = roleIndex; + + roles.append(r); + roleHash.insert(key, r); + + return *r; +} + +ListLayout::ListLayout(const ListLayout *other) : currentBlock(0), currentBlockOffset(0) +{ + for (int i=0 ; i < other->roles.count() ; ++i) { + Role *role = new Role(other->roles[i]); + roles.append(role); + roleHash.insert(role->name, role); + } + currentBlockOffset = other->currentBlockOffset; + currentBlock = other->currentBlock; +} + +ListLayout::~ListLayout() +{ + for (int i=0 ; i < roles.count() ; ++i) { + delete roles[i]; + } +} + +void ListLayout::sync(ListLayout *src, ListLayout *target) +{ + int roleOffset = target->roles.count(); + int newRoleCount = src->roles.count() - roleOffset; + + for (int i=0 ; i < newRoleCount ; ++i) { + Role *role = new Role(src->roles[roleOffset + i]); + target->roles.append(role); + target->roleHash.insert(role->name, role); + } + + target->currentBlockOffset = src->currentBlockOffset; + target->currentBlock = src->currentBlock; +} + +ListLayout::Role::Role(const Role *other) +{ + name = other->name; + type = other->type; + blockIndex = other->blockIndex; + blockOffset = other->blockOffset; + index = other->index; + if (other->subLayout) + subLayout = new ListLayout(other->subLayout); + else + subLayout = 0; +} + +ListLayout::Role::~Role() +{ + delete subLayout; +} + +const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QVariant &data) +{ + Role::DataType type; + + switch (data.type()) { + case QVariant::Double: type = Role::Number; break; + case QVariant::Int: type = Role::Number; break; + case QVariant::UserType: type = Role::List; break; + case QVariant::Bool: type = Role::Bool; break; + case QVariant::String: type = Role::String; break; + default: type = Role::Invalid; break; + } + + if (type == Role::Invalid) { + qmlInfo(0) << "Can't create role for unsupported data type"; + return 0; } - QDeclarativeListModelV8Data *d = (QDeclarativeListModelV8Data *)engine->listModelData(); - return d->constructor->NewInstance(); + return &getRoleOrCreate(key, type); } -QDeclarativeListModelV8Data::QDeclarativeListModelV8Data() +const ListLayout::Role *ListLayout::getExistingRole(const QString &key) { - v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(); - ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter); - ft->InstanceTemplate()->SetHasExternalResource(true); - constructor = qPersistentNew<v8::Function>(ft->GetFunction()); + Role *r = 0; + QStringHash<Role *>::Node *node = roleHash.findNode(key); + if (node) + r = node->value; + return r; } -QDeclarativeListModelV8Data::~QDeclarativeListModelV8Data() +const ListLayout::Role *ListLayout::getExistingRole(v8::Handle<v8::String> key) { - qPersistentDispose(constructor); + Role *r = 0; + QHashedV8String hashedKey(key); + QStringHash<Role *>::Node *node = roleHash.findNode(hashedKey); + if (node) + r = node->value; + return r; } -v8::Handle<v8::Value> QDeclarativeListModelV8Data::Getter(v8::Local<v8::String> property, - const v8::AccessorInfo &info) +ModelObject *ListModel::getOrCreateModelObject(QDeclarativeListModel *model, int elementIndex) { - QV8ListModelResource *r = v8_resource_cast<QV8ListModelResource>(info.This()); - if (!r) - return v8::Undefined(); + ListElement *e = elements[elementIndex]; + if (e->m_objectCache == 0) { + e->m_objectCache = new ModelObject(model, elementIndex); + } + return e->m_objectCache; +} - if (!r->nodeData) // Item at this index has been deleted - return v8::Undefined(); +void ListModel::sync(ListModel *src, ListModel *target, QHash<int, ListModel *> *targetModelHash) +{ + // Sanity check + target->m_uid = src->m_uid; + if (targetModelHash) + targetModelHash->insert(target->m_uid, target); + // Build hash of elements <-> uid for each of the lists + QHash<int, ElementSync> elementHash; + for (int i=0 ; i < target->elements.count() ; ++i) { + ListElement *e = target->elements.at(i); + int uid = e->getUid(); + ElementSync sync; + sync.target = e; + elementHash.insert(uid, sync); + } + for (int i=0 ; i < src->elements.count() ; ++i) { + ListElement *e = src->elements.at(i); + int uid = e->getUid(); + + QHash<int, ElementSync>::iterator it = elementHash.find(uid); + if (it == elementHash.end()) { + ElementSync sync; + sync.src = e; + elementHash.insert(uid, sync); + } else { + ElementSync &sync = it.value(); + sync.src = e; + } + } + + // Get list of elements that are in the target but no longer in the source. These get deleted first. + QHash<int, ElementSync>::iterator it = elementHash.begin(); + QHash<int, ElementSync>::iterator end = elementHash.end(); + while (it != end) { + const ElementSync &s = it.value(); + if (s.src == 0) { + s.target->destroy(target->m_layout); + target->elements.removeOne(s.target); + delete s.target; + } + ++it; + } - int index = r->nodeData->index; - QString propName = r->engine->toString(property); + // Sync the layouts + ListLayout::sync(src->m_layout, target->m_layout); + + // Clear the target list, and append in correct order from the source + target->elements.clear(); + for (int i=0 ; i < src->elements.count() ; ++i) { + ListElement *srcElement = src->elements.at(i); + it = elementHash.find(srcElement->getUid()); + const ElementSync &s = it.value(); + ListElement *targetElement = s.target; + if (targetElement == 0) { + targetElement = new ListElement(srcElement->getUid()); + } + ListElement::sync(srcElement, src->m_layout, targetElement, target->m_layout, targetModelHash); + target->elements.append(targetElement); + } - int role = r->model->m_strings.value(propName, -1); + target->updateCacheIndices(); - if (role >= 0 && index >=0 ) { - const QHash<int, QVariant> &row = r->model->m_values[index]; - return r->engine->fromVariant(row[role]); + // Update values stored in target meta objects + for (int i=0 ; i < target->elements.count() ; ++i) { + ListElement *e = target->elements[i]; + if (e->m_objectCache) + e->m_objectCache->updateValues(); } +} - return v8::Undefined(); +int ListModel::allocateUid() +{ + return uidCounter.fetchAndAddOrdered(1); } -v8::Handle<v8::Value> QDeclarativeListModelV8Data::Setter(v8::Local<v8::String> property, - v8::Local<v8::Value> value, - const v8::AccessorInfo &info) +ListModel::ListModel(ListLayout *layout, QDeclarativeListModel *modelCache, int uid) : m_layout(layout), m_modelCache(modelCache) { - QV8ListModelResource *r = v8_resource_cast<QV8ListModelResource>(info.This()); - if (!r) - return v8::Undefined(); + if (uid == -1) + uid = allocateUid(); + m_uid = uid; +} - if (!r->nodeData) // item at this index has been deleted - return value; +void ListModel::destroy() +{ + clear(); + m_uid = -1; + m_layout = 0; + if (m_modelCache && m_modelCache->m_primary == false) + delete m_modelCache; + m_modelCache = 0; +} + +int ListModel::appendElement() +{ + int elementIndex = elements.count(); + newElement(elementIndex); + return elementIndex; +} +void ListModel::insertElement(int index) +{ + newElement(index); + updateCacheIndices(); +} - if (!value->IsRegExp() && !value->IsDate() && value->IsObject() && !r->engine->isVariant(value)) { - qmlInfo(r->model->m_listModel) << "Cannot add list-type data when modifying or after modification from a worker script"; - return value; +void ListModel::move(int from, int to, int n) +{ + if (from > to) { + // Only move forwards - flip if backwards moving + int tfrom = from; + int tto = to; + from = tto; + to = tto+n; + n = tfrom-tto; } - int index = r->nodeData->index; - QString propName = r->engine->toString(property); + QPODVector<ListElement *, 4> store; + for (int i=0 ; i < (to-from) ; ++i) + store.append(elements[from+n+i]); + for (int i=0 ; i < n ; ++i) + store.append(elements[from+i]); + for (int i=0 ; i < store.count() ; ++i) + elements[from+i] = store[i]; - int role = r->model->m_strings.value(propName, -1); - if (role >= 0 && index >= 0) { - QHash<int, QVariant> &row = r->model->m_values[index]; - row[role] = r->engine->toVariant(value, -1); + updateCacheIndices(); +} - QList<int> roles; - roles << role; - if (r->model->m_parentAgent) { - // This is the list in the worker thread, so tell the agent to - // emit itemsChanged() later - r->model->m_parentAgent->changedData(index, 1, roles); +void ListModel::newElement(int index) +{ + ListElement *e = new ListElement; + elements.insert(index, e); +} + +void ListModel::updateCacheIndices() +{ + for (int i=0 ; i < elements.count() ; ++i) { + ListElement *e = elements.at(i); + if (e->m_objectCache) { + e->m_objectCache->m_elementIndex = i; + } + } +} + +QVariant ListModel::getProperty(int elementIndex, int roleIndex, const QDeclarativeListModel *owner, QV8Engine *eng) +{ + ListElement *e = elements[elementIndex]; + const ListLayout::Role &r = m_layout->getExistingRole(roleIndex); + return e->getProperty(r, owner, eng); +} + +ListModel *ListModel::getListProperty(int elementIndex, const ListLayout::Role &role) +{ + ListElement *e = elements[elementIndex]; + return e->getListProperty(role); +} + +void ListModel::set(int elementIndex, v8::Handle<v8::Object> object, QList<int> *roles, QV8Engine *eng) +{ + ListElement *e = elements[elementIndex]; + + v8::Local<v8::Array> propertyNames = object->GetPropertyNames(); + int propertyCount = propertyNames->Length(); + + for (int i=0 ; i < propertyCount ; ++i) { + v8::Local<v8::String> propertyName = propertyNames->Get(i)->ToString(); + v8::Local<v8::Value> propertyValue = object->Get(propertyName); + + // Check if this key exists yet + int roleIndex = -1; + + // Add the value now + if (propertyValue->IsString()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String); + v8::Handle<v8::String> jsString = propertyValue->ToString(); + QString qstr; + qstr.resize(jsString->Length()); + jsString->Write(reinterpret_cast<uint16_t*>(qstr.data())); + roleIndex = e->setStringProperty(r, qstr); + } else if (propertyValue->IsNumber()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number); + roleIndex = e->setDoubleProperty(r, propertyValue->NumberValue()); + } else if (propertyValue->IsArray()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List); + ListModel *subModel = new ListModel(r.subLayout, 0, -1); + + v8::Handle<v8::Array> subArray = v8::Handle<v8::Array>::Cast(propertyValue); + int arrayLength = subArray->Length(); + for (int j=0 ; j < arrayLength ; ++j) { + v8::Handle<v8::Object> subObject = subArray->Get(j)->ToObject(); + subModel->append(subObject, eng); + } + + roleIndex = e->setListProperty(r, subModel); + } else if (propertyValue->IsBoolean()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool); + roleIndex = e->setBoolProperty(r, propertyValue->BooleanValue()); + } else if (propertyValue->IsObject()) { + QV8ObjectResource *r = (QV8ObjectResource *) propertyValue->ToObject()->GetExternalResource(); + if (r && r->resourceType() == QV8ObjectResource::QObjectType) { + QObject *o = QV8QObjectWrapper::toQObject(r); + const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject); + if (role.type == ListLayout::Role::QObject) + e->setQObjectProperty(role, o); + } else { + const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap); + if (role.type == ListLayout::Role::VariantMap) + e->setVariantMapProperty(role, propertyValue->ToObject(), eng); + } + } else if (propertyValue.IsEmpty() || propertyValue->IsUndefined() || propertyValue->IsNull()) { + const ListLayout::Role *r = m_layout->getExistingRole(propertyName); + if (r) + e->clearProperty(*r); + } + + if (roleIndex != -1) + roles->append(roleIndex); + } + + if (e->m_objectCache) { + e->m_objectCache->updateValues(*roles); + } +} + +void ListModel::set(int elementIndex, v8::Handle<v8::Object> object, QV8Engine *eng) +{ + ListElement *e = elements[elementIndex]; + + v8::Local<v8::Array> propertyNames = object->GetPropertyNames(); + int propertyCount = propertyNames->Length(); + + for (int i=0 ; i < propertyCount ; ++i) { + v8::Local<v8::String> propertyName = propertyNames->Get(i)->ToString(); + v8::Local<v8::Value> propertyValue = object->Get(propertyName); + + // Add the value now + if (propertyValue->IsString()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String); + if (r.type == ListLayout::Role::String) { + v8::Handle<v8::String> jsString = propertyValue->ToString(); + QString qstr; + qstr.resize(jsString->Length()); + jsString->Write(reinterpret_cast<uint16_t*>(qstr.data())); + e->setStringPropertyFast(r, qstr); + } + } else if (propertyValue->IsNumber()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number); + if (r.type == ListLayout::Role::Number) { + e->setDoublePropertyFast(r, propertyValue->NumberValue()); + } + } else if (propertyValue->IsArray()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List); + if (r.type == ListLayout::Role::List) { + ListModel *subModel = new ListModel(r.subLayout, 0, -1); + + v8::Handle<v8::Array> subArray = v8::Handle<v8::Array>::Cast(propertyValue); + int arrayLength = subArray->Length(); + for (int j=0 ; j < arrayLength ; ++j) { + v8::Handle<v8::Object> subObject = subArray->Get(j)->ToObject(); + subModel->append(subObject, eng); + } + + e->setListPropertyFast(r, subModel); + } + } else if (propertyValue->IsBoolean()) { + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool); + if (r.type == ListLayout::Role::Bool) { + e->setBoolPropertyFast(r, propertyValue->BooleanValue()); + } + } else if (propertyValue->IsObject()) { + QV8ObjectResource *r = (QV8ObjectResource *) propertyValue->ToObject()->GetExternalResource(); + if (r && r->resourceType() == QV8ObjectResource::QObjectType) { + QObject *o = QV8QObjectWrapper::toQObject(r); + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject); + if (r.type == ListLayout::Role::QObject) + e->setQObjectPropertyFast(r, o); + } else { + const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap); + if (role.type == ListLayout::Role::VariantMap) + e->setVariantMapFast(role, propertyValue->ToObject(), eng); + } + } else if (propertyValue.IsEmpty() || propertyValue->IsUndefined() || propertyValue->IsNull()) { + const ListLayout::Role *r = m_layout->getExistingRole(propertyName); + if (r) + e->clearProperty(*r); + } + } +} + +void ListModel::clear() +{ + int elementCount = elements.count(); + for (int i=0 ; i < elementCount ; ++i) { + elements[i]->destroy(m_layout); + delete elements[i]; + } + elements.clear(); +} + +void ListModel::remove(int index) +{ + elements[index]->destroy(m_layout); + delete elements[index]; + elements.remove(index); + updateCacheIndices(); +} + +void ListModel::insert(int elementIndex, v8::Handle<v8::Object> object, QV8Engine *eng) +{ + insertElement(elementIndex); + set(elementIndex, object, eng); +} + +int ListModel::append(v8::Handle<v8::Object> object, QV8Engine *eng) +{ + int elementIndex = appendElement(); + set(elementIndex, object, eng); + return elementIndex; +} + +int ListModel::setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data) +{ + int roleIndex = -1; + + if (elementIndex >= 0 && elementIndex < elements.count()) { + ListElement *e = elements[elementIndex]; + const ListLayout::Role *r = m_layout->getRoleOrCreate(key, data); + if (r) { + roleIndex = e->setVariantProperty(*r, data); + + if (roleIndex != -1 && e->m_objectCache) { + QList<int> roles; + roles << roleIndex; + e->m_objectCache->updateValues(roles); + } + } + } + + return roleIndex; +} + +int ListModel::setExistingProperty(int elementIndex, const QString &key, v8::Handle<v8::Value> data, QV8Engine *eng) +{ + int roleIndex = -1; + + if (elementIndex >= 0 && elementIndex < elements.count()) { + ListElement *e = elements[elementIndex]; + const ListLayout::Role *r = m_layout->getExistingRole(key); + if (r) + roleIndex = e->setJsProperty(*r, data, eng); + } + + return roleIndex; +} + +inline char *ListElement::getPropertyMemory(const ListLayout::Role &role) +{ + ListElement *e = this; + int blockIndex = 0; + while (blockIndex < role.blockIndex) { + if (e->next == 0) { + e->next = new ListElement; + e->next->uid = uid; + } + e = e->next; + ++blockIndex; + } + + char *mem = &e->data[role.blockOffset]; + return mem; +} + +QString *ListElement::getStringProperty(const ListLayout::Role &role) +{ + char *mem = getPropertyMemory(role); + QString *s = reinterpret_cast<QString *>(mem); + return s->data_ptr() ? s : 0; +} + +QObject *ListElement::getQObjectProperty(const ListLayout::Role &role) +{ + char *mem = getPropertyMemory(role); + QDeclarativeGuard<QObject> *o = reinterpret_cast<QDeclarativeGuard<QObject> *>(mem); + return o->data(); +} + +QVariantMap *ListElement::getVariantMapProperty(const ListLayout::Role &role) +{ + QVariantMap *map = 0; + + char *mem = getPropertyMemory(role); + if (isMemoryUsed<QVariantMap>(mem)) + map = reinterpret_cast<QVariantMap *>(mem); + + return map; +} + +QDeclarativeGuard<QObject> *ListElement::getGuardProperty(const ListLayout::Role &role) +{ + char *mem = getPropertyMemory(role); + + bool existingGuard = false; + for (size_t i=0 ; i < sizeof(QDeclarativeGuard<QObject>) ; ++i) { + if (mem[i] != 0) { + existingGuard = true; + break; + } + } + + QDeclarativeGuard<QObject> *o = 0; + + if (existingGuard) + o = reinterpret_cast<QDeclarativeGuard<QObject> *>(mem); + + return o; +} + +ListModel *ListElement::getListProperty(const ListLayout::Role &role) +{ + char *mem = getPropertyMemory(role); + ListModel **value = reinterpret_cast<ListModel **>(mem); + return *value; +} + +QVariant ListElement::getProperty(const ListLayout::Role &role, const QDeclarativeListModel *owner, QV8Engine *eng) +{ + char *mem = getPropertyMemory(role); + + QVariant data; + + switch (role.type) { + case ListLayout::Role::Number: + { + double *value = reinterpret_cast<double *>(mem); + data = *value; + } + break; + case ListLayout::Role::String: + { + QString *value = reinterpret_cast<QString *>(mem); + if (value->data_ptr() != 0) + data = *value; + } + break; + case ListLayout::Role::Bool: + { + bool *value = reinterpret_cast<bool *>(mem); + data = *value; + } + break; + case ListLayout::Role::List: + { + ListModel **value = reinterpret_cast<ListModel **>(mem); + ListModel *model = *value; + + if (model) { + if (model->m_modelCache == 0) { + model->m_modelCache = new QDeclarativeListModel(owner, model, eng); + QDeclarativeEngine::setContextForObject(model->m_modelCache, QDeclarativeEngine::contextForObject(owner)); + } + + QObject *object = model->m_modelCache; + data = QVariant::fromValue(object); + } + } + break; + case ListLayout::Role::QObject: + { + QDeclarativeGuard<QObject> *guard = reinterpret_cast<QDeclarativeGuard<QObject> *>(mem); + QObject *object = guard->data(); + if (object) + data = QVariant::fromValue(object); + } + break; + case ListLayout::Role::VariantMap: + { + if (isMemoryUsed<QVariantMap>(mem)) { + QVariantMap *map = reinterpret_cast<QVariantMap *>(mem); + data = *map; + } + } + break; + default: + break; + } + + return data; +} + +int ListElement::setStringProperty(const ListLayout::Role &role, const QString &s) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::String) { + char *mem = getPropertyMemory(role); + QString *c = reinterpret_cast<QString *>(mem); + bool changed; + if (c->data_ptr() == 0) { + new (mem) QString(s); + changed = true; } else { - // This is the list in the main thread, so emit itemsChanged() - emit r->model->m_listModel->itemsChanged(index, 1, roles); + changed = c->compare(s) != 0; + *c = s; } + if (changed) + roleIndex = role.index; } - return value; + return roleIndex; } -template<typename T> -void qdeclarativelistmodel_move(int from, int to, int n, T *items) +int ListElement::setDoubleProperty(const ListLayout::Role &role, double d) { - if (n == 1) { - items->move(from, to); - } else { - T replaced; - int i=0; - typename T::ConstIterator it=items->begin(); it += from+n; - for (; i<to-from; ++i,++it) - replaced.append(*it); - i=0; - it=items->begin(); it += from; - for (; i<n; ++i,++it) - replaced.append(*it); - typename T::ConstIterator f=replaced.begin(); - typename T::Iterator t=items->begin(); t += from; - for (; f != replaced.end(); ++f, ++t) - *t = *f; + int roleIndex = -1; + + if (role.type == ListLayout::Role::Number) { + char *mem = getPropertyMemory(role); + double *value = new (mem) double; + bool changed = *value != d; + *value = d; + if (changed) + roleIndex = role.index; + } + + return roleIndex; +} + +int ListElement::setBoolProperty(const ListLayout::Role &role, bool b) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::Bool) { + char *mem = getPropertyMemory(role); + bool *value = new (mem) bool; + bool changed = *value != b; + *value = b; + if (changed) + roleIndex = role.index; + } + + return roleIndex; +} + +int ListElement::setListProperty(const ListLayout::Role &role, ListModel *m) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::List) { + char *mem = getPropertyMemory(role); + ListModel **value = new (mem) ListModel *; + if (*value) { + (*value)->destroy(); + delete *value; + } + *value = m; + roleIndex = role.index; + } + + return roleIndex; +} + +int ListElement::setQObjectProperty(const ListLayout::Role &role, QObject *o) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::QObject) { + char *mem = getPropertyMemory(role); + QDeclarativeGuard<QObject> *g = reinterpret_cast<QDeclarativeGuard<QObject> *>(mem); + bool existingGuard = false; + for (size_t i=0 ; i < sizeof(QDeclarativeGuard<QObject>) ; ++i) { + if (mem[i] != 0) { + existingGuard = true; + break; + } + } + bool changed; + if (existingGuard) { + changed = g->data() != o; + g->~QDeclarativeGuard(); + } else { + changed = true; + } + new (mem) QDeclarativeGuard<QObject>(o); + if (changed) + roleIndex = role.index; + } + + return roleIndex; +} + +int ListElement::setVariantMapProperty(const ListLayout::Role &role, v8::Handle<v8::Object> o, QV8Engine *eng) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::VariantMap) { + char *mem = getPropertyMemory(role); + if (isMemoryUsed<QVariantMap>(mem)) { + QVariantMap *map = reinterpret_cast<QVariantMap *>(mem); + map->~QMap(); + } + new (mem) QVariantMap(eng->variantMapFromJS(o)); + roleIndex = role.index; + } + + return roleIndex; +} + +int ListElement::setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m) +{ + int roleIndex = -1; + + if (role.type == ListLayout::Role::VariantMap) { + char *mem = getPropertyMemory(role); + if (isMemoryUsed<QVariantMap>(mem)) { + QVariantMap *map = reinterpret_cast<QVariantMap *>(mem); + map->~QMap(); + } + if (m) + new (mem) QVariantMap(*m); + else + new (mem) QVariantMap; + roleIndex = role.index; + } + + return roleIndex; +} + +void ListElement::setStringPropertyFast(const ListLayout::Role &role, const QString &s) +{ + char *mem = getPropertyMemory(role); + new (mem) QString(s); +} + +void ListElement::setDoublePropertyFast(const ListLayout::Role &role, double d) +{ + char *mem = getPropertyMemory(role); + double *value = new (mem) double; + *value = d; +} + +void ListElement::setBoolPropertyFast(const ListLayout::Role &role, bool b) +{ + char *mem = getPropertyMemory(role); + bool *value = new (mem) bool; + *value = b; +} + +void ListElement::setQObjectPropertyFast(const ListLayout::Role &role, QObject *o) +{ + char *mem = getPropertyMemory(role); + new (mem) QDeclarativeGuard<QObject>(o); +} + +void ListElement::setListPropertyFast(const ListLayout::Role &role, ListModel *m) +{ + char *mem = getPropertyMemory(role); + ListModel **value = new (mem) ListModel *; + *value = m; +} + +void ListElement::setVariantMapFast(const ListLayout::Role &role, v8::Handle<v8::Object> o, QV8Engine *eng) +{ + char *mem = getPropertyMemory(role); + QVariantMap *map = new (mem) QVariantMap; + *map = eng->variantMapFromJS(o); +} + +void ListElement::clearProperty(const ListLayout::Role &role) +{ + switch (role.type) { + case ListLayout::Role::String: + setStringProperty(role, QString()); + break; + case ListLayout::Role::Number: + setDoubleProperty(role, 0.0); + break; + case ListLayout::Role::Bool: + setBoolProperty(role, false); + break; + case ListLayout::Role::List: + setListProperty(role, 0); + break; + case ListLayout::Role::QObject: + setQObjectProperty(role, 0); + break; + case ListLayout::Role::VariantMap: + setVariantMapProperty(role, 0); + break; + default: + break; + } +} + +ListElement::ListElement() +{ + m_objectCache = 0; + uid = ListModel::allocateUid(); + next = 0; + qMemSet(data, 0, sizeof(data)); +} + +ListElement::ListElement(int existingUid) +{ + m_objectCache = 0; + uid = existingUid; + next = 0; + qMemSet(data, 0, sizeof(data)); +} + +ListElement::~ListElement() +{ + delete next; +} + +void ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout, QHash<int, ListModel *> *targetModelHash) +{ + for (int i=0 ; i < srcLayout->roleCount() ; ++i) { + const ListLayout::Role &srcRole = srcLayout->getExistingRole(i); + const ListLayout::Role &targetRole = targetLayout->getExistingRole(i); + + switch (srcRole.type) { + case ListLayout::Role::List: + { + ListModel *srcSubModel = src->getListProperty(srcRole); + ListModel *targetSubModel = target->getListProperty(targetRole); + + if (srcSubModel) { + if (targetSubModel == 0) { + targetSubModel = new ListModel(targetRole.subLayout, 0, srcSubModel->getUid()); + target->setListPropertyFast(targetRole, targetSubModel); + } + ListModel::sync(srcSubModel, targetSubModel, targetModelHash); + } + } + break; + case ListLayout::Role::QObject: + { + QObject *object = src->getQObjectProperty(srcRole); + target->setQObjectProperty(targetRole, object); + } + break; + case ListLayout::Role::String: + case ListLayout::Role::Number: + case ListLayout::Role::Bool: + { + QVariant v = src->getProperty(srcRole, 0, 0); + target->setVariantProperty(targetRole, v); + } + case ListLayout::Role::VariantMap: + { + QVariantMap *map = src->getVariantMapProperty(srcRole); + target->setVariantMapProperty(targetRole, map); + } + break; + default: + break; + } + } + +} + +void ListElement::destroy(ListLayout *layout) +{ + if (layout) { + for (int i=0 ; i < layout->roleCount() ; ++i) { + const ListLayout::Role &r = layout->getExistingRole(i); + + switch (r.type) { + case ListLayout::Role::String: + { + QString *string = getStringProperty(r); + if (string) + string->~QString(); + } + break; + case ListLayout::Role::List: + { + ListModel *model = getListProperty(r); + if (model) { + model->destroy(); + delete model; + } + } + break; + case ListLayout::Role::QObject: + { + QDeclarativeGuard<QObject> *guard = getGuardProperty(r); + if (guard) + guard->~QDeclarativeGuard(); + } + break; + case ListLayout::Role::VariantMap: + { + QVariantMap *map = getVariantMapProperty(r); + if (map) + map->~QMap(); + } + break; + default: + // other types don't need explicit cleanup. + break; + } + } + + delete m_objectCache; + } + + if (next) + next->destroy(0); + uid = -1; +} + +int ListElement::setVariantProperty(const ListLayout::Role &role, const QVariant &d) +{ + int roleIndex = -1; + + switch (role.type) { + case ListLayout::Role::Number: + roleIndex = setDoubleProperty(role, d.toDouble()); + break; + case ListLayout::Role::String: + roleIndex = setStringProperty(role, d.toString()); + break; + case ListLayout::Role::Bool: + roleIndex = setBoolProperty(role, d.toBool()); + break; + case ListLayout::Role::List: + roleIndex = setListProperty(role, d.value<ListModel *>()); + break; + default: + break; + } + + return roleIndex; +} + +int ListElement::setJsProperty(const ListLayout::Role &role, v8::Handle<v8::Value> d, QV8Engine *eng) +{ + // Check if this key exists yet + int roleIndex = -1; + + // Add the value now + if (d->IsString()) { + v8::Handle<v8::String> jsString = d->ToString(); + QString qstr; + qstr.resize(jsString->Length()); + jsString->Write(reinterpret_cast<uint16_t*>(qstr.data())); + roleIndex = setStringProperty(role, qstr); + } else if (d->IsNumber()) { + roleIndex = setDoubleProperty(role, d->NumberValue()); + } else if (d->IsArray()) { + ListModel *subModel = new ListModel(role.subLayout, 0, -1); + v8::Handle<v8::Array> subArray = v8::Handle<v8::Array>::Cast(d); + int arrayLength = subArray->Length(); + for (int j=0 ; j < arrayLength ; ++j) { + v8::Handle<v8::Object> subObject = subArray->Get(j)->ToObject(); + subModel->append(subObject, eng); + } + roleIndex = setListProperty(role, subModel); + } else if (d->IsBoolean()) { + roleIndex = setBoolProperty(role, d->BooleanValue()); + } else if (d->IsObject()) { + QV8ObjectResource *r = (QV8ObjectResource *) d->ToObject()->GetExternalResource(); + if (role.type == ListLayout::Role::QObject && r && r->resourceType() == QV8ObjectResource::QObjectType) { + QObject *o = QV8QObjectWrapper::toQObject(r); + roleIndex = setQObjectProperty(role, o); + } else if (role.type == ListLayout::Role::VariantMap) { + roleIndex = setVariantMapProperty(role, d->ToObject(), eng); + } + } else if (d.IsEmpty() || d->IsUndefined() || d->IsNull()) { + clearProperty(role); + } + + return roleIndex; +} + +ModelObject::ModelObject(QDeclarativeListModel *model, int elementIndex) +: m_model(model), m_elementIndex(elementIndex), m_meta(new ModelNodeMetaObject(this)) +{ + updateValues(); + setNodeUpdatesEnabled(true); +} + +void ModelObject::updateValues() +{ + int roleCount = m_model->m_listModel->roleCount(); + for (int i=0 ; i < roleCount ; ++i) { + const ListLayout::Role &role = m_model->m_listModel->getExistingRole(i); + QByteArray name = role.name.toUtf8(); + const QVariant &data = m_model->data(m_elementIndex, i); + setValue(name, data, role.type == ListLayout::Role::List); + } +} + +void ModelObject::updateValues(const QList<int> &roles) +{ + int roleCount = roles.count(); + for (int i=0 ; i < roleCount ; ++i) { + int roleIndex = roles.at(i); + const ListLayout::Role &role = m_model->m_listModel->getExistingRole(roleIndex); + QByteArray name = role.name.toUtf8(); + const QVariant &data = m_model->data(m_elementIndex, roleIndex); + setValue(name, data, role.type == ListLayout::Role::List); + } +} + +ModelNodeMetaObject::ModelNodeMetaObject(ModelObject *object) +: QDeclarativeOpenMetaObject(object), m_enabled(false), m_obj(object) +{ +} + +ModelNodeMetaObject::~ModelNodeMetaObject() +{ +} + +void ModelNodeMetaObject::propertyWritten(int index) +{ + if (!m_enabled) + return; + + QV8Engine *eng = m_obj->m_model->engine(); + + QString propName = QString::fromUtf8(name(index)); + QVariant value = operator[](index); + + v8::HandleScope handle_scope; + v8::Context::Scope scope(eng->context()); + + v8::Handle<v8::Value> v = eng->fromVariant(value); + + int roleIndex = m_obj->m_model->m_listModel->setExistingProperty(m_obj->m_elementIndex, propName, v, eng); + if (roleIndex != -1) { + QList<int> roles; + roles << roleIndex; + m_obj->m_model->emitItemsChanged(m_obj->m_elementIndex, 1, roles); } } @@ -293,114 +1289,112 @@ QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListM handler. You must call sync() or else the changes made to the list from the external thread will not be reflected in the list model in the main thread. - \section1 Restrictions - - If a list model is to be accessed from a WorkerScript, it cannot - contain list-type data. So, the following model cannot be used from a WorkerScript - because of the list contained in the "attributes" property: - - \code - ListModel { - id: fruitModel - ListElement { - name: "Apple" - cost: 2.45 - attributes: [ - ListElement { description: "Core" }, - ListElement { description: "Deciduous" } - ] - } - } - \endcode - - In addition, the WorkerScript cannot add list-type data to the model. - \sa {qmlmodels}{Data Models}, {declarative/threading/threadedlistmodel}{Threaded ListModel example}, QtDeclarative */ +QDeclarativeListModel::QDeclarativeListModel(QObject *parent) +: QListModelInterface(parent) +{ + m_mainThread = true; + m_primary = true; + m_agent = 0; -/* - A ListModel internally uses either a NestedListModel or FlatListModel. - - A NestedListModel can contain lists of ListElements (which - when retrieved from get() is accessible as a list model within the list - model) whereas a FlatListModel cannot. + m_layout = new ListLayout; + m_listModel = new ListModel(m_layout, this, -1); - ListModel uses a NestedListModel to begin with, and if the model is later - used from a WorkerScript, it changes to use a FlatListModel instead. This - is because ModelNode (which abstracts the nested list model data) needs - access to the declarative engine and script engine, which cannot be - safely used from outside of the main thread. -*/ + m_engine = 0; +} -QDeclarativeListModel::QDeclarativeListModel(QObject *parent) -: QListModelInterface(parent), m_agent(0), m_nested(new NestedListModel(this)), m_flat(0) +QDeclarativeListModel::QDeclarativeListModel(const QDeclarativeListModel *owner, ListModel *data, QV8Engine *eng, QObject *parent) +: QListModelInterface(parent) { + m_mainThread = owner->m_mainThread; + m_primary = false; + m_agent = owner->m_agent; + + m_layout = 0; + m_listModel = data; + + m_engine = eng; } -QDeclarativeListModel::QDeclarativeListModel(const QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *parent) -: QListModelInterface(parent), m_agent(0), m_nested(0), m_flat(0) +QDeclarativeListModel::QDeclarativeListModel(QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *agent) +: QListModelInterface(agent) { - m_flat = new FlatListModel(this); - m_flat->m_parentAgent = parent; + m_mainThread = false; + m_primary = true; + m_agent = agent; - if (orig->m_flat) { - m_flat->m_roles = orig->m_flat->m_roles; - m_flat->m_strings = orig->m_flat->m_strings; - m_flat->m_values = orig->m_flat->m_values; + m_layout = new ListLayout(orig->m_layout); + m_listModel = new ListModel(m_layout, this, orig->m_listModel->getUid()); + ListModel::sync(orig->m_listModel, m_listModel, 0); - m_flat->m_nodeData.reserve(m_flat->m_values.count()); - for (int i=0; i<m_flat->m_values.count(); i++) - m_flat->m_nodeData << 0; - } + m_engine = 0; } QDeclarativeListModel::~QDeclarativeListModel() { - if (m_agent) - m_agent->release(); + if (m_primary) { + m_listModel->destroy(); + delete m_listModel; - delete m_nested; - delete m_flat; -} + if (m_mainThread && m_agent) + m_agent->release(); + } -bool QDeclarativeListModel::flatten() -{ - if (m_flat) - return true; + m_listModel = 0; - QList<int> roles = m_nested->roles(); + delete m_layout; + m_layout = 0; +} - QList<QHash<int, QVariant> > values; - bool hasNested = false; - for (int i=0; i<m_nested->count(); i++) { - values.append(m_nested->data(i, roles, &hasNested)); - if (hasNested) - return false; +QV8Engine *QDeclarativeListModel::engine() const +{ + if (m_engine == 0) { + m_engine = QDeclarativeEnginePrivate::getV8Engine(qmlEngine(this)); } - FlatListModel *flat = new FlatListModel(this); - flat->m_values = values; + return m_engine; +} - for (int i=0; i<roles.count(); i++) { - QString s = m_nested->toString(roles[i]); - flat->m_roles.insert(roles[i], s); - flat->m_strings.insert(s, roles[i]); +void QDeclarativeListModel::emitItemsChanged(int index, int count, const QList<int> &roles) +{ + if (m_mainThread) { + emit itemsChanged(index, count, roles); + } else { + m_agent->data.changedChange(this, index, count, roles); } +} - flat->m_nodeData.reserve(flat->m_values.count()); - for (int i=0; i<flat->m_values.count(); i++) - flat->m_nodeData << 0; +void QDeclarativeListModel::emitItemsRemoved(int index, int count) +{ + if (m_mainThread) { + emit itemsRemoved(index, count); + emit countChanged(); + } else { + if (index == 0 && count == this->count()) + m_agent->data.clearChange(this); + m_agent->data.removeChange(this, index, count); + } +} - m_flat = flat; - delete m_nested; - m_nested = 0; - return true; +void QDeclarativeListModel::emitItemsInserted(int index, int count) +{ + if (m_mainThread) { + emit itemsInserted(index, count); + emit countChanged(); + } else { + m_agent->data.insertChange(this, index, count); + } } -bool QDeclarativeListModel::inWorkerThread() const +void QDeclarativeListModel::emitItemsMoved(int from, int to, int n) { - return m_flat && m_flat->m_parentAgent; + if (m_mainThread) { + emit itemsMoved(from, to, n); + } else { + m_agent->data.moveChange(this, from, n, to); + } } QDeclarativeListModelWorkerAgent *QDeclarativeListModel::agent() @@ -408,23 +1402,24 @@ QDeclarativeListModelWorkerAgent *QDeclarativeListModel::agent() if (m_agent) return m_agent; - if (!flatten()) { - qmlInfo(this) << "List contains list-type data and cannot be used from a worker script"; - return 0; - } - m_agent = new QDeclarativeListModelWorkerAgent(this); return m_agent; } QList<int> QDeclarativeListModel::roles() const { - return m_flat ? m_flat->roles() : m_nested->roles(); + QList<int> rolesArray; + + for (int i=0 ; i < m_listModel->roleCount() ; ++i) + rolesArray << i; + + return rolesArray; } QString QDeclarativeListModel::toString(int role) const { - return m_flat ? m_flat->toString(role) : m_nested->toString(role); + const ListLayout::Role &r = m_listModel->getExistingRole(role); + return r.name; } QVariant QDeclarativeListModel::data(int index, int role) const @@ -432,7 +1427,7 @@ QVariant QDeclarativeListModel::data(int index, int role) const if (index >= count() || index < 0) return QVariant(); - return m_flat ? m_flat->data(index, role) : m_nested->data(index, role); + return m_listModel->getProperty(index, role, this, engine()); } /*! @@ -441,7 +1436,7 @@ QVariant QDeclarativeListModel::data(int index, int role) const */ int QDeclarativeListModel::count() const { - return m_flat ? m_flat->count() : m_nested->count(); + return m_listModel->elementCount(); } /*! @@ -454,47 +1449,9 @@ int QDeclarativeListModel::count() const void QDeclarativeListModel::clear() { int cleared = count(); - if (m_flat) - m_flat->clear(); - else - m_nested->clear(); - if (!inWorkerThread()) { - emit itemsRemoved(0, cleared); - emit countChanged(); - } -} - -QDeclarativeListModel *ModelNode::model(const NestedListModel *model) -{ - if (!modelCache) { - modelCache = new QDeclarativeListModel; - QDeclarativeEngine::setContextForObject(modelCache,QDeclarativeEngine::contextForObject(model->m_listModel)); - modelCache->m_nested->_root = this; // ListModel defaults to nestable model - - for (int i=0; i<values.count(); ++i) { - ModelNode *subNode = qvariant_cast<ModelNode *>(values.at(i)); - if (subNode) - subNode->m_model = modelCache->m_nested; - } - } - return modelCache; -} - -ModelObject *ModelNode::object(const NestedListModel *model) -{ - if (!objectCache) { - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(qmlEngine(model->m_listModel)); - objectCache = new ModelObject(this, const_cast<NestedListModel*>(model), ep->v8engine()); - - QHash<QString, ModelNode *>::iterator it; - for (it = properties.begin(); it != properties.end(); ++it) { - objectCache->setValue(it.key().toUtf8(), model->valueForNode(*it)); - } - - objectCache->setNodeUpdatesEnabled(true); - } - return objectCache; + m_listModel->clear(); + emitItemsRemoved(0, cleared); } /*! @@ -511,15 +1468,9 @@ void QDeclarativeListModel::remove(int index) return; } - if (m_flat) - m_flat->remove(index); - else - m_nested->remove(index); + m_listModel->remove(index); - if (!inWorkerThread()) { - emit itemsRemoved(index, 1); - emit countChanged(); - } + emitItemsRemoved(index, 1); } /*! @@ -537,25 +1488,39 @@ void QDeclarativeListModel::remove(int index) \sa set() append() */ -void QDeclarativeListModel::insert(int index, const QDeclarativeV8Handle &handle) + +void QDeclarativeListModel::insert(QDeclarativeV8Function *args) { - v8::Handle<v8::Value> valuemap = handle.toHandle(); + if (args->Length() == 2) { - if (!valuemap->IsObject() || valuemap->IsArray()) { - qmlInfo(this) << tr("insert: value is not an object"); - return; - } + v8::Handle<v8::Value> arg0 = (*args)[0]; + int index = arg0->Int32Value(); - if (index < 0 || index > count()) { - qmlInfo(this) << tr("insert: index %1 out of range").arg(index); - return; - } + if (index < 0 || index > count()) { + qmlInfo(this) << tr("insert: index %1 out of range").arg(index); + return; + } - bool ok = m_flat ? m_flat->insert(index, valuemap) : m_nested->insert(index, valuemap); + v8::Handle<v8::Value> arg1 = (*args)[1]; - if (ok && !inWorkerThread()) { - emit itemsInserted(index, 1); - emit countChanged(); + if (arg1->IsArray()) { + v8::Handle<v8::Array> objectArray = v8::Handle<v8::Array>::Cast(arg1); + int objectArrayLength = objectArray->Length(); + for (int i=0 ; i < objectArrayLength ; ++i) { + v8::Handle<v8::Object> argObject = objectArray->Get(i)->ToObject(); + m_listModel->insert(index+i, argObject, args->engine()); + } + emitItemsInserted(index, objectArrayLength); + } else if (arg1->IsObject()) { + v8::Handle<v8::Object> argObject = arg1->ToObject(); + + m_listModel->insert(index, argObject, args->engine()); + emitItemsInserted(index, 1); + } else { + qmlInfo(this) << tr("insert: value is not an object"); + } + } else { + qmlInfo(this) << tr("insert: value is not an object"); } } @@ -582,25 +1547,8 @@ void QDeclarativeListModel::move(int from, int to, int n) return; } - int origfrom = from; - int origto = to; - int orign = n; - if (from > to) { - // Only move forwards - flip if backwards moving - int tfrom = from; - int tto = to; - from = tto; - to = tto+n; - n = tfrom-tto; - } - - if (m_flat) - m_flat->move(from, to, n); - else - m_nested->move(from, to, n); - - if (!inWorkerThread()) - emit itemsMoved(origfrom, origto, orign); + m_listModel->move(from, to, n); + emitItemsMoved(from, to, n); } /*! @@ -615,16 +1563,32 @@ void QDeclarativeListModel::move(int from, int to, int n) \sa set() remove() */ -void QDeclarativeListModel::append(const QDeclarativeV8Handle &handle) -{ - v8::Handle<v8::Value> valuemap = handle.toHandle(); +void QDeclarativeListModel::append(QDeclarativeV8Function *args) +{ + if (args->Length() == 1) { + v8::Handle<v8::Value> arg = (*args)[0]; + + if (arg->IsArray()) { + v8::Handle<v8::Array> objectArray = v8::Handle<v8::Array>::Cast(arg); + int objectArrayLength = objectArray->Length(); + int index = m_listModel->elementCount(); + for (int i=0 ; i < objectArrayLength ; ++i) { + v8::Handle<v8::Object> argObject = objectArray->Get(i)->ToObject(); + m_listModel->append(argObject, args->engine()); + } + emitItemsInserted(index, objectArrayLength); + } else if (arg->IsObject()) { + v8::Handle<v8::Object> argObject = arg->ToObject(); - if (!valuemap->IsObject() || valuemap->IsArray()) { + int index = m_listModel->append(argObject, args->engine()); + emitItemsInserted(index, 1); + + } else { + qmlInfo(this) << tr("append: value is not an object"); + } + } else { qmlInfo(this) << tr("append: value is not an object"); - return; } - - insert(count(), handle); } /*! @@ -660,8 +1624,16 @@ void QDeclarativeListModel::append(const QDeclarativeV8Handle &handle) */ QDeclarativeV8Handle QDeclarativeListModel::get(int index) const { - // the internal flat/nested class checks for bad index - return QDeclarativeV8Handle::fromHandle(m_flat ? m_flat->get(index) : m_nested->get(index)); + v8::Handle<v8::Value> result = v8::Undefined(); + + if (index >= 0 && index < m_listModel->elementCount()) { + QV8Engine *v8engine = engine(); + + ModelObject *object = m_listModel->getOrCreateModelObject(const_cast<QDeclarativeListModel *>(this), index); + result = v8engine->newQObject(object); + } + + return QDeclarativeV8Handle::fromHandle(result); } /*! @@ -680,15 +1652,7 @@ QDeclarativeV8Handle QDeclarativeListModel::get(int index) const \sa append() */ -void QDeclarativeListModel::set(int index, const QDeclarativeV8Handle &valuemap) -{ - QList<int> roles; - set(index, valuemap, &roles); - if (!roles.isEmpty() && !inWorkerThread()) - emit itemsChanged(index, 1, roles); -} - -void QDeclarativeListModel::set(int index, const QDeclarativeV8Handle &handle, QList<int> *roles) +void QDeclarativeListModel::set(int index, const QDeclarativeV8Handle &handle) { v8::Handle<v8::Value> valuemap = handle.toHandle(); @@ -701,13 +1665,18 @@ void QDeclarativeListModel::set(int index, const QDeclarativeV8Handle &handle, Q return; } + v8::Handle<v8::Object> object = valuemap->ToObject(); + if (index == count()) { - append(handle); + m_listModel->insert(index, object, engine()); + emitItemsInserted(index, 1); } else { - if (m_flat) - m_flat->set(index, valuemap, roles); - else - m_nested->set(index, valuemap, roles); + + QList<int> roles; + m_listModel->set(index, object, &roles, engine()); + + if (roles.count()) + emitItemsChanged(index, 1, roles); } } @@ -726,23 +1695,19 @@ void QDeclarativeListModel::set(int index, const QDeclarativeV8Handle &handle, Q */ void QDeclarativeListModel::setProperty(int index, const QString& property, const QVariant& value) { - QList<int> roles; - setProperty(index, property, value, &roles); - if (!roles.isEmpty() && !inWorkerThread()) - emit itemsChanged(index, 1, roles); -} - -void QDeclarativeListModel::setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles) -{ if (count() == 0 || index >= count() || index < 0) { qmlInfo(this) << tr("set: index %1 out of range").arg(index); return; } - if (m_flat) - m_flat->setProperty(index, property, value, roles); - else - m_nested->setProperty(index, property, value, roles); + int roleIndex = m_listModel->setOrCreateProperty(index, property, value); + if (roleIndex != -1) { + + QList<int> roles; + roles << roleIndex; + + emitItemsChanged(index, 1, roles); + } } /*! @@ -931,78 +1896,93 @@ void QDeclarativeListModelParser::setCustomData(QObject *obj, const QByteArray & { QDeclarativeListModel *rv = static_cast<QDeclarativeListModel *>(obj); - ModelNode *root = new ModelNode(rv->m_nested); - rv->m_nested->m_ownsRoot = true; - rv->m_nested->_root = root; - QStack<ModelNode *> nodes; - nodes << root; - - bool processingSet = false; + QV8Engine *engine = QDeclarativeEnginePrivate::getV8Engine(qmlEngine(rv)); + rv->m_engine = engine; const ListModelData *lmd = (const ListModelData *)d.constData(); const char *data = ((const char *)lmd) + lmd->dataOffset; + QStack<DataStackElement> stack; + for (int ii = 0; ii < lmd->instrCount; ++ii) { const ListInstruction &instr = lmd->instructions()[ii]; switch(instr.type) { case ListInstruction::Push: { - ModelNode *n = nodes.top(); - ModelNode *n2 = new ModelNode(rv->m_nested); - n->values << QVariant::fromValue(n2); - nodes.push(n2); - if (processingSet) - n->isArray = true; + ListModel *subModel = 0; + + if (stack.count() == 0) { + subModel = rv->m_listModel; + } else { + const DataStackElement &e0 = stack.at(stack.size() - 1); + DataStackElement &e1 = stack[stack.size() - 2]; + + const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name); + if (role.type == ListLayout::Role::List) { + subModel = e1.model->getListProperty(e1.elementIndex, role); + + if (subModel == 0) { + subModel = new ListModel(role.subLayout, 0, -1); + QVariant vModel = QVariant::fromValue(subModel); + e1.model->setOrCreateProperty(e1.elementIndex, e0.name, vModel); + } + } + } + + DataStackElement e; + e.model = subModel; + e.elementIndex = subModel ? subModel->appendElement() : -1; + stack.push(e); } break; case ListInstruction::Pop: - nodes.pop(); + stack.pop(); break; case ListInstruction::Value: { - ModelNode *n = nodes.top(); + const DataStackElement &e0 = stack.at(stack.size() - 1); + DataStackElement &e1 = stack[stack.size() - 2]; + + QString name = e0.name; + QVariant value; + switch (QDeclarativeScript::Variant::Type(data[instr.dataIdx])) { - case QDeclarativeScript::Variant::Invalid: - n->isArray = true; - break; - case QDeclarativeScript::Variant::Boolean: - n->values.append(bool(data[1 + instr.dataIdx])); - break; - case QDeclarativeScript::Variant::Number: - n->values.append(QByteArray(data + 1 + instr.dataIdx).toDouble()); - break; - case QDeclarativeScript::Variant::String: - n->values.append(QString::fromUtf8(data + 1 + instr.dataIdx)); - break; - default: - Q_ASSERT("Format error in ListInstruction"); + case QDeclarativeScript::Variant::Invalid: + { + const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name); + ListModel *emptyModel = new ListModel(role.subLayout, 0, -1); + value = QVariant::fromValue(emptyModel); + } + break; + case QDeclarativeScript::Variant::Boolean: + value = bool(data[1 + instr.dataIdx]); + break; + case QDeclarativeScript::Variant::Number: + value = QByteArray(data + 1 + instr.dataIdx).toDouble(); + break; + case QDeclarativeScript::Variant::String: + value = QString::fromUtf8(data + 1 + instr.dataIdx); + break; + default: + Q_ASSERT("Format error in ListInstruction"); } - processingSet = false; + e1.model->setOrCreateProperty(e1.elementIndex, name, value); } break; case ListInstruction::Set: { - ModelNode *n = nodes.top(); - ModelNode *n2 = new ModelNode(rv->m_nested); - n->properties.insert(QString::fromUtf8(data + instr.dataIdx), n2); - nodes.push(n2); - processingSet = true; + DataStackElement e; + e.name = QString::fromUtf8(data + instr.dataIdx); + stack.push(e); } break; } } - - ModelNode *rootNode = rv->m_nested->_root; - for (int i=0; i<rootNode->values.count(); ++i) { - ModelNode *node = qvariant_cast<ModelNode *>(rootNode->values[i]); - node->listIndex = i; - node->updateListIndexes(); - } } bool QDeclarativeListModelParser::definesEmptyList(const QString &s) @@ -1060,691 +2040,4 @@ bool QDeclarativeListModelParser::definesEmptyList(const QString &s) \sa ListModel */ -FlatListModel::FlatListModel(QDeclarativeListModel *base) -: m_engine(0), m_listModel(base), m_parentAgent(0) -{ -} - -FlatListModel::~FlatListModel() -{ - qDeleteAll(m_nodeData); -} - -QVariant FlatListModel::data(int index, int role) const -{ - Q_ASSERT(index >= 0 && index < m_values.count()); - if (m_values[index].contains(role)) - return m_values[index][role]; - return QVariant(); -} - -QList<int> FlatListModel::roles() const -{ - return m_roles.keys(); -} - -QString FlatListModel::toString(int role) const -{ - if (m_roles.contains(role)) - return m_roles[role]; - return QString(); -} - -int FlatListModel::count() const -{ - return m_values.count(); -} - -void FlatListModel::clear() -{ - m_values.clear(); - - qDeleteAll(m_nodeData); - m_nodeData.clear(); -} - -void FlatListModel::remove(int index) -{ - m_values.removeAt(index); - removedNode(index); -} - -bool FlatListModel::insert(int index, v8::Handle<v8::Value> value) -{ - Q_ASSERT(index >= 0 && index <= m_values.count()); - - QHash<int, QVariant> row; - if (!addValue(value, &row, 0)) - return false; - - m_values.insert(index, row); - insertedNode(index); - - return true; -} - -QV8Engine *FlatListModel::engine() const -{ - return m_engine?m_engine:QDeclarativeEnginePrivate::getV8Engine(qmlEngine(m_listModel)); -} - -QV8Engine *NestedListModel::engine() const -{ - return QDeclarativeEnginePrivate::getV8Engine(qmlEngine(m_listModel)); -} - -v8::Handle<v8::Value> FlatListModel::get(int index) const -{ - QV8Engine *v8engine = engine(); - - if (!v8engine) - return v8::Undefined(); - - if (index < 0 || index >= m_values.count()) - return v8::Undefined(); - - FlatListModel *that = const_cast<FlatListModel*>(this); - - FlatNodeData *data = m_nodeData.value(index); - if (!data) { - data = new FlatNodeData(index); - that->m_nodeData.replace(index, data); - } - - v8::Local<v8::Object> rv = QDeclarativeListModelV8Data::create(v8engine); - QV8ListModelResource *r = new QV8ListModelResource(that, data, v8engine); - rv->SetExternalResource(r); - return rv; -} - -void FlatListModel::set(int index, v8::Handle<v8::Value> value, QList<int> *roles) -{ - Q_ASSERT(index >= 0 && index < m_values.count()); - - QHash<int, QVariant> row = m_values[index]; - if (addValue(value, &row, roles)) - m_values[index] = row; -} - -void FlatListModel::setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles) -{ - Q_ASSERT(index >= 0 && index < m_values.count()); - - QHash<QString, int>::Iterator iter = m_strings.find(property); - int role; - if (iter == m_strings.end()) { - role = m_roles.count(); - m_roles.insert(role, property); - m_strings.insert(property, role); - } else { - role = iter.value(); - } - - if (m_values[index][role] != value) { - roles->append(role); - m_values[index][role] = value; - } -} - -void FlatListModel::move(int from, int to, int n) -{ - qdeclarativelistmodel_move<QList<QHash<int, QVariant> > >(from, to, n, &m_values); - moveNodes(from, to, n); -} - -bool FlatListModel::addValue(v8::Handle<v8::Value> value, QHash<int, QVariant> *row, QList<int> *roles) -{ - if (!value->IsObject()) - return false; - - v8::Local<v8::Array> properties = engine()->getOwnPropertyNames(value->ToObject()); - uint32_t length = properties->Length(); - for (uint32_t ii = 0; ii < length; ++ii) { - // XXX TryCatch? - v8::Handle<v8::Value> property = properties->Get(ii); - v8::Handle<v8::Value> jsv = value->ToObject()->Get(property); - - if (!jsv->IsRegExp() && !jsv->IsDate() && jsv->IsObject() && !engine()->isVariant(jsv)) { - qmlInfo(m_listModel) << "Cannot add list-type data when modifying or after modification from a worker script"; - return false; - } - - QString name = engine()->toString(property); - QVariant v = engine()->toVariant(jsv, -1); - - QHash<QString, int>::Iterator iter = m_strings.find(name); - if (iter == m_strings.end()) { - int role = m_roles.count(); - m_roles.insert(role, name); - iter = m_strings.insert(name, role); - if (roles) - roles->append(role); - } else { - int role = iter.value(); - if (roles && row->contains(role) && row->value(role) != v) - roles->append(role); - } - row->insert(*iter, v); - } - return true; -} - -void FlatListModel::insertedNode(int index) -{ - if (index >= 0 && index <= m_values.count()) { - m_nodeData.insert(index, 0); - - for (int i=index + 1; i<m_nodeData.count(); i++) { - if (m_nodeData[i]) - m_nodeData[i]->index = i; - } - } -} - -void FlatListModel::removedNode(int index) -{ - if (index >= 0 && index < m_nodeData.count()) { - delete m_nodeData.takeAt(index); - - for (int i=index; i<m_nodeData.count(); i++) { - if (m_nodeData[i]) - m_nodeData[i]->index = i; - } - } -} - -void FlatListModel::moveNodes(int from, int to, int n) -{ - if (!m_listModel->canMove(from, to, n)) - return; - - qdeclarativelistmodel_move<QList<FlatNodeData *> >(from, to, n, &m_nodeData); - - for (int i=from; i<from + (to-from); i++) { - if (m_nodeData[i]) - m_nodeData[i]->index = i; - } -} - -FlatNodeData::~FlatNodeData() -{ - for (QSet<QV8ListModelResource *>::Iterator iter = objects.begin(); iter != objects.end(); ++iter) { - QV8ListModelResource *data = *iter; - data->nodeData = 0; - } -} - -void FlatNodeData::addData(QV8ListModelResource *data) -{ - objects.insert(data); -} - -void FlatNodeData::removeData(QV8ListModelResource *data) -{ - objects.remove(data); -} - -NestedListModel::NestedListModel(QDeclarativeListModel *base) -: _root(0), m_ownsRoot(false), m_listModel(base), _rolesOk(false) -{ -} - -NestedListModel::~NestedListModel() -{ - if (m_ownsRoot) - delete _root; -} - -QVariant NestedListModel::valueForNode(ModelNode *node, bool *hasNested) const -{ - QObject *rv = 0; - if (hasNested) - *hasNested = false; - - if (node->isArray) { - // List - rv = node->model(this); - if (hasNested) - *hasNested = true; - } else { - if (!node->properties.isEmpty()) { - // Object - rv = node->object(this); - } else if (node->values.count() == 0) { - // Invalid - return QVariant(); - } else if (node->values.count() == 1) { - // Value - QVariant &var = node->values[0]; - ModelNode *valueNode = qvariant_cast<ModelNode *>(var); - if (valueNode) { - if (!valueNode->properties.isEmpty()) - rv = valueNode->object(this); - else - rv = valueNode->model(this); - } else { - return var; - } - } - } - - if (rv) { - return QVariant::fromValue(rv); - } else { - return QVariant(); - } -} - -QHash<int,QVariant> NestedListModel::data(int index, const QList<int> &roles, bool *hasNested) const -{ - Q_ASSERT(_root && index >= 0 && index < _root->values.count()); - checkRoles(); - QHash<int, QVariant> rv; - - ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index)); - if (!node) - return rv; - - for (int ii = 0; ii < roles.count(); ++ii) { - const QString &roleString = roleStrings.at(roles.at(ii)); - - QHash<QString, ModelNode *>::ConstIterator iter = node->properties.find(roleString); - if (iter != node->properties.end()) { - ModelNode *row = *iter; - rv.insert(roles.at(ii), valueForNode(row, hasNested)); - } - } - - return rv; -} - -QVariant NestedListModel::data(int index, int role) const -{ - Q_ASSERT(_root && index >= 0 && index < _root->values.count()); - checkRoles(); - QVariant rv; - if (roleStrings.count() < role) - return rv; - - ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index)); - if (!node) - return rv; - - const QString &roleString = roleStrings.at(role); - - QHash<QString, ModelNode *>::ConstIterator iter = node->properties.find(roleString); - if (iter != node->properties.end()) { - ModelNode *row = *iter; - rv = valueForNode(row); - } - - return rv; -} - -int NestedListModel::count() const -{ - if (!_root) return 0; - return _root->values.count(); -} - -void NestedListModel::clear() -{ - if (_root) - _root->clear(); -} - -void NestedListModel::remove(int index) -{ - if (!_root) - return; - ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index)); - _root->values.removeAt(index); - for (int i = 0; i < _root->values.count(); ++i) { - ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(i)); - if (node) - node->listIndex = i; - } - if (node) - delete node; -} - -bool NestedListModel::insert(int index, v8::Handle<v8::Value> valuemap) -{ - if (!_root) { - _root = new ModelNode(this); - m_ownsRoot = true; - } - - ModelNode *mn = new ModelNode(this); - mn->listIndex = index; - mn->setObjectValue(valuemap); - _root->values.insert(index,QVariant::fromValue(mn)); - for (int i = index + 1; i < _root->values.count(); ++i) { - ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(i)); - if (node) - node->listIndex = i; - } - return true; -} - -void NestedListModel::move(int from, int to, int n) -{ - if (!_root) - return; - qdeclarativelistmodel_move<QVariantList>(from, to, n, &_root->values); - for (int i = qMin(from, to), end = qMin(_root->values.count(), qMax(from, to) + n); i < end; ++i) { - ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(i)); - if (node) - node->listIndex = i; - } -} - -v8::Handle<v8::Value> NestedListModel::get(int index) const -{ - QDeclarativeEngine *eng = qmlEngine(m_listModel); - if (!eng) - return v8::Undefined();; - - if (index < 0 || index >= count()) - return v8::Undefined(); - - ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index)); - if (!node) - return v8::Undefined();; - - return QDeclarativeEnginePrivate::get(eng)->v8engine()->newQObject(node->object(this)); -} - -void NestedListModel::set(int index, v8::Handle<v8::Value> valuemap, QList<int> *roles) -{ - Q_ASSERT(index >=0 && index < count()); - - if (!valuemap->IsObject()) - return; - - ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index)); - bool emitItemsChanged = node->setObjectValue(valuemap); - if (!emitItemsChanged) - return; - - QV8Engine *v8engine = engine(); - - v8::Local<v8::Array> properties = v8engine->getOwnPropertyNames(valuemap->ToObject()); - uint32_t length = properties->Length(); - for (uint32_t ii = 0; ii < length; ++ii) { - // XXX TryCatch? - v8::Handle<v8::Value> property = properties->Get(ii); - QString name = v8engine->toString(property); - - int r = roleStrings.indexOf(name); - if (r < 0) { - r = roleStrings.count(); - roleStrings << name; - } - roles->append(r); - } -} - -void NestedListModel::setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles) -{ - Q_ASSERT(index >=0 && index < count()); - - ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(index)); - bool emitItemsChanged = node->setProperty(property, value); - if (!emitItemsChanged) - return; - - int r = roleStrings.indexOf(property); - if (r < 0) { - r = roleStrings.count(); - roleStrings << property; - } - roles->append(r); -} - -void NestedListModel::checkRoles() const -{ - if (_rolesOk || !_root) - return; - - for (int i = 0; i<_root->values.count(); ++i) { - ModelNode *node = qvariant_cast<ModelNode *>(_root->values.at(i)); - if (node) { - foreach (const QString &role, node->properties.keys()) { - if (!roleStrings.contains(role)) - roleStrings.append(role); - } - } - } - - _rolesOk = true; -} - -QList<int> NestedListModel::roles() const -{ - checkRoles(); - QList<int> rv; - for (int ii = 0; ii < roleStrings.count(); ++ii) - rv << ii; - return rv; -} - -QString NestedListModel::toString(int role) const -{ - checkRoles(); - if (role < roleStrings.count()) - return roleStrings.at(role); - else - return QString(); -} - - -ModelNode::ModelNode(NestedListModel *model) -: modelCache(0), objectCache(0), isArray(false), m_model(model), listIndex(-1) -{ -} - -ModelNode::~ModelNode() -{ - clear(); - if (modelCache) { modelCache->m_nested->_root = 0/* ==this */; delete modelCache; modelCache = 0; } - if (objectCache) { delete objectCache; objectCache = 0; } -} - -void ModelNode::clear() -{ - ModelNode *node; - for (int ii = 0; ii < values.count(); ++ii) { - node = qvariant_cast<ModelNode *>(values.at(ii)); - if (node) { delete node; node = 0; } - } - values.clear(); - - qDeleteAll(properties.values()); - properties.clear(); -} - -bool ModelNode::setObjectValue(v8::Handle<v8::Value> valuemap, bool writeToCache) -{ - if (!valuemap->IsObject()) - return false; - - bool emitItemsChanged = false; - - QV8Engine *v8engine = m_model->engine(); - - v8::Local<v8::Array> propertyNames = v8engine->getOwnPropertyNames(valuemap->ToObject()); - uint32_t length = propertyNames->Length(); - - for (uint32_t ii = 0; ii < length; ++ii) { - // XXX TryCatch? - v8::Handle<v8::Value> property = propertyNames->Get(ii); - v8::Handle<v8::Value> v = valuemap->ToObject()->Get(property); - - QString name = v8engine->toString(property); - ModelNode *prev = properties.value(name); - ModelNode *value = new ModelNode(m_model); - - if (v->IsArray()) { - value->isArray = true; - value->setListValue(v); - if (writeToCache && objectCache) - objectCache->setValue(name.toUtf8(), QVariant::fromValue(value->model(m_model))); - emitItemsChanged = true; // for now, too inefficient to check whether list and sublists have changed - } else { - value->values << v8engine->toVariant(v, -1); - if (writeToCache && objectCache) - objectCache->setValue(name.toUtf8(), value->values.last()); - if (!emitItemsChanged && prev && prev->values.count() == 1 - && prev->values[0] != value->values.last()) { - emitItemsChanged = true; - } - } - if (properties.contains(name)) - delete properties[name]; - properties.insert(name, value); - } - return emitItemsChanged; -} - -void ModelNode::setListValue(v8::Handle<v8::Value> valuelist) -{ - Q_ASSERT(valuelist->IsArray()); - values.clear(); - - QV8Engine *engine = m_model->engine(); - - v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(valuelist); - uint32_t length = array->Length(); - for (uint32_t ii = 0; ii < length; ++ii) { - ModelNode *value = new ModelNode(m_model); - - // XXX TryCatch? - v8::Handle<v8::Value> v = array->Get(ii); - - if (v->IsArray()) { - value->isArray = true; - value->setListValue(v); - } else if (v->IsObject()) { - value->listIndex = ii; - value->setObjectValue(v); - } else { - value->listIndex = ii; - value->values << engine->toVariant(v, -1); - } - - values.append(QVariant::fromValue(value)); - } -} - -bool ModelNode::setProperty(const QString& prop, const QVariant& val) { - QHash<QString, ModelNode *>::const_iterator it = properties.find(prop); - bool emitItemsChanged = false; - if (it != properties.end()) { - if (val != (*it)->values[0]) - emitItemsChanged = true; - (*it)->values[0] = val; - } else { - ModelNode *n = new ModelNode(m_model); - n->values << val; - properties.insert(prop,n); - } - if (objectCache) - objectCache->setValue(prop.toUtf8(), val); - return emitItemsChanged; -} - -void ModelNode::updateListIndexes() -{ - for (QHash<QString, ModelNode *>::ConstIterator iter = properties.begin(); iter != properties.end(); ++iter) { - ModelNode *node = iter.value(); - if (node->isArray) { - for (int i=0; i<node->values.count(); ++i) { - ModelNode *subNode = qvariant_cast<ModelNode *>(node->values.at(i)); - if (subNode) - subNode->listIndex = i; - } - } - node->updateListIndexes(); - } -} - -/* - Need to call this to emit itemsChanged() for modifications outside of set() - and setProperty(), i.e. if an item returned from get() is modified -*/ -void ModelNode::changedProperty(const QString &name) const -{ - if (listIndex < 0) - return; - - m_model->checkRoles(); - QList<int> roles; - int role = m_model->roleStrings.indexOf(name); - if (role < 0) - roles = m_model->roles(); - else - roles << role; - emit m_model->m_listModel->itemsChanged(listIndex, 1, roles); -} - -void ModelNode::dump(ModelNode *node, int ind) -{ - QByteArray indentBa(ind * 4, ' '); - const char *indent = indentBa.constData(); - - for (int ii = 0; ii < node->values.count(); ++ii) { - ModelNode *subNode = qvariant_cast<ModelNode *>(node->values.at(ii)); - if (subNode) { - qWarning().nospace() << indent << "Sub-node " << ii; - dump(subNode, ind + 1); - } else { - qWarning().nospace() << indent << "Sub-node " << ii << ": " << node->values.at(ii).toString(); - } - } - - for (QHash<QString, ModelNode *>::ConstIterator iter = node->properties.begin(); iter != node->properties.end(); ++iter) { - qWarning().nospace() << indent << "Property " << iter.key() << ':'; - dump(iter.value(), ind + 1); - } -} - -ModelObject::ModelObject(ModelNode *node, NestedListModel *model, QV8Engine *eng) -: m_model(model), m_node(node), m_meta(new ModelNodeMetaObject(eng, this)) -{ -} - -void ModelObject::setValue(const QByteArray &name, const QVariant &val) -{ - m_meta->setValue(name, val); - //setProperty(name.constData(), val); -} - -void ModelObject::setNodeUpdatesEnabled(bool enable) -{ - m_meta->m_enabled = enable; -} - -ModelNodeMetaObject::ModelNodeMetaObject(QV8Engine *eng, ModelObject *object) -: QDeclarativeOpenMetaObject(object), m_enabled(false), m_engine(eng), m_obj(object) -{ -} - -void ModelNodeMetaObject::propertyWritten(int index) -{ - if (!m_enabled) - return; - - QString propName = QString::fromUtf8(name(index)); - QVariant value = operator[](index); - - v8::HandleScope handle_scope; - v8::Context::Scope scope(m_engine->context()); - v8::Local<v8::Object> object = v8::Object::New(); - object->Set(m_engine->toString(propName), m_engine->variantWrapper()->newVariant(value)); - bool changed = m_obj->m_node->setObjectValue(object, false); - if (changed) - m_obj->m_node->changedProperty(propName); -} - QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativelistmodel_p.h b/src/declarative/util/qdeclarativelistmodel_p.h index ea83ae1e7e..05cc8c218f 100644 --- a/src/declarative/util/qdeclarativelistmodel_p.h +++ b/src/declarative/util/qdeclarativelistmodel_p.h @@ -53,6 +53,7 @@ #include <private/qlistmodelinterface_p.h> #include <private/qv8engine_p.h> +#include <private/qpodvector_p.h> QT_BEGIN_HEADER @@ -60,10 +61,10 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class FlatListModel; -class NestedListModel; class QDeclarativeListModelWorkerAgent; -struct ModelNode; +class ListModel; +class ListLayout; + class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeListModel : public QListModelInterface { Q_OBJECT @@ -80,8 +81,8 @@ public: Q_INVOKABLE void clear(); Q_INVOKABLE void remove(int index); - Q_INVOKABLE void append(const QDeclarativeV8Handle &); - Q_INVOKABLE void insert(int index, const QDeclarativeV8Handle &); + Q_INVOKABLE void append(QDeclarativeV8Function *args); + Q_INVOKABLE void insert(QDeclarativeV8Function *args); Q_INVOKABLE QDeclarativeV8Handle get(int index) const; Q_INVOKABLE void set(int index, const QDeclarativeV8Handle &); Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value); @@ -96,24 +97,31 @@ Q_SIGNALS: private: friend class QDeclarativeListModelParser; friend class QDeclarativeListModelWorkerAgent; - friend class FlatListModel; - friend class QDeclarativeListModelV8Data; - friend struct ModelNode; + friend class ModelObject; + friend class ModelNodeMetaObject; + friend class ListModel; + friend class ListElement; // Constructs a flat list model for a worker agent - QDeclarativeListModel(const QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *parent); - - void set(int index, const QDeclarativeV8Handle &, QList<int> *roles); - void setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles); + QDeclarativeListModel(QDeclarativeListModel *orig, QDeclarativeListModelWorkerAgent *agent); + QDeclarativeListModel(const QDeclarativeListModel *owner, ListModel *data, QV8Engine *eng, QObject *parent=0); - bool flatten(); - bool inWorkerThread() const; + QV8Engine *engine() const; inline bool canMove(int from, int to, int n) const { return !(from+n > count() || to+n > count() || from < 0 || to < 0 || n < 0); } + ListLayout *m_layout; + ListModel *m_listModel; + QDeclarativeListModelWorkerAgent *m_agent; - NestedListModel *m_nested; - FlatListModel *m_flat; + bool m_mainThread; + bool m_primary; + mutable QV8Engine *m_engine; + + void emitItemsChanged(int index, int count, const QList<int> &roles); + void emitItemsRemoved(int index, int count); + void emitItemsInserted(int index, int count); + void emitItemsMoved(int from, int to, int n); }; // ### FIXME @@ -146,8 +154,16 @@ private: bool definesEmptyList(const QString &); QString listElementTypeName; -}; + struct DataStackElement + { + DataStackElement() : model(0), elementIndex(0) {} + + QString name; + ListModel *model; + int elementIndex; + }; +}; QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativelistmodel_p_p.h b/src/declarative/util/qdeclarativelistmodel_p_p.h index 99cab4cab9..89e8e5e090 100644 --- a/src/declarative/util/qdeclarativelistmodel_p_p.h +++ b/src/declarative/util/qdeclarativelistmodel_p_p.h @@ -64,189 +64,261 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QDeclarativeOpenMetaObject; -class QDeclarativeListModelWorkerAgent; -struct ModelNode; -class FlatNodeData; +class ModelObject; -class FlatListModel +class ModelNodeMetaObject : public QDeclarativeOpenMetaObject { public: - FlatListModel(QDeclarativeListModel *base); - ~FlatListModel(); + ModelNodeMetaObject(ModelObject *object); + ~ModelNodeMetaObject(); - QVariant data(int index, int role) const; + bool m_enabled; - QList<int> roles() const; - QString toString(int role) const; +protected: + void propertyWritten(int index); - int count() const; - void clear(); - void remove(int index); - bool insert(int index, v8::Handle<v8::Value>); - v8::Handle<v8::Value> get(int index) const; - void set(int index, v8::Handle<v8::Value>, QList<int> *roles); - void setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles); - void move(int from, int to, int count); +private: -private: - friend class QDeclarativeListModelWorkerAgent; - friend class QDeclarativeListModel; - friend class QDeclarativeListModelV8Data; - friend class FlatNodeData; - - bool addValue(v8::Handle<v8::Value> value, QHash<int, QVariant> *row, QList<int> *roles); - void insertedNode(int index); - void removedNode(int index); - void moveNodes(int from, int to, int n); - - QV8Engine *engine() const; - QV8Engine *m_engine; - QHash<int, QString> m_roles; - QHash<QString, int> m_strings; - QList<QHash<int, QVariant> > m_values; - QDeclarativeListModel *m_listModel; - - QList<FlatNodeData *> m_nodeData; - QDeclarativeListModelWorkerAgent *m_parentAgent; + ModelObject *m_obj; }; -/* - FlatNodeData and FlatNodeObjectData allow objects returned by get() to still - point to the correct list index if move(), insert() or remove() are called. -*/ -class QV8ListModelResource; -class FlatNodeData +class ModelObject : public QObject { + Q_OBJECT public: - FlatNodeData(int i) - : index(i) {} - - ~FlatNodeData(); - - void addData(QV8ListModelResource *data); - void removeData(QV8ListModelResource *data); - - int index; + ModelObject(QDeclarativeListModel *model, int elementIndex); + + void setValue(const QByteArray &name, const QVariant &val, bool force) + { + if (force) { + QVariant existingValue = m_meta->value(name); + if (existingValue.isValid()) { + (*m_meta)[name] = QVariant(); + } + } + m_meta->setValue(name, val); + } + + void setNodeUpdatesEnabled(bool enable) + { + m_meta->m_enabled = enable; + } + + void updateValues(); + void updateValues(const QList<int> &roles); + + QDeclarativeListModel *m_model; + int m_elementIndex; private: - QSet<QV8ListModelResource*> objects; + ModelNodeMetaObject *m_meta; }; -class QV8ListModelResource : public QV8ObjectResource +class ListLayout { - V8_RESOURCE_TYPE(ListModelType); public: - QV8ListModelResource(FlatListModel *model, FlatNodeData *data, QV8Engine *engine); - ~QV8ListModelResource(); + ListLayout() : currentBlock(0), currentBlockOffset(0) {} + ListLayout(const ListLayout *other); + ~ListLayout(); - FlatListModel *model; - FlatNodeData *nodeData; -}; + class Role + { + public: -class NestedListModel -{ -public: - NestedListModel(QDeclarativeListModel *base); - ~NestedListModel(); + Role() : type(Invalid), blockIndex(-1), blockOffset(-1), index(-1), subLayout(0) {} + explicit Role(const Role *other); + ~Role(); - QHash<int,QVariant> data(int index, const QList<int> &roles, bool *hasNested = 0) const; - QVariant data(int index, int role) const; + // This enum must be kept in sync with the roleTypeNames variable in qdeclarativelistmodel.cpp + enum DataType + { + Invalid = -1, - QList<int> roles() const; - QString toString(int role) const; + String, + Number, + Bool, + List, + QObject, + VariantMap, - int count() const; - void clear(); - void remove(int index); - bool insert(int index, v8::Handle<v8::Value>); - v8::Handle<v8::Value> get(int index) const; - void set(int index, v8::Handle<v8::Value>, QList<int> *roles); - void setProperty(int index, const QString& property, const QVariant& value, QList<int> *roles); - void move(int from, int to, int count); + MaxDataType + }; + + QString name; + DataType type; + int blockIndex; + int blockOffset; + int index; + ListLayout *subLayout; + }; + + const Role *getRoleOrCreate(const QString &key, const QVariant &data); + const Role &getRoleOrCreate(v8::Handle<v8::String> key, Role::DataType type); + const Role &getRoleOrCreate(const QString &key, Role::DataType type); + + const Role &getExistingRole(int index) { return *roles.at(index); } + const Role *getExistingRole(const QString &key); + const Role *getExistingRole(v8::Handle<v8::String> key); - QVariant valueForNode(ModelNode *, bool *hasNested = 0) const; - void checkRoles() const; + int roleCount() const { return roles.count(); } - ModelNode *_root; - bool m_ownsRoot; - QDeclarativeListModel *m_listModel; + static void sync(ListLayout *src, ListLayout *target); - QV8Engine *engine() const; private: - friend struct ModelNode; - mutable QStringList roleStrings; - mutable bool _rolesOk; -}; + const Role &createRole(const QString &key, Role::DataType type); + int currentBlock; + int currentBlockOffset; + QVector<Role *> roles; + QStringHash<Role *> roleHash; +}; -class ModelNodeMetaObject; -class ModelObject : public QObject +class ListElement { - Q_OBJECT public: - ModelObject(ModelNode *node, NestedListModel *model, QV8Engine *eng); - void setValue(const QByteArray &name, const QVariant &val); - void setNodeUpdatesEnabled(bool enable); - NestedListModel *m_model; - ModelNode *m_node; + ListElement(); + ListElement(int existingUid); + ~ListElement(); + + static void sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout, QHash<int, ListModel *> *targetModelHash); + + enum + { + BLOCK_SIZE = 64 - sizeof(int) - sizeof(ListElement *) - sizeof(ModelObject *) + }; private: - ModelNodeMetaObject *m_meta; + + void destroy(ListLayout *layout); + + int setVariantProperty(const ListLayout::Role &role, const QVariant &d); + + int setJsProperty(const ListLayout::Role &role, v8::Handle<v8::Value> d, QV8Engine *eng); + + int setStringProperty(const ListLayout::Role &role, const QString &s); + int setDoubleProperty(const ListLayout::Role &role, double n); + int setBoolProperty(const ListLayout::Role &role, bool b); + int setListProperty(const ListLayout::Role &role, ListModel *m); + int setQObjectProperty(const ListLayout::Role &role, QObject *o); + int setVariantMapProperty(const ListLayout::Role &role, v8::Handle<v8::Object> o, QV8Engine *eng); + int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m); + + void setStringPropertyFast(const ListLayout::Role &role, const QString &s); + void setDoublePropertyFast(const ListLayout::Role &role, double n); + void setBoolPropertyFast(const ListLayout::Role &role, bool b); + void setQObjectPropertyFast(const ListLayout::Role &role, QObject *o); + void setListPropertyFast(const ListLayout::Role &role, ListModel *m); + void setVariantMapFast(const ListLayout::Role &role, v8::Handle<v8::Object> o, QV8Engine *eng); + + void clearProperty(const ListLayout::Role &role); + + QVariant getProperty(const ListLayout::Role &role, const QDeclarativeListModel *owner, QV8Engine *eng); + ListModel *getListProperty(const ListLayout::Role &role); + QString *getStringProperty(const ListLayout::Role &role); + QObject *getQObjectProperty(const ListLayout::Role &role); + QDeclarativeGuard<QObject> *getGuardProperty(const ListLayout::Role &role); + QVariantMap *getVariantMapProperty(const ListLayout::Role &role); + + inline char *getPropertyMemory(const ListLayout::Role &role); + + int getUid() const { return uid; } + + char data[BLOCK_SIZE]; + ListElement *next; + + int uid; + ModelObject *m_objectCache; + + friend class ListModel; }; -class ModelNodeMetaObject : public QDeclarativeOpenMetaObject +class ListModel { public: - ModelNodeMetaObject(QV8Engine *eng, ModelObject *object); - bool m_enabled; + ListModel(ListLayout *layout, QDeclarativeListModel *modelCache, int uid); + ~ListModel() {} -protected: - void propertyWritten(int index); + void destroy(); -private: - QV8Engine *m_engine; - ModelObject *m_obj; -}; + int setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data); + int setExistingProperty(int uid, const QString &key, v8::Handle<v8::Value> data, QV8Engine *eng); -/* - A ModelNode is created for each item in a NestedListModel. -*/ -struct ModelNode -{ - ModelNode(NestedListModel *model); - ~ModelNode(); + QVariant getProperty(int elementIndex, int roleIndex, const QDeclarativeListModel *owner, QV8Engine *eng); + ListModel *getListProperty(int elementIndex, const ListLayout::Role &role); + + int roleCount() const + { + return m_layout->roleCount(); + } + + const ListLayout::Role &getExistingRole(int index) + { + return m_layout->getExistingRole(index); + } - QList<QVariant> values; - QHash<QString, ModelNode *> properties; + const ListLayout::Role &getOrCreateListRole(const QString &name) + { + return m_layout->getRoleOrCreate(name, ListLayout::Role::List); + } + + int elementCount() const + { + return elements.count(); + } + + void set(int elementIndex, v8::Handle<v8::Object> object, QList<int> *roles, QV8Engine *eng); + void set(int elementIndex, v8::Handle<v8::Object> object, QV8Engine *eng); + + int append(v8::Handle<v8::Object> object, QV8Engine *eng); + void insert(int elementIndex, v8::Handle<v8::Object> object, QV8Engine *eng); void clear(); + void remove(int index); + + int appendElement(); + void insertElement(int index); - QDeclarativeListModel *model(const NestedListModel *model); - ModelObject *object(const NestedListModel *model); + void move(int from, int to, int n); - bool setObjectValue(v8::Handle<v8::Value> valuemap, bool writeToCache = true); - void setListValue(v8::Handle<v8::Value> valuelist); - bool setProperty(const QString& prop, const QVariant& val); - void changedProperty(const QString &name) const; - void updateListIndexes(); - static void dump(ModelNode *node, int ind); + int getUid() const { return m_uid; } - QDeclarativeListModel *modelCache; - ModelObject *objectCache; - bool isArray; + static int allocateUid(); + + static void sync(ListModel *src, ListModel *target, QHash<int, ListModel *> *srcModelHash); + + ModelObject *getOrCreateModelObject(QDeclarativeListModel *model, int elementIndex); + +private: + QPODVector<ListElement *, 4> elements; + ListLayout *m_layout; + int m_uid; - NestedListModel *m_model; - int listIndex; // only used for top-level nodes within a list + QDeclarativeListModel *m_modelCache; + + struct ElementSync + { + ElementSync() : src(0), target(0) {} + + ListElement *src; + ListElement *target; + }; + + void newElement(int index); + + void updateCacheIndices(); + + friend class ListElement; + friend class QDeclarativeListModelWorkerAgent; + + static QAtomicInt uidCounter; }; +Q_DECLARE_METATYPE(ListModel *); QT_END_NAMESPACE -Q_DECLARE_METATYPE(ModelNode *) - QT_END_HEADER #endif // QDECLARATIVELISTMODEL_P_P_H diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp index b27e3e387f..2e7ef0599b 100644 --- a/src/declarative/util/qdeclarativelistmodelworkeragent.cpp +++ b/src/declarative/util/qdeclarativelistmodelworkeragent.cpp @@ -53,54 +53,50 @@ QT_BEGIN_NAMESPACE -void QDeclarativeListModelWorkerAgent::Data::clearChange() -{ - changes.clear(); +void QDeclarativeListModelWorkerAgent::Data::clearChange(QDeclarativeListModel *model) +{ + int uid = model->m_listModel->getUid(); + + for (int i=0 ; i < changes.count() ; ++i) { + if (changes[i].modelUid == uid) { + changes.removeAt(i); + --i; + } + } } -void QDeclarativeListModelWorkerAgent::Data::insertChange(int index, int count) +void QDeclarativeListModelWorkerAgent::Data::insertChange(QDeclarativeListModel *model, int index, int count) { - Change c = { Change::Inserted, index, count, 0, QList<int>() }; + Change c = { model->m_listModel->getUid(), Change::Inserted, index, count, 0, QList<int>() }; changes << c; } -void QDeclarativeListModelWorkerAgent::Data::removeChange(int index, int count) +void QDeclarativeListModelWorkerAgent::Data::removeChange(QDeclarativeListModel *model, int index, int count) { - Change c = { Change::Removed, index, count, 0, QList<int>() }; + Change c = { model->m_listModel->getUid(), Change::Removed, index, count, 0, QList<int>() }; changes << c; } -void QDeclarativeListModelWorkerAgent::Data::moveChange(int index, int count, int to) +void QDeclarativeListModelWorkerAgent::Data::moveChange(QDeclarativeListModel *model, int index, int count, int to) { - Change c = { Change::Moved, index, count, to, QList<int>() }; + Change c = { model->m_listModel->getUid(), Change::Moved, index, count, to, QList<int>() }; changes << c; } -void QDeclarativeListModelWorkerAgent::Data::changedChange(int index, int count, const QList<int> &roles) +void QDeclarativeListModelWorkerAgent::Data::changedChange(QDeclarativeListModel *model, int index, int count, const QList<int> &roles) { - Change c = { Change::Changed, index, count, 0, roles }; + Change c = { model->m_listModel->getUid(), Change::Changed, index, count, 0, roles }; changes << c; } QDeclarativeListModelWorkerAgent::QDeclarativeListModelWorkerAgent(QDeclarativeListModel *model) -: m_engine(0), m_ref(1), m_orig(model), m_copy(new QDeclarativeListModel(model, this)) -{ -} - -QDeclarativeListModelWorkerAgent::~QDeclarativeListModelWorkerAgent() +: m_ref(1), m_orig(model), m_copy(new QDeclarativeListModel(model, this)) { } void QDeclarativeListModelWorkerAgent::setV8Engine(QV8Engine *eng) { - m_engine = eng; - if (m_copy->m_flat) - m_copy->m_flat->m_engine = eng; -} - -QV8Engine *QDeclarativeListModelWorkerAgent::v8engine() const -{ - return m_engine; + m_copy->m_engine = eng; } void QDeclarativeListModelWorkerAgent::addref() @@ -123,36 +119,22 @@ int QDeclarativeListModelWorkerAgent::count() const void QDeclarativeListModelWorkerAgent::clear() { - data.clearChange(); - data.removeChange(0, m_copy->count()); m_copy->clear(); } void QDeclarativeListModelWorkerAgent::remove(int index) { - int count = m_copy->count(); m_copy->remove(index); - - if (m_copy->count() != count) - data.removeChange(index, 1); } -void QDeclarativeListModelWorkerAgent::append(const QDeclarativeV8Handle &value) +void QDeclarativeListModelWorkerAgent::append(QDeclarativeV8Function *args) { - int count = m_copy->count(); - m_copy->append(value); - - if (m_copy->count() != count) - data.insertChange(m_copy->count() - 1, 1); + m_copy->append(args); } -void QDeclarativeListModelWorkerAgent::insert(int index, const QDeclarativeV8Handle &value) +void QDeclarativeListModelWorkerAgent::insert(QDeclarativeV8Function *args) { - int count = m_copy->count(); - m_copy->insert(index, value); - - if (m_copy->count() != count) - data.insertChange(index, 1); + m_copy->insert(args); } QDeclarativeV8Handle QDeclarativeListModelWorkerAgent::get(int index) const @@ -162,24 +144,17 @@ QDeclarativeV8Handle QDeclarativeListModelWorkerAgent::get(int index) const void QDeclarativeListModelWorkerAgent::set(int index, const QDeclarativeV8Handle &value) { - QList<int> roles; - m_copy->set(index, value, &roles); - if (!roles.isEmpty()) - data.changedChange(index, 1, roles); + m_copy->set(index, value); } void QDeclarativeListModelWorkerAgent::setProperty(int index, const QString& property, const QVariant& value) { - QList<int> roles; - m_copy->setProperty(index, property, value, &roles); - if (!roles.isEmpty()) - data.changedChange(index, 1, roles); + m_copy->setProperty(index, property, value); } void QDeclarativeListModelWorkerAgent::move(int from, int to, int count) { m_copy->move(from, to, count); - data.moveChange(from, to, count); } void QDeclarativeListModelWorkerAgent::sync() @@ -195,77 +170,48 @@ void QDeclarativeListModelWorkerAgent::sync() mutex.unlock(); } -void QDeclarativeListModelWorkerAgent::changedData(int index, int count, const QList<int> &roles) -{ - data.changedChange(index, count, roles); -} - bool QDeclarativeListModelWorkerAgent::event(QEvent *e) { if (e->type() == QEvent::User) { + QMutexLocker locker(&mutex); Sync *s = static_cast<Sync *>(e); const QList<Change> &changes = s->data.changes; - if (m_copy) { - bool cc = m_orig->count() != s->list->count(); + bool cc = m_orig->count() != s->list->count(); - FlatListModel *orig = m_orig->m_flat; - FlatListModel *copy = s->list->m_flat; - if (!orig || !copy) { - syncDone.wakeAll(); - return QObject::event(e); - } - - orig->m_roles = copy->m_roles; - orig->m_strings = copy->m_strings; - orig->m_values = copy->m_values; + QHash<int, ListModel *> targetModelHash; + ListModel::sync(s->list->m_listModel, m_orig->m_listModel, &targetModelHash); - // update the orig->m_nodeData list - for (int ii = 0; ii < changes.count(); ++ii) { - const Change &change = changes.at(ii); - switch (change.type) { - case Change::Inserted: - orig->insertedNode(change.index); - break; - case Change::Removed: - orig->removedNode(change.index); - break; - case Change::Moved: - orig->moveNodes(change.index, change.to, change.count); - break; - case Change::Changed: - break; - } - } + for (int ii = 0; ii < changes.count(); ++ii) { + const Change &change = changes.at(ii); - syncDone.wakeAll(); - locker.unlock(); + ListModel *model = targetModelHash.value(change.modelUid); - for (int ii = 0; ii < changes.count(); ++ii) { - const Change &change = changes.at(ii); + if (model && model->m_modelCache) { switch (change.type) { case Change::Inserted: - emit m_orig->itemsInserted(change.index, change.count); + emit model->m_modelCache->itemsInserted(change.index, change.count); break; case Change::Removed: - emit m_orig->itemsRemoved(change.index, change.count); + emit model->m_modelCache->itemsRemoved(change.index, change.count); break; case Change::Moved: - emit m_orig->itemsMoved(change.index, change.to, change.count); + emit model->m_modelCache->itemsMoved(change.index, change.to, change.count); break; case Change::Changed: - emit m_orig->itemsChanged(change.index, change.count, change.roles); + emit model->m_modelCache->itemsChanged(change.index, change.count, change.roles); break; } } - - if (cc) - emit m_orig->countChanged(); - } else { - syncDone.wakeAll(); } + + syncDone.wakeAll(); + locker.unlock(); + + if (cc) + emit m_orig->countChanged(); } return QObject::event(e); diff --git a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h index 12505e942c..58651386af 100644 --- a/src/declarative/util/qdeclarativelistmodelworkeragent_p.h +++ b/src/declarative/util/qdeclarativelistmodelworkeragent_p.h @@ -76,10 +76,8 @@ class QDeclarativeListModelWorkerAgent : public QObject public: QDeclarativeListModelWorkerAgent(QDeclarativeListModel *); - ~QDeclarativeListModelWorkerAgent(); void setV8Engine(QV8Engine *eng); - QV8Engine *v8engine() const; void addref(); void release(); @@ -88,8 +86,8 @@ public: Q_INVOKABLE void clear(); Q_INVOKABLE void remove(int index); - Q_INVOKABLE void append(const QDeclarativeV8Handle &); - Q_INVOKABLE void insert(int index, const QDeclarativeV8Handle &); + Q_INVOKABLE void append(QDeclarativeV8Function *args); + Q_INVOKABLE void insert(QDeclarativeV8Function *args); Q_INVOKABLE QDeclarativeV8Handle get(int index) const; Q_INVOKABLE void set(int index, const QDeclarativeV8Handle &); Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value); @@ -116,10 +114,11 @@ protected: private: friend class QDeclarativeWorkerScriptEnginePrivate; - friend class QDeclarativeListModelV8Data; - QV8Engine *m_engine; + friend class QDeclarativeListModel; - struct Change { + struct Change + { + int modelUid; enum { Inserted, Removed, Moved, Changed } type; int index; // Inserted/Removed/Moved/Changed int count; // Inserted/Removed/Moved/Changed @@ -127,14 +126,15 @@ private: QList<int> roles; }; - struct Data { + struct Data + { QList<Change> changes; - void clearChange(); - void insertChange(int index, int count); - void removeChange(int index, int count); - void moveChange(int index, int count, int to); - void changedChange(int index, int count, const QList<int> &roles); + void clearChange(QDeclarativeListModel *model); + void insertChange(QDeclarativeListModel *model, int index, int count); + void removeChange(QDeclarativeListModel *model, int index, int count); + void moveChange(QDeclarativeListModel *model, int index, int count, int to); + void changedChange(QDeclarativeListModel *model, int index, int count, const QList<int> &roles); }; Data data; @@ -144,8 +144,6 @@ private: QDeclarativeListModel *list; }; - void changedData(int index, int count, const QList<int> &roles); - QAtomicInt m_ref; QDeclarativeListModel *m_orig; QDeclarativeListModel *m_copy; diff --git a/src/declarative/util/qdeclarativepath.cpp b/src/declarative/util/qdeclarativepath.cpp index 146fbf9950..bf3b46ee81 100644 --- a/src/declarative/util/qdeclarativepath.cpp +++ b/src/declarative/util/qdeclarativepath.cpp @@ -256,7 +256,7 @@ void QDeclarativePath::endpoint(QList<AttributePoint> &attributePoints, const QS } } -static QString percentString(QStringLiteral("_qfx_percent")); +static QString percentString(QLatin1String("_qfx_percent")); void QDeclarativePath::processPath() { @@ -1396,7 +1396,7 @@ void QDeclarativePathSvg::addToPath(QPainterPath &path, const QDeclarativePathDa PathView's path. You can use it to bunch together items on part of the path, and spread them out on other parts of the path. - The examples below show the normal distrubution of items along a path + The examples below show the normal distribution of items along a path compared to a distribution which places 50% of the items along the PathLine section of the path. \table @@ -1438,7 +1438,7 @@ void QDeclarativePathSvg::addToPath(QPainterPath &path, const QDeclarativePathDa /*! \qmlproperty real QtQuick2::PathPercent::value - The proporation of items that should be laid out up to this point. + The proportion of items that should be laid out up to this point. This value should always be higher than the last value specified by a PathPercent at a previous position in the Path. diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp index 818c1638cd..72add5621f 100644 --- a/src/declarative/util/qdeclarativepropertychanges.cpp +++ b/src/declarative/util/qdeclarativepropertychanges.cpp @@ -108,7 +108,7 @@ QT_BEGIN_NAMESPACE \section2 Resetting property values The \c undefined value can be used to reset the property value for a state. - In the following example, when \c theText changes to the \e widerText + In the following example, when \c myText changes to the \e widerText state, its \c width property is reset, giving the text its natural width and displaying the whole string on a single line. @@ -170,7 +170,8 @@ public: reverseExpression = rewindExpression; } - /*virtual void copyOriginals(QDeclarativeActionEvent *other) + virtual bool needsCopy() { return true; } + virtual void copyOriginals(QDeclarativeActionEvent *other) { QDeclarativeReplaceSignalHandler *rsh = static_cast<QDeclarativeReplaceSignalHandler*>(other); saveCurrentValues(); @@ -181,7 +182,7 @@ public: ownedExpression = rsh->ownedExpression; rsh->ownedExpression = 0; } - }*/ + } virtual void rewind() { ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, rewindExpression); diff --git a/src/declarative/util/qdeclarativestyledtext.cpp b/src/declarative/util/qdeclarativestyledtext.cpp index 872bad6589..1c7ca5fbfd 100644 --- a/src/declarative/util/qdeclarativestyledtext.cpp +++ b/src/declarative/util/qdeclarativestyledtext.cpp @@ -234,6 +234,8 @@ bool QDeclarativeStyledTextPrivate::parseTag(const QChar *&ch, const QString &te int tagLength = 0; while (!ch->isNull()) { if (*ch == greaterThan) { + if (tagLength == 0) + return false; QStringRef tag(&textIn, tagStart, tagLength); const QChar char0 = tag.at(0); if (char0 == QLatin1Char('b')) { @@ -343,6 +345,8 @@ bool QDeclarativeStyledTextPrivate::parseCloseTag(const QChar *&ch, const QStrin int tagLength = 0; while (!ch->isNull()) { if (*ch == greaterThan) { + if (tagLength == 0) + return false; QStringRef tag(&textIn, tagStart, tagLength); const QChar char0 = tag.at(0); hasNewLine = false; diff --git a/src/imports/folderlistmodel/folderlistmodel.pro b/src/imports/folderlistmodel/folderlistmodel.pro index 63f75d9254..26efc654b8 100644 --- a/src/imports/folderlistmodel/folderlistmodel.pro +++ b/src/imports/folderlistmodel/folderlistmodel.pro @@ -13,14 +13,4 @@ target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH qmldir.files += $$PWD/qmldir qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH -symbian:{ - TARGET.UID3 = 0x20021320 - - isEmpty(DESTDIR):importFiles.files = qmlfolderlistmodelplugin$${QT_LIBINFIX}.dll qmldir - else:importFiles.files = $$DESTDIR/qmlfolderlistmodelplugin$${QT_LIBINFIX}.dll qmldir - importFiles.path = $$QT_IMPORTS_BASE_DIR/$$TARGETPATH - - DEPLOYMENT = importFiles -} - INSTALLS += target qmldir diff --git a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp b/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp index 88675d4ae0..a6c9f97a96 100644 --- a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp +++ b/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp @@ -269,7 +269,7 @@ QUrl QDeclarativeFolderListModel::parentFolder() const QString localFile = d->folder.toLocalFile(); if (!localFile.isEmpty()) { QDir dir(localFile); -#if defined(Q_OS_SYMBIAN) || defined(Q_OS_WIN) +#if defined(Q_OS_WIN) if (dir.isRoot()) dir.setPath(""); else diff --git a/src/imports/gestures/gestures.pro b/src/imports/gestures/gestures.pro index e7095956b2..36244a1d71 100644 --- a/src/imports/gestures/gestures.pro +++ b/src/imports/gestures/gestures.pro @@ -13,14 +13,4 @@ target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH qmldir.files += $$PWD/qmldir qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH -symbian:{ - TARGET.UID3 = 0x2002131F - - isEmpty(DESTDIR):importFiles.files = qmlgesturesplugin$${QT_LIBINFIX}.dll qmldir - else:importFiles.files = $$DESTDIR/qmlgesturesplugin$${QT_LIBINFIX}.dll qmldir - importFiles.path = $$QT_IMPORTS_BASE_DIR/$$TARGETPATH - - DEPLOYMENT = importFiles -} - INSTALLS += target qmldir diff --git a/src/imports/particles/particles.pro b/src/imports/particles/particles.pro index 74dab8dcf3..3c523aca4a 100644 --- a/src/imports/particles/particles.pro +++ b/src/imports/particles/particles.pro @@ -20,14 +20,4 @@ target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH qmldir.files += $$PWD/qmldir qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH -symbian:{ - TARGET.UID3 = 0x2002131E - - isEmpty(DESTDIR):importFiles.files = qmlparticlesplugin$${QT_LIBINFIX}.dll qmldir - else:importFiles.files = $$DESTDIR/qmlparticlesplugin$${QT_LIBINFIX}.dll qmldir - importFiles.path = $$QT_IMPORTS_BASE_DIR/$$TARGETPATH - - DEPLOYMENT = importFiles -} - INSTALLS += target qmldir diff --git a/src/imports/qimportbase.pri b/src/imports/qimportbase.pri index 5807425e3c..110d145e94 100644 --- a/src/imports/qimportbase.pri +++ b/src/imports/qimportbase.pri @@ -1,6 +1,5 @@ load(qt_module) -symbian:load(qt_plugin) TEMPLATE = lib CONFIG += qt plugin @@ -30,9 +29,3 @@ contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols load(qt_targets) wince*:LIBS += $$QMAKE_LIBS_GUI - -symbian: { - TARGET.EPOCALLOWDLLDATA=1 - TARGET.CAPABILITY = All -Tcb - load(armcc_warnings) -} diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml index bb97481102..5887ececa0 100644 --- a/src/imports/testlib/TestCase.qml +++ b/src/imports/testlib/TestCase.qml @@ -74,6 +74,7 @@ Item { // Internal private state. Identifiers prefixed with qtest are reserved. property bool qtest_prevWhen: true property int qtest_testId: -1 + property bool qtest_componentCompleted : false property variant qtest_testCaseResult property variant qtest_results: qtest_results_normal TestResult { id: qtest_results_normal } @@ -659,7 +660,7 @@ Item { onWhenChanged: { if (when != qtest_prevWhen) { qtest_prevWhen = when - if (when && !completed && !running) + if (when && !completed && !running && qtest_componentCompleted) qtest_run() } } @@ -685,6 +686,7 @@ Item { Component.onCompleted: { qtest.hasTestCase = true; + qtest_componentCompleted = true; if (util.printAvailableFunctions) { var testList = [] @@ -714,4 +716,4 @@ Item { if (when && !completed && !running) qtest_run() } -} +}
\ No newline at end of file diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp index daec00d38c..c78a1c4d75 100644 --- a/src/imports/testlib/main.cpp +++ b/src/imports/testlib/main.cpp @@ -103,29 +103,9 @@ public Q_SLOTS: bool compare(const QVariant& act, const QVariant& exp) const { return act == exp; } -// QDeclarativeV8Handle toString(const QVariant& v) const -// { -// QString name(v.typeName()); - -// if (v.canConvert<QObject*>()) { -// QDeclarativeType *type = 0; -// const QMetaObject *mo = v.value<QObject*>()->metaObject(); -// while (!type && mo) { -// type = QDeclarativeMetaType::qmlType(mo); -// mo = mo->superClass(); -// } -// if (type) { -// name = type->qmlTypeName(); -// } -// } - -// return QDeclarativeV8Handle::fromHandle(v8::String::New(name.toUtf8())); -// } QDeclarativeV8Handle callerFile(int frameIndex = 0) const { - v8::HandleScope scope; - v8::Local<v8::StackTrace> stacks = v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); int count = stacks->GetFrameCount(); if (count >= frameIndex + 2) { @@ -136,7 +116,6 @@ public Q_SLOTS: } int callerLine(int frameIndex = 0) const { - v8::HandleScope scope; v8::Local<v8::StackTrace> stacks = v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); int count = stacks->GetFrameCount(); if (count >= frameIndex + 2) { @@ -165,7 +144,7 @@ public: qmlRegisterType<QuickTestUtil>(uri,1,0,"TestUtil"); } - void initializeEngine(QDeclarativeEngine *engine, const char *) + void initializeEngine(QDeclarativeEngine *, const char *) { } }; @@ -174,4 +153,4 @@ QT_END_NAMESPACE #include "main.moc" -Q_EXPORT_PLUGIN2(qmltestplugin, QT_PREPEND_NAMESPACE(QTestQmlModule)); +Q_EXPORT_PLUGIN2(qmltestplugin, QT_PREPEND_NAMESPACE(QTestQmlModule)) diff --git a/src/imports/testlib/testlib.pro b/src/imports/testlib/testlib.pro index da072d34b1..dbe45fb6fa 100644 --- a/src/imports/testlib/testlib.pro +++ b/src/imports/testlib/testlib.pro @@ -2,25 +2,8 @@ TARGET = qmltestplugin TARGETPATH = QtTest include(../qimportbase.pri) - CONFIG += qt plugin -symbian { - CONFIG += epocallowdlldata - contains(QT_EDITION, OpenSource) { - TARGET.CAPABILITY = LocalServices NetworkServices ReadUserData UserEnvironment WriteUserData - } else { - TARGET.CAPABILITY = All -Tcb - } - - isEmpty(DESTDIR):importFiles.files = qmltestplugin$${QT_LIBINFIX}.dll qmldir - else:importFiles.files = $$DESTDIR/qmltestplugin$${QT_LIBINFIX}.dll qmldir - importFiles.path = $$QT_IMPORTS_BASE_DIR/$$TARGETPATH - - DEPLOYMENT = importFiles - -} - QT += declarative qmltest qmltest-private v8-private declarative-private core-private testlib SOURCES += main.cpp diff --git a/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro b/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro deleted file mode 100644 index 9971f22e3d..0000000000 --- a/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro +++ /dev/null @@ -1,57 +0,0 @@ -load(qt_module) - -TARGET = qmldbg_inspector -QT += declarative-private core-private gui-private opengl-private qtquick1 widgets widgets-private v8-private - -load(qt_plugin) - -DESTDIR = $$QT.declarative.plugins/qmltooling -QTDIR_build:REQUIRES += "contains(QT_CONFIG, declarative)" - -SOURCES += \ - abstractviewinspector.cpp \ - qdeclarativeinspectorplugin.cpp \ - qtquick1/qdeclarativeviewinspector.cpp \ - qtquick1/abstractliveedittool.cpp \ - qtquick1/liveselectiontool.cpp \ - qtquick1/livelayeritem.cpp \ - qtquick1/livesingleselectionmanipulator.cpp \ - qtquick1/liverubberbandselectionmanipulator.cpp \ - qtquick1/liveselectionrectangle.cpp \ - qtquick1/liveselectionindicator.cpp \ - qtquick1/boundingrecthighlighter.cpp \ - qtquick1/subcomponentmasklayeritem.cpp \ - qtquick1/zoomtool.cpp \ - qtquick1/colorpickertool.cpp \ - abstracttool.cpp \ - sgviewinspector.cpp \ - sgselectiontool.cpp \ - sghighlight.cpp - -HEADERS += \ - abstractviewinspector.h \ - qdeclarativeinspectorplugin.h \ - qdeclarativeinspectorprotocol.h \ - qmlinspectorconstants.h \ - qtquick1/qdeclarativeviewinspector.h \ - qtquick1/qdeclarativeviewinspector_p.h \ - qtquick1/abstractliveedittool.h \ - qtquick1/liveselectiontool.h \ - qtquick1/livelayeritem.h \ - qtquick1/livesingleselectionmanipulator.h \ - qtquick1/liverubberbandselectionmanipulator.h \ - qtquick1/liveselectionrectangle.h \ - qtquick1/liveselectionindicator.h \ - qtquick1/boundingrecthighlighter.h \ - qtquick1/subcomponentmasklayeritem.h \ - qtquick1/zoomtool.h \ - qtquick1/colorpickertool.h \ - abstracttool.h \ - sgviewinspector.h \ - sgselectiontool.h \ - sghighlight.h - -target.path += $$[QT_INSTALL_PLUGINS]/qmltooling -INSTALLS += target - -symbian:TARGET.UID3=0x20031E90 diff --git a/src/plugins/qmltooling/qmldbg_ost/qmldbg_ost.pro b/src/plugins/qmltooling/qmldbg_ost/qmldbg_ost.pro index a12fac5da3..c1ca2a5ef9 100644 --- a/src/plugins/qmltooling/qmldbg_ost/qmldbg_ost.pro +++ b/src/plugins/qmltooling/qmldbg_ost/qmldbg_ost.pro @@ -8,7 +8,7 @@ QTDIR_build:REQUIRES += "contains(QT_CONFIG, declarative)" SOURCES += \ qmlostplugin.cpp \ - qostdevice.cpp + qostdevice.cpp HEADERS += \ qmlostplugin.h \ @@ -17,5 +17,3 @@ HEADERS += \ target.path += $$[QT_INSTALL_PLUGINS]/qmltooling INSTALLS += target - -symbian:TARGET.UID3=0x20031E92 diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/abstractliveedittool.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/abstractliveedittool.cpp index c2482929ca..09a39d6520 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/abstractliveedittool.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick1/abstractliveedittool.cpp @@ -49,6 +49,7 @@ #include <QDeclarativeItem> namespace QmlJSDebugger { +namespace QtQuick1 { AbstractLiveEditTool::AbstractLiveEditTool(QDeclarativeViewInspector *editorView) : AbstractTool(editorView) @@ -192,5 +193,5 @@ QString AbstractLiveEditTool::titleForItem(QGraphicsItem *item) return constructedName; } - +} // namespace QtQuick1 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/abstractliveedittool.h b/src/plugins/qmltooling/qmldbg_qtquick1/abstractliveedittool.h index 04b5f4e46e..fd57076d0c 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/abstractliveedittool.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/abstractliveedittool.h @@ -43,7 +43,7 @@ #define ABSTRACTLIVEEDITTOOL_H #include <QtCore/QList> -#include "../abstracttool.h" +#include "abstracttool.h" QT_BEGIN_NAMESPACE class QMouseEvent; @@ -57,6 +57,7 @@ class QDeclarativeView; QT_END_NAMESPACE namespace QmlJSDebugger { +namespace QtQuick1 { class QDeclarativeViewInspector; @@ -99,6 +100,7 @@ private: QList<QGraphicsItem*> m_itemList; }; -} +} // namespace QtQuick1 +} // namesacpe QmlJSDebugger #endif // ABSTRACTLIVEEDITTOOL_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/boundingrecthighlighter.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/boundingrecthighlighter.cpp index e097d3cd77..7cf1e83520 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/boundingrecthighlighter.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick1/boundingrecthighlighter.cpp @@ -42,7 +42,7 @@ #include "boundingrecthighlighter.h" #include "qdeclarativeviewinspector.h" -#include "../qmlinspectorconstants.h" +#include "qmlinspectorconstants.h" #include <QtWidgets/QGraphicsPolygonItem> @@ -51,6 +51,7 @@ #include <QtCore/QDebug> namespace QmlJSDebugger { +namespace QtQuick1 { BoundingBox::BoundingBox(QGraphicsObject *itemToHighlight, QGraphicsItem *parentItem, QObject *parent) @@ -236,5 +237,5 @@ void BoundingRectHighlighter::refresh() highlightAll(); } - +} // namespace QtQuick1 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/boundingrecthighlighter.h b/src/plugins/qmltooling/qmldbg_qtquick1/boundingrecthighlighter.h index 81883ee0aa..e99197f06d 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/boundingrecthighlighter.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/boundingrecthighlighter.h @@ -54,6 +54,7 @@ QT_FORWARD_DECLARE_CLASS(QStyleOptionGraphicsItem) QT_FORWARD_DECLARE_CLASS(QTimer) namespace QmlJSDebugger { +namespace QtQuick1 { class QDeclarativeViewInspector; class BoundingBox; @@ -110,6 +111,7 @@ public: int type() const; }; +} // namespace QtQuick1 } // namespace QmlJSDebugger #endif // BOUNDINGRECTHIGHLIGHTER_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/colorpickertool.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/colorpickertool.cpp index 581c1f5b1a..3372f9c8e6 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/colorpickertool.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick1/colorpickertool.cpp @@ -52,6 +52,7 @@ #include <QtGui/QPalette> namespace QmlJSDebugger { +namespace QtQuick1 { ColorPickerTool::ColorPickerTool(QDeclarativeViewInspector *view) : AbstractLiveEditTool(view) @@ -95,4 +96,5 @@ void ColorPickerTool::pickColor(const QPoint &pos) emit selectedColorChanged(m_selectedColor); } +} // namespace QtQuick1 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/colorpickertool.h b/src/plugins/qmltooling/qmldbg_qtquick1/colorpickertool.h index a28ffea63a..7e86b015eb 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/colorpickertool.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/colorpickertool.h @@ -49,6 +49,7 @@ QT_FORWARD_DECLARE_CLASS(QPoint) namespace QmlJSDebugger { +namespace QtQuick1 { class ColorPickerTool : public AbstractLiveEditTool { @@ -87,6 +88,7 @@ private: QColor m_selectedColor; }; +} // namespace QtQuick1 } // namespace QmlJSDebugger #endif // COLORPICKERTOOL_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/livelayeritem.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/livelayeritem.cpp index fb7118fbc2..7788eabe26 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/livelayeritem.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick1/livelayeritem.cpp @@ -41,11 +41,12 @@ #include "livelayeritem.h" -#include "../qmlinspectorconstants.h" +#include "qmlinspectorconstants.h" #include <QGraphicsScene> namespace QmlJSDebugger { +namespace QtQuick1 { LiveLayerItem::LiveLayerItem(QGraphicsScene* scene) : QGraphicsObject() @@ -89,4 +90,5 @@ QList<QGraphicsItem*> LiveLayerItem::findAllChildItems(const QGraphicsItem *item return itemList; } +} // namespace QtQuick1 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/livelayeritem.h b/src/plugins/qmltooling/qmldbg_qtquick1/livelayeritem.h index 15f9a27fa4..d819cae8c6 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/livelayeritem.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/livelayeritem.h @@ -45,6 +45,7 @@ #include <QtWidgets/QGraphicsObject> namespace QmlJSDebugger { +namespace QtQuick1 { class LiveLayerItem : public QGraphicsObject { @@ -62,6 +63,7 @@ protected: QList<QGraphicsItem*> findAllChildItems(const QGraphicsItem *item) const; }; -} +} // namespace QtQuick1 +} // namespace QmlJSDebugger #endif // LIVELAYERITEM_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liverubberbandselectionmanipulator.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/liverubberbandselectionmanipulator.cpp index 4987237f89..cfa0d4ff1a 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liverubberbandselectionmanipulator.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick1/liverubberbandselectionmanipulator.cpp @@ -48,6 +48,7 @@ #include <QtCore/QDebug> namespace QmlJSDebugger { +namespace QtQuick1 { LiveRubberBandSelectionManipulator::LiveRubberBandSelectionManipulator(QGraphicsObject *layerItem, QDeclarativeViewInspector *editorView) @@ -162,4 +163,5 @@ bool LiveRubberBandSelectionManipulator::isActive() const return m_isActive; } +} // namespace QtQuick1 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liverubberbandselectionmanipulator.h b/src/plugins/qmltooling/qmldbg_qtquick1/liverubberbandselectionmanipulator.h index aa15a34730..092e852679 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liverubberbandselectionmanipulator.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/liverubberbandselectionmanipulator.h @@ -49,6 +49,7 @@ QT_FORWARD_DECLARE_CLASS(QGraphicsItem) namespace QmlJSDebugger { +namespace QtQuick1 { class QDeclarativeViewInspector; @@ -91,6 +92,7 @@ private: bool m_isActive; }; -} +} // namespace QtQuick1 +} // namespace QmlJSDebugger #endif // RUBBERBANDSELECTIONMANIPULATOR_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liveselectionindicator.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/liveselectionindicator.cpp index 744cbf527e..0c3f47e534 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liveselectionindicator.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick1/liveselectionindicator.cpp @@ -42,7 +42,7 @@ #include "liveselectionindicator.h" #include "qdeclarativeviewinspector_p.h" -#include "../qmlinspectorconstants.h" +#include "qmlinspectorconstants.h" #include <QtWidgets/QGraphicsRectItem> #include <QtWidgets/QGraphicsObject> @@ -50,6 +50,7 @@ #include <QtGui/QPen> namespace QmlJSDebugger { +namespace QtQuick1 { LiveSelectionIndicator::LiveSelectionIndicator(QDeclarativeViewInspector *viewInspector, QGraphicsObject *layerItem) @@ -114,5 +115,6 @@ void LiveSelectionIndicator::setItems(const QList<QWeakPointer<QGraphicsObject> } } -} //namespace QmlJSDebugger +} // namespace QtQuick1 +} // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liveselectionindicator.h b/src/plugins/qmltooling/qmldbg_qtquick1/liveselectionindicator.h index 7b8cc12e62..db57834e95 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liveselectionindicator.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/liveselectionindicator.h @@ -53,6 +53,7 @@ class QPolygonF; QT_END_NAMESPACE namespace QmlJSDebugger { +namespace QtQuick1 { class QDeclarativeViewInspector; @@ -75,6 +76,7 @@ private: QDeclarativeViewInspector *m_view; }; -} +} // namespace QtQuick1 +} // namespace QmlJSDebugger #endif // LIVESELECTIONINDICATOR_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liveselectionrectangle.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/liveselectionrectangle.cpp index 23577561a4..a867aa6daf 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liveselectionrectangle.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick1/liveselectionrectangle.cpp @@ -41,7 +41,7 @@ #include "liveselectionrectangle.h" -#include "../qmlinspectorconstants.h" +#include "qmlinspectorconstants.h" #include <QtGui/QPen> #include <QtWidgets/QGraphicsRectItem> @@ -53,6 +53,7 @@ #include <cmath> namespace QmlJSDebugger { +namespace QtQuick1 { class SelectionRectShape : public QGraphicsRectItem { @@ -110,4 +111,5 @@ void LiveSelectionRectangle::setRect(const QPointF &firstPoint, m_controlShape->setRect(rect); } -} +} // namespace QtQuick1 +} // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liveselectionrectangle.h b/src/plugins/qmltooling/qmldbg_qtquick1/liveselectionrectangle.h index 730cca52d5..17eeda765b 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liveselectionrectangle.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/liveselectionrectangle.h @@ -50,6 +50,7 @@ QT_FORWARD_DECLARE_CLASS(QPointF) QT_FORWARD_DECLARE_CLASS(QRectF) namespace QmlJSDebugger { +namespace QtQuick1 { class LiveSelectionRectangle { @@ -72,6 +73,7 @@ private: QWeakPointer<QGraphicsObject> m_layerItem; }; +} // namespace QtQuick1 } // namespace QmlJSDebugger #endif // LIVESELECTIONRECTANGLE_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liveselectiontool.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/liveselectiontool.cpp index dc51a1f595..5307409272 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liveselectiontool.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick1/liveselectiontool.cpp @@ -58,6 +58,7 @@ #include <QtCore/QDebug> namespace QmlJSDebugger { +namespace QtQuick1 { LiveSelectionTool::LiveSelectionTool(QDeclarativeViewInspector *editorView) : AbstractLiveEditTool(editorView), @@ -420,4 +421,5 @@ void LiveSelectionTool::selectUnderPoint(QMouseEvent *event) m_singleSelectionManipulator.end(event->pos()); } +} // namespace QtQuick1 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liveselectiontool.h b/src/plugins/qmltooling/qmldbg_qtquick1/liveselectiontool.h index 2c281cda3c..b6a9aacd0e 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/liveselectiontool.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/liveselectiontool.h @@ -56,6 +56,7 @@ QT_FORWARD_DECLARE_CLASS(QKeyEvent) QT_FORWARD_DECLARE_CLASS(QAction) namespace QmlJSDebugger { +namespace QtQuick1 { class LiveSelectionTool : public AbstractLiveEditTool { @@ -115,6 +116,7 @@ private: QList<QGraphicsItem*> m_contextMenuItemList; }; +} // namespace QtQuick1 } // namespace QmlJSDebugger #endif // LIVESELECTIONTOOL_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/livesingleselectionmanipulator.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/livesingleselectionmanipulator.cpp index 9c78018ef9..c07e3fae28 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/livesingleselectionmanipulator.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick1/livesingleselectionmanipulator.cpp @@ -46,6 +46,7 @@ #include <QtDebug> namespace QmlJSDebugger { +namespace QtQuick1 { LiveSingleSelectionManipulator::LiveSingleSelectionManipulator(QDeclarativeViewInspector *editorView) : m_editorView(editorView), @@ -148,4 +149,5 @@ QPointF LiveSingleSelectionManipulator::beginPoint() const return m_beginPoint; } +} // namespace QtQuick1 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/livesingleselectionmanipulator.h b/src/plugins/qmltooling/qmldbg_qtquick1/livesingleselectionmanipulator.h index ac65711a91..80923a06ce 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/livesingleselectionmanipulator.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/livesingleselectionmanipulator.h @@ -48,6 +48,7 @@ QT_FORWARD_DECLARE_CLASS(QGraphicsItem) namespace QmlJSDebugger { +namespace QtQuick1 { class QDeclarativeViewInspector; @@ -84,6 +85,7 @@ private: bool m_isActive; }; +} // namespace QtQuick1 } // namespace QmlJSDebugger #endif // LIVESINGLESELECTIONMANIPULATOR_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/qdeclarativeviewinspector.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/qdeclarativeviewinspector.cpp index ca34f9e029..27d252a9ec 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/qdeclarativeviewinspector.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick1/qdeclarativeviewinspector.cpp @@ -52,6 +52,7 @@ #include <QtGui/QMouseEvent> namespace QmlJSDebugger { +namespace QtQuick1 { QDeclarativeViewInspectorPrivate::QDeclarativeViewInspectorPrivate(QDeclarativeViewInspector *q) : q(q) @@ -442,4 +443,5 @@ QRectF QDeclarativeViewInspector::adjustToScreenBoundaries(const QRectF &boundin return boundingRect; } +} // namespace QtQuick1 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/qdeclarativeviewinspector.h b/src/plugins/qmltooling/qmldbg_qtquick1/qdeclarativeviewinspector.h index c769a956e8..f430aa7b65 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/qdeclarativeviewinspector.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/qdeclarativeviewinspector.h @@ -44,13 +44,13 @@ #include <private/qdeclarativeglobal_p.h> -#include "qmlinspectorconstants.h" #include "abstractviewinspector.h" #include <QtCore/QScopedPointer> #include <QtQuick1/QDeclarativeView> namespace QmlJSDebugger { +namespace QtQuick1 { class AbstractLiveEditTool; class QDeclarativeViewInspectorPrivate; @@ -96,6 +96,7 @@ private: friend class AbstractLiveEditTool; }; +} // namespace QtQuick1 } // namespace QmlJSDebugger #endif // QDECLARATIVEVIEWINSPECTOR_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/qdeclarativeviewinspector_p.h b/src/plugins/qmltooling/qmldbg_qtquick1/qdeclarativeviewinspector_p.h index a51f155404..98dc03f84a 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/qdeclarativeviewinspector_p.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/qdeclarativeviewinspector_p.h @@ -52,6 +52,7 @@ #include "QtDeclarative/private/qdeclarativeinspectorservice_p.h" namespace QmlJSDebugger { +namespace QtQuick1 { class QDeclarativeViewInspector; class LiveSelectionTool; @@ -114,6 +115,7 @@ public: static QDeclarativeViewInspectorPrivate *get(QDeclarativeViewInspector *v) { return v->d_func(); } }; +} // namespace QtQuick1 } // namespace QmlJSDebugger #endif // QDECLARATIVEVIEWINSPECTOR_P_H diff --git a/src/plugins/qmltooling/qmldbg_qtquick1/qmldbg_qtquick1.pro b/src/plugins/qmltooling/qmldbg_qtquick1/qmldbg_qtquick1.pro new file mode 100644 index 0000000000..b98f463b5d --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_qtquick1/qmldbg_qtquick1.pro @@ -0,0 +1,50 @@ +load(qt_module) + +TARGET = qmldbg_qtquick1 +QT += declarative-private core-private gui-private widgets-private qtquick1 opengl-private + +load(qt_plugin) + +DESTDIR = $$QT.declarative.plugins/qmltooling + +INCLUDEPATH *= $$PWD $$PWD/../shared + +SOURCES += \ + abstractliveedittool.cpp \ + boundingrecthighlighter.cpp \ + colorpickertool.cpp \ + livelayeritem.cpp \ + liverubberbandselectionmanipulator.cpp \ + liveselectionindicator.cpp \ + liveselectionrectangle.cpp \ + liveselectiontool.cpp \ + livesingleselectionmanipulator.cpp \ + qdeclarativeviewinspector.cpp \ + qtquick1plugin.cpp \ + ../shared/abstracttool.cpp \ + ../shared/abstractviewinspector.cpp \ + subcomponentmasklayeritem.cpp \ + zoomtool.cpp + +HEADERS += \ + abstractliveedittool.h \ + boundingrecthighlighter.h \ + colorpickertool.h \ + livelayeritem.h \ + liverubberbandselectionmanipulator.h \ + liveselectionindicator.h \ + liveselectionrectangle.h \ + liveselectiontool.h \ + livesingleselectionmanipulator.h \ + qdeclarativeviewinspector.h \ + qdeclarativeviewinspector_p.h \ + qtquick1plugin.h \ + ../shared/abstracttool.h \ + ../shared/abstractviewinspector.h \ + ../shared/qdeclarativeinspectorprotocol.h \ + ../shared/qmlinspectorconstants.h \ + subcomponentmasklayeritem.h \ + zoomtool.h + +target.path += $$[QT_INSTALL_PLUGINS]/qmltooling +INSTALLS += target diff --git a/src/plugins/qmltooling/qmldbg_qtquick1/qtquick1plugin.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/qtquick1plugin.cpp new file mode 100644 index 0000000000..a8ad4074ae --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_qtquick1/qtquick1plugin.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtquick1plugin.h" +#include "qdeclarativeviewinspector.h" + +#include <QtCore/qplugin.h> +#include <QtDeclarative/private/qdeclarativeinspectorservice_p.h> +#include <QtQuick1/qdeclarativeview.h> + +namespace QmlJSDebugger { +namespace QtQuick1 { + +QtQuick1Plugin::QtQuick1Plugin() : + m_inspector(0) +{ +} + +QtQuick1Plugin::~QtQuick1Plugin() +{ + delete m_inspector; +} + +bool QtQuick1Plugin::canHandleView(QObject *view) +{ + return qobject_cast<QDeclarativeView*>(view); +} + +void QtQuick1Plugin::activate(QObject *view) +{ + QDeclarativeView *qDeclarativeView = qobject_cast<QDeclarativeView*>(view); + Q_ASSERT(qDeclarativeView); + m_inspector = new QDeclarativeViewInspector(qDeclarativeView, qDeclarativeView); +} + +void QtQuick1Plugin::deactivate() +{ + delete m_inspector; +} + +void QtQuick1Plugin::clientMessage(const QByteArray &message) +{ + if (m_inspector) + m_inspector->handleMessage(message); +} + +} // namespace QtQuick1 +} // namespace QmlJSDebugger + +Q_EXPORT_PLUGIN2(qmldbg_qtquick1, QmlJSDebugger::QtQuick1::QtQuick1Plugin) diff --git a/src/plugins/qmltooling/qmldbg_inspector/qdeclarativeinspectorplugin.h b/src/plugins/qmltooling/qmldbg_qtquick1/qtquick1plugin.h index 542925366c..38048740b7 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qdeclarativeinspectorplugin.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/qtquick1plugin.h @@ -49,23 +49,29 @@ namespace QmlJSDebugger { class AbstractViewInspector; -class QDeclarativeInspectorPlugin : public QObject, public QDeclarativeInspectorInterface +namespace QtQuick1 { + +class QtQuick1Plugin : public QObject, public QDeclarativeInspectorInterface { Q_OBJECT - Q_DISABLE_COPY(QDeclarativeInspectorPlugin) + Q_DISABLE_COPY(QtQuick1Plugin) Q_INTERFACES(QDeclarativeInspectorInterface) public: - QDeclarativeInspectorPlugin(); - ~QDeclarativeInspectorPlugin(); + QtQuick1Plugin(); + ~QtQuick1Plugin(); - void activate(); + // QDeclarativeInspectorInterface + bool canHandleView(QObject *view); + void activate(QObject *view); void deactivate(); + void clientMessage(const QByteArray &message); private: QPointer<AbstractViewInspector> m_inspector; }; +} // namespace QtQuick1 } // namespace QmlJSDebugger #endif // QDECLARATIVEINSPECTORPLUGIN_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/subcomponentmasklayeritem.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/subcomponentmasklayeritem.cpp index 4e3aed2fb4..0b1b9f8598 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/subcomponentmasklayeritem.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick1/subcomponentmasklayeritem.cpp @@ -41,12 +41,13 @@ #include "subcomponentmasklayeritem.h" -#include "../qmlinspectorconstants.h" +#include "qmlinspectorconstants.h" #include "qdeclarativeviewinspector.h" #include <QtGui/QPolygonF> namespace QmlJSDebugger { +namespace QtQuick1 { SubcomponentMaskLayerItem::SubcomponentMaskLayerItem(QDeclarativeViewInspector *inspector, QGraphicsItem *parentItem) : @@ -127,4 +128,5 @@ QGraphicsItem *SubcomponentMaskLayerItem::currentItem() const return m_currentItem; } +} // namespace QtQuick1 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/subcomponentmasklayeritem.h b/src/plugins/qmltooling/qmldbg_qtquick1/subcomponentmasklayeritem.h index 72c74663a1..c5f99f0a45 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/subcomponentmasklayeritem.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/subcomponentmasklayeritem.h @@ -45,6 +45,7 @@ #include <QtWidgets/QGraphicsPolygonItem> namespace QmlJSDebugger { +namespace QtQuick1 { class QDeclarativeViewInspector; @@ -66,6 +67,7 @@ private: QRectF m_itemPolyRect; }; +} // namespace QtQuick1 } // namespace QmlJSDebugger #endif // SUBCOMPONENTMASKLAYERITEM_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/zoomtool.cpp b/src/plugins/qmltooling/qmldbg_qtquick1/zoomtool.cpp index cf456ff251..daf44e23ec 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/zoomtool.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick1/zoomtool.cpp @@ -53,6 +53,7 @@ #include <QtCore/QDebug> namespace QmlJSDebugger { +namespace QtQuick1 { ZoomTool::ZoomTool(QDeclarativeViewInspector *view) : AbstractLiveEditTool(view), @@ -151,7 +152,7 @@ void ZoomTool::mouseReleaseEvent(QMouseEvent *event) view()->setSceneRect(sceneArea); } else { Qt::KeyboardModifier modifierKey = Qt::ControlModifier; -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC modifierKey = Qt::AltModifier; #endif if (event->modifiers() & modifierKey) { @@ -325,4 +326,5 @@ qreal ZoomTool::nextZoomScale(ZoomDirection direction) const return 1.0f; } +} // namespace QtQuick1 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/zoomtool.h b/src/plugins/qmltooling/qmldbg_qtquick1/zoomtool.h index de935591cb..bc26aae894 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qtquick1/zoomtool.h +++ b/src/plugins/qmltooling/qmldbg_qtquick1/zoomtool.h @@ -48,6 +48,7 @@ QT_FORWARD_DECLARE_CLASS(QAction) namespace QmlJSDebugger { +namespace QtQuick1 { class ZoomTool : public AbstractLiveEditTool { @@ -102,6 +103,7 @@ private: qreal m_currentScale; }; +} // namespace QtQuick1 } // namespace QmlJSDebugger #endif // ZOOMTOOL_H diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/qmldbg_qtquick2.pro b/src/plugins/qmltooling/qmldbg_qtquick2/qmldbg_qtquick2.pro new file mode 100644 index 0000000000..a06c1bdc10 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_qtquick2/qmldbg_qtquick2.pro @@ -0,0 +1,31 @@ +load(qt_module) + +TARGET = qmldbg_qtquick2 +QT += declarative-private core-private gui-private opengl-private v8-private + +load(qt_plugin) + +DESTDIR = $$QT.declarative.plugins/qmltooling + +INCLUDEPATH *= $$PWD $$PWD/../shared + +SOURCES += \ + qtquick2plugin.cpp \ + sghighlight.cpp \ + sgselectiontool.cpp \ + sgviewinspector.cpp \ + ../shared/abstracttool.cpp \ + ../shared/abstractviewinspector.cpp + +HEADERS += \ + qtquick2plugin.h \ + sghighlight.h \ + sgselectiontool.h \ + sgviewinspector.h \ + ../shared/abstracttool.h \ + ../shared/abstractviewinspector.h \ + ../shared/qdeclarativeinspectorprotocol.h \ + ../shared/qmlinspectorconstants.h + +target.path += $$[QT_INSTALL_PLUGINS]/qmltooling +INSTALLS += target diff --git a/src/plugins/qmltooling/qmldbg_inspector/qdeclarativeinspectorplugin.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/qtquick2plugin.cpp index f4eec5011d..5ed919c87c 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qdeclarativeinspectorplugin.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick2/qtquick2plugin.cpp @@ -39,9 +39,7 @@ ** ****************************************************************************/ -#include "qdeclarativeinspectorplugin.h" - -#include "qtquick1/qdeclarativeviewinspector_p.h" +#include "qtquick2plugin.h" #include "sgviewinspector.h" #include <QtCore/qplugin.h> @@ -49,37 +47,42 @@ #include <QtDeclarative/QQuickView> namespace QmlJSDebugger { +namespace QtQuick2 { -QDeclarativeInspectorPlugin::QDeclarativeInspectorPlugin() : +QtQuick2Plugin::QtQuick2Plugin() : m_inspector(0) { } -QDeclarativeInspectorPlugin::~QDeclarativeInspectorPlugin() +QtQuick2Plugin::~QtQuick2Plugin() { delete m_inspector; } -void QDeclarativeInspectorPlugin::activate() +bool QtQuick2Plugin::canHandleView(QObject *view) { - QDeclarativeInspectorService *service = QDeclarativeInspectorService::instance(); - QList<QObject*> views = service->views(); - if (views.isEmpty()) - return; + return qobject_cast<QQuickView*>(view); +} - // TODO: Support multiple views - QObject *firstView = views.first(); - if (QDeclarativeView *declarativeView = qobject_cast<QDeclarativeView*>(firstView)) - m_inspector = new QDeclarativeViewInspector(declarativeView, declarativeView); - else if (QQuickView *sgView = qobject_cast<QQuickView*>(firstView)) - m_inspector = new SGViewInspector(sgView, sgView); +void QtQuick2Plugin::activate(QObject *view) +{ + QQuickView *qtQuickView = qobject_cast<QQuickView*>(view); + Q_ASSERT(qtQuickView); + m_inspector = new SGViewInspector(qtQuickView, qtQuickView); } -void QDeclarativeInspectorPlugin::deactivate() +void QtQuick2Plugin::deactivate() { delete m_inspector; } +void QtQuick2Plugin::clientMessage(const QByteArray &message) +{ + if (m_inspector) + m_inspector->handleMessage(message); +} + +} // namespace QtQuick2 } // namespace QmlJSDebugger -Q_EXPORT_PLUGIN2(declarativeinspector, QmlJSDebugger::QDeclarativeInspectorPlugin) +Q_EXPORT_PLUGIN2(qmldbg_qtquick2, QmlJSDebugger::QtQuick2::QtQuick2Plugin) diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/qtquick2plugin.h b/src/plugins/qmltooling/qmldbg_qtquick2/qtquick2plugin.h new file mode 100644 index 0000000000..89edcad6b7 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_qtquick2/qtquick2plugin.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEINSPECTORPLUGIN_H +#define QDECLARATIVEINSPECTORPLUGIN_H + +#include <QtCore/QPointer> +#include <QtDeclarative/private/qdeclarativeinspectorinterface_p.h> + +namespace QmlJSDebugger { + +class AbstractViewInspector; + +namespace QtQuick2 { + +class QtQuick2Plugin : public QObject, public QDeclarativeInspectorInterface +{ + Q_OBJECT + Q_DISABLE_COPY(QtQuick2Plugin) + Q_INTERFACES(QDeclarativeInspectorInterface) + +public: + QtQuick2Plugin(); + ~QtQuick2Plugin(); + + // QDeclarativeInspectorInterface + bool canHandleView(QObject *view); + void activate(QObject *view); + void deactivate(); + void clientMessage(const QByteArray &message); + +private: + QPointer<AbstractViewInspector> m_inspector; +}; + +} // namespace QtQuick2 +} // namespace QmlJSDebugger + +#endif // QDECLARATIVEINSPECTORPLUGIN_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/sghighlight.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/sghighlight.cpp index 1af789d389..ab254a3fdd 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/sghighlight.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick2/sghighlight.cpp @@ -44,6 +44,7 @@ #include <QtGui/QPainter> namespace QmlJSDebugger { +namespace QtQuick2 { SGHighlight::SGHighlight(QQuickItem *item, QQuickItem *parent) : QQuickPaintedItem(parent) @@ -95,4 +96,5 @@ void SGHoverHighlight::paint(QPainter *painter) painter->drawRect(QRect(0, 0, width() - 1, height() - 1)); } +} // namespace QtQuick2 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/sghighlight.h b/src/plugins/qmltooling/qmldbg_qtquick2/sghighlight.h index 8d5659cc5d..8ba1af6576 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/sghighlight.h +++ b/src/plugins/qmltooling/qmldbg_qtquick2/sghighlight.h @@ -46,6 +46,7 @@ #include <QtDeclarative/QQuickPaintedItem> namespace QmlJSDebugger { +namespace QtQuick2 { class SGHighlight : public QQuickPaintedItem { @@ -92,6 +93,7 @@ public: void paint(QPainter *painter); }; +} // namespace QtQuick2 } // namespace QmlJSDebugger #endif // SGHIGHLIGHT_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/sgselectiontool.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/sgselectiontool.cpp index bdfc28f5ec..4d5fc3738d 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/sgselectiontool.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick2/sgselectiontool.cpp @@ -44,12 +44,12 @@ #include "sghighlight.h" #include "sgviewinspector.h" -#include <QtWidgets/QMenu> #include <QtGui/QMouseEvent> #include <QtDeclarative/QQuickView> #include <QtDeclarative/QQuickItem> namespace QmlJSDebugger { +namespace QtQuick2 { SGSelectionTool::SGSelectionTool(SGViewInspector *inspector) : AbstractTool(inspector), @@ -68,8 +68,7 @@ void SGSelectionTool::mousePressEvent(QMouseEvent *event) if (QQuickItem *item = inspector()->topVisibleItemAt(event->pos())) inspector()->setSelectedItems(QList<QQuickItem*>() << item); } else if (event->button() == Qt::RightButton) { - QList<QQuickItem*> items = inspector()->itemsAt(event->pos()); - createContextMenu(items, event->globalPos()); + // todo: Show context menu } } @@ -84,52 +83,10 @@ void SGSelectionTool::hoverMoveEvent(QMouseEvent *event) } } -void SGSelectionTool::createContextMenu(const QList<QQuickItem *> &items, QPoint pos) -{ - QMenu contextMenu; - connect(&contextMenu, SIGNAL(hovered(QAction*)), - this, SLOT(contextMenuElementHovered(QAction*))); - - const QList<QQuickItem*> selectedItems = inspector()->selectedItems(); - int shortcutKey = Qt::Key_1; - - foreach (QQuickItem *item, items) { - const QString title = inspector()->titleForItem(item); - QAction *elementAction = contextMenu.addAction(title); - elementAction->setData(QVariant::fromValue(item)); - - connect(elementAction, SIGNAL(triggered()), this, SLOT(contextMenuElementSelected())); - - if (selectedItems.contains(item)) { - QFont font = elementAction->font(); - font.setBold(true); - elementAction->setFont(font); - } - - if (shortcutKey <= Qt::Key_9) { - elementAction->setShortcut(QKeySequence(shortcutKey)); - shortcutKey++; - } - } - - contextMenu.exec(pos); -} - -void SGSelectionTool::contextMenuElementHovered(QAction *action) -{ - if (QQuickItem *item = action->data().value<QQuickItem*>()) - m_hoverHighlight->setItem(item); -} - -void SGSelectionTool::contextMenuElementSelected() -{ - if (QQuickItem *item = static_cast<QAction*>(sender())->data().value<QQuickItem*>()) - inspector()->setSelectedItems(QList<QQuickItem*>() << item); -} - SGViewInspector *SGSelectionTool::inspector() const { return static_cast<SGViewInspector*>(AbstractTool::inspector()); } +} // namespace QtQuick2 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/sgselectiontool.h b/src/plugins/qmltooling/qmldbg_qtquick2/sgselectiontool.h index 587701733d..faf75be47f 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/sgselectiontool.h +++ b/src/plugins/qmltooling/qmldbg_qtquick2/sgselectiontool.h @@ -47,10 +47,10 @@ #include <QtCore/QList> #include <QtCore/QPoint> -QT_FORWARD_DECLARE_CLASS(QAction) QT_FORWARD_DECLARE_CLASS(QQuickItem) namespace QmlJSDebugger { +namespace QtQuick2 { class SGViewInspector; class SGHoverHighlight; @@ -74,18 +74,13 @@ public: void keyPressEvent(QKeyEvent *) {} void keyReleaseEvent(QKeyEvent *) {} -private slots: - void contextMenuElementHovered(QAction *action); - void contextMenuElementSelected(); - private: - void createContextMenu(const QList<QQuickItem*> &items, QPoint pos); - SGViewInspector *inspector() const; SGHoverHighlight *m_hoverHighlight; }; +} // namespace QtQuick2 } // namespace QmlJSDebugger #endif // SGSELECTIONTOOL_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/sgviewinspector.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/sgviewinspector.cpp index 7b573cab27..06eb6eac97 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/sgviewinspector.cpp +++ b/src/plugins/qmltooling/qmldbg_qtquick2/sgviewinspector.cpp @@ -53,6 +53,7 @@ #include <cfloat> namespace QmlJSDebugger { +namespace QtQuick2 { /* * Collects all the items at the given position, from top to bottom. @@ -327,4 +328,5 @@ QString SGViewInspector::titleForItem(QQuickItem *item) const return constructedName; } +} // namespace QtQuick2 } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/sgviewinspector.h b/src/plugins/qmltooling/qmldbg_qtquick2/sgviewinspector.h index 788d6a0924..fa404a538a 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/sgviewinspector.h +++ b/src/plugins/qmltooling/qmldbg_qtquick2/sgviewinspector.h @@ -53,6 +53,7 @@ class QQuickItem; QT_END_NAMESPACE namespace QmlJSDebugger { +namespace QtQuick2 { class SGSelectionTool; class SGSelectionHighlight; @@ -105,6 +106,7 @@ private: bool m_designMode; }; +} // namespace QtQuick2 } // namespace QmlJSDebugger #endif // QSGVIEWINSPECTOR_H diff --git a/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro b/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro index c5f8f90cd6..8ab507c055 100644 --- a/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro +++ b/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro @@ -16,5 +16,3 @@ HEADERS += \ target.path += $$[QT_INSTALL_PLUGINS]/qmltooling INSTALLS += target - -symbian:TARGET.UID3=0x20031E90 diff --git a/src/plugins/qmltooling/qmltooling.pro b/src/plugins/qmltooling/qmltooling.pro index b5c8eaf487..d03ee07fc9 100644 --- a/src/plugins/qmltooling/qmltooling.pro +++ b/src/plugins/qmltooling/qmltooling.pro @@ -1,7 +1,5 @@ TEMPLATE = subdirs -SUBDIRS = qmldbg_tcp - -SUBDIRS += qmldbg_inspector - -symbian:SUBDIRS += qmldbg_ost +SUBDIRS = qmldbg_tcp +SUBDIRS += qmldbg_qtquick2 +SUBDIRS += qmldbg_qtquick1 diff --git a/src/plugins/qmltooling/qmldbg_inspector/abstracttool.cpp b/src/plugins/qmltooling/shared/abstracttool.cpp index 39ced2a9d0..39ced2a9d0 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/abstracttool.cpp +++ b/src/plugins/qmltooling/shared/abstracttool.cpp diff --git a/src/plugins/qmltooling/qmldbg_inspector/abstracttool.h b/src/plugins/qmltooling/shared/abstracttool.h index 0a216bfa83..0a216bfa83 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/abstracttool.h +++ b/src/plugins/qmltooling/shared/abstracttool.h diff --git a/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.cpp b/src/plugins/qmltooling/shared/abstractviewinspector.cpp index 1cebbd4283..796c4dce67 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.cpp +++ b/src/plugins/qmltooling/shared/abstractviewinspector.cpp @@ -61,11 +61,8 @@ AbstractViewInspector::AbstractViewInspector(QObject *parent) : m_designModeBehavior(false), m_animationPaused(false), m_slowDownFactor(1.0), - m_debugService(0) + m_debugService(QDeclarativeInspectorService::instance()) { - m_debugService = QDeclarativeInspectorService::instance(); - connect(m_debugService, SIGNAL(gotMessage(QByteArray)), - this, SLOT(handleMessage(QByteArray))); } void AbstractViewInspector::createQmlObject(const QString &qml, QObject *parent, diff --git a/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.h b/src/plugins/qmltooling/shared/abstractviewinspector.h index ee6eea5aee..a51efb0b83 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.h +++ b/src/plugins/qmltooling/shared/abstractviewinspector.h @@ -72,6 +72,8 @@ class AbstractViewInspector : public QObject public: explicit AbstractViewInspector(QObject *parent = 0); + void handleMessage(const QByteArray &message); + void createQmlObject(const QString &qml, QObject *parent, const QStringList &importList, const QString &filename = QString()); @@ -128,7 +130,6 @@ protected: virtual bool wheelEvent(QWheelEvent *event); private slots: - void handleMessage(const QByteArray &message); void sendColorChanged(const QColor &color); private: diff --git a/src/plugins/qmltooling/qmldbg_inspector/qdeclarativeinspectorprotocol.h b/src/plugins/qmltooling/shared/qdeclarativeinspectorprotocol.h index 082abeb9bd..082abeb9bd 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qdeclarativeinspectorprotocol.h +++ b/src/plugins/qmltooling/shared/qdeclarativeinspectorprotocol.h diff --git a/src/plugins/qmltooling/qmldbg_inspector/qmlinspectorconstants.h b/src/plugins/qmltooling/shared/qmlinspectorconstants.h index 5335222865..5335222865 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qmlinspectorconstants.h +++ b/src/plugins/qmltooling/shared/qmlinspectorconstants.h diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro index b0b64cdc6b..ff04487b18 100644 --- a/src/qmltest/qmltest.pro +++ b/src/qmltest/qmltest.pro @@ -19,16 +19,6 @@ feature.path = $$[QT_INSTALL_DATA]/mkspecs/features feature.files = $$PWD/features/qmltestcase.prf INSTALLS += feature -symbian { - DEFINES += QT_MAKEDLL - CONFIG += epocallowdlldata - contains(QT_EDITION, OpenSource) { - TARGET.CAPABILITY = LocalServices NetworkServices ReadUserData UserEnvironment WriteUserData - } else { - TARGET.CAPABILITY = All -Tcb - } -} - INCLUDEPATH += $$PWD/QtQuickTest INCLUDEPATH += $$PWD diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp index 601f5dcdbd..976b4d6de0 100644 --- a/src/qmltest/quicktest.cpp +++ b/src/qmltest/quicktest.cpp @@ -65,6 +65,7 @@ #include <QtGui/qtextdocument.h> #include <stdio.h> #include <QtGui/QGuiApplication> +#include <QtCore/QTranslator> QT_BEGIN_NAMESPACE @@ -75,7 +76,7 @@ class QTestRootObject : public QObject Q_PROPERTY(bool hasTestCase READ hasTestCase WRITE setHasTestCase NOTIFY hasTestCaseChanged) public: QTestRootObject(QObject *parent = 0) - : QObject(parent), hasQuit(false), m_hasTestCase(false), m_windowShown(false) {} + : QObject(parent), hasQuit(false), m_windowShown(false), m_hasTestCase(false) {} bool hasQuit:1; bool hasTestCase() const { return m_hasTestCase; } @@ -115,8 +116,10 @@ int quick_test_main(int argc, char **argv, const char *name, quick_test_viewport // -import dir Specify an import directory. // -input dir Specify the input directory for test cases. // -qtquick1 Run with QtQuick 1 rather than QtQuick 2. + // -translation file Specify the translation file. QStringList imports; QString testPath; + QString translationFile; bool qtQuick2 = true; int outargc = 1; int index = 1; @@ -132,6 +135,9 @@ int quick_test_main(int argc, char **argv, const char *name, quick_test_viewport } else if (strcmp(argv[index], "-qtquick1") == 0) { qtQuick2 = false; ++index; + } else if (strcmp(argv[index], "-translation") == 0 && (index + 1) < argc) { + translationFile = stripQuotes(QString::fromLocal8Bit(argv[index + 1])); + index += 2; } else if (outargc != index) { argv[outargc++] = argv[index++]; } else { @@ -146,6 +152,15 @@ int quick_test_main(int argc, char **argv, const char *name, quick_test_viewport QuickTestResult::parseArgs(argc, argv); QuickTestResult::setProgramName(name); + QTranslator translator; + if (!translationFile.isEmpty()) { + if (translator.load(translationFile)) { + app->installTranslator(&translator); + } else { + qWarning() << "Could not load the translation file" << translationFile; + } + } + // Determine where to look for the test data. if (testPath.isEmpty() && sourceDir) testPath = QString::fromLocal8Bit(sourceDir); @@ -198,7 +213,8 @@ int quick_test_main(int argc, char **argv, const char *name, quick_test_viewport continue; rootobj.setHasTestCase(false); - + rootobj.setWindowShown(false); + rootobj.hasQuit = false; QString path = fi.absoluteFilePath(); if (path.startsWith(QLatin1String(":/"))) view.setSource(QUrl(QLatin1String("qrc:") + path.mid(2))); diff --git a/src/qmltest/quicktest.h b/src/qmltest/quicktest.h index a83d176cfa..50c31f0460 100644 --- a/src/qmltest/quicktest.h +++ b/src/qmltest/quicktest.h @@ -48,6 +48,8 @@ #include <QtGui/qopengl.h> #endif +QT_BEGIN_HEADER + QT_BEGIN_NAMESPACE typedef QWidget *(*quick_test_viewport_create)(); @@ -94,4 +96,6 @@ Q_QUICK_TEST_EXPORT int quick_test_main(int argc, char **argv, const char *name, QT_END_NAMESPACE +QT_END_HEADER + #endif diff --git a/src/qmltest/quicktestglobal.h b/src/qmltest/quicktestglobal.h index 6d5c5214f4..54a77a64c9 100644 --- a/src/qmltest/quicktestglobal.h +++ b/src/qmltest/quicktestglobal.h @@ -44,8 +44,10 @@ #include <QtCore/qglobal.h> +QT_BEGIN_HEADER + QT_LICENSED_MODULE(QtQuickTest) -#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) +#if defined(Q_OS_WIN) # if defined(QT_NODLL) # undef QT_MAKEDLL # undef QT_DLL @@ -70,4 +72,6 @@ QT_LICENSED_MODULE(QtQuickTest) # endif #endif +QT_END_HEADER + #endif diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp index 7d8080fc08..2feef36898 100644 --- a/src/qmltest/quicktestresult.cpp +++ b/src/qmltest/quicktestresult.cpp @@ -314,7 +314,6 @@ void QuickTestResult::startLogging() { // The program name is used for logging headers and footers if it // is set. Otherwise the test case name is used. - Q_D(QuickTestResult); if (loggingStarted) return; QTestLog::startLogging(); diff --git a/src/qtquick1/graphicsitems/qdeclarativevisualitemmodel.cpp b/src/qtquick1/graphicsitems/qdeclarativevisualitemmodel.cpp index 58bd09b280..a1fe5ff508 100644 --- a/src/qtquick1/graphicsitems/qdeclarativevisualitemmodel.cpp +++ b/src/qtquick1/graphicsitems/qdeclarativevisualitemmodel.cpp @@ -1157,7 +1157,7 @@ QString QDeclarative1VisualDataModel::stringValue(int index, const QString &name QDeclarativeData *ddata = QDeclarativeData::get(data); if (ddata && ddata->propertyCache) { - QDeclarativePropertyCache::Data *prop = ddata->propertyCache->property(name); + QDeclarativePropertyData *prop = ddata->propertyCache->property(name); if (prop) { if (prop->propType == QVariant::String) { void *args[] = { &val, 0 }; diff --git a/src/qtquick1/qtquick1.pro b/src/qtquick1/qtquick1.pro index 65010fecb8..e06914f5ee 100644 --- a/src/qtquick1/qtquick1.pro +++ b/src/qtquick1/qtquick1.pro @@ -18,6 +18,8 @@ feature.path = $$[QT_INSTALL_DATA]/mkspecs/features feature.files = $$PWD/features/qtquick1.prf INSTALLS += feature +win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS + symbian { DEFINES += QT_MAKEDLL CONFIG += epocallowdlldata diff --git a/src/qtquick1/util/qdeclarativepixmapcache.cpp b/src/qtquick1/util/qdeclarativepixmapcache.cpp index 0b2e16c2ff..f4420cb3af 100644 --- a/src/qtquick1/util/qdeclarativepixmapcache.cpp +++ b/src/qtquick1/util/qdeclarativepixmapcache.cpp @@ -602,7 +602,8 @@ private: int m_unreferencedCost; int m_timerId; }; -Q_GLOBAL_STATIC(QDeclarative1PixmapStore, pixmapStore); + +Q_GLOBAL_STATIC(QDeclarative1PixmapStore, pixmapStore) QDeclarative1PixmapStore::QDeclarative1PixmapStore() : m_unreferencedPixmaps(0), m_lastUnreferencedPixmap(0), m_unreferencedCost(0), m_timerId(-1) @@ -790,6 +791,7 @@ static QDeclarative1PixmapData* createPixmapDataSync(QDeclarativeEngine *engine, return new QDeclarative1PixmapData(url, QPixmap::fromImage(image), readSize, requestSize); } } + break; case QDeclarativeImageProvider::Pixmap: { QPixmap pixmap = ep->getPixmapFromProvider(url, &readSize, requestSize); @@ -798,6 +800,10 @@ static QDeclarative1PixmapData* createPixmapDataSync(QDeclarativeEngine *engine, return new QDeclarative1PixmapData(url, pixmap, readSize, requestSize); } } + break; + case QDeclarativeImageProvider::Texture: + case QDeclarativeImageProvider::Invalid: + break; } // no matching provider, or provider has bad image type, or provider returned null image diff --git a/src/qtquick1/util/qdeclarativepropertychanges.cpp b/src/qtquick1/util/qdeclarativepropertychanges.cpp index 692d7bbb60..3ea22e83fc 100644 --- a/src/qtquick1/util/qdeclarativepropertychanges.cpp +++ b/src/qtquick1/util/qdeclarativepropertychanges.cpp @@ -174,7 +174,8 @@ public: reverseExpression = rewindExpression; } - /*virtual void copyOriginals(QDeclarative1ActionEvent *other) + virtual bool needsCopy() { return true; } + virtual void copyOriginals(QDeclarative1ActionEvent *other) { QDeclarative1ReplaceSignalHandler *rsh = static_cast<QDeclarative1ReplaceSignalHandler*>(other); saveCurrentValues(); @@ -185,7 +186,7 @@ public: ownedExpression = rsh->ownedExpression; rsh->ownedExpression = 0; } - }*/ + } virtual void rewind() { ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, rewindExpression); diff --git a/tests/auto/declarative/debugger/debugger.pro b/tests/auto/declarative/debugger/debugger.pro index 869b3a8cd6..90c5d4bc7e 100644 --- a/tests/auto/declarative/debugger/debugger.pro +++ b/tests/auto/declarative/debugger/debugger.pro @@ -6,6 +6,7 @@ PRIVATETESTS += \ qdeclarativedebugservice \ qdeclarativedebugjs \ qdeclarativeinspector \ + qdeclarativedebugtrace \ qpacketprotocol contains(QT_CONFIG, private_tests) { diff --git a/tests/auto/declarative/debugger/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp b/tests/auto/declarative/debugger/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp index 1587eee060..82e25598e9 100644 --- a/tests/auto/declarative/debugger/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp +++ b/tests/auto/declarative/debugger/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp @@ -162,7 +162,7 @@ void tst_QDeclarativeDebugClient::sequentialConnect() QCOMPARE(m_conn->state(), QAbstractSocket::UnconnectedState); // Make sure that the disconnect is actually delivered to the server - QGuiApplication::processEvents(); + QTest::qWait(100); connection2.connectToHost("127.0.0.1", PORT); QTest::ignoreMessage(QtWarningMsg, "QDeclarativeDebugServer: Connection established"); diff --git a/tests/auto/declarative/debugger/qdeclarativedebugjs/qdeclarativedebugjs.pro b/tests/auto/declarative/debugger/qdeclarativedebugjs/qdeclarativedebugjs.pro index 1cbbbc1c58..a2286ae0d5 100644 --- a/tests/auto/declarative/debugger/qdeclarativedebugjs/qdeclarativedebugjs.pro +++ b/tests/auto/declarative/debugger/qdeclarativedebugjs/qdeclarativedebugjs.pro @@ -15,6 +15,6 @@ testDataFiles.path = . DEPLOYMENT += testDataFiles -CONFIG += parallel_test +CONFIG += parallel_test insignificant_test OTHER_FILES += data/test.qml data/test.js diff --git a/tests/auto/declarative/debugger/qdeclarativedebugjs/tst_qdeclarativedebugjs.cpp b/tests/auto/declarative/debugger/qdeclarativedebugjs/tst_qdeclarativedebugjs.cpp index 73cea4e2d7..1239c43a70 100644 --- a/tests/auto/declarative/debugger/qdeclarativedebugjs/tst_qdeclarativedebugjs.cpp +++ b/tests/auto/declarative/debugger/qdeclarativedebugjs/tst_qdeclarativedebugjs.cpp @@ -1078,17 +1078,15 @@ void tst_QDeclarativeDebugJS::setBreakpointInScriptOnTimerCallback() { int sourceLine = 49; client->setBreakpoint(QLatin1String(SCRIPT), QLatin1String(QMLFILE), sourceLine, -1, true); + //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1) + sourceLine = 67; + client->setBreakpoint(QLatin1String(SCRIPT), QLatin1String(QMLFILE), sourceLine, -1, true); client->startDebugging(); QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(stopped()))); client->evaluate("timer.running = true"); client->continueDebugging(QJSDebugClient::Continue); - //void setBreakpoint(QString type, QString target, int line = -1, int column = -1, bool enabled = false, QString condition = QString(), int ignoreCount = -1) - - sourceLine = 67; - - client->setBreakpoint(QLatin1String(SCRIPT), QLatin1String(QMLFILE), sourceLine, -1, true); QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(stopped()))); QString jsonString(client->response); @@ -1376,6 +1374,7 @@ void tst_QDeclarativeDebugJS::setExceptionBreak() client->startDebugging(); QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(stopped()))); client->evaluate("root.raiseException = true"); + QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(result()))); client->continueDebugging(QJSDebugClient::Continue); QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(stopped()), 10000)); } @@ -1595,6 +1594,7 @@ void tst_QDeclarativeDebugJS::getScopes() QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(stopped()))); client->scopes(); + QEXPECT_FAIL("", "Failing after v8 integration", Abort); QVERIFY(QDeclarativeDebugTest::waitForSignal(client, SIGNAL(result()))); } diff --git a/tests/auto/declarative/debugger/qdeclarativedebugtrace/data/test.qml b/tests/auto/declarative/debugger/qdeclarativedebugtrace/data/test.qml new file mode 100644 index 0000000000..9c36e13c5b --- /dev/null +++ b/tests/auto/declarative/debugger/qdeclarativedebugtrace/data/test.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Item { + +} diff --git a/tests/auto/declarative/debugger/qdeclarativedebugtrace/qdeclarativedebugtrace.pro b/tests/auto/declarative/debugger/qdeclarativedebugtrace/qdeclarativedebugtrace.pro new file mode 100644 index 0000000000..9ddb51c66d --- /dev/null +++ b/tests/auto/declarative/debugger/qdeclarativedebugtrace/qdeclarativedebugtrace.pro @@ -0,0 +1,14 @@ +CONFIG += testcase +TARGET = tst_qdeclarativedebugtrace +macx:CONFIG -= app_bundle + +HEADERS += ../shared/debugutil_p.h + +SOURCES += tst_qdeclarativedebugtrace.cpp \ + ../shared/debugutil.cpp + +OTHER_FILES += data/test.qml + +CONFIG += parallel_test declarative_debug + +QT += core-private gui-private v8-private declarative-private network testlib diff --git a/tests/auto/declarative/debugger/qdeclarativedebugtrace/tst_qdeclarativedebugtrace.cpp b/tests/auto/declarative/debugger/qdeclarativedebugtrace/tst_qdeclarativedebugtrace.cpp new file mode 100644 index 0000000000..52271477e7 --- /dev/null +++ b/tests/auto/declarative/debugger/qdeclarativedebugtrace/tst_qdeclarativedebugtrace.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include <QLibraryInfo> + +#include "QtDeclarative/private/qdeclarativedebugtrace_p.h" +#include "../shared/debugutil_p.h" +#include "../../shared/util.h" + +#define PORT 13773 +#define STR_PORT "13773" + +class QDeclarativeDebugTraceClient : public QDeclarativeDebugClient +{ + Q_OBJECT + +public: + QDeclarativeDebugTraceClient(QDeclarativeDebugConnection *connection) + : QDeclarativeDebugClient(QLatin1String("CanvasFrameRate"), connection) + { + } + + QList<QDeclarativeDebugData> traceMessages; + + void setTraceStatus(bool enabled) { + QByteArray message; + QDataStream stream(&message, QIODevice::WriteOnly); + stream << enabled; + sendMessage(message); + } + +signals: + void complete(); + +protected: + void messageReceived(const QByteArray &message); +}; + +class tst_QDeclarativeDebugTrace : public QObject +{ + Q_OBJECT + +public: + tst_QDeclarativeDebugTrace() + : m_process(0) + , m_connection(0) + , m_client(0) + { + } + +private: + QDeclarativeDebugProcess *m_process; + QDeclarativeDebugConnection *m_connection; + QDeclarativeDebugTraceClient *m_client; + +private slots: + void init(); + void cleanup(); + + void connectWithTraceEnabled(); + void connectWithTraceDisabled(); +}; + +void QDeclarativeDebugTraceClient::messageReceived(const QByteArray &message) +{ + QByteArray msg = message; + QDataStream stream(&msg, QIODevice::ReadOnly); + + + QDeclarativeDebugData data; + data.time = -2; + data.messageType = -1; + data.detailType = -1; + data.line = -1; + data.framerate = -1; + data.animationcount = -1; + + stream >> data.time >> data.messageType; + + QVERIFY(data.time >= -1); + + switch (data.messageType) { + case (QDeclarativeDebugTrace::Event): { + stream >> data.detailType; + + switch (data.detailType) { + case QDeclarativeDebugTrace::AnimationFrame: { + stream >> data.framerate >> data.animationcount; + QVERIFY(data.framerate != -1); + QVERIFY(data.animationcount != -1); + break; + } + case QDeclarativeDebugTrace::FramePaint: + case QDeclarativeDebugTrace::Mouse: + case QDeclarativeDebugTrace::Key: + case QDeclarativeDebugTrace::StartTrace: + case QDeclarativeDebugTrace::EndTrace: + break; + default: { + QString failMsg = QString("Unknown event type:") + data.detailType; + QFAIL(qPrintable(failMsg)); + break; + } + } + break; + } + case QDeclarativeDebugTrace::Complete: { + emit complete(); + QVERIFY(stream.atEnd()); + return; + } + case QDeclarativeDebugTrace::RangeStart: { + stream >> data.detailType; + QVERIFY(data.detailType >= 0 && data.detailType < QDeclarativeDebugTrace::MaximumRangeType); + break; + } + case QDeclarativeDebugTrace::RangeEnd: { + stream >> data.detailType; + QVERIFY(data.detailType >= 0 && data.detailType < QDeclarativeDebugTrace::MaximumRangeType); + break; + } + case QDeclarativeDebugTrace::RangeData: { + stream >> data.detailType >> data.detailData; + QVERIFY(data.detailType >= 0 && data.detailType < QDeclarativeDebugTrace::MaximumRangeType); + break; + } + case QDeclarativeDebugTrace::RangeLocation: { + stream >> data.detailType >> data.detailData >> data.line; + QVERIFY(data.detailType >= 0 && data.detailType < QDeclarativeDebugTrace::MaximumRangeType); + QVERIFY(data.line >= -2); + break; + } + default: + QString failMsg = QString("Unknown message type:") + data.messageType; + QFAIL(qPrintable(failMsg)); + break; + } + QVERIFY(stream.atEnd()); + traceMessages.append(data); +} + +void tst_QDeclarativeDebugTrace::init() +{ + const QString executable = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene"; + QStringList arguments; + arguments << QString("-qmljsdebugger=port:"STR_PORT",block"); + arguments << QString(TESTDATA(QLatin1String("test.qml"))); + + m_process = new QDeclarativeDebugProcess(executable); + m_process->start(QStringList() << arguments); + if (!m_process->waitForSessionStart()) { + QString failMsg = QString("Could not launch app '%1'.\nApplication output:\n%2").arg( + executable, m_process->output()); + QFAIL(qPrintable(failMsg)); + } + + QDeclarativeDebugConnection *m_connection = new QDeclarativeDebugConnection(); + m_client = new QDeclarativeDebugTraceClient(m_connection); + + m_connection->connectToHost(QLatin1String("127.0.0.1"), PORT); +} + +void tst_QDeclarativeDebugTrace::cleanup() +{ + delete m_process; + delete m_connection; + delete m_client; +} + +void tst_QDeclarativeDebugTrace::connectWithTraceEnabled() +{ + QTRY_COMPARE(m_client->status(), QDeclarativeDebugClient::Enabled); + m_client->setTraceStatus(true); + m_client->setTraceStatus(false); + if (!QDeclarativeDebugTest::waitForSignal(m_client, SIGNAL(complete()))) { + QString failMsg + = QString("No trace received in time. App output: \n\n").arg(m_process->output()); + QFAIL(qPrintable(failMsg)); + } + + // must start with "StartTrace" + QCOMPARE(m_client->traceMessages.first().messageType, (int)QDeclarativeDebugTrace::Event); + QCOMPARE(m_client->traceMessages.first().detailType, (int)QDeclarativeDebugTrace::StartTrace); + + // must end with "EndTrace" + QCOMPARE(m_client->traceMessages.last().messageType, (int)QDeclarativeDebugTrace::Event); + QCOMPARE(m_client->traceMessages.last().detailType, (int)QDeclarativeDebugTrace::EndTrace); +} + +void tst_QDeclarativeDebugTrace::connectWithTraceDisabled() +{ + QTRY_COMPARE(m_client->status(), QDeclarativeDebugClient::Enabled); + m_client->setTraceStatus(false); + m_client->setTraceStatus(true); + m_client->setTraceStatus(false); + if (!QDeclarativeDebugTest::waitForSignal(m_client, SIGNAL(complete()))) { + QString failMsg + = QString("No trace received in time. App output: \n\n").arg(m_process->output()); + QFAIL(qPrintable(failMsg)); + } + + // must start with "StartTrace" + QCOMPARE(m_client->traceMessages.first().messageType, (int)QDeclarativeDebugTrace::Event); + QCOMPARE(m_client->traceMessages.first().detailType, (int)QDeclarativeDebugTrace::StartTrace); + + // must end with "EndTrace" + QCOMPARE(m_client->traceMessages.last().messageType, (int)QDeclarativeDebugTrace::Event); + QCOMPARE(m_client->traceMessages.last().detailType, (int)QDeclarativeDebugTrace::EndTrace); +} + +QTEST_MAIN(tst_QDeclarativeDebugTrace) + +#include "tst_qdeclarativedebugtrace.moc" diff --git a/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.cpp b/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.cpp index fe079d645e..5545f8e046 100644 --- a/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.cpp +++ b/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.cpp @@ -45,8 +45,7 @@ #include <QDebug> #include <QThread> -#include "../../../../src/plugins/qmltooling/qmldbg_inspector/qdeclarativeinspectorprotocol.h" -#include "../../../../shared/util.h" +#include "../../../../../src/plugins/qmltooling/shared/qdeclarativeinspectorprotocol.h" #include "../shared/debugutil_p.h" using namespace QmlJSDebugger; diff --git a/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.pro b/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.pro index 26e4208f59..63230c05a0 100644 --- a/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.pro +++ b/tests/auto/declarative/debugger/qdeclarativeinspector/tst_qdeclarativeinspector.pro @@ -1,5 +1,5 @@ CONFIG += testcase -TARGET = tst_qdeclarativinspector +TARGET = tst_qdeclarativeinspector macx:CONFIG -= app_bundle HEADERS += ../shared/debugutil_p.h diff --git a/tests/auto/declarative/debugger/shared/debugutil.cpp b/tests/auto/declarative/debugger/shared/debugutil.cpp index 2c769be53f..154e20bdb3 100644 --- a/tests/auto/declarative/debugger/shared/debugutil.cpp +++ b/tests/auto/declarative/debugger/shared/debugutil.cpp @@ -148,18 +148,24 @@ bool QDeclarativeDebugProcess::waitForSessionStart() QString QDeclarativeDebugProcess::output() const { - return m_outputBuffer; + return m_output; } void QDeclarativeDebugProcess::processAppOutput() { m_mutex.lock(); - const QString appOutput = m_process.readAll(); - static QRegExp newline("[\n\r]{1,2}"); - QStringList lines = appOutput.split(newline); - foreach (const QString &line, lines) { - if (line.isEmpty()) - continue; + + QString newOutput = m_process.readAll(); + m_output.append(newOutput); + m_outputBuffer.append(newOutput); + + while (true) { + const int nlIndex = m_outputBuffer.indexOf(QLatin1Char('\n')); + if (nlIndex < 0) // no further complete lines + break; + const QString line = m_outputBuffer.left(nlIndex); + m_outputBuffer = m_outputBuffer.right(m_outputBuffer.size() - nlIndex - 1); + if (line.startsWith("Qml debugging is enabled")) // ignore continue; if (line.startsWith("QDeclarativeDebugServer:")) { @@ -172,7 +178,6 @@ void QDeclarativeDebugProcess::processAppOutput() continue; } } - m_outputBuffer.append(appOutput); } m_mutex.unlock(); } diff --git a/tests/auto/declarative/debugger/shared/debugutil_p.h b/tests/auto/declarative/debugger/shared/debugutil_p.h index 99a482cf2a..24b7e252cb 100644 --- a/tests/auto/declarative/debugger/shared/debugutil_p.h +++ b/tests/auto/declarative/debugger/shared/debugutil_p.h @@ -113,6 +113,7 @@ private: QString m_executable; QProcess m_process; QString m_outputBuffer; + QString m_output; QTimer m_timer; QEventLoop m_eventLoop; QMutex m_mutex; diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index cd4309486f..f2f127ffc1 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -62,6 +62,7 @@ PRIVATETESTS += \ !contains(QT_CONFIG,xmlpatterns):PRIVATETESTS -= qdeclarativexmllistmodel QUICKTESTS = \ + qquickanchors \ qquickanimatedimage \ qquickborderimage \ qquickcanvas \ @@ -77,10 +78,12 @@ QUICKTESTS = \ qquicklistview \ qquickloader \ qquickmousearea \ + qquickmultipointtoucharea \ qquickpathview \ qquickpincharea \ qquickpositioners \ qquickrepeater \ + qquickspriteimage \ qquicktext \ qquicktextedit \ qquicktextinput \ diff --git a/tests/auto/declarative/examples/examples.pro b/tests/auto/declarative/examples/examples.pro index e68a93c6d5..4ae24bb1a4 100644 --- a/tests/auto/declarative/examples/examples.pro +++ b/tests/auto/declarative/examples/examples.pro @@ -7,7 +7,5 @@ DEFINES += SRCDIR=\\\"$$PWD\\\" CONFIG += parallel_test #temporary -CONFIG += insignificant_test +CONFIG += insignificant_test #QTBUG-22672 QT += core-private gui-private declarative-private qtquick1-private widgets-private v8-private testlib - -qpa:CONFIG+=insignificant_test # QTBUG-20990, aborts diff --git a/tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp b/tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp index 6c375a5adf..b355a8097a 100644 --- a/tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp +++ b/tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp @@ -806,9 +806,11 @@ void tst_qdeclarativeanimations::attached() { QDeclarativeEngine engine; - QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("attached.qml"))); - QTest::ignoreMessage(QtDebugMsg, "off"); - QTest::ignoreMessage(QtDebugMsg, "on"); + QUrl url(QUrl::fromLocalFile(TESTDATA("attached.qml"))); + QDeclarativeComponent c(&engine, url); + QString messageFormat = QString(QLatin1String("%1 (%2:%3)")); + QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("off")).arg(url.toString()).arg(24).toLatin1()); + QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("on")).arg(url.toString()).arg(20).toLatin1()); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); QVERIFY(rect); } diff --git a/tests/auto/declarative/qdeclarativeapplication/tst_qdeclarativeapplication.cpp b/tests/auto/declarative/qdeclarativeapplication/tst_qdeclarativeapplication.cpp index db345e38fd..72313ab054 100644 --- a/tests/auto/declarative/qdeclarativeapplication/tst_qdeclarativeapplication.cpp +++ b/tests/auto/declarative/qdeclarativeapplication/tst_qdeclarativeapplication.cpp @@ -67,8 +67,6 @@ tst_qdeclarativeapplication::tst_qdeclarativeapplication() void tst_qdeclarativeapplication::active() { - QSKIP("QTBUG-21573"); - QDeclarativeComponent component(&engine); component.setData("import QtQuick 2.0; Item { property bool active: Qt.application.active }", QUrl::fromLocalFile("")); QQuickItem *item = qobject_cast<QQuickItem *>(component.create()); @@ -84,23 +82,28 @@ void tst_qdeclarativeapplication::active() view.show(); view.requestActivateWindow(); QTest::qWait(50); + QEXPECT_FAIL("", "QTBUG-21573", Abort); QTRY_COMPARE(view.status(), QQuickView::Ready); QCOMPARE(item->property("active").toBool(), QGuiApplication::activeWindow() != 0); - // not active again +#if 0 + // QGuiApplication has no equivalent of setActiveWindow(0). QTBUG-21573 + // Is this different to clearing the active state of the window or can it be removed? + // On Mac, setActiveWindow(0) on mac does not deactivate the current application, + // must switch to a different app or hide the current app to trigger this // on mac, setActiveWindow(0) on mac does not deactivate the current application // (you have to switch to a different app or hide the current app to trigger this) -#if !defined(Q_WS_MAC) -// QTBUG-21573 -// QGuiApplication::setActiveWindow(0); + + // not active again + QGuiApplication::setActiveWindow(0); QVERIFY(!item->property("active").toBool()); QCOMPARE(item->property("active").toBool(), QGuiApplication::activeWindow() != 0); #endif + } void tst_qdeclarativeapplication::layoutDirection() { - QSKIP("QTBUG-21573"); QDeclarativeComponent component(&engine); component.setData("import QtQuick 2.0; Item { property bool layoutDirection: Qt.application.layoutDirection }", QUrl::fromLocalFile("")); @@ -114,6 +117,7 @@ void tst_qdeclarativeapplication::layoutDirection() // mirrored QGuiApplication::setLayoutDirection(Qt::RightToLeft); + QEXPECT_FAIL("", "QTBUG-21573", Abort); QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::RightToLeft); // not mirrored again diff --git a/tests/auto/declarative/qdeclarativebehaviors/data/startOnCompleted.qml b/tests/auto/declarative/qdeclarativebehaviors/data/startOnCompleted.qml new file mode 100644 index 0000000000..fdc3779a5c --- /dev/null +++ b/tests/auto/declarative/qdeclarativebehaviors/data/startOnCompleted.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +Rectangle { + width: 400 + height: 400 + + Rectangle { + id: innerRect + width: 100; height: 100 + color: "green" + Behavior on x { NumberAnimation {} } + } + + Component.onCompleted: innerRect.x = 100 +} diff --git a/tests/auto/declarative/qdeclarativebehaviors/data/valueType.qml b/tests/auto/declarative/qdeclarativebehaviors/data/valueType.qml new file mode 100644 index 0000000000..7bc8297dc7 --- /dev/null +++ b/tests/auto/declarative/qdeclarativebehaviors/data/valueType.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 +Rectangle { + width: 400 + height: 400 + + color.r: 1 + color.g: 0 + color.b: 1 + + Behavior on color.r { NumberAnimation { duration: 500; } } + + function changeR() { color.r = 0 } +} diff --git a/tests/auto/declarative/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp b/tests/auto/declarative/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp index 38a07eb3d4..35f8b6219d 100644 --- a/tests/auto/declarative/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp +++ b/tests/auto/declarative/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp @@ -66,6 +66,7 @@ private slots: void replaceBinding(); //void transitionOverrides(); void group(); + void valueType(); void emptyBehavior(); void explicitSelection(); void nonSelectingBehavior(); @@ -77,6 +78,7 @@ private slots: void runningTrue(); void sameValue(); void delayedRegistration(); + void startOnCompleted(); }; void tst_qdeclarativebehaviors::simpleBehavior() @@ -236,6 +238,19 @@ void tst_qdeclarativebehaviors::group() } } +void tst_qdeclarativebehaviors::valueType() +{ + QDeclarativeEngine engine; + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("valueType.qml"))); + QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); + QVERIFY(rect); + + //QTBUG-20827 + QCOMPARE(rect->color(), QColor::fromRgb(255,0,255)); + + delete rect; +} + void tst_qdeclarativebehaviors::emptyBehavior() { QDeclarativeEngine engine; @@ -433,6 +448,25 @@ void tst_qdeclarativebehaviors::delayedRegistration() QTRY_COMPARE(innerRect->property("x").toInt(), int(100)); } +//QTBUG-22555 +void tst_qdeclarativebehaviors::startOnCompleted() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, QUrl::fromLocalFile(TESTDATA("startOnCompleted.qml"))); + QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); + QVERIFY(rect != 0); + + QQuickItem *innerRect = rect->findChild<QQuickRectangle*>(); + QVERIFY(innerRect != 0); + + QCOMPARE(innerRect->property("x").toInt(), int(0)); + + QTRY_COMPARE(innerRect->property("x").toInt(), int(100)); + + delete rect; +} + QTEST_MAIN(tst_qdeclarativebehaviors) #include "tst_qdeclarativebehaviors.moc" diff --git a/tests/auto/declarative/qdeclarativecontext/data/RefreshExpressionsType.qml b/tests/auto/declarative/qdeclarativecontext/data/RefreshExpressionsType.qml new file mode 100644 index 0000000000..b7c3427c85 --- /dev/null +++ b/tests/auto/declarative/qdeclarativecontext/data/RefreshExpressionsType.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + property var dummy: countCommand.doCommand(); +} diff --git a/tests/auto/declarative/qdeclarativecontext/data/refreshExpressions.qml b/tests/auto/declarative/qdeclarativecontext/data/refreshExpressions.qml new file mode 100644 index 0000000000..01e503f8dc --- /dev/null +++ b/tests/auto/declarative/qdeclarativecontext/data/refreshExpressions.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +QtObject { + property variant v1: RefreshExpressionsType {} + property variant v2: RefreshExpressionsType {} +} diff --git a/tests/auto/declarative/qdeclarativecontext/data/refreshExpressionsRootContext.qml b/tests/auto/declarative/qdeclarativecontext/data/refreshExpressionsRootContext.qml new file mode 100644 index 0000000000..bd82cd9552 --- /dev/null +++ b/tests/auto/declarative/qdeclarativecontext/data/refreshExpressionsRootContext.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +QtObject { + property var dummy: countCommand.doCommand(), unresolvedName +} + diff --git a/tests/auto/declarative/qdeclarativecontext/qdeclarativecontext.pro b/tests/auto/declarative/qdeclarativecontext/qdeclarativecontext.pro index 65af53a45d..5e48bec033 100644 --- a/tests/auto/declarative/qdeclarativecontext/qdeclarativecontext.pro +++ b/tests/auto/declarative/qdeclarativecontext/qdeclarativecontext.pro @@ -3,6 +3,10 @@ TARGET = tst_qdeclarativecontext SOURCES += tst_qdeclarativecontext.cpp macx:CONFIG -= app_bundle +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + CONFIG += parallel_test -QT += core-private gui-private declarative-private testlib +QT += core-private gui-private declarative-private testlib v8-private diff --git a/tests/auto/declarative/qdeclarativecontext/tst_qdeclarativecontext.cpp b/tests/auto/declarative/qdeclarativecontext/tst_qdeclarativecontext.cpp index c241acac05..68599a2e83 100644 --- a/tests/auto/declarative/qdeclarativecontext/tst_qdeclarativecontext.cpp +++ b/tests/auto/declarative/qdeclarativecontext/tst_qdeclarativecontext.cpp @@ -45,6 +45,18 @@ #include <QDeclarativeContext> #include <QDeclarativeComponent> #include <QDeclarativeExpression> +#include <private/qdeclarativecontext_p.h> +#include "../shared/util.h" + +inline QUrl TEST_FILE(const QString &filename) +{ + return QUrl::fromLocalFile(TESTDATA(filename)); +} + +inline QUrl TEST_FILE(const char *filename) +{ + return TEST_FILE(QLatin1String(filename)); +} class tst_qdeclarativecontext : public QObject { @@ -64,6 +76,10 @@ private slots: void readOnlyContexts(); void nameForObject(); + void refreshExpressions(); + void refreshExpressionsCrash(); + void refreshExpressionsRootContext(); + private: QDeclarativeEngine engine; }; @@ -490,6 +506,144 @@ void tst_qdeclarativecontext::nameForObject() delete o; } +class DeleteCommand : public QObject +{ +Q_OBJECT +public: + DeleteCommand() : object(0) {} + + QObject *object; + +public slots: + void doCommand() { if (object) delete object; object = 0; } +}; + +// Calling refresh expressions would crash if an expression or context was deleted during +// the refreshing +void tst_qdeclarativecontext::refreshExpressionsCrash() +{ + { + QDeclarativeEngine engine; + + DeleteCommand command; + engine.rootContext()->setContextProperty("deleteCommand", &command); + // We use a fresh context here to bypass any root-context optimizations in + // the engine + QDeclarativeContext ctxt(engine.rootContext()); + + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 2.0; QtObject { property var binding: deleteCommand.doCommand() }", QUrl()); + QVERIFY(component.isReady()); + + QObject *o1 = component.create(&ctxt); + QObject *o2 = component.create(&ctxt); + + command.object = o2; + + QDeclarativeContextData::get(&ctxt)->refreshExpressions(); + + delete o1; + } + { + QDeclarativeEngine engine; + + DeleteCommand command; + engine.rootContext()->setContextProperty("deleteCommand", &command); + // We use a fresh context here to bypass any root-context optimizations in + // the engine + QDeclarativeContext ctxt(engine.rootContext()); + + QDeclarativeComponent component(&engine); + component.setData("import QtQuick 2.0; QtObject { property var binding: deleteCommand.doCommand() }", QUrl()); + QVERIFY(component.isReady()); + + QObject *o1 = component.create(&ctxt); + QObject *o2 = component.create(&ctxt); + + command.object = o1; + + QDeclarativeContextData::get(&ctxt)->refreshExpressions(); + + delete o2; + } +} + +class CountCommand : public QObject +{ +Q_OBJECT +public: + CountCommand() : count(0) {} + + int count; + +public slots: + void doCommand() { ++count; } +}; + + +// Test that calling refresh expressions causes all the expressions to refresh +void tst_qdeclarativecontext::refreshExpressions() +{ + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine, TEST_FILE("refreshExpressions.qml")); + QDeclarativeComponent component2(&engine, TEST_FILE("RefreshExpressionsType.qml")); + + CountCommand command; + engine.rootContext()->setContextProperty("countCommand", &command); + + // We use a fresh context here to bypass any root-context optimizations in + // the engine + QDeclarativeContext context(engine.rootContext()); + QDeclarativeContext context2(&context); + + QObject *o1 = component.create(&context); + QObject *o2 = component.create(&context2); + QObject *o3 = component2.create(&context); + + QCOMPARE(command.count, 5); + + QDeclarativeContextData::get(&context)->refreshExpressions(); + + QCOMPARE(command.count, 10); + + delete o3; + delete o2; + delete o1; +} + +// Test that updating the root context, only causes expressions in contexts with an +// unresolved name to reevaluate +void tst_qdeclarativecontext::refreshExpressionsRootContext() +{ + QDeclarativeEngine engine; + + CountCommand command; + engine.rootContext()->setContextProperty("countCommand", &command); + + QDeclarativeComponent component(&engine, TEST_FILE("refreshExpressions.qml")); + QDeclarativeComponent component2(&engine, TEST_FILE("refreshExpressionsRootContext.qml")); + + QDeclarativeContext context(engine.rootContext()); + QDeclarativeContext context2(engine.rootContext()); + + QString warning = component2.url().toString() + QLatin1String(":4: ReferenceError: Can't find variable: unresolvedName"); + + QObject *o1 = component.create(&context); + + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); + QObject *o2 = component2.create(&context2); + + QCOMPARE(command.count, 3); + + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); + QDeclarativeContextData::get(engine.rootContext())->refreshExpressions(); + + QCOMPARE(command.count, 4); + + delete o2; + delete o1; +} + QTEST_MAIN(tst_qdeclarativecontext) #include "tst_qdeclarativecontext.moc" diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/SequenceConversionComponent.qml b/tests/auto/declarative/qdeclarativeecmascript/data/SequenceConversionComponent.qml new file mode 100644 index 0000000000..0c7f60b062 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/SequenceConversionComponent.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +MySequenceConversionObject { + id: sccmsco + objectName: "sccmsco" +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/deleteWhileBindingRunning.qml b/tests/auto/declarative/qdeclarativeecmascript/data/deleteWhileBindingRunning.qml new file mode 100644 index 0000000000..b5cc59e2c0 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/deleteWhileBindingRunning.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +MyDeleteObject { + property int result: nestedObject.intProperty + deleteNestedObject +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/forInLoop.qml b/tests/auto/declarative/qdeclarativeecmascript/data/forInLoop.qml new file mode 100644 index 0000000000..f14367f177 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/forInLoop.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +QtObject { + property list<QtObject> objects + objects: [QtObject { objectName: "obj1" }, QtObject { objectName: "obj2" }, QtObject { objectName: "obj3" }] + property string listResult + + function listProperty() { + for (var i in objects) + listResult += i + "=" + objects[i].objectName + "|" + } +} + diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/nonNotifyable.qml b/tests/auto/declarative/qdeclarativeecmascript/data/nonNotifyable.qml new file mode 100644 index 0000000000..2b8b113c34 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/nonNotifyable.qml @@ -0,0 +1,6 @@ +import Qt.test 1.0 + +MyQmlObject { + id: root + property int test: root.value +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_20344.qml b/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_20344.qml new file mode 100644 index 0000000000..f490848caf --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/qtbug_20344.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +MyQmlObject { + Component.onCompleted: v8function() +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/readonlyDeclaration.qml b/tests/auto/declarative/qdeclarativeecmascript/data/readonlyDeclaration.qml new file mode 100644 index 0000000000..5377d2dcbf --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/readonlyDeclaration.qml @@ -0,0 +1,45 @@ +import QtQuick 2.0 + +QtObject { + property int dummy: 13 + + readonly property int test1: 19 + readonly property int test2: dummy * 49 + readonly property alias test3: other.test + + property bool test: false + + property var dummyObj: QtObject { + id: other + property int test: 9 + } + + Component.onCompleted: { + if (test1 != 19) return; + if (test2 != 637) return; + if (test3 != 9) return; + + var caught = false; + + caught = false; + try { test1 = 13 } catch (e) { caught = true; } + if (!caught) return; + + caught = false; + try { test2 = 13 } catch (e) { caught = true; } + if (!caught) return; + + caught = false; + try { test3 = 13 } catch (e) { caught = true; } + if (!caught) return; + + other.test = 13; + dummy = 9; + + if (test1 != 19) return; + if (test2 != 441) return; + if (test3 != 13) return; + + test = true; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.array.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.array.qml new file mode 100644 index 0000000000..5eaa225708 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.array.qml @@ -0,0 +1,152 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + property bool success: false + + property variant intList + property variant qrealList + property variant boolList + property variant stringList + + function indexedAccess() { + intList = msco.intListProperty; + var jsIntList = msco.intListProperty; + qrealList = msco.qrealListProperty; + var jsQrealList = msco.qrealListProperty; + boolList = msco.boolListProperty; + var jsBoolList = msco.boolListProperty; + stringList = msco.stringListProperty; + var jsStringList = msco.stringListProperty; + + // Three cases: direct property modification, variant copy modification, js var reference modification. + // Only the first and third should "write back" to the original QObject Q_PROPERTY; the second one + // should have no effect whatsoever to maintain "property variant" semantics (see e.g., valuetype). + success = true; + + msco.intListProperty[1] = 33; + if (msco.intListProperty[1] != 33) success = false; // ensure write back + intList[1] = 44; + if (intList[1] == 44) success = false; // ensure no effect + jsIntList[1] = 55; + if (jsIntList[1] != 55 + || jsIntList[1] != msco.intListProperty[1]) success = false; // ensure write back + + msco.qrealListProperty[1] = 33.3; + if (msco.qrealListProperty[1] != 33.3) success = false; // ensure write back + qrealList[1] = 44.4; + if (qrealList[1] == 44.4) success = false; // ensure no effect + jsQrealList[1] = 55.5; + if (jsQrealList[1] != 55.5 + || jsQrealList[1] != msco.qrealListProperty[1]) success = false; // ensure write back + + msco.boolListProperty[1] = true; + if (msco.boolListProperty[1] != true) success = false; // ensure write back + boolList[1] = true; + if (boolList[1] != false) success = false; // ensure no effect + jsBoolList[1] = false; + if (jsBoolList[1] != false + || jsBoolList[1] != msco.boolListProperty[1]) success = false; // ensure write back + + msco.stringListProperty[1] = "changed"; + if (msco.stringListProperty[1] != "changed") success = false; // ensure write back + stringList[1] = "changed"; + if (stringList[1] != "second") success = false; // ensure no effect + jsStringList[1] = "different"; + if (jsStringList[1] != "different" + || jsStringList[1] != msco.stringListProperty[1]) success = false; // ensure write back + } + + function arrayOperations() { + success = true; + var expected = 0; + var expectedStr = ""; + + // ecma262r3 defines array as implementing Length and Put. Test put here. + msco.intListProperty.asdf = 5; // shouldn't work, only indexes are valid names. + if (msco.intListProperty.asdf == 5) success = false; + msco.intListProperty[3] = 38; // should work. + if (msco.intListProperty[3] != 38) success = false; + msco.intListProperty[199] = 200; // should work, and should set length to 200. + if (msco.intListProperty[199] != 200) success = false; + if (msco.intListProperty.length != 200) success = false; + + // other operations are defined on the array prototype; see if they work. + msco.intListProperty = [ 0, 1, 2, 3, 4, 5, 6, 7 ]; + msco.intListProperty.splice(1,3, 33, 44, 55, 66); + expected = [ 0, 33, 44, 55, 66, 4, 5, 6, 7 ]; + if (msco.intListProperty.toString() != expected.toString()) success = false; + + msco.qrealListProperty = [ 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1 ]; + msco.qrealListProperty.splice(1,3, 33.33, 44.44, 55.55, 66.66); + expected = [ 0.1, 33.33, 44.44, 55.55, 66.66, 4.1, 5.1, 6.1, 7.1 ]; + if (msco.qrealListProperty.toString() != expected.toString()) success = false; + + msco.boolListProperty = [ false, true, true, false, false, true, false, true ]; + msco.boolListProperty.splice(1,3, false, true, false, false); + expected = [ false, false, true, false, false, false, true, false, true ]; + if (msco.boolListProperty.toString() != expected.toString()) success = false; + + msco.stringListProperty = [ "one", "two", "three", "four", "five", "six", "seven", "eight" ]; + msco.stringListProperty.splice(1,3, "nine", "ten", "eleven", "twelve"); + expected = [ "one", "nine", "ten", "eleven", "twelve", "five", "six", "seven", "eight" ]; + if (msco.stringListProperty.toString() != expected.toString()) success = false; + } + + property variant variantList: [ 1, 2, 3, 4, 5 ]; + property variant variantList2: [ 1, 2, 3, 4, 5 ]; + function testEqualitySemantics() { + // ensure equality semantics match JS array equality semantics + success = true; + + msco.intListProperty = [ 1, 2, 3, 4, 5 ]; + msco.intListProperty2 = [ 1, 2, 3, 4, 5 ]; + var jsIntList = [ 1, 2, 3, 4, 5 ]; + var jsIntList2 = [ 1, 2, 3, 4, 5 ]; + + if (jsIntList != jsIntList) success = false; + if (jsIntList == jsIntList2) success = false; + if (jsIntList == msco.intListProperty) success = false; + if (jsIntList == variantList) success = false; + + if (msco.intListProperty != msco.intListProperty) success = false; + if (msco.intListProperty == msco.intListProperty2) success = false; + if (msco.intListProperty == jsIntList) success = false; + if (msco.intListProperty == variantList) success = false; + + if (variantList == variantList) return false; + if (variantList == variantList2) return false; + if (variantList == msco.intListProperty) return false; + if (variantList == jsIntList) return false; + + if ((jsIntList == jsIntList2) != (jsIntList == msco.intListProperty)) success = false; + if ((jsIntList == jsIntList2) != (msco.intListProperty == msco.intListProperty2)) success = false; + if ((jsIntList == jsIntList) != (msco.intListProperty == msco.intListProperty)) success = false; + if ((jsIntList == variantList) != (msco.intListProperty == variantList)) success = false; + if ((variantList == jsIntList) != (variantList == msco.intListProperty)) success = false; + if ((msco.intListProperty == variantList) != (variantList == msco.intListProperty)) success = false; + } + + property bool referenceDeletion: false + function testReferenceDeletion() { + referenceDeletion = true; + var testObj = msco.generateTestObject(); + testObj.intListProperty = [1, 2, 3, 4, 5]; + var testSequence = testObj.intListProperty; + var prevString = testSequence.toString(); + var prevValueOf = testSequence.valueOf(); + var prevLength = testSequence.length; + msco.deleteTestObject(testObj); // delete referenced object. + if (testSequence.toString() == prevString) referenceDeletion = false; + if (testSequence.valueOf() == prevValueOf) referenceDeletion = false; + if (testSequence.length == prevLength) referenceDeletion = false; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.bindings.error.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.bindings.error.qml new file mode 100644 index 0000000000..9c87dd293e --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.bindings.error.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + intListProperty: [ 1, 2, 3, 6, 7 ] + } + + MySequenceConversionObject { + id: mscoTwo + objectName: "mscoTwo" + boolListProperty: msco.intListProperty + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.bindings.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.bindings.qml new file mode 100644 index 0000000000..8d83e9f9f5 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.bindings.qml @@ -0,0 +1,28 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + intListProperty: [ 1, 2, 3, 6, 7 ] + } + + MySequenceConversionObject { + id: mscoTwo + objectName: "mscoTwo" + intListProperty: msco.intListProperty + } + + property variant boundSequence: msco.intListProperty + property int boundElement: msco.intListProperty[3] + property variant boundSequenceTwo: mscoTwo.intListProperty + + Component.onCompleted: { + msco.intListProperty[3] = 12; + mscoTwo.intListProperty[4] = 14; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.copy.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.copy.qml new file mode 100644 index 0000000000..f6614dad0c --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.copy.qml @@ -0,0 +1,160 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + property bool success: true + + property variant intList + property variant qrealList + property variant boolList + property variant stringList + property variant urlList + property variant qstringList + + // this test ensures that the "copy resource" codepaths work + function testCopySequences() { + success = true; + + // create "copy resource" sequences + var jsIntList = msco.generateIntSequence(); + var jsQrealList = msco.generateQrealSequence(); + var jsBoolList = msco.generateBoolSequence(); + var jsStringList = msco.generateStringSequence(); + var jsUrlList = msco.generateUrlSequence(); + var jsQStringList = msco.generateQStringSequence(); + + if (jsIntList.toString() != [1, 2, 3].toString()) + success = false; + if (jsQrealList.toString() != [1.1, 2.2, 3.3].toString()) + success = false; + if (jsBoolList.toString() != [true, false, true].toString()) + success = false; + if (jsStringList.toString() != ["one", "two", "three"].toString()) + success = false; + if (jsUrlList.toString() != ["http://www.example1.com", "http://www.example2.com", "http://www.example3.com"].toString()) + success = false; + if (jsQStringList.toString() != ["one", "two", "three"].toString()) + success = false; + + // copy the sequence; should result in a new copy + intList = jsIntList; + qrealList = jsQrealList; + boolList = jsBoolList; + stringList = jsStringList; + urlList = jsUrlList; + qstringList = jsQStringList; + + // these operations shouldn't modify either variables - because + // we don't handle writing to the intermediate variant at list[index] + // for variant properties. + intList[1] = 8; + qrealList[1] = 8.8; + boolList[1] = true; + stringList[1] = "eight"; + urlList[1] = "http://www.example8.com"; + qstringList[1] = "eight"; + + if (jsIntList[1] == 8) + success = false; + if (jsQrealList[1] == 8.8) + success = false; + if (jsBoolList[1] == true) + success = false; + if (jsStringList[1] == "eight") + success = false; + if (jsUrlList[1] == "http://www.example8.com") + success = false; + if (jsQStringList[1] == "eight") + success = false; + + // assign a "copy resource" sequence to a QObject Q_PROPERTY + msco.intListProperty = intList; + msco.qrealListProperty = qrealList; + msco.boolListProperty = boolList; + msco.stringListProperty = stringList; + msco.urlListProperty = urlList; + msco.qstringListProperty = qstringList; + + if (msco.intListProperty.toString() != [1, 2, 3].toString()) + success = false; + if (msco.qrealListProperty.toString() != [1.1, 2.2, 3.3].toString()) + success = false; + if (msco.boolListProperty.toString() != [true, false, true].toString()) + success = false; + if (msco.stringListProperty.toString() != ["one", "two", "three"].toString()) + success = false; + if (msco.urlListProperty.toString() != ["http://www.example1.com", "http://www.example2.com", "http://www.example3.com"].toString()) + success = false; + if (msco.qstringListProperty.toString() != ["one", "two", "three"].toString()) + success = false; + + // now modify the QObject Q_PROPERTY (reference resource) sequences - shouldn't modify the copy resource sequences. + msco.intListProperty[2] = 9; + msco.qrealListProperty[2] = 9.9; + msco.boolListProperty[2] = false; + msco.stringListProperty[2] = "nine"; + msco.urlListProperty[2] = "http://www.example9.com"; + msco.qstringListProperty[2] = "nine"; + + if (intList[2] == 9) + success = false; + if (qrealList[2] == 9.9) + success = false; + if (boolList[2] == false) + success = false; + if (stringList[2] == "nine") + success = false; + if (urlList[2] == "http://www.example9.com") + success = false; + if (qstringList[2] == "nine") + success = false; + } + + property int intVal + property real qrealVal + property bool boolVal + property string stringVal + + // this test ensures that indexed access works for copy resource sequences. + function readSequenceCopyElements() { + success = true; + + var jsIntList = msco.generateIntSequence(); + var jsQrealList = msco.generateQrealSequence(); + var jsBoolList = msco.generateBoolSequence(); + var jsStringList = msco.generateStringSequence(); + + intVal = jsIntList[1]; + qrealVal = jsQrealList[1]; + boolVal = jsBoolList[1]; + stringVal = jsStringList[1]; + + if (intVal != 2) + success = false; + if (qrealVal != 2.2) + success = false; + if (boolVal != false) + success = false; + if (stringVal != "two") + success = false; + } + + // this test ensures that equality works for copy resource sequences. + function testEqualitySemantics() { + success = true; + + var jsIntList = msco.generateIntSequence(); + var jsIntList2 = msco.generateIntSequence(); + + if (jsIntList == jsIntList2) success = false; + if (jsIntList != jsIntList) success = false; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.read.error.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.read.error.qml new file mode 100644 index 0000000000..12a76d7e7d --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.read.error.qml @@ -0,0 +1,21 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + property int pointListLength: 0 + property variant pointList + + function performTest() { + // we have NOT registered QList<QPoint> as a type + pointListLength = msco.pointListProperty.length; + pointList = msco.pointListProperty; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.read.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.read.qml new file mode 100644 index 0000000000..4a8a4a17b2 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.read.qml @@ -0,0 +1,105 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + property int intListLength: 0 + property variant intList + property int qrealListLength: 0 + property variant qrealList + property int boolListLength: 0 + property variant boolList + property int stringListLength: 0 + property variant stringList + property int urlListLength: 0 + property variant urlList + property int qstringListLength: 0 + property variant qstringList + + function readSequences() { + intListLength = msco.intListProperty.length; + intList = msco.intListProperty; + qrealListLength = msco.qrealListProperty.length; + qrealList = msco.qrealListProperty; + boolListLength = msco.boolListProperty.length; + boolList = msco.boolListProperty; + stringListLength = msco.stringListProperty.length; + stringList = msco.stringListProperty; + urlListLength = msco.urlListProperty.length; + urlList = msco.urlListProperty; + qstringListLength = msco.qstringListProperty.length; + qstringList = msco.qstringListProperty; + } + + property int intVal + property real qrealVal + property bool boolVal + property string stringVal + property url urlVal + property string qstringVal + + function readSequenceElements() { + intVal = msco.intListProperty[1]; + qrealVal = msco.qrealListProperty[1]; + boolVal = msco.boolListProperty[1]; + stringVal = msco.stringListProperty[1]; + urlVal = msco.urlListProperty[1]; + qstringVal = msco.qstringListProperty[1]; + } + + property bool enumerationMatches + function enumerateSequenceElements() { + var jsIntList = [1, 2, 3, 4, 5]; + msco.intListProperty = [1, 2, 3, 4, 5]; + + var jsIntListProps = [] + var seqIntListProps = [] + + enumerationMatches = true; + for (var i in jsIntList) { + jsIntListProps.push(i); + if (jsIntList[i] != msco.intListProperty[i]) { + enumerationMatches = false; + } + } + for (var j in msco.intListProperty) { + seqIntListProps.push(j); + if (jsIntList[j] != msco.intListProperty[j]) { + enumerationMatches = false; + } + } + + if (jsIntListProps.length != seqIntListProps.length) { + enumerationMatches = false; + } + + var emptyList = []; + msco.stringListProperty = [] + if (emptyList.toString() != msco.stringListProperty.toString()) { + enumerationMatches = false; + } + if (emptyList.valueOf() != msco.stringListProperty.valueOf()) { + enumerationMatches = false; + } + } + + property bool referenceDeletion: false + function testReferenceDeletion() { + referenceDeletion = true; + var testObj = msco.generateTestObject(); + testObj.intListProperty = [1, 2, 3, 4, 5]; + var testSequence = testObj.intListProperty; + if (testSequence[4] != 5) + referenceDeletion = false; + msco.deleteTestObject(testObj); // delete referenced object. + if (testSequence[4] == 5) + referenceDeletion = false; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.threads.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.threads.qml new file mode 100644 index 0000000000..aefad89ca4 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.threads.qml @@ -0,0 +1,74 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + property bool success: false + property bool finished: false + + function testIntSequence() { + msco.intListProperty = [ 0, 1, 2, 3, 4, 5, 6, 7 ]; + worker.sendSequence(msco.intListProperty); + } + + function testQrealSequence() { + msco.qrealListProperty = [ 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1 ]; + worker.sendSequence(msco.qrealListProperty); + } + + function testBoolSequence() { + msco.boolListProperty = [ false, true, true, false, false, true, false, true ]; + worker.sendSequence(msco.boolListProperty); + } + + function testStringSequence() { + msco.stringListProperty = [ "one", "two", "three", "four" ]; + worker.sendSequence(msco.stringListProperty); + } + + function testQStringSequence() { + msco.qstringListProperty = [ "one", "two", "three", "four" ]; + worker.sendSequence(msco.qstringListProperty); + } + + function testUrlSequence() { + msco.urlListProperty = [ "www.example1.com", "www.example2.com", "www.example3.com", "www.example4.com" ]; + worker.sendSequence(msco.urlListProperty); + } + + function testVariantSequence() { + msco.variantListProperty = [ "one", true, 3, "four" ]; + worker.sendSequence(msco.variantListProperty); + } + + WorkerScript { + id: worker + source: "threadScript.js" + + property variant expected + property variant response + + function sendSequence(seq) { + root.success = false; + root.finished = false; + worker.expected = seq; + worker.sendMessage(seq); + } + + onMessage: { + worker.response = messageObject; + if (worker.response.toString() == worker.expected.toString()) + root.success = true; + else + root.success = false; + root.finished = true; + } + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.write.error.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.write.error.qml new file mode 100644 index 0000000000..75beafd1ee --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.write.error.qml @@ -0,0 +1,18 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + function performTest() { + // we have NOT registered QList<QPoint> as a type + var pointList = [ Qt.point(7,7), Qt.point(8,8), Qt.point(9,9) ]; + msco.pointListProperty = pointList; // error. + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.write.qml b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.write.qml new file mode 100644 index 0000000000..812de043b7 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/sequenceConversion.write.qml @@ -0,0 +1,109 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + id: root + objectName: "root" + + MySequenceConversionObject { + id: msco + objectName: "msco" + } + + property bool success + + function writeSequences() { + success = true; + + var intList = [ 9, 8, 7, 6 ]; + msco.intListProperty = intList; + var qrealList = [ 9.9, 8.8, 7.7, 6.6 ]; + msco.qrealListProperty = qrealList; + var boolList = [ false, false, false, true ]; + msco.boolListProperty = boolList; + var stringList = [ "nine", "eight", "seven", "six" ] + msco.stringListProperty = stringList; + var urlList = [ "http://www.example9.com", "http://www.example8.com", "http://www.example7.com", "http://www.example6.com" ] + msco.urlListProperty = urlList; + var qstringList = [ "nine", "eight", "seven", "six" ] + msco.qstringListProperty = qstringList; + + if (msco.intListProperty[0] != 9 || msco.intListProperty[1] != 8 || msco.intListProperty[2] != 7 || msco.intListProperty[3] != 6) + success = false; + if (msco.qrealListProperty[0] != 9.9 || msco.qrealListProperty[1] != 8.8 || msco.qrealListProperty[2] != 7.7 || msco.qrealListProperty[3] != 6.6) + success = false; + if (msco.boolListProperty[0] != false || msco.boolListProperty[1] != false || msco.boolListProperty[2] != false || msco.boolListProperty[3] != true) + success = false; + if (msco.stringListProperty[0] != "nine" || msco.stringListProperty[1] != "eight" || msco.stringListProperty[2] != "seven" || msco.stringListProperty[3] != "six") + success = false; + if (msco.urlListProperty[0] != "http://www.example9.com" || msco.urlListProperty[1] != "http://www.example8.com" || msco.urlListProperty[2] != "http://www.example7.com" || msco.urlListProperty[3] != "http://www.example6.com") + success = false; + if (msco.qstringListProperty[0] != "nine" || msco.qstringListProperty[1] != "eight" || msco.qstringListProperty[2] != "seven" || msco.qstringListProperty[3] != "six") + success = false; + } + + function writeSequenceElements() { + // set up initial conditions. + writeSequences(); + success = true; + + // element set. + msco.intListProperty[3] = 2; + msco.qrealListProperty[3] = 2.2; + msco.boolListProperty[3] = false; + msco.stringListProperty[3] = "changed"; + msco.urlListProperty[3] = "http://www.examplechanged.com"; + msco.qstringListProperty[3] = "changed"; + + if (msco.intListProperty[0] != 9 || msco.intListProperty[1] != 8 || msco.intListProperty[2] != 7 || msco.intListProperty[3] != 2) + success = false; + if (msco.qrealListProperty[0] != 9.9 || msco.qrealListProperty[1] != 8.8 || msco.qrealListProperty[2] != 7.7 || msco.qrealListProperty[3] != 2.2) + success = false; + if (msco.boolListProperty[0] != false || msco.boolListProperty[1] != false || msco.boolListProperty[2] != false || msco.boolListProperty[3] != false) + success = false; + if (msco.stringListProperty[0] != "nine" || msco.stringListProperty[1] != "eight" || msco.stringListProperty[2] != "seven" || msco.stringListProperty[3] != "changed") + success = false; + if (msco.urlListProperty[0] != "http://www.example9.com" || msco.urlListProperty[1] != "http://www.example8.com" || msco.urlListProperty[2] != "http://www.example7.com" || msco.urlListProperty[3] != "http://www.examplechanged.com") + success = false; + if (msco.qstringListProperty[0] != "nine" || msco.qstringListProperty[1] != "eight" || msco.qstringListProperty[2] != "seven" || msco.qstringListProperty[3] != "changed") + success = false; + } + + function writeOtherElements() { + success = true; + var jsIntList = [1, 2, 3, 4, 5]; + msco.intListProperty = [1, 2, 3, 4, 5]; + + jsIntList[8] = 8; + msco.intListProperty[8] = 8; + if (jsIntList[8] != msco.intListProperty[8]) + success = false; + if (jsIntList.length != msco.intListProperty.length) + success = false; + + // NOTE: we can't exactly match the spec here -- we fill the sequence with a default (rather than empty) value + if (msco.intListProperty[5] != 0 || msco.intListProperty[6] != 0 || msco.intListProperty[7] != 0) + success = false; + + // should have no effect + var currLength = jsIntList.length; + jsIntList.someThing = 9; + msco.intListProperty.someThing = 9; + if (msco.intListProperty.length != currLength) + success = false; + } + + property bool referenceDeletion: false + function testReferenceDeletion() { + referenceDeletion = true; + var testObj = msco.generateTestObject(); + testObj.intListProperty = [1, 2, 3, 4, 5]; + var testSequence = testObj.intListProperty; + if (testSequence[4] != 5) + referenceDeletion = false; + msco.deleteTestObject(testObj); // delete referenced object. + testSequence[4] = 5; // shouldn't work, since referenced object no longer exists. + if (testSequence[4] == 5) + referenceDeletion = false; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/threadScript.js b/tests/auto/declarative/qdeclarativeecmascript/data/threadScript.js new file mode 100644 index 0000000000..9f94de1bc1 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/threadScript.js @@ -0,0 +1,4 @@ +WorkerScript.onMessage = function(msg) { + WorkerScript.sendMessage(msg); +} + diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/typeOf.js b/tests/auto/declarative/qdeclarativeecmascript/data/typeOf.js new file mode 100644 index 0000000000..16a34234c0 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/typeOf.js @@ -0,0 +1,25 @@ +var test1 = typeof a + +var b = {} +var test2 = typeof b + +var c = 5 +var test3 = typeof c + +var d = "hello world" +var test4 = typeof d + +var e = function() {} +var test5 = typeof e + +var f = null +var test6 = typeof f + +var g = undefined +var test7 = typeof g + +var h = true +var test8 = typeof h + +var i = [] +var test9 = typeof i diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/typeOf.qml b/tests/auto/declarative/qdeclarativeecmascript/data/typeOf.qml new file mode 100644 index 0000000000..28f7debed5 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/typeOf.qml @@ -0,0 +1,26 @@ +import QtQuick 2.0 +import "typeOf.js" as TypeOf + +QtObject { + property string test1 + property string test2 + property string test3 + property string test4 + property string test5 + property string test6 + property string test7 + property string test8 + property string test9 + + Component.onCompleted: { + test1 = TypeOf.test1 + test2 = TypeOf.test2 + test3 = TypeOf.test3 + test4 = TypeOf.test4 + test5 = TypeOf.test5 + test6 = TypeOf.test6 + test7 = TypeOf.test7 + test8 = TypeOf.test8 + test9 = TypeOf.test9 + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp index 513705d697..721c719911 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.cpp @@ -101,6 +101,12 @@ public: void setWidth(int) { } }; +void MyQmlObject::v8function(QDeclarativeV8Function *args) +{ + const char *error = "Exception thrown from within QObject slot"; + v8::ThrowException(v8::Exception::Error(v8::String::New(error))); +} + static QJSValue script_api(QDeclarativeEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) @@ -161,6 +167,7 @@ void registerTypes() qmlRegisterExtendedType<DefaultPropertyExtendedObject, DefaultPropertyExtensionObject>("Qt.test", 1,0, "DefaultPropertyExtendedObject"); qmlRegisterType<OverrideDefaultPropertyObject>("Qt.test", 1,0, "OverrideDefaultPropertyObject"); qmlRegisterType<MyRevisionedClass>("Qt.test",1,0,"MyRevisionedClass"); + qmlRegisterType<MyDeleteObject>("Qt.test", 1,0, "MyDeleteObject"); qmlRegisterType<MyRevisionedClass,1>("Qt.test",1,1,"MyRevisionedClass"); // test scarce resource property binding post-evaluation optimisation @@ -196,6 +203,8 @@ void registerTypes() qmlRegisterType<MyDynamicCreationDestructionObject>("Qt.test", 1, 0, "MyDynamicCreationDestructionObject"); qmlRegisterType<WriteCounter>("Qt.test", 1, 0, "WriteCounter"); + + qmlRegisterType<MySequenceConversionObject>("Qt.test", 1, 0, "MySequenceConversionObject"); } #include "testtypes.moc" diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h index 7684ddd438..06cc561c7f 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h +++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h @@ -59,6 +59,7 @@ #include <private/qv8gccallback_p.h> #include <private/qdeclarativeengine_p.h> +#include <private/qv8engine_p.h> class MyQmlAttachedObject : public QObject { @@ -184,6 +185,7 @@ public slots: void setString(const QString &s) { m_string = s; } void myinvokable(MyQmlObject *o) { myinvokableObject = o; } void variantMethod(const QVariant &v) { m_variant = v; } + void v8function(QDeclarativeV8Function*); private: friend class tst_qdeclarativeecmascript; @@ -1148,6 +1150,113 @@ private: int m_count; }; +class MySequenceConversionObject : public QObject +{ + Q_OBJECT + + Q_PROPERTY (QList<int> intListProperty READ intListProperty WRITE setIntListProperty NOTIFY intListPropertyChanged) + Q_PROPERTY (QList<int> intListProperty2 READ intListProperty2 WRITE setIntListProperty2 NOTIFY intListProperty2Changed) + Q_PROPERTY (QList<qreal> qrealListProperty READ qrealListProperty WRITE setQrealListProperty NOTIFY qrealListPropertyChanged) + Q_PROPERTY (QList<bool> boolListProperty READ boolListProperty WRITE setBoolListProperty NOTIFY boolListPropertyChanged) + Q_PROPERTY (QList<QString> stringListProperty READ stringListProperty WRITE setStringListProperty NOTIFY stringListPropertyChanged) + Q_PROPERTY (QList<QUrl> urlListProperty READ urlListProperty WRITE setUrlListProperty NOTIFY urlListPropertyChanged) + Q_PROPERTY (QStringList qstringListProperty READ qstringListProperty WRITE setQStringListProperty NOTIFY qstringListPropertyChanged) + + Q_PROPERTY (QList<QPoint> pointListProperty READ pointListProperty WRITE setPointListProperty NOTIFY pointListPropertyChanged) + Q_PROPERTY (QList<QVariant> variantListProperty READ variantListProperty WRITE setVariantListProperty NOTIFY variantListPropertyChanged) + +public: + MySequenceConversionObject() + { + m_intList << 1 << 2 << 3 << 4; + m_intList2 << 1 << 2 << 3 << 4; + m_qrealList << 1.1 << 2.2 << 3.3 << 4.4; + m_boolList << true << false << true << false; + m_stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth"); + m_urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com"); + m_qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth"); + + m_pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); + m_variantList << QVariant(QLatin1String("one")) << QVariant(true) << QVariant(3); + } + + ~MySequenceConversionObject() {} + + QList<int> intListProperty() const { return m_intList; } + void setIntListProperty(const QList<int> &list) { m_intList = list; emit intListPropertyChanged(); } + QList<int> intListProperty2() const { return m_intList2; } + void setIntListProperty2(const QList<int> &list) { m_intList2 = list; emit intListProperty2Changed(); } + QList<qreal> qrealListProperty() const { return m_qrealList; } + void setQrealListProperty(const QList<qreal> &list) { m_qrealList = list; emit qrealListPropertyChanged(); } + QList<bool> boolListProperty() const { return m_boolList; } + void setBoolListProperty(const QList<bool> &list) { m_boolList = list; emit boolListPropertyChanged(); } + QList<QString> stringListProperty() const { return m_stringList; } + void setStringListProperty(const QList<QString> &list) { m_stringList = list; emit stringListPropertyChanged(); } + QList<QUrl> urlListProperty() const { return m_urlList; } + void setUrlListProperty(const QList<QUrl> &list) { m_urlList = list; emit urlListPropertyChanged(); } + QStringList qstringListProperty() const { return m_qstringList; } + void setQStringListProperty(const QStringList &list) { m_qstringList = list; emit qstringListPropertyChanged(); } + QList<QPoint> pointListProperty() const { return m_pointList; } + void setPointListProperty(const QList<QPoint> &list) { m_pointList = list; emit pointListPropertyChanged(); } + QList<QVariant> variantListProperty() const { return m_variantList; } + void setVariantListProperty(const QList<QVariant> &list) { m_variantList = list; emit variantListPropertyChanged(); } + + // now for "copy resource" sequences: + Q_INVOKABLE QList<int> generateIntSequence() const { QList<int> retn; retn << 1 << 2 << 3; return retn; } + Q_INVOKABLE QList<qreal> generateQrealSequence() const { QList<qreal> retn; retn << 1.1 << 2.2 << 3.3; return retn; } + Q_INVOKABLE QList<bool> generateBoolSequence() const { QList<bool> retn; retn << true << false << true; return retn; } + Q_INVOKABLE QList<QString> generateStringSequence() const { QList<QString> retn; retn << "one" << "two" << "three"; return retn; } + Q_INVOKABLE QList<QUrl> generateUrlSequence() const { QList<QUrl> retn; retn << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com"); return retn; } + Q_INVOKABLE QStringList generateQStringSequence() const { QStringList retn; retn << "one" << "two" << "three"; return retn; } + + // "reference resource" underlying qobject deletion test: + Q_INVOKABLE MySequenceConversionObject *generateTestObject() const { return new MySequenceConversionObject; } + Q_INVOKABLE void deleteTestObject(QObject *object) const { delete object; } + +signals: + void intListPropertyChanged(); + void intListProperty2Changed(); + void qrealListPropertyChanged(); + void boolListPropertyChanged(); + void stringListPropertyChanged(); + void urlListPropertyChanged(); + void qstringListPropertyChanged(); + void pointListPropertyChanged(); + void variantListPropertyChanged(); + +private: + QList<int> m_intList; + QList<int> m_intList2; + QList<qreal> m_qrealList; + QList<bool> m_boolList; + QList<QString> m_stringList; + QList<QUrl> m_urlList; + QStringList m_qstringList; + + QList<QPoint> m_pointList; // not a supported sequence type + QList<QVariant> m_variantList; // not a supported sequence type, but QVariantList support is hardcoded. +}; + +class MyDeleteObject : public QObject +{ + Q_OBJECT + Q_PROPERTY(QObject *nestedObject READ nestedObject NOTIFY nestedObjectChanged); + Q_PROPERTY(int deleteNestedObject READ deleteNestedObject NOTIFY deleteNestedObjectChanged); + +public: + MyDeleteObject() : m_nestedObject(new MyQmlObject) {} + + QObject *nestedObject() const { return m_nestedObject; } + int deleteNestedObject() { delete m_nestedObject; m_nestedObject = 0; return 1; } + +signals: + void nestedObjectChanged(); + void deleteNestedObjectChanged(); + +private: + MyQmlObject *m_nestedObject; +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 40072c9e60..492ed739b2 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -51,6 +51,7 @@ #include <private/qdeclarativeengine_p.h> #include <private/qv8gccallback_p.h> #include <private/qdeclarativevmemetaobject_p.h> +#include <private/qv4compiler_p.h> #include "testtypes.h" #include "testhttpserver.h" #include "../shared/util.h" @@ -169,6 +170,13 @@ private slots: void booleanConversion(); void handleReferenceManagement(); void stringArg(); + void readonlyDeclaration(); + void sequenceConversionRead(); + void sequenceConversionWrite(); + void sequenceConversionArray(); + void sequenceConversionThreads(); + void sequenceConversionBindings(); + void sequenceConversionCopy(); void bug1(); void bug2(); @@ -195,6 +203,7 @@ private slots: void nonscriptable(); void deleteLater(); void in(); + void typeOf(); void sharedAttachedObject(); void objectName(); void writeRemovesBinding(); @@ -207,11 +216,13 @@ private slots: void include(); void signalHandlers(); void doubleEvaluate(); - + void forInLoop(); + void nonNotifyable(); + void deleteWhileBindingRunning(); void callQtInvokables(); void invokableObjectArg(); void invokableObjectRet(); - + void qtbug_20344(); void revisionErrors(); void revision(); @@ -1579,7 +1590,8 @@ void tst_qdeclarativeecmascript::shutdownErrors() void tst_qdeclarativeecmascript::compositePropertyType() { QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml")); - QTest::ignoreMessage(QtDebugMsg, "hello world"); + QString messageFormat = QString(QLatin1String("hello world (%1:%2)")).arg(TEST_FILE("compositePropertyType.qml").toString()).arg(7); + QTest::ignoreMessage(QtDebugMsg, qPrintable(messageFormat)); QObject *object = qobject_cast<QObject *>(component.create()); delete object; } @@ -4034,6 +4046,248 @@ void tst_qdeclarativeecmascript::stringArg() delete object; } +void tst_qdeclarativeecmascript::readonlyDeclaration() +{ + QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml")); + + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("test").toBool(), true); + + delete object; +} + +Q_DECLARE_METATYPE(QList<int>) +Q_DECLARE_METATYPE(QList<qreal>) +Q_DECLARE_METATYPE(QList<bool>) +Q_DECLARE_METATYPE(QList<QString>) +Q_DECLARE_METATYPE(QList<QUrl>) +void tst_qdeclarativeecmascript::sequenceConversionRead() +{ + { + QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco"); + QVERIFY(seq != 0); + + QMetaObject::invokeMethod(object, "readSequences"); + QList<int> intList; intList << 1 << 2 << 3 << 4; + QCOMPARE(object->property("intListLength").toInt(), intList.length()); + QCOMPARE(object->property("intList").value<QList<int> >(), intList); + QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4; + QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length()); + QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList); + QList<bool> boolList; boolList << true << false << true << false; + QCOMPARE(object->property("boolListLength").toInt(), boolList.length()); + QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList); + QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth"); + QCOMPARE(object->property("stringListLength").toInt(), stringList.length()); + QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList); + QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com"); + QCOMPARE(object->property("urlListLength").toInt(), urlList.length()); + QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList); + QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth"); + QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length()); + QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList); + + QMetaObject::invokeMethod(object, "readSequenceElements"); + QCOMPARE(object->property("intVal").toInt(), 2); + QCOMPARE(object->property("qrealVal").toReal(), 2.2); + QCOMPARE(object->property("boolVal").toBool(), false); + QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second"))); + QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com")); + QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second"))); + + QMetaObject::invokeMethod(object, "enumerateSequenceElements"); + QCOMPARE(object->property("enumerationMatches").toBool(), true); + + intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test. + QDeclarativeProperty seqProp(seq, "intListProperty"); + QCOMPARE(seqProp.read().value<QList<int> >(), intList); + QDeclarativeProperty seqProp2(seq, "intListProperty", &engine); + QCOMPARE(seqProp2.read().value<QList<int> >(), intList); + + QMetaObject::invokeMethod(object, "testReferenceDeletion"); + QCOMPARE(object->property("referenceDeletion").toBool(), true); + + delete object; + } + + { + QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco"); + QVERIFY(seq != 0); + + // we haven't registered QList<QPoint> as a sequence type. + QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'"); + QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined"); + QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData()); + QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData()); + + QMetaObject::invokeMethod(object, "performTest"); + + // QList<QPoint> has not been registered as a sequence type. + QCOMPARE(object->property("pointListLength").toInt(), 0); + QVERIFY(!object->property("pointList").isValid()); + QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'"); + QDeclarativeProperty seqProp(seq, "pointListProperty", &engine); + QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type + + delete object; + } +} + +void tst_qdeclarativeecmascript::sequenceConversionWrite() +{ + { + QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco"); + QVERIFY(seq != 0); + + QMetaObject::invokeMethod(object, "writeSequences"); + QCOMPARE(object->property("success").toBool(), true); + + QMetaObject::invokeMethod(object, "writeSequenceElements"); + QCOMPARE(object->property("success").toBool(), true); + + QMetaObject::invokeMethod(object, "writeOtherElements"); + QCOMPARE(object->property("success").toBool(), true); + + QMetaObject::invokeMethod(object, "testReferenceDeletion"); + QCOMPARE(object->property("referenceDeletion").toBool(), true); + + delete object; + } + + { + QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco"); + QVERIFY(seq != 0); + + // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work. + QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void"); + QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData()); + + QMetaObject::invokeMethod(object, "performTest"); + + QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed + QCOMPARE(seq->pointListProperty(), pointList); + + delete object; + } +} + +void tst_qdeclarativeecmascript::sequenceConversionArray() +{ + // ensure that in JS the returned sequences act just like normal JS Arrays. + QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + //QMetaObject::invokeMethod(object, "indexedAccess"); + //QVERIFY(object->property("success").toBool()); + //QMetaObject::invokeMethod(object, "arrayOperations"); + //QVERIFY(object->property("success").toBool()); + QMetaObject::invokeMethod(object, "testEqualitySemantics"); + QVERIFY(object->property("success").toBool()); + //QMetaObject::invokeMethod(object, "testReferenceDeletion"); + //QCOMPARE(object->property("referenceDeletion").toBool(), true); + delete object; +} + +void tst_qdeclarativeecmascript::sequenceConversionThreads() +{ + // ensure that sequence conversion operations work correctly in a worker thread + // and that serialisation between the main and worker thread succeeds. + QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + + QMetaObject::invokeMethod(object, "testIntSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + QMetaObject::invokeMethod(object, "testQrealSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + QMetaObject::invokeMethod(object, "testBoolSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + QMetaObject::invokeMethod(object, "testStringSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + QMetaObject::invokeMethod(object, "testQStringSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + QMetaObject::invokeMethod(object, "testUrlSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + QMetaObject::invokeMethod(object, "testVariantSequence"); + QTRY_VERIFY(object->property("finished").toBool()); + QVERIFY(object->property("success").toBool()); + + delete object; +} + +void tst_qdeclarativeecmascript::sequenceConversionBindings() +{ + { + QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + QList<int> intList; intList << 1 << 2 << 3 << 12 << 7; + QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList); + QCOMPARE(object->property("boundElement").toInt(), intList.at(3)); + QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14; + QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo); + delete object; + } + + { + QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml"); + QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString()); + QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData()); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + delete object; + } +} + +void tst_qdeclarativeecmascript::sequenceConversionCopy() +{ + QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml"); + QDeclarativeComponent component(&engine, qmlFile); + QObject *object = component.create(); + QVERIFY(object != 0); + QMetaObject::invokeMethod(object, "testCopySequences"); + QCOMPARE(object->property("success").toBool(), true); + QMetaObject::invokeMethod(object, "readSequenceCopyElements"); + QCOMPARE(object->property("success").toBool(), true); + QMetaObject::invokeMethod(object, "testEqualitySemantics"); + QCOMPARE(object->property("success").toBool(), true); + delete object; +} + // Test that assigning a null object works // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4 void tst_qdeclarativeecmascript::nullObjectBinding() @@ -4109,7 +4363,8 @@ void tst_qdeclarativeecmascript::qtbug_9792() MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context)); QVERIFY(object != 0); - QTest::ignoreMessage(QtDebugMsg, "Hello world!"); + QString message = QString(QLatin1String("Hello world! (%1:%2)")).arg(TEST_FILE("qtbug_9792.qml").toString()).arg(4); + QTest::ignoreMessage(QtDebugMsg, qPrintable(message)); object->basicSignal(); delete context; @@ -4511,6 +4766,25 @@ void tst_qdeclarativeecmascript::in() delete o; } +void tst_qdeclarativeecmascript::typeOf() +{ + QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml")); + QObject *o = component.create(); + QVERIFY(o != 0); + QEXPECT_FAIL("", "QTBUG-21864", Abort); + QCOMPARE(o->property("test1").toString(), QLatin1String("undefined")); + QCOMPARE(o->property("test2").toString(), QLatin1String("object")); + QCOMPARE(o->property("test3").toString(), QLatin1String("number")); + QCOMPARE(o->property("test4").toString(), QLatin1String("string")); + QCOMPARE(o->property("test5").toString(), QLatin1String("function")); + QCOMPARE(o->property("test6").toString(), QLatin1String("object")); + QCOMPARE(o->property("test7").toString(), QLatin1String("undefined")); + QCOMPARE(o->property("test8").toString(), QLatin1String("boolean")); + QCOMPARE(o->property("test9").toString(), QLatin1String("object")); + + delete o; +} + void tst_qdeclarativeecmascript::sharedAttachedObject() { QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml")); @@ -4642,6 +4916,19 @@ void tst_qdeclarativeecmascript::aliasToCompositeElement() delete object; } +void tst_qdeclarativeecmascript::qtbug_20344() +{ + QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml")); + + QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot"; + QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); + + QObject *object = component.create(); + QVERIFY(object != 0); + + delete object; +} + void tst_qdeclarativeecmascript::revisionErrors() { { @@ -4780,6 +5067,67 @@ void tst_qdeclarativeecmascript::doubleEvaluate() delete object; } +static QStringList messages; +static void captureMsgHandler(QtMsgType, const char *msg) +{ + messages.append(QLatin1String(msg)); +} + +void tst_qdeclarativeecmascript::nonNotifyable() +{ + QV4Compiler::enableV4(false); + QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml")); + QV4Compiler::enableV4(true); + + QtMsgHandler old = qInstallMsgHandler(captureMsgHandler); + messages.clear(); + QObject *object = component.create(); + qInstallMsgHandler(old); + + QVERIFY(object != 0); + + QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") + + component.url().toString() + + QLatin1String(":5 depends on non-NOTIFYable properties:"); + QString expected2 = QLatin1String(" ") + + QLatin1String(object->metaObject()->className()) + + QLatin1String("::value"); + + QCOMPARE(messages.length(), 2); + QCOMPARE(messages.at(0), expected1); + QCOMPARE(messages.at(1), expected2); + + delete object; +} + +void tst_qdeclarativeecmascript::forInLoop() +{ + QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QMetaObject::invokeMethod(object, "listProperty"); + + QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts); + QCOMPARE(r.size(), 3); + QCOMPARE(r[0],QLatin1String("0=obj1")); + QCOMPARE(r[1],QLatin1String("1=obj2")); + QCOMPARE(r[2],QLatin1String("2=obj3")); + + //TODO: should test for in loop for other objects (such as QObjects) as well. + + delete object; +} + +// An object the binding depends on is deleted while the binding is still running +void tst_qdeclarativeecmascript::deleteWhileBindingRunning() +{ + QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + delete object; +} + QTEST_MAIN(tst_qdeclarativeecmascript) #include "tst_qdeclarativeecmascript.moc" diff --git a/tests/auto/declarative/qdeclarativeexpression/tst_qdeclarativeexpression.cpp b/tests/auto/declarative/qdeclarativeexpression/tst_qdeclarativeexpression.cpp index a05c06f23f..a65045b48f 100644 --- a/tests/auto/declarative/qdeclarativeexpression/tst_qdeclarativeexpression.cpp +++ b/tests/auto/declarative/qdeclarativeexpression/tst_qdeclarativeexpression.cpp @@ -54,6 +54,7 @@ public: private slots: void scriptString(); + void syntaxError(); }; class TestObject : public QObject @@ -106,6 +107,15 @@ void tst_qdeclarativeexpression::scriptString() QCOMPARE(error.line(), 8); } +// QTBUG-21310 - crash test +void tst_qdeclarativeexpression::syntaxError() +{ + QDeclarativeEngine engine; + QDeclarativeExpression expression(engine.rootContext(), 0, "asd asd"); + QVariant v = expression.evaluate(); + QCOMPARE(v, QVariant()); +} + QTEST_MAIN(tst_qdeclarativeexpression) #include "tst_qdeclarativeexpression.moc" diff --git a/tests/auto/declarative/qdeclarativefontloader/data/qtbug-20268.qml b/tests/auto/declarative/qdeclarativefontloader/data/qtbug-20268.qml new file mode 100644 index 0000000000..0eafdfa17b --- /dev/null +++ b/tests/auto/declarative/qdeclarativefontloader/data/qtbug-20268.qml @@ -0,0 +1,27 @@ +import QtQuick 2.0 + +Rectangle { + id: test + property variant fontloader: fontloaderelement + height: 100; width: 100 + property bool usename: false + property int statenum: 1 + property alias name: fontloaderelement.name + property alias source: fontloaderelement.source + property alias status: fontloaderelement.status + + FontLoader { + id: fontloaderelement + } + + states: [ + State { name: "start"; when: !usename + PropertyChanges { target: fontloaderelement; source: "tarzeau_ocr_a.ttf" } + }, + State { name: "changefont"; when: usename + PropertyChanges { target: fontloaderelement; name: "Tahoma" } + } + ] + + Text { id: textelement; text: fontloaderelement.name; color: "black" } +} diff --git a/tests/auto/declarative/qdeclarativefontloader/tst_qdeclarativefontloader.cpp b/tests/auto/declarative/qdeclarativefontloader/tst_qdeclarativefontloader.cpp index 67a040dcf2..9831ac1087 100644 --- a/tests/auto/declarative/qdeclarativefontloader/tst_qdeclarativefontloader.cpp +++ b/tests/auto/declarative/qdeclarativefontloader/tst_qdeclarativefontloader.cpp @@ -46,6 +46,8 @@ #include <QtDeclarative/private/qdeclarativefontloader_p.h> #include "../shared/util.h" #include "../../declarative/shared/testhttpserver.h" +#include <QQuickView> +#include <QQuickItem> #define SERVER_PORT 14448 @@ -65,6 +67,7 @@ private slots: void redirWebFont(); void failWebFont(); void changeFont(); + void changeFontSourceViaState(); private: QDeclarativeEngine engine; @@ -220,6 +223,26 @@ void tst_qdeclarativefontloader::changeFont() QTRY_COMPARE(fontObject->name(), QString("Daniel")); } +void tst_qdeclarativefontloader::changeFontSourceViaState() +{ + QQuickView canvas(QUrl::fromLocalFile(TESTDATA("qtbug-20268.qml"))); + canvas.show(); + canvas.requestActivateWindow(); + QTest::qWaitForWindowShown(&canvas); + QTRY_COMPARE(&canvas, qGuiApp->focusWindow()); + + QDeclarativeFontLoader *fontObject = qobject_cast<QDeclarativeFontLoader*>(qvariant_cast<QObject *>(canvas.rootObject()->property("fontloader"))); + QVERIFY(fontObject != 0); + QTRY_VERIFY(fontObject->status() == QDeclarativeFontLoader::Ready); + QVERIFY(fontObject->source() != QUrl("")); + QTRY_COMPARE(fontObject->name(), QString("OCRA")); + + canvas.rootObject()->setProperty("usename", true); + QEXPECT_FAIL("", "QTBUG-20268", Abort); + QTRY_VERIFY(fontObject->status() == QDeclarativeFontLoader::Ready); + QCOMPARE(canvas.rootObject()->property("name").toString(), QString("Tahoma")); +} + QTEST_MAIN(tst_qdeclarativefontloader) #include "tst_qdeclarativefontloader.moc" diff --git a/tests/auto/declarative/qdeclarativeincubator/data/chainInCompletion.qml b/tests/auto/declarative/qdeclarativeincubator/data/chainInCompletion.qml new file mode 100644 index 0000000000..e79fed356a --- /dev/null +++ b/tests/auto/declarative/qdeclarativeincubator/data/chainInCompletion.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +SelfRegistering { + property variant a: CompletionCallback {} +} diff --git a/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp b/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp index 99d2cb1005..6d6fb38daf 100644 --- a/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp +++ b/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp @@ -101,9 +101,37 @@ void CallbackRegisteringType::registerCallback(callback c, void *d) m_data = d; } +CompletionCallbackType::callback CompletionCallbackType::m_callback = 0; +void *CompletionCallbackType::m_data = 0; +CompletionCallbackType::CompletionCallbackType() +{ +} + +void CompletionCallbackType::classBegin() +{ +} + +void CompletionCallbackType::componentComplete() +{ + if (m_callback) m_callback(this, m_data); +} + +void CompletionCallbackType::clearCallback() +{ + m_callback = 0; + m_data = 0; +} + +void CompletionCallbackType::registerCallback(callback c, void *d) +{ + m_callback = c; + m_data = d; +} + void registerTypes() { qmlRegisterType<SelfRegisteringType>("Qt.test", 1,0, "SelfRegistering"); qmlRegisterType<CompletionRegisteringType>("Qt.test", 1,0, "CompletionRegistering"); qmlRegisterType<CallbackRegisteringType>("Qt.test", 1,0, "CallbackRegistering"); + qmlRegisterType<CompletionCallbackType>("Qt.test", 1,0, "CompletionCallback"); } diff --git a/tests/auto/declarative/qdeclarativeincubator/testtypes.h b/tests/auto/declarative/qdeclarativeincubator/testtypes.h index 6e732548b2..8d9968de3c 100644 --- a/tests/auto/declarative/qdeclarativeincubator/testtypes.h +++ b/tests/auto/declarative/qdeclarativeincubator/testtypes.h @@ -100,6 +100,24 @@ private: static CompletionRegisteringType *m_me; }; +class CompletionCallbackType : public QObject, public QDeclarativeParserStatus +{ +Q_OBJECT +public: + CompletionCallbackType(); + + virtual void classBegin(); + virtual void componentComplete(); + + typedef void (*callback)(CompletionCallbackType *, void *); + static void clearCallback(); + static void registerCallback(callback, void *); + +private: + static callback m_callback; + static void *m_data; +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp b/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp index 684cd35613..54ca622753 100644 --- a/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp +++ b/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp @@ -83,6 +83,7 @@ private slots: void asynchronousIfNested(); void nestedComponent(); void chainedAsynchronousIfNested(); + void chainedAsynchronousIfNestedOnCompleted(); void selfDelete(); private: @@ -773,6 +774,134 @@ void tst_qdeclarativeincubator::chainedAsynchronousIfNested() QVERIFY(incubator2.isReady()); } +// Checks that new AsynchronousIfNested incubators can be correctly chained if started in +// componentCompleted(). +void tst_qdeclarativeincubator::chainedAsynchronousIfNestedOnCompleted() +{ + SelfRegisteringType::clearMe(); + + QDeclarativeComponent component(&engine, TEST_FILE("chainInCompletion.qml")); + QVERIFY(component.isReady()); + + QDeclarativeComponent c1(&engine, TEST_FILE("chainedAsynchronousIfNested.qml")); + QVERIFY(c1.isReady()); + + struct MyIncubator : public QDeclarativeIncubator { + MyIncubator(MyIncubator *next, QDeclarativeComponent *component, QDeclarativeContext *ctxt) + : QDeclarativeIncubator(AsynchronousIfNested), next(next), component(component), ctxt(ctxt) {} + + protected: + virtual void statusChanged(Status s) { + if (s == Ready && next) { + component->create(*next, 0, ctxt); + } + } + + private: + MyIncubator *next; + QDeclarativeComponent *component; + QDeclarativeContext *ctxt; + }; + + struct CallbackData { + CallbackData(QDeclarativeComponent *c, MyIncubator *i, QDeclarativeContext *ct) + : component(c), incubator(i), ctxt(ct) {} + QDeclarativeComponent *component; + MyIncubator *incubator; + QDeclarativeContext *ctxt; + static void callback(CompletionCallbackType *o, void *data) { + CallbackData *d = (CallbackData *)data; + d->component->create(*d->incubator, 0, d->ctxt); + } + }; + + QDeclarativeIncubator incubator(QDeclarativeIncubator::Asynchronous); + component.create(incubator); + + QVERIFY(incubator.isLoading()); + QVERIFY(SelfRegisteringType::me() == 0); + + while (SelfRegisteringType::me() == 0 && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(SelfRegisteringType::me() != 0); + QVERIFY(incubator.isLoading()); + + MyIncubator incubator3(0, &c1, qmlContext(SelfRegisteringType::me())); + MyIncubator incubator2(&incubator3, &c1, qmlContext(SelfRegisteringType::me())); + MyIncubator incubator1(&incubator2, &c1, qmlContext(SelfRegisteringType::me())); + + // start incubator1 in componentComplete + CallbackData cd(&c1, &incubator1, qmlContext(SelfRegisteringType::me())); + CompletionCallbackType::registerCallback(&CallbackData::callback, &cd); + + while (!incubator1.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator2.isNull()); + QVERIFY(incubator3.isNull()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isLoading()); + QVERIFY(incubator2.isNull()); + QVERIFY(incubator3.isNull()); + + while (incubator1.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isLoading()); + QVERIFY(incubator2.isNull()); + QVERIFY(incubator3.isNull()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isLoading()); + QVERIFY(incubator3.isNull()); + + while (incubator2.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isLoading()); + QVERIFY(incubator3.isNull()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); + QVERIFY(incubator3.isLoading()); + + while (incubator3.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); + QVERIFY(incubator3.isLoading()); + + bool b = false; + controller.incubateWhile(&b); + } + + { + bool b = true; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isReady()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); + QVERIFY(incubator3.isReady()); +} + void tst_qdeclarativeincubator::selfDelete() { struct MyIncubator : public QDeclarativeIncubator { diff --git a/tests/auto/declarative/qdeclarativelanguage/data/ReadOnlyType.qml b/tests/auto/declarative/qdeclarativelanguage/data/ReadOnlyType.qml new file mode 100644 index 0000000000..456ac762fc --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/ReadOnlyType.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + readonly property int readOnlyProperty: 19 +} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/property.5.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/property.5.errors.txt deleted file mode 100644 index 32a8dc11e1..0000000000 --- a/tests/auto/declarative/qdeclarativelanguage/data/property.5.errors.txt +++ /dev/null @@ -1 +0,0 @@ -4:5:Readonly not yet supported diff --git a/tests/auto/declarative/qdeclarativelanguage/data/property.5.qml b/tests/auto/declarative/qdeclarativelanguage/data/property.5.qml deleted file mode 100644 index a1401d2fdc..0000000000 --- a/tests/auto/declarative/qdeclarativelanguage/data/property.5.qml +++ /dev/null @@ -1,6 +0,0 @@ -import QtQuick 2.0 - -QtObject { - readonly property int a: value -} - diff --git a/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt b/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt index baf47667bc..e71ae4447c 100644 --- a/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt +++ b/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.errors.txt @@ -1 +1 @@ -3:27:Invalid property assignment: "readOnlyEnumProperty" is a read-only property +2:23:Invalid property assignment: "readOnlyProperty" is a read-only property diff --git a/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml b/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml index 422d13d8d0..d80b27a1e3 100644 --- a/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml +++ b/tests/auto/declarative/qdeclarativelanguage/data/readOnly.5.qml @@ -1,4 +1,3 @@ -import Test 1.0 -MyTypeObject { - readOnlyEnumProperty: MyTypeObject.EnumValue1 +ReadOnlyType { + readOnlyProperty: 13 } diff --git a/tests/auto/declarative/qdeclarativelanguage/data/readonly.qml b/tests/auto/declarative/qdeclarativelanguage/data/readonly.qml new file mode 100644 index 0000000000..493a9ad502 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/readonly.qml @@ -0,0 +1,17 @@ +import Test 1.0 + +MyQmlObject { + property int testData: 9 + property alias testData2: myObject.test1 + + readonly property int test1: 10 + readonly property int test2: testData + 9 + readonly property alias test3: myObject.test1 + + + property variant dummy: MyQmlObject { + id: myObject + property int test1: 13 + } +} + diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp index 538ebbb1a3..a3fb5f0917 100644 --- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp +++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp @@ -156,6 +156,7 @@ private slots: void inlineAssignmentsOverrideBindings(); void nestedComponentRoots(); void registrationOrder(); + void readonly(); void basicRemote_data(); void basicRemote(); @@ -364,7 +365,6 @@ void tst_qdeclarativelanguage::errors_data() QTest::newRow("property.2") << "property.2.qml" << "property.2.errors.txt" << false; QTest::newRow("property.3") << "property.3.qml" << "property.3.errors.txt" << false; QTest::newRow("property.4") << "property.4.qml" << "property.4.errors.txt" << false; - QTest::newRow("property.5") << "property.5.qml" << "property.5.errors.txt" << false; QTest::newRow("property.6") << "property.6.qml" << "property.6.errors.txt" << false; QTest::newRow("property.7") << "property.7.qml" << "property.7.errors.txt" << false; @@ -850,7 +850,8 @@ void tst_qdeclarativelanguage::dynamicObjectProperties() // Tests the declaration of dynamic signals and slots void tst_qdeclarativelanguage::dynamicSignalsAndSlots() { - QTest::ignoreMessage(QtDebugMsg, "1921"); + QString message = QString(QLatin1String("1921 (%1:%2)")).arg(TEST_FILE("dynamicSignalsAndSlots.qml").toString()).arg(9); + QTest::ignoreMessage(QtDebugMsg, qPrintable(message)); QDeclarativeComponent component(&engine, TEST_FILE("dynamicSignalsAndSlots.qml")); VERIFY_ERRORS(0); @@ -1288,9 +1289,10 @@ void tst_qdeclarativelanguage::onCompleted() { QDeclarativeComponent component(&engine, TEST_FILE("onCompleted.qml")); VERIFY_ERRORS(0); - QTest::ignoreMessage(QtDebugMsg, "Completed 6 10"); - QTest::ignoreMessage(QtDebugMsg, "Completed 6 10"); - QTest::ignoreMessage(QtDebugMsg, "Completed 10 11"); + QString formatMessage = QString(QLatin1String("%1 (%2:%3)")); + QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Completed 6 10")).arg(TEST_FILE("onCompleted.qml").toString()).arg(8).toLatin1()); + QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Completed 6 10")).arg(TEST_FILE("onCompleted.qml").toString()).arg(14).toLatin1()); + QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Completed 10 11")).arg(TEST_FILE("OnCompletedType.qml").toString()).arg(7).toLatin1()); QObject *object = component.create(); QVERIFY(object != 0); } @@ -1302,10 +1304,10 @@ void tst_qdeclarativelanguage::onDestruction() VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); - - QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10"); - QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10"); - QTest::ignoreMessage(QtDebugMsg, "Destruction 10 11"); + QString formatMessage = QString(QLatin1String("%1 (%2:%3)")); + QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Destruction 6 10")).arg(TEST_FILE("onDestruction.qml").toString()).arg(8).toLatin1()); + QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Destruction 6 10")).arg(TEST_FILE("onDestruction.qml").toString()).arg(14).toLatin1()); + QTest::ignoreMessage(QtDebugMsg, formatMessage.arg(QLatin1String("Destruction 10 11")).arg(TEST_FILE("OnDestructionType.qml").toString()).arg(7).toLatin1()); delete object; } @@ -2142,6 +2144,40 @@ void tst_qdeclarativelanguage::registrationOrder() delete o; } +void tst_qdeclarativelanguage::readonly() +{ + QDeclarativeComponent component(&engine, TEST_FILE("readonly.qml")); + + QObject *o = component.create(); + QVERIFY(o != 0); + + QCOMPARE(o->property("test1").toInt(), 10); + QCOMPARE(o->property("test2").toInt(), 18); + QCOMPARE(o->property("test3").toInt(), 13); + + o->setProperty("testData", 13); + + QCOMPARE(o->property("test1").toInt(), 10); + QCOMPARE(o->property("test2").toInt(), 22); + QCOMPARE(o->property("test3").toInt(), 13); + + o->setProperty("testData2", 2); + + QCOMPARE(o->property("test1").toInt(), 10); + QCOMPARE(o->property("test2").toInt(), 22); + QCOMPARE(o->property("test3").toInt(), 2); + + o->setProperty("test1", 11); + o->setProperty("test2", 11); + o->setProperty("test3", 11); + + QCOMPARE(o->property("test1").toInt(), 10); + QCOMPARE(o->property("test2").toInt(), 22); + QCOMPARE(o->property("test3").toInt(), 2); + + delete o; +} + // QTBUG-18268 void tst_qdeclarativelanguage::remoteLoadCrash() { diff --git a/tests/auto/declarative/qdeclarativelistcompositor/tst_qdeclarativelistcompositor.cpp b/tests/auto/declarative/qdeclarativelistcompositor/tst_qdeclarativelistcompositor.cpp index 67bced6da8..425f35cc08 100644 --- a/tests/auto/declarative/qdeclarativelistcompositor/tst_qdeclarativelistcompositor.cpp +++ b/tests/auto/declarative/qdeclarativelistcompositor/tst_qdeclarativelistcompositor.cpp @@ -146,6 +146,10 @@ class tst_qdeclarativelistcompositor : public QObject } private slots: + void find_data(); + void find(); + void findInsertPosition_data(); + void findInsertPosition(); void insert(); void clearFlags_data(); void clearFlags(); @@ -164,6 +168,131 @@ private slots: void listItemsChanged(); }; +void tst_qdeclarativelistcompositor::find_data() +{ + QTest::addColumn<RangeList>("ranges"); + QTest::addColumn<C::Group>("startGroup"); + QTest::addColumn<int>("startIndex"); + QTest::addColumn<C::Group>("group"); + QTest::addColumn<int>("index"); + QTest::addColumn<int>("selectionIndex"); + QTest::addColumn<int>("visibleIndex"); + QTest::addColumn<int>("defaultIndex"); + QTest::addColumn<int>("cacheIndex"); + QTest::addColumn<int>("rangeFlags"); + QTest::addColumn<int>("rangeIndex"); + + int listA; void *a = &listA; + + QTest::newRow("Start") + << (RangeList() + << Range(a, 0, 1, int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag)) + << Range(a, 1, 1, int(C::AppendFlag | C::PrependFlag | C::CacheFlag)) + << Range(0, 0, 1, int(VisibleFlag| C::CacheFlag))) + << C::Cache << 2 + << Selection << 0 + << 0 << 0 << 0 << 0 + << int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag) << 0; +} + +void tst_qdeclarativelistcompositor::find() +{ + QFETCH(RangeList, ranges); + QFETCH(C::Group, startGroup); + QFETCH(int, startIndex); + QFETCH(C::Group, group); + QFETCH(int, index); + QFETCH(int, cacheIndex); + QFETCH(int, defaultIndex); + QFETCH(int, visibleIndex); + QFETCH(int, selectionIndex); + QFETCH(int, rangeFlags); + QFETCH(int, rangeIndex); + + QDeclarativeListCompositor compositor; + compositor.setGroupCount(4); + compositor.setDefaultGroups(VisibleFlag | C::DefaultFlag); + + foreach (const Range &range, ranges) + compositor.append(range.list, range.index, range.count, range.flags); + + compositor.find(startGroup, startIndex); + + QDeclarativeListCompositor::iterator it = compositor.find(group, index); + QCOMPARE(it.index[C::Cache], cacheIndex); + QCOMPARE(it.index[C::Default], defaultIndex); + QCOMPARE(it.index[Visible], visibleIndex); + QCOMPARE(it.index[Selection], selectionIndex); + QCOMPARE(it->flags, rangeFlags); + QCOMPARE(it->index, rangeIndex); +} + +void tst_qdeclarativelistcompositor::findInsertPosition_data() +{ + QTest::addColumn<RangeList>("ranges"); + QTest::addColumn<C::Group>("startGroup"); + QTest::addColumn<int>("startIndex"); + QTest::addColumn<C::Group>("group"); + QTest::addColumn<int>("index"); + QTest::addColumn<int>("selectionIndex"); + QTest::addColumn<int>("visibleIndex"); + QTest::addColumn<int>("defaultIndex"); + QTest::addColumn<int>("cacheIndex"); + QTest::addColumn<int>("rangeFlags"); + QTest::addColumn<int>("rangeIndex"); + + int listA; void *a = &listA; + + QTest::newRow("Start") + << (RangeList() + << Range(a, 0, 1, int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag)) + << Range(a, 1, 1, int(C::AppendFlag | C::PrependFlag | C::CacheFlag)) + << Range(0, 0, 1, int(VisibleFlag| C::CacheFlag))) + << C::Cache << 2 + << Selection << 0 + << 0 << 0 << 0 << 0 + << int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag) << 0; + QTest::newRow("1") + << (RangeList() + << Range(a, 0, 1, int(C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag)) + << Range(a, 1, 1, int(C::AppendFlag | C::PrependFlag | C::CacheFlag)) + << Range(0, 0, 1, int(VisibleFlag| C::CacheFlag))) + << C::Cache << 2 + << Selection << 1 + << 1 << 0 << 1 << 1 + << int(C::AppendFlag | C::PrependFlag | C::CacheFlag) << 1; +} + +void tst_qdeclarativelistcompositor::findInsertPosition() +{ + QFETCH(RangeList, ranges); + QFETCH(C::Group, startGroup); + QFETCH(int, startIndex); + QFETCH(C::Group, group); + QFETCH(int, index); + QFETCH(int, cacheIndex); + QFETCH(int, defaultIndex); + QFETCH(int, visibleIndex); + QFETCH(int, selectionIndex); + QFETCH(int, rangeFlags); + QFETCH(int, rangeIndex); + + QDeclarativeListCompositor compositor; + compositor.setGroupCount(4); + compositor.setDefaultGroups(VisibleFlag | C::DefaultFlag); + + foreach (const Range &range, ranges) + compositor.append(range.list, range.index, range.count, range.flags); + + QDeclarativeListCompositor::insert_iterator it = compositor.findInsertPosition(group, index); + QCOMPARE(it.index[C::Cache], cacheIndex); + QCOMPARE(it.index[C::Default], defaultIndex); + QCOMPARE(it.index[Visible], visibleIndex); + QCOMPARE(it.index[Selection], selectionIndex); + QCOMPARE(it->flags, rangeFlags); + QCOMPARE(it->index, rangeIndex); +} + void tst_qdeclarativelistcompositor::insert() { QDeclarativeListCompositor compositor; @@ -547,6 +676,27 @@ void tst_qdeclarativelistcompositor::setFlags_data() << IndexArray(defaultIndexes) << ListArray(defaultLists) << IndexArray(visibleIndexes) << ListArray(visibleLists) << IndexArray(selectionIndexes) << ListArray(selectionLists); + } { static const int cacheIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const void *cacheLists[] = {a,a,a,a,a,a,a,a,a,a, a, a}; + static const int defaultIndexes[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const void *defaultLists[] = {a,a,a,a,a,a,a,a,a,a, a, a}; + static const int visibleIndexes[] = {0,1,3,4,5,6,7,8,9,10,11}; + static const void *visibleLists[] = {a,a,a,a,a,a,a,a,a, a, a}; + static const int selectionIndexes[] = {2,6,7,8,9}; + static const void *selectionLists[] = {a,a,a,a,a}; + QTest::newRow("Existing flag, sparse selection") + << (RangeList() + << Range(a, 0, 2, C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 2, 1, C::PrependFlag | SelectionFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 3, 3, C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 6, 4, C::PrependFlag | SelectionFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a,10, 2, C::AppendFlag | C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag)) + << C::Cache << 3 << 1 << int(VisibleFlag) + << InsertList() + << IndexArray(cacheIndexes) << ListArray(cacheLists) + << IndexArray(defaultIndexes) << ListArray(defaultLists) + << IndexArray(visibleIndexes) << ListArray(visibleLists) + << IndexArray(selectionIndexes) << ListArray(selectionLists); } } @@ -756,6 +906,35 @@ void tst_qdeclarativelistcompositor::move_data() << IndexArray(defaultIndexes) << ListArray(defaultLists) << IndexArray() << ListArray() << IndexArray() << ListArray(); + } { static const int cacheIndexes[] = {8,9,10,4,11,0,1,2,3,5,6,7}; + static const void *cacheLists[] = {a,a, a,a, a,a,a,a,a,a,a,a}; + static const int defaultIndexes[] = {8,9,10,4,11,0,1,2,3,5,6,7}; + static const void *defaultLists[] = {a,a, a,a, a,a,a,a,a,a,a,a}; + static const int visibleIndexes[] = {8,9,10,4,11,0,1,2,3,5,6,7}; + static const void *visibleLists[] = {a,a, a,a, a,a,a,a,a,a,a,a}; + QTest::newRow("3, 4, 5") + << (RangeList() + << Range(a, 8, 4, VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 0, 2, C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 2, 1, C::PrependFlag) + << Range(a, 2, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 3, 5, C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 8, 4, C::AppendFlag | C::PrependFlag)) + << C::Default << 3 << C::Default << 4 << 5 + << (RemoveList() + << Remove(0, 3, 3, 3, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 0) + << Remove(0, 3, 3, 3, 2, VisibleFlag | C::DefaultFlag | C::CacheFlag, 1) + << Remove(0, 3, 3, 3, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 2) + << Remove(0, 3, 3, 3, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 3)) + << (InsertList() + << Insert(0, 4, 4, 4, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 0) + << Insert(0, 5, 5, 5, 2, VisibleFlag | C::DefaultFlag | C::CacheFlag, 1) + << Insert(0, 7, 7, 7, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 2) + << Insert(0, 8, 8, 8, 1, VisibleFlag | C::DefaultFlag | C::CacheFlag, 3)) + << IndexArray(cacheIndexes) << ListArray(cacheLists) + << IndexArray(defaultIndexes) << ListArray(defaultLists) + << IndexArray(visibleIndexes) << ListArray(visibleLists) + << IndexArray() << ListArray(); } } @@ -955,6 +1134,21 @@ void tst_qdeclarativelistcompositor::listItemsInserted_data() << IndexArray(defaultIndexes) << IndexArray(visibleIndexes) << IndexArray(); + } { static const int cacheIndexes[] = {/*A*/0,1,2,3,4}; + static const int defaultIndexes[] = {/*A*/0,1,2,3,4,5,6}; + static const int visibleIndexes[] = {/*A*/0,1,2,3,4,5,6}; + QTest::newRow("Consecutive appends") + << (RangeList() + << Range(a, 0, 5, C::PrependFlag | VisibleFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 5, 1, C::PrependFlag | VisibleFlag | C::DefaultFlag) + << Range(a, 6, 0, C::AppendFlag | VisibleFlag | C::PrependFlag | C::DefaultFlag | C::CacheFlag)) + << a << 6 << 1 + << (InsertList() + << Insert(0, 6, 6, 5, 1, VisibleFlag | C::DefaultFlag)) + << IndexArray(cacheIndexes) + << IndexArray(defaultIndexes) + << IndexArray(visibleIndexes) + << IndexArray(); } } @@ -1067,6 +1261,30 @@ void tst_qdeclarativelistcompositor::listItemsRemoved_data() << IndexArray(defaultIndexes) << IndexArray() << IndexArray(); + } { static const int cacheIndexes[] = {/*A*/-1,-1,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1}; + static const int defaultIndexes[] = {/*A*/0,1,2,3,4,5,6}; + QTest::newRow("Sparse remove") + << (RangeList() + << Range(a, 0, 2, C::CacheFlag) + << Range(a, 0, 1, C::DefaultFlag | C::CacheFlag) + << Range(a, 0, 1, C::CacheFlag) + << Range(a, 1, 5, C::DefaultFlag | C::CacheFlag) + << Range(a, 0, 1, C::CacheFlag) + << Range(a, 6, 2, C::DefaultFlag | C::CacheFlag) + << Range(a, 0, 1, C::CacheFlag) + << Range(a, 8, 3, C::DefaultFlag | C::CacheFlag) + << Range(a, 0, 1, C::CacheFlag) + << Range(a, 11, 1, C::DefaultFlag | C::CacheFlag) + << Range(a, 12, 5, C::DefaultFlag)) + << a << 1 << 10 + << (RemoveList() + << Remove(0, 0, 1, 4, 5, C::DefaultFlag | C::CacheFlag) + << Remove(0, 0, 1,10, 2, C::DefaultFlag | C::CacheFlag) + << Remove(0, 0, 1,13, 3, C::DefaultFlag | C::CacheFlag)) + << IndexArray(cacheIndexes) + << IndexArray(defaultIndexes) + << IndexArray() + << IndexArray(); } } @@ -1205,6 +1423,24 @@ void tst_qdeclarativelistcompositor::listItemsMoved_data() << IndexArray(defaultIndexes) << IndexArray() << IndexArray(); + } { static const int cacheIndexes[] = {/*A*/0,1,5,6,7,8,9,10,11,12}; + static const int defaultIndexes[] = {/*A*/0,1,2,3,4,5,6,7,8,9,10,11,12}; + QTest::newRow("Move merge tail") + << (RangeList() + << Range(a, 0, 10, C::PrependFlag | C::DefaultFlag | C::CacheFlag) + << Range(a, 10, 3, C::PrependFlag | C::DefaultFlag) + << Range(a, 13, 0, C::AppendFlag | C::PrependFlag | C::DefaultFlag | C::CacheFlag)) + << a << 8 << 0 << 5 + << (RemoveList() + << Remove(0, 0, 8, 8, 2, C::DefaultFlag | C::CacheFlag, 0) + << Remove(0, 0, 8, 8, 3, C::DefaultFlag, 1)) + << (InsertList() + << Insert(0, 0, 0, 0, 2, C::DefaultFlag | C::CacheFlag, 0) + << Insert(0, 0, 2, 2, 3, C::DefaultFlag, 1)) + << IndexArray(cacheIndexes) + << IndexArray(defaultIndexes) + << IndexArray() + << IndexArray(); } } diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/workerremoveelement.js b/tests/auto/declarative/qdeclarativelistmodel/data/workerremoveelement.js new file mode 100644 index 0000000000..cb9dfa66aa --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/workerremoveelement.js @@ -0,0 +1,8 @@ +WorkerScript.onMessage = function(msg) { + if (msg.action == 'removeItem') { + msg.model.remove(0); + } else if (msg.action == 'dosync') { + msg.model.sync(); + } + WorkerScript.sendMessage({'done': true}) +} diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/workerremoveelement.qml b/tests/auto/declarative/qdeclarativelistmodel/data/workerremoveelement.qml new file mode 100644 index 0000000000..e2361acf6b --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/workerremoveelement.qml @@ -0,0 +1,33 @@ +import QtQuick 2.0 + +Item { + id: item + property variant model + property bool done: false + + WorkerScript { + id: worker + source: "workerremoveelement.js" + onMessage: { + item.done = true + } + } + + function addItem() { + model.append({ 'data': 1 }); + + var element = model.get(0); + } + + function removeItemViaWorker() { + done = false + var msg = { 'action': 'removeItem', 'model': model } + worker.sendMessage(msg); + } + + function doSync() { + done = false + var msg = { 'action': 'dosync', 'model': model } + worker.sendMessage(msg); + } +} diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/workerremovelist.js b/tests/auto/declarative/qdeclarativelistmodel/data/workerremovelist.js new file mode 100644 index 0000000000..f63dd68839 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/workerremovelist.js @@ -0,0 +1,9 @@ +WorkerScript.onMessage = function(msg) { + if (msg.action == 'removeList') { + msg.model.remove(0); + } else if (msg.action == 'dosync') { + msg.model.sync(); + } + WorkerScript.sendMessage({'done': true}) +} + diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/workerremovelist.qml b/tests/auto/declarative/qdeclarativelistmodel/data/workerremovelist.qml new file mode 100644 index 0000000000..bdb5e024d8 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/workerremovelist.qml @@ -0,0 +1,33 @@ +import QtQuick 2.0 + +Item { + id: item + property variant model + property bool done: false + + WorkerScript { + id: worker + source: "workerremovelist.js" + onMessage: { + item.done = true + } + } + + function addList() { + model.append({ 'data': [ { 'subData': 1 } ] }); + + var element = model.get(0); + } + + function removeListViaWorker() { + done = false + var msg = { 'action': 'removeList', 'model': model } + worker.sendMessage(msg); + } + + function doSync() { + done = false + var msg = { 'action': 'dosync', 'model': model } + worker.sendMessage(msg); + } +} diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/workersync.js b/tests/auto/declarative/qdeclarativelistmodel/data/workersync.js new file mode 100644 index 0000000000..9b8d8fa7f3 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/workersync.js @@ -0,0 +1,8 @@ +WorkerScript.onMessage = function(msg) { + if (msg.action == 'addItem') { + msg.model.get(0).level0.append({ 'level1': 33 }); + } else if (msg.action == 'dosync') { + msg.model.sync(); + } + WorkerScript.sendMessage({'done': true}) +} diff --git a/tests/auto/declarative/qdeclarativelistmodel/data/workersync.qml b/tests/auto/declarative/qdeclarativelistmodel/data/workersync.qml new file mode 100644 index 0000000000..c21cd43e7e --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistmodel/data/workersync.qml @@ -0,0 +1,32 @@ +import QtQuick 2.0 + +Item { + id: item + property variant model + property bool done: false + + WorkerScript { + id: worker + source: "workersync.js" + onMessage: { + item.done = true + } + } + + function addItem0() { + model.append({ 'level0': [ { 'level1': 29 } ] }); + model.append({ 'level0': [ { 'level1': 37 } ] }); + } + + function addItemViaWorker() { + done = false + var msg = { 'action': 'addItem', 'model': model } + worker.sendMessage(msg); + } + + function doSync() { + done = false + var msg = { 'action': 'dosync', 'model': model } + worker.sendMessage(msg); + } +} diff --git a/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro b/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro index 1586e68281..fc8a3178ae 100644 --- a/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro +++ b/tests/auto/declarative/qdeclarativelistmodel/qdeclarativelistmodel.pro @@ -4,7 +4,9 @@ macx:CONFIG -= app_bundle SOURCES += tst_qdeclarativelistmodel.cpp -DEFINES += SRCDIR=\\\"$$PWD\\\" +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles CONFIG += parallel_test diff --git a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp index bc6c99102e..e5e12092e3 100644 --- a/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp +++ b/tests/auto/declarative/qdeclarativelistmodel/tst_qdeclarativelistmodel.cpp @@ -51,9 +51,22 @@ #include <QtCore/qtranslator.h> #include <QSignalSpy> +#include "../shared/util.h" + Q_DECLARE_METATYPE(QList<int>) Q_DECLARE_METATYPE(QList<QVariantHash>) +#define RUNEVAL(object, string) \ + QVERIFY(QMetaObject::invokeMethod(object, "runEval", Q_ARG(QVariant, QString(string)))); + +inline QVariant runexpr(QDeclarativeEngine *engine, const QString &str) +{ + QDeclarativeExpression expr(engine->rootContext(), 0, str); + return expr.evaluate(); +} + +#define RUNEXPR(string) runexpr(&engine, QString(string)) + class tst_qdeclarativelistmodel : public QObject { Q_OBJECT @@ -65,6 +78,8 @@ private: QQuickItem *createWorkerTest(QDeclarativeEngine *eng, QDeclarativeComponent *component, QDeclarativeListModel *model); void waitForWorker(QQuickItem *item); + static bool compareVariantList(const QVariantList &testList, QVariant object); + private slots: void static_types(); void static_types_data(); @@ -78,16 +93,12 @@ private slots: void dynamic_worker(); void dynamic_worker_sync_data(); void dynamic_worker_sync(); - void convertNestedToFlat_fail(); - void convertNestedToFlat_fail_data(); - void convertNestedToFlat_ok(); - void convertNestedToFlat_ok_data(); void enumerate(); void error_data(); void error(); void syncError(); - void set(); void get(); + void set(); void get_data(); void get_worker(); void get_worker_data(); @@ -101,8 +112,64 @@ private slots: void property_changes_worker_data(); void clear(); void signal_handlers(); + void worker_sync(); + void worker_remove_element(); + void worker_remove_list(); }; +bool tst_qdeclarativelistmodel::compareVariantList(const QVariantList &testList, QVariant object) +{ + bool allOk = true; + + QDeclarativeListModel *model = qobject_cast<QDeclarativeListModel *>(object.value<QObject *>()); + if (model == 0) + return false; + + if (model->count() != testList.count()) + return false; + + for (int i=0 ; i < testList.count() ; ++i) { + const QVariant &testVariant = testList.at(i); + if (testVariant.type() != QVariant::Map) + return false; + const QVariantMap &map = testVariant.toMap(); + + const QList<int> &roles = model->roles(); + + QVariantMap::const_iterator it = map.begin(); + QVariantMap::const_iterator end = map.end(); + + while (it != end) { + const QString &testKey = it.key(); + const QVariant &testData = it.value(); + + int roleIndex = -1; + for (int j=0 ; j < roles.count() ; ++j) { + if (model->toString(roles[j]).compare(testKey) == 0) { + roleIndex = j; + break; + } + } + + if (roleIndex == -1) + return false; + + const QVariant &modelData = model->data(i, roleIndex); + + if (testData.type() == QVariant::List) { + const QVariantList &subList = testData.toList(); + allOk = allOk && compareVariantList(subList, modelData); + } else { + allOk = allOk && (testData == modelData); + } + + ++it; + } + } + + return allOk; +} + int tst_qdeclarativelistmodel::roleFromName(const QDeclarativeListModel *model, const QString &roleName) { QList<int> roles = model->roles(); @@ -118,7 +185,7 @@ QQuickItem *tst_qdeclarativelistmodel::createWorkerTest(QDeclarativeEngine *eng, QQuickItem *item = qobject_cast<QQuickItem*>(component->create()); QDeclarativeEngine::setContextForObject(model, eng->rootContext()); if (item) - item->setProperty("model", qVariantFromValue(model)); + item->setProperty("model", qVariantFromValue(model)); return item; } @@ -141,43 +208,66 @@ void tst_qdeclarativelistmodel::static_types_data() { QTest::addColumn<QString>("qml"); QTest::addColumn<QVariant>("value"); + QTest::addColumn<QString>("error"); QTest::newRow("string") << "ListElement { foo: \"bar\" }" - << QVariant(QString("bar")); + << QVariant(QString("bar")) + << QString(); QTest::newRow("real") << "ListElement { foo: 10.5 }" - << QVariant(10.5); + << QVariant(10.5) + << QString(); QTest::newRow("real0") << "ListElement { foo: 0 }" - << QVariant(double(0)); + << QVariant(double(0)) + << QString(); QTest::newRow("bool") << "ListElement { foo: false }" - << QVariant(false); + << QVariant(false) + << QString(); QTest::newRow("bool") << "ListElement { foo: true }" - << QVariant(true); + << QVariant(true) + << QString(); QTest::newRow("enum") << "ListElement { foo: Text.AlignHCenter }" - << QVariant(double(QQuickText::AlignHCenter)); + << QVariant(double(QQuickText::AlignHCenter)) + << QString(); QTest::newRow("Qt enum") << "ListElement { foo: Qt.AlignBottom }" - << QVariant(double(Qt::AlignBottom)); + << QVariant(double(Qt::AlignBottom)) + << QString(); + + QTest::newRow("role error") + << "ListElement { foo: 1 } ListElement { foo: 'string' }" + << QVariant() + << QString("<Unknown File>: Can't assign to existing role 'foo' of different type [String -> Number]"); + + QTest::newRow("list type error") + << "ListElement { foo: 1 } ListElement { foo: ListElement { bar: 1 } }" + << QVariant() + << QString("<Unknown File>: Can't assign to existing role 'foo' of different type [List -> Number]"); } void tst_qdeclarativelistmodel::static_types() { QFETCH(QString, qml); QFETCH(QVariant, value); + QFETCH(QString, error); qml = "import QtQuick 2.0\nItem { property variant test: model.get(0).foo; ListModel { id: model; " + qml + " } }"; + if (!error.isEmpty()) { + QTest::ignoreMessage(QtWarningMsg, error.toLatin1()); + } + QDeclarativeEngine engine; QDeclarativeComponent component(&engine); component.setData(qml.toUtf8(), @@ -188,10 +278,12 @@ void tst_qdeclarativelistmodel::static_types() QObject *obj = component.create(); QVERIFY(obj != 0); - QVariant actual = obj->property("test"); + if (error.isEmpty()) { + QVariant actual = obj->property("test"); - QCOMPARE(actual, value); - QCOMPARE(actual.toString(), value.toString()); + QCOMPARE(actual, value); + QCOMPARE(actual.toString(), value.toString()); + } delete obj; } @@ -270,11 +362,11 @@ void tst_qdeclarativelistmodel::static_nestedElements() QFETCH(int, elementCount); QStringList elements; - for (int i=0; i<elementCount; i++) + for (int i=0; i<elementCount; i++) elements.append("ListElement { a: 1; b: 2 }"); QString elementsStr = elements.join(",\n") + "\n"; - QString componentStr = + QString componentStr = "import QtQuick 2.0\n" "Item {\n" " property variant count: model.get(0).attributes.count\n" @@ -283,7 +375,7 @@ void tst_qdeclarativelistmodel::static_nestedElements() " ListElement {\n" " attributes: [\n"; componentStr += elementsStr.toUtf8().constData(); - componentStr += + componentStr += " ]\n" " }\n" " }\n" @@ -320,7 +412,6 @@ void tst_qdeclarativelistmodel::dynamic_data() QTest::addColumn<QString>("warning"); // Simple flat model - QTest::newRow("count") << "count" << 0 << ""; QTest::newRow("get1") << "{get(0) === undefined}" << 1 << ""; @@ -336,7 +427,8 @@ void tst_qdeclarativelistmodel::dynamic_data() QTest::newRow("append3a") << "{append({'foo':123});append({'foo':456});get(0).foo}" << 123 << ""; QTest::newRow("append3b") << "{append({'foo':123});append({'foo':456});get(1).foo}" << 456 << ""; QTest::newRow("append4a") << "{append(123)}" << 0 << "<Unknown File>: QML ListModel: append: value is not an object"; - QTest::newRow("append4b") << "{append([1,2,3])}" << 0 << "<Unknown File>: QML ListModel: append: value is not an object"; + QTest::newRow("append4b") << "{append([{'foo':123},{'foo':456},{'foo':789}]);count}" << 3 << ""; + QTest::newRow("append4c") << "{append([{'foo':123},{'foo':456},{'foo':789}]);get(1).foo}" << 456 << ""; QTest::newRow("clear1") << "{append({'foo':456});clear();count}" << 0 << ""; QTest::newRow("clear2") << "{append({'foo':123});append({'foo':456});clear();count}" << 0 << ""; @@ -361,7 +453,8 @@ void tst_qdeclarativelistmodel::dynamic_data() QTest::newRow("insert3e") << "{append({'foo':123});insert(0,{'foo':456});get(1).foo}" << 123 << ""; QTest::newRow("insert4") << "{append({'foo':123});insert(-1,{'foo':456});count}" << 1 << "<Unknown File>: QML ListModel: insert: index -1 out of range"; QTest::newRow("insert5a") << "{insert(0,123)}" << 0 << "<Unknown File>: QML ListModel: insert: value is not an object"; - QTest::newRow("insert5b") << "{insert(0,[1,2,3])}" << 0 << "<Unknown File>: QML ListModel: insert: value is not an object"; + QTest::newRow("insert5b") << "{insert(0,[{'foo':11},{'foo':22},{'foo':33}]);count}" << 3 << ""; + QTest::newRow("insert5c") << "{insert(0,[{'foo':11},{'foo':22},{'foo':33}]);get(2).foo}" << 33 << ""; QTest::newRow("set1") << "{append({'foo':123});set(0,{'foo':456});count}" << 1 << ""; QTest::newRow("set2") << "{append({'foo':123});set(0,{'foo':456});get(0).foo}" << 456 << ""; @@ -396,8 +489,38 @@ void tst_qdeclarativelistmodel::dynamic_data() QTest::newRow("move3c") << "{append({'foo':123});append({'foo':456});append({'foo':789});move(1,0,-1);count}" << 3 << "<Unknown File>: QML ListModel: move: out of range"; QTest::newRow("move3d") << "{append({'foo':123});append({'foo':456});append({'foo':789});move(0,3,1);count}" << 3 << "<Unknown File>: QML ListModel: move: out of range"; - // Nested models + QTest::newRow("large1") << "{append({'a':1,'b':2,'c':3,'d':4,'e':5,'f':6,'g':7,'h':8});get(0).h}" << 8 << ""; + + QTest::newRow("datatypes1") << "{append({'a':1});append({'a':'string'});}" << 0 << "<Unknown File>: Can't assign to existing role 'a' of different type [String -> Number]"; + + QTest::newRow("null") << "{append({'a':null});}" << 0 << ""; + QTest::newRow("setNull") << "{append({'a':1});set(0, {'a':null});}" << 0 << ""; + QTest::newRow("setString") << "{append({'a':'hello'});set(0, {'a':'world'});get(0).a == 'world'}" << 1 << ""; + QTest::newRow("setInt") << "{append({'a':5});set(0, {'a':10});get(0).a}" << 10 << ""; + QTest::newRow("setNumber") << "{append({'a':6});set(0, {'a':5.5});get(0).a < 5.6}" << 1 << ""; + QTest::newRow("badType0") << "{append({'a':'hello'});set(0, {'a':1});}" << 0 << "<Unknown File>: Can't assign to existing role 'a' of different type [Number -> String]"; + QTest::newRow("invalidInsert0") << "{insert(0);}" << 0 << "<Unknown File>: QML ListModel: insert: value is not an object"; + QTest::newRow("invalidAppend0") << "{append();}" << 0 << "<Unknown File>: QML ListModel: append: value is not an object"; + QTest::newRow("invalidInsert1") << "{insert(0, 34);}" << 0 << "<Unknown File>: QML ListModel: insert: value is not an object"; + QTest::newRow("invalidAppend1") << "{append(37);}" << 0 << "<Unknown File>: QML ListModel: append: value is not an object"; + + // QObjects + QTest::newRow("qobject0") << "{append({'a':dummyItem0});}" << 0 << ""; + QTest::newRow("qobject1") << "{append({'a':dummyItem0});set(0,{'a':dummyItem1});get(0).a == dummyItem1;}" << 1 << ""; + QTest::newRow("qobject2") << "{append({'a':dummyItem0});get(0).a == dummyItem0;}" << 1 << ""; + QTest::newRow("qobject3") << "{append({'a':dummyItem0});append({'b':1});}" << 0 << ""; + + // JS objects + QTest::newRow("js1") << "{append({'foo':{'prop':1}});count}" << 1 << ""; + QTest::newRow("js2") << "{append({'foo':{'prop':27}});get(0).foo.prop}" << 27 << ""; + QTest::newRow("js3") << "{append({'foo':{'prop':27}});append({'bar':1});count}" << 2 << ""; + QTest::newRow("js4") << "{append({'foo':{'prop':27}});append({'bar':1});set(0, {'foo':{'prop':28}});get(0).foo.prop}" << 28 << ""; + QTest::newRow("js5") << "{append({'foo':{'prop':27}});append({'bar':1});set(1, {'foo':{'prop':33}});get(1).foo.prop}" << 33 << ""; + QTest::newRow("js6") << "{append({'foo':{'prop':27}});clear();count}" << 0 << ""; + QTest::newRow("js7") << "{append({'foo':{'prop':27}});set(0, {'foo':null});count}" << 1 << ""; + QTest::newRow("js8") << "{append({'foo':{'prop':27}});set(0, {'foo':{'prop2':31}});get(0).foo.prop2}" << 31 << ""; + // Nested models QTest::newRow("nested-append1") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]});count}" << 1 << ""; QTest::newRow("nested-append2") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]});get(0).bars.get(1).a}" << 2 << ""; QTest::newRow("nested-append3") << "{append({'foo':123,'bars':[{'a':1},{'a':2},{'a':3}]});get(0).bars.append({'a':4});get(0).bars.get(3).a}" << 4 << ""; @@ -415,10 +538,13 @@ void tst_qdeclarativelistmodel::dynamic() QFETCH(int, result); QFETCH(QString, warning); + QQuickItem dummyItem0, dummyItem1; QDeclarativeEngine engine; QDeclarativeListModel model; QDeclarativeEngine::setContextForObject(&model,engine.rootContext()); engine.rootContext()->setContextObject(&model); + engine.rootContext()->setContextProperty("dummyItem0", QVariant::fromValue(&dummyItem0)); + engine.rootContext()->setContextProperty("dummyItem1", QVariant::fromValue(&dummyItem1)); QDeclarativeExpression e(engine.rootContext(), &model, script); if (!warning.isEmpty()) QTest::ignoreMessage(QtWarningMsg, warning.toLatin1()); @@ -446,16 +572,15 @@ void tst_qdeclarativelistmodel::dynamic_worker() QFETCH(int, result); QFETCH(QString, warning); - if (QByteArray(QTest::currentDataTag()).startsWith("nested")) + if (QByteArray(QTest::currentDataTag()).startsWith("qobject")) return; - // This is same as dynamic() except it applies the test to a ListModel called - // from a WorkerScript (i.e. testing the internal FlatListModel that is created - // by the WorkerListModelAgent) + // This is same as dynamic() except it applies the test to a ListModel called + // from a WorkerScript. QDeclarativeListModel model; QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("model.qml"))); QQuickItem *item = createWorkerTest(&eng, &component, &model); QVERIFY(item != 0); @@ -495,13 +620,16 @@ void tst_qdeclarativelistmodel::dynamic_worker_sync() QFETCH(int, result); QFETCH(QString, warning); + if (QByteArray(QTest::currentDataTag()).startsWith("qobject")) + return; + // This is the same as dynamic_worker() except that it executes a set of list operations // from the worker script, calls sync(), and tests the changes are reflected in the // list in the main thread - + QDeclarativeListModel model; QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("model.qml"))); QQuickItem *item = createWorkerTest(&eng, &component, &model); QVERIFY(item != 0); @@ -518,139 +646,55 @@ void tst_qdeclarativelistmodel::dynamic_worker_sync() // execute a set of commands on the worker list model, then check the // changes are reflected in the list model in the main thread - if (QByteArray(QTest::currentDataTag()).startsWith("nested")) - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML ListModel: Cannot add list-type data when modifying or after modification from a worker script"); - - if (QByteArray(QTest::currentDataTag()).startsWith("nested-set")) - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML ListModel: Cannot add list-type data when modifying or after modification from a worker script"); - - QVERIFY(QMetaObject::invokeMethod(item, "evalExpressionViaWorker", + QVERIFY(QMetaObject::invokeMethod(item, "evalExpressionViaWorker", Q_ARG(QVariant, operations.mid(0, operations.length()-1)))); waitForWorker(item); QDeclarativeExpression e(eng.rootContext(), &model, operations.last().toString()); - if (!QByteArray(QTest::currentDataTag()).startsWith("nested")) - QCOMPARE(e.evaluate().toInt(), result); + QCOMPARE(e.evaluate().toInt(), result); delete item; qApp->processEvents(); } -#define RUNEVAL(object, string) \ - QVERIFY(QMetaObject::invokeMethod(object, "runEval", Q_ARG(QVariant, QString(string)))); - -inline QVariant runexpr(QDeclarativeEngine *engine, const QString &str) -{ - QDeclarativeExpression expr(engine->rootContext(), 0, str); - return expr.evaluate(); -} - -#define RUNEXPR(string) runexpr(&engine, QString(string)) - -void tst_qdeclarativelistmodel::convertNestedToFlat_fail() -{ - // If a model has nested data, it cannot be used at all from a worker script - - QFETCH(QString, script); - - QDeclarativeListModel model; - QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); - QQuickItem *item = createWorkerTest(&eng, &component, &model); - QVERIFY(item != 0); - - RUNEVAL(item, "model.append({foo: 123})"); - RUNEVAL(item, "model.append({foo: [{}, {}]})"); - - QCOMPARE(model.count(), 2); - - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML ListModel: List contains list-type data and cannot be used from a worker script"); - QVERIFY(QMetaObject::invokeMethod(item, "evalExpressionViaWorker", Q_ARG(QVariant, script))); - waitForWorker(item); - - QCOMPARE(model.count(), 2); - - delete item; - qApp->processEvents(); -} - -void tst_qdeclarativelistmodel::convertNestedToFlat_fail_data() -{ - QTest::addColumn<QString>("script"); - - QTest::newRow("clear") << "clear()"; - QTest::newRow("remove") << "remove(0)"; - QTest::newRow("append") << "append({'x':1})"; - QTest::newRow("insert") << "insert(0, {'x':1})"; - QTest::newRow("set") << "set(0, {'foo':1})"; - QTest::newRow("setProperty") << "setProperty(0, 'foo', 1})"; - QTest::newRow("move") << "move(0, 1, 1})"; - QTest::newRow("get") << "get(0)"; -} - -void tst_qdeclarativelistmodel::convertNestedToFlat_ok() - +void tst_qdeclarativelistmodel::enumerate() { - // If a model only has plain data, it can be modified from a worker script. However, - // once the model is used from a worker script, it no longer accepts nested data - - QFETCH(QString, script); - - QDeclarativeListModel model; QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); - QQuickItem *item = createWorkerTest(&eng, &component, &model); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("enumerate.qml"))); + QVERIFY(!component.isError()); + QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); QVERIFY(item != 0); - RUNEVAL(item, "model.append({foo: 123})"); - - QCOMPARE(model.count(), 1); - - QVERIFY(QMetaObject::invokeMethod(item, "evalExpressionViaWorker", Q_ARG(QVariant, script))); - waitForWorker(item); - - // can still add plain data - int count = model.count(); - - RUNEVAL(item, "model.append({foo: 123})"); - - QCOMPARE(model.count(), count+1); + QLatin1String expectedStrings[] = { + QLatin1String("val1=1Y"), + QLatin1String("val2=2Y"), + QLatin1String("val3=strY"), + QLatin1String("val4=falseN"), + QLatin1String("val5=trueY") + }; - const char *warning = "<Unknown File>: QML ListModel: Cannot add list-type data when modifying or after modification from a worker script"; + int expectedStringCount = sizeof(expectedStrings) / sizeof(expectedStrings[0]); - QTest::ignoreMessage(QtWarningMsg, warning); - RUNEVAL(item, "model.append({foo: [{}, {}]})"); - - QTest::ignoreMessage(QtWarningMsg, warning); - RUNEVAL(item, "model.insert(0, {foo: [{}, {}]})"); + QStringList r = item->property("result").toString().split(":"); - QTest::ignoreMessage(QtWarningMsg, warning); - RUNEVAL(item, "model.set(0, {foo: [{}, {}]})"); + int matchCount = 0; + for (int i=0 ; i < expectedStringCount ; ++i) { + const QLatin1String &expectedString = expectedStrings[i]; - QCOMPARE(model.count(), count+1); + QStringList::const_iterator it = r.begin(); + QStringList::const_iterator end = r.end(); - delete item; - qApp->processEvents(); -} + while (it != end) { + if (it->compare(expectedString) == 0) { + ++matchCount; + break; + } + ++it; + } + } -void tst_qdeclarativelistmodel::convertNestedToFlat_ok_data() -{ - convertNestedToFlat_fail_data(); -} + QVERIFY(matchCount == expectedStringCount); -void tst_qdeclarativelistmodel::enumerate() -{ - QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/enumerate.qml")); - QVERIFY(!component.isError()); - QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); - QVERIFY(item != 0); - QStringList r = item->property("result").toString().split(":"); - QCOMPARE(r[0],QLatin1String("val1=1Y")); - QCOMPARE(r[1],QLatin1String("val2=2Y")); - QCOMPARE(r[2],QLatin1String("val3=strY")); - QCOMPARE(r[3],QLatin1String("val4=falseN")); - QCOMPARE(r[4],QLatin1String("val5=trueY")); delete item; } @@ -752,11 +796,15 @@ void tst_qdeclarativelistmodel::set() RUNEXPR("model.set(0, {test:true})"); QCOMPARE(RUNEXPR("model.get(0).test").toBool(), true); // triggers creation of model cache - QCOMPARE(model.data(0, model.roles()[0]), qVariantFromValue(true)); + QCOMPARE(model.data(0, model.roles()[0]), qVariantFromValue(true)); RUNEXPR("model.set(0, {test:false})"); QCOMPARE(RUNEXPR("model.get(0).test").toBool(), false); // tests model cache is updated - QCOMPARE(model.data(0, model.roles()[0]), qVariantFromValue(false)); + QCOMPARE(model.data(0, model.roles()[0]), qVariantFromValue(false)); + + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Can't create role for unsupported data type"); + QVariant invalidData = QColor(); + model.setProperty(0, "test", invalidData); } /* @@ -773,21 +821,31 @@ void tst_qdeclarativelistmodel::get() QDeclarativeComponent component(&engine); component.setData( "import QtQuick 2.0\n" - "ListModel { \n" - "ListElement { roleA: 100 }\n" - "ListElement { roleA: 200; roleB: 400 } \n" - "ListElement { roleA: 200; roleB: 400 } \n" - "}", QUrl()); + "ListModel {}\n", QUrl()); QDeclarativeListModel *model = qobject_cast<QDeclarativeListModel*>(component.create()); - int role = roleFromName(model, roleName); - QVERIFY(role >= 0); + engine.rootContext()->setContextProperty("model", model); + + RUNEXPR("model.append({roleA: 100})"); + RUNEXPR("model.append({roleA: 200, roleB: 400})"); + RUNEXPR("model.append({roleA: 200, roleB: 400})"); + RUNEXPR("model.append({roleC: {} })"); + RUNEXPR("model.append({roleD: [ { a:1, b:2 }, { c: 3 } ] })"); QSignalSpy spy(model, SIGNAL(itemsChanged(int, int, QList<int>))); QDeclarativeExpression expr(engine.rootContext(), model, expression); expr.evaluate(); QVERIFY(!expr.hasError()); - QCOMPARE(model->data(index, role), roleValue); + int role = roleFromName(model, roleName); + QVERIFY(role >= 0); + + if (roleValue.type() == QVariant::List) { + const QVariantList &list = roleValue.toList(); + QVERIFY(compareVariantList(list, model->data(index, role))); + } else { + QCOMPARE(model->data(index, role), roleValue); + } + QCOMPARE(spy.count(), 1); QList<QVariant> spyResult = spy.takeFirst(); @@ -805,19 +863,16 @@ void tst_qdeclarativelistmodel::get_data() QTest::addColumn<QString>("roleName"); QTest::addColumn<QVariant>("roleValue"); - QTest::newRow("simple value") << "get(0).roleA = 500" << 0 << "roleA" << QVariant(500); - QTest::newRow("simple value 2") << "get(1).roleB = 500" << 1 << "roleB" << QVariant(500); + QTest::newRow("simple value") << "get(0).roleA = 500" << 0 << "roleA" << QVariant(500); + QTest::newRow("simple value 2") << "get(1).roleB = 500" << 1 << "roleB" << QVariant(500); QVariantMap map; - map["zzz"] = 123; - QTest::newRow("object value") << "get(1).roleB = {'zzz':123}" << 1 << "roleB" << QVariant::fromValue(map); - QVariantList list; map.clear(); map["a"] = 50; map["b"] = 500; list << map; map.clear(); map["c"] = 1000; list << map; - QTest::newRow("list of objects") << "get(2).roleB = [{'a': 50, 'b': 500}, {'c': 1000}]" << 2 << "roleB" << QVariant::fromValue(list); + QTest::newRow("list of objects") << "get(2).roleD = [{'a': 50, 'b': 500}, {'c': 1000}]" << 2 << "roleD" << QVariant::fromValue(list); } void tst_qdeclarativelistmodel::get_worker() @@ -829,7 +884,7 @@ void tst_qdeclarativelistmodel::get_worker() QDeclarativeListModel model; QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("model.qml"))); QQuickItem *item = createWorkerTest(&eng, &component, &model); QVERIFY(item != 0); @@ -837,13 +892,12 @@ void tst_qdeclarativelistmodel::get_worker() RUNEVAL(item, "model.append({roleA: 100})"); RUNEVAL(item, "model.append({roleA: 200, roleB: 400})"); RUNEVAL(item, "model.append({roleA: 200, roleB: 400})"); + RUNEVAL(item, "model.append({roleC: {} })"); + RUNEVAL(item, "model.append({roleD: [ { a:1, b:2 }, { c: 3 } ] })"); int role = roleFromName(&model, roleName); QVERIFY(role >= 0); - const char *warning = "<Unknown File>: QML ListModel: Cannot add list-type data when modifying or after modification from a worker script"; - if (roleValue.type() == QVariant::List || roleValue.type() == QVariant::Map) - QTest::ignoreMessage(QtWarningMsg, warning); QSignalSpy spy(&model, SIGNAL(itemsChanged(int, int, QList<int>))); // in the worker thread, change the model data and call sync() @@ -852,18 +906,19 @@ void tst_qdeclarativelistmodel::get_worker() waitForWorker(item); // see if we receive the model changes in the main thread's model - if (roleValue.type() == QVariant::List || roleValue.type() == QVariant::Map) { - QVERIFY(model.data(index, role) != roleValue); - QCOMPARE(spy.count(), 0); + if (roleValue.type() == QVariant::List) { + const QVariantList &list = roleValue.toList(); + QVERIFY(compareVariantList(list, model.data(index, role))); } else { QCOMPARE(model.data(index, role), roleValue); - QCOMPARE(spy.count(), 1); - - QList<QVariant> spyResult = spy.takeFirst(); - QCOMPARE(spyResult.at(0).toInt(), index); - QCOMPARE(spyResult.at(1).toInt(), 1); // only 1 item is modified at a time - QVERIFY(spyResult.at(2).value<QList<int> >().contains(role)); } + + QCOMPARE(spy.count(), 1); + + QList<QVariant> spyResult = spy.takeFirst(); + QCOMPARE(spyResult.at(0).toInt(), index); + QCOMPARE(spyResult.at(1).toInt(), 1); // only 1 item is modified at a time + QVERIFY(spyResult.at(2).value<QList<int> >().contains(role)); } void tst_qdeclarativelistmodel::get_worker_data() @@ -881,39 +936,48 @@ void tst_qdeclarativelistmodel::get_nested() QFETCH(QString, roleName); QFETCH(QVariant, roleValue); - QDeclarativeEngine eng; - QDeclarativeComponent component(&eng); + if (roleValue.type() == QVariant::Map) + return; + + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine); component.setData( "import QtQuick 2.0\n" - "ListModel { \n" - "ListElement {\n" - "listRoleA: [\n" - "ListElement { roleA: 100 },\n" - "ListElement { roleA: 200; roleB: 400 },\n" - "ListElement { roleA: 200; roleB: 400 } \n" - "]\n" - "}\n" - "ListElement {\n" - "listRoleA: [\n" - "ListElement { roleA: 100 },\n" - "ListElement { roleA: 200; roleB: 400 },\n" - "ListElement { roleA: 200; roleB: 400 } \n" - "]\n" - "listRoleB: [\n" - "ListElement { roleA: 100 },\n" - "ListElement { roleA: 200; roleB: 400 },\n" - "ListElement { roleA: 200; roleB: 400 } \n" - "]\n" - "listRoleC: [\n" - "ListElement { roleA: 100 },\n" - "ListElement { roleA: 200; roleB: 400 },\n" - "ListElement { roleA: 200; roleB: 400 } \n" - "]\n" - "}\n" - "}", QUrl()); + "ListModel {}", QUrl()); QDeclarativeListModel *model = qobject_cast<QDeclarativeListModel*>(component.create()); QVERIFY(component.errorString().isEmpty()); QDeclarativeListModel *childModel; + engine.rootContext()->setContextProperty("model", model); + + RUNEXPR("model.append({ listRoleA: [\n" + "{ roleA: 100 },\n" + "{ roleA: 200, roleB: 400 },\n" + "{ roleA: 200, roleB: 400 }, \n" + "{ roleC: {} }, \n" + "{ roleD: [ { a: 1, b:2 }, { c: 3 } ] } \n" + "] })\n"); + + RUNEXPR("model.append({ listRoleA: [\n" + "{ roleA: 100 },\n" + "{ roleA: 200, roleB: 400 },\n" + "{ roleA: 200, roleB: 400 }, \n" + "{ roleC: {} }, \n" + "{ roleD: [ { a: 1, b:2 }, { c: 3 } ] } \n" + "],\n" + "listRoleB: [\n" + "{ roleA: 100 },\n" + "{ roleA: 200, roleB: 400 },\n" + "{ roleA: 200, roleB: 400 }, \n" + "{ roleC: {} }, \n" + "{ roleD: [ { a: 1, b:2 }, { c: 3 } ] } \n" + "],\n" + "listRoleC: [\n" + "{ roleA: 100 },\n" + "{ roleA: 200, roleB: 400 },\n" + "{ roleA: 200, roleB: 400 }, \n" + "{ roleC: {} }, \n" + "{ roleD: [ { a: 1, b:2 }, { c: 3 } ] } \n" + "] })\n"); // Test setting the inner list data for: // get(0).listRoleA @@ -937,7 +1001,7 @@ void tst_qdeclarativelistmodel::get_nested() QVERIFY(childModel); QString extendedExpression = QString("get(%1).%2.%3").arg(outerListIndex).arg(outerListRoleName).arg(expression); - QDeclarativeExpression expr(eng.rootContext(), model, extendedExpression); + QDeclarativeExpression expr(engine.rootContext(), model, extendedExpression); QSignalSpy spy(childModel, SIGNAL(itemsChanged(int, int, QList<int>))); expr.evaluate(); @@ -945,7 +1009,11 @@ void tst_qdeclarativelistmodel::get_nested() int role = roleFromName(childModel, roleName); QVERIFY(role >= 0); - QCOMPARE(childModel->data(index, role), roleValue); + if (roleValue.type() == QVariant::List) { + QVERIFY(compareVariantList(roleValue.toList(), childModel->data(index, role))); + } else { + QCOMPARE(childModel->data(index, role), roleValue); + } QCOMPARE(spy.count(), 1); QList<QVariant> spyResult = spy.takeFirst(); @@ -966,7 +1034,7 @@ void tst_qdeclarativelistmodel::get_nested_data() void tst_qdeclarativelistmodel::crash_model_with_multiple_roles() { QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/multipleroles.qml")); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("multipleroles.qml"))); QObject *rootItem = component.create(); QVERIFY(component.errorString().isEmpty()); QVERIFY(rootItem != 0); @@ -983,7 +1051,7 @@ void tst_qdeclarativelistmodel::crash_model_with_multiple_roles() void tst_qdeclarativelistmodel::set_model_cache() { QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/setmodelcachelist.qml")); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("setmodelcachelist.qml"))); QObject *model = component.create(); QVERIFY2(component.errorString().isEmpty(), QTest::toString(component.errorString())); QVERIFY(model != 0); @@ -1017,6 +1085,7 @@ void tst_qdeclarativelistmodel::property_changes() "target: model.get(" + QString::number(listIndex) + ")\n" + signalHandler + " gotSignal = true\n" "}\n"; + QDeclarativeComponent component(&engine); component.setData(qml.toUtf8(), QUrl::fromLocalFile("")); engine.rootContext()->setContextProperty("model", &model); @@ -1117,10 +1186,6 @@ void tst_qdeclarativelistmodel::property_changes_data() void tst_qdeclarativelistmodel::property_changes_worker() { - // nested models are not supported when WorkerScript is involved - if (QByteArray(QTest::currentDataTag()).startsWith("nested-")) - return; - QFETCH(QString, script_setup); QFETCH(QString, script_change); QFETCH(QString, roleName); @@ -1129,7 +1194,7 @@ void tst_qdeclarativelistmodel::property_changes_worker() QDeclarativeListModel model; QDeclarativeEngine engine; - QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/model.qml")); + QDeclarativeComponent component(&engine, QUrl::fromLocalFile(TESTDATA("model.qml"))); QVERIFY2(component.errorString().isEmpty(), component.errorString().toUtf8()); QQuickItem *item = createWorkerTest(&engine, &component, &model); QVERIFY(item != 0); @@ -1199,7 +1264,7 @@ void tst_qdeclarativelistmodel::clear() void tst_qdeclarativelistmodel::signal_handlers() { QDeclarativeEngine eng; - QDeclarativeComponent component(&eng, QUrl::fromLocalFile(SRCDIR "/data/signalhandlers.qml")); + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("signalhandlers.qml"))); QObject *model = component.create(); QVERIFY2(component.errorString().isEmpty(), QTest::toString(component.errorString())); QVERIFY(model != 0); @@ -1208,6 +1273,129 @@ void tst_qdeclarativelistmodel::signal_handlers() delete model; } +void tst_qdeclarativelistmodel::worker_sync() +{ + QDeclarativeListModel model; + QDeclarativeEngine eng; + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("workersync.qml"))); + QQuickItem *item = createWorkerTest(&eng, &component, &model); + QVERIFY(item != 0); + + QVERIFY(model.count() == 0); + + QVERIFY(QMetaObject::invokeMethod(item, "addItem0")); + + QVERIFY(model.count() == 2); + QVariant childData = model.data(0, 0); + QDeclarativeListModel *childModel = qobject_cast<QDeclarativeListModel *>(childData.value<QObject *>()); + QVERIFY(childModel); + QVERIFY(childModel->count() == 1); + + QSignalSpy spyModelInserted(&model, SIGNAL(itemsInserted(int,int))); + QSignalSpy spyChildInserted(childModel, SIGNAL(itemsInserted(int,int))); + + QVERIFY(QMetaObject::invokeMethod(item, "addItemViaWorker")); + waitForWorker(item); + + QVERIFY(model.count() == 2); + QVERIFY(childModel->count() == 1); + QVERIFY(spyModelInserted.count() == 0); + QVERIFY(spyChildInserted.count() == 0); + + QVERIFY(QMetaObject::invokeMethod(item, "doSync")); + waitForWorker(item); + + QVERIFY(model.count() == 2); + QVERIFY(childModel->count() == 2); + QVERIFY(spyModelInserted.count() == 0); + QVERIFY(spyChildInserted.count() == 1); + + QVERIFY(QMetaObject::invokeMethod(item, "addItemViaWorker")); + waitForWorker(item); + + QVERIFY(model.count() == 2); + QVERIFY(childModel->count() == 2); + QVERIFY(spyModelInserted.count() == 0); + QVERIFY(spyChildInserted.count() == 1); + + QVERIFY(QMetaObject::invokeMethod(item, "doSync")); + waitForWorker(item); + + QVERIFY(model.count() == 2); + QVERIFY(childModel->count() == 3); + QVERIFY(spyModelInserted.count() == 0); + QVERIFY(spyChildInserted.count() == 2); + + delete item; + qApp->processEvents(); +} + +void tst_qdeclarativelistmodel::worker_remove_element() +{ + QDeclarativeListModel model; + QDeclarativeEngine eng; + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("workerremoveelement.qml"))); + QQuickItem *item = createWorkerTest(&eng, &component, &model); + QVERIFY(item != 0); + + QSignalSpy spyModelRemoved(&model, SIGNAL(itemsRemoved(int,int))); + + QVERIFY(model.count() == 0); + QVERIFY(spyModelRemoved.count() == 0); + + QVERIFY(QMetaObject::invokeMethod(item, "addItem")); + + QVERIFY(model.count() == 1); + + QVERIFY(QMetaObject::invokeMethod(item, "removeItemViaWorker")); + waitForWorker(item); + + QVERIFY(model.count() == 1); + QVERIFY(spyModelRemoved.count() == 0); + + QVERIFY(QMetaObject::invokeMethod(item, "doSync")); + waitForWorker(item); + + QVERIFY(model.count() == 0); + QVERIFY(spyModelRemoved.count() == 1); + + delete item; + qApp->processEvents(); +} + +void tst_qdeclarativelistmodel::worker_remove_list() +{ + QDeclarativeListModel model; + QDeclarativeEngine eng; + QDeclarativeComponent component(&eng, QUrl::fromLocalFile(TESTDATA("workerremovelist.qml"))); + QQuickItem *item = createWorkerTest(&eng, &component, &model); + QVERIFY(item != 0); + + QSignalSpy spyModelRemoved(&model, SIGNAL(itemsRemoved(int,int))); + + QVERIFY(model.count() == 0); + QVERIFY(spyModelRemoved.count() == 0); + + QVERIFY(QMetaObject::invokeMethod(item, "addList")); + + QVERIFY(model.count() == 1); + + QVERIFY(QMetaObject::invokeMethod(item, "removeListViaWorker")); + waitForWorker(item); + + QVERIFY(model.count() == 1); + QVERIFY(spyModelRemoved.count() == 0); + + QVERIFY(QMetaObject::invokeMethod(item, "doSync")); + waitForWorker(item); + + QVERIFY(model.count() == 0); + QVERIFY(spyModelRemoved.count() == 1); + + delete item; + qApp->processEvents(); +} + QTEST_MAIN(tst_qdeclarativelistmodel) #include "tst_qdeclarativelistmodel.moc" diff --git a/tests/auto/declarative/qdeclarativemetatype/tst_qdeclarativemetatype.cpp b/tests/auto/declarative/qdeclarativemetatype/tst_qdeclarativemetatype.cpp index a85e73ed57..ce8b3357fa 100644 --- a/tests/auto/declarative/qdeclarativemetatype/tst_qdeclarativemetatype.cpp +++ b/tests/auto/declarative/qdeclarativemetatype/tst_qdeclarativemetatype.cpp @@ -202,17 +202,6 @@ void tst_qdeclarativemetatype::copy() QT_COPY_TEST(QPalette, QPalette(Qt::green)); { - QPixmap icon(100, 100); - - QIcon v = QIcon(icon); QIcon v2 = QIcon(icon); - QEXPECT_FAIL("", "QTBUG-21629 - copy() test function failure.", Abort); - QVERIFY(QDeclarativeMetaType::copy(QMetaType::QIcon, &v, 0)); - QVERIFY(v.isNull() == QIcon().isNull()); - QVERIFY(QDeclarativeMetaType::copy(QMetaType::QIcon , &v, &v2)); - QVERIFY(v.isNull() == QIcon(icon).isNull()); - } - - { QImage v = QImage(100, 100, QImage::Format_RGB32); QImage v2 = QImage(100, 100, QImage::Format_RGB32); QVERIFY(QDeclarativeMetaType::copy(QMetaType::QImage, &v, 0)); @@ -240,7 +229,6 @@ void tst_qdeclarativemetatype::copy() QVERIFY(v.shape() == QCursor(Qt::SizeFDiagCursor).shape()); } - QT_COPY_TEST(QSizePolicy, QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Maximum)); QT_COPY_TEST(QKeySequence, QKeySequence("Ctrl+O")); QT_COPY_TEST(QPen, QPen(Qt::red)); QT_COPY_TEST(QTextLength, QTextLength(QTextLength::FixedLength, 10.2)); diff --git a/tests/auto/declarative/qdeclarativeqt/data/consoleLog.qml b/tests/auto/declarative/qdeclarativeqt/data/consoleLog.qml index 4c581cf245..afb758a21f 100644 --- a/tests/auto/declarative/qdeclarativeqt/data/consoleLog.qml +++ b/tests/auto/declarative/qdeclarativeqt/data/consoleLog.qml @@ -1,8 +1,30 @@ import QtQuick 2.0 QtObject { + id: root Component.onCompleted: { + var a = [1, 2] + var b = {a: "hello", d: 1 } + var c + var d = 12 + var e = function() { return 5;} + var f = true + var g = {toString: function() { throw new Error('toString'); }} + + console.log("completed", "ok") console.log("completed ok") + console.debug("completed ok") + console.warn("completed ok") + console.error("completed ok") + console.log(a) + console.log(b) + console.log(c) + console.log(d) + console.log(e) + console.log(f) + console.log(root) + console.log(g) + console.log(exception) //This has to be at the end } } diff --git a/tests/auto/declarative/qdeclarativeqt/data/resolvedUrl.qml b/tests/auto/declarative/qdeclarativeqt/data/resolvedUrl.qml new file mode 100644 index 0000000000..06ef48b82b --- /dev/null +++ b/tests/auto/declarative/qdeclarativeqt/data/resolvedUrl.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +QtObject { + property string result + property bool isString: false + + Component.onCompleted: { + var a = Qt.resolvedUrl("resolvedUrl.qml"); + result = a; + isString = (typeof a) == "string" + } +} + diff --git a/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp b/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp index b4ac2dfc66..c550ac2f5b 100644 --- a/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp +++ b/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp @@ -89,6 +89,7 @@ private slots: void atob(); void fontFamilies(); void quit(); + void resolvedUrl(); private: QDeclarativeEngine engine; @@ -436,8 +437,8 @@ void tst_qdeclarativeqt::createQmlObject() QString warning3 = component.url().toString()+ ":11: Error: Qt.createQmlObject(): failed to create object: \n " + TEST_FILE("main.qml").toString() + ":4:1: Duplicate property name"; QString warning4 = component.url().toString()+ ":9: Error: Qt.createQmlObject(): Missing parent object"; QString warning5 = component.url().toString()+ ":8: Error: Qt.createQmlObject(): Invalid arguments"; - QString warning6 = "RunTimeError: Qt.createQmlObject(): failed to create object: \n " + TEST_FILE("inline").toString() + ":3: Cannot assign object type QObject with no default method"; - + QString messageFormat = QString(QLatin1String("%1 (%2:%3)")); + QString warning6 = messageFormat.arg("RunTimeError: Qt.createQmlObject(): failed to create object: \n " + TEST_FILE("inline").toString() + ":3: Cannot assign object type QObject with no default method").arg(TEST_FILE("createQmlObject.qml").toString()).arg(23); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning3)); @@ -460,9 +461,34 @@ void tst_qdeclarativeqt::createQmlObject() void tst_qdeclarativeqt::consoleLog() { - QTest::ignoreMessage(QtDebugMsg, "completed ok"); - QTest::ignoreMessage(QtDebugMsg, "completed ok"); - QDeclarativeComponent component(&engine, TEST_FILE("consoleLog.qml")); + int startLineNumber = 15; + QUrl testFileUrl = TEST_FILE("consoleLog.qml"); + QString testString = QString(QLatin1String("completed ok (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testString.arg(startLineNumber++))); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testString.arg(startLineNumber++))); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testString.arg(startLineNumber++))); + QTest::ignoreMessage(QtWarningMsg, qPrintable(testString.arg(startLineNumber++))); + QTest::ignoreMessage(QtCriticalMsg, qPrintable(testString.arg(startLineNumber++))); + + QString testArray = QString(QLatin1String("[1,2] (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testArray.arg(startLineNumber++))); + QString testObject = QString(QLatin1String("Object (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testObject.arg(startLineNumber++))); + QString testUndefined = QString(QLatin1String("undefined (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testUndefined.arg(startLineNumber++))); + QString testNumber = QString(QLatin1String("12 (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testNumber.arg(startLineNumber++))); + QString testFunction = QString(QLatin1String("function () { return 5;} (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testFunction.arg(startLineNumber++))); + QString testBoolean = QString(QLatin1String("true (%1:%2)")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testBoolean.arg(startLineNumber++))); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testObject.arg(startLineNumber++))); + QTest::ignoreMessage(QtDebugMsg, qPrintable(testObject.arg(startLineNumber++))); + + QString testException = QString(QLatin1String("%1:%2: ReferenceError: Can't find variable: exception")).arg(testFileUrl.toString()); + QTest::ignoreMessage(QtWarningMsg, qPrintable(testException.arg(startLineNumber++))); + + QDeclarativeComponent component(&engine, testFileUrl); QObject *object = component.create(); QVERIFY(object != 0); delete object; @@ -727,6 +753,19 @@ void tst_qdeclarativeqt::quit() delete object; } +void tst_qdeclarativeqt::resolvedUrl() +{ + QDeclarativeComponent component(&engine, TEST_FILE("resolvedUrl.qml")); + + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("result").toString(), component.url().toString()); + QCOMPARE(object->property("isString").toBool(), true); + + delete object; +} + QTEST_MAIN(tst_qdeclarativeqt) #include "tst_qdeclarativeqt.moc" diff --git a/tests/auto/declarative/qdeclarativestates/data/signalOverrideCrash3.qml b/tests/auto/declarative/qdeclarativestates/data/signalOverrideCrash3.qml new file mode 100644 index 0000000000..98d4c57219 --- /dev/null +++ b/tests/auto/declarative/qdeclarativestates/data/signalOverrideCrash3.qml @@ -0,0 +1,27 @@ +import QtQuick 2.0 + +Rectangle { + id: myRect + width: 400 + height: 400 + + onHeightChanged: console.log("base state") + + states: [ + State { + name: "state1" + PropertyChanges { + target: myRect + onHeightChanged: console.log("state1") + color: "green" + } + }, + State { + name: "state2"; + PropertyChanges { + target: myRect + onHeightChanged: console.log("state2") + color: "red" + } + }] +} diff --git a/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp b/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp index f6ab6526aa..5c9760aba3 100644 --- a/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp +++ b/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp @@ -111,6 +111,7 @@ private slots: void signalOverride(); void signalOverrideCrash(); void signalOverrideCrash2(); + void signalOverrideCrash3(); void parentChange(); void parentChangeErrors(); void anchorChanges(); @@ -519,6 +520,22 @@ void tst_qdeclarativestates::signalOverrideCrash2() delete rect; } +void tst_qdeclarativestates::signalOverrideCrash3() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, TESTDATA("signalOverrideCrash3.qml")); + QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); + QVERIFY(rect != 0); + + QQuickItemPrivate::get(rect)->setState("state1"); + QQuickItemPrivate::get(rect)->setState(""); + QQuickItemPrivate::get(rect)->setState("state2"); + QQuickItemPrivate::get(rect)->setState(""); + + delete rect; +} + void tst_qdeclarativestates::parentChange() { QDeclarativeEngine engine; @@ -1211,8 +1228,9 @@ void tst_qdeclarativestates::tempState() QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); QVERIFY(rect != 0); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); - QTest::ignoreMessage(QtDebugMsg, "entering placed"); - QTest::ignoreMessage(QtDebugMsg, "entering idle"); + QString messageFormat = QString(QLatin1String("%1 (file://%2:%3)")); + QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("entering placed")).arg(TESTDATA("legalTempState.qml")).arg(11).toLatin1()); + QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("entering idle")).arg(TESTDATA("legalTempState.qml")).arg(15).toLatin1()); rectPrivate->setState("placed"); QCOMPARE(rectPrivate->state(), QLatin1String("idle")); } diff --git a/tests/auto/declarative/qdeclarativevaluetypes/tst_qdeclarativevaluetypes.cpp b/tests/auto/declarative/qdeclarativevaluetypes/tst_qdeclarativevaluetypes.cpp index db0e05bcf2..b9a249fa92 100644 --- a/tests/auto/declarative/qdeclarativevaluetypes/tst_qdeclarativevaluetypes.cpp +++ b/tests/auto/declarative/qdeclarativevaluetypes/tst_qdeclarativevaluetypes.cpp @@ -1059,8 +1059,9 @@ void tst_qdeclarativevaluetypes::bindingConflict() // doesn't crash void tst_qdeclarativevaluetypes::deletedObject() { + QString messageFormat = QString(QLatin1String("%1 (%2:%3)")); QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml")); - QTest::ignoreMessage(QtDebugMsg, "Test: 2"); + QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("Test: 2")).arg(TEST_FILE("deletedObject.js").toString()).arg(6).toLatin1()); MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); QVERIFY(object != 0); @@ -1068,7 +1069,7 @@ void tst_qdeclarativevaluetypes::deletedObject() QVERIFY(dObject != 0); delete dObject; - QTest::ignoreMessage(QtDebugMsg, "Test: undefined"); + QTest::ignoreMessage(QtDebugMsg, messageFormat.arg(QLatin1String("Test: undefined")).arg(TEST_FILE("deletedObject.js").toString()).arg(11).toLatin1()); object->emitRunScript(); delete object; diff --git a/tests/auto/declarative/qdeclarativeworkerscript/data/externalObjectWorker.qml b/tests/auto/declarative/qdeclarativeworkerscript/data/externalObjectWorker.qml new file mode 100644 index 0000000000..1dae608b50 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeworkerscript/data/externalObjectWorker.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + id: root + + function testExternalObject() { + worker.sendMessage(Qt.vector3d(1,2,3)); + } + + WorkerScript { + id: worker + source: "script.js" + } +} diff --git a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp index bb7921c8e3..eb3413ec10 100644 --- a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp +++ b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp @@ -69,6 +69,7 @@ private slots: void messaging_data(); void messaging_sendQObjectList(); void messaging_sendJsObject(); + void messaging_sendExternalObject(); void script_with_pragma(); void script_included(); void scriptError_onLoad(); @@ -200,6 +201,16 @@ void tst_QDeclarativeWorkerScript::messaging_sendJsObject() delete worker; } +void tst_QDeclarativeWorkerScript::messaging_sendExternalObject() +{ + QDeclarativeComponent component(&m_engine, TESTDATA("externalObjectWorker.qml")); + QObject *obj = component.create(); + QVERIFY(obj); + QMetaObject::invokeMethod(obj, "testExternalObject"); + QTest::qWait(100); // shouldn't crash. + delete obj; +} + void tst_QDeclarativeWorkerScript::script_with_pragma() { QVariant value(100); diff --git a/tests/auto/declarative/qjsengine/tst_qjsengine.cpp b/tests/auto/declarative/qjsengine/tst_qjsengine.cpp index f83a1b3efd..8517850c5b 100644 --- a/tests/auto/declarative/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/declarative/qjsengine/tst_qjsengine.cpp @@ -929,13 +929,11 @@ void tst_QJSEngine::jsParseDate() } // Date.parse() should be able to parse the output of Date().toString() -#ifndef Q_WS_WIN // TODO: Test and remove this since 169701 has been fixed { QJSValue ret = eng.evaluate("var x = new Date(); var s = x.toString(); s == new Date(Date.parse(s)).toString()"); QVERIFY(ret.isBoolean()); QCOMPARE(ret.toBoolean(), true); } -#endif } void tst_QJSEngine::newQObject() @@ -1073,7 +1071,7 @@ void tst_QJSEngine::newQObject_promoteObject() void tst_QJSEngine::newQObject_sameQObject() { #if 0 // ###FIXME: No QObjectWrapOptions API - QSKIP("This test stongly relay on strictlyEquals feature that would change in near future"); + QSKIP("This test strongly relies on strictlyEquals feature that would change in near future"); QScriptEngine eng; // calling newQObject() several times with same object for (int x = 0; x < 2; ++x) { @@ -2170,7 +2168,6 @@ void tst_QJSEngine::evaluate() ret = eng.evaluate(code, /*fileName =*/QString(), lineNumber); else ret = eng.evaluate(code); - QEXPECT_FAIL("/a/gimp", "v8 ignore invalid flags", Abort); QCOMPARE(eng.hasUncaughtException(), expectHadError); #if 0 // ###FIXME: No support for the line number of an uncaught exception QEXPECT_FAIL("f()", "SyntaxError do not report line number", Continue); diff --git a/tests/auto/declarative/qmlplugindump/tst_qmlplugindump.cpp b/tests/auto/declarative/qmlplugindump/tst_qmlplugindump.cpp index 234d4bc04c..57e3abb72c 100644 --- a/tests/auto/declarative/qmlplugindump/tst_qmlplugindump.cpp +++ b/tests/auto/declarative/qmlplugindump/tst_qmlplugindump.cpp @@ -66,10 +66,16 @@ tst_qmlplugindump::tst_qmlplugindump() void tst_qmlplugindump::initTestCase() { - qmlplugindumpPath = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/qmlplugindump"); -#ifdef Q_OS_WIN - qmlplugindumpPath += QLatin1String(".exe"); + qmlplugindumpPath = QLibraryInfo::location(QLibraryInfo::BinariesPath); + +#if defined(Q_OS_MAC) + qmlplugindumpPath += QLatin1String("/qmlplugindump.app/Contents/MacOS/qmlplugindump"); +#elif defined(Q_OS_WIN) + qmlplugindumpPath += QLatin1String("/qmlplugindump.exe"); +#else + qmlplugindumpPath += QLatin1String("/qmlplugindump"); #endif + if (!QFileInfo(qmlplugindumpPath).exists()) { QString message = QString::fromLatin1("qmlplugindump executable not found (looked for %0)") .arg(qmlplugindumpPath); diff --git a/tests/auto/declarative/qquickanchors/data/anchors.qml b/tests/auto/declarative/qquickanchors/data/anchors.qml new file mode 100644 index 0000000000..4be49a3468 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/anchors.qml @@ -0,0 +1,162 @@ +import QtQuick 2.0 + +Rectangle { + color: "white" + width: 240 + height: 320 + Rectangle { id: masterRect; objectName: "masterRect"; x: 26; width: 96; height: 20; color: "red" } + Rectangle { + id: rect1; objectName: "rect1" + y: 20; width: 10; height: 10 + anchors.left: masterRect.left + } + Rectangle { + id: rect2; objectName: "rect2" + y: 20; width: 10; height: 10 + anchors.left: masterRect.right + } + Rectangle { + id: rect3; objectName: "rect3" + y: 20; width: 10; height: 10 + anchors.left: masterRect.horizontalCenter + } + Rectangle { + id: rect4; objectName: "rect4" + y: 30; width: 10; height: 10 + anchors.right: masterRect.left + } + Rectangle { + id: rect5; objectName: "rect5" + y: 30; width: 10; height: 10 + anchors.right: masterRect.right + } + Rectangle { + id: rect6; objectName: "rect6" + y: 30; width: 10; height: 10 + anchors.right: masterRect.horizontalCenter + } + Rectangle { + id: rect7; objectName: "rect7" + y: 50; width: 10; height: 10 + anchors.left: parent.left + } + Rectangle { + id: rect8; objectName: "rect8" + y: 50; width: 10; height: 10 + anchors.left: parent.right + } + Rectangle { + id: rect9; objectName: "rect9" + y: 50; width: 10; height: 10 + anchors.left: parent.horizontalCenter + } + Rectangle { + id: rect10; objectName: "rect10" + y: 60; width: 10; height: 10 + anchors.right: parent.left + } + Rectangle { + id: rect11; objectName: "rect11" + y: 60; width: 10; height: 10 + anchors.right: parent.right + } + Rectangle { + id: rect12; objectName: "rect12" + y: 60; width: 10; height: 10 + anchors.right: parent.horizontalCenter + } + Rectangle { + id: rect13; objectName: "rect13" + x: 200; width: 10; height: 10 + anchors.top: masterRect.bottom + } + Rectangle { + id: rect14; objectName: "rect14" + width: 10; height: 10; color: "steelblue" + anchors.verticalCenter: parent.verticalCenter + } + Rectangle { + id: rect15; objectName: "rect15" + y: 200; height: 10 + anchors.left: masterRect.left + anchors.right: masterRect.right + } + Rectangle { + id: rect16; objectName: "rect16" + y: 220; height: 10 + anchors.left: masterRect.left + anchors.horizontalCenter: masterRect.right + } + Rectangle { + id: rect17; objectName: "rect17" + y: 240; height: 10 + anchors.right: masterRect.right + anchors.horizontalCenter: masterRect.left + } + Rectangle { + id: rect18; objectName: "rect18" + x: 180; width: 10 + anchors.top: masterRect.bottom + anchors.bottom: rect12.top + } + Rectangle { + id: rect19; objectName: "rect19" + y: 70; width: 10; height: 10 + anchors.horizontalCenter: parent.horizontalCenter + } + Rectangle { + id: rect20; objectName: "rect20" + y: 70; width: 10; height: 10 + anchors.horizontalCenter: parent.right + } + Rectangle { + id: rect21; objectName: "rect21" + y: 70; width: 10; height: 10 + anchors.horizontalCenter: parent.left + } + Rectangle { + id: rect22; objectName: "rect22" + width: 10; height: 10 + anchors.centerIn: masterRect + } + Rectangle { + id: rect23; objectName: "rect23" + anchors.left: masterRect.left + anchors.leftMargin: 5 + anchors.right: masterRect.right + anchors.rightMargin: 5 + anchors.top: masterRect.top + anchors.topMargin: 5 + anchors.bottom: masterRect.bottom + anchors.bottomMargin: 5 + } + Rectangle { + id: rect24; objectName: "rect24" + width: 10; height: 10 + anchors.horizontalCenter: masterRect.left + anchors.horizontalCenterOffset: width/2 + } + Rectangle { + id: rect25; objectName: "rect25" + width: 10; height: 10 + anchors.verticalCenter: rect12.top + anchors.verticalCenterOffset: height/2 + } + Rectangle { + id: rect26; objectName: "rect26" + width: 10; height: 10 + anchors.baseline: masterRect.top + anchors.baselineOffset: height/2 + } + Text { + id: text1; objectName: "text1" + y: 200; + text: "Hello" + } + Text { + id: text2; objectName: "text2" + anchors.baseline: text1.baseline + anchors.left: text1.right + text: "World" + } +} diff --git a/tests/auto/declarative/qquickanchors/data/centerin.qml b/tests/auto/declarative/qquickanchors/data/centerin.qml new file mode 100644 index 0000000000..e5f64f1e47 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/centerin.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 + +Rectangle { + width: 200; height: 200 + Rectangle { + objectName: "centered" + width: 50; height: 50; color: "blue" + anchors.centerIn: parent; + anchors.verticalCenterOffset: 30 + anchors.horizontalCenterOffset: 10 + } +} diff --git a/tests/auto/declarative/qquickanchors/data/centerinRotation.qml b/tests/auto/declarative/qquickanchors/data/centerinRotation.qml new file mode 100644 index 0000000000..933a25c100 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/centerinRotation.qml @@ -0,0 +1,17 @@ +import QtQuick 2.0 + +Rectangle { + width: 200; height: 200 + Rectangle { + objectName: "outer" + rotation: 90 + width: 101; height: 101; color: "blue" + anchors.centerIn: parent; + + Rectangle { + objectName: "inner" + width: 50; height: 50; color: "blue" + anchors.centerIn: parent; + } + } +} diff --git a/tests/auto/declarative/qquickanchors/data/crash1.qml b/tests/auto/declarative/qquickanchors/data/crash1.qml new file mode 100644 index 0000000000..98dd6cfa41 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/crash1.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Column { + Text { + text: "foo" + anchors.fill: parent + } + Text { + text: "bar" + } +} diff --git a/tests/auto/declarative/qquickanchors/data/fill.qml b/tests/auto/declarative/qquickanchors/data/fill.qml new file mode 100644 index 0000000000..08db199d7b --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/fill.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Rectangle { + width: 200; height: 200 + Rectangle { + objectName: "filler" + width: 50; height: 50; color: "blue" + anchors.fill: parent; + anchors.leftMargin: 10; + anchors.rightMargin: 20; + anchors.topMargin: 30; + anchors.bottomMargin: 40; + } +} diff --git a/tests/auto/declarative/qquickanchors/data/hvCenter.qml b/tests/auto/declarative/qquickanchors/data/hvCenter.qml new file mode 100644 index 0000000000..6763f8eb75 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/hvCenter.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Rectangle { + width: 77; height: 95 + Rectangle { + objectName: "centered" + width: 57; height: 57; color: "blue" + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } +} diff --git a/tests/auto/declarative/qquickanchors/data/loop1.qml b/tests/auto/declarative/qquickanchors/data/loop1.qml new file mode 100644 index 0000000000..342b2af052 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/loop1.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +Rectangle { + id: rect + width: 120; height: 200; color: "white" + Text { id: text1; anchors.right: text2.right; text: "Hello" } + Text { id: text2; anchors.right: text1.right; anchors.rightMargin: 10; text: "World" } +} diff --git a/tests/auto/declarative/qquickanchors/data/loop2.qml b/tests/auto/declarative/qquickanchors/data/loop2.qml new file mode 100644 index 0000000000..e1875be025 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/loop2.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +Rectangle { + id: container; + width: 600; + height: 600; + + Image { + id: image1 + source: "http://labs.trolltech.com/blogs/wp-content/uploads/2009/03/3311388091_ac2a257feb.jpg" + anchors.right: image2.left + } + + Image { + id: image2 + source: "http://labs.trolltech.com/blogs/wp-content/uploads/2009/03/oslo_groupphoto.jpg" + anchors.left: image1.right + anchors.leftMargin: 20 + } +} diff --git a/tests/auto/declarative/qquickanchors/data/margins.qml b/tests/auto/declarative/qquickanchors/data/margins.qml new file mode 100644 index 0000000000..9403f65a61 --- /dev/null +++ b/tests/auto/declarative/qquickanchors/data/margins.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +Rectangle { + width: 200; height: 200 + Rectangle { + objectName: "filler" + width: 50; height: 50; color: "blue" + anchors.fill: parent; + anchors.margins: 10 + anchors.leftMargin: 5 + anchors.topMargin: 6 + } +} diff --git a/tests/auto/declarative/qquickanchors/qquickanchors.pro b/tests/auto/declarative/qquickanchors/qquickanchors.pro new file mode 100644 index 0000000000..0d085d367d --- /dev/null +++ b/tests/auto/declarative/qquickanchors/qquickanchors.pro @@ -0,0 +1,12 @@ +TARGET = tst_qquickanchors +CONFIG += testcase +SOURCES += tst_qquickanchors.cpp +macx:CONFIG -= app_bundle + +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + +CONFIG += parallel_test + +QT += core-private gui-private declarative-private v8-private testlib diff --git a/tests/auto/declarative/qquickanchors/tst_qquickanchors.cpp b/tests/auto/declarative/qquickanchors/tst_qquickanchors.cpp new file mode 100644 index 0000000000..cfdab7f14c --- /dev/null +++ b/tests/auto/declarative/qquickanchors/tst_qquickanchors.cpp @@ -0,0 +1,693 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <qtest.h> +#include <QSignalSpy> +#include <private/qquickitem_p.h> +#include <QtDeclarative/qdeclarativeengine.h> +#include <QtDeclarative/qdeclarativecomponent.h> +#include <QtDeclarative/qquickview.h> +#include <QtDeclarative/private/qquickrectangle_p.h> +#include <QtDeclarative/private/qquicktext_p.h> +#include <QtDeclarative/private/qquickanchors_p_p.h> +#include <QtDeclarative/private/qquickitem_p.h> +#include "../shared/util.h" + +Q_DECLARE_METATYPE(QQuickAnchors::Anchor) +Q_DECLARE_METATYPE(QQuickAnchorLine::AnchorLine) + +class tst_qquickanchors : public QObject +{ + Q_OBJECT +public: + tst_qquickanchors() {} + +private slots: + void basicAnchors(); + void basicAnchorsRTL(); + void loops(); + void illegalSets(); + void illegalSets_data(); + void reset(); + void reset_data(); + void resetConvenience(); + void nullItem(); + void nullItem_data(); + void crash1(); + void centerIn(); + void centerInRTL(); + void centerInRotation(); + void hvCenter(); + void hvCenterRTL(); + void fill(); + void fillRTL(); + void margins(); + void marginsRTL(); +}; + +/* + Find an item with the specified objectName. +*/ +template<typename T> +T *findItem(QQuickItem *parent, const QString &objectName) +{ + if (!parent) + return 0; + + const QMetaObject &mo = T::staticMetaObject; + //qDebug() << parent->QQuickItem::children().count() << "children"; + for (int i = 0; i < parent->childItems().count(); ++i) { + QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i)); + if (!item) + continue; + //qDebug() << "try" << item; + if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) + return static_cast<T*>(item); + item = findItem<T>(item, objectName); + if (item) + return static_cast<T*>(item); + } + + return 0; +} + +void tst_qquickanchors::basicAnchors() +{ + QQuickView *view = new QQuickView; + view->setSource(QUrl::fromLocalFile(TESTDATA("anchors.qml"))); + + qApp->processEvents(); + + //sibling horizontal + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect1"))->x(), 26.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect2"))->x(), 122.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect3"))->x(), 74.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect4"))->x(), 16.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect5"))->x(), 112.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect6"))->x(), 64.0); + + //parent horizontal + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect7"))->x(), 0.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect8"))->x(), 240.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect9"))->x(), 120.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect10"))->x(), -10.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect11"))->x(), 230.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect12"))->x(), 110.0); + + //vertical + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect13"))->y(), 20.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect14"))->y(), 155.0); + + //stretch + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect15"))->x(), 26.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect15"))->width(), 96.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect16"))->x(), 26.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect16"))->width(), 192.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect17"))->x(), -70.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect17"))->width(), 192.0); + + //vertical stretch + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect18"))->y(), 20.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect18"))->height(), 40.0); + + //more parent horizontal + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect19"))->x(), 115.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect20"))->x(), 235.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect21"))->x(), -5.0); + + //centerIn + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect22"))->x(), 69.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect22"))->y(), 5.0); + + //margins + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect23"))->x(), 31.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect23"))->y(), 5.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect23"))->width(), 86.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect23"))->height(), 10.0); + + // offsets + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect24"))->x(), 26.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect25"))->y(), 60.0); + QCOMPARE(findItem<QQuickRectangle>(view->rootObject(), QLatin1String("rect26"))->y(), 5.0); + + //baseline + QQuickText *text1 = findItem<QQuickText>(view->rootObject(), QLatin1String("text1")); + QQuickText *text2 = findItem<QQuickText>(view->rootObject(), QLatin1String("text2")); + QCOMPARE(text1->y(), text2->y()); + + delete view; +} + +QQuickItem* childItem(QQuickItem *parentItem, const char * itemString) { + return findItem<QQuickItem>(parentItem, QLatin1String(itemString)); +} + +qreal offsetMasterRTL(QQuickItem *rootItem, const char * itemString) { + QQuickItem* masterItem = findItem<QQuickItem>(rootItem, QLatin1String("masterRect")); + return masterItem->width()+2*masterItem->x()-findItem<QQuickItem>(rootItem, QLatin1String(itemString))->width(); +} + +qreal offsetParentRTL(QQuickItem *rootItem, const char * itemString) { + return rootItem->width()+2*rootItem->x()-findItem<QQuickItem>(rootItem, QLatin1String(itemString))->width(); +} + +void mirrorAnchors(QQuickItem *item) { + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + itemPrivate->setLayoutMirror(true); +} + +void tst_qquickanchors::basicAnchorsRTL() +{ + QQuickView *view = new QQuickView; + view->setSource(QUrl::fromLocalFile(TESTDATA("anchors.qml"))); + + qApp->processEvents(); + + QQuickItem* rootItem = qobject_cast<QQuickItem*>(view->rootObject()); + foreach (QObject *child, rootItem->children()) { + bool mirrored = QQuickItemPrivate::get(qobject_cast<QQuickItem*>(child))->anchors()->property("mirrored").toBool(); + QCOMPARE(mirrored, false); + } + + foreach (QObject *child, rootItem->children()) + mirrorAnchors(qobject_cast<QQuickItem*>(child)); + + foreach (QObject *child, rootItem->children()) { + bool mirrored = QQuickItemPrivate::get(qobject_cast<QQuickItem*>(child))->anchors()->property("mirrored").toBool(); + QCOMPARE(mirrored, true); + } + + //sibling horizontal + QCOMPARE(childItem(rootItem, "rect1")->x(), offsetMasterRTL(rootItem, "rect1")-26.0); + QCOMPARE(childItem(rootItem, "rect2")->x(), offsetMasterRTL(rootItem, "rect2")-122.0); + QCOMPARE(childItem(rootItem, "rect3")->x(), offsetMasterRTL(rootItem, "rect3")-74.0); + QCOMPARE(childItem(rootItem, "rect4")->x(), offsetMasterRTL(rootItem, "rect4")-16.0); + QCOMPARE(childItem(rootItem, "rect5")->x(), offsetMasterRTL(rootItem, "rect5")-112.0); + QCOMPARE(childItem(rootItem, "rect6")->x(), offsetMasterRTL(rootItem, "rect6")-64.0); + + //parent horizontal + QCOMPARE(childItem(rootItem, "rect7")->x(), offsetParentRTL(rootItem, "rect7")-0.0); + QCOMPARE(childItem(rootItem, "rect8")->x(), offsetParentRTL(rootItem, "rect8")-240.0); + QCOMPARE(childItem(rootItem, "rect9")->x(), offsetParentRTL(rootItem, "rect9")-120.0); + QCOMPARE(childItem(rootItem, "rect10")->x(), offsetParentRTL(rootItem, "rect10")+10.0); + QCOMPARE(childItem(rootItem, "rect11")->x(), offsetParentRTL(rootItem, "rect11")-230.0); + QCOMPARE(childItem(rootItem, "rect12")->x(), offsetParentRTL(rootItem, "rect12")-110.0); + + //vertical + QCOMPARE(childItem(rootItem, "rect13")->y(), 20.0); + QCOMPARE(childItem(rootItem, "rect14")->y(), 155.0); + + //stretch + QCOMPARE(childItem(rootItem, "rect15")->x(), offsetMasterRTL(rootItem, "rect15")-26.0); + QCOMPARE(childItem(rootItem, "rect15")->width(), 96.0); + QCOMPARE(childItem(rootItem, "rect16")->x(), offsetMasterRTL(rootItem, "rect16")-26.0); + QCOMPARE(childItem(rootItem, "rect16")->width(), 192.0); + QCOMPARE(childItem(rootItem, "rect17")->x(), offsetMasterRTL(rootItem, "rect17")+70.0); + QCOMPARE(childItem(rootItem, "rect17")->width(), 192.0); + + //vertical stretch + QCOMPARE(childItem(rootItem, "rect18")->y(), 20.0); + QCOMPARE(childItem(rootItem, "rect18")->height(), 40.0); + + //more parent horizontal + QCOMPARE(childItem(rootItem, "rect19")->x(), offsetParentRTL(rootItem, "rect19")-115.0); + QCOMPARE(childItem(rootItem, "rect20")->x(), offsetParentRTL(rootItem, "rect20")-235.0); + QCOMPARE(childItem(rootItem, "rect21")->x(), offsetParentRTL(rootItem, "rect21")+5.0); + + //centerIn + QCOMPARE(childItem(rootItem, "rect22")->x(), offsetMasterRTL(rootItem, "rect22")-69.0); + QCOMPARE(childItem(rootItem, "rect22")->y(), 5.0); + + //margins + QCOMPARE(childItem(rootItem, "rect23")->x(), offsetMasterRTL(rootItem, "rect23")-31.0); + QCOMPARE(childItem(rootItem, "rect23")->y(), 5.0); + QCOMPARE(childItem(rootItem, "rect23")->width(), 86.0); + QCOMPARE(childItem(rootItem, "rect23")->height(), 10.0); + + // offsets + QCOMPARE(childItem(rootItem, "rect24")->x(), offsetMasterRTL(rootItem, "rect24")-26.0); + QCOMPARE(childItem(rootItem, "rect25")->y(), 60.0); + QCOMPARE(childItem(rootItem, "rect26")->y(), 5.0); + + //baseline + QQuickText *text1 = findItem<QQuickText>(rootItem, QLatin1String("text1")); + QQuickText *text2 = findItem<QQuickText>(rootItem, QLatin1String("text2")); + QCOMPARE(text1->y(), text2->y()); + + delete view; +} + +// mostly testing that we don't crash +void tst_qquickanchors::loops() +{ + { + QUrl source(QUrl::fromLocalFile(TESTDATA("loop1.qml"))); + + QString expect = source.toString() + ":6:5: QML Text: Possible anchor loop detected on horizontal anchor."; + QTest::ignoreMessage(QtWarningMsg, expect.toLatin1()); + QTest::ignoreMessage(QtWarningMsg, expect.toLatin1()); + QTest::ignoreMessage(QtWarningMsg, expect.toLatin1()); + + QQuickView *view = new QQuickView; + view->setSource(source); + qApp->processEvents(); + + delete view; + } + + { + QUrl source(QUrl::fromLocalFile(TESTDATA("loop2.qml"))); + + QString expect = source.toString() + ":8:3: QML Image: Possible anchor loop detected on horizontal anchor."; + QTest::ignoreMessage(QtWarningMsg, expect.toLatin1()); + + QQuickView *view = new QQuickView; + view->setSource(source); + qApp->processEvents(); + + delete view; + } +} + +void tst_qquickanchors::illegalSets() +{ + QFETCH(QString, qml); + QFETCH(QString, warning); + + QTest::ignoreMessage(QtWarningMsg, warning.toLatin1()); + + QDeclarativeEngine engine; + QDeclarativeComponent component(&engine); + component.setData(QByteArray("import QtQuick 1.0\n" + qml.toUtf8()), QUrl::fromLocalFile("")); + if (!component.isReady()) + qWarning() << "Test errors:" << component.errors(); + QVERIFY(component.isReady()); + QObject *o = component.create(); + delete o; +} + +void tst_qquickanchors::illegalSets_data() +{ + QTest::addColumn<QString>("qml"); + QTest::addColumn<QString>("warning"); + + QTest::newRow("H - too many anchors") + << "Rectangle { id: rect; Rectangle { anchors.left: rect.left; anchors.right: rect.right; anchors.horizontalCenter: rect.horizontalCenter } }" + << "file::2:23: QML Rectangle: Cannot specify left, right, and hcenter anchors."; + + foreach (const QString &side, QStringList() << "left" << "right") { + QTest::newRow("H - anchor to V") + << QString("Rectangle { Rectangle { anchors.%1: parent.top } }").arg(side) + << "file::2:13: QML Rectangle: Cannot anchor a horizontal edge to a vertical edge."; + + QTest::newRow("H - anchor to non parent/sibling") + << QString("Rectangle { Item { Rectangle { id: rect } } Rectangle { anchors.%1: rect.%1 } }").arg(side) + << "file::2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; + + QTest::newRow("H - anchor to self") + << QString("Rectangle { id: rect; anchors.%1: rect.%1 }").arg(side) + << "file::2:1: QML Rectangle: Cannot anchor item to self."; + } + + + QTest::newRow("V - too many anchors") + << "Rectangle { id: rect; Rectangle { anchors.top: rect.top; anchors.bottom: rect.bottom; anchors.verticalCenter: rect.verticalCenter } }" + << "file::2:23: QML Rectangle: Cannot specify top, bottom, and vcenter anchors."; + + QTest::newRow("V - too many anchors with baseline") + << "Rectangle { Text { id: text1; text: \"Hello\" } Text { anchors.baseline: text1.baseline; anchors.top: text1.top; } }" + << "file::2:47: QML Text: Baseline anchor cannot be used in conjunction with top, bottom, or vcenter anchors."; + + foreach (const QString &side, QStringList() << "top" << "bottom" << "baseline") { + + QTest::newRow("V - anchor to H") + << QString("Rectangle { Rectangle { anchors.%1: parent.left } }").arg(side) + << "file::2:13: QML Rectangle: Cannot anchor a vertical edge to a horizontal edge."; + + QTest::newRow("V - anchor to non parent/sibling") + << QString("Rectangle { Item { Rectangle { id: rect } } Rectangle { anchors.%1: rect.%1 } }").arg(side) + << "file::2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; + + QTest::newRow("V - anchor to self") + << QString("Rectangle { id: rect; anchors.%1: rect.%1 }").arg(side) + << "file::2:1: QML Rectangle: Cannot anchor item to self."; + } + + + QTest::newRow("centerIn - anchor to non parent/sibling") + << "Rectangle { Item { Rectangle { id: rect } } Rectangle { anchors.centerIn: rect} }" + << "file::2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; + + + QTest::newRow("fill - anchor to non parent/sibling") + << "Rectangle { Item { Rectangle { id: rect } } Rectangle { anchors.fill: rect} }" + << "file::2:45: QML Rectangle: Cannot anchor to an item that isn't a parent or sibling."; +} + +void tst_qquickanchors::reset() +{ + QFETCH(QString, side); + QFETCH(QQuickAnchorLine::AnchorLine, anchorLine); + QFETCH(QQuickAnchors::Anchor, usedAnchor); + + QQuickItem *baseItem = new QQuickItem; + + QQuickAnchorLine anchor; + anchor.item = baseItem; + anchor.anchorLine = anchorLine; + + QQuickItem *item = new QQuickItem; + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + + const QMetaObject *meta = itemPrivate->anchors()->metaObject(); + QMetaProperty p = meta->property(meta->indexOfProperty(side.toUtf8().constData())); + + QVERIFY(p.write(itemPrivate->anchors(), qVariantFromValue(anchor))); + QCOMPARE(itemPrivate->anchors()->usedAnchors().testFlag(usedAnchor), true); + + QVERIFY(p.reset(itemPrivate->anchors())); + QCOMPARE(itemPrivate->anchors()->usedAnchors().testFlag(usedAnchor), false); + + delete item; + delete baseItem; +} + +void tst_qquickanchors::reset_data() +{ + QTest::addColumn<QString>("side"); + QTest::addColumn<QQuickAnchorLine::AnchorLine>("anchorLine"); + QTest::addColumn<QQuickAnchors::Anchor>("usedAnchor"); + + QTest::newRow("left") << "left" << QQuickAnchorLine::Left << QQuickAnchors::LeftAnchor; + QTest::newRow("top") << "top" << QQuickAnchorLine::Top << QQuickAnchors::TopAnchor; + QTest::newRow("right") << "right" << QQuickAnchorLine::Right << QQuickAnchors::RightAnchor; + QTest::newRow("bottom") << "bottom" << QQuickAnchorLine::Bottom << QQuickAnchors::BottomAnchor; + + QTest::newRow("hcenter") << "horizontalCenter" << QQuickAnchorLine::HCenter << QQuickAnchors::HCenterAnchor; + QTest::newRow("vcenter") << "verticalCenter" << QQuickAnchorLine::VCenter << QQuickAnchors::VCenterAnchor; + QTest::newRow("baseline") << "baseline" << QQuickAnchorLine::Baseline << QQuickAnchors::BaselineAnchor; +} + +void tst_qquickanchors::resetConvenience() +{ + QQuickItem *baseItem = new QQuickItem; + QQuickItem *item = new QQuickItem; + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + + //fill + itemPrivate->anchors()->setFill(baseItem); + QVERIFY(itemPrivate->anchors()->fill() == baseItem); + itemPrivate->anchors()->resetFill(); + QVERIFY(itemPrivate->anchors()->fill() == 0); + + //centerIn + itemPrivate->anchors()->setCenterIn(baseItem); + QVERIFY(itemPrivate->anchors()->centerIn() == baseItem); + itemPrivate->anchors()->resetCenterIn(); + QVERIFY(itemPrivate->anchors()->centerIn() == 0); + + delete item; + delete baseItem; +} + +void tst_qquickanchors::nullItem() +{ + QFETCH(QString, side); + + QQuickAnchorLine anchor; + QQuickItem *item = new QQuickItem; + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + + const QMetaObject *meta = itemPrivate->anchors()->metaObject(); + QMetaProperty p = meta->property(meta->indexOfProperty(side.toUtf8().constData())); + + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML Item: Cannot anchor to a null item."); + QVERIFY(p.write(itemPrivate->anchors(), qVariantFromValue(anchor))); + + delete item; +} + +void tst_qquickanchors::nullItem_data() +{ + QTest::addColumn<QString>("side"); + + QTest::newRow("left") << "left"; + QTest::newRow("top") << "top"; + QTest::newRow("right") << "right"; + QTest::newRow("bottom") << "bottom"; + + QTest::newRow("hcenter") << "horizontalCenter"; + QTest::newRow("vcenter") << "verticalCenter"; + QTest::newRow("baseline") << "baseline"; +} + +//QTBUG-5428 +void tst_qquickanchors::crash1() +{ + QUrl source(QUrl::fromLocalFile(TESTDATA("crash1.qml"))); + + QString expect = source.toString() + ":3:1: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column"; + + QTest::ignoreMessage(QtWarningMsg, expect.toLatin1()); + + QQuickView *view = new QQuickView(source); + qApp->processEvents(); + + delete view; +} + +void tst_qquickanchors::fill() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("fill.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("filler")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + QCOMPARE(rect->x(), 0.0 + 10.0); + QCOMPARE(rect->y(), 0.0 + 30.0); + QCOMPARE(rect->width(), 200.0 - 10.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 30.0 - 40.0); + //Alter Offsets (tests QTBUG-6631) + rectPrivate->anchors()->setLeftMargin(20.0); + rectPrivate->anchors()->setRightMargin(0.0); + rectPrivate->anchors()->setBottomMargin(0.0); + rectPrivate->anchors()->setTopMargin(10.0); + QCOMPARE(rect->x(), 0.0 + 20.0); + QCOMPARE(rect->y(), 0.0 + 10.0); + QCOMPARE(rect->width(), 200.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 10.0); + + delete view; +} + +void tst_qquickanchors::fillRTL() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("fill.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("filler")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + mirrorAnchors(rect); + + QCOMPARE(rect->x(), 0.0 + 20.0); + QCOMPARE(rect->y(), 0.0 + 30.0); + QCOMPARE(rect->width(), 200.0 - 10.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 30.0 - 40.0); + //Alter Offsets (tests QTBUG-6631) + rectPrivate->anchors()->setLeftMargin(20.0); + rectPrivate->anchors()->setRightMargin(0.0); + rectPrivate->anchors()->setBottomMargin(0.0); + rectPrivate->anchors()->setTopMargin(10.0); + QCOMPARE(rect->x(), 0.0 + 0.0); + QCOMPARE(rect->y(), 0.0 + 10.0); + QCOMPARE(rect->width(), 200.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 10.0); + + delete view; +} + +void tst_qquickanchors::centerIn() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("centerin.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("centered")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + + QCOMPARE(rect->x(), 75.0 + 10); + QCOMPARE(rect->y(), 75.0 + 30); + //Alter Offsets (tests QTBUG-6631) + rectPrivate->anchors()->setHorizontalCenterOffset(-20.0); + rectPrivate->anchors()->setVerticalCenterOffset(-10.0); + QCOMPARE(rect->x(), 75.0 - 20.0); + QCOMPARE(rect->y(), 75.0 - 10.0); + + delete view; +} + +void tst_qquickanchors::centerInRTL() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("centerin.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("centered")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + mirrorAnchors(rect); + + QCOMPARE(rect->x(), 75.0 - 10); + QCOMPARE(rect->y(), 75.0 + 30); + //Alter Offsets (tests QTBUG-6631) + rectPrivate->anchors()->setHorizontalCenterOffset(-20.0); + rectPrivate->anchors()->setVerticalCenterOffset(-10.0); + QCOMPARE(rect->x(), 75.0 + 20.0); + QCOMPARE(rect->y(), 75.0 - 10.0); + + delete view; +} + +//QTBUG-12441 +void tst_qquickanchors::centerInRotation() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("centerinRotation.qml"))); + + qApp->processEvents(); + QQuickRectangle* outer = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("outer")); + QQuickRectangle* inner = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("inner")); + + QEXPECT_FAIL("", "QTBUG-12441", Abort); + QCOMPARE(outer->x(), qreal(49.5)); + QCOMPARE(outer->y(), qreal(49.5)); + QCOMPARE(inner->x(), qreal(25.5)); + QCOMPARE(inner->y(), qreal(25.5)); + + delete view; +} + +void tst_qquickanchors::hvCenter() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("hvCenter.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("centered")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + + // test QTBUG-10999 + QCOMPARE(rect->x(), 10.0); + QCOMPARE(rect->y(), 19.0); + + rectPrivate->anchors()->setHorizontalCenterOffset(-5.0); + rectPrivate->anchors()->setVerticalCenterOffset(5.0); + QCOMPARE(rect->x(), 10.0 - 5.0); + QCOMPARE(rect->y(), 19.0 + 5.0); + + delete view; +} + +void tst_qquickanchors::hvCenterRTL() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("hvCenter.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("centered")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + mirrorAnchors(rect); + + // test QTBUG-10999 + QCOMPARE(rect->x(), 10.0); + QCOMPARE(rect->y(), 19.0); + + rectPrivate->anchors()->setHorizontalCenterOffset(-5.0); + rectPrivate->anchors()->setVerticalCenterOffset(5.0); + QCOMPARE(rect->x(), 10.0 + 5.0); + QCOMPARE(rect->y(), 19.0 + 5.0); + + delete view; +} +void tst_qquickanchors::margins() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("margins.qml"))); + + qApp->processEvents(); + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("filler")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + QCOMPARE(rect->x(), 5.0); + QCOMPARE(rect->y(), 6.0); + QCOMPARE(rect->width(), 200.0 - 5.0 - 10.0); + QCOMPARE(rect->height(), 200.0 - 6.0 - 10.0); + + rectPrivate->anchors()->setTopMargin(0.0); + rectPrivate->anchors()->setMargins(20.0); + + QCOMPARE(rect->x(), 5.0); + QCOMPARE(rect->y(), 20.0); + QCOMPARE(rect->width(), 200.0 - 5.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 20.0 - 20.0); + + delete view; +} + +void tst_qquickanchors::marginsRTL() +{ + QQuickView *view = new QQuickView(QUrl::fromLocalFile(TESTDATA("margins.qml"))); + + QQuickRectangle* rect = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("filler")); + QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); + mirrorAnchors(rect); + + QCOMPARE(rect->x(), 10.0); + QCOMPARE(rect->y(), 6.0); + QCOMPARE(rect->width(), 200.0 - 5.0 - 10.0); + QCOMPARE(rect->height(), 200.0 - 6.0 - 10.0); + + rectPrivate->anchors()->setTopMargin(0.0); + rectPrivate->anchors()->setMargins(20.0); + + QCOMPARE(rect->x(), 20.0); + QCOMPARE(rect->y(), 20.0); + QCOMPARE(rect->width(), 200.0 - 5.0 - 20.0); + QCOMPARE(rect->height(), 200.0 - 20.0 - 20.0); + + delete view; +} + + +QTEST_MAIN(tst_qquickanchors) + +#include "tst_qquickanchors.moc" diff --git a/tests/auto/declarative/qquickcanvas/tst_qquickcanvas.cpp b/tests/auto/declarative/qquickcanvas/tst_qquickcanvas.cpp index d2b691d461..640b4b4f40 100644 --- a/tests/auto/declarative/qquickcanvas/tst_qquickcanvas.cpp +++ b/tests/auto/declarative/qquickcanvas/tst_qquickcanvas.cpp @@ -153,8 +153,9 @@ protected: mousePressId = ++mousePressNum; } - bool childMouseEventFilter(QQuickItem *, QEvent *) { - mousePressId = ++mousePressNum; + bool childMouseEventFilter(QQuickItem *, QEvent *event) { + if (event->type() == QEvent::MouseButtonPress) + mousePressId = ++mousePressNum; return false; } diff --git a/tests/auto/declarative/qquickflickable/tst_qquickflickable.cpp b/tests/auto/declarative/qquickflickable/tst_qquickflickable.cpp index 2f155e298e..a02db06616 100644 --- a/tests/auto/declarative/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/declarative/qquickflickable/tst_qquickflickable.cpp @@ -533,7 +533,7 @@ void tst_qquickflickable::disabled() void tst_qquickflickable::flickVelocity() { -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC QSKIP("Producing flicks on Mac CI impossible due to timing problems"); #endif diff --git a/tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp b/tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp index ffb9660262..d0149ed1d6 100644 --- a/tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp +++ b/tests/auto/declarative/qquickfocusscope/tst_qquickfocusscope.cpp @@ -557,6 +557,7 @@ void tst_qquickfocusscope::canvasFocus() QSignalSpy scope2ActiveFocusSpy(scope2, SIGNAL(activeFocusChanged(bool))); QSignalSpy item2ActiveFocusSpy(item2, SIGNAL(activeFocusChanged(bool))); + QEXPECT_FAIL("", "QTBUG-22415", Abort); QCOMPARE(rootItem->hasFocus(), false); QCOMPARE(rootItem->hasActiveFocus(), false); QCOMPARE(scope1->hasFocus(), true); @@ -585,6 +586,7 @@ void tst_qquickfocusscope::canvasFocus() QCOMPARE(scope2->hasActiveFocus(), false); QCOMPARE(item2->hasFocus(), false); QCOMPARE(item2->hasActiveFocus(), false); + QCOMPARE(rootFocusSpy.count(), 1); QCOMPARE(rootActiveFocusSpy.count(), 1); QCOMPARE(scope1FocusSpy.count(), 0); @@ -605,6 +607,7 @@ void tst_qquickfocusscope::canvasFocus() QCOMPARE(scope1->hasActiveFocus(), false); QCOMPARE(item1->hasFocus(), true); QCOMPARE(item1->hasActiveFocus(), false); + QCOMPARE(rootFocusSpy.count(), 2); QCOMPARE(rootActiveFocusSpy.count(), 2); QCOMPARE(scope1FocusSpy.count(), 0); @@ -612,6 +615,7 @@ void tst_qquickfocusscope::canvasFocus() QCOMPARE(item1FocusSpy.count(), 0); QCOMPARE(item1ActiveFocusSpy.count(), 2); + // canvas does not have focus, so item2 will not get active focus item2->forceActiveFocus(); diff --git a/tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp b/tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp index 5f3842a660..a190d878ad 100644 --- a/tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp +++ b/tests/auto/declarative/qquickgridview/tst_qquickgridview.cpp @@ -72,6 +72,8 @@ private slots: void inserted_more(); void inserted_more_data(); void removed(); + void addOrRemoveBeforeVisible(); + void addOrRemoveBeforeVisible_data(); void clear(); void moved(); void moved_data(); @@ -740,6 +742,91 @@ void tst_QQuickGridView::removed() delete canvas; } +void tst_QQuickGridView::addOrRemoveBeforeVisible() +{ + // QTBUG-21588: ensure re-layout is done on grid after adding or removing + // items from before the visible area + + QFETCH(bool, doAdd); + QFETCH(qreal, newTopContentY); + + QQuickView *canvas = createView(); + canvas->show(); + + TestModel model; + for (int i = 0; i < 30; i++) + model.addItem("Item" + QString::number(i), ""); + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); + ctxt->setContextProperty("testTopToBottom", QVariant(false)); + canvas->setSource(QUrl::fromLocalFile(TESTDATA("gridview1.qml"))); + + QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid"); + QTRY_VERIFY(gridview != 0); + QQuickItem *contentItem = gridview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0); + QTRY_COMPARE(name->text(), QString("Item0")); + + gridview->setCurrentIndex(0); + qApp->processEvents(); + + // scroll down until item 0 is no longer drawn + // (bug not triggered if we just move using content y, since that doesn't + // refill and change the visible items) + gridview->setCurrentIndex(24); + qApp->processEvents(); + + QTRY_COMPARE(gridview->currentIndex(), 24); + QTRY_COMPARE(gridview->contentY(), 220.0); + + QTest::qWait(100); // wait for refill to complete + QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 0)); // 0 shouldn't be visible + + if (doAdd) { + model.insertItem(0, "New Item", "New Item number"); + QTRY_COMPARE(gridview->count(), 31); + } else { + model.removeItem(0); + QTRY_COMPARE(gridview->count(), 29); + } + + // scroll back up and item 0 should be gone + gridview->setCurrentIndex(0); + qApp->processEvents(); + QTRY_COMPARE(gridview->currentIndex(), 0); + QTRY_COMPARE(gridview->contentY(), newTopContentY); + + name = findItem<QQuickText>(contentItem, "textName", 0); + if (doAdd) + QCOMPARE(name->text(), QString("New Item")); + else + QCOMPARE(name->text(), QString("Item1")); + + // Confirm items positioned correctly + int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); + for (int i = 0; i < model.count() && i < itemCount; ++i) { + QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", i)); + QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); + QTRY_VERIFY(item->x() == (i%3)*80); + QTRY_VERIFY(item->y() == (i/3)*60 + newTopContentY); + } + + delete canvas; +} + +void tst_QQuickGridView::addOrRemoveBeforeVisible_data() +{ + QTest::addColumn<bool>("doAdd"); + QTest::addColumn<qreal>("newTopContentY"); + + QTest::newRow("add") << true << -60.0; + QTest::newRow("remove") << false << 0.0; +} + void tst_QQuickGridView::clear() { QQuickView *canvas = createView(); @@ -2356,18 +2443,17 @@ void tst_QQuickGridView::enforceRange_rightToLeft() QQuickGridView *gridview = findItem<QQuickGridView>(canvas->rootObject(), "grid"); QTRY_VERIFY(gridview != 0); - QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0); - QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0); - QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange); + QCOMPARE(gridview->preferredHighlightBegin(), 100.0); + QCOMPARE(gridview->preferredHighlightEnd(), 100.0); + QCOMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QVERIFY(contentItem != 0); // view should be positioned at the top of the range. QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0); - QTRY_VERIFY(item); - QEXPECT_FAIL("", "QTBUG-22162", Abort); - QTRY_COMPARE(gridview->contentX(), -100.); + QVERIFY(item); + QTRY_COMPARE(gridview->contentX(), -140.); QTRY_COMPARE(gridview->contentY(), 0.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0); @@ -2378,11 +2464,11 @@ void tst_QQuickGridView::enforceRange_rightToLeft() QTRY_COMPARE(number->text(), model.number(0)); // Check currentIndex is updated when contentItem moves - gridview->setContentX(-200); + gridview->setContentX(-240); QTRY_COMPARE(gridview->currentIndex(), 3); gridview->setCurrentIndex(7); - QTRY_COMPARE(gridview->contentX(), -300.); + QTRY_COMPARE(gridview->contentX(), -340.); QTRY_COMPARE(gridview->contentY(), 0.0); TestModel model2; diff --git a/tests/auto/declarative/qquickitem/tst_qquickitem.cpp b/tests/auto/declarative/qquickitem/tst_qquickitem.cpp index 35346c8236..a5f908ce86 100644 --- a/tests/auto/declarative/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/declarative/qquickitem/tst_qquickitem.cpp @@ -137,11 +137,6 @@ private: w->show(); w->requestActivateWindow(); qApp->processEvents(); - -#ifdef Q_WS_X11 - // to be safe and avoid failing setFocus with window managers - qt_x11_wait_for_window_manager(w); -#endif } }; diff --git a/tests/auto/declarative/qquickitem2/qquickitem2.pro b/tests/auto/declarative/qquickitem2/qquickitem2.pro index 47b31d98e9..2fe1eb1e3a 100644 --- a/tests/auto/declarative/qquickitem2/qquickitem2.pro +++ b/tests/auto/declarative/qquickitem2/qquickitem2.pro @@ -1,5 +1,5 @@ CONFIG += testcase -TARGET = tst_qquickitem +TARGET = tst_qquickitem2 macx:CONFIG -= app_bundle SOURCES += tst_qquickitem.cpp diff --git a/tests/auto/declarative/qquickmultipointtoucharea/data/inFlickable.qml b/tests/auto/declarative/qquickmultipointtoucharea/data/inFlickable.qml new file mode 100644 index 0000000000..53a2bf87f9 --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/data/inFlickable.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +Flickable { + width: 240 + height: 320 + + contentWidth: width + contentHeight: height * 2 + + MultiPointTouchArea { + anchors.fill: parent + minimumTouchPoints: 2 + maximumTouchPoints: 2 + onGestureStarted: { + if ((Math.abs(point2.x - point2.startX) > gesture.dragThreshold/2) && (Math.abs(point1.x - point1.startX) > gesture.dragThreshold/2)) { + gesture.grab() + } + } + touchPoints: [ + TouchPoint { id: point1; objectName: "point1" }, + TouchPoint { id: point2; objectName: "point2" } + ] + } +} + diff --git a/tests/auto/declarative/qquickmultipointtoucharea/data/nested.qml b/tests/auto/declarative/qquickmultipointtoucharea/data/nested.qml new file mode 100644 index 0000000000..37b8820aa0 --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/data/nested.qml @@ -0,0 +1,27 @@ +import QtQuick 2.0 + +MultiPointTouchArea { + width: 240 + height: 320 + + property bool grabInnerArea: true + + minimumTouchPoints: 2 + maximumTouchPoints: 3 + touchPoints: [ + TouchPoint { objectName: "point11" }, + TouchPoint { objectName: "point12" } + ] + + MultiPointTouchArea { + anchors.fill: parent + minimumTouchPoints: 3 + maximumTouchPoints: 3 + onGestureStarted: if (grabInnerArea) gesture.grab() + touchPoints: [ + TouchPoint { objectName: "point21" }, + TouchPoint { objectName: "point22" }, + TouchPoint { objectName: "point23" } + ] + } +} diff --git a/tests/auto/declarative/qquickmultipointtoucharea/data/nonOverlapping.qml b/tests/auto/declarative/qquickmultipointtoucharea/data/nonOverlapping.qml new file mode 100644 index 0000000000..039607e26c --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/data/nonOverlapping.qml @@ -0,0 +1,32 @@ +import QtQuick 2.0 + +Rectangle { + width: 240 + height: 320 + + MultiPointTouchArea { + width: parent.width + height: 160 + minimumTouchPoints: 2 + maximumTouchPoints: 2 + onGestureStarted: gesture.grab() + touchPoints: [ + TouchPoint { objectName: "point11" }, + TouchPoint { objectName: "point12" } + ] + } + + MultiPointTouchArea { + width: parent.width + height: 160 + y: 160 + minimumTouchPoints: 3 + maximumTouchPoints: 3 + onGestureStarted: gesture.grab() + touchPoints: [ + TouchPoint { objectName: "point21" }, + TouchPoint { objectName: "point22" }, + TouchPoint { objectName: "point23" } + ] + } +} diff --git a/tests/auto/declarative/qquickmultipointtoucharea/data/properties.qml b/tests/auto/declarative/qquickmultipointtoucharea/data/properties.qml new file mode 100644 index 0000000000..98ef1a9cbe --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/data/properties.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +MultiPointTouchArea { + width: 240 + height: 320 + + minimumTouchPoints: 2 + maximumTouchPoints: 4 + touchPoints: [ + TouchPoint {}, + TouchPoint {}, + TouchPoint {}, + TouchPoint {} + ] +} diff --git a/tests/auto/declarative/qquickmultipointtoucharea/data/signalTest.qml b/tests/auto/declarative/qquickmultipointtoucharea/data/signalTest.qml new file mode 100644 index 0000000000..3a6aa86a1c --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/data/signalTest.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +MultiPointTouchArea { + width: 240 + height: 320 + + function clearCounts() { + touchPointPressCount = 0; + touchPointUpdateCount = 0; + touchPointReleaseCount = 0; + touchCount = 0; + } + + property int touchPointPressCount: 0 + property int touchPointUpdateCount: 0 + property int touchPointReleaseCount: 0 + property int touchCount: 0 + + maximumTouchPoints: 5 + + onTouchPointsPressed: { touchPointPressCount = touchPoints.length } + onTouchPointsUpdated: { touchPointUpdateCount = touchPoints.length } + onTouchPointsReleased: { touchPointReleaseCount = touchPoints.length } + onTouchUpdated: { touchCount = touchPoints.length } +} diff --git a/tests/auto/declarative/qquickmultipointtoucharea/qquickmultipointtoucharea.pro b/tests/auto/declarative/qquickmultipointtoucharea/qquickmultipointtoucharea.pro new file mode 100644 index 0000000000..8be4b1f1fd --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/qquickmultipointtoucharea.pro @@ -0,0 +1,11 @@ +TARGET = tst_qquickmultipointtoucharea +CONFIG += testcase +macx:CONFIG -= app_bundle + +SOURCES += tst_qquickmultipointtoucharea.cpp + +importFiles.files = data +importFiles.path = . +DEPLOYMENT += importFiles + +QT += core-private gui-private declarative-private testlib diff --git a/tests/auto/declarative/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/declarative/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp new file mode 100644 index 0000000000..9acef50645 --- /dev/null +++ b/tests/auto/declarative/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -0,0 +1,586 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtTest/QSignalSpy> +#include <private/qquickmultipointtoucharea_p.h> +#include <private/qquickflickable_p.h> +#include <QtDeclarative/qquickview.h> + +class tst_QQuickMultiPointTouchArea: public QObject +{ + Q_OBJECT +private slots: + void initTestCase() {} + void cleanupTestCase() {} + + void properties(); + void signalTest(); + void nonOverlapping(); + void nested(); + void inFlickable(); + +private: + QQuickView *createAndShowView(const QString &file); +}; + +void tst_QQuickMultiPointTouchArea::properties() +{ + QQuickView *canvas = createAndShowView("properties.qml"); + QVERIFY(canvas->rootObject() != 0); + + QQuickMultiPointTouchArea *area = qobject_cast<QQuickMultiPointTouchArea *>(canvas->rootObject()); + QVERIFY(area != 0); + + QCOMPARE(area->minimumTouchPoints(), 2); + QCOMPARE(area->maximumTouchPoints(), 4); + + QDeclarativeListReference ref(area, "touchPoints"); + QCOMPARE(ref.count(), 4); + + delete canvas; +} + +void tst_QQuickMultiPointTouchArea::signalTest() +{ + QQuickView *canvas = createAndShowView("signalTest.qml"); + QVERIFY(canvas->rootObject() != 0); + + QQuickMultiPointTouchArea *area = qobject_cast<QQuickMultiPointTouchArea *>(canvas->rootObject()); + QVERIFY(area != 0); + + QPoint p1(20,100); + QPoint p2(40,100); + QPoint p3(60,100); + QPoint p4(80,100); + QPoint p5(100,100); + + QTest::QTouchEventSequence sequence = QTest::touchEvent(canvas); + + sequence.press(0, p1).press(1, p2).commit(); + + QCOMPARE(area->property("touchPointPressCount").toInt(), 2); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0); + QCOMPARE(area->property("touchCount").toInt(), 2); + QMetaObject::invokeMethod(area, "clearCounts"); + + sequence.stationary(0).stationary(1).press(2, p3).commit(); + + QCOMPARE(area->property("touchPointPressCount").toInt(), 1); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0); + QCOMPARE(area->property("touchCount").toInt(), 3); + QMetaObject::invokeMethod(area, "clearCounts"); + + p1 -= QPoint(10,10); + p2 += QPoint(10,10); + sequence.move(0, p1).move(1, p2).stationary(2).commit(); + + QCOMPARE(area->property("touchPointPressCount").toInt(), 0); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 2); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0); + QCOMPARE(area->property("touchCount").toInt(), 3); + QMetaObject::invokeMethod(area, "clearCounts"); + + p3 += QPoint(10,10); + sequence.release(0, p1).release(1, p2) + .move(2, p3).press(3, p4).press(4, p5).commit(); + + QCOMPARE(area->property("touchPointPressCount").toInt(), 2); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 1); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 2); + QCOMPARE(area->property("touchCount").toInt(), 3); + QMetaObject::invokeMethod(area, "clearCounts"); + + sequence.release(2, p3).release(3, p4).release(4, p5).commit(); + + QCOMPARE(area->property("touchPointPressCount").toInt(), 0); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 3); + QCOMPARE(area->property("touchCount").toInt(), 0); + QMetaObject::invokeMethod(area, "clearCounts"); + + delete canvas; +} + +void tst_QQuickMultiPointTouchArea::nonOverlapping() +{ + QQuickView *canvas = createAndShowView("nonOverlapping.qml"); + QVERIFY(canvas->rootObject() != 0); + + QQuickTouchPoint *point11 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point11"); + QQuickTouchPoint *point12 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point12"); + QQuickTouchPoint *point21 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point21"); + QQuickTouchPoint *point22 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point22"); + QQuickTouchPoint *point23 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point23"); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + QPoint p1(20,100); + QPoint p2(40,100); + QPoint p3(60,180); + QPoint p4(80,180); + QPoint p5(100,180); + + QTest::QTouchEventSequence sequence = QTest::touchEvent(canvas); + + sequence.press(0, p1).commit(); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + sequence.stationary(0).press(1, p2).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(100)); + QCOMPARE(point12->x(), qreal(40)); QCOMPARE(point12->y(), qreal(100)); + + p1 += QPoint(0,10); + p2 += QPoint(5,0); + sequence.move(0, p1).move(1, p2).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(110)); + QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); + + sequence.stationary(0).stationary(1).press(2, p3).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + sequence.stationary(0).stationary(1).stationary(2).press(3, p4).press(4, p5).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(110)); + QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); + QCOMPARE(point21->x(), qreal(60)); QCOMPARE(point21->y(), qreal(20)); + QCOMPARE(point22->x(), qreal(80)); QCOMPARE(point22->y(), qreal(20)); + QCOMPARE(point23->x(), qreal(100)); QCOMPARE(point23->y(), qreal(20)); + + p1 += QPoint(4,10); + p2 += QPoint(17,17); + p3 += QPoint(3,0); + p4 += QPoint(1,-1); + p5 += QPoint(-7,10); + sequence.move(0, p1).move(1, p2).move(2, p3).move(3, p4).move(4, p5).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + QCOMPARE(point11->x(), qreal(24)); QCOMPARE(point11->y(), qreal(120)); + QCOMPARE(point12->x(), qreal(62)); QCOMPARE(point12->y(), qreal(117)); + QCOMPARE(point21->x(), qreal(63)); QCOMPARE(point21->y(), qreal(20)); + QCOMPARE(point22->x(), qreal(81)); QCOMPARE(point22->y(), qreal(19)); + QCOMPARE(point23->x(), qreal(93)); QCOMPARE(point23->y(), qreal(30)); + + sequence.release(0, p1).release(1, p2).release(2, p3).release(3, p4).release(4, p5).commit(); + + //points remain valid immediately after release + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + delete canvas; +} + +void tst_QQuickMultiPointTouchArea::nested() +{ + QQuickView *canvas = createAndShowView("nested.qml"); + QVERIFY(canvas->rootObject() != 0); + + QQuickTouchPoint *point11 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point11"); + QQuickTouchPoint *point12 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point12"); + QQuickTouchPoint *point21 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point21"); + QQuickTouchPoint *point22 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point22"); + QQuickTouchPoint *point23 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point23"); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + QPoint p1(20,100); + QPoint p2(40,100); + QPoint p3(60,180); + + QTest::QTouchEventSequence sequence = QTest::touchEvent(canvas); + + sequence.press(0, p1).commit(); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + sequence.stationary(0).press(1, p2).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(100)); + QCOMPARE(point12->x(), qreal(40)); QCOMPARE(point12->y(), qreal(100)); + + p1 += QPoint(0,10); + p2 += QPoint(5,0); + sequence.move(0, p1).move(1, p2).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(110)); + QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); + + sequence.stationary(0).stationary(1).press(2, p3).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + //point11 should be same as point21, point12 same as point22 + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(110)); + QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); + QCOMPARE(point21->x(), qreal(20)); QCOMPARE(point21->y(), qreal(110)); + QCOMPARE(point22->x(), qreal(45)); QCOMPARE(point22->y(), qreal(100)); + QCOMPARE(point23->x(), qreal(60)); QCOMPARE(point23->y(), qreal(180)); + + sequence.stationary(0).stationary(1).stationary(2).press(3, QPoint(80,180)).press(4, QPoint(100,180)).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + //new touch points should be ignored (have no impact on our existing touch points) + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(110)); + QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); + QCOMPARE(point21->x(), qreal(20)); QCOMPARE(point21->y(), qreal(110)); + QCOMPARE(point22->x(), qreal(45)); QCOMPARE(point22->y(), qreal(100)); + QCOMPARE(point23->x(), qreal(60)); QCOMPARE(point23->y(), qreal(180)); + + sequence.stationary(0).stationary(1).stationary(2).release(3, QPoint(80,180)).release(4, QPoint(100,180)).commit(); + + p1 += QPoint(4,10); + p2 += QPoint(17,17); + p3 += QPoint(3,0); + sequence.move(0, p1).move(1, p2).move(2, p3).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + QCOMPARE(point21->x(), qreal(24)); QCOMPARE(point21->y(), qreal(120)); + QCOMPARE(point22->x(), qreal(62)); QCOMPARE(point22->y(), qreal(117)); + QCOMPARE(point21->x(), qreal(24)); QCOMPARE(point21->y(), qreal(120)); + QCOMPARE(point22->x(), qreal(62)); QCOMPARE(point22->y(), qreal(117)); + QCOMPARE(point23->x(), qreal(63)); QCOMPARE(point23->y(), qreal(180)); + + p1 += QPoint(4,10); + p2 += QPoint(17,17); + p3 += QPoint(3,0); + sequence.move(0, p1).move(1, p2).move(2, p3).commit(); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + //first two remain the same (touches now grabbed by inner touch area) + QCOMPARE(point11->x(), qreal(24)); QCOMPARE(point11->y(), qreal(120)); + QCOMPARE(point12->x(), qreal(62)); QCOMPARE(point12->y(), qreal(117)); + QCOMPARE(point21->x(), qreal(28)); QCOMPARE(point21->y(), qreal(130)); + QCOMPARE(point22->x(), qreal(79)); QCOMPARE(point22->y(), qreal(134)); + QCOMPARE(point23->x(), qreal(66)); QCOMPARE(point23->y(), qreal(180)); + + sequence.release(0, p1).release(1, p2).release(2, p3).commit(); + + sequence.press(0, p1).commit(); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + QCOMPARE(point21->isValid(), false); + QCOMPARE(point22->isValid(), false); + QCOMPARE(point23->isValid(), false); + + sequence.release(0, p1).commit(); + + //test with grabbing turned off + canvas->rootObject()->setProperty("grabInnerArea", false); + + sequence.press(0, p1).press(1, p2).press(2, p3).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + p1 -= QPoint(4,10); + p2 -= QPoint(17,17); + p3 -= QPoint(3,0); + sequence.move(0, p1).move(1, p2).move(2, p3).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + QCOMPARE(point21->x(), qreal(24)); QCOMPARE(point21->y(), qreal(120)); + QCOMPARE(point22->x(), qreal(62)); QCOMPARE(point22->y(), qreal(117)); + QCOMPARE(point21->x(), qreal(24)); QCOMPARE(point21->y(), qreal(120)); + QCOMPARE(point22->x(), qreal(62)); QCOMPARE(point22->y(), qreal(117)); + QCOMPARE(point23->x(), qreal(63)); QCOMPARE(point23->y(), qreal(180)); + + p1 -= QPoint(4,10); + p2 -= QPoint(17,17); + p3 -= QPoint(3,0); + sequence.move(0, p1).move(1, p2).move(2, p3).commit(); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + QCOMPARE(point21->isValid(), true); + QCOMPARE(point22->isValid(), true); + QCOMPARE(point23->isValid(), true); + + //all change (touches not grabbed by inner touch area) + QCOMPARE(point11->x(), qreal(20)); QCOMPARE(point11->y(), qreal(110)); + QCOMPARE(point12->x(), qreal(45)); QCOMPARE(point12->y(), qreal(100)); + QCOMPARE(point21->x(), qreal(20)); QCOMPARE(point21->y(), qreal(110)); + QCOMPARE(point22->x(), qreal(45)); QCOMPARE(point22->y(), qreal(100)); + QCOMPARE(point23->x(), qreal(60)); QCOMPARE(point23->y(), qreal(180)); + + sequence.release(0, p1).release(1, p2).release(2, p3).commit(); + + delete canvas; +} + +void tst_QQuickMultiPointTouchArea::inFlickable() +{ + QQuickView *canvas = createAndShowView("inFlickable.qml"); + QVERIFY(canvas->rootObject() != 0); + + QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(canvas->rootObject()); + QVERIFY(flickable != 0); + + QQuickTouchPoint *point11 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point1"); + QQuickTouchPoint *point12 = canvas->rootObject()->findChild<QQuickTouchPoint*>("point2"); + + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + + QPoint p1(20,100); + QPoint p2(40,100); + + //moving one point vertically + QTest::touchEvent(canvas).press(0, p1); + QTest::mousePress(canvas, Qt::LeftButton, 0, p1); + + p1 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1); + QTest::mouseMove(canvas, p1); + + QVERIFY(flickable->contentY() < 0); + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + + QTest::touchEvent(canvas).release(0, p1); + QTest::mouseRelease(canvas,Qt::LeftButton, 0, p1); + QTest::qWait(50); + + QTRY_VERIFY(!flickable->isMoving()); + + //moving two points vertically + p1 = QPoint(20,100); + QTest::touchEvent(canvas).press(0, p1).press(1, p2); + QTest::mousePress(canvas, Qt::LeftButton, 0, p1); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + QVERIFY(flickable->contentY() < 0); + QCOMPARE(point11->isValid(), false); + QCOMPARE(point12->isValid(), false); + + QTest::touchEvent(canvas).release(0, p1).release(1, p2); + QTest::mouseRelease(canvas,Qt::LeftButton, 0, p1); + QTest::qWait(50); + + QTRY_VERIFY(!flickable->isMoving()); + + //moving two points horizontally, then one point vertically + p1 = QPoint(20,100); + p2 = QPoint(40,100); + QTest::touchEvent(canvas).press(0, p1).press(1, p2); + QTest::mousePress(canvas, Qt::LeftButton, 0, p1); + + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + + p1 += QPoint(15,0); p2 += QPoint(15,0); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(15,0); p2 += QPoint(15,0); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(15,0); p2 += QPoint(15,0); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(15,0); p2 += QPoint(15,0); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + p1 += QPoint(0,15); p2 += QPoint(0,15); + QTest::touchEvent(canvas).move(0, p1).move(1, p2); + QTest::mouseMove(canvas, p1); + + QVERIFY(flickable->contentY() == 0); + QCOMPARE(point11->isValid(), true); + QCOMPARE(point12->isValid(), true); + + QTest::touchEvent(canvas).release(0, p1).release(1, p2); + QTest::mouseRelease(canvas,Qt::LeftButton, 0, p1); + QTest::qWait(50); + + delete canvas; +} + +QQuickView *tst_QQuickMultiPointTouchArea::createAndShowView(const QString &file) +{ + QQuickView *canvas = new QQuickView(0); + canvas->setSource(QUrl::fromLocalFile(QCoreApplication::applicationDirPath() + QLatin1String("/data/") + file)); + canvas->show(); + canvas->requestActivateWindow(); + QTest::qWaitForWindowShown(canvas); + + return canvas; +} + +QTEST_MAIN(tst_QQuickMultiPointTouchArea) + +#include "tst_qquickmultipointtoucharea.moc" diff --git a/tests/auto/declarative/qquickpathview/data/pathline.qml b/tests/auto/declarative/qquickpathview/data/pathline.qml new file mode 100644 index 0000000000..4c1c785bce --- /dev/null +++ b/tests/auto/declarative/qquickpathview/data/pathline.qml @@ -0,0 +1,48 @@ +import QtQuick 2.0 + +Rectangle { + id: app + width: 360 + height: 360 + + PathView { + id: pathView + objectName: "view" + x: (app.width-pathView.width)/2 + y: 100 + width: 240 + height: 100 + + model: testModel + + Rectangle { + anchors.fill: parent + color: "white" + border.color: "black" + } + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + + delegate: Rectangle { + objectName: "wrapper" + width: 100 + height: 100 + color: PathView.isCurrentItem ? "red" : "yellow" + Text { + text: index + anchors.centerIn: parent + } + z: (PathView.isCurrentItem?1:0) + } + path: Path { + id: path + startX: -100+pathView.width/2 + startY: pathView.height/2 + PathLine { + id: line + x: 100+pathView.width/2 + y: pathView.height/2 + } + } + } +} diff --git a/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp b/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp index dc85f590e9..5e434b0259 100644 --- a/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp @@ -111,6 +111,7 @@ private slots: void changePreferredHighlight(); void missingPercent(); void creationContext(); + void currentOffsetOnInsertion(); private: QQuickView *createView(); @@ -240,6 +241,8 @@ void tst_QQuickPathView::initValues() QCOMPARE(obj->dragMargin(), 0.); QCOMPARE(obj->count(), 0); QCOMPARE(obj->pathItemCount(), -1); + + delete obj; } void tst_QQuickPathView::items() @@ -303,6 +306,8 @@ void tst_QQuickPathView::pathview2() QCOMPARE(obj->dragMargin(), 0.); QCOMPARE(obj->count(), 8); QCOMPARE(obj->pathItemCount(), 10); + + delete obj; } void tst_QQuickPathView::pathview3() @@ -321,6 +326,8 @@ void tst_QQuickPathView::pathview3() QCOMPARE(obj->dragMargin(), 24.); QCOMPARE(obj->count(), 8); QCOMPARE(obj->pathItemCount(), 4); + + delete obj; } void tst_QQuickPathView::path() @@ -366,6 +373,8 @@ void tst_QQuickPathView::path() QCOMPARE(cubic->control1Y(), 90.); QCOMPARE(cubic->control2X(), 210.); QCOMPARE(cubic->control2Y(), 90.); + + delete obj; } void tst_QQuickPathView::dataModel() @@ -1081,6 +1090,86 @@ void tst_QQuickPathView::creationContext() QCOMPARE(item->property("text").toString(), QString("Hello!")); } +// QTBUG-21320 +void tst_QQuickPathView::currentOffsetOnInsertion() +{ + QQuickView *canvas = createView(); + canvas->show(); + + TestModel model; + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathline.qml"))); + qApp->processEvents(); + + QQuickPathView *pathview = findItem<QQuickPathView>(canvas->rootObject(), "view"); + QVERIFY(pathview != 0); + + pathview->setPreferredHighlightBegin(0.5); + pathview->setPreferredHighlightEnd(0.5); + + QCOMPARE(pathview->count(), model.count()); + + model.addItem("item0", "0"); + + QCOMPARE(pathview->count(), model.count()); + + QQuickRectangle *item = 0; + QTRY_VERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 0)); + + QDeclarativePath *path = qobject_cast<QDeclarativePath*>(pathview->path()); + QVERIFY(path); + + QPointF start = path->pointAt(0.5); + start = QPointF(qRound(start.x()), qRound(start.y())); + QPointF offset;//Center of item is at point, but pos is from corner + offset.setX(item->width()/2); + offset.setY(item->height()/2); + QCOMPARE(item->pos() + offset, start); + + QSignalSpy currentIndexSpy(pathview, SIGNAL(currentIndexChanged())); + + // insert an item at the beginning + model.insertItem(0, "item1", "1"); + qApp->processEvents(); + + QCOMPARE(currentIndexSpy.count(), 1); + + // currentIndex is now 1 + QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 1)); + + // verify that current item (item 1) is still at offset 0.5 + QCOMPARE(item->pos() + offset, start); + + // insert another item at the beginning + model.insertItem(0, "item2", "2"); + qApp->processEvents(); + + QCOMPARE(currentIndexSpy.count(), 2); + + // currentIndex is now 2 + QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 2)); + + // verify that current item (item 2) is still at offset 0.5 + QCOMPARE(item->pos() + offset, start); + + // verify that remove before current maintains current item + model.removeItem(0); + qApp->processEvents(); + + QCOMPARE(currentIndexSpy.count(), 3); + + // currentIndex is now 1 + QVERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 1)); + + // verify that current item (item 1) is still at offset 0.5 + QCOMPARE(item->pos() + offset, start); + + delete canvas; +} + QQuickView *tst_QQuickPathView::createView() { QQuickView *canvas = new QQuickView(0); diff --git a/tests/auto/declarative/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/declarative/qquickpositioners/tst_qquickpositioners.cpp index 1d3ccabbf5..f50b5a5b49 100644 --- a/tests/auto/declarative/qquickpositioners/tst_qquickpositioners.cpp +++ b/tests/auto/declarative/qquickpositioners/tst_qquickpositioners.cpp @@ -267,8 +267,8 @@ void tst_qquickpositioners::test_horizontal_animated() QTRY_COMPARE(row->height(), 50.0); QTest::qWait(0);//Let the animation start - QCOMPARE(two->x(), -100.0); - QCOMPARE(three->x(), 50.0); + QVERIFY(two->x() >= -100.0 && two->x() < 50.0); + QVERIFY(three->x() >= 50.0 && three->x() < 100.0); QTRY_COMPARE(two->x(), 50.0); QTRY_COMPARE(three->x(), 100.0); @@ -323,8 +323,8 @@ void tst_qquickpositioners::test_horizontal_animated_rightToLeft() QTRY_COMPARE(row->height(), 50.0); QTest::qWait(0);//Let the animation start - QCOMPARE(one->x(), 50.0); - QCOMPARE(two->x(), -100.0); + QVERIFY(one->x() >= 50.0 && one->x() < 100); + QVERIFY(two->x() >= -100.0 && two->x() < 50.0); QTRY_COMPARE(one->x(), 100.0); QTRY_COMPARE(two->x(), 50.0); @@ -361,13 +361,11 @@ void tst_qquickpositioners::test_horizontal_animated_disabled() //Add 'two' two->setVisible(true); QCOMPARE(two->isVisible(), true); - qApp->processEvents(); - QCOMPARE(row->width(), 150.0); - QCOMPARE(row->height(), 50.0); + QTRY_COMPARE(row->width(), 150.0); + QTRY_COMPARE(row->height(), 50.0); - qApp->processEvents(); - QCOMPARE(two->x(), 50.0); - QCOMPARE(three->x(), 100.0); + QTRY_COMPARE(two->x(), 50.0); + QTRY_COMPARE(three->x(), 100.0); delete canvas; } @@ -468,8 +466,8 @@ void tst_qquickpositioners::test_vertical_animated() QTRY_COMPARE(column->height(), 150.0); QTRY_COMPARE(column->width(), 50.0); QTest::qWait(0);//Let the animation start - QCOMPARE(two->y(), -100.0); - QCOMPARE(three->y(), 50.0); + QVERIFY(two->y() >= -100.0 && two->y() < 50.0); + QVERIFY(three->y() >= 50.0 && three->y() < 100.0); QTRY_COMPARE(two->y(), 50.0); QTRY_COMPARE(three->y(), 100.0); diff --git a/src/declarative/debugger/qdeclarativedebuggerstatus.cpp b/tests/auto/declarative/qquickspriteimage/data/basic.qml index 4f016b4afc..1fcdfd99c3 100644 --- a/src/declarative/debugger/qdeclarativedebuggerstatus.cpp +++ b/tests/auto/declarative/qquickspriteimage/data/basic.qml @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the QtDeclarative module of the Qt Toolkit. +** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage @@ -39,16 +39,22 @@ ** ****************************************************************************/ -#include "qdeclarativedebuggerstatus_p.h" +import QtQuick 2.0 -QT_BEGIN_NAMESPACE +Rectangle { + color: "black" + width: 320 + height: 320 -QDeclarativeDebuggerStatus::~QDeclarativeDebuggerStatus() -{ + SpriteImage { + objectName: "sprite" + sprites: Sprite { + name: "happy" + source: "squarefacesprite.png" + frames: 6 + duration: 120 + } + width: 160 + height: 160 + } } - -void QDeclarativeDebuggerStatus::setSelectedState(bool) -{ -} - -QT_END_NAMESPACE diff --git a/tests/auto/declarative/qquickspriteimage/data/squarefacesprite.png b/tests/auto/declarative/qquickspriteimage/data/squarefacesprite.png Binary files differnew file mode 100644 index 0000000000..f9a5d5fcce --- /dev/null +++ b/tests/auto/declarative/qquickspriteimage/data/squarefacesprite.png diff --git a/tests/auto/declarative/qquickspriteimage/qquickspriteimage.pro b/tests/auto/declarative/qquickspriteimage/qquickspriteimage.pro new file mode 100644 index 0000000000..db5c45da8a --- /dev/null +++ b/tests/auto/declarative/qquickspriteimage/qquickspriteimage.pro @@ -0,0 +1,12 @@ +CONFIG += testcase +TARGET = tst_qquickspriteimage +SOURCES += tst_qquickspriteimage.cpp +macx:CONFIG -= app_bundle + +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + +CONFIG += parallel_test + +QT += core-private gui-private declarative-private network testlib diff --git a/tests/auto/declarative/qquickspriteimage/tst_qquickspriteimage.cpp b/tests/auto/declarative/qquickspriteimage/tst_qquickspriteimage.cpp new file mode 100644 index 0000000000..1b8c58b873 --- /dev/null +++ b/tests/auto/declarative/qquickspriteimage/tst_qquickspriteimage.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtTest/QtTest> +#include "../shared/util.h" +#include <qquickview.h> +#include <private/qquickspriteimage_p.h> + +class tst_qquickspriteimage : public QObject +{ + Q_OBJECT +public: + tst_qquickspriteimage(){} + +private slots: + void test_properties(); +}; + +void tst_qquickspriteimage::test_properties() +{ + QQuickView *canvas = new QQuickView(0); + + canvas->setSource(QUrl::fromLocalFile(TESTDATA("basic.qml"))); + canvas->show(); + QTest::qWaitForWindowShown(canvas); + + QVERIFY(canvas->rootObject()); + QQuickSpriteImage* sprite = canvas->rootObject()->findChild<QQuickSpriteImage*>("sprite"); + QVERIFY(sprite); + + QVERIFY(sprite->running()); + QVERIFY(sprite->interpolate()); + + sprite->setRunning(false); + QVERIFY(!sprite->running()); + sprite->setInterpolate(false); + QVERIFY(!sprite->interpolate()); + + delete canvas; +} + +QTEST_MAIN(tst_qquickspriteimage) + +#include "tst_qquickspriteimage.moc" diff --git a/tests/auto/declarative/qquicktext/tst_qquicktext.cpp b/tests/auto/declarative/qquicktext/tst_qquicktext.cpp index 3a08dd208d..8ac3a078bc 100644 --- a/tests/auto/declarative/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/declarative/qquicktext/tst_qquicktext.cpp @@ -520,15 +520,7 @@ void tst_qquicktext::alignments() QFETCH(int, vAlign); QFETCH(QString, expectfile); -#ifdef Q_WS_X11 - // Font-specific, but not likely platform-specific, so only test on one platform - QFont fn; - fn.setRawName("-misc-fixed-medium-r-*-*-8-*-*-*-*-*-*-*"); - QApplication::setFont(fn); -#endif - QQuickView *canvas = createView(TESTDATA("alignments.qml")); - canvas->show(); canvas->requestActivateWindow(); QTest::qWait(50); @@ -545,14 +537,9 @@ void tst_qquicktext::alignments() canvas->render(&p); QImage expect(expectfile); - -#ifdef Q_WS_X11 - // Font-specific, but not likely platform-specific, so only test on one platform if (QApplicationPrivate::graphics_system_name == "raster" || QApplicationPrivate::graphics_system_name == "") { QCOMPARE(actual,expect); } -#endif - delete canvas; #endif } diff --git a/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp index 86c33a64d8..693619f638 100644 --- a/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp @@ -63,7 +63,7 @@ #include <private/qtextcontrol_p.h> #include "../shared/util.h" -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC #include <Carbon/Carbon.h> #endif @@ -151,8 +151,7 @@ private slots: void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); - void preeditMicroFocus(); - void inputContextMouseHandler(); + void preeditCursorRectangle(); void inputMethodComposing(); void cursorRectangleSize(); @@ -573,12 +572,15 @@ void tst_qquicktextedit::hAlign_RightToLeft() QTRY_COMPARE(&canvas, qGuiApp->focusWindow()); textEdit->setText(QString()); - { QInputMethodEvent ev(rtlText, QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(&canvas, &ev); } - QEXPECT_FAIL("", "QTBUG-21691", Abort); + { QInputMethodEvent ev(rtlText, QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &ev); } QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight); - { QInputMethodEvent ev("Hello world!", QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(&canvas, &ev); } + { QInputMethodEvent ev("Hello world!", QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &ev); } QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignLeft); + // Clear pre-edit text. TextEdit should maybe do this itself on setText, but that may be + // redundant as an actual input method may take care of it. + { QInputMethodEvent ev; QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &ev); } + #ifndef Q_OS_MAC // QTBUG-18040 // empty text with implicit alignment follows the system locale-based // keyboard input direction from QGuiApplication::keyboardInputDirection @@ -1402,8 +1404,6 @@ void tst_qquicktextedit::mouseSelection() QTest::mouseClick(&canvas, Qt::LeftButton, Qt::NoModifier, p1); QTest::mouseClick(&canvas, Qt::LeftButton, Qt::ShiftModifier, p2); QTest::qWait(50); - if (!selectedText.isEmpty()) - QEXPECT_FAIL("", "QTBUG-21743", Continue); QTRY_COMPARE(textEditObject->selectedText(), selectedText); } @@ -1525,36 +1525,28 @@ void tst_qquicktextedit::positionAt() const int y1 = fm.height() * 3 / 2; int pos = texteditObject->positionAt(texteditObject->width()/2, y0); - int width = 0; + int widthBegin = 0; + int widthEnd = 0; if (!qmlDisableDistanceField()) { - QTextLayout layout(texteditObject->text().left(pos)); + QTextLayout layout(texteditObject->text()); - { - QTextOption option; - option.setUseDesignMetrics(true); - layout.setTextOption(option); - } + QTextOption option; + option.setUseDesignMetrics(true); + layout.setTextOption(option); layout.beginLayout(); QTextLine line = layout.createLine(); layout.endLayout(); - width = ceil(line.horizontalAdvance()); - + widthBegin = floor(line.cursorToX(pos - 1)); + widthEnd = ceil(line.cursorToX(pos + 1)); } else { - width = fm.width(texteditObject->text().left(pos)); + widthBegin = fm.width(texteditObject->text().left(pos - 1)); + widthEnd = fm.width(texteditObject->text().left(pos + 1)); } - - int diff = abs(int(width-texteditObject->width()/2)); - - QEXPECT_FAIL("", "QTBUG-21689", Abort); - // some tollerance for different fonts. -#ifdef Q_OS_LINUX - QVERIFY(diff < 2); -#else - QVERIFY(diff < 5); -#endif + QVERIFY(widthBegin <= texteditObject->width() / 2); + QVERIFY(widthEnd >= texteditObject->width() / 2); const qreal x0 = texteditObject->positionToRectangle(pos).x(); const qreal x1 = texteditObject->positionToRectangle(pos + 1).x(); @@ -1564,7 +1556,7 @@ void tst_qquicktextedit::positionAt() texteditObject->setCursorPosition(0); QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>()); - QGuiApplication::sendEvent(&canvas, &inputEvent); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &inputEvent); // Check all points within the preedit text return the same position. QCOMPARE(texteditObject->positionAt(0, y0), 0); @@ -1780,7 +1772,7 @@ void tst_qquicktextedit::navigation() void tst_qquicktextedit::copyAndPaste() { #ifndef QT_NO_CLIPBOARD -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC { PasteboardRef pasteboard; OSStatus status = PasteboardCreate(0, &pasteboard); @@ -1909,55 +1901,6 @@ void tst_qquicktextedit::simulateKey(QQuickView *view, int key, Qt::KeyboardModi QGuiApplication::sendEvent(view, &release); } - -#ifndef QTBUG_21691 -class MyInputContext : public QInputContext -{ -public: - MyInputContext() : updateReceived(false), eventType(QEvent::None) {} - ~MyInputContext() {} - - QString identifierName() { return QString(); } - QString language() { return QString(); } - - void reset() {} - - bool isComposing() const { return false; } - - void update() { updateReceived = true; } - - void sendPreeditText(const QString &text, int cursor) - { - QList<QInputMethodEvent::Attribute> attributes; - attributes.append(QInputMethodEvent::Attribute( - QInputMethodEvent::Cursor, cursor, text.length(), QVariant())); - - QInputMethodEvent event(text, attributes); - sendEvent(event); - } - - void mouseHandler(int x, QMouseEvent *event) - { - cursor = x; - eventType = event->type(); - eventPosition = event->pos(); - eventGlobalPosition = event->globalPos(); - eventButton = event->button(); - eventButtons = event->buttons(); - eventModifiers = event->modifiers(); - } - - bool updateReceived; - int cursor; - QEvent::Type eventType; - QPoint eventPosition; - QPoint eventGlobalPosition; - Qt::MouseButton eventButton; - Qt::MouseButtons eventButtons; - Qt::KeyboardModifiers eventModifiers; -}; -#endif - void tst_qquicktextedit::textInput() { QQuickView view(QUrl::fromLocalFile(TESTDATA("inputMethodEvent.qml"))); @@ -1972,8 +1915,7 @@ void tst_qquicktextedit::textInput() // test that input method event is committed QInputMethodEvent event; event.setCommitString( "Hello world!", 0, 0); - QGuiApplication::sendEvent(&view, &event); - QEXPECT_FAIL("", "QTBUG-21689", Abort); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); QCOMPARE(edit->text(), QString("Hello world!")); // QTBUG-12339 @@ -2179,12 +2121,8 @@ void tst_qquicktextedit::testQtQuick11Attributes_data() << ":1 \"TextEdit.onLinkActivated\" is not available in QtQuick 1.0.\n"; } -void tst_qquicktextedit::preeditMicroFocus() +void tst_qquicktextedit::preeditCursorRectangle() { -#ifdef QTBUG_21691 - QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort); - QVERIFY(false); -#else QString preeditText = "super"; QQuickView view(QUrl::fromLocalFile(TESTDATA("inputMethodEvent.qml"))); @@ -2196,173 +2134,52 @@ void tst_qquicktextedit::preeditMicroFocus() QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject()); QVERIFY(edit); - QSignalSpy cursorRectangleSpy(edit, SIGNAL(cursorRectangleChanged())); + QSignalSpy editSpy(edit, SIGNAL(cursorRectangleChanged())); + QSignalSpy panelSpy(qGuiApp->inputPanel(), SIGNAL(cursorRectangleChanged())); QRect currentRect; - QRect previousRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + + QInputMethodQueryEvent query(Qt::ImCursorRectangle); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + QRect previousRect = query.value(Qt::ImCursorRectangle).toRect(); // Verify that the micro focus rect is positioned the same for position 0 as // it would be if there was no preedit text. - ic.updateReceived = false; - ic.sendPreeditText(preeditText, 0); - currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + QInputMethodEvent imEvent(preeditText, QList<QInputMethodEvent::Attribute>() + << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, preeditText.length(), QVariant())); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + currentRect = query.value(Qt::ImCursorRectangle).toRect(); QCOMPARE(currentRect, previousRect); -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - QCOMPARE(ic.updateReceived, false); // The cursor position hasn't changed. -#endif - QCOMPARE(cursorRectangleSpy.count(), 0); + QCOMPARE(editSpy.count(), 0); + QCOMPARE(panelSpy.count(), 0); // Verify that the micro focus rect moves to the left as the cursor position // is incremented. for (int i = 1; i <= 5; ++i) { - ic.updateReceived = false; - ic.sendPreeditText(preeditText, i); - currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + QInputMethodEvent imEvent(preeditText, QList<QInputMethodEvent::Attribute>() + << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, i, preeditText.length(), QVariant())); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + currentRect = query.value(Qt::ImCursorRectangle).toRect(); QVERIFY(previousRect.left() < currentRect.left()); -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - QCOMPARE(ic.updateReceived, true); -#endif - QVERIFY(cursorRectangleSpy.count() > 0); - cursorRectangleSpy.clear(); + QVERIFY(editSpy.count() > 0); editSpy.clear(); + QVERIFY(panelSpy.count() > 0); panelSpy.clear(); previousRect = currentRect; } // Verify that if there is no preedit cursor then the micro focus rect is the // same as it would be if it were positioned at the end of the preedit text. - ic.sendPreeditText(preeditText, 0); - ic.updateReceived = false; - ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>())); - currentRect = edit->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); + editSpy.clear(); + panelSpy.clear(); + { QInputMethodEvent imEvent(preeditText, QList<QInputMethodEvent::Attribute>()); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); } + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + currentRect = query.value(Qt::ImCursorRectangle).toRect(); QCOMPARE(currentRect, previousRect); -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - QCOMPARE(ic.updateReceived, true); -#endif - QVERIFY(cursorRectangleSpy.count() > 0); -#endif -} - -void tst_qquicktextedit::inputContextMouseHandler() -{ - -#ifdef QTBUG_21691 - QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort); - QVERIFY(false); -#else - QString text = "supercalifragisiticexpialidocious!"; - - QQuickView view(QUrl::fromLocalFile(TESTDATA("inputContext.qml"))); - MyInputContext ic; - // QQuickCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has focus - // and QWidget won't allow an input context to be set when the flag is not set. - view.setAttribute(Qt::WA_InputMethodEnabled, true); - view.setInputContext(&ic); - view.setAttribute(Qt::WA_InputMethodEnabled, false); - view.show(); - view.requestActivateWindow(); - QTest::qWaitForWindowShown(&view); - - QTRY_COMPARE(&view, qGuiApp->focusWindow()); - QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject()); - QVERIFY(edit); - edit->setCursorPosition(12); - - QFontMetricsF fm(edit->font()); - const qreal y = fm.height() / 2; - - QPoint position2 = edit->mapToScene(QPointF(fm.width(text.mid(0, 2)), y)).toPoint(); - QPoint position8 = edit->mapToScene(QPointF(fm.width(text.mid(0, 8)), y)).toPoint(); - QPoint position20 = edit->mapToScene(QPointF(fm.width(text.mid(0, 20)), y)).toPoint(); - QPoint position27 = edit->mapToScene(QPointF(fm.width(text.mid(0, 27)), y)).toPoint(); - QPoint globalPosition2 = view.mapToGlobal(position2); - QPoint globalposition8 = view.mapToGlobal(position8); - QPoint globalposition20 = view.mapToGlobal(position20); - QPoint globalposition27 = view.mapToGlobal(position27); - - ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>())); - - QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, position2); - QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick); - QCOMPARE(ic.eventPosition, position2); - QCOMPARE(ic.eventGlobalPosition, globalPosition2); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor < 0); - ic.eventType = QEvent::None; - - QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position2); - QCOMPARE(ic.eventType, QEvent::MouseButtonPress); - QCOMPARE(ic.eventPosition, position2); - QCOMPARE(ic.eventGlobalPosition, globalPosition2); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor < 0); - ic.eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::None); - - { QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::MouseMove); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); // 15 is expected but some platforms may be off by one. - ic.eventType = QEvent::None; - - QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position27); - QCOMPARE(ic.eventType, QEvent::MouseButtonRelease); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); - ic.eventType = QEvent::None; - - // And in the other direction. - QTest::mouseDClick(&view, Qt::LeftButton, Qt::ControlModifier, position27); - QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); - ic.eventType = QEvent::None; - - QTest::mousePress(&view, Qt::RightButton, Qt::ControlModifier, position27); - QCOMPARE(ic.eventType, QEvent::MouseButtonPress); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::RightButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); - ic.eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::MouseMove); - QCOMPARE(ic.eventPosition, position20); - QCOMPARE(ic.eventGlobalPosition, globalposition20); - QCOMPARE(ic.eventButton, Qt::RightButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor >= 7 && ic.cursor <= 9); - ic.eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::None); - - QTest::mouseRelease(&view, Qt::RightButton, Qt::ControlModifier, position2); - QCOMPARE(ic.eventType, QEvent::MouseButtonRelease); - QCOMPARE(ic.eventPosition, position2); - QCOMPARE(ic.eventGlobalPosition, globalPosition2); - QCOMPARE(ic.eventButton, Qt::RightButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor < 0); - ic.eventType = QEvent::None; -#endif + QVERIFY(editSpy.count() > 0); + QVERIFY(panelSpy.count() > 0); } void tst_qquicktextedit::inputMethodComposing() diff --git a/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp index 23224d0452..bf29f88ff1 100644 --- a/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp @@ -56,6 +56,10 @@ #include <QtOpenGL/QGLShaderProgram> #include <math.h> +#ifdef Q_OS_MAC +#include <Carbon/Carbon.h> +#endif + #include "qplatformdefs.h" Q_DECLARE_METATYPE(QQuickTextInput::SelectionMode) @@ -142,8 +146,7 @@ private slots: void testQtQuick11Attributes_data(); void preeditAutoScroll(); - void preeditMicroFocus(); - void inputContextMouseHandler(); + void preeditCursorRectangle(); void inputMethodComposing(); void cursorRectangleSize(); @@ -1158,15 +1161,20 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() // If there is no commited text, the preedit text should determine the alignment. textInput->setText(QString()); - { QInputMethodEvent ev(rtlText, QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(&canvas, &ev); } - QEXPECT_FAIL("", "QTBUG-21691", Continue); + { QInputMethodEvent ev(rtlText, QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &ev); } QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); - { QInputMethodEvent ev("Hello world!", QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(&canvas, &ev); } + { QInputMethodEvent ev("Hello world!", QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &ev); } QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft); -#ifndef Q_OS_MAC // QTBUG-18040 + // Clear pre-edit text. TextInput should maybe do this itself on setText, but that may be + // redundant as an actual input method may take care of it. + { QInputMethodEvent ev; QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &ev); } + +#ifdef Q_OS_MAC // empty text with implicit alignment follows the system locale-based // keyboard input direction from QGuiApplication::keyboardInputDirection + QEXPECT_FAIL("", "QTBUG-18040", Abort); +#endif textInput->setText(""); QCOMPARE(textInput->hAlign(), QGuiApplication::keyboardInputDirection() == Qt::LeftToRight ? QQuickTextInput::AlignLeft : QQuickTextInput::AlignRight); @@ -1177,10 +1185,11 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() textInput->setHAlign(QQuickTextInput::AlignRight); QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight); QVERIFY(-textInputPrivate->hscroll > canvas.width()/2); -#endif -#ifndef Q_OS_MAC // QTBUG-18040 - // alignment of TextInput with no text set to it + +#ifdef Q_OS_MAC + QEXPECT_FAIL("", "QTBUG-18040", Abort); // alignment of TextInput with no text set to it +#endif QString componentStr = "import QtQuick 2.0\nTextInput {}"; QDeclarativeComponent textComponent(&engine); textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); @@ -1188,7 +1197,6 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() QCOMPARE(textObject->hAlign(), QGuiApplication::keyboardInputDirection() == Qt::LeftToRight ? QQuickTextInput::AlignLeft : QQuickTextInput::AlignRight); delete textObject; -#endif } void tst_qquicktextinput::positionAt() @@ -1207,52 +1215,30 @@ void tst_qquicktextinput::positionAt() int pos = textinputObject->positionAt(textinputObject->width()/2); int textWidth = 0; - int textLeftWidth = 0; + int textLeftWidthBegin = 0; + int textLeftWidthEnd = 0; if (!qmlDisableDistanceField()) { - { - QTextLayout layout(textinputObject->text().left(pos)); + QTextLayout layout(textinputObject->text()); - { - QTextOption option; - option.setUseDesignMetrics(true); - layout.setTextOption(option); - } - - layout.beginLayout(); - QTextLine line = layout.createLine(); - layout.endLayout(); + QTextOption option; + option.setUseDesignMetrics(true); + layout.setTextOption(option); - textLeftWidth = ceil(line.horizontalAdvance()); - } - { - QTextLayout layout(textinputObject->text()); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); - { - QTextOption option; - option.setUseDesignMetrics(true); - layout.setTextOption(option); - } - - layout.beginLayout(); - QTextLine line = layout.createLine(); - layout.endLayout(); - - textWidth = ceil(line.horizontalAdvance()); - } + textLeftWidthBegin = floor(line.cursorToX(pos - 1)); + textLeftWidthEnd = ceil(line.cursorToX(pos + 1)); + textWidth = floor(line.horizontalAdvance()); } else { textWidth = fm.width(textinputObject->text()); - textLeftWidth = fm.width(textinputObject->text().left(pos)); + textLeftWidthBegin = fm.width(textinputObject->text().left(pos - 1)); + textLeftWidthEnd = fm.width(textinputObject->text().left(pos + 1)); } - int diff = abs(textWidth - (textLeftWidth+textinputObject->width()/2)); - - // some tollerance for different fonts. - QEXPECT_FAIL("", "QTBUG-21689", Abort); -#ifdef Q_OS_LINUX - QVERIFY(diff < 2); -#else - QVERIFY(diff < 5); -#endif + QVERIFY(textLeftWidthBegin <= textWidth - textinputObject->width() / 2); + QVERIFY(textLeftWidthEnd >= textWidth - textinputObject->width() / 2); int x = textinputObject->positionToRectangle(pos + 1).x() - 1; QCOMPARE(textinputObject->positionAt(x, QQuickTextInput::CursorBetweenCharacters), pos + 1); @@ -1263,33 +1249,25 @@ void tst_qquicktextinput::positionAt() pos = textinputObject->positionAt(textinputObject->width()/2); if (!qmlDisableDistanceField()) { - { - QTextLayout layout(textinputObject->text().left(pos)); + QTextLayout layout(textinputObject->text()); - { - QTextOption option; - option.setUseDesignMetrics(true); - layout.setTextOption(option); - } + QTextOption option; + option.setUseDesignMetrics(true); + layout.setTextOption(option); - layout.beginLayout(); - QTextLine line = layout.createLine(); - layout.endLayout(); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); - textLeftWidth = ceil(line.horizontalAdvance()); - } + textLeftWidthBegin = floor(line.cursorToX(pos - 1)); + textLeftWidthEnd = ceil(line.cursorToX(pos + 1)); } else { - textLeftWidth = fm.width(textinputObject->text().left(pos)); + textLeftWidthBegin = fm.width(textinputObject->text().left(pos - 1)); + textLeftWidthEnd = fm.width(textinputObject->text().left(pos + 1)); } - diff = abs(int(textLeftWidth-textinputObject->width()/2)); - - // some tollerance for different fonts. -#ifdef Q_OS_LINUX - QVERIFY(diff < 2); -#else - QVERIFY(diff < 5); -#endif + QVERIFY(textLeftWidthBegin <= textinputObject->width() / 2); + QVERIFY(textLeftWidthEnd >= textinputObject->width() / 2); x = textinputObject->positionToRectangle(pos + 1).x() - 1; QCOMPARE(textinputObject->positionAt(x, QQuickTextInput::CursorBetweenCharacters), pos + 1); @@ -1303,7 +1281,7 @@ void tst_qquicktextinput::positionAt() textinputObject->setCursorPosition(0); QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>()); - QGuiApplication::sendEvent(&canvas, &inputEvent); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &inputEvent); // Check all points within the preedit text return the same position. QCOMPARE(textinputObject->positionAt(0), 0); @@ -1495,25 +1473,24 @@ void tst_qquicktextinput::inputMethods() // test that input method event is committed QInputMethodEvent event; event.setCommitString( "My ", -12, 0); - QGuiApplication::sendEvent(&canvas, &event); - QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); QCOMPARE(input->text(), QString("My Hello world!")); input->setCursorPosition(2); event.setCommitString("Your", -2, 2); - QGuiApplication::sendEvent(&canvas, &event); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); QCOMPARE(input->text(), QString("Your Hello world!")); QCOMPARE(input->cursorPosition(), 4); input->setCursorPosition(7); event.setCommitString("Goodbye", -2, 5); - QGuiApplication::sendEvent(&canvas, &event); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); QCOMPARE(input->text(), QString("Your Goodbye world!")); QCOMPARE(input->cursorPosition(), 12); input->setCursorPosition(8); event.setCommitString("Our", -8, 4); - QGuiApplication::sendEvent(&canvas, &event); + QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); QCOMPARE(input->text(), QString("Our Goodbye world!")); QCOMPARE(input->cursorPosition(), 7); } @@ -1602,7 +1579,7 @@ void tst_qquicktextinput::navigation_RTL() void tst_qquicktextinput::copyAndPaste() { #ifndef QT_NO_CLIPBOARD -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC { PasteboardRef pasteboard; OSStatus status = PasteboardCreate(0, &pasteboard); @@ -2265,66 +2242,69 @@ void tst_qquicktextinput::testQtQuick11Attributes_data() << ""; } +static void sendPreeditText(const QString &text, int cursor) +{ + QInputMethodEvent event(text, QList<QInputMethodEvent::Attribute>() + << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursor, text.length(), QVariant())); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &event); +} + void tst_qquicktextinput::preeditAutoScroll() { -#ifdef QTBUG_21691 - QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort); - QVERIFY(false); -#else QString preeditText = "califragisiticexpialidocious!"; QQuickView view(QUrl::fromLocalFile(TESTDATA("preeditAutoScroll.qml"))); - MyInputContext ic; - // QQuickCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has active focus - // and QWidget won't allow an input context to be set when the flag is not set. - view.setAttribute(Qt::WA_InputMethodEnabled, true); - view.setInputContext(&ic); - view.setAttribute(Qt::WA_InputMethodEnabled, false); view.show(); view.requestActivateWindow(); QTest::qWaitForWindowShown(&view); QTRY_COMPARE(&view, qGuiApp->focusWindow()); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(view.rootObject()); QVERIFY(input); + QVERIFY(input->hasActiveFocus()); + + input->setWidth(input->implicitWidth()); QSignalSpy cursorRectangleSpy(input, SIGNAL(cursorRectangleChanged())); int cursorRectangleChanges = 0; - QFontMetricsF fm(input->font()); - input->setWidth(fm.width(input->text())); - // test the text is scrolled so the preedit is visible. - ic.sendPreeditText(preeditText.mid(0, 3), 1); + sendPreeditText(preeditText.mid(0, 3), 1); QVERIFY(input->positionAt(0) != 0); QVERIFY(input->cursorRectangle().left() < input->boundingRect().width()); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); // test the text is scrolled back when the preedit is removed. - ic.sendEvent(QInputMethodEvent()); + QInputMethodEvent imEvent; + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); QCOMPARE(input->positionAt(0), 0); QCOMPARE(input->positionAt(input->width()), 5); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); - // some tolerance for different fonts. -#ifdef Q_OS_LINUX - const int error = 2; -#else - const int error = 5; -#endif + QTextLayout layout(preeditText); + if (!qmlDisableDistanceField()) { + QTextOption option; + option.setUseDesignMetrics(true); + layout.setTextOption(option); + } + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); // test if the preedit is larger than the text input that the // character preceding the cursor is still visible. qreal x = input->positionToRectangle(0).x(); for (int i = 0; i < 3; ++i) { - ic.sendPreeditText(preeditText, i + 1); - QVERIFY(input->cursorRectangle().right() >= fm.width(preeditText.at(i)) - error); + sendPreeditText(preeditText, i + 1); + int width = ceil(line.cursorToX(i, QTextLine::Trailing)) - floor(line.cursorToX(i)); + QVERIFY(input->cursorRectangle().right() >= width - 3); QVERIFY(input->positionToRectangle(0).x() < x); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); x = input->positionToRectangle(0).x(); } for (int i = 1; i >= 0; --i) { - ic.sendPreeditText(preeditText, i + 1); - QVERIFY(input->cursorRectangle().right() >= fm.width(preeditText.at(i)) - error); + sendPreeditText(preeditText, i + 1); + int width = ceil(line.cursorToX(i, QTextLine::Trailing)) - floor(line.cursorToX(i)); + QVERIFY(input->cursorRectangle().right() >= width - 3); QVERIFY(input->positionToRectangle(0).x() > x); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); x = input->positionToRectangle(0).x(); @@ -2332,45 +2312,34 @@ void tst_qquicktextinput::preeditAutoScroll() // Test incrementing the preedit cursor doesn't cause further // scrolling when right most text is visible. - ic.sendPreeditText(preeditText, preeditText.length() - 3); + sendPreeditText(preeditText, preeditText.length() - 3); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); x = input->positionToRectangle(0).x(); for (int i = 2; i >= 0; --i) { - ic.sendPreeditText(preeditText, preeditText.length() - i); + sendPreeditText(preeditText, preeditText.length() - i); QCOMPARE(input->positionToRectangle(0).x(), x); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); } for (int i = 1; i < 3; ++i) { - ic.sendPreeditText(preeditText, preeditText.length() - i); + sendPreeditText(preeditText, preeditText.length() - i); QCOMPARE(input->positionToRectangle(0).x(), x); QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges); } // Test disabling auto scroll. - ic.sendEvent(QInputMethodEvent()); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); input->setAutoScroll(false); - ic.sendPreeditText(preeditText.mid(0, 3), 1); + sendPreeditText(preeditText.mid(0, 3), 1); QCOMPARE(input->positionAt(0), 0); QCOMPARE(input->positionAt(input->width()), 5); -#endif } -void tst_qquicktextinput::preeditMicroFocus() +void tst_qquicktextinput::preeditCursorRectangle() { -#ifdef QTBUG_21691 - QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort); - QVERIFY(false); -#else QString preeditText = "super"; QQuickView view(QUrl::fromLocalFile(TESTDATA("inputMethodEvent.qml"))); - MyInputContext ic; - // QQuickCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has active focus - // and QWidget won't allow an input context to be set when the flag is not set. - view.setAttribute(Qt::WA_InputMethodEnabled, true); - view.setInputContext(&ic); - view.setAttribute(Qt::WA_InputMethodEnabled, false); view.show(); view.requestActivateWindow(); QTest::qWaitForWindowShown(&view); @@ -2379,163 +2348,43 @@ void tst_qquicktextinput::preeditMicroFocus() QVERIFY(input); QRect currentRect; - QRect previousRect = input->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + + QInputMethodQueryEvent query(Qt::ImCursorRectangle); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + QRect previousRect = query.value(Qt::ImCursorRectangle).toRect(); // Verify that the micro focus rect is positioned the same for position 0 as // it would be if there was no preedit text. - ic.updateReceived = false; - ic.sendPreeditText(preeditText, 0); - currentRect = input->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + sendPreeditText(preeditText, 0); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + currentRect = query.value(Qt::ImCursorRectangle).toRect(); QCOMPARE(currentRect, previousRect); -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - QCOMPARE(ic.updateReceived, true); -#endif + + QSignalSpy inputSpy(input, SIGNAL(cursorRectangleChanged())); + QSignalSpy panelSpy(qGuiApp->inputPanel(), SIGNAL(cursorRectangleChanged())); // Verify that the micro focus rect moves to the left as the cursor position // is incremented. for (int i = 1; i <= 5; ++i) { - ic.updateReceived = false; - ic.sendPreeditText(preeditText, i); - currentRect = input->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + sendPreeditText(preeditText, i); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + currentRect = query.value(Qt::ImCursorRectangle).toRect(); QVERIFY(previousRect.left() < currentRect.left()); -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - QCOMPARE(ic.updateReceived, true); -#endif + QVERIFY(inputSpy.count() > 0); inputSpy.clear(); + QVERIFY(panelSpy.count() > 0); panelSpy.clear(); previousRect = currentRect; } // Verify that if there is no preedit cursor then the micro focus rect is the // same as it would be if it were positioned at the end of the preedit text. - ic.sendPreeditText(preeditText, 0); - ic.updateReceived = false; - ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>())); - currentRect = input->inputMethodQuery(Qt::ImCursorRectangle).toRect(); + sendPreeditText(preeditText, 0); + QInputMethodEvent imEvent(preeditText, QList<QInputMethodEvent::Attribute>()); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent); + QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &query); + currentRect = query.value(Qt::ImCursorRectangle).toRect(); QCOMPARE(currentRect, previousRect); -#if defined(Q_WS_X11) || defined(Q_WS_QWS) - QCOMPARE(ic.updateReceived, true); -#endif -#endif -} - -void tst_qquicktextinput::inputContextMouseHandler() -{ -#ifdef QTBUG_21691 - QEXPECT_FAIL("", QTBUG_21691_MESSAGE, Abort); - QVERIFY(false); -#else - QString text = "supercalifragisiticexpialidocious!"; - - QQuickView view(QUrl::fromLocalFile(TESTDATA("inputContext.qml"))); - MyInputContext ic; - // QQuickCanvas won't set the Qt::WA_InputMethodEnabled flag unless a suitable item has active focus - // and QWidget won't allow an input context to be set when the flag is not set. - view.setAttribute(Qt::WA_InputMethodEnabled, true); - view.setInputContext(&ic); - view.setAttribute(Qt::WA_InputMethodEnabled, false); - view.show(); - view.requestActivateWindow(); - QTest::qWaitForWindowShown(&view); - QTRY_COMPARE(&view, qGuiApp->focusWindow()); - QQuickTextInput *input = qobject_cast<QQuickTextInput *>(view.rootObject()); - QVERIFY(input); - - QFontMetricsF fm(input->font()); - const qreal y = fm.height() / 2; - - QPoint position2 = input->mapToScene(QPointF(fm.width(text.mid(0, 2)), y)).toPoint(); - QPoint position8 = input->mapToScene(QPointF(fm.width(text.mid(0, 8)), y)).toPoint(); - QPoint position20 = input->mapToScene(QPointF(fm.width(text.mid(0, 20)), y)).toPoint(); - QPoint position27 = input->mapToScene(QPointF(fm.width(text.mid(0, 27)), y)).toPoint(); - QPoint globalPosition2 = view.mapToGlobal(position2); - QPoint globalposition8 = view.mapToGlobal(position8); - QPoint globalposition20 = view.mapToGlobal(position20); - QPoint globalposition27 = view.mapToGlobal(position27); - - ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>())); - - QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, position2); - QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick); - QCOMPARE(ic.eventPosition, position2); - QCOMPARE(ic.eventGlobalPosition, globalPosition2); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor < 0); - ic.eventType = QEvent::None; - - QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position2); - QCOMPARE(ic.eventType, QEvent::MouseButtonPress); - QCOMPARE(ic.eventPosition, position2); - QCOMPARE(ic.eventGlobalPosition, globalPosition2); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor < 0); - ic.eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::None); - - { QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::MouseMove); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); // 15 is expected but some platforms may be off by one. - ic.eventType = QEvent::None; - - QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position27); - QCOMPARE(ic.eventType, QEvent::MouseButtonRelease); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::NoModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); - ic.eventType = QEvent::None; - - // And in the other direction. - QTest::mouseDClick(&view, Qt::LeftButton, Qt::ControlModifier, position27); - QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::LeftButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); - ic.eventType = QEvent::None; - - QTest::mousePress(&view, Qt::RightButton, Qt::ControlModifier, position27); - QCOMPARE(ic.eventType, QEvent::MouseButtonPress); - QCOMPARE(ic.eventPosition, position27); - QCOMPARE(ic.eventGlobalPosition, globalposition27); - QCOMPARE(ic.eventButton, Qt::RightButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); - ic.eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::MouseMove); - QCOMPARE(ic.eventPosition, position20); - QCOMPARE(ic.eventGlobalPosition, globalposition20); - QCOMPARE(ic.eventButton, Qt::RightButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor >= 7 && ic.cursor <= 9); - ic.eventType = QEvent::None; - - { QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); - QGuiApplication::sendEvent(&view, &mv); } - QCOMPARE(ic.eventType, QEvent::None); - - QTest::mouseRelease(&view, Qt::RightButton, Qt::ControlModifier, position2); - QCOMPARE(ic.eventType, QEvent::MouseButtonRelease); - QCOMPARE(ic.eventPosition, position2); - QCOMPARE(ic.eventGlobalPosition, globalPosition2); - QCOMPARE(ic.eventButton, Qt::RightButton); - QCOMPARE(ic.eventModifiers, Qt::ControlModifier); - QVERIFY(ic.cursor < 0); - ic.eventType = QEvent::None; -#endif + QVERIFY(inputSpy.count() > 0); + QVERIFY(panelSpy.count() > 0); } void tst_qquicktextinput::inputMethodComposing() diff --git a/tests/auto/declarative/qquickview/tst_qquickview.cpp b/tests/auto/declarative/qquickview/tst_qquickview.cpp index a2334d2e58..fc480b5fca 100644 --- a/tests/auto/declarative/qquickview/tst_qquickview.cpp +++ b/tests/auto/declarative/qquickview/tst_qquickview.cpp @@ -89,9 +89,8 @@ void tst_QQuickView::resizemodeitem() // size update from view canvas->resize(QSize(80,100)); - QTest::qWait(50); - QCOMPARE(item->width(), 80.0); + QTRY_COMPARE(item->width(), 80.0); QCOMPARE(item->height(), 100.0); QCOMPARE(canvas->size(), QSize(80, 100)); QCOMPARE(canvas->size(), canvas->sizeHint()); @@ -177,7 +176,6 @@ void tst_QQuickView::resizemodeitem() QTest::qWait(50); // initial size from root object - QEXPECT_FAIL("", "QTBUG-22019", Abort); QCOMPARE(item->width(), 300.0); QCOMPARE(item->height(), 300.0); QCOMPARE(canvas->size(), QSize(300, 300)); diff --git a/tests/auto/declarative/qquickvisualdatamodel/data/create.qml b/tests/auto/declarative/qquickvisualdatamodel/data/create.qml index 36ea3baf76..3475a0dace 100644 --- a/tests/auto/declarative/qquickvisualdatamodel/data/create.qml +++ b/tests/auto/declarative/qquickvisualdatamodel/data/create.qml @@ -7,6 +7,8 @@ ListView { model: VisualDataModel { id: visualModel + persistedItems.includeByDefault: true + model: myModel delegate: Item { id: delegate @@ -16,6 +18,7 @@ ListView { property bool destroyed: false + Component.onDestruction: destroyed = true } } diff --git a/tests/auto/declarative/qquickvisualdatamodel/data/datalist-package.qml b/tests/auto/declarative/qquickvisualdatamodel/data/datalist-package.qml new file mode 100644 index 0000000000..ae3bd81d91 --- /dev/null +++ b/tests/auto/declarative/qquickvisualdatamodel/data/datalist-package.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 + +ListView { + width: 100 + height: 100 + model: visualModel.parts.package + VisualDataModel { + id: visualModel + objectName: "visualModel" + model: myModel + delegate: Package { + Rectangle { + height: 25 + width: 100 + Package.name: "package" + Text { objectName: "display"; text: display } + } + } + } +} diff --git a/tests/auto/declarative/qquickvisualdatamodel/data/groups-invalid.qml b/tests/auto/declarative/qquickvisualdatamodel/data/groups-invalid.qml new file mode 100644 index 0000000000..70c6f9f995 --- /dev/null +++ b/tests/auto/declarative/qquickvisualdatamodel/data/groups-invalid.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +VisualDataModel { + id: visualModel + + objectName: "visualModel" + + groups: [ + VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" }, + VisualDataGroup { id: unnamed; objectName: "unnamed" }, + VisualDataGroup { id: capitalised; objectName: "capitalised"; name: "Capitalised" } + ] +} diff --git a/tests/auto/declarative/qquickvisualdatamodel/data/groups-package.qml b/tests/auto/declarative/qquickvisualdatamodel/data/groups-package.qml new file mode 100644 index 0000000000..ea5ad5d3bd --- /dev/null +++ b/tests/auto/declarative/qquickvisualdatamodel/data/groups-package.qml @@ -0,0 +1,52 @@ +import QtQuick 2.0 + +ListView { + width: 100 + height: 100 + + function contains(array, value) { + for (var i = 0; i < array.length; ++i) + if (array[i] == value) + return true + return false + } + model: visualModel.parts.package + + VisualDataModel { + id: visualModel + + objectName: "visualModel" + + groups: [ + VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + ] + + model: myModel + delegate: Package { + id: delegate + + property variant test1: name + property variant test2: index + property variant test3: VisualDataModel.itemsIndex + property variant test4: VisualDataModel.inItems + property variant test5: VisualDataModel.visibleIndex + property variant test6: VisualDataModel.inVisible + property variant test7: VisualDataModel.selectedIndex + property variant test8: VisualDataModel.inSelected + property variant test9: VisualDataModel.groups + + function hide() { VisualDataModel.inVisible = false } + function select() { VisualDataModel.inSelected = true } + + Item { + Package.name: "package" + + objectName: "delegate" + width: 100 + height: 2 + } + } + } + +} diff --git a/tests/auto/declarative/qquickvisualdatamodel/data/groups.qml b/tests/auto/declarative/qquickvisualdatamodel/data/groups.qml index a24e223bc5..7502dd2502 100644 --- a/tests/auto/declarative/qquickvisualdatamodel/data/groups.qml +++ b/tests/auto/declarative/qquickvisualdatamodel/data/groups.qml @@ -11,7 +11,12 @@ ListView { return false } - model: VisualDataModel { + model: visualModel + VisualDataModel { + id: visualModel + + objectName: "visualModel" + groups: [ VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } @@ -20,6 +25,7 @@ ListView { model: myModel delegate: Item { id: delegate + objectName: "delegate" width: 100 height: 2 diff --git a/tests/auto/declarative/qquickvisualdatamodel/data/onChanged.qml b/tests/auto/declarative/qquickvisualdatamodel/data/onChanged.qml new file mode 100644 index 0000000000..71dc7d72d7 --- /dev/null +++ b/tests/auto/declarative/qquickvisualdatamodel/data/onChanged.qml @@ -0,0 +1,87 @@ +import QtQuick 2.0 + +VisualDataModel { + id: vm + + property var inserted + property var removed + + Component.onCompleted: { + vm.inserted = [] + vm.removed = [] + vi.inserted = [] + vi.removed = [] + si.inserted = [] + si.removed = [] + } + + function verify(changes, indexes, counts, moveIds) { + if (changes.length != indexes.length + || changes.length != counts.length + || changes.length != moveIds.length) { + console.log("invalid length", changes.length, indexes.length, counts.length, moveIds.length) + return false + } + + var valid = true; + for (var i = 0; i < changes.length; ++i) { + if (changes[i].index != indexes[i]) { + console.log(i, "incorrect index. actual:", changes[i].index, "expected:", indexes[i]) + valid = false; + } + if (changes[i].count != counts[i]) { + console.log(i, "incorrect count. actual:", changes[i].count, "expected:", counts[i]) + valid = false; + } + if (changes[i].moveId != moveIds[i]) { + console.log(i, "incorrect moveId. actual:", changes[i].moveId, "expected:", moveIds[i]) + valid = false; + } + } + return valid + } + + groups: [ + VisualDataGroup { + id: vi; + + property var inserted + property var removed + + name: "visible" + includeByDefault: true + + onChanged: { + vi.inserted = inserted + vi.removed = removed + } + }, + VisualDataGroup { + id: si; + + property var inserted + property var removed + + name: "selected" + onChanged: { + si.inserted = inserted + si.removed = removed + } + } + ] + + model: ListModel { + id: listModel + ListElement { number: "one" } + ListElement { number: "two" } + ListElement { number: "three" } + ListElement { number: "four" } + } + + delegate: Item {} + + items.onChanged: { + vm.inserted = inserted + vm.removed = removed + } +} diff --git a/tests/auto/declarative/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp b/tests/auto/declarative/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp index aba760db91..706c20fa15 100644 --- a/tests/auto/declarative/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp +++ b/tests/auto/declarative/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp @@ -122,18 +122,27 @@ private slots: void initTestCase(); void cleanupTestCase(); void rootIndex(); + void updateLayout_data(); void updateLayout(); + void childChanged_data(); void childChanged(); void objectListModel(); void singleRole(); void modelProperties(); + void noDelegate_data(); void noDelegate(); void qaimRowsMoved(); void qaimRowsMoved_data(); + void remove_data(); void remove(); + void move_data(); void move(); + void groups_data(); void groups(); + void invalidGroups(); void get(); + void onChanged_data(); + void onChanged(); void create(); private: @@ -262,8 +271,18 @@ void tst_qquickvisualdatamodel::rootIndex() delete obj; } +void tst_qquickvisualdatamodel::updateLayout_data() +{ + QTest::addColumn<QUrl>("source"); + + QTest::newRow("item delegate") << QUrl::fromLocalFile(TESTDATA("datalist.qml")); + QTest::newRow("package delegate") << QUrl::fromLocalFile(TESTDATA("datalist-package.qml")); +} + void tst_qquickvisualdatamodel::updateLayout() { + QFETCH(QUrl, source); + QQuickView view; QStandardItemModel model; @@ -271,7 +290,7 @@ void tst_qquickvisualdatamodel::updateLayout() view.rootContext()->setContextProperty("myModel", &model); - view.setSource(QUrl::fromLocalFile(TESTDATA("datalist.qml"))); + view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); QVERIFY(listview != 0); @@ -302,8 +321,18 @@ void tst_qquickvisualdatamodel::updateLayout() QCOMPARE(name->text(), QString("Row 1 Item")); } +void tst_qquickvisualdatamodel::childChanged_data() +{ + QTest::addColumn<QUrl>("source"); + + QTest::newRow("item delegate") << QUrl::fromLocalFile(TESTDATA("datalist.qml")); + QTest::newRow("package delegate") << QUrl::fromLocalFile(TESTDATA("datalist-package.qml")); +} + void tst_qquickvisualdatamodel::childChanged() { + QFETCH(QUrl, source); + QQuickView view; QStandardItemModel model; @@ -311,7 +340,7 @@ void tst_qquickvisualdatamodel::childChanged() view.rootContext()->setContextProperty("myModel", &model); - view.setSource(QUrl::fromLocalFile(TESTDATA("datalist.qml"))); + view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); QVERIFY(listview != 0); @@ -567,8 +596,18 @@ void tst_qquickvisualdatamodel::modelProperties() //### should also test QStringList and QVariantList } +void tst_qquickvisualdatamodel::noDelegate_data() +{ + QTest::addColumn<QUrl>("source"); + + QTest::newRow("item delegate") << QUrl::fromLocalFile(TESTDATA("datalist.qml")); + QTest::newRow("package delegate") << QUrl::fromLocalFile(TESTDATA("datalist-package.qml")); +} + void tst_qquickvisualdatamodel::noDelegate() { + QFETCH(QUrl, source); + QQuickView view; QStandardItemModel model; @@ -576,7 +615,7 @@ void tst_qquickvisualdatamodel::noDelegate() view.rootContext()->setContextProperty("myModel", &model); - view.setSource(QUrl::fromLocalFile(TESTDATA("datalist.qml"))); + view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); QVERIFY(listview != 0); @@ -669,6 +708,19 @@ void tst_qquickvisualdatamodel::qaimRowsMoved_data() << 10 << 1 << 5; } +void tst_qquickvisualdatamodel::remove_data() +{ + QTest::addColumn<QUrl>("source"); + QTest::addColumn<QString>("package delegate"); + + QTest::newRow("item delegate") + << QUrl::fromLocalFile(TESTDATA("groups.qml")) + << QString(); + QTest::newRow("package") + << QUrl::fromLocalFile(TESTDATA("groups-package.qml")) + << QString("package."); +} + void tst_qquickvisualdatamodel::remove() { QQuickView view; @@ -766,6 +818,19 @@ void tst_qquickvisualdatamodel::remove() } } +void tst_qquickvisualdatamodel::move_data() +{ + QTest::addColumn<QUrl>("source"); + QTest::addColumn<QString>("package delegate"); + + QTest::newRow("item delegate") + << QUrl::fromLocalFile(TESTDATA("groups.qml")) + << QString(); + QTest::newRow("package") + << QUrl::fromLocalFile(TESTDATA("groups-package.qml")) + << QString("package."); +} + void tst_qquickvisualdatamodel::move() { QQuickView view; @@ -906,6 +971,18 @@ void tst_qquickvisualdatamodel::move() } } +void tst_qquickvisualdatamodel::groups_data() +{ + QTest::addColumn<QUrl>("source"); + QTest::addColumn<QString>("part"); + + QTest::newRow("item delegate") + << QUrl::fromLocalFile(TESTDATA("groups.qml")) + << QString(); + QTest::newRow("package") + << QUrl::fromLocalFile(TESTDATA("groups-package.qml")) + << QString("visualModel.parts.package."); +} template <int N> void tst_qquickvisualdatamodel::groups_verify( const SingleRoleModel &model, @@ -921,17 +998,17 @@ template <int N> void tst_qquickvisualdatamodel::groups_verify( for (int i = 0; i < N; ++i) { QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", mIndex[i]); QVERIFY(delegate); - QCOMPARE(delegate->property("test1").toString(), model.list.at(mIndex[i])); - QCOMPARE(delegate->property("test2").toInt() , mIndex[i]); - QCOMPARE(delegate->property("test3").toInt() , iIndex[i]); - QCOMPARE(delegate->property("test4").toBool(), true); - QCOMPARE(delegate->property("test5").toInt() , vIndex[i]); - QCOMPARE(delegate->property("test6").toBool(), vMember[i]); - QCOMPARE(delegate->property("test7").toInt() , sIndex[i]); - QCOMPARE(delegate->property("test8").toBool(), sMember[i]); - QCOMPARE(delegate->property("test9").toStringList().contains("items") , QBool(true)); - QCOMPARE(delegate->property("test9").toStringList().contains("visible") , QBool(vMember[i])); - QCOMPARE(delegate->property("test9").toStringList().contains("selected"), QBool(sMember[i])); + QCOMPARE(evaluate<QString>(delegate, "test1"), model.list.at(mIndex[i])); + QCOMPARE(evaluate<int>(delegate, "test2") , mIndex[i]); + QCOMPARE(evaluate<int>(delegate, "test3") , iIndex[i]); + QCOMPARE(evaluate<bool>(delegate, "test4"), true); + QCOMPARE(evaluate<int>(delegate, "test5") , vIndex[i]); + QCOMPARE(evaluate<bool>(delegate, "test6"), vMember[i]); + QCOMPARE(evaluate<int>(delegate, "test7") , sIndex[i]); + QCOMPARE(evaluate<bool>(delegate, "test8"), sMember[i]); + QCOMPARE(evaluate<QStringList>(delegate, "test9").contains("items") , QBool(true)); + QCOMPARE(evaluate<QStringList>(delegate, "test9").contains("visible") , QBool(vMember[i])); + QCOMPARE(evaluate<QStringList>(delegate, "test9").contains("selected"), QBool(sMember[i])); } failed = false; } @@ -943,6 +1020,9 @@ template <int N> void tst_qquickvisualdatamodel::groups_verify( void tst_qquickvisualdatamodel::groups() { + QFETCH(QUrl, source); + QFETCH(QString, part); + QQuickView view; SingleRoleModel model; @@ -963,7 +1043,7 @@ void tst_qquickvisualdatamodel::groups() QDeclarativeContext *ctxt = view.rootContext(); ctxt->setContextProperty("myModel", &model); - view.setSource(QUrl::fromLocalFile(TESTDATA("groups.qml"))); + view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); QVERIFY(listview != 0); @@ -971,13 +1051,13 @@ void tst_qquickvisualdatamodel::groups() QQuickItem *contentItem = listview->contentItem(); QVERIFY(contentItem != 0); - QQuickVisualDataModel *visualModel = qobject_cast<QQuickVisualDataModel *>(qvariant_cast<QObject *>(listview->model())); + QQuickVisualDataModel *visualModel = listview->findChild<QQuickVisualDataModel *>("visualModel"); QVERIFY(visualModel); - QQuickVisualDataGroup *visibleItems = visualModel->findChild<QQuickVisualDataGroup *>("visibleItems"); + QQuickVisualDataGroup *visibleItems = listview->findChild<QQuickVisualDataGroup *>("visibleItems"); QVERIFY(visibleItems); - QQuickVisualDataGroup *selectedItems = visualModel->findChild<QQuickVisualDataGroup *>("selectedItems"); + QQuickVisualDataGroup *selectedItems = listview->findChild<QQuickVisualDataGroup *>("selectedItems"); QVERIFY(selectedItems); const bool f = false; @@ -1130,23 +1210,26 @@ void tst_qquickvisualdatamodel::groups() QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); } { - evaluate<void>(visualModel, "filterOnGroup = \"visible\""); + evaluate<void>(visualModel, part + "filterOnGroup = \"visible\""); QCOMPARE(listview->count(), 9); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); + QCOMPARE(evaluate<QString>(visualModel, part + "filterOnGroup"), QString("visible")); } { - evaluate<void>(visualModel, "filterOnGroup = \"selected\""); + evaluate<void>(visualModel, part + "filterOnGroup = \"selected\""); QCOMPARE(listview->count(), 2); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); + QCOMPARE(evaluate<QString>(visualModel, part + "filterOnGroup"), QString("selected")); } { - evaluate<void>(visualModel, "filterOnGroup = \"items\""); + evaluate<void>(visualModel, part + "filterOnGroup = undefined"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); + QCOMPARE(evaluate<QString>(visualModel, part + "filterOnGroup"), QString("items")); } { QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", 5); QVERIFY(delegate); @@ -1410,6 +1493,144 @@ void tst_qquickvisualdatamodel::get() } } +void tst_qquickvisualdatamodel::invalidGroups() +{ + QUrl source = QUrl::fromLocalFile(TESTDATA("groups-invalid.qml")); + QTest::ignoreMessage(QtWarningMsg, (source.toString() + ":12:9: QML VisualDataGroup: " + QQuickVisualDataGroup::tr("Group names must start with a lower case letter")).toUtf8()); + + QDeclarativeComponent component(&engine, source); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object); + + QCOMPARE(evaluate<int>(object.data(), "groups.length"), 4); + QCOMPARE(evaluate<QString>(object.data(), "groups[0].name"), QString("items")); + QCOMPARE(evaluate<QString>(object.data(), "groups[1].name"), QString("persistedItems")); + QCOMPARE(evaluate<QString>(object.data(), "groups[2].name"), QString("visible")); + QCOMPARE(evaluate<QString>(object.data(), "groups[3].name"), QString("selected")); +} + +void tst_qquickvisualdatamodel::onChanged_data() +{ + QTest::addColumn<QString>("expression"); + QTest::addColumn<QStringList>("tests"); + + QTest::newRow("item appended") + << QString("listModel.append({\"number\": \"five\"})") + << (QStringList() + << "verify(vm.removed, [], [], [])" + << "verify(vm.inserted, [4], [1], [undefined])" + << "verify(vi.removed, [], [], [])" + << "verify(vi.inserted, [4], [1], [undefined])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + QTest::newRow("item prepended") + << QString("listModel.insert(0, {\"number\": \"five\"})") + << (QStringList() + << "verify(vm.removed, [], [], [])" + << "verify(vm.inserted, [0], [1], [undefined])" + << "verify(vi.removed, [], [], [])" + << "verify(vi.inserted, [0], [1], [undefined])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + QTest::newRow("item inserted") + << QString("listModel.insert(2, {\"number\": \"five\"})") + << (QStringList() + << "verify(vm.removed, [], [], [])" + << "verify(vm.inserted, [2], [1], [undefined])" + << "verify(vi.removed, [], [], [])" + << "verify(vi.inserted, [2], [1], [undefined])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + + QTest::newRow("item removed tail") + << QString("listModel.remove(3)") + << (QStringList() + << "verify(vm.removed, [3], [1], [undefined])" + << "verify(vm.inserted, [], [], [])" + << "verify(vi.removed, [3], [1], [undefined])" + << "verify(vi.inserted, [], [], [])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + QTest::newRow("item removed head") + << QString("listModel.remove(0)") + << (QStringList() + << "verify(vm.removed, [0], [1], [undefined])" + << "verify(vm.inserted, [], [], [])" + << "verify(vi.removed, [0], [1], [undefined])" + << "verify(vi.inserted, [], [], [])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + QTest::newRow("item removed middle") + << QString("listModel.remove(1)") + << (QStringList() + << "verify(vm.removed, [1], [1], [undefined])" + << "verify(vm.inserted, [], [], [])" + << "verify(vi.removed, [1], [1], [undefined])" + << "verify(vi.inserted, [], [], [])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + + + QTest::newRow("item moved from tail") + << QString("listModel.move(3, 0, 1)") + << (QStringList() + << "verify(vm.removed, [3], [1], [vm.inserted[0].moveId])" + << "verify(vm.inserted, [0], [1], [vm.removed[0].moveId])" + << "verify(vi.removed, [3], [1], [vi.inserted[0].moveId])" + << "verify(vi.inserted, [0], [1], [vi.removed[0].moveId])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + QTest::newRow("item moved from head") + << QString("listModel.move(0, 2, 2)") + << (QStringList() + << "verify(vm.removed, [0], [2], [vm.inserted[0].moveId])" + << "verify(vm.inserted, [2], [2], [vm.removed[0].moveId])" + << "verify(vi.removed, [0], [2], [vi.inserted[0].moveId])" + << "verify(vi.inserted, [2], [2], [vi.removed[0].moveId])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); + + QTest::newRow("groups changed") + << QString("items.setGroups(1, 2, [\"items\", \"selected\"])") + << (QStringList() + << "verify(vm.inserted, [], [], [])" + << "verify(vm.removed, [], [], [])" + << "verify(vi.removed, [1], [2], [undefined])" + << "verify(vi.inserted, [], [], [])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [0], [2], [undefined])"); + + QTest::newRow("multiple removes") + << QString("{ vi.remove(1, 1); " + "vi.removeGroups(0, 2, \"items\") }") + << (QStringList() + << "verify(vm.removed, [0, 1], [1, 1], [undefined, undefined])" + << "verify(vm.inserted, [], [], [])" + << "verify(vi.removed, [1], [1], [undefined])" + << "verify(vi.inserted, [], [], [])" + << "verify(si.removed, [], [], [])" + << "verify(si.inserted, [], [], [])"); +} + +void tst_qquickvisualdatamodel::onChanged() +{ + QFETCH(QString, expression); + QFETCH(QStringList, tests); + + QDeclarativeComponent component(&engine, QUrl::fromLocalFile(TESTDATA("onChanged.qml"))); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object); + + evaluate<void>(object.data(), expression); + + foreach (const QString &test, tests) { + bool passed = evaluate<bool>(object.data(), test); + if (!passed) + qWarning() << test; + QVERIFY(passed); + } +} + void tst_qquickvisualdatamodel::create() { QQuickView view; @@ -1455,8 +1676,20 @@ void tst_qquickvisualdatamodel::create() QQuickItem *delegate; + // persistedItems.includeByDefault is true, so all items belong to persistedItems initially. + QVERIFY(delegate = findItem<QQuickItem>(contentItem, "delegate", 1)); + QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); + + // changing include by default doesn't remove persistance. + evaluate<void>(visualModel, "persistedItems.includeByDefault = false"); + QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); + + // removing from persistedItems does. + evaluate<void>(visualModel, "persistedItems.remove(0, 20)"); + QCOMPARE(listview->count(), 20); + QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false); + // Request an item instantiated by the view. - QVERIFY(findItem<QQuickItem>(contentItem, "delegate", 1)); QVERIFY(delegate = qobject_cast<QQuickItem *>(evaluate<QObject *>(visualModel, "items.create(1)"))); QCOMPARE(delegate, findItem<QQuickItem>(contentItem, "delegate", 1)); QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); diff --git a/tests/auto/declarative/v4/data/qtbug_21883.qml b/tests/auto/declarative/v4/data/qtbug_21883.qml new file mode 100644 index 0000000000..a51f97c944 --- /dev/null +++ b/tests/auto/declarative/v4/data/qtbug_21883.qml @@ -0,0 +1,5 @@ +import Qt.v4 1.0 + +Result { + property Result dummy: Result +} diff --git a/tests/auto/declarative/v4/tst_v4.cpp b/tests/auto/declarative/v4/tst_v4.cpp index 0b6b2c24f7..20d739f4b5 100644 --- a/tests/auto/declarative/v4/tst_v4.cpp +++ b/tests/auto/declarative/v4/tst_v4.cpp @@ -77,6 +77,7 @@ private slots: void qtscript_data(); void nestedObjectAccess(); void subscriptionsInConditionalExpressions(); + void qtbug_21883(); private: QDeclarativeEngine engine; @@ -239,6 +240,19 @@ void tst_v4::subscriptionsInConditionalExpressions() delete o; } +// Crash test +void tst_v4::qtbug_21883() +{ + QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21883.qml")); + + QString warning = component.url().toString() + ":4: Unable to assign null to ResultObject*"; + QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); + + QObject *o = component.create(); + QVERIFY(o != 0); + delete o; +} + QTEST_MAIN(tst_v4) #include "tst_v4.moc" diff --git a/tests/auto/headersclean/tst_headersclean.cpp b/tests/auto/headersclean/tst_headersclean.cpp index 60bb799076..9aa7f1d693 100644 --- a/tests/auto/headersclean/tst_headersclean.cpp +++ b/tests/auto/headersclean/tst_headersclean.cpp @@ -49,6 +49,7 @@ #include <QtCore/QtCore> #include <QtTest/QtTest> +#include <QtDeclarative/QtDeclarative> class tst_HeadersClean: public QObject { diff --git a/tests/auto/particles/qquickage/tst_qquickage.cpp b/tests/auto/particles/qquickage/tst_qquickage.cpp index 73db409de3..b787a73ef7 100644 --- a/tests/auto/particles/qquickage/tst_qquickage.cpp +++ b/tests/auto/particles/qquickage/tst_qquickage.cpp @@ -68,7 +68,7 @@ void tst_qquickage::test_kill() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -84,6 +84,7 @@ void tst_qquickage::test_kill() QCOMPARE(d->endSize, 32.f); QVERIFY(d->t <= ((qreal)system->timeInt/1000.0) - 0.5f + EPSILON); } + delete view; } void tst_qquickage::test_jump() @@ -92,14 +93,14 @@ void tst_qquickage::test_jump() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused - //Allow for a small variance because jump is trying to simulate off wall time - extremelyFuzzyCompare(d->x, -100.f, 5.0f); - extremelyFuzzyCompare(d->y, -100.f, 5.0f); + //Allow for variance because jump is trying to simulate off wall time and things have emitted 'continuously' before first affect + QVERIFY(d->x <= -50.f); + QVERIFY(d->y <= -50.f); QCOMPARE(d->vx, 500.f); QCOMPARE(d->vy, 500.f); QCOMPARE(d->ax, 0.f); @@ -109,6 +110,7 @@ void tst_qquickage::test_jump() QCOMPARE(d->endSize, 32.f); QVERIFY(d->t <= ((qreal)system->timeInt/1000.0) - 0.4f + EPSILON); } + delete view; } void tst_qquickage::test_onceOff() @@ -117,7 +119,7 @@ void tst_qquickage::test_onceOff() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -133,6 +135,7 @@ void tst_qquickage::test_onceOff() QCOMPARE(d->endSize, 32.f); QVERIFY(d->t <= ((qreal)system->timeInt/1000.0) - 0.4f + EPSILON); } + delete view; } void tst_qquickage::test_sustained() @@ -142,7 +145,7 @@ void tst_qquickage::test_sustained() ensureAnimTime(600, system->m_animation); //TODO: Ensure some particles have lived to 0.4s point despite unified timer - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -158,6 +161,7 @@ void tst_qquickage::test_sustained() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyCompare(d->t, ((qreal)system->timeInt/1000.0) - 0.4f)); } + delete view; } QTEST_MAIN(tst_qquickage); diff --git a/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp b/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp index d21753e8a0..4e3fda3d03 100644 --- a/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp +++ b/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp @@ -66,7 +66,7 @@ void tst_qquickangleddirection::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -85,6 +85,7 @@ void tst_qquickangleddirection::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickangleddirection); diff --git a/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp b/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp index 052578f3a8..22c2d5efa0 100644 --- a/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp +++ b/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp @@ -65,7 +65,7 @@ void tst_qquickcumulativedirection::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -81,6 +81,7 @@ void tst_qquickcumulativedirection::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickcumulativedirection); diff --git a/tests/auto/particles/qquickcustomaffector/data/basic.qml b/tests/auto/particles/qquickcustomaffector/data/basic.qml index 7371698026..253c566c66 100644 --- a/tests/auto/particles/qquickcustomaffector/data/basic.qml +++ b/tests/auto/particles/qquickcustomaffector/data/basic.qml @@ -54,6 +54,7 @@ Rectangle { ImageParticle { source: "../../shared/star.png" + rotation: 90 } Emitter{ @@ -75,6 +76,12 @@ Rectangle { particles[i].initialAY = 100; particles[i].startSize = 100; particles[i].endSize = 100; + particles[i].autoRotate = true; + particles[i].update = true; + particles[i].red = 0; + particles[i].green = 1.0; + particles[i].blue = 0; + particles[i].alpha = 0; } } } diff --git a/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp b/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp index 77b1d09763..c33895e9ad 100644 --- a/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp +++ b/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp @@ -66,10 +66,13 @@ void tst_qquickcustomaffector::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused + //in CI the whole simulation often happens at once, so dead particles end up missing out + if (!d->stillAlive()) + continue; //parameters no longer get set once you die QCOMPARE(d->x, 100.f); QCOMPARE(d->y, 100.f); @@ -80,8 +83,14 @@ void tst_qquickcustomaffector::test_basic() QCOMPARE(d->lifeSpan, 0.5f); QCOMPARE(d->size, 100.f); QCOMPARE(d->endSize, 100.f); + QCOMPARE(d->autoRotate, 1.f); + QCOMPARE(d->color.r, (uchar)0); + QCOMPARE(d->color.g, (uchar)255); + QCOMPARE(d->color.b, (uchar)0); + QCOMPARE(d->color.a, (uchar)0); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } void tst_qquickcustomaffector::test_move() @@ -90,7 +99,7 @@ void tst_qquickcustomaffector::test_move() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -108,6 +117,7 @@ void tst_qquickcustomaffector::test_move() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickcustomaffector); diff --git a/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp b/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp index 3c73fad3f3..60977b2f49 100644 --- a/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp +++ b/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp @@ -67,7 +67,7 @@ void tst_qquickcustomparticle::test_basic() ensureAnimTime(600, system->m_animation); bool oneNonZero = false; - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -86,6 +86,7 @@ void tst_qquickcustomparticle::test_basic() if (d->r != 0.0 ) oneNonZero = true; } + delete view; QVERIFY(oneNonZero);//Zero is a valid value, but it also needs to be set to a random number } diff --git a/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp b/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp index 7f412c8521..683eb49ed7 100644 --- a/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp +++ b/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp @@ -82,7 +82,7 @@ void tst_qquickellipseextruder::test_basic() ensureAnimTime(600, system->m_animation); //Filled - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -97,6 +97,7 @@ void tst_qquickellipseextruder::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + //Just border QCOMPARE(system->groupData[1]->size(), 500); foreach (QQuickParticleData *d, system->groupData[1]->data) { @@ -113,6 +114,7 @@ void tst_qquickellipseextruder::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickellipseextruder); diff --git a/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp b/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp index aca4ea2330..bea3e18d27 100644 --- a/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp +++ b/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp @@ -67,7 +67,7 @@ void tst_qquickfriction::test_basic() ensureAnimTime(600, system->m_animation); //Default is just slowed a little - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -101,6 +101,7 @@ void tst_qquickfriction::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } void tst_qquickfriction::test_threshold() @@ -110,7 +111,7 @@ void tst_qquickfriction::test_threshold() ensureAnimTime(600, system->m_animation); //Speed capped at 50, but it might take a frame or two to get there - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1.0f) continue; //Particle data unused @@ -127,6 +128,7 @@ void tst_qquickfriction::test_threshold() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickfriction); diff --git a/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp b/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp index 5613591171..bc8cca8522 100644 --- a/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp +++ b/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp @@ -65,18 +65,21 @@ void tst_qquickgravity::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); + float mag = 707.10678f; foreach (QQuickParticleData *d, system->groupData[0]->data) { - if (d->t == -1) - continue; //Particle data unused + if (d->t == -1 || !d->stillAlive()) + continue; //Particle data unused or dead - QCOMPARE(d->ax, 707.10678f); - QCOMPARE(d->ay, 707.10678f); + float t = ((qreal)system->timeInt/1000.0) - d->t; + QVERIFY(extremelyFuzzyCompare(d->vx, t*mag, 20.0f)); + QVERIFY(extremelyFuzzyCompare(d->vy, t*mag, 20.0f)); QCOMPARE(d->lifeSpan, 0.5f); QCOMPARE(d->size, 32.f); QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickgravity); diff --git a/tests/auto/particles/qquickgroupgoal/data/basic.qml b/tests/auto/particles/qquickgroupgoal/data/basic.qml new file mode 100644 index 0000000000..4b27cd4ac9 --- /dev/null +++ b/tests/auto/particles/qquickgroupgoal/data/basic.qml @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Particles 2.0 + +Rectangle { + color: "black" + width: 320 + height: 320 + + ParticleSystem { + id: sys + objectName: "system" + anchors.fill: parent + + ImageParticle { + source: "../../shared/star.png" + } + + GroupGoal { + groups: ["notdefault"] + goalState: "" + jump: true + } + + Emitter { + //0,0 position + group: "notdefault" + size: 32 + emitRate: 1000 + lifeSpan: 500 + } + } +} diff --git a/tests/auto/particles/qquickgroupgoal/qquickgroupgoal.pro b/tests/auto/particles/qquickgroupgoal/qquickgroupgoal.pro new file mode 100644 index 0000000000..8e7d5ae021 --- /dev/null +++ b/tests/auto/particles/qquickgroupgoal/qquickgroupgoal.pro @@ -0,0 +1,11 @@ +CONFIG += testcase +TARGET = tst_qquickgroupgoal +SOURCES += tst_qquickgroupgoal.cpp +macx:CONFIG -= app_bundle + +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + +QT += core-private gui-private v8-private declarative-private opengl-private testlib + diff --git a/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp b/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp new file mode 100644 index 0000000000..92f30d903f --- /dev/null +++ b/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include "../shared/particlestestsshared.h" +#include <private/qquickparticlesystem_p.h> +#include <private/qabstractanimation_p.h> + +class tst_qquickgroupgoal : public QObject +{ + Q_OBJECT +public: + tst_qquickgroupgoal(); + +private slots: + void test_instantTransition(); +}; + +tst_qquickgroupgoal::tst_qquickgroupgoal() +{ + QUnifiedTimer::instance()->setConsistentTiming(true); +} + +void tst_qquickgroupgoal::test_instantTransition() +{ + //Note: Does not go through sprite engine + QQuickView* view = createView(QCoreApplication::applicationDirPath() + "/data/basic.qml", 600); + QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); + ensureAnimTime(600, system->m_animation); + + QVERIFY(system->groupData[0]->size() <= 500 && system->groupData[0]->size() >= 450); + foreach (QQuickParticleData *d, system->groupData[0]->data) { + if (d->t == -1) + continue; //Particle data unused + + QCOMPARE(d->x, 0.f); + QCOMPARE(d->y, 0.f); + QCOMPARE(d->vx, 0.f); + QCOMPARE(d->vy, 0.f); + QCOMPARE(d->ax, 0.f); + QCOMPARE(d->ay, 0.f); + QCOMPARE(d->lifeSpan, 0.5f); + QCOMPARE(d->size, 32.f); + QCOMPARE(d->endSize, 32.f); + QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); + } + delete view; +} + +QTEST_MAIN(tst_qquickgroupgoal); + +#include "tst_qquickgroupgoal.moc" diff --git a/tests/auto/particles/qquickimageparticle/qquickimageparticle.pro b/tests/auto/particles/qquickimageparticle/qquickimageparticle.pro index c05ecdfb09..14d28fd43d 100644 --- a/tests/auto/particles/qquickimageparticle/qquickimageparticle.pro +++ b/tests/auto/particles/qquickimageparticle/qquickimageparticle.pro @@ -8,4 +8,3 @@ testDataFiles.path = . DEPLOYMENT += testDataFiles QT += core-private gui-private v8-private declarative-private opengl-private testlib - diff --git a/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp b/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp index e56de35137..27b386dcd5 100644 --- a/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp +++ b/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp @@ -71,7 +71,7 @@ void tst_qquickimageparticle::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -105,6 +105,7 @@ void tst_qquickimageparticle::test_basic() QCOMPARE(d->frameCount, 1.0f); QCOMPARE(d->animT, -1.0f); } + delete view; } @@ -114,7 +115,7 @@ void tst_qquickimageparticle::test_colored() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -148,6 +149,7 @@ void tst_qquickimageparticle::test_colored() QCOMPARE(d->frameCount, 1.0f); QCOMPARE(d->animT, -1.0f); } + delete view; } @@ -157,7 +159,7 @@ void tst_qquickimageparticle::test_deformed() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -191,6 +193,7 @@ void tst_qquickimageparticle::test_deformed() QCOMPARE(d->frameCount, 1.0f); QCOMPARE(d->animT, -1.0f); } + delete view; } @@ -200,7 +203,7 @@ void tst_qquickimageparticle::test_tabled() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -235,6 +238,7 @@ void tst_qquickimageparticle::test_tabled() QCOMPARE(d->animT, -1.0f); //TODO: This performance level doesn't alter particleData, but goes straight to shaders. Find something to test } + delete view; } @@ -244,7 +248,7 @@ void tst_qquickimageparticle::test_sprite() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -278,6 +282,7 @@ void tst_qquickimageparticle::test_sprite() QCOMPARE(d->animWidth, 31.0f); QCOMPARE(d->animHeight, 30.0f); } + delete view; } QTEST_MAIN(tst_qquickimageparticle); diff --git a/tests/auto/particles/qquickitemparticle/qquickitemparticle.pro b/tests/auto/particles/qquickitemparticle/qquickitemparticle.pro index dc006d2ba1..8e8eadd463 100644 --- a/tests/auto/particles/qquickitemparticle/qquickitemparticle.pro +++ b/tests/auto/particles/qquickitemparticle/qquickitemparticle.pro @@ -7,5 +7,7 @@ testDataFiles.files = data testDataFiles.path = . DEPLOYMENT += testDataFiles +CONFIG += insignificant_test #temporary + QT += core-private gui-private v8-private declarative-private opengl-private testlib diff --git a/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp b/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp index 40197ec619..6cfb6c5562 100644 --- a/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp +++ b/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp @@ -66,7 +66,7 @@ void tst_qquickitemparticle::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -88,6 +88,7 @@ void tst_qquickitemparticle::test_basic() QVERIFY(d->delegate); QVERIFY(qobject_cast<QQuickImage*>(d->delegate)); } + delete view; } QTEST_MAIN(tst_qquickitemparticle); diff --git a/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp b/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp index ff45a9e92c..69d87acf44 100644 --- a/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp +++ b/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp @@ -65,7 +65,7 @@ void tst_qquicklineextruder::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -96,6 +96,7 @@ void tst_qquicklineextruder::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquicklineextruder); diff --git a/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp b/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp index b2a178fa1c..c13a776586 100644 --- a/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp +++ b/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp @@ -65,7 +65,7 @@ void tst_qquickmaskextruder::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -81,6 +81,7 @@ void tst_qquickmaskextruder::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickmaskextruder); diff --git a/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp b/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp index c3b155aa68..2548d879d0 100644 --- a/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp +++ b/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp @@ -82,6 +82,7 @@ void tst_qquickparticlegroup::test_instantTransition() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickparticlegroup); diff --git a/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp b/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp index b85c57da0b..f9bb971a82 100644 --- a/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp +++ b/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp @@ -65,7 +65,7 @@ void tst_qquickparticlesystem::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); int stillAlive = 0; foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) @@ -84,6 +84,7 @@ void tst_qquickparticlesystem::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; QVERIFY(extremelyFuzzyCompare(stillAlive, 500, 5));//Small simulation variance is permissible. } diff --git a/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp b/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp index 6a64f919c0..e6b1b6e1c8 100644 --- a/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp +++ b/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp @@ -65,7 +65,7 @@ void tst_qquickpointattractor::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -82,6 +82,7 @@ void tst_qquickpointattractor::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickpointattractor); diff --git a/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp b/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp index 19cc471126..b554ba7226 100644 --- a/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp +++ b/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp @@ -65,7 +65,7 @@ void tst_qquickpointdirection::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -83,6 +83,7 @@ void tst_qquickpointdirection::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickpointdirection); diff --git a/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp b/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp index 6fb2e9cae8..d8c17efdaf 100644 --- a/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp +++ b/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp @@ -65,7 +65,7 @@ void tst_qquickrectangleextruder::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -106,6 +106,7 @@ void tst_qquickrectangleextruder::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickrectangleextruder); diff --git a/tests/auto/particles/qquickspritegoal/data/basic.qml b/tests/auto/particles/qquickspritegoal/data/basic.qml new file mode 100644 index 0000000000..4c172ef28d --- /dev/null +++ b/tests/auto/particles/qquickspritegoal/data/basic.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Particles 2.0 + +Rectangle { + color: "black" + width: 320 + height: 320 + + ParticleSystem { + id: sys + objectName: "system" + anchors.fill: parent + + ImageParticle { + sprites: [Sprite { + name: "happy" + source: "../../shared/squarefacesprite.png" + frames: 6 + duration: 120 + }, Sprite { + name: "twoHappy" + source: "../../shared/squarefacesprite.png" + frames: 3 + duration: 240 + }] + } + + SpriteGoal { + goalState: "twoHappy" + jump: true + } + + Emitter { + //0,0 position + size: 32 + emitRate: 1000 + lifeSpan: 500 + } + } +} diff --git a/tests/auto/particles/qquickspritegoal/qquickspritegoal.pro b/tests/auto/particles/qquickspritegoal/qquickspritegoal.pro new file mode 100644 index 0000000000..d335a91537 --- /dev/null +++ b/tests/auto/particles/qquickspritegoal/qquickspritegoal.pro @@ -0,0 +1,11 @@ +CONFIG += testcase +TARGET = tst_qquickspritegoal +SOURCES += tst_qquickspritegoal.cpp +macx:CONFIG -= app_bundle + +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + +QT += core-private gui-private v8-private declarative-private opengl-private testlib + diff --git a/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp b/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp new file mode 100644 index 0000000000..9bb19d207a --- /dev/null +++ b/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include "../shared/particlestestsshared.h" +#include <private/qquickparticlesystem_p.h> +#include <private/qabstractanimation_p.h> + +class tst_qquickspritegoal : public QObject +{ + Q_OBJECT +public: + tst_qquickspritegoal(); + +private slots: + void test_instantTransition(); +}; + +tst_qquickspritegoal::tst_qquickspritegoal() +{ + QUnifiedTimer::instance()->setConsistentTiming(true); +} + +void tst_qquickspritegoal::test_instantTransition() +{ + QQuickView* view = createView(QCoreApplication::applicationDirPath() + "/data/basic.qml", 600); + QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); + ensureAnimTime(600, system->m_animation); + + QVERIFY(system->groupData[0]->size() <= 500 && system->groupData[0]->size() >= 450); + foreach (QQuickParticleData *d, system->groupData[0]->data) { + if (d->t == -1) + continue; //Particle data unused + + QCOMPARE(d->animIdx, 1.f);//Spawns at 0, affector moves it. + QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); + } + delete view; +} + +QTEST_MAIN(tst_qquickspritegoal); + +#include "tst_qquickspritegoal.moc" diff --git a/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp b/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp index 7d83ae8830..789334e175 100644 --- a/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp +++ b/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp @@ -65,7 +65,7 @@ void tst_qquicktargetdirection::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -81,6 +81,7 @@ void tst_qquicktargetdirection::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquicktargetdirection); diff --git a/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp b/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp index 6325ca6efe..89463b6362 100644 --- a/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp +++ b/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp @@ -65,7 +65,7 @@ void tst_qquicktrailemitter::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -98,6 +98,7 @@ void tst_qquicktrailemitter::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquicktrailemitter); diff --git a/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp b/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp index 29faec2381..9f4d50c45e 100644 --- a/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp +++ b/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp @@ -67,7 +67,7 @@ void tst_qquickturbulence::test_basic() //Note that the noise image built-in provides the 'randomness', so this test should be stable so long as it and the size //of the Turbulence item remain the same - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); foreach (QQuickParticleData *d, system->groupData[0]->data) { if (d->t == -1) continue; //Particle data unused @@ -79,6 +79,7 @@ void tst_qquickturbulence::test_basic() QCOMPARE(d->endSize, 32.f); QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0))); } + delete view; } QTEST_MAIN(tst_qquickturbulence); diff --git a/tests/auto/particles/qquickwander/tst_qquickwander.cpp b/tests/auto/particles/qquickwander/tst_qquickwander.cpp index 41f09d4993..ac88b582c4 100644 --- a/tests/auto/particles/qquickwander/tst_qquickwander.cpp +++ b/tests/auto/particles/qquickwander/tst_qquickwander.cpp @@ -65,7 +65,7 @@ void tst_qquickwander::test_basic() QQuickParticleSystem* system = view->rootObject()->findChild<QQuickParticleSystem*>("system"); ensureAnimTime(600, system->m_animation); - QCOMPARE(system->groupData[0]->size(), 500); + QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); //Since Wander is random perturbations, the compromise between stability and actual testing is to hope that one of //the 500 was randomly changed from 0.0 in velocity bool vxChanged = false; @@ -85,6 +85,7 @@ void tst_qquickwander::test_basic() if (d->vy != 0.0f) vyChanged = true; } + delete view; QVERIFY(vxChanged); QVERIFY(vyChanged); } diff --git a/tests/auto/qtquick1/examples/examples.pro b/tests/auto/qtquick1/examples/examples.pro index ca4ad04e47..3086ea1413 100644 --- a/tests/auto/qtquick1/examples/examples.pro +++ b/tests/auto/qtquick1/examples/examples.pro @@ -11,4 +11,4 @@ CONFIG += parallel_test QT += core-private gui-private widgets-private declarative-private qtquick1-private testlib -qpa:CONFIG+=insignificant_test # QTBUG-20990, aborts +CONFIG+=insignificant_test # QTBUG-20990, aborts diff --git a/tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro b/tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro index 3b0fd671e1..eefb4d5902 100644 --- a/tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro +++ b/tests/auto/qtquick1/qdeclarativeflipable/qdeclarativeflipable.pro @@ -9,4 +9,4 @@ DEFINES += SRCDIR=\\\"$$PWD\\\" CONFIG += parallel_test QT += core-private gui-private widgets-private v8-private declarative-private qtquick1-private testlib -qpa:contains(QT_CONFIG,xcb):CONFIG+=insignificant_test # QTBUG-21012 fails on exit (X11-specific) +contains(QT_CONFIG,xcb):CONFIG+=insignificant_test # QTBUG-21012 fails on exit (X11-specific) diff --git a/tests/auto/qtquick1/qdeclarativefocusscope/qdeclarativefocusscope.pro b/tests/auto/qtquick1/qdeclarativefocusscope/qdeclarativefocusscope.pro index a42997dc08..67bd8ae6d4 100644 --- a/tests/auto/qtquick1/qdeclarativefocusscope/qdeclarativefocusscope.pro +++ b/tests/auto/qtquick1/qdeclarativefocusscope/qdeclarativefocusscope.pro @@ -6,4 +6,4 @@ macx:CONFIG -= app_bundle DEFINES += SRCDIR=\\\"$$PWD\\\" QT += core-private gui-private widgets-private declarative-private qtquick1-private testlib -qpa:CONFIG+=insignificant_test # QTBUG-21013 unstable +CONFIG+=insignificant_test # QTBUG-21013 unstable diff --git a/tests/auto/qtquick1/qdeclarativeitem/qdeclarativeitem.pro b/tests/auto/qtquick1/qdeclarativeitem/qdeclarativeitem.pro index 31a71a5ab8..8663c69ea4 100644 --- a/tests/auto/qtquick1/qdeclarativeitem/qdeclarativeitem.pro +++ b/tests/auto/qtquick1/qdeclarativeitem/qdeclarativeitem.pro @@ -9,4 +9,4 @@ DEFINES += SRCDIR=\\\"$$PWD\\\" CONFIG += parallel_test QT += core-private gui-private widgets-private v8-private declarative-private qtquick1-private testlib -qpa:contains(QT_CONFIG,xcb):CONFIG+=insignificant_test # QTBUG-21012 fails on exit (X11-specific) +contains(QT_CONFIG,xcb):CONFIG+=insignificant_test # QTBUG-21012 fails on exit (X11-specific) diff --git a/tests/auto/qtquick1/qdeclarativestates/data/signalOverrideCrash3.qml b/tests/auto/qtquick1/qdeclarativestates/data/signalOverrideCrash3.qml new file mode 100644 index 0000000000..ed1f22f39a --- /dev/null +++ b/tests/auto/qtquick1/qdeclarativestates/data/signalOverrideCrash3.qml @@ -0,0 +1,27 @@ +import QtQuick 1.0 + +Rectangle { + id: myRect + width: 400 + height: 400 + + onHeightChanged: console.log("base state") + + states: [ + State { + name: "state1" + PropertyChanges { + target: myRect + onHeightChanged: console.log("state1") + color: "green" + } + }, + State { + name: "state2"; + PropertyChanges { + target: myRect + onHeightChanged: console.log("state2") + color: "red" + } + }] +} diff --git a/tests/auto/qtquick1/qdeclarativestates/tst_qdeclarativestates.cpp b/tests/auto/qtquick1/qdeclarativestates/tst_qdeclarativestates.cpp index 809d9ca65c..ba4177e7ff 100644 --- a/tests/auto/qtquick1/qdeclarativestates/tst_qdeclarativestates.cpp +++ b/tests/auto/qtquick1/qdeclarativestates/tst_qdeclarativestates.cpp @@ -108,6 +108,7 @@ private slots: void signalOverride(); void signalOverrideCrash(); void signalOverrideCrash2(); + void signalOverrideCrash3(); void parentChange(); void parentChangeErrors(); void anchorChanges(); @@ -515,6 +516,22 @@ void tst_qdeclarativestates::signalOverrideCrash2() delete rect; } +void tst_qdeclarativestates::signalOverrideCrash3() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/signalOverrideCrash3.qml"); + QDeclarative1Rectangle *rect = qobject_cast<QDeclarative1Rectangle*>(rectComponent.create()); + QVERIFY(rect != 0); + + QDeclarativeItemPrivate::get(rect)->setState("state1"); + QDeclarativeItemPrivate::get(rect)->setState(""); + QDeclarativeItemPrivate::get(rect)->setState("state2"); + QDeclarativeItemPrivate::get(rect)->setState(""); + + delete rect; +} + void tst_qdeclarativestates::parentChange() { QDeclarativeEngine engine; diff --git a/tests/auto/qtquick1/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/qtquick1/qdeclarativetextedit/tst_qdeclarativetextedit.cpp index 58027bf760..f6af1297bb 100644 --- a/tests/auto/qtquick1/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/qtquick1/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -1630,10 +1630,8 @@ void tst_qdeclarativetextedit::positionAt() int pos = texteditObject->positionAt(texteditObject->width()/2, y0); int diff = abs(int(fm.width(texteditObject->text().left(pos))-texteditObject->width()/2)); -#ifdef Q_WS_QPA QEXPECT_FAIL("", "QTBUG-21016 fails", Continue); -#endif - // some tollerance for different fonts. + // some tolerance for different fonts. #ifdef Q_OS_LINUX QVERIFY(diff < 2); #else diff --git a/tests/system/sys_elements.qtt b/tests/system/sys_elements.qtt index 296dd83cb8..2ffb83a91a 100644 --- a/tests/system/sys_elements.qtt +++ b/tests/system/sys_elements.qtt @@ -44,79 +44,75 @@ testcase = { pre_existing_elements_data: { - // ElementName: [preconditions,[groups]] - Rectangle: ["",["QtQuick1.0","BAT"]], - Image: ["",["QtQuick1.0","BAT"]], - AnimatedImage: ["",["QtQuick1.0","BAT"]], - BorderImage: ["",["QtQuick1.0","BAT"]], - SystemPalette: ["",["QtQuick1.0","BAT"]], - Text: ["",["QtQuick1.0","BAT"]], - TextInput: ["",["QtQuick1.0","BAT"]], - TextEdit: ["",["QtQuick1.0","BAT"]], - FontLoader: ["",["QtQuick1.0","BAT"]], - Flipable: ["",["QtQuick1.0","BAT"]], - Flickable: ["",["QtQuick1.0","BAT"]], - IntValidator: ["",["QtQuick1.0","BAT"]], - DoubleValidator: ["",["QtQuick1.0","BAT"]], - RegExpValidator: ["",["QtQuick1.0","BAT"]], - Column: ["",["QtQuick1.0","BAT"]], - Row: ["",["QtQuick1.0","BAT"]], - Flow: ["",["QtQuick1.0","BAT"]], - Grid: ["",["QtQuick1.0","BAT"]], - Repeater: ["",["QtQuick1.0","BAT"]], - ListView: ["",["QtQuick1.0","BAT"]], - Keys: ["",["QtQuick1.0","BAT"]], - MouseArea: ["",["QtQuick1.0","BAT"]], - SequentialAnimation: ["",["QtQuick1.0","BAT"]], - ParallelAnimation: ["",["QtQuick1.0","BAT"]], - XmlListModel: ["",["QtQuick1.0","BAT"]], - Scale: ["",["QtQuick1.0","BAT"]] + Rectangle: ["Rectangle"], + Image: ["Image"], + AnimatedImage: ["AnimatedImage"], + BorderImage: ["BorderImage"], + SystemPalette: ["SystemPalette"], + Text: ["Text"], + TextInput: ["TextInput"], + TextEdit: ["TextEdit"], + FontLoader: ["FontLoader"], + Flipable: ["Flipable"], + Flickable: ["Flickable"], + IntValidator: ["IntValidator"], + DoubleValidator: ["DoubleValidator"], + RegExpValidator: ["RegExpValidator"], + Column: ["Column"], + Row: ["Row"], + Flow: ["Flow"], + Grid: ["Grid"], + Repeater: ["Repeater"], + ListView: ["ListView"], + Keys: ["Keys"], + MouseArea: ["MouseArea"], + SequentialAnimation: ["SequentialAnimation"], + ParallelAnimation: ["ParallelAnimation"], + XmlListModel: ["XmlListModel"], + Scale: ["Scale"] }, - pre_existing_elements: function(prec,groups) { + pre_existing_elements: function(name) { // Test Meta-data - testTitle = currentDataTag()+ " Element"; + testTitle = name+ " Element"; testBinary = "qmlscene tests/testapplications/elements/elements.qml"; - testGoal = "Verify the "+currentDataTag()+" element is shown correctly"; - testPreconditions = prec; - testGroups = groups; + testGoal = "Verify the "+name+" element is shown correctly"; + testPreconditions = "None"; + testGroups = "BAT"; // Test Steps prompt(twiki('---+++ ' + testTitle + '<br><br> *Goal:* ' + testGoal + '<br> *Pre-Requisites:* ' + testPreconditions + '<br> *Tested Binary:* ' + testBinary + '<br> - | Select the '+currentDataTag()+' list item | Verify that the '+currentDataTag()+' application is displayed | + | Select the '+name+' list item | Verify that the '+name+' application is displayed | | Follow the instructions in the in-app test | Verify all steps are completed successfully |')); }, new_elements_data: { - // ElementName: [preconditions,[groups]] - ParticleSystem: ["",["QtQuick2.0","BAT"]], - ImageParticle: ["",["QtQuick2.0","BAT"]], - Emitter: ["",["QtQuick2.0","BAT"]], - Affector: ["",["QtQuick2.0","BAT"]], - Shape: ["",["QtQuick2.0","BAT"]], - TrailEmitter: ["",["QtQuick2.0","BAT"]], - Direction: ["",["QtQuick2.0","BAT"]] + ParticleSystem: ["ParticleSystem"], + ImageParticle: ["ImageParticle"], + Emitter: ["Emitter"], + Affector: ["Affector"], + Shape: ["Shape",], + TrailEmitter: ["TrailEmitter"], + Direction: ["Direction"] }, - new_elements: function(prec,groups) { + new_elements: function(name) { // Test Meta-data - testTitle = currentDataTag()+ " Element"; + testTitle = name+ " Element"; testBinary = "qmlscene tests/testapplications/elements/elements.qml"; - testGoal = "Verify the "+currentDataTag()+" element is shown correctly"; - testPreconditions = prec; - testGroups = groups; + testGoal = "Verify the "+name+" element is shown correctly"; + testPreconditions = "None"; + testGroups = "BAT"; // Test Steps prompt(twiki('---+++ ' + testTitle + '<br><br> *Goal:* ' + testGoal + '<br> *Pre-Requisites:* ' + testPreconditions + '<br> *Tested Binary:* ' + testBinary + '<br> - | Select the '+currentDataTag()+' list item | Verify that the '+currentDataTag()+' application is displayed | + | Select the '+name+' list item | Verify that the '+name+' application is displayed | | Follow the instructions in the in-app test | Verify all steps are completed successfully |')); } } - - diff --git a/tests/system/sys_text.qtt b/tests/system/sys_text.qtt new file mode 100644 index 0000000000..0b31688089 --- /dev/null +++ b/tests/system/sys_text.qtt @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//TESTED_COMPONENT=qtdeclarative + +testcase = { + + text_formatting_data: { + // Text type, autotext, plain text, rich text, styled text + BasicText: ["Basic","plain, unformatted red text","plain, unformatted red text","plain, unformatted red text","plain, unformatted red text"], + Rich: ["Rich","bold style","surrounding b,/b tags and no formatting","bold style","bold style"] + }, + + text_formatting: function(texttype,autoformat,plainformat,richformat,styledformat) { + // Test Meta-data + testTitle = "Text Formats"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify that text shows correctly when displayed in different formats"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run ' + testBinary + ' | Verify that the Text application is displayed | + | Select Text: '+texttype+', Format: AutoText controls | A single line of text is shown | + | | Qt Quick should be rendered with '+autoformat+' | + | Select the Wrap: Word option | A block of text is shown | + | Select the Format: PlainText option | Qt Quick should be shown with '+plainformat+' | + | Select the Format: RichText option | Qt Quick should be shown with '+richformat+' | + | Select the Format: StyledText option | Qt Quick should be shown with '+styledformat+' |')); + }, + + text_wrapping_data: { + // Text type, No wrap, word wrap, wrap anywhere, auto wrap + Basic: ["Basic", + "two lines, wrapped at the newline (Qt Quick consists...)", + "many lines, with no broken words", + "many lines, words broken at the text boundary", + "many lines, with no broken words"], + Long: ["Long", + "one lone line", + "two lines, wrapped at the - (topboxesand...),", + "many lines, wrapped at the boundary", + "many lines, wrapped at the boundary, and specifically the - in set-top"], + Rich: ["Rich", + "two lines, wrapped at the break (Qt Quick consists...)", + "many lines, with no broken words", + "many lines, words broken at the text boundary", + "many lines, with no broken words"] + }, + + text_wrapping: function(texttype,noWrap,wordWrap,anywhereWrap,autoWrap) { + // Test Meta-data + testTitle = "Wrap Modes"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify that text wraps correctly with different wrap methods and text formats"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run ' + testBinary + ' | Verify that the Text application is displayed | + | Select Text: '+texttype+', Format: AutoText controls | Verify '+noWrap+' is displayed | + | Select the Wrap: Word option | Verify '+wordWrap+' is displayed | + | Select the Wrap: Anywhere option | Verify '+anywhereWrap+' is displayed | + | Select the Wrap: Auto option | Verify '+autoWrap+' is displayed |')); + }, + + text_styling_data: { + // Text type + Basic: ["Basic"], + Long: ["Long"], + Rich: ["Rich"] + }, + + text_styling: function(texttype) { + // Test Meta-data + testTitle = "Style Effects"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify that styling (underline, strikeout etc) works as intended"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run ' + testBinary + ' | Verify that the Text application is displayed | + | Select Text: '+texttype+', Wrap: WordWrap | Verify the text is displayed, wrapped if necessary | + | Select the U_Line: On option | Verify an underline is drawn under each character | + | Select the Strike: On option | Verify a strikethrough is drawn through each character | + | Select the Style: Outline option | Verify each character is red and has a green outline around it | + | Select the SColor: Blue option | Verify each character is red and has a blue outline around it | + | Select the Style: Raised option | Verify each character is red and has a blue shadow behind and below it | + | Select the Style: Sunken option | Verify each character is red and has a blue shadow behind and above it |')); + } +}
\ No newline at end of file diff --git a/tests/system/sys_textedit.qtt b/tests/system/sys_textedit.qtt new file mode 100644 index 0000000000..632da21a8f --- /dev/null +++ b/tests/system/sys_textedit.qtt @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//TESTED_COMPONENT=qtdeclarative + +testcase = { + + text_formatting_data: { + // Text type, autotext, plain text, rich text, styled text + BasicText: ["Basic","plain, unformatted red text","plain, unformatted red text","plain, unformatted red text","plain, unformatted red text"], + Rich: ["Rich","bold style","surrounding b,/b tags and no formatting","bold style","bold style"] + }, + + text_formatting: function(texttype,autoformat,plainformat,richformat,styledformat) { + // Test Meta-data + testTitle = "Text Formats"; + testBinary = "qmlscene tests/testapplications/text/textedit.qml"; + testGoal = "Verify that text shows correctly when displayed in different formats"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run ' + testBinary + ' | Verify that the Text application is displayed | + | Select Text: '+texttype+', Format: AutoText controls | A single line of text is shown | + | | Qt Quick should be rendered with '+autoformat+' | + | Select the Wrap: Word option | A block of text is shown | + | Select the Format: PlainText option | Qt Quick should be shown with '+plainformat+' | + | Select the Format: RichText option | Qt Quick should be shown with '+richformat+' | + | Select the Format: StyledText option | Qt Quick should be shown with '+styledformat+' |')); + }, + + text_wrapping_data: { + // Text type, No wrap, word wrap, wrap anywhere, auto wrap + Basic: ["Basic", + "two lines, wrapped at the newline (Qt Quick consists...)", + "many lines, with no broken words", + "many lines, words broken at the text boundary", + "many lines, with no broken words"], + Long: ["Long", + "one lone line", + "two lines, wrapped at the - (topboxesand...),", + "many lines, wrapped at the boundary", + "many lines, wrapped at the boundary, and specifically the - in set-top"], + Rich: ["Rich", + "two lines, wrapped at the break (Qt Quick consists...)", + "many lines, with no broken words", + "many lines, words broken at the text boundary", + "many lines, with no broken words"] + }, + + text_wrapping: function(texttype,noWrap,wordWrap,anywhereWrap,autoWrap) { + // Test Meta-data + testTitle = "Wrap Modes"; + testBinary = "qmlscene tests/testapplications/text/textedit.qml"; + testGoal = "Verify that text wraps correctly with different wrap methods and text formats"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run ' + testBinary + ' | Verify that the Text application is displayed | + | Select Text: '+texttype+', Format: AutoText controls | Verify '+noWrap+' is displayed | + | Select the Wrap: Word option | Verify '+wordWrap+' is displayed | + | Select the Wrap: Anywhere option | Verify '+anywhereWrap+' is displayed | + | Select the Wrap: Auto option | Verify '+autoWrap+' is displayed |')); + }, + + text_styling_data: { + // Text type + Basic: ["Basic"], + Long: ["Long"], + Rich: ["Rich"] + }, + + text_styling: function(texttype) { + // Test Meta-data + testTitle = "Style Effects"; + testBinary = "qmlscene tests/testapplications/text/textedit.qml"; + testGoal = "Verify that styling (underline, strikeout etc) works as intended"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + | *Step* | *Verification* | + | Run ' + testBinary + ' | Verify that the Text application is displayed | + | Select Text: '+texttype+', Wrap: WordWrap | Verify the text is displayed, wrapped if necessary | + | Select the U_Line: On option | Verify an underline is drawn under each character | + | Select the Strike: On option | Verify a strikethrough is drawn through each character |')); + }, + + select_text: function() + { + // Test meta data + testTitle = "Text Selection"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify text can be selected via various methods"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Short option | "Hello World" is shown | + | Press the Select Word button | World is selected | + | Press the Select All button | Hello World is selected | + | Press the Select None button | No text is selected | + | Select the Mouse: On option | | + | Drag over some text | Only that text is selected. On a touchscreen only device the virtual keyboard may show | + | Select the Mouse: Off option | | + | Press the Select None button | No text is selected | + | Drag over some text | No text is selected. On a touchscreen only device the virtual keyboard may show | ')); + }, + + cut_copy_and_paste: function() + { + // Test meta data + testTitle = "Cut, copy and paste"; + testBinary = "qmlscene tests/testapplications/text/textedit.qml"; + testGoal = "Verify selected text can be copied/cut to the clipboard, and returned"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Short option | "Hello World" is shown | + | Press the Select All button | Hello World is selected | + | Press the Copy Button | | + | Tap at the end of the text | Text is no longer selected, cursor is at the text end | + | Press the Paste Button | "Hello WorldHello World" is shown | + | Press the Select Word button | World is highlighted | + | Press the Cut button | World is removed from the text | + | Press the Paste button | "Hello WorldHello World" is shown | ')); + }, + + activate_links: function() + { + // Test meta data + testTitle = "Link Activation"; + testBinary = "qmlscene tests/testapplications/text/textedit.qml"; + testGoal = "Verify http links in text can be activated"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Links option | "This is a link..." is shown | + | Tap on the "Qt Docs" text | The border around the TextEdit will become red | ')); + } + +} diff --git a/tests/system/sys_textinput.qtt b/tests/system/sys_textinput.qtt new file mode 100644 index 0000000000..5533864c87 --- /dev/null +++ b/tests/system/sys_textinput.qtt @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//TESTED_COMPONENT=qtdeclarative + +testcase = { + + select_text: function() + { + // Test meta data + testTitle = "Text Selection"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify text can be selected via various methods"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Short option | "Hello World" is shown | + | Press the Select Word button | World is selected | + | Press the Select All button | Hello World is selected | + | Press the Select None button | No text is selected | + | Select the Mouse: On option | | + | Drag over some text | Only that text is selected. On a touchscreen only device the virtual keyboard may show | + | Select the Mouse: Off option | | + | Press the Select None button | No text is selected | + | Drag over some text | No text is selected. On a touchscreen only device the virtual keyboard may show |')); + }, + + cut_copy_and_paste: function() + { + // Test meta data + testTitle = "Cut, copy and paste"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify selected text can be copied/cut to the clipboard, and returned"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Short option | "Hello World" is shown | + | Press the Select All button | Hello World is selected | + | Press the Copy Button | | + | Press the Position End Button | Text is no longer selected, cursor is at the text end | + | Press the Paste Button | "Hello WorldHello World" is shown | + | Press the Select Word button | World is highlighted | + | Press the Cut button | World is removed from the text | + | Press the Paste button | "Hello WorldHello World" is shown |')); + }, + + password_echo_mode: function() + { + // Test meta data + testTitle = "Password Echo"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify password echo modes display text correctly"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Short option | "Hello World" is shown | + | Select the Echo: Password option | Hello World is now a string of asterisks | + | Enter an exclamation mark | An asterisk is added to the string | + | Select the Echo: None option | No text is visible | + | Enter an exclamation mark | No text is shown | + | Select the Echo: OnEdit option | A string of asterisks is shown | + | Enter an exclamation mark | An exclamation mark appears at the end of the asterisks, but shortly becomes an asterisk | + | Select the Echo: Normal option | Hello World!!! is now displayed |')); + }, + + styling: function() + { + // Test meta data + testTitle = "Text Styling"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify text can be displayed using generic styling"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Text: Short option | "Hello World" is shown | + | Select the Bold: On option | Hello World is now in bold | + | Press the Italics: On option | Hello World is now in italics | + | Press the Strikeout: On option | Hello World now has a line passing through it | + | Press the Underline: On option | Hello World is now underlined | ')); + }, + + cursor_behavior: function() + { + // Test meta data + testTitle = "Cursor Behavior"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify the text cursor displays correctly"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Enter enough text into the field such that it passes beyond the far right | The text scrolls to the left when the edge is reached | + | Select the Autoscroll: Off button | The far left edge shows the first character of the text | + | Select the Cursor: Off option | The cursor disappears | + | Select the Cursor: On option | The cursor appears | ')); + }, + + capitalization: function() + { + // Test meta data + testTitle = "Capitalization"; + testBinary = "qmlscene tests/testapplications/text/text.qml"; + testGoal = "Verify character capitalization behaves correctly"; + testPreconditions = "None"; + testGroups = "BAT"; + + // Test Steps + prompt(twiki('---+++ ' + testTitle + '<br><br> + *Goal:* ' + testGoal + '<br> + *Pre-Requisites:* ' + testPreconditions + '<br> + *Tested Binary:* ' + testBinary + '<br> + + | *Step* | *Verification* | + | Execute '+testBinary+' | "The TextInput item displays an editable line of text." is displayed | + | Select the Cap10n: Upper option | The text is converted to all upper case | + | Select the Cap10n: Lower option | The text is converted to all lower case | + | Select the Cap10n: SmallCaps option | The text is converted to all small sized upper case characters | + | Select the Cap10n: Capitals option | The text is shown with each first character of every word capitalized | ')); + } +}
\ No newline at end of file diff --git a/tests/testapplications/elements/content/GridViewElement.qml b/tests/testapplications/elements/content/GridViewElement.qml index 2b9884d4a9..79b48d55c3 100644 --- a/tests/testapplications/elements/content/GridViewElement.qml +++ b/tests/testapplications/elements/content/GridViewElement.qml @@ -123,5 +123,6 @@ Rectangle { ListElement { label: "Shape"; help: "The Shape element allows you to specify an area for affectors and emitter." } ListElement { label: "TrailEmitter"; help: "The TrailEmitter element allows you to emit logical particles from other logical particles." } ListElement { label: "Direction"; help: "The Direction elements allow you to specify a vector space." } + ListElement { label: "SpriteImage"; help: "The SpriteImage element plays stochastic sprite animations." } } } diff --git a/tests/testapplications/elements/content/SpriteImageElement.qml b/tests/testapplications/elements/content/SpriteImageElement.qml new file mode 100644 index 0000000000..2015eabe8a --- /dev/null +++ b/tests/testapplications/elements/content/SpriteImageElement.qml @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + id: spriteimageelementtest + anchors.fill: parent + property string testtext: "" + SpriteImage { + id: spriteimage + sprites: [Sprite { + name: "happy" + source: "pics/squarefacesprite2.png" + frames: 6 + duration: 120 + to: {"silly": 1, "sad":0} + }, Sprite { + name: "silly" + source: "pics/squarefacesprite.png" + frames: 6 + duration: 120 + to: {"happy": 1, "sad": 0} + }, Sprite { + name: "sad" + source: "pics/squarefacesprite3.png" + frames: 6 + duration: 120 + to: {"evil": 0.5, "sad": 1, "cyclops" : 0} + }, Sprite { + name: "cyclops" + source: "pics/squarefacesprite4.png" + frames: 6 + duration: 120 + to: {"love": 0.1, "boggled": 0.1, "cyclops" : 0.1} + }, Sprite { + name: "evil" + source: "pics/squarefacesprite5.png" + frames: 6 + duration: 120 + to: {"sad": 1.0, "cyclops" : 0} + }, Sprite { + name: "love" + source: "pics/squarefacesprite6.png" + frames: 6 + duration: 120 + to: {"love": 0.1, "boggled": 0.1, "cyclops" : 0.1} + }, Sprite { + name: "boggled" + source: "pics/squarefacesprite7.png" + frames: 6 + duration: 120 + to: {"love": 0.1, "boggled": 0.1, "cyclops" : 0.1, "dying":0} + }, Sprite { + name: "dying" + source: "pics/squarefacespriteX.png" + frames: 4 + duration: 120 + to: {"dead":1.0} + }, Sprite { + name: "dead" + source: "pics/squarefacespriteXX.png" + frames: 1 + duration: 10000 + }] + + width: 300 + height: 300 + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + } + + + SystemTestHelp { id: helpbubble; visible: statenum != 0 + anchors { top: parent.top; horizontalCenter: parent.horizontalCenter; topMargin: 50 } + } + BugPanel { id: bugpanel } + + states: [ + State { name: "start"; when: statenum == 1 + StateChangeScript { script: spriteimage.jumpTo("happy"); } + PropertyChanges { target: spriteimageelementtest + testtext: "This is a SpriteImage element. It should be animating currently."+ + "It should alternate between winking and sticking out its tongue." } + }, + State { name: "stochastic2"; when: statenum == 2 + StateChangeScript { script: spriteimage.jumpTo("sad"); } + PropertyChanges { target: spriteimageelementtest + testtext: "The sprite should now be animating between frowning and being evil."+ + "This should not be alternating, but mostly frowning with the occasional evil eyes."+ + "After an evil eyes animation, it should return to frowning at least once." } + }, + State { name: "stochastic3"; when: statenum == 3 + StateChangeScript { script: spriteimage.jumpTo("cyclops"); } + PropertyChanges { target: spriteimageelementtest + testtext: "The sprite should now be animating fairly randomly between three animations where it does silly things with its eyes.\n"+ + "Next the sprite will animate into a static 'dead' state."+ + "When it does, it should first animate to and play through the 'big eyes' animation (if it is not currently playing that animation) before it enters the dying animation."} + }, + State { name: "dead"; when: statenum == 4 + PropertyChanges { target: spriteimage; goalState: "dead" } + PropertyChanges { target: spriteimageelementtest + testtext: "After a brief dying animation, the image should now be static.\n"+ + "Advance to restart the test." } + } + ] +} diff --git a/tests/testapplications/elements/content/pics/squarefacesprite.png b/tests/testapplications/elements/content/pics/squarefacesprite.png Binary files differnew file mode 100644 index 0000000000..f9a5d5fcce --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite.png diff --git a/tests/testapplications/elements/content/pics/squarefacesprite2.png b/tests/testapplications/elements/content/pics/squarefacesprite2.png Binary files differnew file mode 100644 index 0000000000..7106a520a4 --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite2.png diff --git a/tests/testapplications/elements/content/pics/squarefacesprite3.png b/tests/testapplications/elements/content/pics/squarefacesprite3.png Binary files differnew file mode 100644 index 0000000000..f4e6f26856 --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite3.png diff --git a/tests/testapplications/elements/content/pics/squarefacesprite4.png b/tests/testapplications/elements/content/pics/squarefacesprite4.png Binary files differnew file mode 100644 index 0000000000..1e094eed4a --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite4.png diff --git a/tests/testapplications/elements/content/pics/squarefacesprite5.png b/tests/testapplications/elements/content/pics/squarefacesprite5.png Binary files differnew file mode 100644 index 0000000000..1cfc5c7f8c --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite5.png diff --git a/tests/testapplications/elements/content/pics/squarefacesprite6.png b/tests/testapplications/elements/content/pics/squarefacesprite6.png Binary files differnew file mode 100644 index 0000000000..b040139a9e --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite6.png diff --git a/tests/testapplications/elements/content/pics/squarefacesprite7.png b/tests/testapplications/elements/content/pics/squarefacesprite7.png Binary files differnew file mode 100644 index 0000000000..b1e5e4e339 --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacesprite7.png diff --git a/tests/testapplications/elements/content/pics/squarefacespriteX.png b/tests/testapplications/elements/content/pics/squarefacespriteX.png Binary files differnew file mode 100644 index 0000000000..93a0181dd0 --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacespriteX.png diff --git a/tests/testapplications/elements/content/pics/squarefacespriteXX.png b/tests/testapplications/elements/content/pics/squarefacespriteXX.png Binary files differnew file mode 100644 index 0000000000..3159efe246 --- /dev/null +++ b/tests/testapplications/elements/content/pics/squarefacespriteXX.png diff --git a/tests/testapplications/text/Button.qml b/tests/testapplications/text/Button.qml new file mode 100644 index 0000000000..95252bfab2 --- /dev/null +++ b/tests/testapplications/text/Button.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +MouseArea { + property string buttontext: "" + width: parent.width / 4 + height: parent.height - 4 + Rectangle { + anchors.fill: parent + radius: 5 + color: "lightgray" + border.color: "black" + } + Text { + anchors.centerIn: parent + text: buttontext + color: "black" + } +}
\ No newline at end of file diff --git a/tests/testapplications/text/ControlView.qml b/tests/testapplications/text/ControlView.qml new file mode 100644 index 0000000000..a3a4a70507 --- /dev/null +++ b/tests/testapplications/text/ControlView.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +ListView { + id: controlviewitem + property string controlname: "" + property variant controlvalue + signal reset + height: 40; width: 200; highlightRangeMode: ListView.StrictlyEnforceRange + orientation: ListView.Horizontal; snapMode: ListView.SnapOneItem + preferredHighlightBegin: 50; preferredHighlightEnd: 150; + delegate: Rectangle { height: 40; width: 100; border.color: "black" + Text { anchors.centerIn: parent; width: parent.width; text: model.name; elide: Text.ElideRight; horizontalAlignment: Text.AlignHCenter } } + header: headfoot + footer: headfoot + Component { + id: headfoot + Rectangle { + MouseArea { id: resetbutton; anchors.fill: parent; onClicked: { reset(); } } + color: "lightgray"; height: 40; width: 50; border.color: "gray" + Text { id: headertext; anchors.centerIn: parent; wrapMode: Text.WrapAnywhere + rotation: -40; text: controlviewitem.controlname; font.pixelSize: 12; horizontalAlignment: Text.AlignHCenter } + } + } +}
\ No newline at end of file diff --git a/tests/testapplications/text/text.qml b/tests/testapplications/text/text.qml new file mode 100644 index 0000000000..28166c962c --- /dev/null +++ b/tests/testapplications/text/text.qml @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + height: 360; width: 640 + + Connections { target: pointvalue; onReset: { textelement.font.pointSize = 12 } } + + Item { + id: textpanel + height: 360 + width: 440 + Text { + id: textelement + height: parent.height - 20; width: parent.width - 20 + anchors.centerIn: parent + + text: { textvalue.model.get(textvalue.currentIndex).value } + textFormat: { formatvalue.model.get(formatvalue.currentIndex).value } + color: { colorvalue.model.get(colorvalue.currentIndex).value } + elide: { elidevalue.model.get(elidevalue.currentIndex).value } + font.bold: { boldvalue.model.get(boldvalue.currentIndex).value } + font.italic: { italicsvalue.model.get(italicsvalue.currentIndex).value } + font.capitalization: { capsvalue.model.get(capsvalue.currentIndex).value } + font.family: { familyvalue.model.get(familyvalue.currentIndex).value } + font.strikeout: strikeoutvalue.currentIndex + font.underline: underlinevalue.currentIndex + font.letterSpacing: { lspacingvalue.model.get(lspacingvalue.currentIndex).value } + font.wordSpacing: { wspacingvalue.model.get(wspacingvalue.currentIndex).value } + font.weight: { weightvalue.model.get(weightvalue.currentIndex).value } + font.pointSize: { pointvalue.model.get(pointvalue.currentIndex).value } + font.pixelSize: { pixelvalue.model.get(pixelvalue.currentIndex).value } + horizontalAlignment: { halignvalue.model.get(halignvalue.currentIndex).value } + verticalAlignment: { valignvalue.model.get(valignvalue.currentIndex).value } + wrapMode: { wrapvalue.model.get(wrapvalue.currentIndex).value } + maximumLineCount: { maxlinevalue.model.get(maxlinevalue.currentIndex).value } + lineHeight: { lineheightvalue.model.get(lineheightvalue.currentIndex).value } + lineHeightMode: { lineheightmodevalue.model.get(lineheightmodevalue.currentIndex).value } + smooth: { smoothvalue.model.get(smoothvalue.currentIndex).value } + style: { stylevalue.model.get(stylevalue.currentIndex).value } + styleColor: { stylecolorvalue.model.get(stylecolorvalue.currentIndex).value } + + Rectangle{ color: "transparent"; border.color: "green"; anchors.fill: parent } + } + + Text { + id: infopanel + anchors { left: parent.left; leftMargin: 10; bottom: parent.bottom } + height: 150; color: "black"; width: 150 + function elidename() { + switch (textelement.elide) { + case Text.ElideNone: return "None"; + case Text.ElideLeft: return "Left"; + case Text.ElideMiddle: return "Middle"; + case Text.ElideRight: return "Right"; + } + } + text: + "LineCount: "+textelement.lineCount+" of "+textelement.maximumLineCount+ + "\nPaintedHeight/Width: "+textelement.paintedHeight+"/"+textelement.paintedWidth+ + "\nPointSize: "+textelement.font.pointSize+ + "\nPixelSize: "+textelement.font.pixelSize+ + "\nTruncated: "+textelement.truncated+ + "\nElide: "+ elidename() + + } + } + + Item { + id: controlpanel + width: 200; height: parent.height + anchors.right: parent.right + Rectangle { anchors.fill: parent; color: "transparent"; border.color: "black" } + ListView { id: controls; model: controlsmodel; anchors.fill: parent; clip: true; cacheBuffer: 500 } + VisualItemModel { + id: controlsmodel + ControlView { + id: textvalue + controlname: "Text" + model: textmodel + ListModel { id: textmodel } + Component.onCompleted: { + textmodel.append({ "name": "Basic", + "value": "Qt Quick is a collection of technologies that are designed to help developers create the kind of intuitive, "+ + "modern, fluid user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+ + "portable devices.\n"+ + "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+ + "and a language runtime. "+ + "A collection of C++ APIs is used to integrate these high level features with classic Qt applications."}); + textmodel.append({ "name": "Short", + "value": "Button Text."}); + textmodel.append({ "name": "Long", + "value": "QtQuickisacollectionoftechnologiesthataredesignedtohelpdeveloperscreatethekindofintuitive,"+ + "modern,fluiduserinterfacesthatareincreasinglyusedonmobilephones,mediaplayers,set-topboxesandother"+ + "portabledevices."}); + textmodel.append({ "name": "Rich", + "value": "<b>Qt Quick</b> is a collection of technologies that are designed to help developers create the kind of <i>intuitive, "+ + "modern, fluid</i> user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+ + "portable devices.<br>"+ + "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+ + "and a language runtime. "+ + "A collection of C++ APIs is used to integrate these high level features with classic Qt applications."}); + } + } + ControlView { + id: formatvalue + controlname: "Format" + model: ListModel { ListElement { name: "Auto"; value: Text.AutoText } ListElement { name: "Plain"; value: Text.PlainText } + ListElement { name: "Rich"; value: Text.RichText } ListElement { name: "Styled"; value: Text.StyledText } } } + ControlView { + id: colorvalue + controlname: "Color" + model: ListModel { ListElement { name: "Red"; value: "red" } + ListElement { name: "Green"; value: "green" } ListElement { name: "Blue"; value: "blue" } } + } + ControlView { + id: elidevalue + controlname: "Elide" + model: ListModel { ListElement { name: "None"; value: Text.ElideNone } ListElement { name: "Left"; value: Text.ElideLeft } + ListElement { name: "Middle"; value: Text.ElideMiddle } ListElement { name: "Right"; value: Text.ElideRight } } + } + ControlView { + id: boldvalue + controlname: "Bold" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } + } + ControlView { + id: italicsvalue + controlname: "Italic" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } + } + ControlView { + id: capsvalue + controlname: "Cap10n" + model: ListModel { + ListElement { name: "Mixed"; value: Font.MixedCase } ListElement { name: "Upper"; value: Font.AllUppercase } + ListElement { name: "Lower"; value: Font.AllLowercase } ListElement { name: "SmallCaps"; value: Font.SmallCaps } + ListElement { name: "Capitals"; value: Font.Capitalize } + } + } + ControlView { + id: familyvalue + controlname: "Font" + property variant fontfamilies + function setModel() { + familiesmodel.clear(); + for (var i = 0; i < fontfamilies.length; ++i) { + familiesmodel.append({ "name": fontfamilies[i], "value": fontfamilies[i] }); + } + familyvalue.currentIndex = 0; + } + model: familiesmodel + ListModel { id: familiesmodel } + Component.onCompleted: { fontfamilies = Qt.fontFamilies(); setModel(); } + } + ControlView { + id: lspacingvalue + controlname: "LSpacing" + model: ListModel { ListElement { name: "0"; value: 0 } ListElement { name: "1"; value: 1 } ListElement { name: "2.5"; value: 2.5 } } } + ControlView { + id: wspacingvalue + controlname: "WSpacing" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: pixelvalue + controlname: "Pixel" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: pointvalue + controlname: "Point" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: strikeoutvalue + controlname: "Strike" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: underlinevalue + controlname: "U_line" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: weightvalue + controlname: "Weight" + model: ListModel { ListElement { name: "Light"; value: Font.Light } ListElement { name: "Normal"; value: Font.Normal } + ListElement { name: "DemiBold"; value: Font.DemiBold } ListElement { name: "Bold"; value: Font.Bold } + ListElement { name: "Black"; value: Font.Black } } + Component.onCompleted: { currentIndex = 1 } // set to default + } + ControlView { + id: halignvalue + controlname: "HAlign" + model: ListModel { ListElement { name: "Left"; value: Text.AlignLeft } ListElement { name: "Right"; value: Text.AlignRight } + ListElement { name: "Center"; value: Text.AlignHCenter } ListElement { name: "Justify"; value: Text.AlignJustify } } } + ControlView { + id: valignvalue + controlname: "VAlign" + model: ListModel { ListElement { name: "Top"; value: Text.AlignTop } ListElement { name: "Bottom"; value: Text.AlignBottom } + ListElement { name: "Center"; value: Text.AlignVCenter } } } + ControlView { + id: maxlinevalue + controlname: "Lines" + model: ListModel { ListElement { name: "Max"; value: 2147483647 } ListElement { name: "1"; value: 1 } + ListElement { name: "2"; value: 2 } ListElement { name: "10"; value: 10 }} } + ControlView { + id: lineheightvalue + controlname: "LHeight" + model: ListModel { ListElement { name: "1"; value: 1.0 } ListElement { name: "2"; value: 2.0 } ListElement { name: "30"; value: 30.0 }} } + ControlView { + id: lineheightmodevalue + controlname: "LHMode" + model: ListModel { + ListElement { name: "Multiply"; value: Text.ProportionalHeight } ListElement { name: "Fixed"; value: Text.FixedHeight } } } + ControlView { + id: smoothvalue + controlname: "Smooth" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: stylevalue + controlname: "Style" + model: ListModel { ListElement { name: "Normal"; value: Text.Normal } ListElement { name: "Outline"; value: Text.Outline } + ListElement { name: "Raised"; value: Text.Raised } ListElement { name: "Sunken"; value: Text.Sunken } } } + ControlView { + id: stylecolorvalue + controlname: "SColor" + model: ListModel { ListElement { name: "Green"; value: "green" } ListElement { name: "Blue"; value: "blue" } } } + ControlView { + id: wrapvalue + controlname: "Wrap" + model: ListModel { ListElement { name: "None"; value: Text.NoWrap } ListElement { name: "Word"; value: Text.WordWrap } + ListElement { name: "Anywhere"; value: Text.WrapAnywhere } ListElement { name: "Wrap"; value: Text.Wrap } } } + } + } +} + + + + + + + + + + + + + + + + + diff --git a/tests/testapplications/text/textedit.qml b/tests/testapplications/text/textedit.qml new file mode 100644 index 0000000000..a33859b0b8 --- /dev/null +++ b/tests/testapplications/text/textedit.qml @@ -0,0 +1,268 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + height: 360; width: 640 + property int intmax: 2147483647 + + Connections { target: pointvalue; onReset: { texteditelement.font.pointSize = 12 } } + + Item { + id: textpanel + height: 360 + width: 440 + TextEdit { + id: texteditelement + height: parent.height - 20; width: parent.width - 20 + anchors.centerIn: parent + + text: { textvalue.model.get(textvalue.currentIndex).value } + textFormat: { formatvalue.model.get(formatvalue.currentIndex).value } + color: { colorvalue.model.get(colorvalue.currentIndex).value } + font.bold: { boldvalue.model.get(boldvalue.currentIndex).value } + font.italic: { italicsvalue.model.get(italicsvalue.currentIndex).value } + font.capitalization: { capsvalue.model.get(capsvalue.currentIndex).value } + font.family: { familyvalue.model.get(familyvalue.currentIndex).value } + font.strikeout: strikeoutvalue.currentIndex + font.underline: underlinevalue.currentIndex + font.letterSpacing: { lspacingvalue.model.get(lspacingvalue.currentIndex).value } + font.wordSpacing: { wspacingvalue.model.get(wspacingvalue.currentIndex).value } + font.weight: { weightvalue.model.get(weightvalue.currentIndex).value } + font.pointSize: { pointvalue.model.get(pointvalue.currentIndex).value } + font.pixelSize: { pixelvalue.model.get(pixelvalue.currentIndex).value } + horizontalAlignment: { halignvalue.model.get(halignvalue.currentIndex).value } + verticalAlignment: { valignvalue.model.get(valignvalue.currentIndex).value } + wrapMode: { wrapvalue.model.get(wrapvalue.currentIndex).value } + smooth: { smoothvalue.model.get(smoothvalue.currentIndex).value } + selectByMouse: { mousevalue.model.get(mousevalue.currentIndex).value } + onLinkActivated: { bordercolor.border.color = "red" } + Rectangle { id: bordercolor; color: "transparent"; border.color: "green"; anchors.fill: parent } + } + + Text { + id: infopanel + anchors { left: parent.left; leftMargin: 10; bottom: parent.bottom } + height: 150; color: "black"; width: 150 + text: + "LineCount: "+texteditelement.lineCount+ + "\nPaintedHeight/Width: "+texteditelement.paintedHeight+"/"+texteditelement.paintedWidth+ + "\nPointSize: "+texteditelement.font.pointSize+"\nPixelSize: "+texteditelement.font.pixelSize+ + "\nCan Paste: "+texteditelement.canPaste + } + Row { + id: selectionbuttons + height:40 + width: 300 + anchors.right: texteditelement.right; anchors.bottom: texteditelement.bottom + Button { buttontext: "Select Word"; width: parent.width/3; onClicked: { texteditelement.selectWord() } } + Button { buttontext: "Select All"; width: parent.width/3; onClicked: { texteditelement.selectAll() } } + Button { buttontext: "Select None"; width: parent.width/3; onClicked: { texteditelement.deselect() } } + } + Row { + height:40 + width: 300 + anchors.right: texteditelement.right; anchors.bottom: selectionbuttons.top + Button { buttontext: "Cut"; width: parent.width/3; onClicked: { texteditelement.cut() } } + Button { buttontext: "Copy"; width: parent.width/3; onClicked: { texteditelement.copy() } } + Button { buttontext: "Paste"; width: parent.width/3; onClicked: { texteditelement.paste() } } + } + } + + Item { + id: controlpanel + width: 200; height: parent.height + anchors.right: parent.right + Rectangle { anchors.fill: parent; color: "transparent"; border.color: "black" } + ListView { id: controls; model: controlsmodel; anchors.fill: parent; clip: true; cacheBuffer: 500 } + VisualItemModel { + id: controlsmodel + ControlView { + id: textvalue + controlname: "Text" + model: textmodel + ListModel { id: textmodel } + Component.onCompleted: { + textmodel.append({ "name": "Basic", + "value": "Qt Quick is a collection of technologies that are designed to help developers create the kind of intuitive, "+ + "modern, fluid user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+ + "portable devices."+texteditelement.newline+ + "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+ + "and a language runtime.\n"+ + "A collection of C++ APIs is used to integrate these high level features with classic Qt applications."}); + textmodel.append({ "name": "Short", + "value": "Hello World"}); + textmodel.append({ "name": "Long", + "value": "QtQuickisacollectionoftechnologiesthataredesignedtohelpdeveloperscreatethekindofintuitive,"+ + "modern,fluiduserinterfacesthatareincreasinglyusedonmobilephones,mediaplayers,set-topboxesandother"+ + "portabledevices."}); + textmodel.append({ "name": "Rich", + "value": "<b>Qt Quick</b> is a collection of technologies that are designed to help developers create the kind of <i>intuitive, "+ + "modern, fluid</i> user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+ + "portable devices.<br>"+ + "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+ + "and a language runtime. "+ + "A collection of C++ APIs is used to integrate these high level features with classic Qt applications."}); + textmodel.append({ "name": "Links", + "value": "This is a link - <a href=\"http://doc.qt.nokia.com\">Qt Docs</a>"}); + } + } + ControlView { + id: formatvalue + controlname: "Format" + model: ListModel { ListElement { name: "Auto"; value: Text.AutoText } ListElement { name: "Plain"; value: Text.PlainText } + ListElement { name: "Rich"; value: Text.RichText } ListElement { name: "Styled"; value: Text.StyledText } } } + ControlView { + id: colorvalue + controlname: "Color" + model: ListModel { ListElement { name: "Red"; value: "red" } + ListElement { name: "Green"; value: "green" } ListElement { name: "Blue"; value: "blue" } } + } + ControlView { + id: boldvalue + controlname: "Bold" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } + } + ControlView { + id: italicsvalue + controlname: "Italic" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } + } + ControlView { + id: capsvalue + controlname: "Cap10n" + model: ListModel { + ListElement { name: "Mixed"; value: Font.MixedCase } ListElement { name: "Upper"; value: Font.AllUppercase } + ListElement { name: "Lower"; value: Font.AllLowercase } ListElement { name: "SmallCaps"; value: Font.SmallCaps } + ListElement { name: "Capitals"; value: Font.Capitalize } + } + } + ControlView { + id: familyvalue + controlname: "Font" + property variant fontfamilies + function setModel() { + familiesmodel.clear(); + for (var i = 0; i < fontfamilies.length; ++i) { + familiesmodel.append({ "name": fontfamilies[i], "value": fontfamilies[i] }); + } + familyvalue.currentIndex = 0; + } + model: familiesmodel + ListModel { id: familiesmodel } + Component.onCompleted: { fontfamilies = Qt.fontFamilies(); setModel(); } + } + ControlView { + id: lspacingvalue + controlname: "LSpacing" + model: ListModel { ListElement { name: "0"; value: 0 } ListElement { name: "1"; value: 1 } ListElement { name: "2.5"; value: 2.5 } } } + ControlView { + id: wspacingvalue + controlname: "WSpacing" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: pixelvalue + controlname: "Pixel" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: pointvalue + controlname: "Point" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: strikeoutvalue + controlname: "Strike" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: underlinevalue + controlname: "U_line" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: weightvalue + controlname: "Weight" + model: ListModel { ListElement { name: "Light"; value: Font.Light } ListElement { name: "Normal"; value: Font.Normal } + ListElement { name: "DemiBold"; value: Font.DemiBold } ListElement { name: "Bold"; value: Font.Bold } + ListElement { name: "Black"; value: Font.Black } } + Component.onCompleted: { currentIndex = 1 } // set to default + } + ControlView { + id: mousevalue + controlname: "Mouse" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: halignvalue + controlname: "HAlign" + model: ListModel { ListElement { name: "Left"; value: Text.AlignLeft } ListElement { name: "Right"; value: Text.AlignRight } + ListElement { name: "Center"; value: Text.AlignHCenter } ListElement { name: "Justify"; value: Text.AlignJustify } } } + ControlView { + id: valignvalue + controlname: "VAlign" + model: ListModel { ListElement { name: "Top"; value: Text.AlignTop } ListElement { name: "Bottom"; value: Text.AlignBottom } + ListElement { name: "Center"; value: Text.AlignVCenter } } } + ControlView { + id: smoothvalue + controlname: "Smooth" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: wrapvalue + controlname: "Wrap" + model: ListModel { ListElement { name: "None"; value: Text.NoWrap } ListElement { name: "Word"; value: Text.WordWrap } + ListElement { name: "Anywhere"; value: Text.WrapAnywhere } ListElement { name: "Wrap"; value: Text.Wrap } } } + } + } +} + + + + + + + + + + + + + + + + + diff --git a/tests/testapplications/text/textinput.qml b/tests/testapplications/text/textinput.qml new file mode 100644 index 0000000000..98f2628372 --- /dev/null +++ b/tests/testapplications/text/textinput.qml @@ -0,0 +1,343 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + height: 360; width: 640 + + Connections { target: pointvalue; onReset: { textinputelement.font.pointSize = 12 } } + + Item { + id: textpanel + height: 360 + width: 440 + MouseArea { anchors.fill: parent; onClicked: textinputelement.focus = false } + TextInput { + id: textinputelement + height: 50; width: parent.width - 20 + anchors.centerIn: parent + focus: true + property int validatorval + validatorval: { validvalue.model.get(validvalue.currentIndex).value } + text: { textvalue.model.get(textvalue.currentIndex).value } + autoScroll: { autoscrollvalue.model.get(autoscrollvalue.currentIndex).value } + color: { colorvalue.model.get(colorvalue.currentIndex).value } + font.bold: { boldvalue.model.get(boldvalue.currentIndex).value } + font.italic: { italicsvalue.model.get(italicsvalue.currentIndex).value } + font.capitalization: { capsvalue.model.get(capsvalue.currentIndex).value } + font.family: { familyvalue.model.get(familyvalue.currentIndex).value } + font.strikeout: strikeoutvalue.currentIndex + font.underline: underlinevalue.currentIndex + font.letterSpacing: { lspacingvalue.model.get(lspacingvalue.currentIndex).value } + font.wordSpacing: { wspacingvalue.model.get(wspacingvalue.currentIndex).value } + font.weight: { weightvalue.model.get(weightvalue.currentIndex).value } + font.pointSize: { pointvalue.model.get(pointvalue.currentIndex).value } + font.pixelSize: { pixelvalue.model.get(pixelvalue.currentIndex).value } + horizontalAlignment: { halignvalue.model.get(halignvalue.currentIndex).value } + smooth: { smoothvalue.model.get(smoothvalue.currentIndex).value } + selectByMouse: { mousevalue.model.get(mousevalue.currentIndex).value } + echoMode: { echovalue.model.get(echovalue.currentIndex).value } + cursorVisible: { cursorvisiblevalue.model.get(cursorvisiblevalue.currentIndex).value } + cursorDelegate: cursordelegate + onValidatorvalChanged: { + //console.log(validatorval); + if (validatorval == 0) + validator = intval; + else if (validatorval == 1) + validator = dubval; + else if (validatorval == 2) + validator = regval; + else + validator = noval; + } + IntValidator { id: intval; top: 30; bottom: 12 } + DoubleValidator { id: dubval; top: 30; bottom: 12 } + RegExpValidator { id: regval; regExp: /Qt/ } + RegExpValidator { id: noval; regExp: /.*/ } + Rectangle{ color: "transparent"; border.color: "green"; anchors.fill: parent } + } + + Row { + id: buttonrow + height: 40 + width: parent.width - 20 + anchors.left: textinputelement.left + anchors.bottom: buttonrow2.top; anchors.bottomMargin: 2 + Button { buttontext: "Select Word"; onClicked: { textinputelement.selectWord() } } + Button { buttontext: "Select All"; onClicked: { textinputelement.selectAll() } } + Button { buttontext: "Select to 5"; onClicked: { textinputelement.moveCursorSelection(5) } } + Button { buttontext: "Select None"; onClicked: { textinputelement.deselect() } } + } + Row { + id: buttonrow2 + height: 40 + width: parent.width - 20 + anchors.left: textinputelement.left + anchors.bottom: buttonrow3.top; anchors.bottomMargin: 2 + Button { buttontext: "Cut"; onClicked: { textinputelement.cut() } } + Button { buttontext: "Copy"; onClicked: { textinputelement.copy() } } + Button { buttontext: "Paste"; onClicked: { textinputelement.paste() } } + } + Row { + id: buttonrow3 + height: 40 + width: parent.width - 20 + anchors.left: textinputelement.left + anchors.bottom: textinputelement.top; anchors.bottomMargin: 2 + Button { buttontext: "Position 12px"; onClicked: { textinputelement.cursorPosition = textinputelement.positionAt(12) } } + Button { buttontext: "Select 3-6"; onClicked: { textinputelement.select(3,6) } } + Button { buttontext: "Position End"; onClicked: { textinputelement.cursorPosition = textinputelement.text.length } } + } + Component { + id: cursordelegate + Rectangle { + id: cursordelegaterect + height: 48; width: 3; color: "red"; visible: parent.cursorVisible + SequentialAnimation on opacity { running: true; loops: Animation.Infinite + NumberAnimation { to: 0; duration: 1000 } + NumberAnimation { to: 1; duration: 1000 } + } + } + } + + Text { + id: infopanel + anchors { left: parent.left; leftMargin: 10; bottom: parent.bottom } + height: 150; color: "black"; width: 150 + text: + "\nPointSize: "+textinputelement.font.pointSize+ + "\nPixelSize: "+textinputelement.font.pixelSize+ + "\nAcceptable Input: "+textinputelement.acceptableInput+ + "\nCan Paste: "+textinputelement.canPaste+ + "\nCursor Position: "+textinputelement.cursorPosition+ + "\nRight to Left: "+textinputelement.isRightToLeft(0,textinputelement.text.length); + } + } + + Item { + id: controlpanel + width: 200; height: parent.height + anchors.right: parent.right + Rectangle { anchors.fill: parent; color: "transparent"; border.color: "black" } + ListView { id: controls; model: controlsmodel; anchors.fill: parent; clip: true; cacheBuffer: 500 } + VisualItemModel { + id: controlsmodel + ControlView { + id: textvalue + controlname: "Text" + model: textmodel + ListModel { id: textmodel } + Component.onCompleted: { + textmodel.append({ "name": "Basic", "value": "The TextInput item displays an editable line of text."}); + textmodel.append({ "name": "Short", "value": "Hello World"}); + textmodel.append({ "name": "Long", + "value": "Qt Quick is a collection of technologies that are designed to help developers create the kind of intuitive, "+ + "modern, fluid user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+ + "portable devices. "+ + "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+ + "and a language runtime. "+ + "A collection of C++ APIs is used to integrate these high level features with classic Qt applications."}); + } + } + ControlView { + id: autoscrollvalue + controlname: "AutoScroll" + model: ListModel { ListElement { name: "On"; value: true } ListElement { name: "Off"; value: false } } + } + ControlView { + id: colorvalue + controlname: "Color" + model: ListModel { ListElement { name: "Red"; value: "red" } + ListElement { name: "Green"; value: "green" } ListElement { name: "Blue"; value: "blue" } } + } + ControlView { + id: elidevalue + controlname: "Elide" + model: ListModel { ListElement { name: "None"; value: Text.ElideNone } ListElement { name: "Left"; value: Text.ElideLeft } + ListElement { name: "Middle"; value: Text.ElideMiddle } ListElement { name: "Right"; value: Text.ElideRight } } + } + ControlView { + id: boldvalue + controlname: "Bold" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } + } + ControlView { + id: italicsvalue + controlname: "Italic" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } + } + ControlView { + id: capsvalue + controlname: "Cap10n" + model: ListModel { + ListElement { name: "Mixed"; value: Font.MixedCase } ListElement { name: "Upper"; value: Font.AllUppercase } + ListElement { name: "Lower"; value: Font.AllLowercase } ListElement { name: "SmallCaps"; value: Font.SmallCaps } + ListElement { name: "Capitals"; value: Font.Capitalize } + } + } + ControlView { + id: cursorvisiblevalue + controlname: "Cursor" + model: ListModel { ListElement { name: "On"; value: true } ListElement { name: "Off"; value: false } } + } + ControlView { + id: echovalue + controlname: "Echo" + model: ListModel { ListElement { name: "Normal"; value: TextInput.Normal } ListElement { name: "Password"; value: TextInput.Password } + ListElement { name: "None"; value: TextInput.NoEcho } ListElement { name: "OnEdit"; value: TextInput.PasswordEchoOnEdit } } } + ControlView { + id: familyvalue + controlname: "Font" + property variant fontfamilies + function setModel() { + familiesmodel.clear(); + for (var i = 0; i < fontfamilies.length; ++i) { + familiesmodel.append({ "name": fontfamilies[i], "value": fontfamilies[i] }); + } + familyvalue.currentIndex = 0; + } + model: familiesmodel + ListModel { id: familiesmodel } + Component.onCompleted: { fontfamilies = Qt.fontFamilies(); setModel(); } + } + ControlView { + id: lspacingvalue + controlname: "LSpacing" + model: ListModel { ListElement { name: "0"; value: 0 } ListElement { name: "1"; value: 1 } ListElement { name: "2.5"; value: 2.5 } } } + ControlView { + id: wspacingvalue + controlname: "WSpacing" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: pixelvalue + controlname: "Pixel" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: pointvalue + controlname: "Point" + model: ListModel { ListElement { name: "-1"; value: -1 } ListElement { name: "8"; value: 8 } ListElement { name: "20"; value: 20 } } } + ControlView { + id: strikeoutvalue + controlname: "Strike" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: underlinevalue + controlname: "U_line" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: weightvalue + controlname: "Weight" + model: ListModel { ListElement { name: "Light"; value: Font.Light } ListElement { name: "Normal"; value: Font.Normal } + ListElement { name: "DemiBold"; value: Font.DemiBold } ListElement { name: "Bold"; value: Font.Bold } + ListElement { name: "Black"; value: Font.Black } } + Component.onCompleted: { currentIndex = 1 } // set to default + } + ControlView { + id: halignvalue + controlname: "HAlign" + model: ListModel { ListElement { name: "Left"; value: Text.AlignLeft } ListElement { name: "Right"; value: Text.AlignRight } + ListElement { name: "Center"; value: Text.AlignHCenter } ListElement { name: "Justify"; value: Text.AlignJustify } } } + ControlView { + id: valignvalue + controlname: "VAlign" + model: ListModel { ListElement { name: "Top"; value: Text.AlignTop } ListElement { name: "Bottom"; value: Text.AlignBottom } + ListElement { name: "Center"; value: Text.AlignVCenter } } } + ControlView { + id: maxlinevalue + controlname: "Lines" + model: ListModel { ListElement { name: "Unset"; value: 1 } ListElement { name: "2"; value: 2 } ListElement { name: "10"; value: 10 }} } + ControlView { + id: lineheightvalue + controlname: "LHeight" + model: ListModel { ListElement { name: "1"; value: 1.0 } ListElement { name: "2"; value: 2.0 } ListElement { name: "30"; value: 30.0 }} } + ControlView { + id: lineheightmodevalue + controlname: "LHMode" + model: ListModel { + ListElement { name: "Multiply"; value: Text.ProportionalHeight } ListElement { name: "Fixed"; value: Text.FixedHeight } } } + ControlView { + id: mousevalue + controlname: "Mouse" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: smoothvalue + controlname: "Smooth" + model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } } + ControlView { + id: stylevalue + controlname: "Style" + model: ListModel { ListElement { name: "Normal"; value: Text.Normal } ListElement { name: "Outline"; value: Text.Outline } + ListElement { name: "Raised"; value: Text.Raised } ListElement { name: "Sunken"; value: Text.Sunken } } } + ControlView { + id: stylecolorvalue + controlname: "SColor" + model: ListModel { ListElement { name: "Green"; value: "green" } ListElement { name: "Blue"; value: "blue" } } } + ControlView { + id: wrapvalue + controlname: "Wrap" + model: ListModel { ListElement { name: "None"; value: Text.NoWrap } ListElement { name: "Word"; value: Text.WordWrap } + ListElement { name: "Anywhere"; value: Text.WrapAnywhere } ListElement { name: "Wrap"; value: Text.Wrap } } } + ControlView { + id: validvalue + controlname: "Valid" + model: ListModel { ListElement { name: "None"; value: -1 } ListElement { name: "Int"; value: 0 } + ListElement { name: "Double"; value: 1 } ListElement { name: "RegExp"; value: 2 } } } + } + } +} + + + + + + + + + + + + + + + + + diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index b4cf2da3ff..f0863032e3 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -148,7 +148,17 @@ QByteArray convertToId(const QByteArray &cppName) return cppToId.value(cppName, cppName); } -QSet<const QMetaObject *> collectReachableMetaObjects(const QList<QDeclarativeType *> &skip = QList<QDeclarativeType *>()) +/* All exported module APIs are collected into this list */ +class ModuleApi { +public: + QString uri; + int majorVersion; + int minorVersion; + QByteArray objectId; +}; +QList<ModuleApi> moduleApis; + +QSet<const QMetaObject *> collectReachableMetaObjects(QDeclarativeEngine *engine, const QList<QDeclarativeType *> &skip = QList<QDeclarativeType *>()) { QSet<const QMetaObject *> metas; metas.insert(FriendlyQObject::qtMeta()); @@ -221,6 +231,33 @@ QSet<const QMetaObject *> collectReachableMetaObjects(const QList<QDeclarativeTy qWarning() << "Could not create" << tyName; } + // extract exported module api + QHashIterator<QString, QList<QDeclarativeMetaType::ModuleApi> > moduleApiIt(QDeclarativeMetaType::moduleApis()); + while (moduleApiIt.hasNext()) { + moduleApiIt.next(); + foreach (const QDeclarativeMetaType::ModuleApi &api, moduleApiIt.value()) { + ModuleApi moduleApi; + moduleApi.uri = moduleApiIt.key(); + moduleApi.majorVersion = api.major; + moduleApi.minorVersion = api.minor; + + if (api.qobject) { + if (QObject *object = (*api.qobject)(engine, engine)) { + collectReachableMetaObjects(object, &metas); + moduleApi.objectId = convertToId(object->metaObject()->className()); + delete object; + } + } else if (api.script) { + qWarning() << "Can't dump the module api in " << moduleApi.uri << ". QJSValue based module API is not supported."; +// QJSValue value = (*api.script)(engine, engine); +// IdToObjectHash jsObjects; +// collectReachableJSObjects(value, &jsObjects, &metas); + } + + moduleApis += moduleApi; + } + } + return metas; } @@ -318,9 +355,21 @@ public: qml->writeEndObject(); } + void dump(const ModuleApi &api) + { + qml->writeStartObject(QLatin1String("ModuleApi")); + if (api.uri != relocatableModuleUri) + qml->writeScriptBinding(QLatin1String("uri"), enquote(api.uri)); + qml->writeScriptBinding(QLatin1String("version"), QString("%1.%2").arg( + QString::number(api.majorVersion), + QString::number(api.minorVersion))); + qml->writeScriptBinding(QLatin1String("name"), enquote(api.objectId)); + qml->writeEndObject(); + } + void writeEasingCurve() { - qml->writeStartObject("Component"); + qml->writeStartObject(QLatin1String("Component")); qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("QEasingCurve"))); qml->writeScriptBinding(QLatin1String("prototype"), enquote(QLatin1String("QDeclarativeEasingValueType"))); qml->writeEndObject(); @@ -582,7 +631,7 @@ int main(int argc, char *argv[]) } // find all QMetaObjects reachable from the builtin module - QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects(); + QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects(&engine); QList<QDeclarativeType *> defaultTypes = QDeclarativeMetaType::qmlTypes(); // add some otherwise unreachable QMetaObjects @@ -633,7 +682,7 @@ int main(int argc, char *argv[]) } } - QSet<const QMetaObject *> candidates = collectReachableMetaObjects(defaultTypes); + QSet<const QMetaObject *> candidates = collectReachableMetaObjects(&engine, defaultTypes); candidates.subtract(defaultReachable); // Also eliminate meta objects with the same classname. @@ -681,10 +730,15 @@ int main(int argc, char *argv[]) if (pluginImportUri.isEmpty()) dumper.writeEasingCurve(); + // write out module api elements + foreach (const ModuleApi &api, moduleApis) { + dumper.dump(api); + } + qml.writeEndObject(); qml.writeEndDocument(); - std::cout << bytes.constData(); + std::cout << bytes.constData() << std::flush; // workaround to avoid crashes on exit QTimer timer; diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp index 4706c72eb6..336fc899cd 100644 --- a/tools/qmlscene/main.cpp +++ b/tools/qmlscene/main.cpp @@ -514,7 +514,7 @@ int main(int argc, char ** argv) window->show(); -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC window->raise(); #endif diff --git a/tools/qmlscene/qmlscene.pro b/tools/qmlscene/qmlscene.pro index 66c2cda035..d0c4ec7a20 100644 --- a/tools/qmlscene/qmlscene.pro +++ b/tools/qmlscene/qmlscene.pro @@ -13,8 +13,4 @@ SOURCES += main.cpp CONFIG += console declarative_debug -symbian { - TARGET.EPOCHEAPSIZE = 0x20000 0x5000000 -} - DEFINES += QML_RUNTIME_TESTING diff --git a/tools/qmltestrunner/qmltestrunner.pro b/tools/qmltestrunner/qmltestrunner.pro index 1f864e2706..72990d6f98 100644 --- a/tools/qmltestrunner/qmltestrunner.pro +++ b/tools/qmltestrunner/qmltestrunner.pro @@ -9,7 +9,5 @@ QT += declarative qmltest macx: CONFIG -= app_bundle -#DEFINES += QUICK_TEST_SOURCE_DIR=\"\\\"$$OUT_PWD\\\"\" - target.path = $$[QT_INSTALL_BINS] INSTALLS += target diff --git a/tools/qmlviewer/deviceorientation_maemo5.cpp b/tools/qmlviewer/deviceorientation_maemo5.cpp deleted file mode 100644 index 59292d93ff..0000000000 --- a/tools/qmlviewer/deviceorientation_maemo5.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "deviceorientation.h" -#include <QtDBus> - -#include <mce/mode-names.h> -#include <mce/dbus-names.h> - -class MaemoOrientation : public DeviceOrientation -{ - Q_OBJECT -public: - MaemoOrientation() - : o(UnknownOrientation), sensorEnabled(false) - { - resumeListening(); - // connect to the orientation change signal - QDBusConnection::systemBus().connect(QString(), MCE_SIGNAL_PATH, MCE_SIGNAL_IF, - MCE_DEVICE_ORIENTATION_SIG, - this, - SLOT(deviceOrientationChanged(QString))); - } - - ~MaemoOrientation() - { - // disable the orientation sensor - QDBusConnection::systemBus().call( - QDBusMessage::createMethodCall(MCE_SERVICE, MCE_REQUEST_PATH, - MCE_REQUEST_IF, MCE_ACCELEROMETER_DISABLE_REQ)); - } - - inline Orientation orientation() const - { - return o; - } - - void setOrientation(Orientation o) - { - } - - void pauseListening() { - if (sensorEnabled) { - // disable the orientation sensor - QDBusConnection::systemBus().call( - QDBusMessage::createMethodCall(MCE_SERVICE, MCE_REQUEST_PATH, - MCE_REQUEST_IF, MCE_ACCELEROMETER_DISABLE_REQ)); - sensorEnabled = false; - } - } - - void resumeListening() { - if (!sensorEnabled) { - // enable the orientation sensor - QDBusConnection::systemBus().call( - QDBusMessage::createMethodCall(MCE_SERVICE, MCE_REQUEST_PATH, - MCE_REQUEST_IF, MCE_ACCELEROMETER_ENABLE_REQ)); - - QDBusMessage reply = QDBusConnection::systemBus().call( - QDBusMessage::createMethodCall(MCE_SERVICE, MCE_REQUEST_PATH, - MCE_REQUEST_IF, MCE_DEVICE_ORIENTATION_GET)); - - if (reply.type() == QDBusMessage::ErrorMessage) { - qWarning("Unable to retrieve device orientation: %s", qPrintable(reply.errorMessage())); - } else { - Orientation orientation = toOrientation(reply.arguments().value(0).toString()); - if (o != orientation) { - o = orientation; - emit orientationChanged(); - } - sensorEnabled = true; - } - } - } - -private Q_SLOTS: - void deviceOrientationChanged(const QString &newOrientation) - { - o = toOrientation(newOrientation); - - emit orientationChanged(); -// printf("%d\n", o); - } - -private: - static Orientation toOrientation(const QString &nativeOrientation) - { - if (nativeOrientation == MCE_ORIENTATION_LANDSCAPE) - return Landscape; - else if (nativeOrientation == MCE_ORIENTATION_LANDSCAPE_INVERTED) - return LandscapeInverted; - else if (nativeOrientation == MCE_ORIENTATION_PORTRAIT) - return Portrait; - else if (nativeOrientation == MCE_ORIENTATION_PORTRAIT_INVERTED) - return PortraitInverted; - return UnknownOrientation; - } - -private: - Orientation o; - bool sensorEnabled; -}; - -DeviceOrientation* DeviceOrientation::instance() -{ - static MaemoOrientation *o = new MaemoOrientation; - return o; -} - -#include "deviceorientation_maemo5.moc" diff --git a/tools/qmlviewer/deviceorientation_symbian.cpp b/tools/qmlviewer/deviceorientation_symbian.cpp deleted file mode 100644 index deeb45dc5a..0000000000 --- a/tools/qmlviewer/deviceorientation_symbian.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "deviceorientation.h" - -#include <e32base.h> -#include <sensrvchannelfinder.h> -#include <sensrvdatalistener.h> -#include <sensrvchannel.h> -#include <sensrvorientationsensor.h> - -class SymbianOrientation : public DeviceOrientation, public MSensrvDataListener -{ - Q_OBJECT -public: - SymbianOrientation() - : DeviceOrientation(), m_current(UnknownOrientation), m_sensorChannel(0), m_channelOpen(false) - { - TRAP_IGNORE(initL()); - if (!m_sensorChannel) - qWarning("No valid sensors found."); - } - - ~SymbianOrientation() - { - if (m_sensorChannel) { - m_sensorChannel->StopDataListening(); - m_sensorChannel->CloseChannel(); - delete m_sensorChannel; - } - } - - void initL() - { - CSensrvChannelFinder *channelFinder = CSensrvChannelFinder::NewLC(); - RSensrvChannelInfoList channelInfoList; - CleanupClosePushL(channelInfoList); - - TSensrvChannelInfo searchConditions; - searchConditions.iChannelType = KSensrvChannelTypeIdOrientationData; - channelFinder->FindChannelsL(channelInfoList, searchConditions); - - for (int i = 0; i < channelInfoList.Count(); ++i) { - TRAPD(error, m_sensorChannel = CSensrvChannel::NewL(channelInfoList[i])); - if (!error) - TRAP(error, m_sensorChannel->OpenChannelL()); - if (!error) { - TRAP(error, m_sensorChannel->StartDataListeningL(this, 1, 1, 0)); - m_channelOpen = true; - break; - } - if (error) { - delete m_sensorChannel; - m_sensorChannel = 0; - } - } - - channelInfoList.Close(); - CleanupStack::Pop(&channelInfoList); - CleanupStack::PopAndDestroy(channelFinder); - } - - Orientation orientation() const - { - return m_current; - } - - void setOrientation(Orientation) { } - -private: - DeviceOrientation::Orientation m_current; - CSensrvChannel *m_sensorChannel; - bool m_channelOpen; - void pauseListening() { - if (m_sensorChannel && m_channelOpen) { - m_sensorChannel->StopDataListening(); - m_sensorChannel->CloseChannel(); - m_channelOpen = false; - } - } - - void resumeListening() { - if (m_sensorChannel && !m_channelOpen) { - TRAPD(error, m_sensorChannel->OpenChannelL()); - if (!error) { - TRAP(error, m_sensorChannel->StartDataListeningL(this, 1, 1, 0)); - if (!error) { - m_channelOpen = true; - } - } - if (error) { - delete m_sensorChannel; - m_sensorChannel = 0; - } - } - } - - void DataReceived(CSensrvChannel &channel, TInt count, TInt dataLost) - { - Q_UNUSED(dataLost) - if (channel.GetChannelInfo().iChannelType == KSensrvChannelTypeIdOrientationData) { - TSensrvOrientationData data; - for (int i = 0; i < count; ++i) { - TPckgBuf<TSensrvOrientationData> dataBuf; - channel.GetData(dataBuf); - data = dataBuf(); - Orientation orientation = UnknownOrientation; - switch (data.iDeviceOrientation) { - case TSensrvOrientationData::EOrientationDisplayUp: - orientation = Portrait; - break; - case TSensrvOrientationData::EOrientationDisplayRightUp: - orientation = Landscape; - break; - case TSensrvOrientationData::EOrientationDisplayLeftUp: - orientation = LandscapeInverted; - break; - case TSensrvOrientationData::EOrientationDisplayDown: - orientation = PortraitInverted; - break; - case TSensrvOrientationData::EOrientationUndefined: - case TSensrvOrientationData::EOrientationDisplayUpwards: - case TSensrvOrientationData::EOrientationDisplayDownwards: - default: - break; - } - - if (m_current != orientation && orientation != UnknownOrientation) { - m_current = orientation; - emit orientationChanged(); - } - } - } - } - - void DataError(CSensrvChannel& /* channel */, TSensrvErrorSeverity /* error */) - { - } - - void GetDataListenerInterfaceL(TUid /* interfaceUid */, TAny*& /* interface */) - { - } -}; - - -DeviceOrientation* DeviceOrientation::instance() -{ - static SymbianOrientation *o = 0; - if (!o) - o = new SymbianOrientation; - return o; -} - -#include "deviceorientation_symbian.moc" diff --git a/tools/qmlviewer/loggerwidget.cpp b/tools/qmlviewer/loggerwidget.cpp index a82336bfb9..0393299d1f 100644 --- a/tools/qmlviewer/loggerwidget.cpp +++ b/tools/qmlviewer/loggerwidget.cpp @@ -47,11 +47,6 @@ #include <QPlainTextEdit> #include <QLabel> #include <QVBoxLayout> -#ifdef Q_WS_MAEMO_5 -# include <QScrollArea> -# include <QVBoxLayout> -# include "texteditautoresizer_maemo5.h" -#endif #include "loggerwidget.h" @@ -65,31 +60,7 @@ LoggerWidget::LoggerWidget(QWidget *parent) : setWindowTitle(tr("Warnings")); m_plainTextEdit = new QPlainTextEdit(); - -#if defined(Q_OS_SYMBIAN) - QAction* clearAction = new QAction(tr("Clear"), this); - clearAction->setSoftKeyRole(QAction::PositiveSoftKey); - connect(clearAction, SIGNAL(triggered()), m_plainTextEdit, SLOT(clear())); - addAction(clearAction); - - 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); - QScrollArea *area = new QScrollArea(); - area->setWidget(m_plainTextEdit); - area->setWidgetResizable(true); - setCentralWidget(area); -#else setCentralWidget(m_plainTextEdit); -#endif - m_noWarningsLabel = new QLabel(m_plainTextEdit); m_noWarningsLabel->setText(tr("(No warnings)")); m_noWarningsLabel->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp index cf33c4e365..2ab4689020 100644 --- a/tools/qmlviewer/main.cpp +++ b/tools/qmlviewer/main.cpp @@ -76,13 +76,6 @@ void exitApp(int i) QWeakPointer<LoggerWidget> logger; static QAtomicInt recursiveLock(0); -#if defined (Q_OS_SYMBIAN) -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#endif - void myMessageOutput(QtMsgType type, const char *msg) { QString strMsg = QString::fromLatin1(msg); @@ -91,26 +84,13 @@ void myMessageOutput(QtMsgType type, const char *msg) if (!logger.isNull()) { if (recursiveLock.testAndSetOrdered(0, 1)) { QMetaObject::invokeMethod(logger.data(), "append", Q_ARG(QString, strMsg)); - recursiveLock = 0; + recursiveLock.store(0); } } else { warnings += strMsg; warnings += QLatin1Char('\n'); } } -#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); @@ -154,7 +134,7 @@ void usage() qWarning(" -I <directory> ........................... prepend to the module import search path,"); qWarning(" display path if <directory> is empty"); qWarning(" -P <directory> ........................... prepend to the plugin search path"); -#if defined(Q_WS_MAC) +#if defined(Q_OS_MAC) qWarning(" -no-opengl ............................... don't use a QGLWidget for the viewport"); qWarning(" -opengl .................................. use a QGLWidget for the viewport (default)"); #else @@ -212,12 +192,8 @@ struct ViewerOptions warningsConfig(DefaultWarnings), sizeToView(true) { -#if defined(Q_OS_SYMBIAN) - maximized = true; - useNativeFileBrowser = false; -#endif -#if defined(Q_WS_MAC) +#if defined(Q_OS_MAC) useGL = true; #endif } @@ -522,22 +498,6 @@ QDeclarativeViewer *openFile(const QString &fileName) int main(int argc, char ** argv) { systemMsgOutput = qInstallMsgHandler(myMessageOutput); - -#if defined (Q_WS_X11) || defined (Q_WS_MAC) - //### default to using raster graphics backend for now - bool gsSpecified = false; - for (int i = 0; i < argc; ++i) { - QString arg = QString::fromAscii(argv[i]); - if (arg == QLatin1String("-graphicssystem")) { - gsSpecified = true; - break; - } - } - - if (!gsSpecified) - QApplication::setGraphicsSystem(QLatin1String("raster")); -#endif - Application app(argc, argv); app.setApplicationName(QLatin1String("QtQmlViewer")); app.setOrganizationName(QLatin1String("Nokia")); diff --git a/tools/qmlviewer/proxysettings.cpp b/tools/qmlviewer/proxysettings.cpp index 8bc778d18a..bb83d79db9 100644 --- a/tools/qmlviewer/proxysettings.cpp +++ b/tools/qmlviewer/proxysettings.cpp @@ -51,11 +51,7 @@ ProxySettings::ProxySettings (QWidget * parent) : QDialog (parent), Ui::ProxySettings() { setupUi (this); - -#if !defined Q_WS_MAEMO_5 - // the onscreen keyboard can't cope with masks proxyServerEdit->setInputMask(QLatin1String("000.000.000.000;_")); -#endif QIntValidator *validator = new QIntValidator (0, 9999, this); proxyPortEdit->setValidator(validator); diff --git a/tools/qmlviewer/proxysettings.h b/tools/qmlviewer/proxysettings.h index 2633c2404c..8946934f91 100644 --- a/tools/qmlviewer/proxysettings.h +++ b/tools/qmlviewer/proxysettings.h @@ -44,11 +44,7 @@ #include <QDialog> #include <QNetworkProxy> -#ifdef Q_WS_MAEMO_5 -#include "ui_proxysettings_maemo5.h" -#else #include "ui_proxysettings.h" -#endif QT_BEGIN_NAMESPACE /** diff --git a/tools/qmlviewer/proxysettings_maemo5.ui b/tools/qmlviewer/proxysettings_maemo5.ui deleted file mode 100644 index 75875d835b..0000000000 --- a/tools/qmlviewer/proxysettings_maemo5.ui +++ /dev/null @@ -1,177 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>ProxySettings</class> - <widget class="QDialog" name="ProxySettings"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>447</width> - <height>162</height> - </rect> - </property> - <property name="windowTitle"> - <string>HTTP Proxy</string> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <property name="leftMargin"> - <number>16</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>16</number> - </property> - <property name="bottomMargin"> - <number>8</number> - </property> - <property name="horizontalSpacing"> - <number>16</number> - </property> - <property name="verticalSpacing"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QCheckBox" name="proxyCheckBox"> - <property name="text"> - <string>Use HTTP Proxy</string> - </property> - </widget> - </item> - <item row="0" column="1" rowspan="2"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="0" rowspan="2"> - <widget class="QWidget" name="widget" native="true"> - <layout class="QGridLayout" name="gridLayout"> - <property name="horizontalSpacing"> - <number>16</number> - </property> - <property name="verticalSpacing"> - <number>0</number> - </property> - <property name="margin"> - <number>0</number> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="serverAddressLabel"> - <property name="text"> - <string>Server</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="proxyServerEdit"> - <property name="placeholderText"> - <string>Name or IP</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Port</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="proxyPortEdit"> - <property name="text"> - <string notr="true">8080</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="usernameLabel"> - <property name="text"> - <string>Username</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLineEdit" name="usernameEdit"/> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="passwordLabel"> - <property name="text"> - <string>Password</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QLineEdit" name="passwordEdit"> - <property name="echoMode"> - <enum>QLineEdit::Password</enum> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item row="2" column="1"> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - </item> - </layout> - </widget> - <tabstops> - <tabstop>proxyCheckBox</tabstop> - <tabstop>proxyServerEdit</tabstop> - <tabstop>proxyPortEdit</tabstop> - <tabstop>usernameEdit</tabstop> - <tabstop>passwordEdit</tabstop> - <tabstop>buttonBox</tabstop> - </tabstops> - <resources/> - <connections> - <connection> - <sender>buttonBox</sender> - <signal>accepted()</signal> - <receiver>ProxySettings</receiver> - <slot>accept()</slot> - <hints> - <hint type="sourcelabel"> - <x>318</x> - <y>100</y> - </hint> - <hint type="destinationlabel"> - <x>157</x> - <y>116</y> - </hint> - </hints> - </connection> - <connection> - <sender>buttonBox</sender> - <signal>rejected()</signal> - <receiver>ProxySettings</receiver> - <slot>reject()</slot> - <hints> - <hint type="sourcelabel"> - <x>318</x> - <y>100</y> - </hint> - <hint type="destinationlabel"> - <x>286</x> - <y>116</y> - </hint> - </hints> - </connection> - </connections> -</ui> diff --git a/tools/qmlviewer/qdeclarativetester.cpp b/tools/qmlviewer/qdeclarativetester.cpp index 451950a021..69e31584db 100644 --- a/tools/qmlviewer/qdeclarativetester.cpp +++ b/tools/qmlviewer/qdeclarativetester.cpp @@ -49,9 +49,7 @@ #include <QCryptographicHash> #include <QGraphicsObject> #include <QtCore/private/qabstractanimation_p.h> -#ifndef Q_OS_SYMBIAN #include <QtQuick1/private/qdeclarativeitem_p.h> -#endif QT_BEGIN_NAMESPACE @@ -269,9 +267,8 @@ void QDeclarativeTester::save() void QDeclarativeTester::updateCurrentTime(int msec) { -#ifndef Q_OS_SYMBIAN QDeclarativeItemPrivate::setConsistentTime(msec); -#endif + if (!testscript && msec > 16 && options & QDeclarativeViewer::Snapshot) return; @@ -280,14 +277,14 @@ void QDeclarativeTester::updateCurrentTime(int msec) if (options & QDeclarativeViewer::TestImages) { img.fill(qRgb(255,255,255)); -#ifdef Q_WS_MAC +/*#ifdef Q_OS_MAC //Compile failure on Cocoa x64 QTBUG-22304 bool oldSmooth = qt_applefontsmoothing_enabled; qt_applefontsmoothing_enabled = false; -#endif +#endif*/ QPainter p(&img); -#ifdef Q_WS_MAC +/*#ifdef Q_OS_MAC //Compile failure on Cocoa x64 QTBUG-22304 qt_applefontsmoothing_enabled = oldSmooth; -#endif +#endif*/ m_view->render(&p); } @@ -450,4 +447,4 @@ void QDeclarativeTester::registerTypes() qmlRegisterType<QDeclarativeVisualTestKey>("Qt.VisualTest", 4,7, "Key"); } -QT_END_NAMESPACE +QT_END_NAMESPACE
\ No newline at end of file diff --git a/tools/qmlviewer/qml.pri b/tools/qmlviewer/qml.pri index e84dfb5c9b..8f54505f0e 100644 --- a/tools/qmlviewer/qml.pri +++ b/tools/qmlviewer/qml.pri @@ -19,25 +19,7 @@ SOURCES += $$PWD/qmlruntime.cpp \ RESOURCES = $$PWD/browser/browser.qrc \ $$PWD/startup/startup.qrc -symbian { - contains(QT_CONFIG, s60) { - LIBS += -lavkon -lcone - } - !contains(S60_VERSION, 3.1):!contains(S60_VERSION, 3.2) { - LIBS += -lsensrvclient -lsensrvutil - SOURCES += $$PWD/deviceorientation_symbian.cpp - } else { - SOURCES += $$PWD/deviceorientation.cpp - } - FORMS = $$PWD/recopts.ui \ - $$PWD/proxysettings.ui -} else:maemo5 { - QT += dbus - HEADERS += $$PWD/texteditautoresizer_maemo5.h - SOURCES += $$PWD/deviceorientation_maemo5.cpp - FORMS = $$PWD/recopts_maemo5.ui \ - $$PWD/proxysettings_maemo5.ui -} else:linux-g++-maemo { +linux-g++-maemo { QT += dbus SOURCES += $$PWD/deviceorientation_harmattan.cpp FORMS = $$PWD/recopts.ui \ diff --git a/tools/qmlviewer/qmlruntime.cpp b/tools/qmlviewer/qmlruntime.cpp index a1ebd54a52..4a938b7ea7 100644 --- a/tools/qmlviewer/qmlruntime.cpp +++ b/tools/qmlviewer/qmlruntime.cpp @@ -44,15 +44,7 @@ #ifdef hz #undef hz #endif -#ifdef Q_WS_MAEMO_5 -# include <QMaemo5ValueButton> -# include <QMaemo5ListPickSelector> -# include <QWidgetAction> -# include <QStringListModel> -# include "ui_recopts_maemo5.h" -#else # include "ui_recopts.h" -#endif #include "qmlruntime.h" #include <qdeclarativecontext.h> @@ -93,15 +85,12 @@ #include <QMutexLocker> #include "proxysettings.h" #include "deviceorientation.h" +#include <qdeclarativetester.h> #ifdef GL_SUPPORTED #include <QGLWidget> #endif -#if defined(Q_WS_S60) -#include <aknappui.h> // For locking app orientation -#endif - #include <qdeclarativetester.h> #include "qdeclarative.h" #include "private/qabstractanimation_p.h" @@ -192,60 +181,6 @@ private: bool activeWindow; }; - - -#if defined(Q_WS_MAEMO_5) - -class Maemo5PickerAction : public QWidgetAction { - Q_OBJECT -public: - Maemo5PickerAction(const QString &text, QActionGroup *actions, QObject *parent) - : QWidgetAction(parent), m_text(text), m_actions(actions) - { } - - QWidget *createWidget(QWidget *parent) - { - QMaemo5ValueButton *button = new QMaemo5ValueButton(m_text, parent); - button->setValueLayout(QMaemo5ValueButton::ValueUnderTextCentered); - QMaemo5ListPickSelector *pick = new QMaemo5ListPickSelector(button); - button->setPickSelector(pick); - if (m_actions) { - QStringList sl; - int curIdx = -1, idx = 0; - foreach (QAction *a, m_actions->actions()) { - sl << a->text(); - if (a->isChecked()) - curIdx = idx; - idx++; - } - pick->setModel(new QStringListModel(sl)); - pick->setCurrentIndex(curIdx); - } else { - button->setEnabled(false); - } - connect(pick, SIGNAL(selected(QString)), this, SLOT(emitTriggered())); - return button; - } - -private slots: - void emitTriggered() - { - QMaemo5ListPickSelector *pick = qobject_cast<QMaemo5ListPickSelector *>(sender()); - if (!pick) - return; - int idx = pick->currentIndex(); - - if (m_actions && idx >= 0 && idx < m_actions->actions().count()) - m_actions->actions().at(idx)->trigger(); - } - -private: - QString m_text; - QPointer<QActionGroup> m_actions; -}; - -#endif // Q_WS_MAEMO_5 - static struct { const char *name, *args; } ffmpegprofiles[] = { {"Maximum Quality", "-sameq"}, {"High Quality", "-qmax 2"}, @@ -262,9 +197,7 @@ public: RecordingDialog(QWidget *parent) : QDialog(parent) { setupUi(this); -#ifndef Q_WS_MAEMO_5 hz->setValidator(new QDoubleValidator(hz)); -#endif for (int i=0; ffmpegprofiles[i].name; ++i) { profile->addItem(QString::fromAscii(ffmpegprofiles[i].name)); } @@ -295,59 +228,25 @@ public: { QString str = tr("Original (%1x%2)").arg(s.width()).arg(s.height()); -#ifdef Q_WS_MAEMO_5 - sizeCombo->setItemText(0, str); -#else sizeOriginal->setText(str); if (sizeWidth->value()<=1) { sizeWidth->setValue(s.width()); sizeHeight->setValue(s.height()); } -#endif } void showffmpegOptions(bool b) { -#ifdef Q_WS_MAEMO_5 - profileLabel->setVisible(b); - profile->setVisible(b); - ffmpegHelp->setVisible(b); - args->setVisible(b); -#else ffmpegOptions->setVisible(b); -#endif } void showRateOptions(bool b) { -#ifdef Q_WS_MAEMO_5 - rateLabel->setVisible(b); - rateCombo->setVisible(b); -#else rateOptions->setVisible(b); -#endif } void setVideoRate(int rate) { -#ifdef Q_WS_MAEMO_5 - int idx; - if (rate >= 60) - idx = 0; - else if (rate >= 50) - idx = 2; - else if (rate >= 25) - idx = 3; - else if (rate >= 24) - idx = 4; - else if (rate >= 20) - idx = 5; - else if (rate >= 15) - idx = 6; - else - idx = 7; - rateCombo->setCurrentIndex(idx); -#else if (rate == 24) hz24->setChecked(true); else if (rate == 25) @@ -360,23 +259,10 @@ public: hzCustom->setChecked(true); hz->setText(QString::number(rate)); } -#endif } int videoRate() const { -#ifdef Q_WS_MAEMO_5 - switch (rateCombo->currentIndex()) { - case 0: return 60; - case 1: return 50; - case 2: return 25; - case 3: return 24; - case 4: return 20; - case 5: return 15; - case 7: return 10; - default: return 60; - } -#else if (hz24->isChecked()) return 24; else if (hz25->isChecked()) @@ -388,20 +274,10 @@ public: else { return hz->text().toInt(); } -#endif } QSize videoSize() const { -#ifdef Q_WS_MAEMO_5 - switch (sizeCombo->currentIndex()) { - case 0: return QSize(); - case 1: return QSize(640,480); - case 2: return QSize(320,240); - case 3: return QSize(1280,720); - default: return QSize(); - } -#else if (sizeOriginal->isChecked()) return QSize(); else if (size720p->isChecked()) @@ -412,7 +288,6 @@ public: return QSize(320,240); else return QSize(sizeWidth->value(), sizeHeight->value()); -#endif } @@ -615,11 +490,6 @@ QDeclarativeViewer::QDeclarativeViewer(QWidget *parent, Qt::WindowFlags flags) { QDeclarativeViewer::registerTypes(); setWindowTitle(tr("Qt QML Viewer")); -#ifdef Q_WS_MAEMO_5 - setAttribute(Qt::WA_Maemo5StackedWindow); -// setPalette(QApplication::palette("QLabel")); -#endif - devicemode = false; canvas = 0; record_autotime = 0; @@ -742,10 +612,8 @@ 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); @@ -763,30 +631,22 @@ void QDeclarativeViewer::createMenu() orientation->setExclusive(true); connect(orientation, SIGNAL(triggered(QAction*)), this, SLOT(changeOrientation(QAction*))); -#if defined(Q_OS_SYMBIAN) - QAction *autoOrientationAction = new QAction(tr("Auto-orientation"), this); - autoOrientationAction->setCheckable(true); -#endif QAction *portraitAction = new QAction(tr("Portrait"), this); portraitAction->setCheckable(true); QAction *landscapeAction = new QAction(tr("Landscape"), this); landscapeAction->setCheckable(true); -#if !defined(Q_OS_SYMBIAN) QAction *portraitInvAction = new QAction(tr("Portrait (inverted)"), this); portraitInvAction->setCheckable(true); QAction *landscapeInvAction = new QAction(tr("Landscape (inverted)"), this); landscapeInvAction->setCheckable(true); -#endif QAction *aboutAction = new QAction(tr("&About Qt..."), this); aboutAction->setMenuRole(QAction::AboutQtRole); connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); -#if !defined(Q_OS_SYMBIAN) QAction *closeAction = new QAction(tr("&Close"), this); closeAction->setShortcuts(QKeySequence::Close); connect(closeAction, SIGNAL(triggered()), this, SLOT(close())); -#endif QAction *quitAction = new QAction(tr("&Quit"), this); quitAction->setMenuRole(QAction::QuitRole); @@ -795,34 +655,12 @@ void QDeclarativeViewer::createMenu() QMenuBar *menu = menuBar(); if (!menu) - return; - -#if defined(Q_WS_MAEMO_5) - menu->addAction(openAction); - menu->addAction(openUrlAction); - menu->addAction(reloadAction); - - menu->addAction(snapshotAction); - menu->addAction(recordAction); - - menu->addAction(recordOptions); - menu->addAction(proxyAction); - - menu->addAction(slowAction); - menu->addAction(showWarningsWindow); - - orientation->addAction(landscapeAction); - orientation->addAction(portraitAction); - menu->addAction(new Maemo5PickerAction(tr("Set orientation"), orientation, this)); - menu->addAction(fullscreenAction); - return; -#endif // Q_WS_MAEMO_5 + return; QMenu *fileMenu = menu->addMenu(tr("&File")); fileMenu->addAction(openAction); fileMenu->addAction(openUrlAction); fileMenu->addAction(reloadAction); -#if !defined(Q_OS_SYMBIAN) fileMenu->addSeparator(); fileMenu->addAction(closeAction); fileMenu->addAction(quitAction); @@ -830,7 +668,6 @@ 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); @@ -838,25 +675,16 @@ void QDeclarativeViewer::createMenu() QMenu *settingsMenu = menu->addMenu(tr("&Settings")); settingsMenu->addAction(proxyAction); -#if defined(Q_OS_SYMBIAN) - settingsMenu->addAction(fullscreenAction); -#else settingsMenu->addAction(recordOptions); settingsMenu->addMenu(loggerWindow->preferencesMenu()); -#endif // !Q_OS_SYMBIAN settingsMenu->addAction(rotateAction); QMenu *propertiesMenu = settingsMenu->addMenu(tr("Properties")); -#if defined(Q_OS_SYMBIAN) - orientation->addAction(autoOrientationAction); -#endif orientation->addAction(portraitAction); orientation->addAction(landscapeAction); -#if !defined(Q_OS_SYMBIAN) orientation->addAction(portraitInvAction); orientation->addAction(landscapeInvAction); -#endif propertiesMenu->addActions(orientation->actions()); QMenu *helpMenu = menu->addMenu(tr("&Help")); @@ -880,23 +708,6 @@ void QDeclarativeViewer::proxySettingsChanged() void QDeclarativeViewer::rotateOrientation() { -#if defined(Q_WS_S60) - CAknAppUi *appUi = static_cast<CAknAppUi *>(CEikonEnv::Static()->AppUi()); - if (appUi) { - CAknAppUi::TAppUiOrientation oldOrientation = appUi->Orientation(); - QString newOrientation; - if (oldOrientation == CAknAppUi::EAppUiOrientationPortrait) { - newOrientation = QLatin1String("Landscape"); - } else { - newOrientation = QLatin1String("Portrait"); - } - foreach (QAction *action, orientation->actions()) { - if (action->text() == newOrientation) { - changeOrientation(action); - } - } - } -#else QAction *current = orientation->checkedAction(); QList<QAction *> actions = orientation->actions(); int index = actions.indexOf(current); @@ -905,7 +716,6 @@ void QDeclarativeViewer::rotateOrientation() QAction *newOrientation = actions[(index + 1) % actions.count()]; changeOrientation(newOrientation); -#endif } void QDeclarativeViewer::toggleFullScreen() @@ -918,11 +728,7 @@ void QDeclarativeViewer::toggleFullScreen() void QDeclarativeViewer::showWarnings(bool show) { -#if defined(Q_OS_SYMBIAN) - loggerWindow->showMaximized(); -#else loggerWindow->setVisible(show); -#endif } void QDeclarativeViewer::warningsWidgetOpened() @@ -1117,12 +923,7 @@ bool QDeclarativeViewer::open(const QString& file_or_url) canvas->engine()->clearComponentCache(); QDeclarativeContext *ctxt = canvas->rootContext(); ctxt->setContextProperty(QLatin1String("qmlViewer"), this); -#ifdef Q_OS_SYMBIAN - ctxt->setContextProperty(QLatin1String("qmlViewerFolder"), QLatin1String("E:\\")); // Documents on your S60 phone -#else ctxt->setContextProperty(QLatin1String("qmlViewerFolder"), QDir::currentPath()); -#endif - ctxt->setContextProperty(QLatin1String("runtime"), Runtime::instance()); QString fileName = url.toLocalFile(); @@ -1442,22 +1243,6 @@ void QDeclarativeViewer::changeOrientation(QAction *action) return; QString o = action->text(); action->setChecked(true); -#if defined(Q_WS_S60) - CAknAppUi *appUi = static_cast<CAknAppUi *>(CEikonEnv::Static()->AppUi()); - if (appUi) { - CAknAppUi::TAppUiOrientation orientation = appUi->Orientation(); - if (o == QLatin1String("Auto-orientation")) { - appUi->SetOrientationL(CAknAppUi::EAppUiOrientationAutomatic); - rotateAction->setVisible(false); - } else if (o == QLatin1String("Portrait")) { - appUi->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait); - rotateAction->setVisible(true); - } else if (o == QLatin1String("Landscape")) { - appUi->SetOrientationL(CAknAppUi::EAppUiOrientationLandscape); - rotateAction->setVisible(true); - } - } -#else if (o == QLatin1String("Portrait")) DeviceOrientation::instance()->setOrientation(DeviceOrientation::Portrait); else if (o == QLatin1String("Landscape")) @@ -1466,7 +1251,6 @@ void QDeclarativeViewer::changeOrientation(QAction *action) DeviceOrientation::instance()->setOrientation(DeviceOrientation::PortraitInverted); else if (o == QLatin1String("Landscape (inverted)")) DeviceOrientation::instance()->setOrientation(DeviceOrientation::LandscapeInverted); -#endif } void QDeclarativeViewer::orientationChanged() @@ -1489,7 +1273,7 @@ void QDeclarativeViewer::setUseGL(bool useGL) #ifdef GL_SUPPORTED if (useGL) { QGLFormat format = QGLFormat::defaultFormat(); -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC format.setSampleBuffers(true); format.setSwapInterval(1); #else @@ -1564,4 +1348,4 @@ void QDeclarativeViewer::registerTypes() QT_END_NAMESPACE -#include "qmlruntime.moc" +#include "qmlruntime.moc"
\ No newline at end of file diff --git a/tools/qmlviewer/qmlviewer.pro b/tools/qmlviewer/qmlviewer.pro index 1f7a6024f4..980c1d4b3c 100644 --- a/tools/qmlviewer/qmlviewer.pro +++ b/tools/qmlviewer/qmlviewer.pro @@ -17,20 +17,6 @@ DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII target.path = $$[QT_INSTALL_BINS] INSTALLS += target -maemo5 { - QT += maemo5 -} -symbian { - TARGET.UID3 = 0x20021317 - CONFIG += qt_demo - TARGET.EPOCHEAPSIZE = 0x20000 0x4000000 - TARGET.CAPABILITY = NetworkServices ReadUserData - - # Deploy plugin for remote debugging - qmldebuggingplugin.sources = $$QT_BUILD_TREE/plugins/qmltooling/qmldbg_tcp$${QT_LIBINFIX}.dll $$QT_BUILD_TREE/plugins/qmltooling/qmldbg_ost$${QT_LIBINFIX}.dll - qmldebuggingplugin.path = c:$$QT_PLUGINS_BASE_DIR/qmltooling - DEPLOYMENT += qmldebuggingplugin -} mac { QMAKE_INFO_PLIST=Info_mac.plist TARGET=QMLViewer diff --git a/tools/qmlviewer/recopts_maemo5.ui b/tools/qmlviewer/recopts_maemo5.ui deleted file mode 100644 index 3bb5ecabd9..0000000000 --- a/tools/qmlviewer/recopts_maemo5.ui +++ /dev/null @@ -1,254 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>RecordingOptions</class> - <widget class="QDialog" name="RecordingOptions"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>469</width> - <height>142</height> - </rect> - </property> - <property name="windowTitle"> - <string>Video options</string> - </property> - <layout class="QGridLayout" name="gridLayout" columnstretch="0,2,0"> - <property name="sizeConstraint"> - <enum>QLayout::SetMinAndMaxSize</enum> - </property> - <property name="leftMargin"> - <number>16</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>16</number> - </property> - <property name="bottomMargin"> - <number>8</number> - </property> - <property name="horizontalSpacing"> - <number>16</number> - </property> - <property name="verticalSpacing"> - <number>0</number> - </property> - <item row="0" column="1"> - <widget class="QLineEdit" name="file"/> - </item> - <item row="0" column="2" rowspan="3"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>72</width> - <height>56</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>Size</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QComboBox" name="sizeCombo"> - <item> - <property name="text"> - <string/> - </property> - </item> - <item> - <property name="text"> - <string>VGA</string> - </property> - </item> - <item> - <property name="text"> - <string>QVGA</string> - </property> - </item> - <item> - <property name="text"> - <string>720p</string> - </property> - </item> - </widget> - </item> - <item row="2" column="0" rowspan="2"> - <widget class="QLabel" name="rateLabel"> - <property name="text"> - <string>Rate</string> - </property> - </widget> - </item> - <item row="2" column="1" rowspan="2"> - <widget class="QComboBox" name="rateCombo"> - <item> - <property name="text"> - <string>60 Hz</string> - </property> - </item> - <item> - <property name="text"> - <string>50 Hz</string> - </property> - </item> - <item> - <property name="text"> - <string>25 Hz</string> - </property> - </item> - <item> - <property name="text"> - <string>24 Hz</string> - </property> - </item> - <item> - <property name="text"> - <string>20 Hz</string> - </property> - </item> - <item> - <property name="text"> - <string>15 Hz</string> - </property> - </item> - <item> - <property name="text"> - <string>10 Hz</string> - </property> - </item> - </widget> - </item> - <item row="5" column="1"> - <widget class="QLineEdit" name="args"/> - </item> - <item row="4" column="1"> - <widget class="QComboBox" name="profile"/> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="profileLabel"> - <property name="text"> - <string>Profile</string> - </property> - </widget> - </item> - <item row="6" column="0" colspan="2"> - <widget class="QLabel" name="warning"> - <property name="text"> - <string notr="true">warning</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="4" column="2" rowspan="3"> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QPushButton" name="pickfile"> - <property name="text"> - <string>File</string> - </property> - </widget> - </item> - <item row="5" column="0"> - <widget class="QPushButton" name="ffmpegHelp"> - <property name="text"> - <string>Options</string> - </property> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections> - <connection> - <sender>buttonBox</sender> - <signal>accepted()</signal> - <receiver>RecordingOptions</receiver> - <slot>accept()</slot> - <hints> - <hint type="sourcelabel"> - <x>258</x> - <y>424</y> - </hint> - <hint type="destinationlabel"> - <x>60</x> - <y>219</y> - </hint> - </hints> - </connection> - <connection> - <sender>buttonBox</sender> - <signal>rejected()</signal> - <receiver>RecordingOptions</receiver> - <slot>reject()</slot> - <hints> - <hint type="sourcelabel"> - <x>258</x> - <y>424</y> - </hint> - <hint type="destinationlabel"> - <x>92</x> - <y>219</y> - </hint> - </hints> - </connection> - <connection> - <sender>profile</sender> - <signal>activated(int)</signal> - <receiver>RecordingOptions</receiver> - <slot>pickProfile(int)</slot> - <hints> - <hint type="sourcelabel"> - <x>92</x> - <y>329</y> - </hint> - <hint type="destinationlabel"> - <x>48</x> - <y>194</y> - </hint> - </hints> - </connection> - <connection> - <sender>args</sender> - <signal>textEdited(QString)</signal> - <receiver>RecordingOptions</receiver> - <slot>storeCustomArgs(QString)</slot> - <hints> - <hint type="sourcelabel"> - <x>128</x> - <y>357</y> - </hint> - <hint type="destinationlabel"> - <x>102</x> - <y>189</y> - </hint> - </hints> - </connection> - </connections> - <slots> - <signal>filePicked(QString)</signal> - <signal>argumentsPicked(QString)</signal> - <slot>pickFile()</slot> - <slot>pickProfile(int)</slot> - <slot>storeCustomArgs(QString)</slot> - </slots> -</ui> diff --git a/tools/qmlviewer/texteditautoresizer_maemo5.h b/tools/qmlviewer/texteditautoresizer_maemo5.h deleted file mode 100644 index 10bf4a1443..0000000000 --- a/tools/qmlviewer/texteditautoresizer_maemo5.h +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 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:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtGui/qplaintextedit.h> -#include <QtGui/qtextedit.h> -#include <QtGui/qscroller.h> -#include <QtGui/qscrollarea.h> -#include <QtDebug> - -#ifndef TEXTEDITAUTORESIZER_H -#define TEXTEDITAUTORESIZER_H - -class TextEditAutoResizer : public QObject -{ - Q_OBJECT -public: - TextEditAutoResizer(QWidget *parent) - : QObject(parent), plainTextEdit(qobject_cast<QPlainTextEdit *>(parent)), - textEdit(qobject_cast<QTextEdit *>(parent)), edit(qobject_cast<QFrame *>(parent)) - { - // parent must either inherit QPlainTextEdit or QTextEdit! - Q_ASSERT(plainTextEdit || textEdit); - - connect(parent, SIGNAL(textChanged()), this, SLOT(textEditChanged())); - connect(parent, SIGNAL(cursorPositionChanged()), this, SLOT(textEditChanged())); - - textEditChanged(); - } - -private Q_SLOTS: - inline void textEditChanged(); - -private: - QPlainTextEdit *plainTextEdit; - QTextEdit *textEdit; - QFrame *edit; -}; - -void TextEditAutoResizer::textEditChanged() -{ - QTextDocument *doc = textEdit ? textEdit->document() : plainTextEdit->document(); - QRect cursor = textEdit ? textEdit->cursorRect() : plainTextEdit->cursorRect(); - - QSize s = doc->size().toSize(); - if (plainTextEdit) - s.setHeight((s.height() + 2) * edit->fontMetrics().lineSpacing()); - - const QRect fr = edit->frameRect(); - const QRect cr = edit->contentsRect(); - - edit->setMinimumHeight(qMax(70, s.height() + (fr.height() - cr.height() - 1))); - - // make sure the cursor is visible in case we have a QAbstractScrollArea parent - QPoint pos = edit->pos(); - QWidget *pw = edit->parentWidget(); - while (pw) { - if (qobject_cast<QScrollArea *>(pw)) - break; - pw = pw->parentWidget(); - } - - if (pw) { - QScrollArea *area = static_cast<QScrollArea *>(pw); - QPoint scrollto = area->widget()->mapFrom(edit, cursor.center()); - QPoint margin(10 + cursor.width(), 2 * cursor.height()); - -#ifdef Q_WS_MAEMO_5 - QScroller::scroller(area)->ensureVisible(scrollto, margin.x(), margin.y()); -#else - area->ensureVisible(scrollto.x(), scrollto.y(), margin.x(), margin.y()); -#endif - } -} - -#endif |