]> git.saurik.com Git - wxWidgets.git/blobdiff - src/os2/dnd.cpp
Fixed #1338966.
[wxWidgets.git] / src / os2 / dnd.cpp
index 70d916d6528af2565d4fcb688aec4e35a6d76a2a..9100811fc9b6c2459e25e527a30662dd0d221956 100644 (file)
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////////
-// Name:        dnd.cpp
+// Name:        src/os2/dnd.cpp
 // Purpose:     wxDropTarget, wxDropSource, wxDataObject implementation
 // Author:      David Webster
 // Modified by:
 // Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
-#ifdef __GNUG__
-#pragma implementation "dnd.h"
-#endif
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#if wxUSE_DRAG_AND_DROP
 
-#define INCL_PM
-#define INCL_DOS
-#include <os2.h>
 #include "wx/window.h"
 #include "wx/app.h"
 #include "wx/gdicmn.h"
 #include "wx/dnd.h"
 
-#if wxUSE_DRAG_AND_DROP
+#define INCL_PM
+#define INCL_DOS
+#include <os2.h>
 
 // ----------------------------------------------------------------------------
 // global
 // ----------------------------------------------------------------------------
 
+/////////////////////////////////////////////////////////////////////////////
+// Private functions
+/////////////////////////////////////////////////////////////////////////////
+
+#if 0
+static wxDragResult ConvertDragEffectToResult (
+  DWORD                             dwEffect
+)
+{
+    switch (dwEffect)
+    {
+        case DO_COPY:
+            return wxDragCopy;
+
+        case DO_LINK:
+            return wxDragLink;
+
+        case DO_MOVE:
+            return wxDragMove;
+
+        default:
+        case DO_DEFAULT:
+            return wxDragNone;
+    }
+} // end of ConvertDragEffectToResult
+
+static DWORD ConvertDragResultToEffect (
+  wxDragResult                      eResult
+)
+{
+    switch (eResult)
+    {
+        case wxDragCopy:
+            return DO_COPY;
+
+        case wxDragLink:
+            return DO_LINK;
+
+        case wxDragMove:
+            return DO_MOVE;
+
+        default:
+        case wxDragNone:
+            return DO_DEFAULT;
+    }
+} // end of ConvertDragResultToEffect
+#endif
+
+class CIDropTarget
+{
+public:
+    CIDropTarget(wxDropTarget* pTarget)
+    {
+        m_pTarget   = pTarget;
+        m_pDragItem = NULL;
+    }
+    virtual ~CIDropTarget() { }
+
+    //
+    // Accessors for CDropTarget
+    //
+    void      Free(void) { ::DrgFreeDraginfo(m_pDragInfo); }
+    PDRAGINFO GetDataSource(void) { return m_pDragInfo; }
+    void      SetDataSource(PDRAGINFO pDragInfo) { m_pDragInfo = pDragInfo; }
+    void      SetHWND(HWND hWnd) { m_hWnd = hWnd; }
+
+    //
+    // CIDropTarget methods
+    //
+           bool    DragLeave(void);
+           MRESULT DragOver(void);
+           MRESULT Drop(void);
+
+protected:
+
+    PDRAGINFO                       m_pDragInfo;
+    PDRAGITEM                       m_pDragItem; // !NULL between DragEnter and DragLeave/Drop
+    wxDropTarget*                   m_pTarget;   // the real target (we're just a proxy)
+    HWND                            m_hWnd;      // window we're associated with
+}; // end of CLASS CIDropTarget
+
+bool CIDropTarget::DragLeave()
+{
+    //
+    // Remove the UI feedback
+    //
+    m_pTarget->OnLeave();
+
+    //
+    // Release the held object
+    //
+    Free();
+    return true;
+} // end of CIDropTarget::DragLeave
+
+MRESULT CIDropTarget::DragOver ()
+{
+    char                            zBuffer[128];
+    ULONG                           ulBytes;
+    USHORT                          uOp = 0;
+    USHORT                          uIndicator;
+    ULONG                           ulItems;
+    ULONG                           i;
+
+    ::DrgAccessDraginfo(m_pDragInfo);
+    switch(m_pDragInfo->usOperation)
+    {
+        case DO_UNKNOWN:
+            Free();
+            return (MRFROM2SHORT(DOR_NODROPOP, 0));
+
+        case DO_DEFAULT:
+            m_pDragItem = ::DrgQueryDragitemPtr(m_pDragInfo, 0);
+            ulBytes     = ::DrgQueryStrName( m_pDragItem->hstrContainerName
+                                            ,128
+                                            ,zBuffer
+                                           );
+            if (!ulBytes)
+                return (MRFROM2SHORT(DOR_NODROPOP, 0));
+            else
+                uOp = DO_MOVE;
+            break;
+
+        case DO_COPY:
+        case DO_MOVE:
+            uOp = m_pDragInfo->usOperation;
+            break;
+    }
+    uIndicator = DOR_DROP;
+    ulItems = (ULONG)::DrgQueryDragitemCount(m_pDragInfo);
+    for (i = 0; i < ulItems; i++)
+    {
+        m_pDragItem = ::DrgQueryDragitemPtr(m_pDragInfo, i);
+        if (((m_pDragItem->fsSupportedOps & DO_COPYABLE) &&
+             (uOp == (USHORT)DO_COPY))                   ||
+            ((m_pDragItem->fsSupportedOps & DO_MOVEABLE) &&
+             (uOp == (USHORT)DO_COPY)))
+        {
+            if (::DrgVerifyRMF(m_pDragItem, "DRM_OS2FILE", "DRF_UNKNOWN"))
+                uIndicator = (USHORT)DOR_DROP;
+            else
+                uIndicator = (USHORT)DOR_NEVERDROP;
+        }
+    }
+    Free();
+    return (MRFROM2SHORT(uIndicator, uOp));
+} // end of CIDropTarget::DragOver
+
+// #pragma page   "CIDropTarget::Drop"
+/////////////////////////////////////////////////////////////////////////////
+//
+// CIDropTarget::Drop
+//
+//   Instructs the drop target to paste data that was just now dropped on it.
+//
+// PARAMETERS
+//   pIDataSource -- the data to paste
+//   dwKeyState   -- kbd & mouse state
+//   pt           -- mouse coordinates
+//   pdwEffect    -- effect flag
+//
+// RETURN VALUE
+//  STDMETHODIMP S_OK
+//
+/////////////////////////////////////////////////////////////////////////////
+MRESULT CIDropTarget::Drop ()
+{
+    char                            zBuffer[128];
+    ULONG                           ulBytes;
+    USHORT                          uOp = 0;
+    USHORT                          uIndicator;
+    ULONG                           ulItems;
+    ULONG                           i;
+
+    ::DrgAccessDraginfo(m_pDragInfo);
+    switch(m_pDragInfo->usOperation)
+    {
+        case DO_UNKNOWN:
+            Free();
+            return (MRFROM2SHORT(DOR_NODROPOP, 0));
+
+        case DO_DEFAULT:
+            m_pDragItem = ::DrgQueryDragitemPtr(m_pDragInfo, 0);
+            ulBytes     = ::DrgQueryStrName( m_pDragItem->hstrContainerName
+                                            ,128
+                                            ,zBuffer
+                                           );
+            if (!ulBytes)
+                return (MRFROM2SHORT(DOR_NODROPOP, 0));
+            else
+                uOp = DO_MOVE;
+            break;
+
+        case DO_COPY:
+        case DO_MOVE:
+            uOp = m_pDragInfo->usOperation;
+            break;
+    }
+    uIndicator = DOR_DROP;
+    ulItems = (ULONG)::DrgQueryDragitemCount(m_pDragInfo);
+    for (i = 0; i < ulItems; i++)
+    {
+        m_pDragItem = ::DrgQueryDragitemPtr(m_pDragInfo, i);
+        if (((m_pDragItem->fsSupportedOps & DO_COPYABLE) &&
+             (uOp == (USHORT)DO_COPY))                   ||
+            ((m_pDragItem->fsSupportedOps & DO_MOVEABLE) &&
+             (uOp == (USHORT)DO_COPY)))
+        {
+            if (::DrgVerifyRMF(m_pDragItem, "DRM_OS2FILE", "DRF_UNKNOWN"))
+                uIndicator = (USHORT)DOR_DROP;
+            else
+                uIndicator = (USHORT)DOR_NEVERDROP;
+        }
+    }
+
+    //
+    // First ask the drop target if it wants data
+    //
+    if (m_pTarget->OnDrop( m_pDragInfo->xDrop
+                          ,m_pDragInfo->yDrop
+                         ))
+    {
+        wxDragResult                 eRc = wxDragNone;
+
+        //
+        // And now it has the data
+        //
+        eRc = m_pTarget->OnData( m_pDragInfo->xDrop
+                                ,m_pDragInfo->yDrop
+                                ,eRc
+                               );
+    }
+    //else: OnDrop() returned false, no need to copy data
+
+    //
+    // Release the held object
+    //
+    Free();
+    return (MRFROM2SHORT(uIndicator, uOp));
+} // end of CIDropTarget::Drop
+
 // ----------------------------------------------------------------------------
 // wxDropTarget
 // ----------------------------------------------------------------------------
 
