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