source: trunk/src/gui/kernel/qdnd_qws.cpp@ 624

Last change on this file since 624 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 12.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qapplication.h"
43
44#ifndef QT_NO_DRAGANDDROP
45
46#include "qwidget.h"
47#include "qdatetime.h"
48#include "qbitmap.h"
49#include "qcursor.h"
50#include "qevent.h"
51#include "qpainter.h"
52#include "qdnd_p.h"
53
54QT_BEGIN_NAMESPACE
55
56QT_USE_NAMESPACE
57
58static QPixmap *defaultPm = 0;
59static const int default_pm_hotx = -2;
60static const int default_pm_hoty = -16;
61static const char *const default_pm[] = {
62"13 9 3 1",
63". c None",
64" c #000000",
65"X c #FFFFFF",
66"X X X X X X X",
67" X X X X X X ",
68"X ......... X",
69" X.........X ",
70"X ......... X",
71" X.........X ",
72"X ......... X",
73" X X X X X X ",
74"X X X X X X X",
75};
76
77// Shift/Ctrl handling, and final drop status
78static Qt::DropAction global_accepted_action = Qt::CopyAction;
79static Qt::DropActions possible_actions = Qt::IgnoreAction;
80
81
82// static variables in place of a proper cross-process solution
83static QDrag *drag_object;
84static bool qt_qws_dnd_dragging = false;
85
86
87static Qt::KeyboardModifiers oldstate;
88
89class QShapedPixmapWidget : public QWidget {
90 QPixmap pixmap;
91public:
92 QShapedPixmapWidget() :
93 QWidget(0, Qt::Tool | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint)
94 {
95 // ### Temporary workaround for 4.2-rc1!!! To prevent flickering when
96 // using drag'n drop in a client application. (task 126956)
97 // setAttribute() should be done unconditionally!
98 if (QApplication::type() == QApplication::GuiServer)
99 setAttribute(Qt::WA_TransparentForMouseEvents);
100 }
101
102 void setPixmap(QPixmap pm)
103 {
104 pixmap = pm;
105 if (!pixmap.mask().isNull()) {
106 setMask(pixmap.mask());
107 } else {
108 clearMask();
109 }
110 resize(pm.width(),pm.height());
111 }
112
113 void paintEvent(QPaintEvent*)
114 {
115 QPainter p(this);
116 p.drawPixmap(0,0,pixmap);
117 }
118};
119
120
121static QShapedPixmapWidget *qt_qws_dnd_deco = 0;
122
123
124void QDragManager::updatePixmap()
125{
126 if (qt_qws_dnd_deco) {
127 QPixmap pm;
128 QPoint pm_hot(default_pm_hotx,default_pm_hoty);
129 if (drag_object) {
130 pm = drag_object->pixmap();
131 if (!pm.isNull())
132 pm_hot = drag_object->hotSpot();
133 }
134 if (pm.isNull()) {
135 if (!defaultPm)
136 defaultPm = new QPixmap(default_pm);
137 pm = *defaultPm;
138 }
139 qt_qws_dnd_deco->setPixmap(pm);
140 qt_qws_dnd_deco->move(QCursor::pos()-pm_hot);
141 if (willDrop) {
142 qt_qws_dnd_deco->show();
143 } else {
144 qt_qws_dnd_deco->hide();
145 }
146 }
147}
148
149void QDragManager::timerEvent(QTimerEvent *) { }
150
151void QDragManager::move(const QPoint &) { }
152
153void QDragManager::updateCursor()
154{
155#ifndef QT_NO_CURSOR
156 if (willDrop) {
157 if (qt_qws_dnd_deco)
158 qt_qws_dnd_deco->show();
159 if (currentActionForOverrideCursor != global_accepted_action) {
160 QApplication::changeOverrideCursor(QCursor(dragCursor(global_accepted_action), 0, 0));
161 currentActionForOverrideCursor = global_accepted_action;
162 }
163 } else {
164 QCursor *overrideCursor = QApplication::overrideCursor();
165 if (!overrideCursor || overrideCursor->shape() != Qt::ForbiddenCursor) {
166 QApplication::changeOverrideCursor(QCursor(Qt::ForbiddenCursor));
167 currentActionForOverrideCursor = Qt::IgnoreAction;
168 }
169 if (qt_qws_dnd_deco)
170 qt_qws_dnd_deco->hide();
171 }
172#endif
173}
174
175
176bool QDragManager::eventFilter(QObject *o, QEvent *e)
177{
178 if (beingCancelled) {
179 if (e->type() == QEvent::KeyRelease && static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
180 qApp->removeEventFilter(this);
181 Q_ASSERT(object == 0);
182 beingCancelled = false;
183 eventLoop->exit();
184 return true; // block the key release
185 }
186 return false;
187 }
188
189
190
191 if (!o->isWidgetType())
192 return false;
193
194 switch(e->type()) {
195
196 case QEvent::KeyPress:
197 case QEvent::KeyRelease:
198 {
199 QKeyEvent *ke = ((QKeyEvent*)e);
200 if (ke->key() == Qt::Key_Escape && e->type() == QEvent::KeyPress) {
201 cancel();
202 qApp->removeEventFilter(this);
203 beingCancelled = false;
204 eventLoop->exit();
205 } else {
206 updateCursor();
207 }
208 return true; // Eat all key events
209 }
210
211 case QEvent::MouseButtonPress:
212 case QEvent::MouseMove:
213 {
214 if (!object) { //#### this should not happen
215 qWarning("QDragManager::eventFilter: No object");
216 return true;
217 }
218
219 QDragManager *manager = QDragManager::self();
220 QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData;
221 if (manager->object)
222 possible_actions = manager->dragPrivate()->possible_actions;
223 else
224 possible_actions = Qt::IgnoreAction;
225
226 QMouseEvent *me = (QMouseEvent *)e;
227 if (me->buttons()) {
228 Qt::DropAction prevAction = global_accepted_action;
229 QWidget *cw = QApplication::widgetAt(me->globalPos());
230
231 // Fix for when we move mouse on to the deco widget
232 if (qt_qws_dnd_deco && cw == qt_qws_dnd_deco)
233 cw = object->target();
234
235 while (cw && !cw->acceptDrops() && !cw->isWindow())
236 cw = cw->parentWidget();
237
238 if (object->target() != cw) {
239 if (object->target()) {
240 QDragLeaveEvent dle;
241 QApplication::sendEvent(object->target(), &dle);
242 willDrop = false;
243 global_accepted_action = Qt::IgnoreAction;
244 updateCursor();
245 restoreCursor = true;
246 object->d_func()->target = 0;
247 }
248 if (cw && cw->acceptDrops()) {
249 object->d_func()->target = cw;
250 QDragEnterEvent dee(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData,
251 me->buttons(), me->modifiers());
252 QApplication::sendEvent(object->target(), &dee);
253 willDrop = dee.isAccepted() && dee.dropAction() != Qt::IgnoreAction;
254 global_accepted_action = willDrop ? dee.dropAction() : Qt::IgnoreAction;
255 updateCursor();
256 restoreCursor = true;
257 }
258 } else if (cw) {
259 QDragMoveEvent dme(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData,
260 me->buttons(), me->modifiers());
261 if (global_accepted_action != Qt::IgnoreAction) {
262 dme.setDropAction(global_accepted_action);
263 dme.accept();
264 }
265 QApplication::sendEvent(cw, &dme);
266 willDrop = dme.isAccepted();
267 global_accepted_action = willDrop ? dme.dropAction() : Qt::IgnoreAction;
268 updatePixmap();
269 updateCursor();
270 }
271 if (global_accepted_action != prevAction)
272 emitActionChanged(global_accepted_action);
273 }
274 return true; // Eat all mouse events
275 }
276
277 case QEvent::MouseButtonRelease:
278 {
279 qApp->removeEventFilter(this);
280 if (restoreCursor) {
281 willDrop = false;
282#ifndef QT_NO_CURSOR
283 QApplication::restoreOverrideCursor();
284#endif
285 restoreCursor = false;
286 }
287 if (object && object->target()) {
288 QMouseEvent *me = (QMouseEvent *)e;
289
290 QDragManager *manager = QDragManager::self();
291 QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData;
292
293 QDropEvent de(object->target()->mapFromGlobal(me->globalPos()), possible_actions, dropData,
294 me->buttons(), me->modifiers());
295 QApplication::sendEvent(object->target(), &de);
296 if (de.isAccepted())
297 global_accepted_action = de.dropAction();
298 else
299 global_accepted_action = Qt::IgnoreAction;
300
301 if (object)
302 object->deleteLater();
303 drag_object = object = 0;
304 }
305 eventLoop->exit();
306 return true; // Eat all mouse events
307 }
308
309 default:
310 break;
311 }
312
313 return false;
314}
315
316Qt::DropAction QDragManager::drag(QDrag *o)
317{
318 if (object == o || !o || !o->source())
319 return Qt::IgnoreAction;
320
321 if (object) {
322 cancel();
323 qApp->removeEventFilter(this);
324 beingCancelled = false;
325 }
326
327 object = drag_object = o;
328 qt_qws_dnd_deco = new QShapedPixmapWidget();
329 oldstate = Qt::NoModifier; // #### Should use state that caused the drag
330// drag_mode = mode;
331
332 willDrop = false;
333 updatePixmap();
334 updateCursor();
335 restoreCursor = true;
336 object->d_func()->target = 0;
337 qApp->installEventFilter(this);
338
339 global_accepted_action = Qt::CopyAction;
340#ifndef QT_NO_CURSOR
341 qApp->setOverrideCursor(Qt::ArrowCursor);
342 restoreCursor = true;
343 updateCursor();
344#endif
345
346 qt_qws_dnd_dragging = true;
347
348 eventLoop = new QEventLoop;
349 (void) eventLoop->exec();
350 delete eventLoop;
351 eventLoop = 0;
352
353 delete qt_qws_dnd_deco;
354 qt_qws_dnd_deco = 0;
355 qt_qws_dnd_dragging = false;
356
357
358 return global_accepted_action;
359}
360
361
362void QDragManager::cancel(bool deleteSource)
363{
364// qDebug("QDragManager::cancel");
365 beingCancelled = true;
366
367 if (object->target()) {
368 QDragLeaveEvent dle;
369 QApplication::sendEvent(object->target(), &dle);
370 }
371
372#ifndef QT_NO_CURSOR
373 if (restoreCursor) {
374 QApplication::restoreOverrideCursor();
375 restoreCursor = false;
376 }
377#endif
378
379 if (drag_object) {
380 if (deleteSource)
381 object->deleteLater();
382 drag_object = object = 0;
383 }
384
385 delete qt_qws_dnd_deco;
386 qt_qws_dnd_deco = 0;
387
388 global_accepted_action = Qt::IgnoreAction;
389}
390
391
392void QDragManager::drop()
393{
394}
395
396QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type type) const
397{
398 if (!drag_object)
399 return QVariant();
400 QByteArray data = drag_object->mimeData()->data(mimetype);
401 if (type == QVariant::String)
402 return QString::fromUtf8(data);
403 return data;
404}
405
406bool QDropData::hasFormat_sys(const QString &format) const
407{
408 return formats().contains(format);
409}
410
411QStringList QDropData::formats_sys() const
412{
413 if (drag_object)
414 return drag_object->mimeData()->formats();
415 return QStringList();
416}
417
418
419#endif // QT_NO_DRAGANDDROP
420
421
422QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.