-wxDropTarget::wxDropTarget(
+wxDropTarget::wxDropTarget (
   wxDataObject*                     pDataObject
 )
 {
-    // TODO:
-};
+    m_dataObject  = pDataObject;
+    m_pDropTarget = new CIDropTarget(this);
+} // end of wxDropTarget::wxDropTarget
 
 wxDropTarget::~wxDropTarget()
 {
-};
+    Release();
+} // end of wxDropTarget::~wxDropTarget
 
-void wxDropTarget::Register(
-  WXHWND                            hwnd
-)
+bool wxDropTarget::GetData ()
 {
-    //TODO:
-};
+    wxDataFormat                    vFormat = GetSupportedFormat(m_pDropTarget->GetDataSource());
 
-void wxDropTarget::Revoke(
-  WXHWND                            hwnd
-)
+    if (vFormat == wxDF_INVALID)
+    {
+        return false;
+    }
+    //
+    // Under OS/2 we already have the data via the attached DRAGITEM's
+    //
+    return true;
+} // end of wxDropTarget::GetData
+
+wxDataFormat wxDropTarget::GetSupportedFormat (
+  PDRAGINFO                         pDataSource
+) const
 {
-    //TODO:
-};
+    PDRAGITEM                       pDragItem;
+    wxDataFormat                    vFormat;
+    wxDataFormat*                   pFormats;
+    ULONG                           ulFormats = m_dataObject->GetFormatCount(wxDataObject::Set);
+    ULONG                           ulItems = (ULONG)::DrgQueryDragitemCount(pDataSource);
+    ULONG                           i;
+    ULONG                           n;
+    wxString                        sMechanism;
+    wxString                        sFormat;
+    bool                            bValid = false;
 
