diff options
33 files changed, 3458 insertions, 1398 deletions
diff --git a/doc/src/snippets/declarative/drag.qml b/doc/src/snippets/declarative/drag.qml new file mode 100644 index 0000000000..d863fdf510 --- /dev/null +++ b/doc/src/snippets/declarative/drag.qml @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 200; height: 200 + + DropArea { + x: 75; y: 75 + width: 50; height: 50 + + Rectangle { + anchors.fill: parent + color: "green" + + visible: parent.containsDrag + } + } + + Rectangle { + x: 10; y: 10 + width: 20; height: 20 + color: "red" + + Drag.active: dragArea.drag.active + Drag.hotSpot.x: 10 + Drag.hotSpot.y: 10 + + MouseArea { + id: dragArea + anchors.fill: parent + + drag.target: parent + } + } +} +//![0] diff --git a/examples/declarative/dragtarget/dragtarget.qmlproject b/examples/declarative/draganddrop/dragtarget.qmlproject index d4909f8685..d4909f8685 100644 --- a/examples/declarative/dragtarget/dragtarget.qmlproject +++ b/examples/declarative/draganddrop/dragtarget.qmlproject diff --git a/examples/declarative/dragtarget/tiles/DragTile.qml b/examples/declarative/draganddrop/tiles/DragTile.qml index f1bd79314a..d7bc920735 100644 --- a/examples/declarative/dragtarget/tiles/DragTile.qml +++ b/examples/declarative/draganddrop/tiles/DragTile.qml @@ -40,60 +40,50 @@ import QtQuick 2.0 -Rectangle { - id: dragRectangle +Item { + id: root + property string colorKey - property Item dropTarget + width: 100; height: 100 - property string colorKey + MouseArea { + id: mouseArea - color: colorKey + width: 100; height: 100 + anchors.centerIn: parent - width: 100; height: 100 + drag.target: tile - Text { - anchors.fill: parent - color: "white" - font.pixelSize: 90 - text: modelData + 1 - horizontalAlignment:Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } + onReleased: parent = tile.Drag.target !== null ? tile.Drag.target : root - MouseArea { - id: draggable + Rectangle { + id: tile - anchors.fill: parent + width: 100; height: 100 - drag.target: parent - drag.keys: [ colorKey ] + anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: parent.verticalCenter + color: colorKey - drag.onDropped: dropTarget = dropItem + Drag.keys: [ colorKey ] + Drag.active: mouseArea.drag.active + Drag.hotSpot.x: 50 + Drag.hotSpot.y: 50 - 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 - } + Text { + anchors.fill: parent + color: "white" + font.pixelSize: 90 + text: modelData + 1 + horizontalAlignment:Text.AlignHCenter + verticalAlignment: Text.AlignVCenter } - ] + + states: State { + when: mouseArea.drag.active + ParentChange { target: tile; parent: root } + AnchorChanges { target: tile; anchors.verticalCenter: undefined; anchors.horizontalCenter: undefined } + } + } } } + diff --git a/examples/declarative/dragtarget/tiles/DropTile.qml b/examples/declarative/draganddrop/tiles/DropTile.qml index 80aa81f671..492706439a 100644 --- a/examples/declarative/dragtarget/tiles/DropTile.qml +++ b/examples/declarative/draganddrop/tiles/DropTile.qml @@ -40,31 +40,29 @@ import QtQuick 2.0 -Rectangle { - id: dropRectangle +DropArea { + id: dragTarget property string colorKey - - color: colorKey + property alias dropProxy: dragTarget width: 100; height: 100 + keys: [ colorKey ] - DragTarget { - id: dragTarget + Rectangle { + id: dropRectangle anchors.fill: parent + color: colorKey - keys: [ colorKey ] - dropItem: dropRectangle - } - - states: [ - State { - when: dragTarget.containsDrag - PropertyChanges { - target: dropRectangle - color: "grey" + states: [ + State { + when: dragTarget.containsDrag + PropertyChanges { + target: dropRectangle + color: "grey" + } } - } - ] + ] + } } diff --git a/examples/declarative/dragtarget/tiles/tiles.qml b/examples/declarative/draganddrop/tiles/tiles.qml index 1f783e3322..17dcd3b547 100644 --- a/examples/declarative/dragtarget/tiles/tiles.qml +++ b/examples/declarative/draganddrop/tiles/tiles.qml @@ -48,12 +48,6 @@ Rectangle { color: "black" - DragTarget { - id: resetTarget - - anchors.fill: parent - } - Grid { id: redDestination @@ -61,22 +55,16 @@ Rectangle { anchors.margins: 5 width: 300 height: 300 - opacity: 0.5 - columns: 3 Repeater { - model: 9 - delegate: DropTile { - colorKey: "red" - } + model: 9; + delegate: DropTile { colorKey: "red" } } } Grid { - id: blueDestination - anchors.right: blueSource.left; anchors.bottom: parent.bottom; anchors.margins: 5 width: 300 @@ -88,9 +76,7 @@ Rectangle { Repeater { model: 9 - delegate: DropTile { - colorKey: "blue" - } + delegate: DropTile { colorKey: "blue" } } } @@ -100,12 +86,11 @@ Rectangle { anchors.left: parent.left; anchors.top: parent.top; anchors.bottom: parent.bottom anchors.margins: 5 width: 100 + spacing: -60 Repeater { model: 9 - delegate: DragTile { - colorKey: "red" - } + delegate: DragTile { colorKey: "red" } } } Column { @@ -114,12 +99,11 @@ Rectangle { anchors.right: parent.right; anchors.top: parent.top; anchors.bottom: parent.bottom anchors.margins: 5 width: 100 + spacing: -60 Repeater { model: 9 - delegate: DragTile { - colorKey: "blue" - } + delegate: DragTile { colorKey: "blue" } } } } diff --git a/examples/declarative/draganddrop/views/gridview.qml b/examples/declarative/draganddrop/views/gridview.qml new file mode 100644 index 0000000000..f16a79c9dc --- /dev/null +++ b/examples/declarative/draganddrop/views/gridview.qml @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** 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:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +GridView { + id: root + width: 360; height: 360 + cellWidth: 90; cellHeight: 90 + + model: VisualDataModel { + id: visualModel + model: ListModel { + id: colorModel + ListElement { color: "blue" } + ListElement { color: "green" } + ListElement { color: "red" } + ListElement { color: "yellow" } + ListElement { color: "orange" } + ListElement { color: "purple" } + ListElement { color: "cyan" } + ListElement { color: "magenta" } + ListElement { color: "chartreuse" } + ListElement { color: "aquamarine" } + ListElement { color: "indigo" } + ListElement { color: "black" } + ListElement { color: "chartreuse" } + ListElement { color: "violet" } + ListElement { color: "grey" } + ListElement { color: "springgreen" } + } + + delegate: MouseArea { + id: delegateRoot + + property int visualIndex: VisualDataModel.itemsIndex + + width: 90; height: 90 + drag.target: icon + + Rectangle { + id: icon + width: 80; height: 80 + anchors { + horizontalCenter: parent.horizontalCenter; + verticalCenter: parent.verticalCenter + } + color: model.color + radius: 3 + + Drag.active: delegateRoot.pressed + Drag.source: delegateRoot + Drag.hotSpot.x: 40 + Drag.hotSpot.y: 40 + + states: [ + State { + when: icon.Drag.active + ParentChange { + target: icon + parent: root + } + + AnchorChanges { + target: icon; + anchors.horizontalCenter: undefined; + anchors.verticalCenter: undefined + } + } + ] + } + + DropArea { + anchors { fill: parent; margins: 15 } + + onEntered: visualModel.items.move(drag.source.visualIndex, delegateRoot.visualIndex) + } + } + } +} diff --git a/examples/declarative/dragtarget/lists/listmodel.qml b/examples/declarative/dragtarget/lists/listmodel.qml deleted file mode 100644 index f153087e7b..0000000000 --- a/examples/declarative/dragtarget/lists/listmodel.qml +++ /dev/null @@ -1,296 +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:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor -** the names of its contributors may be used to endorse or promote -** products derived from this software without specific prior written -** permission. -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 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 deleted file mode 100644 index d4909f8685..0000000000 --- a/examples/declarative/dragtarget/lists/lists.qmlproject +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index 49858d1fc4..0000000000 --- a/examples/declarative/dragtarget/text/dragtext.qml +++ /dev/null @@ -1,182 +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:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor -** the names of its contributors may be used to endorse or promote -** products derived from this software without specific prior written -** permission. -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 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 deleted file mode 100644 index d4909f8685..0000000000 --- a/examples/declarative/dragtarget/text/text.qmlproject +++ /dev/null @@ -1,16 +0,0 @@ -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/modelviews/visualdatamodel/dragselection.qml b/examples/declarative/modelviews/visualdatamodel/dragselection.qml index d4412f9719..afbea1ff94 100644 --- a/examples/declarative/modelviews/visualdatamodel/dragselection.qml +++ b/examples/declarative/modelviews/visualdatamodel/dragselection.qml @@ -69,6 +69,8 @@ Item { width: 64 height: 64 + Drag.active: visibleContainer.drag.active + anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter } states: State { @@ -79,7 +81,7 @@ Item { ParentChange { target: draggable; parent: root } } } - DragTarget { + DropArea { anchors.fill: parent onEntered: visualModel.items.move(selectedItems, 0, packageRoot.VisualDataModel.itemsIndex, selectedItems.count) } diff --git a/src/declarative/items/items.pri b/src/declarative/items/items.pri index 04330748e1..355a762764 100644 --- a/src/declarative/items/items.pri +++ b/src/declarative/items/items.pri @@ -64,8 +64,8 @@ HEADERS += \ $$PWD/qsgspriteengine_p.h \ $$PWD/qsgsprite_p.h \ $$PWD/qsgspriteimage_p.h \ - $$PWD/qsgevent.h \ - $$PWD/qsgdragtarget_p.h \ + $$PWD/qsgdrag_p.h \ + $$PWD/qsgdroparea_p.h \ $$PWD/qsgitemview_p.h \ $$PWD/qsgitemview_p_p.h @@ -110,7 +110,8 @@ SOURCES += \ $$PWD/qsgspriteengine.cpp \ $$PWD/qsgsprite.cpp \ $$PWD/qsgspriteimage.cpp \ - $$PWD/qsgdragtarget.cpp \ + $$PWD/qsgdrag.cpp \ + $$PWD/qsgdroparea.cpp \ $$PWD/qsgitemview.cpp SOURCES += \ diff --git a/src/declarative/items/qsgcanvas.cpp b/src/declarative/items/qsgcanvas.cpp index 4eb6f92395..09a13f403c 100644 --- a/src/declarative/items/qsgcanvas.cpp +++ b/src/declarative/items/qsgcanvas.cpp @@ -45,8 +45,6 @@ #include "qsgitem.h" #include "qsgitem_p.h" -#include "qsgevent.h" - #include <private/qsgrenderer_p.h> #include <private/qsgflashnode_p.h> @@ -897,11 +895,11 @@ 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)); + case QEvent::DragEnter: + case QEvent::DragLeave: + case QEvent::DragMove: + case QEvent::Drop: + d->deliverDragEvent(&d->dragGrabber, e); break; case QEvent::WindowDeactivate: rootItem()->windowDeactivateEvent(); @@ -1362,76 +1360,124 @@ bool QSGCanvasPrivate::deliverTouchPoints(QSGItem *item, QTouchEvent *event, con return false; } -void QSGCanvasPrivate::deliverDragEvent(QSGDragEvent *event) +void QSGCanvasPrivate::deliverDragEvent(QSGDragGrabber *grabber, QEvent *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); + grabber->resetTarget(); + QSGDragGrabber::iterator grabItem = grabber->begin(); + if (grabItem != grabber->end()) { + Q_ASSERT(event->type() != QEvent::DragEnter); + if (event->type() == QEvent::Drop) { + QDropEvent *e = static_cast<QDropEvent *>(event); + for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) { + QPointF p = (**grabItem)->mapFromScene(e->pos()); + QDropEvent translatedEvent( + p.toPoint(), + e->possibleActions(), + e->mimeData(), + e->mouseButtons(), + e->keyboardModifiers()); + QSGDropEventEx::copyActions(&translatedEvent, *e); + q->sendEvent(**grabItem, &translatedEvent); + e->setAccepted(translatedEvent.isAccepted()); + e->setDropAction(translatedEvent.dropAction()); + grabber->setTarget(**grabItem); + } } - } 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); + if (event->type() != QEvent::DragMove) { // Either an accepted drop or a leave. + QDragLeaveEvent leaveEvent; + for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) + q->sendEvent(**grabItem, &leaveEvent); + return; + } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) { + QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event); + if (deliverDragEvent(grabber, **grabItem, moveEvent)) { + moveEvent->setAccepted(true); + for (++grabItem; grabItem != grabber->end();) { + QPointF p = (**grabItem)->mapFromScene(moveEvent->pos()); + if (QRectF(0, 0, (**grabItem)->width(), (**grabItem)->height()).contains(p)) { + QDragMoveEvent translatedEvent( + p.toPoint(), + moveEvent->possibleActions(), + moveEvent->mimeData(), + moveEvent->mouseButtons(), + moveEvent->keyboardModifiers()); + QSGDropEventEx::copyActions(&translatedEvent, *moveEvent); + q->sendEvent(**grabItem, &translatedEvent); + ++grabItem; + } else { + QDragLeaveEvent leaveEvent; + q->sendEvent(**grabItem, &leaveEvent); + grabItem = grabber->release(grabItem); + } + } + return; + } else { + QDragLeaveEvent leaveEvent; + q->sendEvent(**grabItem, &leaveEvent); + } } - event->setAccepted(false); + } + if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) { + QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event); + QDragEnterEvent enterEvent( + e->pos(), + e->possibleActions(), + e->mimeData(), + e->mouseButtons(), + e->keyboardModifiers()); + QSGDropEventEx::copyActions(&enterEvent, *e); + event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent)); } } -bool QSGCanvasPrivate::deliverDragEvent(QSGItem *item, QSGDragEvent *event) +bool QSGCanvasPrivate::deliverDragEvent(QSGDragGrabber *grabber, QSGItem *item, QDragMoveEvent *event) { Q_Q(QSGCanvas); + bool accepted = false; QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item); - if (itemPrivate->opacity == 0.0) + if (itemPrivate->opacity == 0.0 || !item->isVisible() || !item->isEnabled()) 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()); + QPointF p = item->mapFromScene(event->pos()); 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); + if (event->type() == QEvent::DragMove || itemPrivate->flags & QSGItem::ItemAcceptsDrops) { + QDragMoveEvent translatedEvent( + p.toPoint(), + event->possibleActions(), + event->mimeData(), + event->mouseButtons(), + event->keyboardModifiers(), + event->type()); + QSGDropEventEx::copyActions(&translatedEvent, *event); + q->sendEvent(item, &translatedEvent); + if (event->type() == QEvent::DragEnter) { + if (translatedEvent.isAccepted()) { + grabber->grab(item); + accepted = true; } - event->setDropItem(enterEvent.dropItem()); - event->setGrabItem(item); } else { - return false; + accepted = true; } } + } else if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) { + return false; + } - q->sendEvent(item, event); - if (event->isAccepted()) { - event->setGrabItem(item); + QDragEnterEvent enterEvent( + event->pos(), + event->possibleActions(), + event->mimeData(), + event->mouseButtons(), + event->keyboardModifiers()); + QSGDropEventEx::copyActions(&enterEvent, *event); + QList<QSGItem *> children = itemPrivate->paintOrderChildItems(); + for (int ii = children.count() - 1; ii >= 0; --ii) { + if (deliverDragEvent(grabber, children.at(ii), &enterEvent)) return true; - } - event->setAccepted(true); } - return false; + return accepted; } bool QSGCanvasPrivate::sendFilteredMouseEvent(QSGItem *target, QSGItem *item, QMouseEvent *event) @@ -1509,11 +1555,11 @@ 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)); + case QEvent::DragEnter: + case QEvent::DragMove: + case QEvent::DragLeave: + case QEvent::Drop: + QSGItemPrivate::get(item)->deliverDragEvent(e); break; default: break; diff --git a/src/declarative/items/qsgcanvas_p.h b/src/declarative/items/qsgcanvas_p.h index 4a53e6bb1b..e2ec7a1963 100644 --- a/src/declarative/items/qsgcanvas_p.h +++ b/src/declarative/items/qsgcanvas_p.h @@ -55,10 +55,10 @@ #include "qsgitem.h" #include "qsgcanvas.h" -#include "qsgevent.h" #include <private/qdeclarativeguard_p.h> #include <private/qsgcontext_p.h> +#include <private/qsgdrag_p.h> #include <QtCore/qthread.h> #include <QtCore/qmutex.h> @@ -102,6 +102,7 @@ public: QSGItem *activeFocusItem; QSGItem *mouseGrabberItem; + QSGDragGrabber dragGrabber; // Mouse positions are saved in widget coordinates QPointF lastMousePosition; @@ -118,8 +119,8 @@ public: bool sendHoverEvent(QEvent::Type, QSGItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool accepted); bool clearHover(); - void deliverDragEvent(QSGDragEvent *); - bool deliverDragEvent(QSGItem *item, QSGDragEvent *); + void deliverDragEvent(QSGDragGrabber *, QEvent *); + bool deliverDragEvent(QSGDragGrabber *, QSGItem *, QDragMoveEvent *); QList<QSGItem*> hoverItems; enum FocusOption { @@ -300,7 +301,6 @@ public: void run(); }; - Q_DECLARE_OPERATORS_FOR_FLAGS(QSGCanvasPrivate::FocusOptions) QT_END_NAMESPACE diff --git a/src/declarative/items/qsgdrag.cpp b/src/declarative/items/qsgdrag.cpp new file mode 100644 index 0000000000..7c73db7d38 --- /dev/null +++ b/src/declarative/items/qsgdrag.cpp @@ -0,0 +1,474 @@ +/**************************************************************************** +** +** 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 "qsgdrag_p.h" + +#include <private/qsgitem_p.h> +#include <private/qsgevents_p_p.h> +#include <private/qsgitemchangelistener_p.h> +#include <private/qv8engine_p.h> + +#include <QtGui/qevent.h> + +QT_BEGIN_NAMESPACE + +class QSGDragAttachedPrivate : public QObjectPrivate, public QSGItemChangeListener +{ + Q_DECLARE_PUBLIC(QSGDragAttached) +public: + static QSGDragAttachedPrivate *get(QSGDragAttached *attached) { + return static_cast<QSGDragAttachedPrivate *>(QObjectPrivate::get(attached)); } + + QSGDragAttachedPrivate() + : attachedItem(0) + , mimeData(0) + , proposedAction(Qt::MoveAction) + , supportedActions(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction) + , active(false) + , listening(false) + { + } + + void itemGeometryChanged(QSGItem *, const QRectF &, const QRectF &); + void start() { start(supportedActions); } + void start(Qt::DropActions supportedActions); + void setTarget(QSGItem *item); + + QSGDragGrabber dragGrabber; + + QDeclarativeGuard<QObject> source; + QDeclarativeGuard<QObject> target; + QSGItem *attachedItem; + QSGDragMimeData *mimeData; + Qt::DropAction proposedAction; + Qt::DropActions supportedActions; + bool active : 1; + bool listening : 1; + QPointF hotSpot; + QStringList keys; +}; + +/*! + \qmlclass Drag QSGDrag + \inqmlmodule QtQuick 2 + \brief The Drag attached property provides drag and drop events for moved Items. + + Using the Drag attached property any Item can made a source of drag and drop + events within a scene. + + When a drag is \l active on an item any change in that items position will + generate a drag events that will be sent to any DropArea that intersects + the with new position of the item. Other items which implement drag and + drop event handlers can also receive these events. + + The following snippet shows how an item can be dragged with a MouseArea. + However, dragging is not limited to mouse drags, anything that can move an item + can generate drag events, this can include touch events, animations and bindings. + + \snippet doc/src/snippets/declarative/drag.qml 0 + + A drag can be terminated either by cancelling 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, + otherwise it will return Qt.IgnoreAction. + +*/ + +QSGDragAttached *QSGDragAttached::properties(QObject *obj) +{ + QSGDragAttached *rv = attachedProperties.value(obj); + if (!rv) { + rv = new QSGDragAttached(obj); + attachedProperties.insert(obj, rv); + } + return rv; +} + +QHash<QObject*, QSGDragAttached *> QSGDragAttached::attachedProperties; + +void QSGDragAttachedPrivate::itemGeometryChanged(QSGItem *, const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_Q(QSGDragAttached); + if (newGeometry.topLeft() == oldGeometry.topLeft() || !active) + return; + + if (QSGCanvas *canvas = attachedItem->canvas()) { + QPoint scenePos = attachedItem->mapToScene(hotSpot).toPoint(); + QDragMoveEvent event(scenePos, mimeData->m_supportedActions, mimeData, Qt::NoButton, Qt::NoModifier); + QSGDropEventEx::setProposedAction(&event, proposedAction); + QSGCanvasPrivate::get(canvas)->deliverDragEvent(&dragGrabber, &event); + if (target != dragGrabber.target()) { + target = dragGrabber.target(); + emit q->targetChanged(); + } + } +} + +QSGDragAttached::QSGDragAttached(QObject *parent) + : QObject(*new QSGDragAttachedPrivate, parent) +{ + Q_D(QSGDragAttached); + d->attachedItem = qobject_cast<QSGItem *>(parent); + d->source = d->attachedItem; +} + +QSGDragAttached::~QSGDragAttached() +{ + Q_D(QSGDragAttached); + delete d->mimeData; +} + +/*! + \qmlattachedproperty bool QtQuick2::Drag::active + + This property holds whether a drag event sequence is currently active. + + Setting this property to true will send a QDragEnter event to the scene + with the item's current position. Setting it to false will send a + QDragLeave event. + + While a drag is active any change in an item's position will send a QDragMove + event with item's new position to the scene. +*/ + +bool QSGDragAttached::isActive() const +{ + Q_D(const QSGDragAttached); + return d->active; +} + +void QSGDragAttached::setActive(bool active) +{ + Q_D(QSGDragAttached); + if (d->active != active) { + if (active) + d->start(d->supportedActions); + else + cancel(); + } +} + +/*! + \qmlattachedproperty Object QtQuick2::Drag::source + + This property holds an object that is identified to recipients of drag events as + the source of the events. By default this is the item Drag property is attached to. + + Changes to source while a Drag is active don't take effect until a new drag is started. +*/ + +QObject *QSGDragAttached::source() const +{ + Q_D(const QSGDragAttached); + return d->source; +} + +void QSGDragAttached::setSource(QObject *item) +{ + Q_D(QSGDragAttached); + if (d->source != item) { + d->source = item; + emit sourceChanged(); + } +} + +void QSGDragAttached::resetSource() +{ + Q_D(QSGDragAttached); + if (d->source != d->attachedItem) { + d->source = d->attachedItem; + emit sourceChanged(); + } +} + +/*! + \qmlattachedproperty Object QtQuick2::Drag::target + + While a drag is active this property holds the last object to accept an + enter event from the dragged item, if the current drag position doesn't + intersect any accepting targets it is null. + + 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. +*/ + +QObject *QSGDragAttached::target() const +{ + Q_D(const QSGDragAttached); + return d->target; +} + +/*! + \qmlattachedproperty QPointF QtQuick2::Drag::hotSpot + + This property holds the drag position relative to the top left of the item. + + By default this is (0, 0). + + Changes to hotSpot will take effect when the next event is sent. +*/ + +QPointF QSGDragAttached::hotSpot() const +{ + Q_D(const QSGDragAttached); + return d->hotSpot; +} + +void QSGDragAttached::setHotSpot(const QPointF &hotSpot) +{ + Q_D(QSGDragAttached); + if (d->hotSpot != hotSpot) { + d->hotSpot = hotSpot; + emit hotSpotChanged(); + // Send a move event if active? + } +} + +/*! + \qmlattachedproperty stringlist QtQuick2::Drag::keys + + This property holds a list of keys that can be used by a DropArea to filter drag events. + + Changes to keys while a Drag is active don't take effect until a new drag is started. +*/ + +QStringList QSGDragAttached::keys() const +{ + Q_D(const QSGDragAttached); + return d->keys; +} + +void QSGDragAttached::setKeys(const QStringList &keys) +{ + Q_D(QSGDragAttached); + if (d->keys != keys) { + d->keys = keys; + emit keysChanged(); + } +} + +/*! + \qmlattachedproperty flags QtQuick2::Drag::supportedActions + + This property holds return values of Drag.drop() supported by the drag source. + + Changes to supportedActions while a Drag is active don't take effect + until a new drag is started. +*/ + +Qt::DropActions QSGDragAttached::supportedActions() const +{ + Q_D(const QSGDragAttached); + return d->supportedActions; +} + +void QSGDragAttached::setSupportedActions(Qt::DropActions actions) +{ + Q_D(QSGDragAttached); + if (d->supportedActions != actions) { + d->supportedActions = actions; + emit supportedActionsChanged(); + } +} + +/*! + \qmlattachedproperty enumeration QtQuick2::Drag::proposedAction + + This property holds an action that is recommended by the drag source as a + return value from Drag.drop(). + + Changes to proposedAction will take effect when the next event is sent. +*/ + +Qt::DropAction QSGDragAttached::proposedAction() const +{ + Q_D(const QSGDragAttached); + return d->proposedAction; +} + +void QSGDragAttached::setProposedAction(Qt::DropAction action) +{ + Q_D(QSGDragAttached); + if (d->proposedAction != action) { + d->proposedAction = action; + emit proposedActionChanged(); + // send a move event with the new default action if active? + } +} + +void QSGDragAttachedPrivate::start(Qt::DropActions supportedActions) +{ + Q_Q(QSGDragAttached); + Q_ASSERT(!active); + + if (QSGCanvas *canvas = attachedItem ? attachedItem->canvas() : 0) { + if (!mimeData) + mimeData = new QSGDragMimeData; + if (!listening) { + QSGItemPrivate::get(attachedItem)->addItemChangeListener(this, QSGItemPrivate::Geometry); + listening = true; + } + + mimeData->m_source = source; + mimeData->m_supportedActions = supportedActions; + mimeData->m_keys = keys; + active = true; + + QPoint scenePos = attachedItem->mapToScene(hotSpot).toPoint(); + QDragEnterEvent event(scenePos, supportedActions, mimeData, Qt::NoButton, Qt::NoModifier); + QSGDropEventEx::setProposedAction(&event, proposedAction); + QSGCanvasPrivate::get(canvas)->deliverDragEvent(&dragGrabber, &event); + + emit q->activeChanged(); + if (target != dragGrabber.target()) { + target = dragGrabber.target(); + emit q->targetChanged(); + } + } +} + +/*! + \qmlattachedmethod void QtQuick2::Drag::start(flags supportedActions) + + Starts sending drag events. + + The optional \a supportedActions argument can be used to override the \l supportedActions + property for the started sequence. +*/ + +void QSGDragAttached::start(QDeclarativeV8Function *args) +{ + Q_D(QSGDragAttached); + if (d->active) + cancel(); + + Qt::DropActions supportedActions = d->supportedActions; + // check arguments for supportedActions, maybe data? + if (args->Length() >= 1) { + v8::Local<v8::Value> v = (*args)[0]; + if (v->IsInt32()) + supportedActions = Qt::DropActions(v->Int32Value()); + } + + d->start(supportedActions); +} + +/*! + \qmlattachedmethod enum QtQuick2::Drag::drop() + + Ends a drag sequence by sending a drop event to the target item. + + Returns the action accepted by the target item. If the target item or a parent doesn't accept + the drop event then Qt.IgnoreAction will be returned. + + The returned drop action may be one of: + + \list + \o Qt.CopyAction Copy the data to the target + \o Qt.MoveAction Move the data from the source to the target + \o Qt.LinkAction Create a link from the source to the target. + \o Qt.IgnoreAction Ignore the action (do nothing with the data). + \endlist + +*/ + +int QSGDragAttached::drop() +{ + Q_D(QSGDragAttached); + Qt::DropAction acceptedAction = Qt::IgnoreAction; + + if (!d->active) + return acceptedAction; + + QObject *target = 0; + + if (QSGCanvas *canvas = d->attachedItem->canvas()) { + QPoint scenePos = d->attachedItem->mapToScene(d->hotSpot).toPoint(); + + QDropEvent event( + scenePos, d->mimeData->m_supportedActions, d->mimeData, Qt::NoButton, Qt::NoModifier); + QSGDropEventEx::setProposedAction(&event, d->proposedAction); + QSGCanvasPrivate::get(canvas)->deliverDragEvent(&d->dragGrabber, &event); + + if (event.isAccepted()) { + acceptedAction = event.dropAction(); + target = d->dragGrabber.target(); + } + } + + d->active = false; + if (d->target != target) { + d->target = target; + emit targetChanged(); + } + + emit activeChanged(); + return acceptedAction; +} + +/*! + \qmlattachedmethod void QtQuick2::Drag::cancel() + + Ends a drag sequence. +*/ + +void QSGDragAttached::cancel() +{ + Q_D(QSGDragAttached); + if (!d->active) + return; + + if (QSGCanvas *canvas = d->attachedItem->canvas()) { + QDragLeaveEvent event; + QSGCanvasPrivate::get(canvas)->deliverDragEvent(&d->dragGrabber, &event); + } + + d->active = false; + if (d->target) { + d->target = 0; + emit targetChanged(); + } + emit activeChanged(); +} + +QT_END_NAMESPACE diff --git a/src/declarative/items/qsgdrag_p.h b/src/declarative/items/qsgdrag_p.h new file mode 100644 index 0000000000..a1b6cdca9b --- /dev/null +++ b/src/declarative/items/qsgdrag_p.h @@ -0,0 +1,212 @@ +// Commit: c6e6a35aeb8794d68a3ca0c4e27a3a1181c066b5 +/**************************************************************************** +** +** 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 QSGDRAG_P_H +#define QSGDRAG_P_H + +#include <qsgitem.h> + +#include <private/qv8engine_p.h> + +#include <QtCore/qmimedata.h> +#include <QtCore/qstringlist.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QSGItem; +class QSGDrag; +class QSGDragPrivate; + +class QSGDragGrabber +{ + class Item : public QDeclarativeGuard<QSGItem> + { + public: + Item(QSGItem *item) : QDeclarativeGuard<QSGItem>(item) {} + + QIntrusiveListNode node; + protected: + void objectDestroyed(QSGItem *) { delete this; } + }; + + typedef QIntrusiveList<Item, &Item::node> ItemList; + +public: + QSGDragGrabber() : m_target(0) {} + ~QSGDragGrabber() { while (!m_items.isEmpty()) delete m_items.first(); } + + + QObject *target() const + { + if (m_target) + return m_target; + else if (!m_items.isEmpty()) + return *m_items.first(); + else + return 0; + } + void setTarget(QObject *target) { m_target = target; } + void resetTarget() { m_target = 0; } + + typedef ItemList::iterator iterator; + iterator begin() { return m_items.begin(); } + iterator end() { return m_items.end(); } + + void grab(QSGItem *item) { m_items.insert(new Item(item)); } + iterator release(iterator at) { Item *item = *at; at = at.erase(); delete item; return at; } + +private: + + ItemList m_items; + QObject *m_target; +}; + +class QSGDropEventEx : public QDropEvent +{ +public: + void setProposedAction(Qt::DropAction action) { default_action = action; drop_action = action; } + + static void setProposedAction(QDropEvent *event, Qt::DropAction action) { + static_cast<QSGDropEventEx *>(event)->setProposedAction(action); + } + + void copyActions(const QDropEvent &from) { + default_action = from.proposedAction(); drop_action = from.dropAction(); } + + static void copyActions(QDropEvent *to, const QDropEvent &from) { + static_cast<QSGDropEventEx *>(to)->copyActions(from); + } +}; + +class QSGDragMimeData : public QMimeData +{ + Q_OBJECT +public: + QSGDragMimeData() + : m_source(0) + { + } + + QStringList keys() const { return m_keys; } + QObject *source() const { return m_source; } + +private: + QObject *m_source; + Qt::DropActions m_supportedActions; + QStringList m_keys; + + friend class QSGDragAttached; + friend class QSGDragAttachedPrivate; +}; + +class QDeclarativeV8Function; + +class QSGDragAttachedPrivate; +class QSGDragAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged) + Q_PROPERTY(QObject *source READ source WRITE setSource NOTIFY sourceChanged RESET resetSource) + Q_PROPERTY(QObject *target READ target NOTIFY targetChanged) + Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot NOTIFY hotSpotChanged) + Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged) + Q_PROPERTY(Qt::DropActions supportedActions READ supportedActions WRITE setSupportedActions NOTIFY supportedActionsChanged) + Q_PROPERTY(Qt::DropAction proposedAction READ proposedAction WRITE setProposedAction NOTIFY proposedActionChanged) +public: + QSGDragAttached(QObject *parent); + ~QSGDragAttached(); + + bool isActive() const; + void setActive(bool active); + + QObject *source() const; + void setSource(QObject *item); + void resetSource(); + + QObject *target() const; + + QPointF hotSpot() const; + void setHotSpot(const QPointF &hotSpot); + + QStringList keys() const; + void setKeys(const QStringList &keys); + + Qt::DropActions supportedActions() const; + void setSupportedActions(Qt::DropActions actions); + + Qt::DropAction proposedAction() const; + void setProposedAction(Qt::DropAction action); + + Q_INVOKABLE int drop(); + + static QSGDragAttached *properties(QObject *obj); + +public Q_SLOTS: + void start(QDeclarativeV8Function *); + void cancel(); + +Q_SIGNALS: + void activeChanged(); + void sourceChanged(); + void targetChanged(); + void hotSpotChanged(); + void keysChanged(); + void supportedActionsChanged(); + void proposedActionChanged(); + +private: + static QHash<QObject*, QSGDragAttached *> attachedProperties; + + Q_DECLARE_PRIVATE(QSGDragAttached) +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/declarative/items/qsgdragtarget.cpp b/src/declarative/items/qsgdragtarget.cpp deleted file mode 100644 index 5b6d36ee11..0000000000 --- a/src/declarative/items/qsgdragtarget.cpp +++ /dev/null @@ -1,363 +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 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 "qsgdragtarget_p.h" -#include "qsgitem_p.h" -#include "qsgcanvas.h" - -QT_BEGIN_NAMESPACE - -/*! - \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/qsgdroparea.cpp b/src/declarative/items/qsgdroparea.cpp new file mode 100644 index 0000000000..a1b81be1ae --- /dev/null +++ b/src/declarative/items/qsgdroparea.cpp @@ -0,0 +1,426 @@ +/**************************************************************************** +** +** 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 "qsgdroparea_p.h" +#include "qsgdrag_p.h" +#include "qsgitem_p.h" +#include "qsgcanvas.h" + +#include <private/qdeclarativeengine_p.h> + +QSGDropAreaDrag::QSGDropAreaDrag(QSGDropAreaPrivate *d, QObject *parent) + : QObject(parent) + , d(d) +{ +} + +QSGDropAreaDrag::~QSGDropAreaDrag() +{ +} + +class QSGDropAreaPrivate : public QSGItemPrivate +{ + Q_DECLARE_PUBLIC(QSGDropArea) + +public: + QSGDropAreaPrivate(); + ~QSGDropAreaPrivate(); + + bool hasMatchingKey(const QStringList &keys) const; + + QStringList getKeys(const QMimeData *mimeData) const; + + QStringList keys; + QRegExp keyRegExp; + QPointF dragPosition; + QSGDropAreaDrag *drag; + QDeclarativeGuard<QObject> source; + QDeclarativeGuard<QMimeData> mimeData; +}; + +QSGDropAreaPrivate::QSGDropAreaPrivate() + : drag(0) +{ +} + +QSGDropAreaPrivate::~QSGDropAreaPrivate() +{ + delete drag; +} + +/*! + \qmlclass DropArea QSGDropArea + \inqmlmodule QtQuick 2 + \brief The DropArea item provides drag and drop handling. + + A DropArea is an invisible item which receives events when other items are + dragged over it. + + The Drag attached property can be used to notify the DropArea when an Item is + dragged over it. + + 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. +*/ + +QSGDropArea::QSGDropArea(QSGItem *parent) + : QSGItem(*new QSGDropAreaPrivate, parent) +{ + setFlags(ItemAcceptsDrops); +} + +QSGDropArea::~QSGDropArea() +{ +} + +/*! + \qmlproperty bool QtQuick2::DropArea::containsDrag + + This property identifies whether the DropArea currently contains any + dragged items. +*/ + +bool QSGDropArea::containsDrag() const +{ + Q_D(const QSGDropArea); + return d->mimeData; +} + +/*! + \qmlproperty stringlist QtQuick2::DropArea::keys + + This property holds a list of drag keys a DropArea will accept. + + If no keys are listed the DropArea will accept events from any drag source, + otherwise the drag source must have at least one compatible key. + + \sa QtQuick2::Drag::keys +*/ + +QStringList QSGDropArea::keys() const +{ + Q_D(const QSGDropArea); + return d->keys; +} + +void QSGDropArea::setKeys(const QStringList &keys) +{ + Q_D(QSGDropArea); + 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(); + } +} + +QSGDropAreaDrag *QSGDropArea::drag() +{ + Q_D(QSGDropArea); + if (!d->drag) + d->drag = new QSGDropAreaDrag(d); + return d->drag; +} + +/*! + \qmlproperty Object QtQuick2::DropArea::drag.source + + This property holds the source of a drag. +*/ + +QObject *QSGDropAreaDrag::source() const +{ + return d->source; +} + +/*! + \qmlproperty qreal QtQuick2::DropArea::drag.x + \qmlproperty qreal QtQuick2::DropArea::drag.y + + These properties hold the coordinates of the last drag event. +*/ + +qreal QSGDropAreaDrag::x() const +{ + return d->dragPosition.x(); +} + +qreal QSGDropAreaDrag::y() const +{ + return d->dragPosition.y(); +} + +/*! + \qmlsignal QtQuick2::DropArea::onPositionChanged(DragEvent drag) + + This handler is called when the position of a drag has changed. +*/ + +void QSGDropArea::dragMoveEvent(QDragMoveEvent *event) +{ + Q_D(QSGDropArea); + if (!d->mimeData) + return; + + d->dragPosition = event->pos(); + if (d->drag) + emit d->drag->positionChanged(); + + event->accept(); + QSGDropEvent dragTargetEvent(d, event); + emit positionChanged(&dragTargetEvent); +} + +bool QSGDropAreaPrivate::hasMatchingKey(const QStringList &keys) const +{ + if (keyRegExp.isEmpty()) + return true; + + foreach (const QString &key, keys) { + if (keyRegExp.exactMatch(key)) + return true; + } + return false; +} + +QStringList QSGDropAreaPrivate::getKeys(const QMimeData *mimeData) const +{ + if (const QSGDragMimeData *dragMime = qobject_cast<const QSGDragMimeData *>(mimeData)) + return dragMime->keys(); + return mimeData->formats(); +} + +/*! + \qmlsignal QtQuick2::DropArea::onEntered(DragEvent drag) + + This handler is called when a \a drag enters the bounds of a DropArea. +*/ + +void QSGDropArea::dragEnterEvent(QDragEnterEvent *event) +{ + Q_D(QSGDropArea); + const QMimeData *mimeData = event->mimeData(); + if (!d->effectiveEnable || d->mimeData || !mimeData || !d->hasMatchingKey(d->getKeys(mimeData))) + return; + + d->dragPosition = event->pos(); + + event->accept(); + QSGDropEvent dragTargetEvent(d, event); + emit entered(&dragTargetEvent); + + if (event->isAccepted()) { + d->mimeData = const_cast<QMimeData *>(mimeData); + if (QSGDragMimeData *dragMime = qobject_cast<QSGDragMimeData *>(d->mimeData)) + d->source = dragMime->source(); + else + d->source = event->source(); + d->dragPosition = event->pos(); + if (d->drag) { + emit d->drag->positionChanged(); + emit d->drag->sourceChanged(); + } + emit containsDragChanged(); + } +} + +/*! + \qmlsignal QtQuick2::DropArea::onExited() + + This handler is called when a drag exits the bounds of a DropArea. +*/ + +void QSGDropArea::dragLeaveEvent(QDragLeaveEvent *) +{ + Q_D(QSGDropArea); + if (!d->mimeData) + return; + + emit exited(); + + d->mimeData = 0; + d->source = 0; + emit containsDragChanged(); + if (d->drag) + emit d->drag->sourceChanged(); +} + +/*! + \qmlsignal QtQuick2::DropArea::onDropped(DragEvent drop) + + This handler is called when a drop event occurs within the bounds of a + a DropArea. +*/ + +void QSGDropArea::dropEvent(QDropEvent *event) +{ + Q_D(QSGDropArea); + if (!d->mimeData) + return; + + QSGDropEvent dragTargetEvent(d, event); + emit dropped(&dragTargetEvent); + + d->mimeData = 0; + d->source = 0; + emit containsDragChanged(); + if (d->drag) + emit d->drag->sourceChanged(); +} + +/*! + \qmlclass DragEvent QSGDragEvent + \inqmlmodule QtQuick 2 + \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 y + properties, and the \l keys property identifies the drag keys of the event + \l source. +*/ + +/*! + \qmlproperty real QtQuick2::DragEvent::x + + This property holds the x coordinate of a drag event. +*/ + +/*! + \qmlproperty real QtQuick2::DragEvent::y + + This property holds the y coordinate of a drag event. +*/ + +/*! + \qmlproperty Object QtQuick2::DragEvent::drag.source + + This property holds the source of a drag event. +*/ + +QObject *QSGDropEvent::source() +{ + if (const QSGDragMimeData *dragMime = qobject_cast<const QSGDragMimeData *>(event->mimeData())) + return dragMime->source(); + else + return event->source(); +} + +/*! + \qmlproperty stringlist QtQuick2::DragEvent::keys + + This property holds a list of keys identifying the data type or source of a + drag event. +*/ + +QStringList QSGDropEvent::keys() const +{ + return d->getKeys(event->mimeData()); +} + +/*! + \qmlproperty enum QtQuick2::DragEvent::action + + This property holds the action that the \l source is to perform on an accepted drop. + + The drop action may be one of: + + \list + \o Qt.CopyAction Copy the data to the target + \o Qt.MoveAction Move the data from the source to the target + \o Qt.LinkAction Create a link from the source to the target. + \o Qt.IgnoreAction Ignore the action (do nothing with the data). + \endlist +*/ + +/*! + \qmlproperty flags QtQuick2::DragEvent::supportedActions + + This property holds the set of \l {action}{actions} supported by the + drag source. +*/ + +/*! + \qmlproperty real QtQuick2::DragEvent::accepted + + This property holds whether the drag event was accepted by a handler. + + The default value is true. +*/ + +/*! + \qmlmethod void QtQuick2::DragEvent::accept() + \qmlmethod void QtQuick2::DragEvent::accept(enum action) + + Accepts the drag event. + + If an \a action is specified it will overwrite the value of the \l action property. +*/ + +void QSGDropEvent::accept(QDeclarativeV8Function *args) +{ + Qt::DropAction action = event->dropAction(); + + if (args->Length() >= 1) { + v8::Local<v8::Value> v = (*args)[0]; + if (v->IsInt32()) + action = Qt::DropAction(v->Int32Value()); + } + // get action from arguments. + event->setDropAction(action); + event->accept(); +} + + +QT_END_NAMESPACE + diff --git a/src/declarative/items/qsgdragtarget_p.h b/src/declarative/items/qsgdroparea_p.h index 004bec1f20..cd51f57e0b 100644 --- a/src/declarative/items/qsgdragtarget_p.h +++ b/src/declarative/items/qsgdroparea_p.h @@ -39,11 +39,15 @@ ** ****************************************************************************/ -#ifndef QSGDRAGTARGET_P_H -#define QSGDRAGTARGET_P_H +#ifndef QSGDROPAREA_P_H +#define QSGDROPAREA_P_H #include "qsgitem.h" -#include "qsgevent.h" + +#include <private/qdeclarativeguard_p.h> +#include <private/qv8engine_p.h> + +#include <QtGui/qevent.h> QT_BEGIN_HEADER @@ -51,44 +55,78 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QSGDragTargetEvent : public QObject +class QSGDropAreaPrivate; +class QSGDropEvent : public QObject { Q_OBJECT Q_PROPERTY(qreal x READ x) Q_PROPERTY(qreal y READ y) - Q_PROPERTY(QVariant data READ data) + Q_PROPERTY(QObject *source READ source) Q_PROPERTY(QStringList keys READ keys) + Q_PROPERTY(Qt::DropActions supportedActions READ supportedActions) + Q_PROPERTY(Qt::DropAction action READ action WRITE setAction RESET resetAction) Q_PROPERTY(bool accepted READ accepted WRITE setAccepted) public: - QSGDragTargetEvent(QSGDragEvent *event) : _event(event) {} + QSGDropEvent(QSGDropAreaPrivate *d, QDropEvent *event) : d(d), event(event) {} + + qreal x() const { return event->pos().x(); } + qreal y() const { return event->pos().y(); } + + QObject *source(); + + Qt::DropActions supportedActions() const { return event->possibleActions(); } + Qt::DropAction action() const { return event->dropAction(); } + void setAction(Qt::DropAction action) { event->setDropAction(action); } + void resetAction() { event->setDropAction(event->proposedAction()); } + + QStringList keys() const; + + bool accepted() const { return event->isAccepted(); } + void setAccepted(bool accepted) { event->setAccepted(accepted); } + + Q_INVOKABLE void accept(QDeclarativeV8Function *); - qreal x() const { return _event->x(); } - qreal y() const { return _event->y(); } +private: + QSGDropAreaPrivate *d; + QDropEvent *event; +}; - QVariant data() const { return _event->data(); } - QStringList keys() const { return _event->keys(); } +class QSGDropAreaDrag : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal x READ x NOTIFY positionChanged) + Q_PROPERTY(qreal y READ y NOTIFY positionChanged) + Q_PROPERTY(QObject *source READ source NOTIFY sourceChanged) +public: + QSGDropAreaDrag(QSGDropAreaPrivate *d, QObject *parent = 0); + ~QSGDropAreaDrag(); - bool accepted() const { return _event->isAccepted(); } - void setAccepted(bool accepted) { _event->setAccepted(accepted); } + qreal x() const; + qreal y() const; + QObject *source() const; + +Q_SIGNALS: + void positionChanged(); + void sourceChanged(); private: - QSGDragEvent *_event; + QSGDropAreaPrivate *d; + + friend class QSGDropArea; + friend class QSGDropAreaPrivate; }; -class QSGDragTargetPrivate; -class Q_AUTOTEST_EXPORT QSGDragTarget : public QSGItem +class QSGDropAreaPrivate; +class Q_AUTOTEST_EXPORT QSGDropArea : 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) + Q_PROPERTY(QSGDropAreaDrag *drag READ drag CONSTANT) public: - QSGDragTarget(QSGItem *parent=0); - ~QSGDragTarget(); + QSGDropArea(QSGItem *parent=0); + ~QSGDropArea(); bool containsDrag() const; void setContainsDrag(bool drag); @@ -96,41 +134,33 @@ public: 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; + QSGDropAreaDrag *drag(); Q_SIGNALS: void containsDragChanged(); void keysChanged(); - void dropItemChanged(); - void dragPositionChanged(); - void dragDataChanged(); + void sourceChanged(); - void entered(QSGDragTargetEvent *drag); - void exited(QSGDragTargetEvent *drag); - void positionChanged(QSGDragTargetEvent *drag); - void dropped(QSGDragTargetEvent *drag); + void entered(QSGDropEvent *drag); + void exited(); + void positionChanged(QSGDropEvent *drag); + void dropped(QSGDropEvent *drop); protected: - void dragMoveEvent(QSGDragEvent *event); - void dragEnterEvent(QSGDragEvent *event); - void dragExitEvent(QSGDragEvent *event); - void dragDropEvent(QSGDragEvent *event); + void dragMoveEvent(QDragMoveEvent *event); + void dragEnterEvent(QDragEnterEvent *event); + void dragLeaveEvent(QDragLeaveEvent *event); + void dropEvent(QDropEvent *event); private: - Q_DISABLE_COPY(QSGDragTarget) - Q_DECLARE_PRIVATE(QSGDragTarget) + Q_DISABLE_COPY(QSGDropArea) + Q_DECLARE_PRIVATE(QSGDropArea) }; QT_END_NAMESPACE -QML_DECLARE_TYPE(QSGDragTargetEvent) -QML_DECLARE_TYPE(QSGDragTarget) +QML_DECLARE_TYPE(QSGDropEvent) +QML_DECLARE_TYPE(QSGDropArea) QT_END_HEADER diff --git a/src/declarative/items/qsgevent.h b/src/declarative/items/qsgevent.h deleted file mode 100644 index d82ee809ae..0000000000 --- a/src/declarative/items/qsgevent.h +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 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 76a1f1bef9..8ede2a490e 100644 --- a/src/declarative/items/qsgitem.cpp +++ b/src/declarative/items/qsgitem.cpp @@ -44,7 +44,6 @@ #include "qsgcanvas.h" #include <QtDeclarative/qjsengine.h> #include "qsgcanvas_p.h" -#include "qsgevent.h" #include "qsgevents_p_p.h" @@ -2882,24 +2881,26 @@ void QSGItem::hoverLeaveEvent(QHoverEvent *event) Q_UNUSED(event); } -void QSGItem::dragMoveEvent(QSGDragEvent *event) +void QSGItem::dragEnterEvent(QDragEnterEvent *event) { - event->setAccepted(false); + Q_UNUSED(event); } -void QSGItem::dragEnterEvent(QSGDragEvent *event) +void QSGItem::dragMoveEvent(QDragMoveEvent *event) { - event->setAccepted(false); + + Q_UNUSED(event); } -void QSGItem::dragExitEvent(QSGDragEvent *event) +void QSGItem::dragLeaveEvent(QDragLeaveEvent *event) { - event->setAccepted(false); + + Q_UNUSED(event); } -void QSGItem::dragDropEvent(QSGDragEvent *event) +void QSGItem::dropEvent(QDropEvent *event) { - event->setAccepted(false); + Q_UNUSED(event); } bool QSGItem::childMouseEventFilter(QSGItem *, QEvent *) @@ -3424,23 +3425,23 @@ void QSGItemPrivate::deliverHoverEvent(QHoverEvent *e) } } -void QSGItemPrivate::deliverDragEvent(QSGDragEvent *e) +void QSGItemPrivate::deliverDragEvent(QEvent *e) { Q_Q(QSGItem); switch (e->type()) { default: Q_ASSERT(!"Unknown event type"); - case QSGEvent::SGDragEnter: - q->dragEnterEvent(e); + case QEvent::DragEnter: + q->dragEnterEvent(static_cast<QDragEnterEvent *>(e)); break; - case QSGEvent::SGDragExit: - q->dragExitEvent(e); + case QEvent::DragLeave: + q->dragLeaveEvent(static_cast<QDragLeaveEvent *>(e)); break; - case QSGEvent::SGDragMove: - q->dragMoveEvent(e); + case QEvent::DragMove: + q->dragMoveEvent(static_cast<QDragMoveEvent *>(e)); break; - case QSGEvent::SGDragDrop: - q->dragDropEvent(e); + case QEvent::Drop: + q->dropEvent(static_cast<QDropEvent *>(e)); break; } } diff --git a/src/declarative/items/qsgitem.h b/src/declarative/items/qsgitem.h index e340a6a364..018453f68f 100644 --- a/src/declarative/items/qsgitem.h +++ b/src/declarative/items/qsgitem.h @@ -154,7 +154,8 @@ public: ItemClipsChildrenToShape = 0x01, ItemAcceptsInputMethod = 0x02, ItemIsFocusScope = 0x04, - ItemHasContents = 0x08 + ItemHasContents = 0x08, + ItemAcceptsDrops = 0x10 // Remember to increment the size of QSGItemPrivate::flags }; Q_DECLARE_FLAGS(Flags, Flag) @@ -373,10 +374,10 @@ protected: virtual void hoverEnterEvent(QHoverEvent *event); virtual void hoverMoveEvent(QHoverEvent *event); virtual void hoverLeaveEvent(QHoverEvent *event); - virtual void dragMoveEvent(QSGDragEvent *event); - virtual void dragEnterEvent(QSGDragEvent *event); - virtual void dragExitEvent(QSGDragEvent *event); - virtual void dragDropEvent(QSGDragEvent *event); + virtual void dragEnterEvent(QDragEnterEvent *); + virtual void dragMoveEvent(QDragMoveEvent *); + virtual void dragLeaveEvent(QDragLeaveEvent *); + virtual void dropEvent(QDropEvent *); virtual bool childMouseEventFilter(QSGItem *, QEvent *); virtual void windowDeactivateEvent(); diff --git a/src/declarative/items/qsgitem_p.h b/src/declarative/items/qsgitem_p.h index e48c1043e5..02c3f8772f 100644 --- a/src/declarative/items/qsgitem_p.h +++ b/src/declarative/items/qsgitem_p.h @@ -232,7 +232,7 @@ public: QDeclarativeStateGroup *_stateGroup; QSGItem::TransformOrigin origin:5; - quint32 flags:4; + quint32 flags:5; bool widthValid:1; bool heightValid:1; bool componentComplete:1; @@ -326,7 +326,7 @@ public: void deliverWheelEvent(QWheelEvent *); void deliverTouchEvent(QTouchEvent *); void deliverHoverEvent(QHoverEvent *); - void deliverDragEvent(QSGDragEvent *); + void deliverDragEvent(QEvent *); bool calcEffectiveVisible() const; void setEffectiveVisibleRecur(bool); diff --git a/src/declarative/items/qsgitemsmodule.cpp b/src/declarative/items/qsgitemsmodule.cpp index db98dc4ad5..70a9499266 100644 --- a/src/declarative/items/qsgitemsmodule.cpp +++ b/src/declarative/items/qsgitemsmodule.cpp @@ -78,7 +78,8 @@ #include "qsgcontext2d_p.h" #include "qsgsprite_p.h" #include "qsgspriteimage_p.h" -#include "qsgdragtarget_p.h" +#include "qsgdrag_p.h" +#include "qsgdroparea_p.h" static QDeclarativePrivate::AutoParentResult qsgitem_autoParent(QObject *obj, QObject *parent) { @@ -106,7 +107,6 @@ static void qt_sgitems_defineModule(const char *uri, int major, int minor) #endif qmlRegisterType<QSGBorderImage>(uri,major,minor,"BorderImage"); qmlRegisterType<QSGColumn>(uri,major,minor,"Column"); - qmlRegisterType<QSGDrag>(uri,major,minor,"Drag"); qmlRegisterType<QSGFlickable>(uri,major,minor,"Flickable"); qmlRegisterType<QSGFlipable>(uri,major,minor,"Flipable"); qmlRegisterType<QSGFlow>(uri,major,minor,"Flow"); @@ -196,8 +196,10 @@ static void qt_sgitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QSGPathAnimation>("QtQuick",2,0,"PathAnimation"); qmlRegisterType<QDeclarativePathInterpolator>("QtQuick",2,0,"PathInterpolator"); - qmlRegisterType<QSGDragTarget>("QtQuick", 2, 0, "DragTarget"); - qmlRegisterType<QSGDragTargetEvent>(); + qmlRegisterType<QSGDropArea>("QtQuick", 2, 0, "DropArea"); + qmlRegisterType<QSGDropEvent>(); + qmlRegisterType<QSGDropAreaDrag>(); + qmlRegisterUncreatableType<QSGDrag>("QtQuick", 2, 0, "Drag", QSGDragAttached::tr("Drag is only available via attached properties")); } void QSGItemsModule::defineModule() diff --git a/src/declarative/items/qsgmousearea.cpp b/src/declarative/items/qsgmousearea.cpp index cae0be60c5..de7913c3d1 100644 --- a/src/declarative/items/qsgmousearea.cpp +++ b/src/declarative/items/qsgmousearea.cpp @@ -42,8 +42,8 @@ #include "qsgmousearea_p.h" #include "qsgmousearea_p_p.h" #include "qsgcanvas.h" -#include "qsgevent.h" #include "qsgevents_p_p.h" +#include "qsgdrag_p.h" #include <QtGui/qevent.h> #include <QtGui/qguiapplication.h> @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE static const int PressAndHoldDelay = 800; QSGDrag::QSGDrag(QObject *parent) -: QObject(parent), _target(0), _dropItem(0), _grabItem(0), _axis(XandYAxis), _xmin(-FLT_MAX), +: QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX), _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false) { } @@ -85,64 +85,6 @@ void QSGDrag::resetTarget() emit targetChanged(); } -/*! - \qmlproperty Item QtQuick2::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 QtQuick2::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; @@ -234,29 +176,14 @@ void QSGDrag::setFilterChildren(bool filter) emit filterChildrenChanged(); } -/*! - \qmlproperty stringlist QtQuick2::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 +QSGDragAttached *QSGDrag::qmlAttachedProperties(QObject *obj) { - return _keys; -} - -void QSGDrag::setKeys(const QStringList &keys) -{ - if (_keys != keys) { - _keys = keys; - emit keysChanged(); - } + return QSGDragAttached::properties(obj); } QSGMouseAreaPrivate::QSGMouseAreaPrivate() : absorb(true), hovered(false), pressed(false), longPress(false), - moved(false), stealMouse(false), doubleClick(false), preventStealing(false), dragRejected(false), + moved(false), stealMouse(false), doubleClick(false), preventStealing(false), drag(0) { } @@ -708,7 +635,6 @@ void QSGMouseArea::mousePressEvent(QMouseEvent *event) QSGItem::mousePressEvent(event); else { d->longPress = false; - d->dragRejected = false; d->saveEvent(event); if (d->drag) { d->dragX = drag()->axis() & QSGDrag::XAxis; @@ -744,7 +670,6 @@ void QSGMouseArea::mouseMoveEvent(QMouseEvent *event) setHovered(true); if (d->drag && d->drag->target()) { - if (!d->moved) { d->targetStartPos = d->drag->target()->parentItem() ? d->drag->target()->parentItem()->mapToScene(d->drag->target()->pos()) @@ -765,36 +690,22 @@ void QSGMouseArea::mouseMoveEvent(QMouseEvent *event) qreal dx = qAbs(curLocalPos.x() - startLocalPos.x()); qreal dy = qAbs(curLocalPos.y() - startLocalPos.y()); - 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 (keepMouseGrab() && d->stealMouse && !d->drag->active()) + d->drag->setActive(true); QPointF startPos = d->drag->target()->parentItem() ? d->drag->target()->parentItem()->mapFromScene(d->targetStartPos) : d->targetStartPos; + QPointF dragPos = d->drag->target()->pos(); + if (d->dragX && d->drag->active()) { qreal x = (curLocalPos.x() - startLocalPos.x()) + startPos.x(); if (x < drag()->xmin()) x = drag()->xmin(); else if (x > drag()->xmax()) x = drag()->xmax(); - drag()->target()->setX(x); + dragPos.setX(x); } if (d->dragY && d->drag->active()) { qreal y = (curLocalPos.y() - startLocalPos.y()) + startPos.y(); @@ -802,8 +713,9 @@ void QSGMouseArea::mouseMoveEvent(QMouseEvent *event) y = drag()->ymin(); else if (y > drag()->ymax()) y = drag()->ymax(); - drag()->target()->setY(y); + dragPos.setY(y); } + d->drag->target()->setPos(dragPos); if (!keepMouseGrab()) { if ((!d->dragY && dy < dragThreshold && d->dragX && dx > dragThreshold) @@ -815,18 +727,6 @@ void QSGMouseArea::mouseMoveEvent(QMouseEvent *event) } d->moved = true; - - if (d->drag->active()) { - QSGDragEvent dragEvent( - QSGEvent::SGDragMove, - event->windowPos(), - 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 mouseXChanged(&me); @@ -845,24 +745,8 @@ void QSGMouseArea::mouseReleaseEvent(QMouseEvent *event) } else { d->saveEvent(event); setPressed(false); - if (d->drag && d->drag->active()) { - QSGDragEvent dragEvent( - QSGEvent::SGDragDrop, - event->windowPos(), - 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); + if (d->drag) 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 a8015fc99b..f0edf41777 100644 --- a/src/declarative/items/qsgmousearea_p.h +++ b/src/declarative/items/qsgmousearea_p.h @@ -53,6 +53,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) +class QSGDragAttached; class QSGMouseEvent; class Q_AUTOTEST_EXPORT QSGDrag : public QObject { @@ -60,8 +61,6 @@ class Q_AUTOTEST_EXPORT QSGDrag : public QObject 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) @@ -69,7 +68,6 @@ 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: @@ -77,19 +75,9 @@ public: ~QSGDrag(); QSGItem *target() const; - void setTarget(QSGItem *); + void setTarget(QSGItem *target); 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); @@ -109,17 +97,10 @@ 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(); } + static QSGDragAttached *qmlAttachedProperties(QObject *obj); Q_SIGNALS: void targetChanged(); - void dropItemChanged(); - void dataChanged(); void axisChanged(); void minimumXChanged(); void maximumXChanged(); @@ -127,17 +108,9 @@ 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; @@ -245,6 +218,7 @@ private: QT_END_NAMESPACE QML_DECLARE_TYPE(QSGDrag) +QML_DECLARE_TYPEINFO(QSGDrag, QML_HAS_ATTACHED_PROPERTIES) QML_DECLARE_TYPE(QSGMouseArea) QT_END_HEADER diff --git a/src/declarative/items/qsgmousearea_p_p.h b/src/declarative/items/qsgmousearea_p_p.h index 2ec1eda3f7..6cf663ac6d 100644 --- a/src/declarative/items/qsgmousearea_p_p.h +++ b/src/declarative/items/qsgmousearea_p_p.h @@ -95,7 +95,6 @@ public: bool stealMouse : 1; bool doubleClick : 1; bool preventStealing : 1; - bool dragRejected : 1; QSGDrag *drag; QPointF startScene; QPointF targetStartPos; diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index 324880120b..c9b54b2908 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -64,6 +64,8 @@ SGTESTS = \ qsganimatedimage \ qsgborderimage \ qsgcanvas \ + qsgdrag \ + qsgdroparea \ qsgflickable \ qsgflipable \ qsgfocusscope \ diff --git a/tests/auto/declarative/qsgdrag/qsgdrag.pro b/tests/auto/declarative/qsgdrag/qsgdrag.pro new file mode 100644 index 0000000000..213385cd1f --- /dev/null +++ b/tests/auto/declarative/qsgdrag/qsgdrag.pro @@ -0,0 +1,11 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative gui network +macx:CONFIG -= app_bundle + +SOURCES += tst_qsgdrag.cpp + +DEFINES += SRCDIR=\\\"$$PWD\\\" + +CONFIG += parallel_test + +QT += core-private gui-private declarative-private diff --git a/tests/auto/declarative/qsgdrag/tst_qsgdrag.cpp b/tests/auto/declarative/qsgdrag/tst_qsgdrag.cpp new file mode 100644 index 0000000000..5d5da9a931 --- /dev/null +++ b/tests/auto/declarative/qsgdrag/tst_qsgdrag.cpp @@ -0,0 +1,768 @@ +/**************************************************************************** +** +** 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 <QtDeclarative/qsgitem.h> +#include <QtDeclarative/qsgview.h> +#include <QtDeclarative/qdeclarativecontext.h> +#include <QtDeclarative/qdeclarativeengine.h> +#include <QtDeclarative/qdeclarativeexpression.h> +#include "../../../shared/util.h" + +template <typename T> static T evaluate(QObject *scope, const QString &expression) +{ + QDeclarativeExpression expr(qmlContext(scope), scope, expression); + QVariant result = expr.evaluate(); + if (expr.hasError()) + qWarning() << expr.error().toString(); + return result.value<T>(); +} + +template <> void evaluate<void>(QObject *scope, const QString &expression) +{ + QDeclarativeExpression expr(qmlContext(scope), scope, expression); + expr.evaluate(); + if (expr.hasError()) + qWarning() << expr.error().toString(); +} + +Q_DECLARE_METATYPE(Qt::DropActions) + +class TestDropTarget : public QSGItem +{ + Q_OBJECT +public: + TestDropTarget(QSGItem *parent = 0) + : QSGItem(parent) + , enterEvents(0) + , moveEvents(0) + , leaveEvents(0) + , dropEvents(0) + , acceptAction(Qt::MoveAction) + , defaultAction(Qt::IgnoreAction) + , proposedAction(Qt::IgnoreAction) + , accept(true) + { + setFlags(ItemAcceptsDrops); + } + + void reset() + { + enterEvents = 0; + moveEvents = 0; + leaveEvents = 0; + dropEvents = 0; + defaultAction = Qt::IgnoreAction; + proposedAction = Qt::IgnoreAction; + supportedActions = Qt::IgnoreAction; + } + + void dragEnterEvent(QDragEnterEvent *event) + { + ++enterEvents; + position = event->pos(); + defaultAction = event->dropAction(); + proposedAction = event->proposedAction(); + supportedActions = event->possibleActions(); + event->setAccepted(accept); + } + + void dragMoveEvent(QDragMoveEvent *event) + { + ++moveEvents; + position = event->pos(); + defaultAction = event->dropAction(); + proposedAction = event->proposedAction(); + supportedActions = event->possibleActions(); + event->setAccepted(accept); + } + + void dragLeaveEvent(QDragLeaveEvent *event) + { + ++leaveEvents; + event->setAccepted(accept); + } + + void dropEvent(QDropEvent *event) + { + ++dropEvents; + position = event->pos(); + defaultAction = event->dropAction(); + proposedAction = event->proposedAction(); + supportedActions = event->possibleActions(); + event->setDropAction(acceptAction); + event->setAccepted(accept); + } + + int enterEvents; + int moveEvents; + int leaveEvents; + int dropEvents; + Qt::DropAction acceptAction; + Qt::DropAction defaultAction; + Qt::DropAction proposedAction; + Qt::DropActions supportedActions; + QPointF position; + bool accept; +}; + +class tst_QSGDrag: public QObject +{ + Q_OBJECT +private slots: + void initTestCase(); + void cleanupTestCase(); + + void active(); + void drop(); + void move(); + void hotSpot(); + void supportedActions(); + void proposedAction(); + void keys(); + void source(); + +private: + QDeclarativeEngine engine; +}; + +void tst_QSGDrag::initTestCase() +{ + +} + +void tst_QSGDrag::cleanupTestCase() +{ + +} + +void tst_QSGDrag::active() +{ + QSGCanvas canvas; + TestDropTarget dropTarget(canvas.rootItem()); + dropTarget.setSize(QSizeF(100, 100)); + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "Item {\n" + "property bool dragActive: Drag.active\n" + "property Item dragTarget: Drag.target\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}", QUrl()); + QSGItem *item = qobject_cast<QSGItem *>(component.create()); + QVERIFY(item); + item->setParentItem(&dropTarget); + + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + + evaluate<void>(item, "Drag.active = true"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget)); + QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); + + dropTarget.reset(); + evaluate<void>(item, "Drag.active = false"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); + + dropTarget.reset(); + evaluate<void>(item, "Drag.cancel()"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); + + dropTarget.reset(); + evaluate<void>(item, "Drag.start()"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget)); + QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); + + // Start while a drag is active, cancels the previous drag and starts a new one. + dropTarget.reset(); + evaluate<void>(item, "Drag.start()"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget)); + QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 1); + + dropTarget.reset(); + evaluate<void>(item, "Drag.cancel()"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); + + // Enter events aren't sent to items without the QSGItem::ItemAcceptsDrops flag. + dropTarget.setFlags(QSGItem::Flags()); + + dropTarget.reset(); + evaluate<void>(item, "Drag.active = true"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); + + dropTarget.reset(); + evaluate<void>(item, "Drag.active = false"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); + + dropTarget.setFlags(QSGItem::ItemAcceptsDrops); + + dropTarget.reset(); + evaluate<void>(item, "Drag.active = true"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget)); + QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); + + dropTarget.setFlags(QSGItem::Flags()); + + dropTarget.reset(); + evaluate<void>(item, "Drag.active = false"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); + + // Follow up events aren't sent to items if the enter event isn't accepted. + dropTarget.setFlags(QSGItem::ItemAcceptsDrops); + dropTarget.accept = false; + + dropTarget.reset(); + evaluate<void>(item, "Drag.active = true"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); + + dropTarget.reset(); + evaluate<void>(item, "Drag.active = false"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); + + dropTarget.accept = true; + + dropTarget.reset(); + evaluate<void>(item, "Drag.active = true"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget)); + QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); + + dropTarget.accept = false; + + dropTarget.reset(); + evaluate<void>(item, "Drag.active = false"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); +} + +void tst_QSGDrag::drop() +{ + QSGCanvas canvas; + TestDropTarget outerTarget(canvas.rootItem()); + outerTarget.setSize(QSizeF(100, 100)); + outerTarget.acceptAction = Qt::CopyAction; + TestDropTarget innerTarget(&outerTarget); + innerTarget.setSize(QSizeF(100, 100)); + innerTarget.acceptAction = Qt::MoveAction; + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "Item {\n" + "property bool dragActive: Drag.active\n" + "property Item dragTarget: Drag.target\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}", QUrl()); + QSGItem *item = qobject_cast<QSGItem *>(component.create()); + QVERIFY(item); + item->setParentItem(&outerTarget); + + innerTarget.reset(); outerTarget.reset(); + evaluate<void>(item, "Drag.active = true"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&innerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&innerTarget)); + QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); + QCOMPARE(innerTarget.enterEvents, 1); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); + + innerTarget.reset(); outerTarget.reset(); + QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.MoveAction"), true); + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&innerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&innerTarget)); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 1); QCOMPARE(outerTarget.dropEvents, 0); + QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 1); + + innerTarget.reset(); outerTarget.reset(); + evaluate<void>(item, "Drag.active = true"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&innerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&innerTarget)); + QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); + QCOMPARE(innerTarget.enterEvents, 1); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); + + // Inner target declines the drop so it is propagated to the outer target. + innerTarget.accept = false; + + innerTarget.reset(); outerTarget.reset(); + QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.CopyAction"), true); + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1); + QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 1); + + + // Inner target doesn't accept enter so drop goes directly to outer. + innerTarget.accept = true; + innerTarget.setFlags(QSGItem::Flags()); + + innerTarget.reset(); outerTarget.reset(); + evaluate<void>(item, "Drag.active = true"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); + QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); + + innerTarget.reset(); outerTarget.reset(); + QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.CopyAction"), true); + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1); + QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); + + // Neither target accepts drop so Qt::IgnoreAction is returned. + innerTarget.reset(); outerTarget.reset(); + evaluate<void>(item, "Drag.active = true"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); + QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); + + outerTarget.accept = false; + + innerTarget.reset(); outerTarget.reset(); + QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.IgnoreAction"), true); + QCOMPARE(evaluate<bool>(item, "Drag.active"), false); + QCOMPARE(evaluate<bool>(item, "dragActive"), false); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1); + QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); +} + +void tst_QSGDrag::move() +{ + QSGCanvas canvas; + TestDropTarget outerTarget(canvas.rootItem()); + outerTarget.setSize(QSizeF(100, 100)); + TestDropTarget leftTarget(&outerTarget); + leftTarget.setPos(QPointF(0, 35)); + leftTarget.setSize(QSizeF(30, 30)); + TestDropTarget rightTarget(&outerTarget); + rightTarget.setPos(QPointF(70, 35)); + rightTarget.setSize(QSizeF(30, 30)); + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "Item {\n" + "property bool dragActive: Drag.active\n" + "property Item dragTarget: Drag.target\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}", QUrl()); + QSGItem *item = qobject_cast<QSGItem *>(component.create()); + QVERIFY(item); + item->setParentItem(&outerTarget); + + evaluate<void>(item, "Drag.active = true"); + QCOMPARE(evaluate<bool>(item, "Drag.active"), true); + QCOMPARE(evaluate<bool>(item, "dragActive"), true); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0); + QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); + QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); + QCOMPARE(outerTarget.position.x(), qreal(50)); QCOMPARE(outerTarget.position.y(), qreal(50)); + + // Move within the outer target. + outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); + item->setPos(QPointF(60, 50)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1); + QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); + QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); + QCOMPARE(outerTarget.position.x(), qreal(60)); QCOMPARE(outerTarget.position.y(), qreal(50)); + + // Move into the right target. + outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); + item->setPos(QPointF(75, 50)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&rightTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&rightTarget)); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1); + QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); + QCOMPARE(rightTarget.enterEvents, 1); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); + QCOMPARE(outerTarget.position.x(), qreal(75)); QCOMPARE(outerTarget.position.y(), qreal(50)); + QCOMPARE(rightTarget.position.x(), qreal(5)); QCOMPARE(rightTarget.position.y(), qreal(15)); + + // Move into the left target. + outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); + item->setPos(QPointF(25, 50)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&leftTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&leftTarget)); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1); + QCOMPARE(leftTarget .enterEvents, 1); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); + QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 1); QCOMPARE(rightTarget.moveEvents, 0); + QCOMPARE(outerTarget.position.x(), qreal(25)); QCOMPARE(outerTarget.position.y(), qreal(50)); + QCOMPARE(leftTarget.position.x(), qreal(25)); QCOMPARE(leftTarget.position.y(), qreal(15)); + + // Move within the left target. + outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); + item->setPos(QPointF(25, 40)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&leftTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&leftTarget)); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1); + QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 1); + QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); + QCOMPARE(outerTarget.position.x(), qreal(25)); QCOMPARE(outerTarget.position.y(), qreal(40)); + QCOMPARE(leftTarget.position.x(), qreal(25)); QCOMPARE(leftTarget.position.y(), qreal(5)); + + // Move out of all targets. + outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); + item->setPos(QPointF(110, 50)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 1); QCOMPARE(outerTarget.moveEvents, 0); + QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 1); QCOMPARE(leftTarget .moveEvents, 0); + QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); + + // Stop the right target accepting drag events and move into it. + rightTarget.accept = false; + + outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); + item->setPos(QPointF(80, 50)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0); + QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); + QCOMPARE(rightTarget.enterEvents, 1); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); + QCOMPARE(outerTarget.position.x(), qreal(80)); QCOMPARE(outerTarget.position.y(), qreal(50)); + + // Stop the outer target accepting drag events after it has accepted an enter event. + outerTarget.accept = false; + + outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); + item->setPos(QPointF(60, 50)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1); + QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); + QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); + QCOMPARE(outerTarget.position.x(), qreal(60)); QCOMPARE(outerTarget.position.y(), qreal(50)); + + // Clear the QSGItem::ItemAcceptsDrops flag from the outer target after it accepted an enter event. + outerTarget.setFlags(QSGItem::Flags()); + + outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); + item->setPos(QPointF(40, 50)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1); + QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); + QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); + QCOMPARE(outerTarget.position.x(), qreal(40)); QCOMPARE(outerTarget.position.y(), qreal(50)); + + // Clear the QSGItem::ItemAcceptsDrops flag from the left target before it accepts an enter event. + leftTarget.setFlags(QSGItem::Flags()); + + outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); + item->setPos(QPointF(25, 50)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget)); + QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1); + QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); + QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); + QCOMPARE(outerTarget.position.x(), qreal(25)); QCOMPARE(outerTarget.position.y(), qreal(50)); +} + + +void tst_QSGDrag::hotSpot() +{ + QSGCanvas canvas; + TestDropTarget dropTarget(canvas.rootItem()); + dropTarget.setSize(QSizeF(100, 100)); + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "Item {\n" + "property real hotSpotX: Drag.hotSpot.x\n" + "property real hotSpotY: Drag.hotSpot.y\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}", QUrl()); + QSGItem *item = qobject_cast<QSGItem *>(component.create()); + QVERIFY(item); + item->setParentItem(&dropTarget); + + QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.x"), qreal(0)); + QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.y"), qreal(0)); + QCOMPARE(evaluate<qreal>(item, "hotSpotX"), qreal(0)); + QCOMPARE(evaluate<qreal>(item, "hotSpotY"), qreal(0)); + + evaluate<void>(item, "{ Drag.start(); Drag.cancel() }"); + QCOMPARE(dropTarget.position.x(), qreal(50)); + QCOMPARE(dropTarget.position.y(), qreal(50)); + + evaluate<void>(item, "{ Drag.hotSpot.x = 5, Drag.hotSpot.y = 5 }"); + QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.x"), qreal(5)); + QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.y"), qreal(5)); + QCOMPARE(evaluate<qreal>(item, "hotSpotX"), qreal(5)); + QCOMPARE(evaluate<qreal>(item, "hotSpotY"), qreal(5)); + + evaluate<void>(item, "Drag.start()"); + QCOMPARE(dropTarget.position.x(), qreal(55)); + QCOMPARE(dropTarget.position.y(), qreal(55)); + + item->setPos(QPointF(30, 20)); + QCOMPARE(dropTarget.position.x(), qreal(35)); + QCOMPARE(dropTarget.position.y(), qreal(25)); + + evaluate<void>(item, "{ Drag.hotSpot.x = 10; Drag.hotSpot.y = 10 }"); + QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.x"), qreal(10)); + QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.y"), qreal(10)); + QCOMPARE(evaluate<qreal>(item, "hotSpotX"), qreal(10)); + QCOMPARE(evaluate<qreal>(item, "hotSpotY"), qreal(10)); + // Changing the hotSpot won't generate a move event so the position is unchanged. Should it? + QCOMPARE(dropTarget.position.x(), qreal(35)); + QCOMPARE(dropTarget.position.y(), qreal(25)); + + item->setPos(QPointF(10, 20)); + QCOMPARE(dropTarget.position.x(), qreal(20)); + QCOMPARE(dropTarget.position.y(), qreal(30)); +} + +void tst_QSGDrag::supportedActions() +{ + QSGCanvas canvas; + TestDropTarget dropTarget(canvas.rootItem()); + dropTarget.setSize(QSizeF(100, 100)); + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "Item {\n" + "property int supportedActions: Drag.supportedActions\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}", QUrl()); + QSGItem *item = qobject_cast<QSGItem *>(component.create()); + QVERIFY(item); + item->setParentItem(&dropTarget); + + QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.CopyAction | Qt.MoveAction | Qt.LinkAction"), true); + QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.CopyAction | Qt.MoveAction | Qt.LinkAction"), true); + evaluate<void>(item, "{ Drag.start(); Drag.cancel() }"); + QCOMPARE(dropTarget.supportedActions, Qt::CopyAction | Qt::MoveAction | Qt::LinkAction); + + evaluate<void>(item, "Drag.supportedActions = Qt.CopyAction | Qt.MoveAction"); + QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.CopyAction | Qt.MoveAction"), true); + QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.CopyAction | Qt.MoveAction"), true); + evaluate<void>(item, "Drag.start()"); + QCOMPARE(dropTarget.supportedActions, Qt::CopyAction | Qt::MoveAction); + + // Once a drag is started the proposed actions are locked in for future events. + evaluate<void>(item, "Drag.supportedActions = Qt.MoveAction"); + QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.MoveAction"), true); + QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.MoveAction"), true); + item->setPos(QPointF(60, 60)); + QCOMPARE(dropTarget.supportedActions, Qt::CopyAction | Qt::MoveAction); + + // Calling start with proposed actions will override the current actions for the next sequence. + evaluate<void>(item, "Drag.start(Qt.CopyAction)"); + QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.MoveAction"), true); + QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.MoveAction"), true); + QCOMPARE(dropTarget.supportedActions, Qt::CopyAction); + + evaluate<void>(item, "Drag.start()"); + QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.MoveAction"), true); + QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.MoveAction"), true); + QCOMPARE(dropTarget.supportedActions, Qt::MoveAction); +} + +void tst_QSGDrag::proposedAction() +{ + QSGCanvas canvas; + TestDropTarget dropTarget(canvas.rootItem()); + dropTarget.setSize(QSizeF(100, 100)); + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "Item {\n" + "property int proposedAction: Drag.proposedAction\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}", QUrl()); + QSGItem *item = qobject_cast<QSGItem *>(component.create()); + QVERIFY(item); + item->setParentItem(&dropTarget); + + QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.MoveAction"), true); + QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.MoveAction"), true); + evaluate<void>(item, "{ Drag.start(); Drag.cancel() }"); + QCOMPARE(dropTarget.defaultAction, Qt::MoveAction); + QCOMPARE(dropTarget.proposedAction, Qt::MoveAction); + + evaluate<void>(item, "Drag.proposedAction = Qt.CopyAction"); + QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.CopyAction"), true); + QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.CopyAction"), true); + evaluate<void>(item, "Drag.start()"); + QCOMPARE(dropTarget.defaultAction, Qt::CopyAction); + QCOMPARE(dropTarget.proposedAction, Qt::CopyAction); + + // The proposed action can change during a drag. + evaluate<void>(item, "Drag.proposedAction = Qt.MoveAction"); + QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.MoveAction"), true); + QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.MoveAction"), true); + item->setPos(QPointF(60, 60)); + QCOMPARE(dropTarget.defaultAction, Qt::MoveAction); + QCOMPARE(dropTarget.proposedAction, Qt::MoveAction); + + evaluate<void>(item, "Drag.proposedAction = Qt.LinkAction"); + QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.LinkAction"), true); + QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.LinkAction"), true); + evaluate<void>(item, "Drag.drop()"); + QCOMPARE(dropTarget.defaultAction, Qt::LinkAction); + QCOMPARE(dropTarget.proposedAction, Qt::LinkAction); +} + +void tst_QSGDrag::keys() +{ + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "Item {\n" + "property variant keys: Drag.keys\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}", QUrl()); + QSGItem *item = qobject_cast<QSGItem *>(component.create()); + QVERIFY(item); + +// QCOMPARE(evaluate<QStringList>(item, "Drag.keys"), QStringList()); +// QCOMPARE(evaluate<QStringList>(item, "keys"), QStringList()); + QCOMPARE(item->property("keys").toStringList(), QStringList()); + + evaluate<void>(item, "Drag.keys = [\"red\", \"blue\"]"); +// QCOMPARE(evaluate<QStringList>(item, "Drag.keys"), QStringList() << "red" << "blue"); +// QCOMPARE(evaluate<QStringList>(item, "keys"), QStringList() << "red" << "blue"); + QCOMPARE(item->property("keys").toStringList(), QStringList() << "red" << "blue"); +} + +void tst_QSGDrag::source() +{ + + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "Item {\n" + "property Item source: Drag.source\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "Item { id: proxySource; objectName: \"proxySource\" }\n" + "}", QUrl()); + QSGItem *item = qobject_cast<QSGItem *>(component.create()); + QVERIFY(item); + + QCOMPARE(evaluate<QObject *>(item, "Drag.source"), static_cast<QObject *>(item)); + QCOMPARE(evaluate<QObject *>(item, "source"), static_cast<QObject *>(item)); + + QSGItem *proxySource = item->findChild<QSGItem *>("proxySource"); + QVERIFY(proxySource); + + evaluate<void>(item, "Drag.source = proxySource"); + QCOMPARE(evaluate<QObject *>(item, "Drag.source"), static_cast<QObject *>(proxySource)); + QCOMPARE(evaluate<QObject *>(item, "source"), static_cast<QObject *>(proxySource)); +} + +QTEST_MAIN(tst_QSGDrag) + +#include "tst_qsgdrag.moc" diff --git a/tests/auto/declarative/qsgdroparea/qsgdroparea.pro b/tests/auto/declarative/qsgdroparea/qsgdroparea.pro new file mode 100644 index 0000000000..2f4be247b0 --- /dev/null +++ b/tests/auto/declarative/qsgdroparea/qsgdroparea.pro @@ -0,0 +1,11 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative gui network +macx:CONFIG -= app_bundle + +SOURCES += tst_qsgdroparea.cpp + +DEFINES += SRCDIR=\\\"$$PWD\\\" + +CONFIG += parallel_test + +QT += core-private gui-private declarative-private diff --git a/tests/auto/declarative/qsgdroparea/tst_qsgdroparea.cpp b/tests/auto/declarative/qsgdroparea/tst_qsgdroparea.cpp new file mode 100644 index 0000000000..4fa6704611 --- /dev/null +++ b/tests/auto/declarative/qsgdroparea/tst_qsgdroparea.cpp @@ -0,0 +1,1063 @@ +/**************************************************************************** +** +** 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 <QtDeclarative/qsgitem.h> +#include <QtDeclarative/qsgview.h> +#include <QtDeclarative/qdeclarativecontext.h> +#include <QtDeclarative/qdeclarativeengine.h> +#include <QtDeclarative/qdeclarativeexpression.h> +#include "../../../shared/util.h" + +#include <QtGui/qwindowsysteminterface_qpa.h> + +template <typename T> static T evaluate(QObject *scope, const QString &expression) +{ + QDeclarativeExpression expr(qmlContext(scope), scope, expression); + QVariant result = expr.evaluate(); + if (expr.hasError()) + qWarning() << expr.error().toString(); + return result.value<T>(); +} + +template <> void evaluate<void>(QObject *scope, const QString &expression) +{ + QDeclarativeExpression expr(qmlContext(scope), scope, expression); + expr.evaluate(); + if (expr.hasError()) + qWarning() << expr.error().toString(); +} + +class tst_QSGDropArea: public QObject +{ + Q_OBJECT +private slots: + void initTestCase(); + void cleanupTestCase(); + + void containsDrag_internal(); + void containsDrag_external(); + void keys_internal(); + void keys_external(); + void source_internal(); +// void source_external(); + void position_internal(); + void position_external(); + void drop_internal(); +// void drop_external(); + void simultaneousDrags(); + +private: + QDeclarativeEngine engine; +}; + +void tst_QSGDropArea::initTestCase() +{ + +} + +void tst_QSGDropArea::cleanupTestCase() +{ + +} + +void tst_QSGDropArea::containsDrag_internal() +{ + QSGCanvas canvas; + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "DropArea {\n" + "property bool hasDrag: containsDrag\n" + "property int enterEvents: 0\n" + "property int exitEvents: 0\n" + "width: 100; height: 100\n" + "onEntered: {++enterEvents}\n" + "onExited: {++exitEvents}\n" + "Item {\n" + "objectName: \"dragItem\"\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}\n" + "}", QUrl()); + QSGItem *dropArea = qobject_cast<QSGItem *>(component.create()); + QVERIFY(dropArea); + dropArea->setParentItem(canvas.rootItem()); + + QSGItem *dragItem = dropArea->findChild<QSGItem *>("dragItem"); + QVERIFY(dragItem); + + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), false); + + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); + QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), true); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 0); + + evaluate<void>(dropArea, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem, "Drag.active = false"); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), false); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 1); + + evaluate<void>(dropArea, "{ enterEvents = 0; exitEvents = 0 }"); + + dragItem->setPos(QPointF(150, 50)); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), false); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 0); + + dragItem->setPos(QPointF(50, 50)); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); + QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), true); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 0); + + evaluate<void>(dropArea, "{ enterEvents = 0; exitEvents = 0 }"); + dragItem->setPos(QPointF(150, 50)); + + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), false); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 1); + + evaluate<void>(dragItem, "Drag.active = false"); +} + +void tst_QSGDropArea::containsDrag_external() +{ + QSGCanvas canvas; + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "DropArea {\n" + "property bool hasDrag: containsDrag\n" + "property int enterEvents: 0\n" + "property int exitEvents: 0\n" + "width: 100; height: 100\n" + "onEntered: {++enterEvents}\n" + "onExited: {++exitEvents}\n" + "}", QUrl()); + QSGItem *dropArea = qobject_cast<QSGItem *>(component.create()); + QVERIFY(dropArea); + dropArea->setParentItem(canvas.rootItem()); + + QMimeData data; + QSGCanvas alternateCanvas; + + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), false); + + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); + QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), true); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 0); + + evaluate<void>(dropArea, "{ enterEvents = 0; exitEvents = 0 }"); + QWindowSystemInterface::handleDrag(&alternateCanvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), false); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 1); + + evaluate<void>(dropArea, "{ enterEvents = 0; exitEvents = 0 }"); + + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(150, 50)); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), false); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 0); + + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); + QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), true); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 0); + + evaluate<void>(dropArea, "{ enterEvents = 0; exitEvents = 0 }"); + + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(150, 50)); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), false); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 1); + + QWindowSystemInterface::handleDrop(&canvas, &data, QPoint(150, 50)); +} + +void tst_QSGDropArea::keys_internal() +{ + QSGCanvas canvas; + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "DropArea {\n" + "property variant dragKeys\n" + "property variant dropKeys: keys\n" + "property int enterEvents: 0\n" + "width: 100; height: 100\n" + "onEntered: {++enterEvents; dragKeys = drag.keys }\n" + "Item {\n" + "objectName: \"dragItem\"\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "Drag.keys: [\"red\", \"blue\"]\n" + "}\n" + "}", QUrl()); + QSGItem *dropArea = qobject_cast<QSGItem *>(component.create()); + QVERIFY(dropArea); + dropArea->setParentItem(canvas.rootItem()); + + QSGItem *dragItem = dropArea->findChild<QSGItem *>("dragItem"); + QVERIFY(dragItem); + + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "red" << "blue"); + + evaluate<void>(dragItem, "Drag.active = false"); + evaluate<void>(dropArea, "keys = \"blue\""); + QCOMPARE(dropArea->property("keys").toStringList(), QStringList() << "blue"); + QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList() << "blue"); + evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "red" << "blue"); + + evaluate<void>(dragItem, "Drag.active = false"); + evaluate<void>(dropArea, "keys = \"red\""); + QCOMPARE(dropArea->property("keys").toStringList(), QStringList() << "red"); + QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList() << "red"); + evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "red" << "blue"); + + evaluate<void>(dragItem, "Drag.active = false"); + evaluate<void>(dropArea, "keys = \"green\""); + QCOMPARE(dropArea->property("keys").toStringList(), QStringList() << "green"); + QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList() << "green"); + evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + + evaluate<void>(dragItem, "Drag.active = false"); + evaluate<void>(dropArea, "keys = [\"red\", \"green\"]"); + QCOMPARE(dropArea->property("keys").toStringList(), QStringList() << "red" << "green"); + QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList() << "red" << "green"); + evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "red" << "blue"); + + evaluate<void>(dragItem, "Drag.active = false"); + evaluate<void>(dragItem, "Drag.keys = []"); + evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); +} + +void tst_QSGDropArea::keys_external() +{ + QSGCanvas canvas; + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "DropArea {\n" + "property variant dragKeys\n" + "property variant dropKeys: keys\n" + "property int enterEvents: 0\n" + "width: 100; height: 100\n" + "onEntered: {++enterEvents; dragKeys = drag.keys }\n" + "}", QUrl()); + QSGItem *dropArea = qobject_cast<QSGItem *>(component.create()); + QVERIFY(dropArea); + dropArea->setParentItem(canvas.rootItem()); + + QMimeData data; + QSGCanvas alternateCanvas; + + data.setData("text/x-red", "red"); + data.setData("text/x-blue", "blue"); + + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "text/x-red" << "text/x-blue"); + + QWindowSystemInterface::handleDrag(&alternateCanvas, &data, QPoint(50, 50)); + evaluate<void>(dropArea, "keys = \"text/x-blue\""); + QCOMPARE(dropArea->property("keys").toStringList(), QStringList() << "text/x-blue"); + QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList() << "text/x-blue"); + evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "text/x-red" << "text/x-blue"); + + QWindowSystemInterface::handleDrag(&alternateCanvas, &data, QPoint(50, 50)); + evaluate<void>(dropArea, "keys = \"text/x-red\""); + QCOMPARE(dropArea->property("keys").toStringList(), QStringList() << "text/x-red"); + QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList() << "text/x-red"); + evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "text/x-red" << "text/x-blue"); + + QWindowSystemInterface::handleDrag(&alternateCanvas, &data, QPoint(50, 50)); + evaluate<void>(dropArea, "keys = \"text/x-green\""); + QCOMPARE(dropArea->property("keys").toStringList(), QStringList() << "text/x-green"); + QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList() << "text/x-green"); + evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + + QWindowSystemInterface::handleDrag(&alternateCanvas, &data, QPoint(50, 50)); + evaluate<void>(dropArea, "keys = [\"text/x-red\", \"text/x-green\"]"); + QCOMPARE(dropArea->property("keys").toStringList(), QStringList() << "text/x-red" << "text/x-green"); + QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList() << "text/x-red" << "text/x-green"); + evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "text/x-red" << "text/x-blue"); + + QWindowSystemInterface::handleDrag(&alternateCanvas, &data, QPoint(50, 50)); + data.removeFormat("text/x-red"); + data.removeFormat("text/x-blue"); + evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + + QWindowSystemInterface::handleDrop(&canvas, &data, QPoint(50, 50)); +} + +void tst_QSGDropArea::source_internal() +{ + QSGCanvas canvas; + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "DropArea {\n" + "property Item source: drag.source\n" + "property Item eventSource\n" + "width: 100; height: 100\n" + "onEntered: {eventSource = drag.source}\n" + "Item {\n" + "objectName: \"dragItem\"\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}\n" + "Item { id: dragSource; objectName: \"dragSource\" }\n" + "}", QUrl()); + QSGItem *dropArea = qobject_cast<QSGItem *>(component.create()); + QVERIFY(dropArea); + dropArea->setParentItem(canvas.rootItem()); + + QSGItem *dragItem = dropArea->findChild<QSGItem *>("dragItem"); + QVERIFY(dragItem); + + QSGItem *dragSource = dropArea->findChild<QSGItem *>("dragSource"); + QVERIFY(dragSource); + + QCOMPARE(evaluate<QObject *>(dropArea, "source"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(dropArea, "drag.source"), static_cast<QObject *>(0)); + + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<QObject *>(dropArea, "source"), static_cast<QObject *>(dragItem)); + QCOMPARE(evaluate<QObject *>(dropArea, "drag.source"), static_cast<QObject *>(dragItem)); + QCOMPARE(evaluate<QObject *>(dropArea, "eventSource"), static_cast<QObject *>(dragItem)); + + evaluate<void>(dragItem, "Drag.active = false"); + QCOMPARE(evaluate<QObject *>(dropArea, "source"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(dropArea, "drag.source"), static_cast<QObject *>(0)); + + + evaluate<void>(dropArea, "{ eventSource = null }"); + evaluate<void>(dragItem, "Drag.source = dragSource"); + + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<QObject *>(dropArea, "source"), static_cast<QObject *>(dragSource)); + QCOMPARE(evaluate<QObject *>(dropArea, "drag.source"), static_cast<QObject *>(dragSource)); + QCOMPARE(evaluate<QObject *>(dropArea, "eventSource"), static_cast<QObject *>(dragSource)); + + evaluate<void>(dragItem, "Drag.active = false"); + QCOMPARE(evaluate<QObject *>(dropArea, "source"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(dropArea, "drag.source"), static_cast<QObject *>(0)); +} + +// Setting a source can't be emulated using the QWindowSystemInterface API. + +//void tst_QSGDropArea::source_external() +//{ +//} + +void tst_QSGDropArea::position_internal() +{ + QSGCanvas canvas; + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "DropArea {\n" + "property real dragX: drag.x\n" + "property real dragY: drag.y\n" + "property real eventX\n" + "property real eventY\n" + "property int enterEvents: 0\n" + "property int moveEvents: 0\n" + "width: 100; height: 100\n" + "onEntered: {++enterEvents; eventX = drag.x; eventY = drag.y}\n" + "onPositionChanged: {++moveEvents; eventX = drag.x; eventY = drag.y}\n" + "Item {\n" + "objectName: \"dragItem\"\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}\n" + "}", QUrl()); + QSGItem *dropArea = qobject_cast<QSGItem *>(component.create()); + QVERIFY(dropArea); + dropArea->setParentItem(canvas.rootItem()); + + QSGItem *dragItem = dropArea->findChild<QSGItem *>("dragItem"); + QVERIFY(dragItem); + + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "moveEvents"), 0); + QCOMPARE(evaluate<qreal>(dropArea, "drag.x"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "drag.y"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "dragX"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "dragY"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "eventX"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "eventY"), qreal(50)); + + evaluate<void>(dropArea, "{ enterEvents = 0; moveEvents = 0; eventX = -1; eventY = -1 }"); + dragItem->setPos(QPointF(40, 50)); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea, "moveEvents"), 1); + QCOMPARE(evaluate<qreal>(dropArea, "drag.x"), qreal(40)); + QCOMPARE(evaluate<qreal>(dropArea, "drag.y"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "dragX"), qreal(40)); + QCOMPARE(evaluate<qreal>(dropArea, "dragY"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "eventX"), qreal(40)); + QCOMPARE(evaluate<qreal>(dropArea, "eventY"), qreal(50)); + + evaluate<void>(dropArea, "{ enterEvents = 0; moveEvents = 0; eventX = -1; eventY = -1 }"); + dragItem->setPos(QPointF(75, 25)); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea, "moveEvents"), 1); + QCOMPARE(evaluate<qreal>(dropArea, "drag.x"), qreal(75)); + QCOMPARE(evaluate<qreal>(dropArea, "drag.y"), qreal(25)); + QCOMPARE(evaluate<qreal>(dropArea, "dragX"), qreal(75)); + QCOMPARE(evaluate<qreal>(dropArea, "dragY"), qreal(25)); + QCOMPARE(evaluate<qreal>(dropArea, "eventX"), qreal(75)); + QCOMPARE(evaluate<qreal>(dropArea, "eventY"), qreal(25)); + + evaluate<void>(dragItem, "Drag.active = false"); +} + +void tst_QSGDropArea::position_external() +{ + QSGCanvas canvas; + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "DropArea {\n" + "property real dragX: drag.x\n" + "property real dragY: drag.y\n" + "property real eventX\n" + "property real eventY\n" + "property int enterEvents: 0\n" + "property int moveEvents: 0\n" + "width: 100; height: 100\n" + "onEntered: {++enterEvents; eventX = drag.x; eventY = drag.y}\n" + "onPositionChanged: {++moveEvents; eventX = drag.x; eventY = drag.y}\n" + "}", QUrl()); + QSGItem *dropArea = qobject_cast<QSGItem *>(component.create()); + QVERIFY(dropArea); + dropArea->setParentItem(canvas.rootItem()); + + QMimeData data; + + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "moveEvents"), 1); + QCOMPARE(evaluate<qreal>(dropArea, "drag.x"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "drag.y"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "dragX"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "dragY"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "eventX"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "eventY"), qreal(50)); + + evaluate<void>(dropArea, "{ enterEvents = 0; moveEvents = 0; eventX = -1; eventY = -1 }"); + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(40, 50)); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea, "moveEvents"), 1); + QCOMPARE(evaluate<qreal>(dropArea, "drag.x"), qreal(40)); + QCOMPARE(evaluate<qreal>(dropArea, "drag.y"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "dragX"), qreal(40)); + QCOMPARE(evaluate<qreal>(dropArea, "dragY"), qreal(50)); + QCOMPARE(evaluate<qreal>(dropArea, "eventX"), qreal(40)); + QCOMPARE(evaluate<qreal>(dropArea, "eventY"), qreal(50)); + + evaluate<void>(dropArea, "{ enterEvents = 0; moveEvents = 0; eventX = -1; eventY = -1 }"); + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(75, 25)); + QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea, "moveEvents"), 1); + QCOMPARE(evaluate<qreal>(dropArea, "drag.x"), qreal(75)); + QCOMPARE(evaluate<qreal>(dropArea, "drag.y"), qreal(25)); + QCOMPARE(evaluate<qreal>(dropArea, "dragX"), qreal(75)); + QCOMPARE(evaluate<qreal>(dropArea, "dragY"), qreal(25)); + QCOMPARE(evaluate<qreal>(dropArea, "eventX"), qreal(75)); + QCOMPARE(evaluate<qreal>(dropArea, "eventY"), qreal(25)); + + QWindowSystemInterface::handleDrop(&canvas, &data, QPoint(75, 25)); +} + +void tst_QSGDropArea::drop_internal() +{ + QSGCanvas canvas; + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "DropArea {\n" + "property bool accept: false\n" + "property bool setAccepted: false\n" + "property bool acceptDropAction: false\n" + "property bool setDropAction: false\n" + "property int dropAction: Qt.IgnoreAction\n" + "property int proposedAction: Qt.IgnoreAction\n" + "property int supportedActions: Qt.IgnoreAction\n" + "property int dropEvents: 0\n" + "width: 100; height: 100\n" + "onDropped: {\n" + "++dropEvents\n" + "supportedActions = drop.supportedActions\n" + "proposedAction = drop.action\n" + "if (setDropAction)\n" + "drop.action = dropAction\n" + "if (acceptDropAction)\n" + "drop.accept(dropAction)\n" + "else if (setAccepted)\n" + "drop.accepted = accept\n" + "else if (accept)\n" + "drop.accept()\n" + "}\n" + "Item {\n" + "objectName: \"dragItem\"\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "}\n" + "}", QUrl()); + QSGItem *dropArea = qobject_cast<QSGItem *>(component.create()); + QVERIFY(dropArea); + dropArea->setParentItem(canvas.rootItem()); + + QSGItem *dragItem = dropArea->findChild<QSGItem *>("dragItem"); + QVERIFY(dragItem); + + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<int>(dragItem, "Drag.drop()"), int(Qt::IgnoreAction)); + QCOMPARE(evaluate<int>(dropArea, "dropEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "supportedActions"), int(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "proposedAction"), int(Qt::MoveAction)); + + evaluate<void>(dropArea, "{ dropEvents = 0; proposedAction = Qt.IgnoreAction; supportedActions = Qt.IgnoreAction }"); + evaluate<void>(dropArea, "{ accept = true; setDropAction = true; dropAction = Qt.LinkAction }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<int>(dragItem, "Drag.drop()"), int(Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "dropEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "supportedActions"), int(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "proposedAction"), int(Qt::MoveAction)); + + evaluate<void>(dropArea, "{ dropEvents = 0; proposedAction = Qt.IgnoreAction; supportedActions = Qt.IgnoreAction }"); + evaluate<void>(dropArea, "{ setAccepted = true; }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<int>(dragItem, "Drag.drop()"), int(Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "dropEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "supportedActions"), int(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "proposedAction"), int(Qt::MoveAction)); + + evaluate<void>(dropArea, "{ dropEvents = 0; proposedAction = Qt.IgnoreAction; supportedActions = Qt.IgnoreAction }"); + evaluate<void>(dropArea, "{ accept = false; setAccepted = true; }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<int>(dragItem, "Drag.drop()"), int(Qt::IgnoreAction)); + QCOMPARE(evaluate<int>(dropArea, "dropEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "supportedActions"), int(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "proposedAction"), int(Qt::MoveAction)); + + evaluate<void>(dropArea, "{ dropEvents = 0; proposedAction = Qt.IgnoreAction; supportedActions = Qt.IgnoreAction }"); + evaluate<void>(dropArea, "{ setAccepted = false; setDropAction = false; acceptDropAction = true; }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<int>(dragItem, "Drag.drop()"), int(Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "dropEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "supportedActions"), int(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "proposedAction"), int(Qt::MoveAction)); + + evaluate<void>(dropArea, "{ dropEvents = 0; proposedAction = Qt.IgnoreAction; supportedActions = Qt.IgnoreAction }"); + evaluate<void>(dropArea, "{ acceptDropAction = false; dropAction = Qt.IgnoreAction; accept = true }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<int>(dragItem, "Drag.drop()"), int(Qt::MoveAction)); + QCOMPARE(evaluate<int>(dropArea, "dropEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "supportedActions"), int(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "proposedAction"), int(Qt::MoveAction)); + + evaluate<void>(dropArea, "{ dropEvents = 0; proposedAction = Qt.IgnoreAction; supportedActions = Qt.IgnoreAction }"); + evaluate<void>(dropArea, "{ setAccepted = true }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<int>(dragItem, "Drag.drop()"), int(Qt::MoveAction)); + QCOMPARE(evaluate<int>(dropArea, "dropEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "supportedActions"), int(Qt::CopyAction | Qt::MoveAction | Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "proposedAction"), int(Qt::MoveAction)); + + evaluate<void>(dropArea, "{ dropEvents = 0; proposedAction = Qt.IgnoreAction; supportedActions = Qt.IgnoreAction }"); + evaluate<void>(dropArea, "{ setAccepted = false }"); + evaluate<void>(dragItem, "Drag.supportedActions = Qt.LinkAction"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<int>(dragItem, "Drag.drop()"), int(Qt::MoveAction)); + QCOMPARE(evaluate<int>(dropArea, "dropEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "supportedActions"), int(Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "proposedAction"), int(Qt::MoveAction)); + + evaluate<void>(dropArea, "{ dropEvents = 0; proposedAction = Qt.IgnoreAction; supportedActions = Qt.IgnoreAction }"); + evaluate<void>(dropArea, "{ setAccepted = true }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<int>(dragItem, "Drag.drop()"), int(Qt::MoveAction)); + QCOMPARE(evaluate<int>(dropArea, "dropEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "supportedActions"), int(Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "proposedAction"), int(Qt::MoveAction)); + + evaluate<void>(dropArea, "{ dropEvents = 0; proposedAction = Qt.IgnoreAction; supportedActions = Qt.IgnoreAction }"); + evaluate<void>(dropArea, "{ setAccepted = false }"); + evaluate<void>(dragItem, "Drag.proposedAction = Qt.LinkAction"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<int>(dragItem, "Drag.drop()"), int(Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "dropEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "supportedActions"), int(Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "proposedAction"), int(Qt::LinkAction)); + + evaluate<void>(dropArea, "{ dropEvents = 0; proposedAction = Qt.IgnoreAction; supportedActions = Qt.IgnoreAction }"); + evaluate<void>(dropArea, "{ setAccepted = true }"); + evaluate<void>(dragItem, "Drag.active = true"); + QCOMPARE(evaluate<int>(dragItem, "Drag.drop()"), int(Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "dropEvents"), 1); + QCOMPARE(evaluate<int>(dropArea, "supportedActions"), int(Qt::LinkAction)); + QCOMPARE(evaluate<int>(dropArea, "proposedAction"), int(Qt::LinkAction)); +} + +// Setting the supportedActions can't be emulated using the QWindowSystemInterface API. + +//void tst_QSGDropArea::drop_external() +//{ +//} + +void tst_QSGDropArea::simultaneousDrags() +{ + QSGCanvas canvas; + QDeclarativeComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "DropArea {\n" + "property int enterEvents: 0\n" + "property int exitEvents: 0\n" + "width: 100; height: 100\n" + "keys: [\"red\", \"text/x-red\"]\n" + "onEntered: {++enterEvents}\n" + "onExited: {++exitEvents}\n" + "DropArea {\n" + "objectName: \"dropArea2\"\n" + "property int enterEvents: 0\n" + "property int exitEvents: 0\n" + "width: 100; height: 100\n" + "keys: [\"blue\", \"text/x-blue\"]\n" + "onEntered: {++enterEvents}\n" + "onExited: {++exitEvents}\n" + "}\n" + "Item {\n" + "objectName: \"dragItem1\"\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "Drag.keys: [\"red\", \"blue\"]" + "}\n" + "Item {\n" + "objectName: \"dragItem2\"\n" + "x: 50; y: 50\n" + "width: 10; height: 10\n" + "Drag.keys: [\"red\", \"blue\"]" + "}\n" + "}", QUrl()); + + QSGItem *dropArea1 = qobject_cast<QSGItem *>(component.create()); + QVERIFY(dropArea1); + dropArea1->setParentItem(canvas.rootItem()); + + QSGItem *dropArea2 = dropArea1->findChild<QSGItem *>("dropArea2"); + QVERIFY(dropArea2); + + QSGItem *dragItem1 = dropArea1->findChild<QSGItem *>("dragItem1"); + QVERIFY(dragItem1); + + QSGItem *dragItem2 = dropArea1->findChild<QSGItem *>("dragItem2"); + QVERIFY(dragItem2); + + QMimeData data; + data.setData("text/x-red", "red"); + data.setData("text/x-blue", "blue"); + + QSGCanvas alternateCanvas; + + // Mixed internal drags. + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem1, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem2, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dragItem2, "Drag.active = false"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dragItem2, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dragItem1, "Drag.active = false"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 1); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem2, "Drag.active = false"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + // internal then external. + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem1, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + QWindowSystemInterface::handleDrag(&alternateCanvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dragItem1, "Drag.active = false"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 1); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + QWindowSystemInterface::handleDrag(&alternateCanvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + // external then internal. + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem2, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dragItem2, "Drag.active = false"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dragItem2, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + QWindowSystemInterface::handleDrag(&alternateCanvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 1); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem2, "Drag.active = false"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + // Different acceptance + evaluate<void>(dragItem1, "Drag.keys = \"red\""); + evaluate<void>(dragItem2, "Drag.keys = \"blue\""); + data.removeFormat("text/x-red"); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem1, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem2, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem2, "Drag.active = false"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 1); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem2, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem1, "Drag.active = false"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem2, "Drag.active = false"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 1); + + // internal then external + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem1, "Drag.active = true"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + QWindowSystemInterface::handleDrag(&alternateCanvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 1); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + QWindowSystemInterface::handleDrag(&canvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 1); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dragItem1, "Drag.active = false"); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); + + evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); + evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); + QWindowSystemInterface::handleDrag(&alternateCanvas, &data, QPoint(50, 50)); + QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); + QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false); + QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); + QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 1); + + QWindowSystemInterface::handleDrop(&alternateCanvas, &data, QPoint(50, 50)); +} + +QTEST_MAIN(tst_QSGDropArea) + +#include "tst_qsgdroparea.moc" diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index e7f183e798..d0ab0d8784 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -43,7 +43,6 @@ #include <QtDeclarative/private/qdeclarativemetatype_p.h> #include <QtDeclarative/private/qdeclarativeopenmetaobject_p.h> #include <QtDeclarative/private/qsgevents_p_p.h> -#include <QtDeclarative/private/qsgdragtarget_p.h> #include <QtDeclarative/private/qsgpincharea_p.h> #include <QtWidgets/QApplication> @@ -588,7 +587,7 @@ int main(int argc, char *argv[]) // add some otherwise unreachable QMetaObjects defaultReachable.insert(&QSGMouseEvent::staticMetaObject); - // QSGKeyEvent, QSGPinchEvent, QSGDragTargetEvent are not exported + // QSGKeyEvent, QSGPinchEvent, QSGDropEvent are not exported // this will hold the meta objects we want to dump information of QSet<const QMetaObject *> metas; |