1/////////////////////////////////////////////////////////////////////////////// 2// Name: src/msw/ole/dropsrc.cpp 3// Purpose: implementation of wxIDropSource and wxDropSource 4// Author: Vadim Zeitlin 5// Modified by: 6// Created: 10.05.98 7// RCS-ID: $Id: dropsrc.cpp 38920 2006-04-26 08:21:31Z ABX $ 8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 9// Licence: wxWindows licence 10/////////////////////////////////////////////////////////////////////////////// 11 12// ============================================================================ 13// declarations 14// ============================================================================ 15 16// ---------------------------------------------------------------------------- 17// headers 18// ---------------------------------------------------------------------------- 19 20// For compilers that support precompilation, includes "wx.h". 21#include "wx/wxprec.h" 22 23#if defined(__BORLANDC__) 24 #pragma hdrstop 25#endif 26 27#if wxUSE_OLE && wxUSE_DRAG_AND_DROP 28 29#ifndef WX_PRECOMP 30 #include "wx/window.h" 31 #include "wx/log.h" 32#endif 33 34#include "wx/dnd.h" 35 36#include "wx/msw/private.h" 37 38// for some compilers, the entire ole2.h must be included, not only oleauto.h 39#if wxUSE_NORLANDER_HEADERS || defined(__WATCOMC__) || defined(__WXWINCE__) 40 #include <ole2.h> 41#endif 42 43#include <oleauto.h> 44 45#include "wx/msw/ole/oleutils.h" 46 47// ---------------------------------------------------------------------------- 48// wxIDropSource implementation of IDropSource interface 49// ---------------------------------------------------------------------------- 50 51class wxIDropSource : public IDropSource 52{ 53public: 54 wxIDropSource(wxDropSource *pDropSource); 55 virtual ~wxIDropSource() { } 56 57 // IDropSource 58 STDMETHODIMP QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState); 59 STDMETHODIMP GiveFeedback(DWORD dwEffect); 60 61 DECLARE_IUNKNOWN_METHODS; 62 63private: 64 DWORD m_grfInitKeyState; // button which started the d&d operation 65 wxDropSource *m_pDropSource; // pointer to C++ class we belong to 66 67 DECLARE_NO_COPY_CLASS(wxIDropSource) 68}; 69 70// ============================================================================ 71// Implementation 72// ============================================================================ 73 74// ---------------------------------------------------------------------------- 75// wxIDropSource implementation 76// ---------------------------------------------------------------------------- 77BEGIN_IID_TABLE(wxIDropSource) 78 ADD_IID(Unknown) 79 ADD_IID(DropSource) 80END_IID_TABLE; 81 82IMPLEMENT_IUNKNOWN_METHODS(wxIDropSource) 83 84wxIDropSource::wxIDropSource(wxDropSource *pDropSource) 85{ 86 wxASSERT( pDropSource != NULL ); 87 88 m_pDropSource = pDropSource; 89 m_grfInitKeyState = 0; 90} 91 92// Name : wxIDropSource::QueryContinueDrag 93// Purpose : decide if drag operation must be continued or not 94// Returns : HRESULT: S_OK if we should continue 95// DRAGDROP_S_DROP to drop right now 96// DRAGDROP_S_CANCEL to cancel everything 97// Params : [in] BOOL fEscapePressed <Esc> pressed since last call? 98// [in] DWORD grfKeyState mask containing state of kbd keys 99// Notes : as there is no reasonably simple portable way to implement this 100// function, we currently don't give the possibility to override the 101// default behaviour implemented here 102STDMETHODIMP wxIDropSource::QueryContinueDrag(BOOL fEscapePressed, 103 DWORD grfKeyState) 104{ 105 if ( fEscapePressed ) 106 return DRAGDROP_S_CANCEL; 107 108 // initialize ourself with the drag begin button 109 if ( m_grfInitKeyState == 0 ) { 110 m_grfInitKeyState = grfKeyState & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON); 111 } 112 113 if ( !(grfKeyState & m_grfInitKeyState) ) { 114 // button which started d&d released, go! 115 return DRAGDROP_S_DROP; 116 } 117 118 return S_OK; 119} 120 121// Name : wxIDropSource::GiveFeedback 122// Purpose : give UI feedback according to current state of operation 123// Returns : STDMETHODIMP 124// Params : [in] DWORD dwEffect - what would happen if we dropped now 125// Notes : default implementation is ok in more than 99% of cases 126STDMETHODIMP wxIDropSource::GiveFeedback(DWORD dwEffect) 127{ 128 wxDragResult effect; 129 if ( dwEffect & DROPEFFECT_COPY ) 130 effect = wxDragCopy; 131 else if ( dwEffect & DROPEFFECT_MOVE ) 132 effect = wxDragMove; 133 else 134 effect = wxDragNone; 135 136 if ( m_pDropSource->GiveFeedback(effect) ) 137 return S_OK; 138 139 return DRAGDROP_S_USEDEFAULTCURSORS; 140} 141 142// ---------------------------------------------------------------------------- 143// wxDropSource implementation 144// ---------------------------------------------------------------------------- 145 146// ctors 147 148// common part of all ctors 149void wxDropSource::Init() 150{ 151 m_pIDropSource = new wxIDropSource(this); 152 m_pIDropSource->AddRef(); 153} 154 155wxDropSource::wxDropSource(wxWindow* WXUNUSED(win), 156 const wxCursor &cursorCopy, 157 const wxCursor &cursorMove, 158 const wxCursor &cursorStop) 159 : wxDropSourceBase(cursorCopy, cursorMove, cursorStop) 160{ 161 Init(); 162} 163 164wxDropSource::wxDropSource(wxDataObject& data, 165 wxWindow* WXUNUSED(win), 166 const wxCursor &cursorCopy, 167 const wxCursor &cursorMove, 168 const wxCursor &cursorStop) 169 : wxDropSourceBase(cursorCopy, cursorMove, cursorStop) 170{ 171 Init(); 172 SetData(data); 173} 174 175wxDropSource::~wxDropSource() 176{ 177 m_pIDropSource->Release(); 178} 179 180// Name : DoDragDrop 181// Purpose : start drag and drop operation 182// Returns : wxDragResult - the code of performed operation 183// Params : [in] int flags: specifies if moving is allowe (or only copying) 184// Notes : you must call SetData() before if you had used def ctor 185wxDragResult wxDropSource::DoDragDrop(int flags) 186{ 187 wxCHECK_MSG( m_data != NULL, wxDragNone, wxT("No data in wxDropSource!") ); 188 189 DWORD dwEffect; 190 HRESULT hr = ::DoDragDrop(m_data->GetInterface(), 191 m_pIDropSource, 192 (flags & wxDrag_AllowMove) 193 ? DROPEFFECT_COPY | DROPEFFECT_MOVE 194 : DROPEFFECT_COPY, 195 &dwEffect); 196 197 if ( hr == DRAGDROP_S_CANCEL ) { 198 return wxDragCancel; 199 } 200 else if ( hr == DRAGDROP_S_DROP ) { 201 if ( dwEffect & DROPEFFECT_COPY ) { 202 return wxDragCopy; 203 } 204 else if ( dwEffect & DROPEFFECT_MOVE ) { 205 // consistency check: normally, we shouldn't get "move" at all 206 // here if we don't allow it, but in practice it does happen quite often 207 return (flags & wxDrag_AllowMove) ? wxDragMove : wxDragCopy; 208 } 209 else { 210 // not copy or move 211 return wxDragNone; 212 } 213 } 214 else { 215 if ( FAILED(hr) ) { 216 wxLogApiError(wxT("DoDragDrop"), hr); 217 wxLogError(wxT("Drag & drop operation failed.")); 218 } 219 else { 220 wxLogDebug(wxT("Unexpected success return code %08lx from DoDragDrop."), 221 hr); 222 } 223 224 return wxDragError; 225 } 226} 227 228// Name : wxDropSource::GiveFeedback 229// Purpose : visually inform the user about d&d operation state 230// Returns : bool: true if we do all ourselves or false for default feedback 231// Params : [in] DragResult effect - what would happen if we dropped now 232// Notes : here we just leave this stuff for default implementation 233bool wxDropSource::GiveFeedback(wxDragResult effect) 234{ 235 const wxCursor& cursor = GetCursor(effect); 236 if ( cursor.Ok() ) 237 { 238 ::SetCursor((HCURSOR)cursor.GetHCURSOR()); 239 240 return true; 241 } 242 else 243 { 244 return false; 245 } 246} 247 248#endif // wxUSE_OLE && wxUSE_DRAG_AND_DROP 249