-wxDragResult wxDropTarget::OnDragOver(
-  wxCoord                           x
-, wxCoord                           y
-, wxDragResult                      vDef
-)
+    pFormats = ulFormats == 1 ? &vFormat :  new wxDataFormat[ulFormats];
+    m_dataObject->GetAllFormats( pFormats
+                                ,wxDataObject::Set
+                               );
+
+    for (n = 0; n < ulFormats; n++)
+    {
+        switch(pFormats[n].GetType())
+        {
+            case wxDF_TEXT:
+            case wxDF_FILENAME:
+            case wxDF_HTML:
+                sMechanism = _T("DRM_OS2FILE");
+                sFormat    = _T("DRF_TEXT");
+                break;
+
+            case wxDF_OEMTEXT:
+                sMechanism = _T("DRM_OS2FILE");
+                sFormat    = _T("DRF_OEMTEXT");
+                break;
+
+            case wxDF_BITMAP:
+                sMechanism = _T("DRM_OS2FILE");
+                sFormat    = _T("DRF_BITMAP");
+                break;
+
+            case wxDF_METAFILE:
+            case wxDF_ENHMETAFILE:
+                sMechanism = _T("DRM_OS2FILE");
+                sFormat    = _T("DRF_METAFILE");
+                break;
+
+            case wxDF_TIFF:
+                sMechanism = _T("DRM_OS2FILE");
+                sFormat    = _T("DRF_TIFF");
+                break;
+
+            case wxDF_SYLK:
+                sMechanism = _T("DRM_OS2FILE");
+                sFormat    = _T("DRF_SYLK");
+                break;
+
+            case wxDF_DIF:
+                sMechanism = _T("DRM_OS2FILE");
+                sFormat    = _T("DRF_DIF");
+                break;
+
+            case wxDF_DIB:
+                sMechanism = _T("DRM_OS2FILE");
+                sFormat    = _T("DRF_DIB");
+                break;
+
+            case wxDF_PALETTE:
+            case wxDF_PENDATA:
+            case wxDF_RIFF:
+            case wxDF_WAVE:
+            case wxDF_UNICODETEXT:
+            case wxDF_LOCALE:
+                sMechanism = _T("DRM_OS2FILE");
+                sFormat    = _T("DRF_UNKNOWN");
+                break;
+
+            case wxDF_PRIVATE:
+                sMechanism = _T("DRM_OBJECT");
+                sFormat    = _T("DRF_UNKNOWN");
+                break;
+        }
+        for (i = 0; i < ulItems; i++)
+        {
+            pDragItem = ::DrgQueryDragitemPtr(pDataSource, i);
+            if (::DrgVerifyRMF(pDragItem, (PSZ)sMechanism.c_str(), (PSZ)sFormat.c_str()))
+            {
+                bValid = true;
+                break;
+            }
+        }
+        if (bValid)
+        {
+            vFormat = pFormats[n];
+            break;
+        }
+    }
+    if (pFormats != &vFormat)
+    {
+        //
+        // Free memory if we allocated it
+        //
+        delete [] pFormats;
+    }
+    return (n < ulFormats ? vFormat : wxFormatInvalid);
+} // end of wxDropTarget::GetSupportedFormat
+
+bool wxDropTarget::IsAcceptedData (
+  PDRAGINFO                         pDataSource
+) const
 {
-    //TODO:
-    return vDef;
-};
+    return (GetSupportedFormat(pDataSource) != wxDF_INVALID);
+} // end of wxDropTarget::IsAcceptedData
 
