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