Changeset 438 for trunk/src/gui/kernel/qdnd_pm.cpp
- Timestamp:
- Dec 24, 2009, 3:29:44 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/gui/kernel/qdnd_pm.cpp
r107 r438 51 51 #include "qdatastream.h" 52 52 #include "qcursor.h" 53 #include "q t_os2.h"53 #include "qdesktopwidget.h" 54 54 #include "qdnd_p.h" 55 55 #include "qdebug.h" 56 56 57 #include "qt_os2.h" 58 57 59 QT_BEGIN_NAMESPACE 58 60 59 61 #if !defined(QT_NO_DRAGANDDROP) && !defined(QT_NO_CLIPBOARD) 62 63 /** \internal 64 * Data for QDragEnterEvent/QDragMoveEvent/QPMDropEvent. 65 */ 66 class QPMDragData 67 { 68 public: 69 QPMDragData(); 70 ~QPMDragData(); 71 72 void initialize( DRAGINFO *di ); 73 void reset( bool isAccepted, bool isActAccepted ); 74 void reset() { reset( FALSE, FALSE ); } 75 76 void setDropped( bool d ) { dropped = d; } 77 bool isDropped() const { return dropped; } 78 79 DRAGINFO *info() const { return di; } 80 81 bool provides( const char *format ); 82 const char *format( int fn ); 83 QByteArray encodedData( const char *format ); 84 85 private: 86 87 void initWorkers(); 88 89 bool initialized : 1; 90 bool dropped : 1; 91 bool gotWorkers : 1; 92 93 DRAGINFO *di; 94 // @todo later 95 // QPtrList<QPMMime::DropWorker> workers; 96 }; 97 98 QPMDragData::QPMDragData() 99 : initialized(false), dropped(false) 100 , gotWorkers(false), di(NULL) 101 { 102 QDragManager *manager = QDragManager::self(); 103 Q_ASSERT(!manager->dropData->d); 104 manager->dropData->d = this; 105 } 106 107 QPMDragData::~QPMDragData() 108 { 109 reset(); 110 111 QDragManager *manager = QDragManager::self(); 112 Q_ASSERT(manager->dropData->d == this); 113 manager->dropData->d = 0; 114 } 115 116 void QPMDragData::initialize(DRAGINFO *info) 117 { 118 Q_ASSERT(info); 119 if (initialized || !info) 120 return; 121 122 initialized = true; 123 di = info; 124 } 125 126 void QPMDragData::initWorkers() 127 { 128 Q_ASSERT(initialized); 129 if (!initialized || gotWorkers) 130 return; 131 132 gotWorkers = true; 133 134 // @todo later 135 #if 0 136 // go through all convertors and collect DropWorkers to use 137 QPtrList<QPMMime> mimes = QPMMime::all(); 138 for ( QPMMime *mime = mimes.first(); mime; mime = mimes.next() ) { 139 QPMMime::DropWorker *wrk = mime->dropWorkerFor( di ); 140 if ( wrk ) { 141 if ( wrk->isExclusive() ) { 142 // ignore all other workers if some of them identified itself 143 // as exclusive 144 workers.clear(); 145 workers.append( wrk ); 146 break; 147 } 148 // ensure there are no duplicates 149 if ( !workers.containsRef( wrk ) ) 150 workers.append( wrk ); 151 } 152 } 153 154 #if defined(QT_DEBUG_DND) 155 qDebug( "QPMDragData: %d drop workers for DRAGINFO %p", 156 workers.count(), di ); 157 #endif 158 159 // init all workers 160 for ( QPMMime::DropWorker *w = workers.first(); w; w = workers.next() ) { 161 w->nfo = di; 162 w->init(); 163 } 164 #endif 165 } 166 167 void QPMDragData::reset(bool isAccepted, bool isActAccepted) 168 { 169 if (!initialized) 170 return; 171 172 // @todo later 173 #if 0 174 // cleanup all workers 175 for ( QPMMime::DropWorker *w = workers.first(); w; w = workers.next() ) { 176 w->cleanup( isAccepted, isActAccepted ); 177 w->nfo = NULL; 178 } 179 180 workers.clear(); 181 #endif 182 di = NULL; 183 initialized = dropped = gotWorkers = FALSE; 184 } 185 186 // @todo later 187 #if 0 188 class QPMDropEvent : public QDropEvent 189 { 190 public: 191 QPMDropEvent( const QPoint &pos, QPMDragData *data ) 192 : QDropEvent( pos ) { d = data; } 193 194 inline bool isTrulyAccepted() const { return accpt; } 195 inline bool isActionTrulyAccepted() const { return accptact; } 196 }; 197 198 class QPMDragEnterEvent : public QDragEnterEvent 199 { 200 public: 201 QPMDragEnterEvent( const QPoint &pos, QPMDragData *data ) 202 : QDragEnterEvent( pos ) { d = data; } 203 204 inline bool isTrulyAccepted() const { return accpt; } 205 inline bool isActionTrulyAccepted() const { return accptact; } 206 }; 207 208 class QPMDragMoveEvent : public QDragMoveEvent 209 { 210 public: 211 QPMDragMoveEvent( const QPoint &pos, QPMDragData *data ) 212 : QDragMoveEvent( pos ) { d = data; } 213 214 inline bool isTrulyAccepted() const { return accpt; } 215 inline bool isActionTrulyAccepted() const { return accptact; } 216 }; 217 218 bool QDropEvent::provides( const char* mimeType ) const 219 { 220 QPMDragData *data = static_cast<QPMDragData *> (d); 221 Q_ASSERT( data ); 222 if ( !data ) 223 return FALSE; 224 225 return data->provides( mimeType ); 226 } 227 228 const char *QDropEvent::format( int fn ) const 229 { 230 QPMDragData *data = static_cast<QPMDragData *> (d); 231 Q_ASSERT( data ); 232 if ( !data ) 233 return NULL; 234 235 return data->format( fn ); 236 } 237 238 QByteArray QDropEvent::encodedData( const char *format ) const 239 { 240 QByteArray array; 241 242 QPMDragData *data = static_cast<QPMDragData *> (d); 243 Q_ASSERT( data ); 244 245 if ( !data || !data->isDropped() ) { 246 // This is a QDragEnterEvent/QDragMoveEvent subclass; we cannot provide 247 // any MIME contents yet because it's impossible to do data transfers 248 // before DM_DROP is sent. Return shortly. 249 return array; 250 } 251 252 array = data->encodedData( format ); 253 return array; 254 } 255 #endif 256 257 /*! 258 * \internal 259 * Direct manipulation (Drag & Drop) event handler 260 */ 261 MRESULT qt_dispatchDragAndDrop(QWidget *widget, const QMSG &qmsg) 262 { 263 static HWND lastDragOverHwnd = 0; // last target window 264 static USHORT lastDragOverOp = 0; // last DM_DRAGOVER operation 265 static USHORT lastRealOp = 0; // last real op (never DO_DEFAULT or DO_UNKNOWN) 266 static USHORT defaultOp = 0; // default op for DO_DEFAULT or DO_UNKNOWN 267 268 static USHORT supportedOps = 0; // operations supported by all items 269 static bool sourceAllowsOp = FALSE; // does source allow requested operation 270 271 static bool lastAccept = FALSE; // last reply from the target 272 static bool lastAcceptAction = FALSE; // last action reply from the target 273 274 static QPMDragData dragData; 275 276 Q_ASSERT(widget); 277 278 BOOL ok = FALSE; 279 280 switch( qmsg.msg ) { 281 case DM_DRAGOVER: { 282 bool first = lastDragOverHwnd != qmsg.hwnd; 283 if (first) { 284 // the first DM_DRAGOVER message 285 lastDragOverHwnd = qmsg.hwnd; 286 lastAccept = lastAcceptAction = FALSE; 287 supportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE; 288 // ensure drag data is reset (just in case of a wrong msg flow...) 289 dragData.reset(); 290 } 291 292 Q_ASSERT(first || widget->acceptDrops()); 293 if (!widget->acceptDrops()) { 294 if (!first) { 295 // Odin32 apps are dramatically bogus, they continue to send 296 // DM_DRAGOVER even if we reply DOR_NEVERDROP. Simulate 297 // DM_DRAGLEAVE 298 lastDragOverHwnd = 0; 299 dragData.reset(); 300 } 301 return MRFROM2SHORT(DOR_NEVERDROP, 0); 302 } 303 304 DRAGINFO *info = (DRAGINFO *)qmsg.mp1; 305 ok = DrgAccessDraginfo(info); 306 Q_ASSERT(ok && info); 307 if (!ok || !info) 308 return MRFROM2SHORT(DOR_NEVERDROP, 0); 309 310 USHORT dropReply = DOR_DROP; 311 312 if (first) { 313 // determine the set of operations supported by *all* items 314 // (this implies that DRAGITEM::fsSupportedOps is a bit field) 315 ULONG itemCount = DrgQueryDragitemCount(info); 316 for (ULONG i = 0; i < itemCount; ++ i) { 317 PDRAGITEM item = DrgQueryDragitemPtr(info, i); 318 Q_ASSERT(item); 319 if (!item) { 320 dropReply = DOR_NEVERDROP; 321 break; 322 } 323 supportedOps &= item->fsSupportedOps; 324 } 325 if (dropReply != DOR_NEVERDROP) { 326 Q_ASSERT(itemCount); 327 if (!itemCount || !supportedOps) { 328 // items don't have even a single common operation... 329 dropReply = DOR_NEVERDROP; 330 } else { 331 // determine the default operation 332 // (in order MOVE, COPY, LINK, for compatibility with Win32) 333 if (supportedOps & DO_MOVEABLE) defaultOp = DO_MOVE; 334 else if (supportedOps & DO_COPYABLE) defaultOp = DO_COPY; 335 else if (supportedOps & DO_LINKABLE) defaultOp = DO_LINK; 336 else Q_ASSERT(false); // should never happen 337 } 338 } 339 } 340 341 if (dropReply != DOR_NEVERDROP) { 342 343 if (first || lastDragOverOp != info->usOperation) { 344 // the current drop operation was changed by a modifier key 345 lastDragOverOp = info->usOperation; 346 lastRealOp = info->usOperation; 347 if (lastRealOp == DO_DEFAULT || lastRealOp == DO_UNKNOWN) { 348 // the default operation is requested 349 lastRealOp = defaultOp; 350 } 351 sourceAllowsOp = 352 ((supportedOps & DO_MOVEABLE) && lastRealOp == DO_MOVE) || 353 ((supportedOps & DO_COPYABLE) && lastRealOp == DO_COPY) || 354 ((supportedOps & DO_LINKABLE) && lastRealOp == DO_LINK); 355 } 356 357 // Note that if sourceAllowsOp = false here, we have to deliver 358 // events anyway (stealing them from Qt would be confusing), but 359 // we will silently ignore any accept commands and always reject 360 // the drop. Other platforms seem to do the same. 361 362 // convert the operation to an Action 363 Qt::DropAction action = Qt::CopyAction; 364 if (lastRealOp == DO_COPY) action = Qt::CopyAction; 365 else if (lastRealOp == DO_MOVE) action = Qt::MoveAction; 366 else if (lastRealOp == DO_LINK) action = Qt::LinkAction; 367 else Q_ASSERT(false); // should never happen 368 369 // flip y coordinate 370 QPoint pnt(info->xDrop, info->yDrop); 371 pnt.setY(QApplication::desktop()->height() - (pnt.y() + 1)); 372 pnt = widget->mapFromGlobal(pnt); 373 374 // initialize drag data used in QPMDrag.../QPMDrop... events 375 if (first) 376 dragData.initialize(info); 377 378 // @todo later 379 #if 0 380 QDropEvent *de = NULL; 381 QPMDragEnterEvent *dee = NULL; 382 QPMDragMoveEvent *dme = NULL; 383 384 if (first) 385 de = dee = new QPMDragEnterEvent(pnt, &dragData); 386 else 387 de = dme = new QPMDragMoveEvent(pnt, &dragData); 388 389 de->setAction(action); 390 de->accept(lastAccept); 391 de->acceptAction(lastAcceptAction); 392 393 QApplication::sendEvent(widget, de); 394 395 // if not allowed or not accepted, always reply DOR_NODROP 396 // to have DM_DRAGOVER delivered to us again in any case 397 398 dropReply = sourceAllowsOp && de->isAccepted() ? 399 DOR_DROP : DOR_NODROP; 400 401 lastAccept = dee ? dee->isTrulyAccepted() : 402 dme->isTrulyAccepted(); 403 lastAcceptAction = dee ? dee->isActionTrulyAccepted() : 404 dme->isActionTrulyAccepted(); 405 delete de; 406 #endif 407 } 408 409 DrgFreeDraginfo(info); 410 411 return MRFROM2SHORT(dropReply, lastRealOp); 412 } 413 case DM_DRAGLEAVE: { 414 // Odin32 apps produce incorrect message flow, ignore 415 Q_ASSERT(lastDragOverHwnd != 0); 416 if (lastDragOverHwnd == 0) 417 return 0; 418 419 lastDragOverHwnd = 0; 420 dragData.reset(); 421 422 if (!widget->acceptDrops()) 423 return 0; 424 425 QDragLeaveEvent de; 426 QApplication::sendEvent(widget, &de); 427 return 0; 428 } 429 case DM_DROP: { 430 // Odin32 apps produce incorrect message flow, ignore 431 Q_ASSERT(lastDragOverHwnd != 0); 432 if (lastDragOverHwnd == 0) 433 return 0; 434 435 // Odin32 apps send DM_DROP even if we replied DOR_NEVERDROP or 436 // DOR_NODROP, simulate DM_DRAGLEAVE 437 Q_ASSERT(lastAccept || lastAcceptAction); 438 if (!lastAccept && !lastAcceptAction) { 439 WinSendMsg(qmsg.hwnd, DM_DRAGLEAVE, 0, 0); 440 return 0; 441 } 442 443 lastDragOverHwnd = 0; 444 445 Q_ASSERT(widget->acceptDrops()); 446 if (!widget->acceptDrops()) 447 return 0; 448 449 DRAGINFO *info = (DRAGINFO *)qmsg.mp1; 450 ok = DrgAccessDraginfo(info); 451 Q_ASSERT(ok && info); 452 if (!ok || !info) 453 return MRFROM2SHORT(DOR_NEVERDROP, 0); 454 455 Q_ASSERT(lastRealOp == info->usOperation); 456 457 // convert the operation to an Action 458 Qt::DropAction action = Qt::CopyAction; 459 if (lastRealOp == DO_COPY ) action = Qt::CopyAction; 460 else if (lastRealOp == DO_MOVE ) action = Qt::MoveAction; 461 else if (lastRealOp == DO_LINK ) action = Qt::LinkAction; 462 else Q_ASSERT(false); // should never happen 463 464 // flip y coordinate 465 QPoint pnt(info->xDrop, info->yDrop); 466 pnt.setY(QApplication::desktop()->height() - (pnt.y() + 1)); 467 468 dragData.setDropped(true); 469 470 // @todo later 471 #if 0 472 QPMDropEvent de(widget->mapFromGlobal(pnt), &dragData); 473 de.setAction(action); 474 de.accept(lastAccept); 475 de.acceptAction(lastAcceptAction); 476 477 QApplication::sendEvent(widget, &de); 478 479 dragData.reset(de.isTrulyAccepted(), de.isActionTrulyAccepted()); 480 481 // If the target has accepted the particular Drop action (using 482 // acceptProposedAction() rather than just accept()), it means that 483 // it will perform the necessary operation on its own (for example, 484 // will delete the source if the accepted action is Move). In this 485 // case, we always send DMFL_TARGETFAIL to the source to prevent it 486 // from doing the same on its side. 487 488 ULONG targetReply = 489 de.isTrulyAccepted() && !de.isActionTrulyAccepted() ? 490 DMFL_TARGETSUCCESSFUL : DMFL_TARGETFAIL; 491 #else 492 ULONG targetReply = DMFL_TARGETFAIL; 493 #endif 494 495 // send DM_ENDCONVERSATION for every item 496 ULONG itemCount = DrgQueryDragitemCount(info); 497 for (ULONG i = 0; i < itemCount; ++ i) { 498 PDRAGITEM item = DrgQueryDragitemPtr(info, i); 499 Q_ASSERT(item); 500 if (!item) 501 continue; 502 // it is possible that this item required DM_RENDERPREPARE but 503 // returned FALSE in reply to it (so hwndItem may be NULL) 504 if (!item->hwndItem) 505 continue; 506 DrgSendTransferMsg(item->hwndItem, DM_ENDCONVERSATION, 507 MPFROMLONG(item->ulItemID), 508 MPFROMLONG(targetReply)); 509 } 510 511 DrgDeleteDraginfoStrHandles(info); 512 DrgFreeDraginfo(info); 513 514 return 0; 515 } 516 default: 517 break; 518 } 519 520 return WinDefWindowProc(qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2); 521 } 60 522 61 523 //---------------------------------------------------------------------
Note:
See TracChangeset
for help on using the changeset viewer.