aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2011-06-10 13:50:03 +1000
committerAaron Kennedy <aaron.kennedy@nokia.com>2011-06-10 13:50:03 +1000
commitdc2b89dcb0022f9352932cf09ae716b4ac0dc043 (patch)
treec6f1e352938294e5ff202abb92e3299e74475ec0
parentdb09dd7c820fb612658a08a1617758db277c5b55 (diff)
parent77dfbea79094be6b763319fcca03f6b48ab8248e (diff)
Merge branch 'qtquick2' into v8
-rw-r--r--examples/declarative/dragtarget/dragtarget.qmlproject16
-rw-r--r--examples/declarative/dragtarget/lists/listmodel.qml256
-rw-r--r--examples/declarative/dragtarget/lists/lists.qmlproject16
-rw-r--r--examples/declarative/dragtarget/text/dragtext.qml142
-rw-r--r--examples/declarative/dragtarget/text/text.qmlproject16
-rw-r--r--examples/declarative/dragtarget/tiles/DragTile.qml59
-rw-r--r--examples/declarative/dragtarget/tiles/DropTile.qml30
-rw-r--r--examples/declarative/dragtarget/tiles/tiles.qml85
-rw-r--r--src/declarative/items/items.pri3
-rw-r--r--src/declarative/items/qsgcanvas.cpp97
-rw-r--r--src/declarative/items/qsgcanvas_p.h5
-rw-r--r--src/declarative/items/qsgdragtarget.cpp361
-rw-r--r--src/declarative/items/qsgdragtarget_p.h137
-rw-r--r--src/declarative/items/qsgevent.h137
-rw-r--r--src/declarative/items/qsgitem.cpp42
-rw-r--r--src/declarative/items/qsgitem.h5
-rw-r--r--src/declarative/items/qsgitem_p.h1
-rw-r--r--src/declarative/items/qsgitemsmodule.cpp4
-rw-r--r--src/declarative/items/qsgmousearea.cpp139
-rw-r--r--src/declarative/items/qsgmousearea_p.h32
-rw-r--r--src/declarative/items/qsgmousearea_p_p.h1
-rw-r--r--src/declarative/particles/qsgmodelparticle.cpp43
-rw-r--r--src/declarative/particles/qsgmodelparticle_p.h4
-rw-r--r--src/declarative/qml/qdeclarativecompiler.cpp6
-rw-r--r--src/declarative/util/qdeclarativepixmapcache.cpp1
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/data/NestedComponentRoot.qml6
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/data/nestedComponentRoots.qml4
-rw-r--r--tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp7
-rw-r--r--tests/benchmarks/declarative/declarative.pro1
-rw-r--r--tests/benchmarks/declarative/javascript/data/NestedIdObject.qml9
-rw-r--r--tests/benchmarks/declarative/javascript/data/intQObjectProperty.qml13
-rw-r--r--tests/benchmarks/declarative/javascript/data/localId.qml13
-rw-r--r--tests/benchmarks/declarative/javascript/data/nestedId.qml13
-rw-r--r--tests/benchmarks/declarative/javascript/data/stringQObjectProperty.qml14
-rw-r--r--tests/benchmarks/declarative/javascript/javascript.pro11
-rw-r--r--tests/benchmarks/declarative/javascript/testtypes.cpp48
-rw-r--r--tests/benchmarks/declarative/javascript/testtypes.h65
-rw-r--r--tests/benchmarks/declarative/javascript/tst_javascript.cpp123
38 files changed, 1942 insertions, 23 deletions
diff --git a/examples/declarative/dragtarget/dragtarget.qmlproject b/examples/declarative/dragtarget/dragtarget.qmlproject
new file mode 100644
index 0000000000..d4909f8685
--- /dev/null
+++ b/examples/declarative/dragtarget/dragtarget.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.0
+
+Project {
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ /* List of plugin directories passed to QML runtime */
+ // importPaths: [ " ../exampleplugin " ]
+}
diff --git a/examples/declarative/dragtarget/lists/listmodel.qml b/examples/declarative/dragtarget/lists/listmodel.qml
new file mode 100644
index 0000000000..50b1d397c7
--- /dev/null
+++ b/examples/declarative/dragtarget/lists/listmodel.qml
@@ -0,0 +1,256 @@
+import QtQuick 2.0
+
+
+Rectangle {
+ id: root
+ color: "grey"
+
+ width: 720
+ height: 380
+
+ Component {
+ id: draggedText
+ Text {
+ x: rootTarget.dragX - 10
+ y: rootTarget.dragY - 10
+ width: 20
+ height: 20
+
+ text: rootTarget.dragData.display
+ font.pixelSize: 18
+ }
+ }
+
+ DragTarget {
+ id: rootTarget
+
+ anchors.fill: parent
+ }
+
+ Loader {
+ anchors.fill: parent
+ sourceComponent: rootTarget.containsDrag ? draggedText : undefined
+ }
+
+ GridView {
+ id: gridView
+
+ width: 240
+ height: 360
+
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.margins: 10
+
+ cellWidth: 60
+ cellHeight: 60
+
+ model: ListModel {
+ id: gridModel
+
+ ListElement { display: "1" }
+ ListElement { display: "2" }
+ ListElement { display: "3" }
+ ListElement { display: "4" }
+ ListElement { display: "5" }
+ ListElement { display: "6" }
+ ListElement { display: "7" }
+ ListElement { display: "8" }
+ ListElement { display: "9" }
+ ListElement { display: "10" }
+ ListElement { display: "11" }
+ ListElement { display: "12" }
+ ListElement { display: "13" }
+ ListElement { display: "14" }
+ ListElement { display: "15" }
+ ListElement { display: "16" }
+ ListElement { display: "17" }
+ ListElement { display: "18" }
+ ListElement { display: "19" }
+ ListElement { display: "20" }
+ ListElement { display: "21" }
+ ListElement { display: "22" }
+ ListElement { display: "23" }
+ ListElement { display: "24" }
+ }
+
+ delegate: Rectangle {
+ id: root
+
+ width: 60
+ height: 60
+
+ color: "black"
+
+ Text {
+ anchors.fill: parent
+ color: draggable.drag.active ? "gold" : "white"
+ text: display
+ font.pixelSize: 16
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ MouseArea {
+ id: draggable
+
+ property int initialIndex
+
+ width: 60
+ height: 60
+
+ drag.data: model
+ drag.keys: ["grid"]
+ drag.target: draggable
+
+ states: State {
+ when: !draggable.drag.active
+ PropertyChanges { target: draggable; x: 0; y: 0 }
+ }
+ }
+ }
+
+ DragTarget {
+ anchors.fill: parent
+
+ keys: [ "grid" ]
+ onPositionChanged: {
+ var index = gridView.indexAt(drag.x, drag.y)
+ if (index != -1)
+ gridModel.move(drag.data.index, index, 1)
+ }
+ }
+
+ DragTarget {
+ property int dragIndex
+ anchors.fill: parent
+
+ keys: [ "list" ]
+ onEntered: {
+ dragIndex = gridView.indexAt(drag.x, drag.y)
+ if (dragIndex != -1) {
+ gridModel.insert(dragIndex, { "display": drag.data.display })
+ } else {
+ event.accepted = false
+ }
+ }
+ onPositionChanged: {
+ var index = gridView.indexAt(drag.x, drag.y);
+ if (index != -1) {
+ gridModel.move(dragIndex, index, 1)
+ dragIndex = index
+ }
+ }
+ onExited: gridModel.remove(dragIndex, 1)
+ }
+ }
+
+ ListView {
+ id: listView
+
+ width: 240
+ height: 360
+
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.margins: 10
+
+ model: ListModel {
+ id: listModel
+
+ ListElement { display: "a" }
+ ListElement { display: "b" }
+ ListElement { display: "c" }
+ ListElement { display: "d"}
+ ListElement { display: "e" }
+ ListElement { display: "f" }
+ ListElement { display: "g" }
+ ListElement { display: "h" }
+ ListElement { display: "i" }
+ ListElement { display: "j" }
+ ListElement { display: "k" }
+ ListElement { display: "l" }
+ ListElement { display: "m" }
+ ListElement { display: "n" }
+ ListElement { display: "o" }
+ ListElement { display: "p" }
+ ListElement { display: "q" }
+ ListElement { display: "r" }
+ ListElement { display: "s" }
+ ListElement { display: "t" }
+ ListElement { display: "u" }
+ ListElement { display: "v" }
+ ListElement { display: "w" }
+ ListElement { display: "x" }
+ }
+
+ delegate: Rectangle {
+ id: root
+
+ width: 240
+ height: 15
+
+ color: "black"
+
+ Text {
+ anchors.fill: parent
+ color: draggable.drag.active ? "gold" : "white"
+ text: display
+ font.pixelSize: 12
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ MouseArea {
+ id: draggable
+
+ width: 240
+ height: 15
+
+ drag.data: model
+ drag.keys: ["list"]
+ drag.target: draggable
+
+ states: State {
+ when: !draggable.drag.active
+ PropertyChanges { target: draggable; x: 0; y: 0 }
+ }
+ }
+ }
+
+ DragTarget {
+ anchors.fill: parent
+
+ keys: [ "list" ]
+ onPositionChanged: {
+ var index = listView.indexAt(drag.x, drag.y)
+ if (index != -1)
+ listModel.move(drag.data.index, index, 1)
+ }
+ }
+
+ DragTarget {
+ property int dragIndex
+ anchors.fill: parent
+
+ keys: [ "grid" ]
+
+ onEntered: {
+ dragIndex = listView.indexAt(drag.x, drag.y)
+ if (dragIndex != -1) {
+ listModel.insert(dragIndex, { "display": drag.data.display })
+ } else {
+ event.accepted = false
+ }
+ }
+ onPositionChanged: {
+ var index = listView.indexAt(drag.x, drag.y);
+ if (index != -1) {
+ listModel.move(dragIndex, index, 1)
+ dragIndex = index
+ }
+ }
+ onExited: listModel.remove(dragIndex, 1)
+ }
+ }
+}
diff --git a/examples/declarative/dragtarget/lists/lists.qmlproject b/examples/declarative/dragtarget/lists/lists.qmlproject
new file mode 100644
index 0000000000..d4909f8685
--- /dev/null
+++ b/examples/declarative/dragtarget/lists/lists.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.0
+
+Project {
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ /* List of plugin directories passed to QML runtime */
+ // importPaths: [ " ../exampleplugin " ]
+}
diff --git a/examples/declarative/dragtarget/text/dragtext.qml b/examples/declarative/dragtarget/text/dragtext.qml
new file mode 100644
index 0000000000..c4a4f24f74
--- /dev/null
+++ b/examples/declarative/dragtarget/text/dragtext.qml
@@ -0,0 +1,142 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 320; height: 480
+
+ Rectangle {
+ id: inputRect
+ anchors.left: parent.left; anchors.right: parent.right; anchors.top: parent.top
+ anchors.margins: 2
+ height: input.implicitHeight + 4
+
+ border.width: 1
+
+ TextInput {
+ id: input
+ anchors.fill: parent; anchors.margins: 2
+
+ text: "the quick brown fox jumped over the lazy dog"
+
+ DragTarget {
+ id: inputTarget
+
+ anchors.fill: parent
+
+ Component {
+ id: draggedInputText
+ Text {
+ x: inputTarget.dragX
+ y: inputTarget.dragY
+ text: inputTarget.dragData
+ color: "blue"
+ font: input.font
+ }
+ }
+
+ Loader {
+ sourceComponent: parent.containsDrag ? draggedInputText : undefined
+ }
+ }
+
+
+ MouseArea {
+ id: inputDraggable
+
+ anchors.fill: parent
+ enabled: input.selectionStart != input.selectionEnd
+
+ drag.data: input.selectedText
+ drag.target: inputDraggable
+
+ drag.onDragged: {
+ var position = input.positionAt(mouse.x);
+ mouse.accepted = position >= input.selectionStart && position < input.selectionEnd
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ onPressed: {
+ var position = input.positionAt(mouse.x);
+ if (position < input.selectionStart || position >= input.selectionEnd) {
+ input.cursorPosition = position
+ } else {
+ mouse.accepted = false
+ }
+ }
+ onPositionChanged: input.moveCursorSelection(input.positionAt(mouse.x))
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ id: editRect
+ anchors.left: parent.left; anchors.right: parent.right;
+ anchors.top: inputRect.bottom; anchors.bottom: parent.bottom
+ anchors.margins: 2
+
+ border.width: 1
+
+ TextEdit {
+ id: edit
+ anchors.fill: parent; anchors.margins: 2
+
+ text: "the quick brown fox jumped over the lazy dog"
+ font.pixelSize: 18
+ wrapMode: TextEdit.WordWrap
+
+ DragTarget {
+ id: editTarget
+
+ anchors.fill: parent
+
+
+ Component {
+ id: draggedEditText
+ Text {
+ x: editTarget.dragX
+ y: editTarget.dragY
+ text: editTarget.dragData
+ color: "red"
+ font: edit.font
+ }
+ }
+
+ Loader {
+ sourceComponent: parent.containsDrag ? draggedEditText : undefined
+ }
+ }
+
+ MouseArea {
+ id: editDraggable
+
+ anchors.fill: parent
+ enabled: edit.selectionStart != edit.selectionEnd
+
+ drag.data: edit.selectedText
+ drag.target: editDraggable
+
+ drag.onDragged: {
+ var position = edit.positionAt(mouse.x, mouse.y);
+ mouse.accepted = position >= edit.selectionStart && position < edit.selectionEnd
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ onPressed: {
+ var position = edit.positionAt(mouse.x, mouse.y);
+ if (position < edit.selectionStart || position >= edit.selectionEnd) {
+ edit.cursorPosition = position
+ } else {
+ mouse.accepted = false
+ }
+ }
+ onPositionChanged: edit.moveCursorSelection(edit.positionAt(mouse.x, mouse.y))
+ }
+ }
+ }
+ }
+}
diff --git a/examples/declarative/dragtarget/text/text.qmlproject b/examples/declarative/dragtarget/text/text.qmlproject
new file mode 100644
index 0000000000..d4909f8685
--- /dev/null
+++ b/examples/declarative/dragtarget/text/text.qmlproject
@@ -0,0 +1,16 @@
+import QmlProject 1.0
+
+Project {
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ /* List of plugin directories passed to QML runtime */
+ // importPaths: [ " ../exampleplugin " ]
+}
diff --git a/examples/declarative/dragtarget/tiles/DragTile.qml b/examples/declarative/dragtarget/tiles/DragTile.qml
new file mode 100644
index 0000000000..213373a392
--- /dev/null
+++ b/examples/declarative/dragtarget/tiles/DragTile.qml
@@ -0,0 +1,59 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: dragRectangle
+
+ property Item dropTarget
+
+ property string colorKey
+
+ color: colorKey
+
+ width: 100; height: 100
+
+ Text {
+ anchors.fill: parent
+ color: "white"
+ font.pixelSize: 90
+ text: modelData + 1
+ horizontalAlignment:Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ MouseArea {
+ id: draggable
+
+ anchors.fill: parent
+
+ drag.target: parent
+ drag.keys: [ colorKey ]
+
+ drag.onDropped: dropTarget = dropItem
+
+ states: [
+ State {
+ when: dragRectangle.dropTarget != undefined && !draggable.drag.active
+ ParentChange {
+ target: dragRectangle
+ parent: dropTarget
+ x: 0
+ y: 0
+ }
+ },
+ State {
+ when: dragRectangle.dropTarget != undefined && draggable.drag.active
+ ParentChange {
+ target: dragRectangle
+ parent: dropTarget
+ }
+ },
+ State {
+ when: !draggable.drag.active
+ AnchorChanges {
+ target: dragRectangle
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+ ]
+ }
+}
diff --git a/examples/declarative/dragtarget/tiles/DropTile.qml b/examples/declarative/dragtarget/tiles/DropTile.qml
new file mode 100644
index 0000000000..9d968753db
--- /dev/null
+++ b/examples/declarative/dragtarget/tiles/DropTile.qml
@@ -0,0 +1,30 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: dropRectangle
+
+ property string colorKey
+
+ color: colorKey
+
+ width: 100; height: 100
+
+ DragTarget {
+ id: dragTarget
+
+ anchors.fill: parent
+
+ keys: [ colorKey ]
+ dropItem: dropRectangle
+ }
+
+ states: [
+ State {
+ when: dragTarget.containsDrag
+ PropertyChanges {
+ target: dropRectangle
+ color: "grey"
+ }
+ }
+ ]
+}
diff --git a/examples/declarative/dragtarget/tiles/tiles.qml b/examples/declarative/dragtarget/tiles/tiles.qml
new file mode 100644
index 0000000000..d8bcb39bd2
--- /dev/null
+++ b/examples/declarative/dragtarget/tiles/tiles.qml
@@ -0,0 +1,85 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+
+ width: 620
+ height: 410
+
+ color: "black"
+
+ DragTarget {
+ id: resetTarget
+
+ anchors.fill: parent
+ }
+
+ Grid {
+ id: redDestination
+
+ anchors.left: redSource.right; anchors.top: parent.top;
+ anchors.margins: 5
+ width: 300
+ height: 300
+
+ opacity: 0.5
+
+ columns: 3
+
+ Repeater {
+ model: 9
+ delegate: DropTile {
+ colorKey: "red"
+ }
+ }
+ }
+
+ Grid {
+ id: blueDestination
+
+ anchors.right: blueSource.left; anchors.bottom: parent.bottom;
+ anchors.margins: 5
+ width: 300
+ height: 300
+
+ opacity: 0.5
+
+ columns: 3
+
+ Repeater {
+ model: 9
+ delegate: DropTile {
+ colorKey: "blue"
+ }
+ }
+ }
+
+ Column {
+ id: redSource
+
+ anchors.left: parent.left; anchors.top: parent.top; anchors.bottom: parent.bottom
+ anchors.margins: 5
+ width: 100
+
+ Repeater {
+ model: 9
+ delegate: DragTile {
+ colorKey: "red"
+ }
+ }
+ }
+ Column {
+ id: blueSource
+
+ anchors.right: parent.right; anchors.top: parent.top; anchors.bottom: parent.bottom
+ anchors.margins: 5
+ width: 100
+
+ Repeater {
+ model: 9
+ delegate: DragTile {
+ colorKey: "blue"
+ }
+ }
+ }
+}
diff --git a/src/declarative/items/items.pri b/src/declarative/items/items.pri
index f29a82e77e..bf92025b75 100644
--- a/src/declarative/items/items.pri
+++ b/src/declarative/items/items.pri
@@ -64,6 +64,8 @@ HEADERS += \
$$PWD/qsgspriteengine_p.h \
$$PWD/qsgsprite_p.h \
$$PWD/qsgspriteimage_p.h \
+ $$PWD/qsgevent.h \
+ $$PWD/qsgdragtarget_p.h \
SOURCES += \
$$PWD/qsgevents.cpp \
@@ -106,6 +108,7 @@ SOURCES += \
$$PWD/qsgspriteengine.cpp \
$$PWD/qsgsprite.cpp \
$$PWD/qsgspriteimage.cpp \
+ $$PWD/qsgdragtarget.cpp \
SOURCES += \
$$PWD/qsgshadereffectitem.cpp \
diff --git a/src/declarative/items/qsgcanvas.cpp b/src/declarative/items/qsgcanvas.cpp
index dce5fe0888..3a88fbb790 100644
--- a/src/declarative/items/qsgcanvas.cpp
+++ b/src/declarative/items/qsgcanvas.cpp
@@ -45,6 +45,8 @@
#include "qsgitem.h"
#include "qsgitem_p.h"
+#include "qsgevent.h"
+
#include <private/qsgrenderer_p.h>
#include <private/qsgflashnode_p.h>
@@ -987,6 +989,12 @@ bool QSGCanvas::event(QEvent *e)
d->clearHover();
d->lastMousePosition = QPoint();
break;
+ case QSGEvent::SGDragEnter:
+ case QSGEvent::SGDragExit:
+ case QSGEvent::SGDragMove:
+ case QSGEvent::SGDragDrop:
+ d->deliverDragEvent(static_cast<QSGDragEvent *>(e));
+ break;
default:
break;
}
@@ -1446,6 +1454,78 @@ bool QSGCanvasPrivate::deliverTouchPoints(QSGItem *item, QTouchEvent *event, con
return false;
}
+void QSGCanvasPrivate::deliverDragEvent(QSGDragEvent *event)
+{
+ Q_Q(QSGCanvas);
+ if (event->type() == QSGEvent::SGDragExit || event->type() == QSGEvent::SGDragDrop) {
+ if (QSGItem *grabItem = event->grabItem()) {
+ event->setPosition(grabItem->mapFromScene(event->scenePosition()));
+ q->sendEvent(grabItem, event);
+ }
+ } else if (!deliverDragEvent(rootItem, event)) {
+ if (QSGItem *grabItem = event->grabItem()) {
+ QSGDragEvent exitEvent(QSGEvent::SGDragExit, *event);
+ exitEvent.setPosition(grabItem->mapFromScene(event->scenePosition()));
+ q->sendEvent(grabItem, &exitEvent);
+ event->setDropItem(0);
+ event->setGrabItem(0);
+ }
+ event->setAccepted(false);
+ }
+}
+
+bool QSGCanvasPrivate::deliverDragEvent(QSGItem *item, QSGDragEvent *event)
+{
+ Q_Q(QSGCanvas);
+ QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
+ if (itemPrivate->opacity == 0.0)
+ return false;
+
+ if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
+ QPointF p = item->mapFromScene(event->scenePosition());
+ if (!QRectF(0, 0, item->width(), item->height()).contains(p))
+ return false;
+ }
+
+ QList<QSGItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QSGItem *child = children.at(ii);
+ if (!child->isVisible() || !child->isEnabled())
+ continue;
+ if (deliverDragEvent(child, event))
+ return true;
+ }
+
+ QPointF p = item->mapFromScene(event->scenePosition());
+ if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
+ event->setPosition(p);
+
+ if (event->type() == QSGEvent::SGDragMove && item != event->grabItem()) {
+ QSGDragEvent enterEvent(QSGEvent::SGDragEnter, *event);
+ q->sendEvent(item, &enterEvent);
+ if (enterEvent.isAccepted()) {
+ if (QSGItem *grabItem = event->grabItem()) {
+ QSGDragEvent exitEvent(QSGEvent::SGDragExit, *event);
+ q->sendEvent(grabItem, &exitEvent);
+ }
+ event->setDropItem(enterEvent.dropItem());
+ event->setGrabItem(item);
+ } else {
+ return false;
+ }
+ }
+
+ q->sendEvent(item, event);
+ if (event->isAccepted()) {
+ event->setGrabItem(item);
+ return true;
+ }
+ event->setAccepted(true);
+ }
+
+ return false;
+}
+
bool QSGCanvasPrivate::sendFilteredMouseEvent(QSGItem *target, QSGItem *item, QGraphicsSceneMouseEvent *event)
{
if (!target)
@@ -1521,6 +1601,12 @@ bool QSGCanvas::sendEvent(QSGItem *item, QEvent *e)
case QEvent::TouchEnd:
QSGItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
break;
+ case QSGEvent::SGDragEnter:
+ case QSGEvent::SGDragExit:
+ case QSGEvent::SGDragMove:
+ case QSGEvent::SGDragDrop:
+ QSGItemPrivate::get(item)->deliverDragEvent(static_cast<QSGDragEvent *>(e));
+ break;
default:
break;
}
@@ -1804,7 +1890,14 @@ void QSGCanvas::maybeUpdate()
Q_D(QSGCanvas);
if (d->threadedRendering && d->thread && d->thread->isRunning()) {
- if (!d->renderThreadAwakened) {
+ Q_ASSERT_X(QThread::currentThread() == QApplication::instance()->thread() || d->thread->inSync,
+ "QSGCanvas::update",
+ "Function can only be called from GUI thread or during QSGItem::updatePaintNode()");
+
+ if (d->thread->inSync) {
+ d->thread->isExternalUpdatePending = true;
+
+ } else if (!d->renderThreadAwakened) {
#ifdef THREAD_DEBUG
printf("GUI: doing update...\n");
#endif
@@ -1911,7 +2004,9 @@ void QSGCanvasRenderThread::run()
#ifdef THREAD_DEBUG
printf(" RenderThread: Doing locked sync\n");
#endif
+ inSync = true;
d->syncSceneGraph();
+ inSync = false;
// Wake GUI after sync to let it continue animating and event processing.
wake();
diff --git a/src/declarative/items/qsgcanvas_p.h b/src/declarative/items/qsgcanvas_p.h
index 87fae1c31a..9b2683cc38 100644
--- a/src/declarative/items/qsgcanvas_p.h
+++ b/src/declarative/items/qsgcanvas_p.h
@@ -55,6 +55,7 @@
#include "qsgitem.h"
#include "qsgcanvas.h"
+#include "qsgevent.h"
#include <private/qdeclarativeguard_p.h>
#include <private/qsgcontext_p.h>
@@ -116,6 +117,8 @@ public:
bool deliverHoverEvent(QSGItem *, QGraphicsSceneHoverEvent *);
void sendHoverEvent(QEvent::Type, QSGItem *, QGraphicsSceneHoverEvent *);
void clearHover();
+ void deliverDragEvent(QSGDragEvent *);
+ bool deliverDragEvent(QSGItem *item, QSGDragEvent *);
QDeclarativeGuard<QSGItem> hoverItem;
enum FocusOption {
@@ -180,6 +183,7 @@ public:
, isRenderBlocked(false)
, isExternalUpdatePending(false)
, syncAlreadyHappened(false)
+ , inSync(false)
, doGrab(false)
, shouldExit(false)
, hasExited(false)
@@ -222,6 +226,7 @@ public:
uint isRenderBlocked : 1;
uint isExternalUpdatePending : 1;
uint syncAlreadyHappened : 1;
+ uint inSync : 1;
uint doGrab : 1;
uint shouldExit : 1;
diff --git a/src/declarative/items/qsgdragtarget.cpp b/src/declarative/items/qsgdragtarget.cpp
new file mode 100644
index 0000000000..c1ed167ee6
--- /dev/null
+++ b/src/declarative/items/qsgdragtarget.cpp
@@ -0,0 +1,361 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdragtarget_p.h"
+#include "qsgitem_p.h"
+#include "qsgcanvas.h"
+
+/*!
+ \qmlclass DragEvent QSGDragEvent
+ \brief The DragEvent object provides information about a drag event.
+
+ The position of the drag event can be obtained from the \l x and \l
+ properties, the \l keys property identifies the drag keys of the event
+ source and the \l data property contains the payload of the drag event.
+*/
+
+/*!
+ \qmlproperty real DragEvent::x
+
+ This property holds the x coordinate of a drag event.
+*/
+
+/*!
+ \qmlproperty real DragEvent::y
+
+ This property holds the y coordinate of a drag event.
+*/
+
+/*!
+ \qmlproperty stringlist DragEvent::keys
+
+ This property holds a list of keys identifying the data type or source of a
+ drag event.
+*/
+
+/*!
+ \qmlproperty variant DragEvent::data
+
+ This property holds data payload of a drag event.
+*/
+
+/*!
+ \qmlproperty real DragEvent::accepted
+
+ This property holds whether the drag event was accepted by a handler.
+
+ The default value is true.
+*/
+
+class QSGDragTargetPrivate : public QSGItemPrivate
+{
+ Q_DECLARE_PUBLIC(QSGDragTarget)
+
+public:
+ QSGDragTargetPrivate();
+ ~QSGDragTargetPrivate();
+
+ bool hasMatchingKey(const QStringList &keys) const;
+
+ QStringList keys;
+ QRegExp keyRegExp;
+ QVariant dragData;
+ QPointF dragPosition;
+ QSGItem *dropItem;
+ bool containsDrag : 1;
+};
+
+QSGDragTargetPrivate::QSGDragTargetPrivate()
+ : dropItem(0)
+ , containsDrag(false)
+{
+}
+
+QSGDragTargetPrivate::~QSGDragTargetPrivate()
+{
+}
+
+/*!
+ \qmlclass DragTarget QSGDragTarget
+ \brief The DragTarget item provides drag and drop handling.
+
+ A DragTarget is an invisible item which receives events when another item
+ is dragged over it.
+
+ A MouseArea item can be used to drag items.
+
+ The \l keys property can be used to filter drag events which don't include
+ a matching key.
+
+ The \l dropItem property is communicated to the source of a drag event as
+ the recipient of a drop on the drag target.
+
+ The \l delegate property provides a means to specify a component to be
+ instantiated for each active drag over a drag target.
+*/
+
+QSGDragTarget::QSGDragTarget(QSGItem *parent)
+ : QSGItem(*new QSGDragTargetPrivate, parent)
+{
+}
+
+QSGDragTarget::~QSGDragTarget()
+{
+}
+
+/*!
+ \qmlproperty bool DragTarget::containsDrag
+
+ This property identifies whether the DragTarget currently contains any
+ dragged items.
+*/
+
+bool QSGDragTarget::containsDrag() const
+{
+ Q_D(const QSGDragTarget);
+ return d->containsDrag;
+}
+
+/*!
+ \qmlproperty stringlist DragTarget::keys
+
+ This property holds a list of drag keys a DragTarget will accept.
+*/
+
+QStringList QSGDragTarget::keys() const
+{
+ Q_D(const QSGDragTarget);
+ return d->keys;
+}
+
+void QSGDragTarget::setKeys(const QStringList &keys)
+{
+ Q_D(QSGDragTarget);
+ if (d->keys != keys) {
+ d->keys = keys;
+
+ if (keys.isEmpty()) {
+ d->keyRegExp = QRegExp();
+ } else {
+ QString pattern = QLatin1Char('(') + QRegExp::escape(keys.first());
+ for (int i = 1; i < keys.count(); ++i)
+ pattern += QLatin1Char('|') + QRegExp::escape(keys.at(i));
+ pattern += QLatin1Char(')');
+ d->keyRegExp = QRegExp(pattern.replace(QLatin1String("\\*"), QLatin1String(".+")));
+ }
+ emit keysChanged();
+ }
+}
+
+/*!
+ \qmlproperty Item DragTarget::dropItem
+
+ This property identifies an item as the recipient of a drop event within
+ a DragTarget.
+
+ \sa MouseArea::drag.dropItem
+*/
+
+QSGItem *QSGDragTarget::dropItem() const
+{
+ Q_D(const QSGDragTarget);
+ return d->dropItem;
+}
+
+void QSGDragTarget::setDropItem(QSGItem *item)
+{
+ Q_D(QSGDragTarget);
+ if (d->dropItem != item) {
+ d->dropItem = item;
+ emit dropItemChanged();
+ }
+}
+
+void QSGDragTarget::resetDropItem()
+{
+ Q_D(QSGDragTarget);
+ if (d->dropItem) {
+ d->dropItem = 0;
+ emit dropItemChanged();
+ }
+}
+
+qreal QSGDragTarget::dragX() const
+{
+ Q_D(const QSGDragTarget);
+ return d->dragPosition.x();
+}
+
+qreal QSGDragTarget::dragY() const
+{
+ Q_D(const QSGDragTarget);
+ return d->dragPosition.y();
+}
+
+QVariant QSGDragTarget::dragData() const
+{
+ Q_D(const QSGDragTarget);
+ return d->dragData;
+}
+
+/*!
+ \qmlsignal DragTarget::onPositionChanged(DragEvent drag)
+ \qmlattachedsignal DragTarget::onPositionChanged(DragEvent drag)
+
+ This handler is called when the position of a drag has changed.
+*/
+
+void QSGDragTarget::dragMoveEvent(QSGDragEvent *event)
+{
+ Q_D(QSGDragTarget);
+ if (!d->containsDrag) {
+ event->setAccepted(false);
+ return;
+ }
+
+ event->setDropItem(d->dropItem);
+
+ d->dragPosition = event->position();
+ emit dragPositionChanged();
+
+ QSGDragTargetEvent dragTargetEvent(event);
+ emit positionChanged(&dragTargetEvent);
+}
+
+bool QSGDragTargetPrivate::hasMatchingKey(const QStringList &keys) const
+{
+ if (keyRegExp.isEmpty())
+ return true;
+
+ foreach (const QString &key, keys) {
+ if (keyRegExp.exactMatch(key))
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \qmlsignal DragTarget::onEntered(DragEvent drag)
+ \qmlattachedsignal DragTarget::onEntered(DragEvent drag)
+
+ This handler is called when a drag enters the bounds of a DragTarget.
+*/
+
+void QSGDragTarget::dragEnterEvent(QSGDragEvent *event)
+{
+ Q_D(QSGDragTarget);
+ if (!d->effectiveEnable || !d->hasMatchingKey(event->keys()) || d->containsDrag) {
+ event->setAccepted(false);
+ return;
+ }
+
+ event->setDropItem(d->dropItem);
+
+ QSGDragTargetEvent dragTargetEvent(event);
+ emit entered(&dragTargetEvent);
+
+ if (event->isAccepted()) {
+
+ d->dragData = event->data();
+ d->containsDrag = true;
+ if (!d->dragData.isNull())
+ emit dragDataChanged();
+ emit containsDragChanged();
+ }
+}
+
+/*!
+ \qmlsignal DragTarget::onExited(DragEvent drag)
+ \qmlattachedsignal DragTarget::onExited(DragEvent drag)
+
+ This handler is called when a drag exits the bounds of a DragTarget.
+*/
+
+void QSGDragTarget::dragExitEvent(QSGDragEvent *event)
+{
+ Q_D(QSGDragTarget);
+ if (!d->containsDrag) {
+ event->setAccepted(false);
+ return;
+ }
+
+ QSGDragTargetEvent dragTargetEvent(event);
+ emit exited(&dragTargetEvent);
+
+ d->containsDrag = false;
+ emit containsDragChanged();
+ if (!d->dragData.isNull()) {
+ d->dragData = QVariant();
+ emit dragDataChanged();
+ }
+}
+
+/*!
+ \qmlsignal DragTarget::onDropped(DragEvent drag)
+ \qmlattachedsignal DragTarget::onDropped(DragEvent drag)
+
+ This handler is called when a drop event occurs within the bounds of a
+ a DragTarget.
+*/
+
+void QSGDragTarget::dragDropEvent(QSGDragEvent *event)
+{
+ Q_D(QSGDragTarget);
+ if (!d->containsDrag) {
+ event->setAccepted(false);
+ return;
+ }
+
+ event->setDropItem(d->dropItem);
+
+ QSGDragTargetEvent dragTargetEvent(event);
+ emit dropped(&dragTargetEvent);
+
+ d->containsDrag = false;
+ emit containsDragChanged();
+ if (!d->dragData.isNull()) {
+ d->dragData = QVariant();
+ emit dragDataChanged();
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/declarative/items/qsgdragtarget_p.h b/src/declarative/items/qsgdragtarget_p.h
new file mode 100644
index 0000000000..ad13e11854
--- /dev/null
+++ b/src/declarative/items/qsgdragtarget_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGDRAGTARGET_P_H
+#define QSGDRAGTARGET_P_H
+
+#include "qsgitem.h"
+#include "qsgevent.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGDragTargetEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal x READ x)
+ Q_PROPERTY(qreal y READ y)
+ Q_PROPERTY(QVariant data READ data)
+ Q_PROPERTY(QStringList keys READ keys)
+ Q_PROPERTY(bool accepted READ accepted WRITE setAccepted)
+public:
+ QSGDragTargetEvent(QSGDragEvent *event) : _event(event) {}
+
+ qreal x() const { return _event->x(); }
+ qreal y() const { return _event->y(); }
+
+ QVariant data() const { return _event->data(); }
+ QStringList keys() const { return _event->keys(); }
+
+ bool accepted() const { return _event->isAccepted(); }
+ void setAccepted(bool accepted) { _event->setAccepted(accepted); }
+
+private:
+ QSGDragEvent *_event;
+};
+
+class QSGDragTargetPrivate;
+class Q_AUTOTEST_EXPORT QSGDragTarget : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool containsDrag READ containsDrag NOTIFY containsDragChanged)
+ Q_PROPERTY(QSGItem *dropItem READ dropItem WRITE setDropItem NOTIFY dropItemChanged RESET resetDropItem)
+ Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged)
+ Q_PROPERTY(qreal dragX READ dragX NOTIFY dragPositionChanged)
+ Q_PROPERTY(qreal dragY READ dragY NOTIFY dragPositionChanged)
+ Q_PROPERTY(QVariant dragData READ dragData NOTIFY dragDataChanged)
+
+public:
+ QSGDragTarget(QSGItem *parent=0);
+ ~QSGDragTarget();
+
+ bool containsDrag() const;
+ void setContainsDrag(bool drag);
+
+ QStringList keys() const;
+ void setKeys(const QStringList &keys);
+
+ QSGItem *dropItem() const;
+ void setDropItem(QSGItem *item);
+ void resetDropItem();
+
+ qreal dragX() const;
+ qreal dragY() const;
+ QVariant dragData() const;
+
+Q_SIGNALS:
+ void containsDragChanged();
+ void keysChanged();
+ void dropItemChanged();
+ void dragPositionChanged();
+ void dragDataChanged();
+
+ void entered(QSGDragTargetEvent *drag);
+ void exited(QSGDragTargetEvent *drag);
+ void positionChanged(QSGDragTargetEvent *drag);
+ void dropped(QSGDragTargetEvent *drag);
+
+protected:
+ void dragMoveEvent(QSGDragEvent *event);
+ void dragEnterEvent(QSGDragEvent *event);
+ void dragExitEvent(QSGDragEvent *event);
+ void dragDropEvent(QSGDragEvent *event);
+
+private:
+ Q_DISABLE_COPY(QSGDragTarget)
+ Q_DECLARE_PRIVATE(QSGDragTarget)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QSGDragTargetEvent)
+QML_DECLARE_TYPE(QSGDragTarget)
+
+QT_END_HEADER
+
+#endif // QSGDRAGTARGET_P_H
diff --git a/src/declarative/items/qsgevent.h b/src/declarative/items/qsgevent.h
new file mode 100644
index 0000000000..93b53d1312
--- /dev/null
+++ b/src/declarative/items/qsgevent.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDRAGEVENT_H
+#define QDRAGEVENT_H
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qnamespace.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+
+class Q_DECLARATIVE_EXPORT QSGEvent : public QEvent
+{
+public:
+ // XXX: Merge types into QEvent or formally reserve a suitable range.
+ // Alternatively start from QEvent::User and add a SGUser value for use by items.
+ enum SGType
+ {
+ SGDragEnter = 600,
+ SGDragExit,
+ SGDragMove,
+ SGDragDrop
+ };
+
+ QSGEvent(QSGEvent::SGType type) : QEvent(Type(type)) {}
+
+ SGType type() const { return SGType(QEvent::type()); }
+};
+
+class Q_DECLARATIVE_EXPORT QSGDragEvent : public QSGEvent
+{
+public:
+ QSGDragEvent(
+ SGType type,
+ const QPointF &scenePosition,
+ const QVariant &data,
+ const QStringList &keys,
+ QSGItem *grabItem = 0)
+ : QSGEvent(type)
+ , _scenePosition(scenePosition),
+ _data(data)
+ , _keys(keys)
+ , _dropItem(0)
+ , _grabItem(grabItem)
+ {
+ }
+ QSGDragEvent(SGType type, const QSGDragEvent &event)
+ : QSGEvent(type)
+ , _scenePosition(event._scenePosition)
+ , _position(event._position)
+ , _data(event._data)
+ , _keys(event._keys)
+ , _dropItem(event._dropItem)
+ , _grabItem(event._grabItem)
+ {
+ }
+
+ QVariant data() const { return _data; }
+
+ qreal x() const { return _position.x(); }
+ qreal y() const { return _position.y(); }
+ QPointF position() const { return _position; }
+ void setPosition(const QPointF &position) { _position = position; }
+
+ QPointF scenePosition() const { return _scenePosition; }
+
+ QStringList keys() const { return _keys; }
+
+ QSGItem *dropItem() const { return _dropItem; }
+ void setDropItem(QSGItem *dropItem) { _dropItem = dropItem; }
+
+ QSGItem *grabItem() const { return _grabItem; }
+ void setGrabItem(QSGItem *item) { _grabItem = item; }
+
+private:
+ QPointF _scenePosition;
+ QPointF _position;
+ QVariant _data;
+ QStringList _keys;
+ QSGItem *_dropItem;
+ QSGItem *_grabItem;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
+
diff --git a/src/declarative/items/qsgitem.cpp b/src/declarative/items/qsgitem.cpp
index bb3ad8a2ca..9826e0f2c1 100644
--- a/src/declarative/items/qsgitem.cpp
+++ b/src/declarative/items/qsgitem.cpp
@@ -45,6 +45,7 @@
#include "qsgcanvas.h"
#include <QtScript/qscriptengine.h>
#include "qsgcanvas_p.h"
+#include "qsgevent.h"
#include "qsgevents_p_p.h"
@@ -1689,6 +1690,26 @@ void QSGItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
Q_UNUSED(event);
}
+void QSGItem::dragMoveEvent(QSGDragEvent *event)
+{
+ event->setAccepted(false);
+}
+
+void QSGItem::dragEnterEvent(QSGDragEvent *event)
+{
+ event->setAccepted(false);
+}
+
+void QSGItem::dragExitEvent(QSGDragEvent *event)
+{
+ event->setAccepted(false);
+}
+
+void QSGItem::dragDropEvent(QSGDragEvent *event)
+{
+ event->setAccepted(false);
+}
+
bool QSGItem::childMouseEventFilter(QSGItem *, QEvent *)
{
return false;
@@ -2177,6 +2198,27 @@ void QSGItemPrivate::deliverHoverEvent(QGraphicsSceneHoverEvent *e)
}
}
+void QSGItemPrivate::deliverDragEvent(QSGDragEvent *e)
+{
+ Q_Q(QSGItem);
+ switch (e->type()) {
+ default:
+ Q_ASSERT(!"Unknown event type");
+ case QSGEvent::SGDragEnter:
+ q->dragEnterEvent(e);
+ break;
+ case QSGEvent::SGDragExit:
+ q->dragExitEvent(e);
+ break;
+ case QSGEvent::SGDragMove:
+ q->dragMoveEvent(e);
+ break;
+ case QSGEvent::SGDragDrop:
+ q->dragDropEvent(e);
+ break;
+ }
+}
+
void QSGItem::itemChange(ItemChange change, const ItemChangeData &value)
{
Q_UNUSED(change);
diff --git a/src/declarative/items/qsgitem.h b/src/declarative/items/qsgitem.h
index a4420b2af5..91028148c4 100644
--- a/src/declarative/items/qsgitem.h
+++ b/src/declarative/items/qsgitem.h
@@ -89,6 +89,7 @@ class QSGKeyEvent;
class QSGAnchors;
class QSGItemPrivate;
class QSGCanvas;
+class QSGDragEvent;
class QSGEngine;
class QTouchEvent;
class QSGNode;
@@ -363,6 +364,10 @@ protected:
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void dragMoveEvent(QSGDragEvent *event);
+ virtual void dragEnterEvent(QSGDragEvent *event);
+ virtual void dragExitEvent(QSGDragEvent *event);
+ virtual void dragDropEvent(QSGDragEvent *event);
virtual bool childMouseEventFilter(QSGItem *, QEvent *);
virtual void geometryChanged(const QRectF &newGeometry,
diff --git a/src/declarative/items/qsgitem_p.h b/src/declarative/items/qsgitem_p.h
index 0f4a3213b4..300ccdc49e 100644
--- a/src/declarative/items/qsgitem_p.h
+++ b/src/declarative/items/qsgitem_p.h
@@ -324,6 +324,7 @@ public:
void deliverWheelEvent(QGraphicsSceneWheelEvent *);
void deliverTouchEvent(QTouchEvent *);
void deliverHoverEvent(QGraphicsSceneHoverEvent *);
+ void deliverDragEvent(QSGDragEvent *);
bool calcEffectiveVisible() const;
void setEffectiveVisibleRecur(bool);
diff --git a/src/declarative/items/qsgitemsmodule.cpp b/src/declarative/items/qsgitemsmodule.cpp
index a29776fc68..f1e3a0cb91 100644
--- a/src/declarative/items/qsgitemsmodule.cpp
+++ b/src/declarative/items/qsgitemsmodule.cpp
@@ -77,6 +77,7 @@
#include "qsgcontext2d_p.h"
#include "qsgsprite_p.h"
#include "qsgspriteimage_p.h"
+#include "qsgdragtarget_p.h"
static QDeclarativePrivate::AutoParentResult qsgitem_autoParent(QObject *obj, QObject *parent)
{
@@ -189,6 +190,9 @@ static void qt_sgitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QSGAnchorSet>();
qmlRegisterType<QSGAnchorAnimation>(uri, major, minor,"AnchorAnimation");
qmlRegisterType<QSGParentAnimation>(uri, major, minor,"ParentAnimation");
+
+ qmlRegisterType<QSGDragTarget>("QtQuick", 2, 0, "DragTarget");
+ qmlRegisterType<QSGDragTargetEvent>();
}
void QSGItemsModule::defineModule()
diff --git a/src/declarative/items/qsgmousearea.cpp b/src/declarative/items/qsgmousearea.cpp
index 887d78a64d..6b4311e698 100644
--- a/src/declarative/items/qsgmousearea.cpp
+++ b/src/declarative/items/qsgmousearea.cpp
@@ -43,6 +43,7 @@
#include "qsgmousearea_p.h"
#include "qsgmousearea_p_p.h"
#include "qsgcanvas.h"
+#include "qsgevent.h"
#include "qsgevents_p_p.h"
#include <QtGui/qgraphicssceneevent.h>
@@ -54,8 +55,8 @@ QT_BEGIN_NAMESPACE
static const int PressAndHoldDelay = 800;
QSGDrag::QSGDrag(QObject *parent)
-: QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX), _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX),
-_active(false), _filterChildren(false)
+: QObject(parent), _target(0), _dropItem(0), _grabItem(0), _axis(XandYAxis), _xmin(-FLT_MAX),
+_xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false)
{
}
@@ -78,12 +79,70 @@ void QSGDrag::setTarget(QSGItem *t)
void QSGDrag::resetTarget()
{
- if (!_target)
+ if (_target == 0)
return;
_target = 0;
emit targetChanged();
}
+/*!
+ \qmlproperty Item MouseArea::drag.dropItem
+
+ This property holds the item an active drag will be dropped on if released
+ at the current position.
+*/
+
+QSGItem *QSGDrag::dropItem() const
+{
+ return _dropItem;
+}
+
+void QSGDrag::setDropItem(QSGItem *item)
+{
+ if (_dropItem != item) {
+ _dropItem = item;
+ emit dropItemChanged();
+ }
+}
+
+QSGItem *QSGDrag::grabItem() const
+{
+ return _grabItem;
+}
+
+void QSGDrag::setGrabItem(QSGItem *item)
+{
+ _grabItem = item;
+}
+
+/*!
+ \qmlproperty variant MouseArea::drag.data
+
+ This property holds the data sent to recipients of drag events generated
+ by a MouseArea.
+*/
+
+QVariant QSGDrag::data() const
+{
+ return _data;
+}
+
+void QSGDrag::setData(const QVariant &data)
+{
+ if (_data != data) {
+ _data = data;
+ emit dataChanged();
+ }
+}
+
+void QSGDrag::resetData()
+{
+ if (!_data.isNull()) {
+ _data = QVariant();
+ emit dataChanged();
+ }
+}
+
QSGDrag::Axis QSGDrag::axis() const
{
return _axis;
@@ -175,9 +234,30 @@ void QSGDrag::setFilterChildren(bool filter)
emit filterChildrenChanged();
}
+/*!
+ \qmlproperty stringlist MouseArea::drag.keys
+
+ This property holds a list of keys drag recipients can use to identify the
+ source or data type of a drag event.
+*/
+
+QStringList QSGDrag::keys() const
+{
+ return _keys;
+}
+
+void QSGDrag::setKeys(const QStringList &keys)
+{
+ if (_keys != keys) {
+ _keys = keys;
+ emit keysChanged();
+ }
+}
+
QSGMouseAreaPrivate::QSGMouseAreaPrivate()
: absorb(true), hovered(false), pressed(false), longPress(false),
- moved(false), stealMouse(false), doubleClick(false), preventStealing(false), drag(0)
+ moved(false), stealMouse(false), doubleClick(false), preventStealing(false), dragRejected(false),
+ drag(0)
{
Q_Q(QSGMouseArea);
forwardTo = QDeclarativeListProperty<QSGItem>(q, forwardToList);
@@ -384,6 +464,7 @@ void QSGMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
QSGItem::mousePressEvent(event);
else {
d->longPress = false;
+ d->dragRejected = false;
d->saveEvent(event);
if (d->drag) {
d->dragX = drag()->axis() & QSGDrag::XAxis;
@@ -440,8 +521,24 @@ void QSGMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
- if (keepMouseGrab() && d->stealMouse)
- d->drag->setActive(true);
+ if (keepMouseGrab() && d->stealMouse && !d->dragRejected && !d->drag->active()) {
+ QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ d->drag->emitDragged(&me);
+ if (me.isAccepted()) {
+ d->drag->setActive(true);
+ QSGDragEvent dragEvent(
+ QSGEvent::SGDragEnter,
+ d->startScene,
+ d->drag->data(),
+ d->drag->keys());
+ QCoreApplication::sendEvent(canvas(), &dragEvent);
+
+ d->drag->setGrabItem(dragEvent.grabItem());
+ d->drag->setDropItem(dragEvent.dropItem());
+ } else {
+ d->dragRejected = true;
+ }
+ }
if (d->dragX && d->drag->active()) {
qreal x = (curLocalPos.x() - startLocalPos.x()) + d->startX;
@@ -470,6 +567,18 @@ void QSGMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
}
d->moved = true;
+
+ if (d->drag->active()) {
+ QSGDragEvent dragEvent(
+ QSGEvent::SGDragMove,
+ event->scenePos(),
+ d->drag->data(),
+ d->drag->keys(),
+ d->drag->grabItem());
+ QCoreApplication::sendEvent(canvas(), &dragEvent);
+ d->drag->setGrabItem(dragEvent.grabItem());
+ d->drag->setDropItem(dragEvent.dropItem());
+ }
}
QSGMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
emit mousePositionChanged(&me);
@@ -490,8 +599,24 @@ void QSGMouseArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
} else {
d->saveEvent(event);
setPressed(false);
- if (d->drag)
+ if (d->drag && d->drag->active()) {
+ QSGDragEvent dragEvent(
+ QSGEvent::SGDragDrop,
+ event->scenePos(),
+ d->drag->data(),
+ d->drag->keys(),
+ d->drag->grabItem());
+ QCoreApplication::sendEvent(canvas(), &dragEvent);
+ d->drag->setGrabItem(0);
+ if (dragEvent.isAccepted()) {
+ d->drag->setDropItem(dragEvent.dropItem());
+ d->drag->emitDropped(dragEvent.dropItem());
+ } else {
+ d->drag->emitCanceled();
+ }
+ d->drag->setDropItem(0);
d->drag->setActive(false);
+ }
// If we don't accept hover, we need to reset containsMouse.
if (!acceptHoverEvents())
setHovered(false);
diff --git a/src/declarative/items/qsgmousearea_p.h b/src/declarative/items/qsgmousearea_p.h
index 469b9f7168..d7248bca37 100644
--- a/src/declarative/items/qsgmousearea_p.h
+++ b/src/declarative/items/qsgmousearea_p.h
@@ -51,12 +51,15 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
+class QSGMouseEvent;
class Q_AUTOTEST_EXPORT QSGDrag : public QObject
{
Q_OBJECT
Q_ENUMS(Axis)
Q_PROPERTY(QSGItem *target READ target WRITE setTarget NOTIFY targetChanged RESET resetTarget)
+ Q_PROPERTY(QSGItem *dropItem READ dropItem NOTIFY dropItemChanged)
+ Q_PROPERTY(QVariant data READ data WRITE setData NOTIFY dataChanged RESET resetData)
Q_PROPERTY(Axis axis READ axis WRITE setAxis NOTIFY axisChanged)
Q_PROPERTY(qreal minimumX READ xmin WRITE setXmin NOTIFY minimumXChanged)
Q_PROPERTY(qreal maximumX READ xmax WRITE setXmax NOTIFY maximumXChanged)
@@ -64,6 +67,7 @@ class Q_AUTOTEST_EXPORT QSGDrag : public QObject
Q_PROPERTY(qreal maximumY READ ymax WRITE setYmax NOTIFY maximumYChanged)
Q_PROPERTY(bool active READ active NOTIFY activeChanged)
Q_PROPERTY(bool filterChildren READ filterChildren WRITE setFilterChildren NOTIFY filterChildrenChanged)
+ Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged)
//### consider drag and drop
public:
@@ -74,6 +78,16 @@ public:
void setTarget(QSGItem *);
void resetTarget();
+ QSGItem *dropItem() const;
+ void setDropItem(QSGItem *item);
+
+ QSGItem *grabItem() const;
+ void setGrabItem(QSGItem *grabItem);
+
+ QVariant data() const;
+ void setData(const QVariant &data);
+ void resetData();
+
enum Axis { XAxis=0x01, YAxis=0x02, XandYAxis=0x03 };
Axis axis() const;
void setAxis(Axis);
@@ -93,8 +107,17 @@ public:
bool filterChildren() const;
void setFilterChildren(bool);
+ QStringList keys() const;
+ void setKeys(const QStringList &keys);
+
+ void emitDragged(QSGMouseEvent *event) { emit dragged(event); }
+ void emitDropped(QSGItem *dropItem) { emit dropped(dropItem); }
+ void emitCanceled() { emit canceled(); }
+
Q_SIGNALS:
void targetChanged();
+ void dropItemChanged();
+ void dataChanged();
void axisChanged();
void minimumXChanged();
void maximumXChanged();
@@ -102,9 +125,17 @@ Q_SIGNALS:
void maximumYChanged();
void activeChanged();
void filterChildrenChanged();
+ void keysChanged();
+ void dragged(QSGMouseEvent *mouse);
+ void dropped(QSGItem *dropItem);
+ void canceled();
private:
+ QStringList _keys;
+ QVariant _data;
QSGItem *_target;
+ QSGItem *_dropItem;
+ QSGItem *_grabItem;
Axis _axis;
qreal _xmin;
qreal _xmax;
@@ -115,7 +146,6 @@ private:
Q_DISABLE_COPY(QSGDrag)
};
-class QSGMouseEvent;
class QSGMouseAreaPrivate;
class Q_AUTOTEST_EXPORT QSGMouseArea : public QSGItem
{
diff --git a/src/declarative/items/qsgmousearea_p_p.h b/src/declarative/items/qsgmousearea_p_p.h
index e736c059a2..11f7089503 100644
--- a/src/declarative/items/qsgmousearea_p_p.h
+++ b/src/declarative/items/qsgmousearea_p_p.h
@@ -96,6 +96,7 @@ public:
bool stealMouse : 1;
bool doubleClick : 1;
bool preventStealing : 1;
+ bool dragRejected : 1;
QSGDrag *drag;
QPointF startScene;
qreal startX;
diff --git a/src/declarative/particles/qsgmodelparticle.cpp b/src/declarative/particles/qsgmodelparticle.cpp
index 94ce082c9d..704b9a298c 100644
--- a/src/declarative/particles/qsgmodelparticle.cpp
+++ b/src/declarative/particles/qsgmodelparticle.cpp
@@ -42,6 +42,7 @@
#include "qsgmodelparticle_p.h"
#include <QtDeclarative/private/qsgvisualitemmodel_p.h>
#include <qsgnode.h>
+#include <QTimer>
#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -50,6 +51,12 @@ QSGModelParticle::QSGModelParticle(QSGItem *parent) :
QSGParticlePainter(parent), m_ownModel(false), m_comp(0), m_model(0), m_fade(true), m_modelCount(0)
{
setFlag(QSGItem::ItemHasContents);
+ QTimer* manageDelegates = new QTimer(this);//TODO: don't leak
+ connect(manageDelegates, SIGNAL(timeout()),
+ this, SLOT(processPending()));
+ manageDelegates->setInterval(16);
+ manageDelegates->setSingleShot(false);
+ manageDelegates->start();
}
QVariant QSGModelParticle::model() const
@@ -153,27 +160,38 @@ void QSGModelParticle::load(QSGParticleData* d)
if(m_stasis.contains(m_items[pos]))
qWarning() << "Current model particles prefers overwrite:false";
//remove old item from the particle that is dying to make room for this one
- m_items[pos]->setOpacity(0.);
+ m_deletables << m_items[pos];
m_available << m_idx[pos];
- m_model->release(m_items[pos]);
m_idx[pos] = -1;
m_items[pos] = 0;
m_data[pos] = 0;
m_activeCount--;
}
- m_items[pos] = m_model->item(m_available.first());
- m_idx[pos] = m_available.first();
- m_available.pop_front();
- QSGModelParticleAttached* mpa = qobject_cast<QSGModelParticleAttached*>(qmlAttachedPropertiesObject<QSGModelParticle>(m_items[pos]));
- if(mpa){
- mpa->m_mp = this;
- mpa->attach();
- }
- m_items[pos]->setParentItem(this);
+ m_requests << pos;
m_data[pos] = d;
m_activeCount++;
}
+void QSGModelParticle::processPending()
+{//can't create/delete arbitrary items in the render thread
+ foreach(QSGItem* item, m_deletables){
+ item->setOpacity(0.);
+ m_model->release(item);
+ }
+
+ foreach(int pos, m_requests){
+ m_items[pos] = m_model->item(m_available.first());
+ m_idx[pos] = m_available.first();
+ m_available.pop_front();
+ QSGModelParticleAttached* mpa = qobject_cast<QSGModelParticleAttached*>(qmlAttachedPropertiesObject<QSGModelParticle>(m_items[pos]));
+ if(mpa){
+ mpa->m_mp = this;
+ mpa->attach();
+ }
+ m_items[pos]->setParentItem(this);
+ }
+}
+
void QSGModelParticle::reload(QSGParticleData* d)
{
//No-op unless we start copying the data.
@@ -242,9 +260,8 @@ void QSGModelParticle::prepareNextFrame()
continue;
}
if(t >= 1.0){//Usually happens from load
- item->setOpacity(0.);
m_available << m_idx[i];
- m_model->release(m_items[i]);
+ m_deletables << item;
m_idx[i] = -1;
m_items[i] = 0;
m_data[i] = 0;
diff --git a/src/declarative/particles/qsgmodelparticle_p.h b/src/declarative/particles/qsgmodelparticle_p.h
index 4dd8bfa710..04533a73ce 100644
--- a/src/declarative/particles/qsgmodelparticle_p.h
+++ b/src/declarative/particles/qsgmodelparticle_p.h
@@ -96,12 +96,14 @@ protected:
void prepareNextFrame();
private slots:
void updateCount();
+ void processPending();
private:
bool m_ownModel;
QDeclarativeComponent* m_comp;
QSGVisualDataModel *m_model;
QVariant m_dataSource;
- QList<QPointer<QSGItem> > m_deletables;
+ QList<QSGItem*> m_deletables;
+ QList< int > m_requests;
int m_particleCount;
bool m_fade;
diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp
index 712f787549..e4ad463dad 100644
--- a/src/declarative/qml/qdeclarativecompiler.cpp
+++ b/src/declarative/qml/qdeclarativecompiler.cpp
@@ -649,6 +649,7 @@ bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine,
out->dumpInstructions();
if (compilerStatDump())
dumpStats();
+ Q_ASSERT(out->rootPropertyCache);
} else {
reset(out);
}
@@ -1229,6 +1230,11 @@ void QDeclarativeCompiler::genComponent(QDeclarativeParser::Object *obj)
id.setId.index = obj->idIndex;
output->addInstruction(id);
}
+
+ if (obj == unitRoot) {
+ output->rootPropertyCache = output->types[obj->type].createPropertyCache(engine);
+ output->rootPropertyCache->addref();
+ }
}
bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj,
diff --git a/src/declarative/util/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp
index dce938995d..108d2579ac 100644
--- a/src/declarative/util/qdeclarativepixmapcache.cpp
+++ b/src/declarative/util/qdeclarativepixmapcache.cpp
@@ -1119,6 +1119,7 @@ QSGTexture *QDeclarativePixmap::texture(QSGContext *context) const
return d->texture;
else if (d->pixmapStatus == Ready) {
d->texture = context->createTexture(d->pixmap.toImage());
+ d->context = context;
return d->texture;
}
}
diff --git a/tests/auto/declarative/qdeclarativelanguage/data/NestedComponentRoot.qml b/tests/auto/declarative/qdeclarativelanguage/data/NestedComponentRoot.qml
new file mode 100644
index 0000000000..785a27dd79
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativelanguage/data/NestedComponentRoot.qml
@@ -0,0 +1,6 @@
+import QtQuick 1.0
+
+Component {
+ Item {
+ }
+}
diff --git a/tests/auto/declarative/qdeclarativelanguage/data/nestedComponentRoots.qml b/tests/auto/declarative/qdeclarativelanguage/data/nestedComponentRoots.qml
new file mode 100644
index 0000000000..361bcbcb56
--- /dev/null
+++ b/tests/auto/declarative/qdeclarativelanguage/data/nestedComponentRoots.qml
@@ -0,0 +1,4 @@
+import QtQuick 1.0
+
+NestedComponentRoot {
+}
diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp
index 132c947d93..3c6ce9da6d 100644
--- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp
+++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp
@@ -135,6 +135,7 @@ private slots:
void reservedWords_data();
void reservedWords();
void inlineAssignmentsOverrideBindings();
+ void nestedComponentRoots();
void basicRemote_data();
void basicRemote();
@@ -1428,6 +1429,12 @@ void tst_qdeclarativelanguage::inlineAssignmentsOverrideBindings()
delete o;
}
+// QTBUG-19354
+void tst_qdeclarativelanguage::nestedComponentRoots()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("nestedComponentRoots.qml"));
+}
+
// Import tests (QT-558)
void tst_qdeclarativelanguage::importsBuiltin_data()
{
diff --git a/tests/benchmarks/declarative/declarative.pro b/tests/benchmarks/declarative/declarative.pro
index a827978d63..f2dfdf971a 100644
--- a/tests/benchmarks/declarative/declarative.pro
+++ b/tests/benchmarks/declarative/declarative.pro
@@ -3,6 +3,7 @@ TEMPLATE = subdirs
SUBDIRS += \
binding \
creation \
+ javascript \
holistic \
pointers \
qdeclarativecomponent \
diff --git a/tests/benchmarks/declarative/javascript/data/NestedIdObject.qml b/tests/benchmarks/declarative/javascript/data/NestedIdObject.qml
new file mode 100644
index 0000000000..410ee00ddc
--- /dev/null
+++ b/tests/benchmarks/declarative/javascript/data/NestedIdObject.qml
@@ -0,0 +1,9 @@
+import QtQuick 1.0
+
+QtObject {
+ function runtest() {
+ for (var ii = 0; ii < 5000000; ++ii) {
+ root
+ }
+ }
+}
diff --git a/tests/benchmarks/declarative/javascript/data/intQObjectProperty.qml b/tests/benchmarks/declarative/javascript/data/intQObjectProperty.qml
new file mode 100644
index 0000000000..c3e6ebc16a
--- /dev/null
+++ b/tests/benchmarks/declarative/javascript/data/intQObjectProperty.qml
@@ -0,0 +1,13 @@
+import Qt.test 1.0
+
+TestObject {
+ id: root
+
+ function runtest() {
+ var r = root;
+
+ for (var ii = 0; ii < 5000000; ++ii) {
+ r.intValue
+ }
+ }
+}
diff --git a/tests/benchmarks/declarative/javascript/data/localId.qml b/tests/benchmarks/declarative/javascript/data/localId.qml
new file mode 100644
index 0000000000..474d0760a3
--- /dev/null
+++ b/tests/benchmarks/declarative/javascript/data/localId.qml
@@ -0,0 +1,13 @@
+// Benchmarks the cost of accessing an id in the same file as the script.
+
+import QtQuick 1.0
+
+QtObject {
+ id: root
+
+ function runtest() {
+ for (var ii = 0; ii < 5000000; ++ii) {
+ root
+ }
+ }
+}
diff --git a/tests/benchmarks/declarative/javascript/data/nestedId.qml b/tests/benchmarks/declarative/javascript/data/nestedId.qml
new file mode 100644
index 0000000000..49c4e3ca43
--- /dev/null
+++ b/tests/benchmarks/declarative/javascript/data/nestedId.qml
@@ -0,0 +1,13 @@
+// Benchmarks the cost of accessing an id in a parent context of the script.
+
+import QtQuick 1.0
+
+QtObject {
+ id: root
+
+ property variant object: NestedIdObject {}
+ function runtest() {
+ object.runtest();
+ }
+}
+
diff --git a/tests/benchmarks/declarative/javascript/data/stringQObjectProperty.qml b/tests/benchmarks/declarative/javascript/data/stringQObjectProperty.qml
new file mode 100644
index 0000000000..ccd8a791b6
--- /dev/null
+++ b/tests/benchmarks/declarative/javascript/data/stringQObjectProperty.qml
@@ -0,0 +1,14 @@
+import Qt.test 1.0
+
+TestObject {
+ id: root
+
+ function runtest() {
+ var r = root;
+
+ for (var ii = 0; ii < 5000000; ++ii) {
+ r.stringValue
+ }
+ }
+}
+
diff --git a/tests/benchmarks/declarative/javascript/javascript.pro b/tests/benchmarks/declarative/javascript/javascript.pro
new file mode 100644
index 0000000000..7395cef07e
--- /dev/null
+++ b/tests/benchmarks/declarative/javascript/javascript.pro
@@ -0,0 +1,11 @@
+load(qttest_p4)
+TEMPLATE = app
+TARGET = tst_javascript
+QT += declarative
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_javascript.cpp testtypes.cpp
+HEADERS += testtypes.h
+
+# Define SRCDIR equal to test's source directory
+DEFINES += SRCDIR=\\\"$$PWD\\\"
diff --git a/tests/benchmarks/declarative/javascript/testtypes.cpp b/tests/benchmarks/declarative/javascript/testtypes.cpp
new file mode 100644
index 0000000000..f490b770fd
--- /dev/null
+++ b/tests/benchmarks/declarative/javascript/testtypes.cpp
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** 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 "testtypes.h"
+#include <QtDeclarative/qdeclarative.h>
+
+void registerTypes()
+{
+ qmlRegisterType<TestObject>("Qt.test", 1,0, "TestObject");
+}
diff --git a/tests/benchmarks/declarative/javascript/testtypes.h b/tests/benchmarks/declarative/javascript/testtypes.h
new file mode 100644
index 0000000000..c89f10757b
--- /dev/null
+++ b/tests/benchmarks/declarative/javascript/testtypes.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef TESTTYPES_H
+#define TESTTYPES_H
+
+#include <QtCore/qobject.h>
+
+class TestObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int intValue READ intValue);
+ Q_PROPERTY(QString stringValue READ stringValue);
+
+public:
+ TestObject() : m_string("Hello world!") {}
+
+ int intValue() const { return 13; }
+ QString stringValue() const { return m_string; }
+
+private:
+ QString m_string;
+};
+
+void registerTypes();
+
+#endif // TESTTYPES_H
diff --git a/tests/benchmarks/declarative/javascript/tst_javascript.cpp b/tests/benchmarks/declarative/javascript/tst_javascript.cpp
new file mode 100644
index 0000000000..73c1d7c7ad
--- /dev/null
+++ b/tests/benchmarks/declarative/javascript/tst_javascript.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** 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 <QDir>
+#include <QDebug>
+#include <qtest.h>
+#include <QDeclarativeEngine>
+#include <QDeclarativeComponent>
+
+#include "testtypes.h"
+
+class tst_javascript : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_javascript();
+ virtual ~tst_javascript();
+
+private slots:
+ void run_data();
+ void run();
+
+private:
+ QDeclarativeEngine engine;
+};
+
+tst_javascript::tst_javascript()
+{
+ registerTypes();
+}
+
+tst_javascript::~tst_javascript()
+{
+}
+
+void tst_javascript::run_data()
+{
+ QTest::addColumn<QString>("file");
+
+ QDir dir(SRCDIR "/data");
+
+ QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
+
+ for (int ii = 0; ii < files.count(); ++ii) {
+ QString file = files.at(ii);
+ if (file.endsWith(".qml") && file.at(0).isLower()) {
+
+ QString testName = file.left(file.length() - 4 /* strlen(".qml") */);
+ QString fileName = QLatin1String(SRCDIR) + QLatin1String("/data/") + file;
+
+
+ QTest::newRow(qPrintable(testName)) << fileName;
+
+ }
+ }
+}
+
+void tst_javascript::run()
+{
+ QFETCH(QString, file);
+
+ QDeclarativeComponent c(&engine, file);
+
+ if (c.isError()) {
+ qWarning() << c.errors();
+ }
+
+ QVERIFY(!c.isError());
+
+ QObject *o = c.create();
+ QVERIFY(o != 0);
+
+ QMetaMethod method = o->metaObject()->method(o->metaObject()->indexOfMethod("runtest()"));
+
+ QBENCHMARK {
+ method.invoke(o);
+ }
+
+ delete o;
+}
+
+QTEST_MAIN(tst_javascript)
+
+#include "tst_javascript.moc"