]> git.saurik.com Git - wxWidgets.git/commitdiff
wxDataObject and wxDropSource implementations
authorVadim Zeitlin <vadim@wxwidgets.org>
Wed, 27 May 1998 23:38:26 +0000 (23:38 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Wed, 27 May 1998 23:38:26 +0000 (23:38 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@53 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

src/msw/ole/dataobj.cpp [new file with mode: 0644]
src/msw/ole/dropsrc.cpp [new file with mode: 0644]

diff --git a/src/msw/ole/dataobj.cpp b/src/msw/ole/dataobj.cpp
new file mode 100644 (file)
index 0000000..c2d512d
--- /dev/null
@@ -0,0 +1,406 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        msw/ole/dataobj.cpp
+// Purpose:     implementation of wx[I]DataObject class
+// Author:      Vadim Zeitlin
+// Modified by: 
+// Created:     10.05.98
+// RCS-ID:      $Id$
+// Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
+// Licence:     wxWindows license
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#ifdef __GNUG__
+  #pragma implementation "dataobj.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#if defined(__BORLANDC__)
+  #pragma hdrstop
+#endif
+
+#include  <wx/log.h>
+#include  <wx/msw/ole/oleutils.h>
+#include  <wx/msw/ole/dataobj.h>
+
+#ifndef __WIN32__
+  #include <ole2.h>
+  #include <olestd.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// functions
+// ----------------------------------------------------------------------------
+
+#ifdef  __DEBUG__
+  static const char *GetTymedName(DWORD tymed);
+#else
+  #define GetTymedName(tymed) ""
+#endif
+
+// ----------------------------------------------------------------------------
+// wxIEnumFORMATETC interface implementation
+// ----------------------------------------------------------------------------
+class wxIEnumFORMATETC : public IEnumFORMATETC
+{
+public:
+  wxIEnumFORMATETC(CLIPFORMAT cf);
+
+  DECLARE_IUNKNOWN_METHODS;
+
+  // IEnumFORMATETC
+  STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched);
+  STDMETHODIMP Skip(ULONG celt);
+  STDMETHODIMP Reset();
+  STDMETHODIMP Clone(IEnumFORMATETC **ppenum);
+
+private:
+  FORMATETC   m_format;   // (unique @@@) format we can provide data in
+  ULONG       m_nCurrent; // current enum position (currently either 0 or 1)
+};
+
+// ----------------------------------------------------------------------------
+// wxIDataObject implementation of IDataObject interface
+// ----------------------------------------------------------------------------
+class wxIDataObject : public IDataObject
+{
+public:
+  wxIDataObject(wxDataObject *pDataObject);
+
+  DECLARE_IUNKNOWN_METHODS;
+
+  // IDataObject
+  STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
+  STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
+  STDMETHODIMP QueryGetData(FORMATETC *pformatetc);
+  STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *In, FORMATETC *pOut);
+  STDMETHODIMP SetData(FORMATETC *pfetc, STGMEDIUM *pmedium, BOOL fRelease);
+  STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFEtc);
+  STDMETHODIMP DAdvise(FORMATETC *pfetc, DWORD ad, IAdviseSink *p, DWORD *pdw);
+  STDMETHODIMP DUnadvise(DWORD dwConnection);
+  STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
+
+private:
+  wxDataObject *m_pDataObject;      // pointer to C++ class we belong to
+};
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxIEnumFORMATETC
+// ----------------------------------------------------------------------------
+
+BEGIN_IID_TABLE(wxIEnumFORMATETC)
+  ADD_IID(Unknown)
+  ADD_IID(EnumFORMATETC)
+END_IID_TABLE;
+
+IMPLEMENT_IUNKNOWN_METHODS(wxIEnumFORMATETC)
+
+wxIEnumFORMATETC::wxIEnumFORMATETC(CLIPFORMAT cf)
+{
+  m_format.cfFormat = cf;
+  m_format.ptd      = NULL;
+  m_format.dwAspect = DVASPECT_CONTENT;
+  m_format.lindex   = -1;
+  m_format.tymed    = TYMED_HGLOBAL;
+  m_cRef = 0;
+  m_nCurrent = 0;
+}
+
+STDMETHODIMP wxIEnumFORMATETC::Next(ULONG      celt,
+                                    FORMATETC *rgelt,
+                                    ULONG     *pceltFetched)
+{
+  wxLogTrace("wxIEnumFORMATETC::Next");
+
+  if ( celt > 1 )
+    return S_FALSE;
+
+  if ( m_nCurrent == 0 ) {
+    *rgelt = m_format;
+    m_nCurrent++;
+
+    return S_OK;
+  }
+  else
+    return S_FALSE;
+}
+
+STDMETHODIMP wxIEnumFORMATETC::Skip(ULONG celt)
+{
+  wxLogTrace("wxIEnumFORMATETC::Skip");
+
+  if ( m_nCurrent == 0 )
+    m_nCurrent++;
+
+  return S_FALSE;
+}
+
+STDMETHODIMP wxIEnumFORMATETC::Reset()
+{
+  wxLogTrace("wxIEnumFORMATETC::Reset");
+
+  m_nCurrent = 0;
+
+  return S_OK;
+}
+
+STDMETHODIMP wxIEnumFORMATETC::Clone(IEnumFORMATETC **ppenum)
+{
+  wxLogTrace("wxIEnumFORMATETC::Clone");
+
+  wxIEnumFORMATETC *pNew = new wxIEnumFORMATETC(m_format.cfFormat);
+  pNew->AddRef();
+  *ppenum = pNew;
+
+  return S_OK;
+}
+
+// ----------------------------------------------------------------------------
+// wxIDataObject
+// ----------------------------------------------------------------------------
+
+BEGIN_IID_TABLE(wxIDataObject)
+  ADD_IID(Unknown)
+  ADD_IID(DataObject)
+END_IID_TABLE;
+
+IMPLEMENT_IUNKNOWN_METHODS(wxIDataObject)
+
+wxIDataObject::wxIDataObject(wxDataObject *pDataObject)
+{
+  m_cRef = 0;
+  m_pDataObject = pDataObject;
+}
+
+// get data functions
+STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
+{
+  wxLogTrace("wxIDataObject::GetData");
+
+  // is data is in our format?
+  HRESULT hr = QueryGetData(pformatetcIn);
+  if ( FAILED(hr) )
+    return hr;
+
+  // alloc memory
+  HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
+                                m_pDataObject->GetDataSize());
+  if ( hGlobal == NULL ) {
+    wxLogLastError("GlobalAlloc");
+    return E_OUTOFMEMORY;
+  }
+
+  // copy data
+  pmedium->tymed          = TYMED_HGLOBAL;
+  pmedium->hGlobal        = hGlobal;
+  pmedium->pUnkForRelease = NULL;
+
+  hr = GetDataHere(pformatetcIn, pmedium);
+  if ( FAILED(hr) ) {
+    GlobalFree(hGlobal);
+    return hr;
+  }
+
+  return S_OK;
+}
+
+STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
+                                        STGMEDIUM *pmedium)
+{
+  wxLogTrace("wxIDataObject::GetDataHere");
+
+  // put data in caller provided medium
+  if ( pmedium->tymed != TYMED_HGLOBAL )
+    return DV_E_TYMED;
+
+  // copy data
+  void *pBuf = GlobalLock(pmedium->hGlobal);
+  if ( pBuf == NULL ) {
+    wxLogLastError("GlobalLock");
+    return E_OUTOFMEMORY;
+  }
+
+  m_pDataObject->GetDataHere(pBuf);
+
+  GlobalUnlock(pmedium->hGlobal);
+
+  return S_OK;
+}
+
+// set data functions (not implemented)
+STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
+                                    STGMEDIUM *pmedium,
+                                    BOOL       fRelease)
+{
+  wxLogTrace("wxIDataObject::SetData");
+  return E_NOTIMPL;
+}
+
+// information functions
+STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
+{
+  // do we accept data in this format?
+  if ( pformatetc == NULL ) {
+    wxLogTrace("wxIDataObject::QueryGetData: invalid ptr.");
+    return E_INVALIDARG;
+  }
+
+  // the only one allowed by current COM implementation
+  if ( pformatetc->lindex != -1 ) {
+    wxLogTrace("wxIDataObject::QueryGetData: bad lindex %d",
+               pformatetc->lindex);
+    return DV_E_LINDEX;
+  }
+
+  // we don't support anything other (THUMBNAIL, ICON, DOCPRINT...)
+  if ( pformatetc->dwAspect != DVASPECT_CONTENT ) {
+    wxLogTrace("wxIDataObject::QueryGetData: bad dwAspect %d",
+               pformatetc->dwAspect);
+    return DV_E_DVASPECT;
+  }
+
+  // @@ we only transfer data by global memory (bad for large amounts of it!)
+  if ( !(pformatetc->tymed & TYMED_HGLOBAL) ) {
+    wxLogTrace("wxIDataObject::QueryGetData: %s != TYMED_HGLOBAL.",
+               GetTymedName(pformatetc->tymed));
+    return DV_E_TYMED;
+  }
+
+  // and now check the type of data requested
+  if ( m_pDataObject->IsSupportedFormat(pformatetc->cfFormat) ) {
+    wxLogTrace("wxIDataObject::QueryGetData: %s ok",
+               wxDataObject::GetFormatName(pformatetc->cfFormat));
+    return S_OK;
+  }
+  else {
+    wxLogTrace("wxIDataObject::QueryGetData: %s unsupported",
+               wxDataObject::GetFormatName(pformatetc->cfFormat));
+    return DV_E_FORMATETC;
+  }
+}
+
+STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *pFormatetcIn,
+                                                  FORMATETC *pFormatetcOut)
+{
+  wxLogTrace("wxIDataObject::GetCanonicalFormatEtc");
+
+  // @@ implementation is trivial, we might want something better here
+  if ( pFormatetcOut != NULL )
+    pFormatetcOut->ptd = NULL;
+  return DATA_S_SAMEFORMATETC;
+}
+
+STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection,
+                                          IEnumFORMATETC **ppenumFormatEtc)
+{
+  wxLogTrace("wxIDataObject::EnumFormatEtc");
+
+  if ( dwDirection == DATADIR_SET ) {
+    // we don't allow setting of data anyhow
+    return E_NOTIMPL;
+  }
+
+  wxIEnumFORMATETC *pEnum = 
+    new wxIEnumFORMATETC(m_pDataObject->GetPreferredFormat());
+  pEnum->AddRef();
+  *ppenumFormatEtc = pEnum;
+
+  return S_OK;
+}
+
+// advise sink functions (not implemented)
+STDMETHODIMP wxIDataObject::DAdvise(FORMATETC   *pformatetc,
+                                    DWORD        advf,
+                                    IAdviseSink *pAdvSink,
+                                    DWORD       *pdwConnection)
+{
+  return OLE_E_ADVISENOTSUPPORTED;
+}
+
+STDMETHODIMP wxIDataObject::DUnadvise(DWORD dwConnection)
+{
+  return OLE_E_ADVISENOTSUPPORTED;
+}
+
+STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
+{
+  return OLE_E_ADVISENOTSUPPORTED;
+}
+
+// ----------------------------------------------------------------------------
+// wxDataObject
+// ----------------------------------------------------------------------------
+
+wxDataObject::wxDataObject()
+{
+  m_pIDataObject = new wxIDataObject(this);
+  m_pIDataObject->AddRef();
+}
+
+wxDataObject::~wxDataObject()
+{
+  m_pIDataObject->Release();
+}
+
+#ifdef  __DEBUG__
+
+const char *wxDataObject::GetFormatName(wxDataFormat format)
+{
+  static char s_szBuf[128];
+  switch ( format ) {
+    case CF_TEXT:         return "CF_TEXT";
+    case CF_BITMAP:       return "CF_BITMAP";
+    case CF_METAFILEPICT: return "CF_METAFILEPICT";
+    case CF_SYLK:         return "CF_SYLK";
+    case CF_DIF:          return "CF_DIF";
+    case CF_TIFF:         return "CF_TIFF";
+    case CF_OEMTEXT:      return "CF_OEMTEXT";
+    case CF_DIB:          return "CF_DIB";
+    case CF_PALETTE:      return "CF_PALETTE";
+    case CF_PENDATA:      return "CF_PENDATA";
+    case CF_RIFF:         return "CF_RIFF";
+    case CF_WAVE:         return "CF_WAVE";
+    case CF_UNICODETEXT:  return "CF_UNICODETEXT";
+    case CF_ENHMETAFILE:  return "CF_ENHMETAFILE";
+    case CF_HDROP:        return "CF_HDROP";
+    case CF_LOCALE:       return "CF_LOCALE";
+    default:
+      sprintf(s_szBuf, "clipboard format %d (unknown)", format);
+      return s_szBuf;
+  }
+}
+
+// ----------------------------------------------------------------------------
+// private functions
+// ----------------------------------------------------------------------------
+static const char *GetTymedName(DWORD tymed)
+{
+  static char s_szBuf[128];
+  switch ( tymed ) {
+    case TYMED_HGLOBAL:   return "TYMED_HGLOBAL";
+    case TYMED_FILE:      return "TYMED_FILE";
+    case TYMED_ISTREAM:   return "TYMED_ISTREAM";
+    case TYMED_ISTORAGE:  return "TYMED_ISTORAGE";
+    case TYMED_GDI:       return "TYMED_GDI";
+    case TYMED_MFPICT:    return "TYMED_MFPICT";
+    case TYMED_ENHMF:     return "TYMED_ENHMF";
+    default:
+      sprintf(s_szBuf, "type of media format %d (unknown)", tymed);
+      return s_szBuf;
+  }
+}
+
+#endif  //DEBUG
\ No newline at end of file
diff --git a/src/msw/ole/dropsrc.cpp b/src/msw/ole/dropsrc.cpp
new file mode 100644 (file)
index 0000000..024b37d
--- /dev/null
@@ -0,0 +1,234 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        msw/ole/dropsrc.cpp
+// Purpose:     implementation of wxIDropSource and wxDropSource
+// Author:      Vadim Zeitlin
+// Modified by: 
+// Created:     10.05.98
+// RCS-ID:      $Id$
+// Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
+// Licence:     wxWindows license
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#ifdef __GNUG__
+  #pragma implementation "dropsrc.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#if defined(__BORLANDC__)
+  #pragma hdrstop
+#endif
+
+#include  <wx/setup.h>
+
+#if USE_DRAG_AND_DROP
+
+#include  <wx/log.h>
+#include  <wx/msw/ole/oleutils.h>
+#include  <wx/msw/ole/dataobj.h>
+#include  <wx/msw/ole/dropsrc.h>
+
+#ifndef __WIN32__
+  #include <ole2.h>
+  #include <olestd.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// wxIDropSource implementation of IDropSource interface
+// ----------------------------------------------------------------------------
+
+class wxIDropSource : public IDropSource
+{
+public:
+  wxIDropSource(wxDropSource *pDropSource);
+
+  DECLARE_IUNKNOWN_METHODS;
+
+  // IDropSource
+  STDMETHODIMP QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
+  STDMETHODIMP GiveFeedback(DWORD dwEffect);
+
+private:
+  DWORD         m_grfInitKeyState;  // button which started the d&d operation
+  wxDropSource *m_pDropSource;      // pointer to C++ class we belong to
+};
+
+// ============================================================================
+// Implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxIDropSource implementation
+// ----------------------------------------------------------------------------
+BEGIN_IID_TABLE(wxIDropSource)
+  ADD_IID(Unknown)
+  ADD_IID(DropSource)
+END_IID_TABLE;
+
+IMPLEMENT_IUNKNOWN_METHODS(wxIDropSource)
+
+wxIDropSource::wxIDropSource(wxDropSource *pDropSource)
+{
+  wxASSERT( pDropSource != NULL );
+
+  m_pDropSource = pDropSource;
+  m_grfInitKeyState = 0;
+  m_cRef = 0;
+}
+
+// Name    : wxIDropSource::QueryContinueDrag
+// Purpose : decide if drag operation must be continued or not
+// Returns : HRESULT: S_OK              if we should continue
+//                    DRAGDROP_S_DROP   to drop right now
+//                    DRAGDROP_S_CANCEL to cancel everything
+// Params  : [in] BOOL  fEscapePressed  <Esc> pressed since last call?
+//           [in] DWORD grfKeyState     mask containing state of kbd keys
+// Notes   : as there is no reasonably simple portable way to implement this
+//           function, we currently don't give the possibility to override the
+//           default behaviour implemented here
+STDMETHODIMP wxIDropSource::QueryContinueDrag(BOOL fEscapePressed,
+                                              DWORD grfKeyState)
+{
+  if ( fEscapePressed )
+    return DRAGDROP_S_CANCEL;
+
+  // initialize ourself with the drag begin button
+  if ( m_grfInitKeyState == 0 ) {
+    m_grfInitKeyState = grfKeyState & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON);
+  }
+
+  if ( !(grfKeyState & m_grfInitKeyState) ) {
+    // button which started d&d released, go!
+    return DRAGDROP_S_DROP;
+  }
+
+  return S_OK;
+}
+
+// Name    : wxIDropSource::GiveFeedback
+// Purpose : give UI feedback according to current state of operation
+// Returns : STDMETHODIMP 
+// Params  : [in] DWORD dwEffect - what would happen if we dropped now
+// Notes   : default implementation is ok in more than 99% of cases
+STDMETHODIMP wxIDropSource::GiveFeedback(DWORD dwEffect)
+{
+  wxDropSource::DragResult effect;
+  if ( dwEffect & DROPEFFECT_COPY )
+    effect = wxDropSource::Copy;
+  else if ( dwEffect & DROPEFFECT_MOVE )
+    effect = wxDropSource::Move;
+  else
+    effect = wxDropSource::None;
+
+  if ( m_pDropSource->GiveFeedback(effect,
+                                   (dwEffect & DROPEFFECT_SCROLL) != 0 ) )
+    return S_OK;
+
+  return DRAGDROP_S_USEDEFAULTCURSORS;
+}
+
+// ----------------------------------------------------------------------------
+// wxDropSource implementation
+// ----------------------------------------------------------------------------
+
+// ctors
+
+// common part of all ctors
+void wxDropSource::Init()
+{
+  m_pIDropSource = new wxIDropSource(this);
+  m_pIDropSource->AddRef();
+}
+
+wxDropSource::wxDropSource()
+{
+  Init();
+  m_pData = NULL;
+}
+
+wxDropSource::wxDropSource(wxDataObject& data)
+{
+  Init();
+  SetData(data);
+}
+
+void wxDropSource::SetData(wxDataObject& data)
+{
+  m_pData = &data;
+}
+
+wxDropSource::~wxDropSource()
+{
+  m_pIDropSource->Release();
+}
+
+// Name    : DoDragDrop
+// Purpose : start drag and drop operation
+// Returns : DragResult - the code of performed operation
+// Params  : [in] bool bAllowMove: if false, only copy is allowed
+// Notes   : you must call SetData() before if you had used def ctor
+wxDropSource::DragResult wxDropSource::DoDragDrop(bool bAllowMove)
+{
+  wxCHECK_RET( m_pData != NULL, None );
+
+  DWORD dwEffect;
+  HRESULT hr = ::DoDragDrop(m_pData->GetInterface(), 
+                            m_pIDropSource, 
+                            bAllowMove ? DROPEFFECT_COPY | DROPEFFECT_MOVE
+                                       : DROPEFFECT_COPY,
+                            &dwEffect);
+
+  if ( hr == DRAGDROP_S_CANCEL ) {
+    return Cancel;
+  }
+  else if ( hr == DRAGDROP_S_DROP ) {
+    if ( dwEffect & DROPEFFECT_COPY ) {
+      return Copy;
+    }
+    else if ( dwEffect & DROPEFFECT_MOVE ) {
+      // consistency check: normally, we shouldn't get "move" at all
+      // here if !bAllowMove, but in practice it does happen quite often
+      if ( bAllowMove )
+        return Move;
+      else
+        return Copy;
+    }
+    else {
+      // not copy or move
+      return None;
+    }
+  }
+  else {
+    if ( FAILED(hr) ) {
+      wxLogApiError("DoDragDrop", hr);
+      wxLogError("Drag & drop operation failed.");
+    }
+    else {
+      wxLogDebug("Unexpected success return code %08lx from DoDragDrop.", hr);
+    }
+
+    return Error;
+  }
+}
+
+// Name    : wxDropSource::GiveFeedback
+// Purpose : visually inform the user about d&d operation state
+// Returns : bool: true if we do all ourselves or false for default feedback
+// Params  : [in] DragResult effect - what would happen if we dropped now
+//           [in] bool bScrolling   - true if target is scrolling    
+// Notes   : here we just leave this stuff for default implementation
+bool wxDropSource::GiveFeedback(DragResult effect, bool bScrolling)
+{
+  return false;
+}
+
+#endif  //USE_DRAG_AND_DROP
\ No newline at end of file