-bool wxDropTarget::OnDrop(
-  wxCoord                           x
-, wxCoord                           y
-)
+void wxDropTarget::Release ()
 {
-    //TODO:
-    return FALSE;
-};
+    m_pDropTarget->Free();
+} // end of wxDropTarget::Release
+
 
-wxDragResult wxDropTarget::OnData(
-  wxCoord                           x
-, wxCoord                           y
-, wxDragResult                      vResult
+wxDragResult wxDropTarget::OnData (
+  wxCoord                           WXUNUSED(vX)
+, wxCoord                           WXUNUSED(y)
+, wxDragResult                      WXUNUSED(vResult)
 )
 {
-    //TODO:
     return (wxDragResult)0;
-};
+} // end of wxDropTarget::OnData
 
-bool wxDropTarget::GetData()
-{
-    //TODO:
-    return FALSE;
-};
-
-bool wxDropTarget::IsAcceptable(
-  DRAGINFO*                         pInfo
+bool wxDropTarget::OnDrop (
+  wxCoord                           WXUNUSED(x)
+, wxCoord                           WXUNUSED(y)
 )
 {
-    //TODO:
-    return FALSE;
-};
+    return true;
+} // end of wxDropTarget::OnDrop
 
 //-------------------------------------------------------------------------
 // wxDropSource
 //-------------------------------------------------------------------------
 
-wxDropSource::wxDropSource(
-  wxWindow*                         pWin
-)
+wxDropSource::wxDropSource ( wxWindow* WXUNUSED(pWin) )
 {
-    // TODO
-};
+    Init();
+} // end of wxDropSource::wxDropSource
 
-wxDropSource::wxDropSource(
-  wxDataObject&                     rData
-, wxWindow*                         pWin
-)
+wxDropSource::wxDropSource ( wxDataObject& rData, wxWindow* WXUNUSED(pWin) )
 {
-    // TODO
-};
+    Init();
+    SetData(rData);
+} // end of wxDropSource::wxDropSource
 
-wxDropSource::~wxDropSource()
+wxDropSource::~wxDropSource ()
 {
-    // TODO
-};
+    ::DrgFreeDraginfo(m_pDragInfo);
+} // end of wxDropSource::~wxDropSource
 
