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