Add DropArea item and Drag attached property.

Refactors drag API to improve compatibility with traditional drag and
drop by reusing events and adding drop actions.

Event sending is removed from MouseArea, instead the Drag object can
be attached to the item that is dragged and it will send drag events
when the position of that item is changed or when its active
property changes.

The DragTarget item is renamed to DropArea and can now communicate
supported and suggested actions.

Task-number: QTBUG-19747
Change-Id: I46cb77e68cf1ff32bbcbf0945facb593c9c2243c
Reviewed-on: http://codereview.qt-project.org/4638
Sanity-Review: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Martin Jones <martin.jones@nokia.com>
This commit is contained in:
Andrew den Exter 2011-09-12 14:17:08 +10:00 committed by Qt by Nokia
parent 65bf7aa06a
commit c825865cdd
33 changed files with 3461 additions and 1401 deletions

View File

@ -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]

View File

@ -40,60 +40,50 @@
import QtQuick 2.0
Rectangle {
id: dragRectangle
property Item dropTarget
Item {
id: root
property string colorKey
color: colorKey
width: 100; height: 100
Text {
anchors.fill: parent
color: "white"
font.pixelSize: 90
text: modelData + 1
horizontalAlignment:Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
MouseArea {
id: draggable
id: mouseArea
anchors.fill: parent
width: 100; height: 100
anchors.centerIn: parent
drag.target: parent
drag.keys: [ colorKey ]
drag.target: tile
drag.onDropped: dropTarget = dropItem
onReleased: parent = tile.Drag.target !== null ? tile.Drag.target : root
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
}
Rectangle {
id: tile
width: 100; height: 100
anchors.horizontalCenter: parent.horizontalCenter; anchors.verticalCenter: parent.verticalCenter
color: colorKey
Drag.keys: [ colorKey ]
Drag.active: mouseArea.drag.active
Drag.hotSpot.x: 50
Drag.hotSpot.y: 50
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 }
}
}
}
}

View File

@ -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"
}
}
}
]
]
}
}

View File

@ -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" }
}
}
}

View File

@ -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)
}
}
}
}

View File

@ -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)
}
}
}

View File

@ -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 " ]
}

View File

@ -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))
}
}
}
}
}

View File

@ -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 " ]
}

View File

@ -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)
}

View File

@ -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 += \

View File

@ -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;
}
}
q->sendEvent(item, event);
if (event->isAccepted()) {
event->setGrabItem(item);
return true;
}
event->setAccepted(true);
} else if (itemPrivate->flags & QSGItem::ItemClipsChildrenToShape) {
return false;
}
return false;
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;
}
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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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->x(); }
qreal y() const { return _event->y(); }
qreal x() const { return event->pos().x(); }
qreal y() const { return event->pos().y(); }
QVariant data() const { return _event->data(); }
QStringList keys() const { return _event->keys(); }
QObject *source();
bool accepted() const { return _event->isAccepted(); }
void setAccepted(bool accepted) { _event->setAccepted(accepted); }
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 *);
private:
QSGDragEvent *_event;
QSGDropAreaPrivate *d;
QDropEvent *event;
};
class QSGDragTargetPrivate;
class Q_AUTOTEST_EXPORT QSGDragTarget : public QSGItem
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();
qreal x() const;
qreal y() const;
QObject *source() const;
Q_SIGNALS:
void positionChanged();
void sourceChanged();
private:
QSGDropAreaPrivate *d;
friend class QSGDropArea;
friend class QSGDropAreaPrivate;
};
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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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);

View File

@ -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()

View File

@ -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);

View File

@ -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

View File

@ -95,7 +95,6 @@ public:
bool stealMouse : 1;
bool doubleClick : 1;
bool preventStealing : 1;
bool dragRejected : 1;
QSGDrag *drag;
QPointF startScene;
QPointF targetStartPos;

View File

@ -64,6 +64,8 @@ SGTESTS = \
qsganimatedimage \
qsgborderimage \
qsgcanvas \
qsgdrag \
qsgdroparea \
qsgflickable \
qsgflipable \
qsgfocusscope \

View File

@ -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

View File

@ -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"

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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;