From: Vadim Zeitlin Date: Wed, 27 May 1998 23:38:26 +0000 (+0000) Subject: wxDataObject and wxDropSource implementations X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/269a5a34a6eb0f1eab66c5e09c667b66f0ac90a3 wxDataObject and wxDropSource implementations git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@53 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/src/msw/ole/dataobj.cpp b/src/msw/ole/dataobj.cpp new file mode 100644 index 0000000000..c2d512d673 --- /dev/null +++ b/src/msw/ole/dataobj.cpp @@ -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 +// 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 +#include +#include + +#ifndef __WIN32__ + #include + #include +#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 index 0000000000..024b37defc --- /dev/null +++ b/src/msw/ole/dropsrc.cpp @@ -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 +// 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 + +#if USE_DRAG_AND_DROP + +#include +#include +#include +#include + +#ifndef __WIN32__ + #include + #include +#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 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