-wxDragResult wxDropSource::DoDragDrop(
-  bool                              WXUNUSED(bAllowMove)
+wxDragResult wxDropSource::DoDragDrop (
+  int                              WXUNUSED(flags)
 )
 {
-    // TODO
+    //
+    // Need to specify drag items in derived classes that know their data types
+    // before calling DoDragDrop
+    //
+    if (::DrgDrag( m_pWindow->GetHWND()
+                  ,m_pDragInfo
+                  ,&m_vDragImage
+                  ,m_ulItems
+                  ,VK_BUTTON2
+                  ,NULL
+                 ) != NULLHANDLE)
+    {
+        switch(m_pDragInfo->usOperation)
+        {
+            case DO_COPY:
+                return wxDragCopy;
+
+            case DO_MOVE:
+                return wxDragCopy;
+
+            case DO_LINK:
+                return wxDragCopy;
+
+            default:
+                return wxDragNone;
+        }
+    }
     return wxDragError;
-};
+} // end of wxDropSource::DoDragDrop
+
+bool wxDropSource::GiveFeedback (
+  wxDragResult                      eEffect
+)
+{
+    const wxCursor&                 rCursor = GetCursor(eEffect);
 
-void wxDropSource::Init()
+    if (rCursor.Ok())
+    {
+        ::WinSetPointer(HWND_DESKTOP, (HPOINTER)rCursor.GetHCURSOR());
+        m_vDragImage.hImage = (LHANDLE)rCursor.GetHCURSOR();
+        switch(eEffect)
+        {
+            case wxDragCopy:
+                m_pDragInfo->usOperation = DO_COPY;
+                break;
+
+            case wxDragMove:
+                m_pDragInfo->usOperation = DO_MOVE;
+                break;
+
+            case wxDragLink:
+                m_pDragInfo->usOperation = DO_LINK;
+                break;
+
+            case wxDragNone:
+            case wxDragCancel:
+            case wxDragError:
+                break;
+        }
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+} // end of GuiAdvDnd_CDropSource::GiveFeedback
+
+void wxDropSource::Init ()
 {
-    // TODO
-};
+    m_pDragInfo = ::DrgAllocDraginfo(m_ulItems);
+
+    //
+    // Set a default drag image struct with what we know so far
+    //
+    m_vDragImage.cb             = sizeof(DRAGIMAGE);
+    m_vDragImage.cptl           = 0;  // non-zero if fl is DRG_POLYGON
+    m_vDragImage.hImage         = 0;  // Set in GiveFeedback
+    m_vDragImage.sizlStretch.cx = 20L;
+    m_vDragImage.sizlStretch.cy = 20L;
+    m_vDragImage.fl             = DRG_ICON | DRG_STRETCH;
+    m_vDragImage.cxOffset       = 0;
+    m_vDragImage.cyOffset       = 0;
+
+    HSTR    hStrType = ::DrgAddStrHandle(DRT_UNKNOWN);
+    HSTR    hStrRMF;
+    HSTR    hStrContainer;
+    wxChar  zFormats[128];
+    wxChar  zContainer[128];
+    USHORT  uSize = (USHORT)(GetDataObject()->GetDataSize(GetDataObject()->GetPreferredFormat()) + 1);
+    wxChar* pzBuffer = new wxChar[uSize];
+
+    memset(pzBuffer, '\0', GetDataObject()->GetDataSize(GetDataObject()->GetPreferredFormat()));
+    pzBuffer[GetDataObject()->GetDataSize(GetDataObject()->GetPreferredFormat())] = '\0';
+    GetDataObject()->GetDataHere( GetDataObject()->GetPreferredFormat()
+                                 ,(void*)pzBuffer
+                                );
+
+    wxStrcpy(zFormats, _T("<DRM_OS2FILE, DRF_UNKNOWN>"));
+    wxStrcpy(zContainer, GetDataObject()->GetPreferredFormat().GetId());
+
+    hStrRMF       = ::DrgAddStrHandle((PSZ)zFormats);
+    hStrContainer = ::DrgAddStrHandle((PSZ)zContainer);
+
+    m_pDragItem = new DRAGITEM[m_ulItems];
+    for (ULONG i = 0; i < m_ulItems; i++)
+    {
+        m_pDragItem[i].hwndItem          = m_pWindow->GetHWND();
+        m_pDragItem[i].hstrType          = hStrType;
+        m_pDragItem[i].hstrRMF           = hStrRMF;
+        m_pDragItem[i].hstrContainerName = hStrContainer;
+        m_pDragItem[i].fsControl         = 0;
+        m_pDragItem[i].fsSupportedOps    = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE;
+        m_pDragItem[i].hstrSourceName    = ::DrgAddStrHandle((PSZ)pzBuffer);
+        m_pDragItem[i].hstrTargetName    = m_pDragItem[i].hstrSourceName;
+        m_pDragItem[i].ulItemID          = i;
+        ::DrgSetDragitem( m_pDragInfo
+                         ,&m_pDragItem[i]
+                         ,sizeof(DRAGITEM)
+                         ,0
+                        );
+    }
+    delete [] pzBuffer;
+    delete [] m_pDragItem;
+} // end of wxDropSource::Init
 
 #endif //wxUSE_DRAG_AND_DROP