1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <qdrag.h>
5#include "private/qguiapplication_p.h"
6#include "qpa/qplatformintegration.h"
7#include "qpa/qplatformdrag.h"
8#include <qpixmap.h>
9#include <qpoint.h>
10#include "qdnd_p.h"
11
12#include <QtCore/qpointer.h>
13
14QT_BEGIN_NAMESPACE
15
16/*!
17 \class QDrag
18 \inmodule QtGui
19 \ingroup draganddrop
20 \brief The QDrag class provides support for MIME-based drag and drop data
21 transfer.
22
23 Drag and drop is an intuitive way for users to copy or move data around in an
24 application, and is used in many desktop environments as a mechanism for copying
25 data between applications. Drag and drop support in Qt is centered around the
26 QDrag class that handles most of the details of a drag and drop operation.
27
28 The data to be transferred by the drag and drop operation is contained in a
29 QMimeData object. This is specified with the setMimeData() function in the
30 following way:
31
32 \snippet dragging/mainwindow.cpp 1
33
34 Note that setMimeData() assigns ownership of the QMimeData object to the
35 QDrag object. The QDrag must be constructed on the heap with a parent QObject
36 to ensure that Qt can clean up after the drag and drop operation has been
37 completed.
38
39 A pixmap can be used to represent the data while the drag is in
40 progress, and will move with the cursor to the drop target. This
41 pixmap typically shows an icon that represents the MIME type of
42 the data being transferred, but any pixmap can be set with
43 setPixmap(). The cursor's hot spot can be given a position
44 relative to the top-left corner of the pixmap with the
45 setHotSpot() function. The following code positions the pixmap so
46 that the cursor's hot spot points to the center of its bottom
47 edge:
48
49 \snippet separations/finalwidget.cpp 2
50
51 \note On X11, the pixmap may not be able to keep up with the mouse
52 movements if the hot spot causes the pixmap to be displayed
53 directly under the cursor.
54
55 The source and target widgets can be found with source() and target().
56 These functions are often used to determine whether drag and drop operations
57 started and finished at the same widget, so that special behavior can be
58 implemented.
59
60 QDrag only deals with the drag and drop operation itself. It is up to the
61 developer to decide when a drag operation begins, and how a QDrag object should
62 be constructed and used. For a given widget, it is often necessary to
63 reimplement \l{QWidget::mousePressEvent()}{mousePressEvent()} to determine
64 whether the user has pressed a mouse button, and reimplement
65 \l{QWidget::mouseMoveEvent()}{mouseMoveEvent()} to check whether a QDrag is
66 required.
67
68 \sa {Drag and Drop}, QClipboard, QMimeData, {Draggable Icons Example},
69 {Draggable Text Example}, {Drop Site Example}
70*/
71
72/*!
73 Constructs a new drag object for the widget specified by \a dragSource.
74*/
75QDrag::QDrag(QObject *dragSource)
76 : QObject(*new QDragPrivate, dragSource)
77{
78 Q_D(QDrag);
79 d->source = dragSource;
80 d->target = nullptr;
81 d->data = nullptr;
82 d->hotspot = QPoint(-10, -10);
83 d->executed_action = Qt::IgnoreAction;
84 d->supported_actions = Qt::IgnoreAction;
85 d->default_action = Qt::IgnoreAction;
86}
87
88/*!
89 Destroys the drag object.
90*/
91QDrag::~QDrag()
92{
93 Q_D(QDrag);
94 delete d->data;
95}
96
97/*!
98 Sets the data to be sent to the given MIME \a data. Ownership of the data is
99 transferred to the QDrag object.
100*/
101void QDrag::setMimeData(QMimeData *data)
102{
103 Q_D(QDrag);
104 if (d->data == data)
105 return;
106 if (d->data != nullptr)
107 delete d->data;
108 d->data = data;
109}
110
111/*!
112 Returns the MIME data that is encapsulated by the drag object.
113*/
114QMimeData *QDrag::mimeData() const
115{
116 Q_D(const QDrag);
117 return d->data;
118}
119
120/*!
121 Sets \a pixmap as the pixmap used to represent the data in a drag
122 and drop operation. You can only set a pixmap before the drag is
123 started.
124*/
125void QDrag::setPixmap(const QPixmap &pixmap)
126{
127 Q_D(QDrag);
128 d->pixmap = pixmap;
129}
130
131/*!
132 Returns the pixmap used to represent the data in a drag and drop operation.
133*/
134QPixmap QDrag::pixmap() const
135{
136 Q_D(const QDrag);
137 return d->pixmap;
138}
139
140/*!
141 Sets the position of the hot spot relative to the top-left corner of the
142 pixmap used to the point specified by \a hotspot.
143
144 \b{Note:} on X11, the pixmap may not be able to keep up with the mouse
145 movements if the hot spot causes the pixmap to be displayed
146 directly under the cursor.
147*/
148void QDrag::setHotSpot(const QPoint& hotspot)
149{
150 Q_D(QDrag);
151 d->hotspot = hotspot;
152}
153
154/*!
155 Returns the position of the hot spot relative to the top-left corner of the
156 cursor.
157*/
158QPoint QDrag::hotSpot() const
159{
160 Q_D(const QDrag);
161 return d->hotspot;
162}
163
164/*!
165 Returns the source of the drag object. This is the widget where the drag
166 and drop operation originated.
167*/
168QObject *QDrag::source() const
169{
170 Q_D(const QDrag);
171 return d->source;
172}
173
174/*!
175 Returns the target of the drag and drop operation. This is the widget where
176 the drag object was dropped.
177*/
178QObject *QDrag::target() const
179{
180 Q_D(const QDrag);
181 return d->target;
182}
183
184/*!
185 \since 4.3
186
187 Starts the drag and drop operation and returns a value indicating the requested
188 drop action when it is completed. The drop actions that the user can choose
189 from are specified in \a supportedActions. The default proposed action will be selected
190 among the allowed actions in the following order: Move, Copy and Link.
191
192 \b{Note:} On Linux and \macos, the drag and drop operation
193 can take some time, but this function does not block the event
194 loop. Other events are still delivered to the application while
195 the operation is performed. On Windows, the Qt event loop is
196 blocked during the operation.
197
198 \sa cancel()
199*/
200
201Qt::DropAction QDrag::exec(Qt::DropActions supportedActions)
202{
203 return exec(supportedActions, defaultAction: Qt::IgnoreAction);
204}
205
206/*!
207 \since 4.3
208
209 Starts the drag and drop operation and returns a value indicating the requested
210 drop action when it is completed. The drop actions that the user can choose
211 from are specified in \a supportedActions.
212
213 The \a defaultDropAction determines which action will be proposed when the user performs a
214 drag without using modifier keys.
215
216 \b{Note:} On Linux and \macos, the drag and drop operation
217 can take some time, but this function does not block the event
218 loop. Other events are still delivered to the application while
219 the operation is performed. On Windows, the Qt event loop is
220 blocked during the operation. However, QDrag::exec() on
221 Windows causes processEvents() to be called frequently to keep the GUI responsive.
222 If any loops or operations are called while a drag operation is active, it will block the drag operation.
223*/
224
225Qt::DropAction QDrag::exec(Qt::DropActions supportedActions, Qt::DropAction defaultDropAction)
226{
227 Q_D(QDrag);
228 if (!d->data) {
229 qWarning(msg: "QDrag: No mimedata set before starting the drag");
230 return d->executed_action;
231 }
232 Qt::DropAction transformedDefaultDropAction = Qt::IgnoreAction;
233
234 if (defaultDropAction == Qt::IgnoreAction) {
235 if (supportedActions & Qt::MoveAction) {
236 transformedDefaultDropAction = Qt::MoveAction;
237 } else if (supportedActions & Qt::CopyAction) {
238 transformedDefaultDropAction = Qt::CopyAction;
239 } else if (supportedActions & Qt::LinkAction) {
240 transformedDefaultDropAction = Qt::LinkAction;
241 }
242 } else {
243 transformedDefaultDropAction = defaultDropAction;
244 }
245 d->supported_actions = supportedActions;
246 d->default_action = transformedDefaultDropAction;
247 QPointer<QDrag> self = this;
248 auto executed_action = QDragManager::self()->drag(self.data());
249 if (self.isNull())
250 return Qt::IgnoreAction;
251 d->executed_action = executed_action;
252 return d->executed_action;
253}
254
255/*!
256 Sets the drag \a cursor for the \a action. This allows you
257 to override the default native cursors. To revert to using the
258 native cursor for \a action pass in a null QPixmap as \a cursor.
259
260 Note: setting the drag cursor for IgnoreAction may not work on
261 all platforms. X11 and macOS has been tested to work. Windows
262 does not support it.
263*/
264void QDrag::setDragCursor(const QPixmap &cursor, Qt::DropAction action)
265{
266 Q_D(QDrag);
267 if (cursor.isNull())
268 d->customCursors.remove(key: action);
269 else
270 d->customCursors[action] = cursor;
271}
272
273/*!
274 Returns the drag cursor for the \a action.
275
276 \since 5.0
277*/
278
279QPixmap QDrag::dragCursor(Qt::DropAction action) const
280{
281 typedef QMap<Qt::DropAction, QPixmap>::const_iterator Iterator;
282
283 Q_D(const QDrag);
284 const Iterator it = d->customCursors.constFind(key: action);
285 if (it != d->customCursors.constEnd())
286 return it.value();
287
288 Qt::CursorShape shape = Qt::ForbiddenCursor;
289 switch (action) {
290 case Qt::MoveAction:
291 shape = Qt::DragMoveCursor;
292 break;
293 case Qt::CopyAction:
294 shape = Qt::DragCopyCursor;
295 break;
296 case Qt::LinkAction:
297 shape = Qt::DragLinkCursor;
298 break;
299 default:
300 shape = Qt::ForbiddenCursor;
301 }
302 return QGuiApplicationPrivate::instance()->getPixmapCursor(cshape: shape);
303}
304
305/*!
306 Returns the set of possible drop actions for this drag operation.
307
308 \sa exec(), defaultAction()
309*/
310Qt::DropActions QDrag::supportedActions() const
311{
312 Q_D(const QDrag);
313 return d->supported_actions;
314}
315
316
317/*!
318 Returns the default proposed drop action for this drag operation.
319
320 \sa exec(), supportedActions()
321*/
322Qt::DropAction QDrag::defaultAction() const
323{
324 Q_D(const QDrag);
325 return d->default_action;
326}
327
328/*!
329 Cancels a drag operation initiated by Qt.
330
331 \note This is currently implemented on Windows and X11.
332
333 \since 5.7
334 \sa exec()
335*/
336void QDrag::cancel()
337{
338 if (QPlatformDrag *platformDrag = QGuiApplicationPrivate::platformIntegration()->drag())
339 platformDrag->cancelDrag();
340}
341
342/*!
343 \fn void QDrag::actionChanged(Qt::DropAction action)
344
345 This signal is emitted when the \a action associated with the
346 drag changes.
347
348 \sa targetChanged()
349*/
350
351/*!
352 \fn void QDrag::targetChanged(QObject *newTarget)
353
354 This signal is emitted when the target of the drag and drop
355 operation changes, with \a newTarget the new target.
356
357 \sa target(), actionChanged()
358*/
359
360QT_END_NAMESPACE
361
362#include "moc_qdrag.cpp"
363

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtbase/src/gui/kernel/qdrag.cpp