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

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 12.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
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 qt-info@nokia.com.
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 case QEvent::ShortcutOverride:
196 // prevent accelerators from firing while dragging
197 e->accept();
198 return true;
199
200 case QEvent::KeyPress:
201 case QEvent::KeyRelease:
202 {
203 QKeyEvent *ke = ((QKeyEvent*)e);
204 if (ke->key() == Qt::Key_Escape && e->type() == QEvent::KeyPress) {
205 cancel();
206 qApp->removeEventFilter(this);
207 beingCancelled = false;
208 eventLoop->exit();
209 } else {
210 updateCursor();
211 }
212 return true; // Eat all key events
213 }
214
215 case QEvent::MouseButtonPress:
216 case QEvent::MouseMove:
217 {
218 if (!object) { //#### this should not happen
219 qWarning("QDragManager::eventFilter: No object");
220 return true;
221 }
222
223 QDragManager *manager = QDragManager::self();
224 QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData;
225 if (manager->object)
226 possible_actions = manager->dragPrivate()->possible_actions;
227 else
228 possible_actions = Qt::IgnoreAction;
229
230 QMouseEvent *me = (QMouseEvent *)e;
231 if (me->buttons()) {
232 Qt::DropAction prevAction = global_accepted_action;
233 QWidget *cw = QApplication::widgetAt(me->globalPos());
234
235 // Fix for when we move mouse on to the deco widget
236 if (qt_qws_dnd_deco && cw == qt_qws_dnd_deco)
237 cw = object->target();
238
239 while (cw && !cw->acceptDrops() && !cw->isWindow())
240 cw = cw->parentWidget();
241
242 if (object->target() != cw) {
243 if (object->target()) {
244 QDragLeaveEvent dle;
245 QApplication::sendEvent(object->target(), &dle);
246 willDrop = false;
247 global_accepted_action = Qt::IgnoreAction;
248 updateCursor();
249 restoreCursor = true;
250 object->d_func()->target = 0;
251 }
252 if (cw && cw->acceptDrops()) {
253 object->d_func()->target = cw;
254 QDragEnterEvent dee(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData,
255 me->buttons(), me->modifiers());
256 QApplication::sendEvent(object->target(), &dee);
257 willDrop = dee.isAccepted() && dee.dropAction() != Qt::IgnoreAction;
258 global_accepted_action = willDrop ? dee.dropAction() : Qt::IgnoreAction;
259 updateCursor();
260 restoreCursor = true;
261 }
262 } else if (cw) {
263 QDragMoveEvent dme(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData,
264 me->buttons(), me->modifiers());
265 if (global_accepted_action != Qt::IgnoreAction) {
266 dme.setDropAction(global_accepted_action);
267 dme.accept();
268 }
269 QApplication::sendEvent(cw, &dme);
270 willDrop = dme.isAccepted();
271 global_accepted_action = willDrop ? dme.dropAction() : Qt::IgnoreAction;
272 updatePixmap();
273 updateCursor();
274 }
275 if (global_accepted_action != prevAction)
276 emitActionChanged(global_accepted_action);
277 }
278 return true; // Eat all mouse events
279 }
280
281 case QEvent::MouseButtonRelease:
282 {
283 qApp->removeEventFilter(this);
284 if (restoreCursor) {
285 willDrop = false;
286#ifndef QT_NO_CURSOR
287 QApplication::restoreOverrideCursor();
288#endif
289 restoreCursor = false;
290 }
291 if (object && object->target()) {
292 QMouseEvent *me = (QMouseEvent *)e;
293
294 QDragManager *manager = QDragManager::self();
295 QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData;
296
297 QDropEvent de(object->target()->mapFromGlobal(me->globalPos()), possible_actions, dropData,
298 me->buttons(), me->modifiers());
299 QApplication::sendEvent(object->target(), &de);
300 if (de.isAccepted())
301 global_accepted_action = de.dropAction();
302 else
303 global_accepted_action = Qt::IgnoreAction;
304
305 if (object)
306 object->deleteLater();
307 drag_object = object = 0;
308 }
309 eventLoop->exit();
310 return true; // Eat all mouse events
311 }
312
313 default:
314 break;
315 }
316
317 return false;
318}
319
320Qt::DropAction QDragManager::drag(QDrag *o)
321{
322 if (object == o || !o || !o->source())
323 return Qt::IgnoreAction;
324
325 if (object) {
326 cancel();
327 qApp->removeEventFilter(this);
328 beingCancelled = false;
329 }
330
331 object = drag_object = o;
332 qt_qws_dnd_deco = new QShapedPixmapWidget();
333 oldstate = Qt::NoModifier; // #### Should use state that caused the drag
334// drag_mode = mode;
335
336 willDrop = false;
337 updatePixmap();
338 updateCursor();
339 restoreCursor = true;
340 object->d_func()->target = 0;
341 qApp->installEventFilter(this);
342
343 global_accepted_action = Qt::CopyAction;
344#ifndef QT_NO_CURSOR
345 qApp->setOverrideCursor(Qt::ArrowCursor);
346 restoreCursor = true;
347 updateCursor();
348#endif
349
350 qt_qws_dnd_dragging = true;
351
352 eventLoop = new QEventLoop;
353 (void) eventLoop->exec();
354 delete eventLoop;
355 eventLoop = 0;
356
357 delete qt_qws_dnd_deco;
358 qt_qws_dnd_deco = 0;
359 qt_qws_dnd_dragging = false;
360
361
362 return global_accepted_action;
363}
364
365
366void QDragManager::cancel(bool deleteSource)
367{
368// qDebug("QDragManager::cancel");
369 beingCancelled = true;
370
371 if (object->target()) {
372 QDragLeaveEvent dle;
373 QApplication::sendEvent(object->target(), &dle);
374 }
375
376#ifndef QT_NO_CURSOR
377 if (restoreCursor) {
378 QApplication::restoreOverrideCursor();
379 restoreCursor = false;
380 }
381#endif
382
383 if (drag_object) {
384 if (deleteSource)
385 object->deleteLater();
386 drag_object = object = 0;
387 }
388
389 delete qt_qws_dnd_deco;
390 qt_qws_dnd_deco = 0;
391
392 global_accepted_action = Qt::IgnoreAction;
393}
394
395
396void QDragManager::drop()
397{
398}
399
400QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type type) const
401{
402 if (!drag_object)
403 return QVariant();
404 QByteArray data = drag_object->mimeData()->data(mimetype);
405 if (type == QVariant::String)
406 return QString::fromUtf8(data);
407 return data;
408}
409
410bool QDropData::hasFormat_sys(const QString &format) const
411{
412 return formats().contains(format);
413}
414
415QStringList QDropData::formats_sys() const
416{
417 if (drag_object)
418 return drag_object->mimeData()->formats();
419 return QStringList();
420}
421
422
423#endif // QT_NO_DRAGANDDROP
424
425
426QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.