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