Support for new native OS/2 tree control with drag-and-drop.
[wxWidgets.git] / src / os2 / dnd.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: dnd.cpp
3 // Purpose: wxDropTarget, wxDropSource, wxDataObject implementation
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/21/99
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 AUTHOR
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "dnd.h"
14 #endif
15
16 #define INCL_PM
17 #define INCL_DOS
18 #include <os2.h>
19 #include "wx/window.h"
20 #include "wx/app.h"
21 #include "wx/gdicmn.h"
22 #include "wx/dnd.h"
23
24 #if wxUSE_DRAG_AND_DROP
25
26 // ----------------------------------------------------------------------------
27 // global
28 // ----------------------------------------------------------------------------
29
30 /////////////////////////////////////////////////////////////////////////////
31 // Private functions
32 /////////////////////////////////////////////////////////////////////////////
33
34 static wxDragResult ConvertDragEffectToResult (
35 DWORD dwEffect
36 )
37 {
38 switch (dwEffect)
39 {
40 case DO_COPY:
41 return wxDragCopy;
42
43 case DO_LINK:
44 return wxDragLink;
45
46 case DO_MOVE:
47 return wxDragMove;
48
49 default:
50 case DO_DEFAULT:
51 return wxDragNone;
52 }
53 } // end of ConvertDragEffectToResult
54
55 static DWORD ConvertDragResultToEffect (
56 wxDragResult eResult
57 )
58 {
59 switch (eResult)
60 {
61 case wxDragCopy:
62 return DO_COPY;
63
64 case wxDragLink:
65 return DO_LINK;
66
67 case wxDragMove:
68 return DO_MOVE;
69
70 default:
71 case wxDragNone:
72 return DO_DEFAULT;
73 }
74 } // end of ConvertDragResultToEffect
75
76 class CIDropTarget
77 {
78 public:
79 CIDropTarget(wxDropTarget* pTarget)
80 {
81 m_pTarget = pTarget;
82 m_pDragItem = NULL;
83 }
84 virtual ~CIDropTarget() { }
85
86 //
87 // Accessors for CDropTarget
88 //
89 void Free(void) { ::DrgFreeDraginfo(m_pDragInfo); }
90 PDRAGINFO GetDataSource(void) { return m_pDragInfo; }
91 void SetDataSource(PDRAGINFO pDragInfo) { m_pDragInfo = pDragInfo; }
92 void SetHWND(HWND hWnd) { m_hWnd = hWnd; }
93
94 //
95 // CIDropTarget methods
96 //
97 bool DragLeave(void);
98 MRESULT DragOver(void);
99 MRESULT Drop(void);
100
101 protected:
102
103 PDRAGINFO m_pDragInfo;
104 PDRAGITEM m_pDragItem; // !NULL between DragEnter and DragLeave/Drop
105 wxDropTarget* m_pTarget; // the real target (we're just a proxy)
106 HWND m_hWnd; // window we're associated with
107 }; // end of CLASS CIDropTarget
108
109 bool CIDropTarget::DragLeave()
110 {
111 //
112 // Remove the UI feedback
113 //
114 m_pTarget->OnLeave();
115
116 //
117 // Release the held object
118 //
119 Free();
120 return TRUE;
121 } // end of CIDropTarget::DragLeave
122
123 MRESULT CIDropTarget::DragOver ()
124 {
125 char zBuffer[128];
126 ULONG ulBytes;
127 USHORT uOp;
128 USHORT uIndicator;
129 ULONG ulItems;
130 ULONG i;
131
132 ::DrgAccessDraginfo(m_pDragInfo);
133 switch(m_pDragInfo->usOperation)
134 {
135 case DO_UNKNOWN:
136 Free();
137 return (MRFROM2SHORT(DOR_NODROPOP, 0));
138
139 case DO_DEFAULT:
140 m_pDragItem = ::DrgQueryDragitemPtr(m_pDragInfo, 0);
141 ulBytes = ::DrgQueryStrName( m_pDragItem->hstrContainerName
142 ,128
143 ,zBuffer
144 );
145 if (!ulBytes)
146 return (MRFROM2SHORT(DOR_NODROPOP, 0));
147 else
148 uOp = DO_MOVE;
149 break;
150
151 case DO_COPY:
152 case DO_MOVE:
153 uOp = m_pDragInfo->usOperation;
154 break;
155 }
156 uIndicator = DOR_DROP;
157 ulItems = (ULONG)::DrgQueryDragitemCount(m_pDragInfo);
158 for (i = 0; i < ulItems; i++)
159 {
160 m_pDragItem = ::DrgQueryDragitemPtr(m_pDragInfo, i);
161 if (((m_pDragItem->fsSupportedOps & DO_COPYABLE) &&
162 (uOp == (USHORT)DO_COPY)) ||
163 ((m_pDragItem->fsSupportedOps & DO_MOVEABLE) &&
164 (uOp == (USHORT)DO_COPY)))
165 {
166 if (::DrgVerifyRMF(m_pDragItem, "DRM_OS2FILE", "DRF_UNKNOWN"))
167 uIndicator = (USHORT)DOR_DROP;
168 else
169 uIndicator = (USHORT)DOR_NEVERDROP;
170 }
171 }
172 Free();
173 return (MRFROM2SHORT(uIndicator, uOp));
174 } // end of CIDropTarget::DragOver
175
176 // #pragma page "CIDropTarget::Drop"
177 /////////////////////////////////////////////////////////////////////////////
178 //
179 // CIDropTarget::Drop
180 //
181 // Instructs the drop target to paste data that was just now dropped on it.
182 //
183 // PARAMETERS
184 // pIDataSource -- the data to paste
185 // dwKeyState -- kbd & mouse state
186 // pt -- mouse coordinates
187 // pdwEffect -- effect flag
188 //
189 // RETURN VALUE
190 // STDMETHODIMP S_OK
191 //
192 /////////////////////////////////////////////////////////////////////////////
193 MRESULT CIDropTarget::Drop ()
194 {
195 char zBuffer[128];
196 ULONG ulBytes;
197 USHORT uOp;
198 USHORT uIndicator;
199 ULONG ulItems;
200 ULONG i;
201
202 ::DrgAccessDraginfo(m_pDragInfo);
203 switch(m_pDragInfo->usOperation)
204 {
205 case DO_UNKNOWN:
206 Free();
207 return (MRFROM2SHORT(DOR_NODROPOP, 0));
208
209 case DO_DEFAULT:
210 m_pDragItem = ::DrgQueryDragitemPtr(m_pDragInfo, 0);
211 ulBytes = ::DrgQueryStrName( m_pDragItem->hstrContainerName
212 ,128
213 ,zBuffer
214 );
215 if (!ulBytes)
216 return (MRFROM2SHORT(DOR_NODROPOP, 0));
217 else
218 uOp = DO_MOVE;
219 break;
220
221 case DO_COPY:
222 case DO_MOVE:
223 uOp = m_pDragInfo->usOperation;
224 break;
225 }
226 uIndicator = DOR_DROP;
227 ulItems = (ULONG)::DrgQueryDragitemCount(m_pDragInfo);
228 for (i = 0; i < ulItems; i++)
229 {
230 m_pDragItem = ::DrgQueryDragitemPtr(m_pDragInfo, i);
231 if (((m_pDragItem->fsSupportedOps & DO_COPYABLE) &&
232 (uOp == (USHORT)DO_COPY)) ||
233 ((m_pDragItem->fsSupportedOps & DO_MOVEABLE) &&
234 (uOp == (USHORT)DO_COPY)))
235 {
236 if (::DrgVerifyRMF(m_pDragItem, "DRM_OS2FILE", "DRF_UNKNOWN"))
237 uIndicator = (USHORT)DOR_DROP;
238 else
239 uIndicator = (USHORT)DOR_NEVERDROP;
240 }
241 }
242
243 //
244 // First ask the drop target if it wants data
245 //
246 if (m_pTarget->OnDrop( m_pDragInfo->xDrop
247 ,m_pDragInfo->yDrop
248 ))
249 {
250 wxDragResult eRc;
251
252 //
253 // And now it has the data
254 //
255 eRc = m_pTarget->OnData( m_pDragInfo->xDrop
256 ,m_pDragInfo->yDrop
257 ,eRc
258 );
259 }
260 //else: OnDrop() returned FALSE, no need to copy data
261
262 //
263 // Release the held object
264 //
265 Free();
266 return (MRFROM2SHORT(uIndicator, uOp));
267 } // end of CIDropTarget::Drop
268
269 // ----------------------------------------------------------------------------
270 // wxDropTarget
271 // ----------------------------------------------------------------------------
272
273 wxDropTarget::wxDropTarget (
274 wxDataObject* pDataObject
275 )
276 {
277 m_dataObject = pDataObject;
278 m_pDropTarget = new CIDropTarget(this);
279 } // end of wxDropTarget::wxDropTarget
280
281 wxDropTarget::~wxDropTarget()
282 {
283 Release();
284 } // end of wxDropTarget::~wxDropTarget
285
286 bool wxDropTarget::GetData ()
287 {
288 wxDataFormat vFormat = GetSupportedFormat(m_pDropTarget->GetDataSource());
289
290 if (vFormat == wxDF_INVALID)
291 {
292 return FALSE;
293 }
294 //
295 // Under OS/2 we already have the data via the attached DRAGITEM's
296 //
297 return TRUE;
298 } // end of wxDropTarget::GetData
299
300 wxDataFormat wxDropTarget::GetSupportedFormat (
301 PDRAGINFO pDataSource
302 ) const
303 {
304 PDRAGITEM pDragItem;
305 wxDataFormat vFormat;
306 wxDataFormat* pFormats;
307 ULONG ulFormats = m_dataObject->GetFormatCount(wxDataObject::Set);
308 ULONG ulItems = (ULONG)::DrgQueryDragitemCount(pDataSource);
309 ULONG i;
310 ULONG n;
311 wxString sMechanism;
312 wxString sFormat;
313 bool bValid = FALSE;
314
315 pFormats = ulFormats == 1 ? &vFormat : new wxDataFormat[ulFormats];
316 m_dataObject->GetAllFormats( pFormats
317 ,wxDataObject::Set
318 );
319
320 for (n = 0; n < ulFormats; n++)
321 {
322 switch(pFormats[n].GetType())
323 {
324 case wxDF_TEXT:
325 case wxDF_FILENAME:
326 case wxDF_HTML:
327 sMechanism = "DRM_OS2FILE";
328 sFormat = "DRF_TEXT";
329 break;
330
331 case wxDF_OEMTEXT:
332 sMechanism = "DRM_OS2FILE";
333 sFormat = "DRF_OEMTEXT";
334 break;
335
336 case wxDF_BITMAP:
337 sMechanism = "DRM_OS2FILE";
338 sFormat = "DRF_BITMAP";
339 break;
340
341 case wxDF_METAFILE:
342 case wxDF_ENHMETAFILE:
343 sMechanism = "DRM_OS2FILE";
344 sFormat = "DRF_METAFILE";
345 break;
346
347 case wxDF_TIFF:
348 sMechanism = "DRM_OS2FILE";
349 sFormat = "DRF_TIFF";
350 break;
351
352 case wxDF_SYLK:
353 sMechanism = "DRM_OS2FILE";
354 sFormat = "DRF_SYLK";
355 break;
356
357 case wxDF_DIF:
358 sMechanism = "DRM_OS2FILE";
359 sFormat = "DRF_DIF";
360 break;
361
362 case wxDF_DIB:
363 sMechanism = "DRM_OS2FILE";
364 sFormat = "DRF_DIB";
365 break;
366
367 case wxDF_PALETTE:
368 case wxDF_PENDATA:
369 case wxDF_RIFF:
370 case wxDF_WAVE:
371 case wxDF_UNICODETEXT:
372 case wxDF_LOCALE:
373 sMechanism = "DRM_OS2FILE";
374 sFormat = "DRF_UNKNOWN";
375 break;
376
377 case wxDF_PRIVATE:
378 sMechanism = "DRM_OBJECT";
379 sFormat = "DRF_UNKNOWN";
380 break;
381 }
382 for (i = 0; i < ulItems; i++)
383 {
384 pDragItem = ::DrgQueryDragitemPtr(pDataSource, i);
385 if (::DrgVerifyRMF(pDragItem, sMechanism.c_str(), sFormat.c_str()))
386 {
387 bValid = TRUE;
388 break;
389 }
390 }
391 if (bValid)
392 {
393 vFormat = pFormats[n];
394 break;
395 }
396 }
397 if (pFormats != &vFormat)
398 {
399 //
400 // Free memory if we allocated it
401 //
402 delete [] pFormats;
403 }
404 return (n < ulFormats ? vFormat : wxFormatInvalid);
405 } // end of wxDropTarget::GetSupportedFormat
406
407 bool wxDropTarget::IsAcceptedData (
408 PDRAGINFO pDataSource
409 ) const
410 {
411 return (GetSupportedFormat(pDataSource) != wxDF_INVALID);
412 } // end of wxDropTarget::IsAcceptedData
413
414 void wxDropTarget::Release ()
415 {
416 m_pDropTarget->Free();
417 } // end of wxDropTarget::Release
418
419
420 wxDragResult wxDropTarget::OnData (
421 wxCoord WXUNUSED(vX)
422 , wxCoord WXUNUSED(y)
423 , wxDragResult WXUNUSED(vResult)
424 )
425 {
426 return (wxDragResult)0;
427 } // end of wxDropTarget::OnData
428
429 bool wxDropTarget::OnDrop (
430 wxCoord WXUNUSED(x)
431 , wxCoord WXUNUSED(y)
432 )
433 {
434 return TRUE;
435 } // end of wxDropTarget::OnDrop
436
437 //-------------------------------------------------------------------------
438 // wxDropSource
439 //-------------------------------------------------------------------------
440
441 wxDropSource::wxDropSource (
442 wxWindow* pWin
443 )
444 {
445 Init();
446 } // end of wxDropSource::wxDropSource
447
448 wxDropSource::wxDropSource (
449 wxDataObject& rData
450 , wxWindow* pWin
451 )
452 {
453 Init();
454 SetData(rData);
455 } // end of wxDropSource::wxDropSource
456
457 wxDropSource::~wxDropSource ()
458 {
459 ::DrgFreeDraginfo(m_pDragInfo);
460 } // end of wxDropSource::~wxDropSource
461
462 wxDragResult wxDropSource::DoDragDrop (
463 int WXUNUSED(flags)
464 )
465 {
466 //
467 // Need to specify drag items in derived classes that know their data types
468 // before calling DoDragDrop
469 //
470 if (::DrgDrag( m_pWindow->GetHWND()
471 ,m_pDragInfo
472 ,&m_vDragImage
473 ,m_ulItems
474 ,VK_BUTTON2
475 ,NULL
476 ) != NULLHANDLE)
477 {
478 switch(m_pDragInfo->usOperation)
479 {
480 case DO_COPY:
481 return wxDragCopy;
482
483 case DO_MOVE:
484 return wxDragCopy;
485
486 case DO_LINK:
487 return wxDragCopy;
488
489 default:
490 return wxDragNone;
491 }
492 }
493 return wxDragError;
494 } // end of wxDropSource::DoDragDrop
495
496 bool wxDropSource::GiveFeedback (
497 wxDragResult eEffect
498 )
499 {
500 const wxCursor& rCursor = GetCursor(eEffect);
501
502 if (rCursor.Ok())
503 {
504 ::WinSetPointer(HWND_DESKTOP, (HPOINTER)rCursor.GetHCURSOR());
505 m_vDragImage.hImage = (LHANDLE)rCursor.GetHCURSOR();
506 switch(eEffect)
507 {
508 case wxDragCopy:
509 m_pDragInfo->usOperation = DO_COPY;
510 break;
511
512 case wxDragMove:
513 m_pDragInfo->usOperation = DO_MOVE;
514 break;
515
516 case wxDragLink:
517 m_pDragInfo->usOperation = DO_LINK;
518 break;
519 }
520 return TRUE;
521 }
522 else
523 {
524 return FALSE;
525 }
526 } // end of GuiAdvDnd_CDropSource::GiveFeedback
527
528 void wxDropSource::Init ()
529 {
530 m_pDragInfo = ::DrgAllocDraginfo(m_ulItems);
531
532 //
533 // Set a default drag image struct with what we know so far
534 //
535 m_vDragImage.cb = sizeof(DRAGIMAGE);
536 m_vDragImage.cptl = 0; // non-zero if fl is DRG_POLYGON
537 m_vDragImage.hImage = 0; // Set in GiveFeedback
538 m_vDragImage.sizlStretch.cx = 20L;
539 m_vDragImage.sizlStretch.cy = 20L;
540 m_vDragImage.fl = DRG_ICON | DRG_STRETCH;
541 m_vDragImage.cxOffset = 0;
542 m_vDragImage.cyOffset = 0;
543
544 HSTR hStrType = ::DrgAddStrHandle(DRT_UNKNOWN);
545 HSTR hStrRMF;
546 HSTR hStrContainer;
547 char zFormats[128];
548 char zContainer[128];
549 USHORT uSize = GetDataObject()->GetDataSize(GetDataObject()->GetPreferredFormat()) + 1;
550 char* pzBuffer = new char[uSize];
551
552 memset(pzBuffer, '\0', GetDataObject()->GetDataSize(GetDataObject()->GetPreferredFormat()));
553 pzBuffer[GetDataObject()->GetDataSize(GetDataObject()->GetPreferredFormat())] = '\0';
554 GetDataObject()->GetDataHere( GetDataObject()->GetPreferredFormat()
555 ,(void*)pzBuffer
556 );
557
558 strcpy(zFormats, "<DRM_OS2FILE, DRF_UNKNOWN>");
559 strcpy(zContainer, GetDataObject()->GetPreferredFormat().GetId().c_str());
560
561 hStrRMF = ::DrgAddStrHandle(zFormats);
562 hStrContainer = ::DrgAddStrHandle(zContainer);
563
564 m_pDragItem = new DRAGITEM[m_ulItems];
565 for (ULONG i = 0; i < m_ulItems; i++);
566 {
567 m_pDragItem[i].hwndItem = m_pWindow->GetHWND();
568 m_pDragItem[i].hstrType = hStrType;
569 m_pDragItem[i].hstrRMF = hStrRMF;
570 m_pDragItem[i].hstrContainerName = hStrContainer;
571 m_pDragItem[i].fsControl = 0;
572 m_pDragItem[i].fsSupportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE;
573 m_pDragItem[i].hstrSourceName = ::DrgAddStrHandle(pzBuffer);
574 m_pDragItem[i].hstrTargetName = m_pDragItem[i].hstrSourceName;
575 m_pDragItem[i].ulItemID = i;
576 ::DrgSetDragitem( m_pDragInfo
577 ,&m_pDragItem[i]
578 ,sizeof(DRAGITEM)
579 ,0
580 );
581 }
582 delete [] pzBuffer;
583 delete [] m_pDragItem;
584 } // end of wxDropSource::Init
585
586 #endif //wxUSE_DRAG_AND_DROP