]> git.saurik.com Git - wxWidgets.git/blame - src/msw/ole/droptgt.cpp
added helpext.cpp and regenerated the makefiles
[wxWidgets.git] / src / msw / ole / droptgt.cpp
CommitLineData
bbf1f0e5
KB
1///////////////////////////////////////////////////////////////////////////////
2// Name: ole/droptgt.cpp
3// Purpose: wxDropTarget implementation
4// Author: Vadim Zeitlin
3f480da3
VZ
5// Modified by:
6// Created:
bbf1f0e5
KB
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// Licence: wxWindows license
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// Declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21#pragma implementation "droptgt.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
bbf1f0e5
KB
25#include "wx/wxprec.h"
26
27#if defined(__BORLANDC__)
28#pragma hdrstop
29#endif
30
3f480da3 31#include "wx/setup.h"
bbf1f0e5 32
47d67540 33#if wxUSE_DRAG_AND_DROP
bbf1f0e5 34
3f480da3 35#include "wx/log.h"
bbf1f0e5
KB
36
37#ifdef __WIN32__
3f480da3
VZ
38 #ifndef __GNUWIN32__
39 #include <shlobj.h> // for DROPFILES structure
40 #endif
bbf1f0e5 41#else
3f480da3 42 #include <shellapi.h>
bbf1f0e5
KB
43#endif
44
9e2896e5 45#include "wx/dnd.h"
bbf1f0e5
KB
46
47#ifndef __WIN32__
3f480da3
VZ
48 #include <ole2.h>
49 #include <olestd.h>
bbf1f0e5
KB
50#endif
51
3f480da3 52#include "wx/msw/ole/oleutils.h"
bbf1f0e5
KB
53
54// ----------------------------------------------------------------------------
55// IDropTarget interface: forward all interesting things to wxDropTarget
56// (the name is unfortunate, but wx_I_DropTarget is not at all the same thing
57// as wxDropTarget which is 'public' class, while this one is private)
58// ----------------------------------------------------------------------------
59
60class wxIDropTarget : public IDropTarget
61{
62public:
63 wxIDropTarget(wxDropTarget *p);
64 ~wxIDropTarget();
65
66 // IDropTarget methods
67 STDMETHODIMP DragEnter(LPDATAOBJECT, DWORD, POINTL, LPDWORD);
68 STDMETHODIMP DragOver(DWORD, POINTL, LPDWORD);
69 STDMETHODIMP DragLeave(void);
70 STDMETHODIMP Drop(LPDATAOBJECT, DWORD, POINTL, LPDWORD);
71
bbf1f0e5
KB
72 DECLARE_IUNKNOWN_METHODS;
73
74protected:
75 IDataObject *m_pIDataObject; // !NULL between DragEnter and DragLeave/Drop
76 wxDropTarget *m_pTarget; // the real target (we're just a proxy)
77
bbf1f0e5
KB
78private:
79 static inline DWORD GetDropEffect(DWORD flags);
80};
81
82// ============================================================================
83// wxIDropTarget implementation
84// ============================================================================
85
86// Name : static wxDropTarget::GetDropEffect
87// Purpose : determine the drop operation from keyboard/mouse state.
3f480da3 88// Returns : DWORD combined from DROPEFFECT_xxx constants
bbf1f0e5
KB
89// Params : [in] DWORD flags kbd & mouse flags as passed to
90// IDropTarget methods
91// Notes : We do "move" normally and "copy" if <Ctrl> is pressed,
3f480da3 92// which is the standard behaviour (currently there is no
bbf1f0e5
KB
93// way to redefine it)
94DWORD wxIDropTarget::GetDropEffect(DWORD flags)
95{
96 return flags & MK_CONTROL ? DROPEFFECT_COPY : DROPEFFECT_MOVE;
97}
98
99wxIDropTarget::wxIDropTarget(wxDropTarget *pTarget)
3f480da3
VZ
100{
101 m_cRef = 0;
bbf1f0e5 102 m_pTarget = pTarget;
3f480da3 103 m_pIDataObject = NULL;
bbf1f0e5
KB
104}
105
3f480da3
VZ
106wxIDropTarget::~wxIDropTarget()
107{
bbf1f0e5
KB
108}
109
110BEGIN_IID_TABLE(wxIDropTarget)
111 ADD_IID(Unknown)
112 ADD_IID(DropTarget)
113END_IID_TABLE;
114
115IMPLEMENT_IUNKNOWN_METHODS(wxIDropTarget)
116
bbf1f0e5
KB
117// Name : wxIDropTarget::DragEnter
118// Purpose : Called when the mouse enters the window (dragging something)
119// Returns : S_OK
120// Params : [in] IDataObject *pIDataSource : source data
121// [in] DWORD grfKeyState : kbd & mouse state
122// [in] POINTL pt : mouse coordinates
123// [out]DWORD *pdwEffect : effect flag
3f480da3 124// Notes :
bbf1f0e5
KB
125STDMETHODIMP wxIDropTarget::DragEnter(IDataObject *pIDataSource,
126 DWORD grfKeyState,
127 POINTL pt,
128 DWORD *pdwEffect)
129{
223d09f6 130 wxLogDebug(wxT("IDropTarget::DragEnter"));
bbf1f0e5
KB
131
132 wxASSERT( m_pIDataObject == NULL );
133
134 if ( !m_pTarget->IsAcceptedData(pIDataSource) ) {
135 // we don't accept this kind of data
136 *pdwEffect = DROPEFFECT_NONE;
137
138 return S_OK;
139 }
140
3f480da3
VZ
141 // TODO should check the point also?
142
bbf1f0e5
KB
143 *pdwEffect = GetDropEffect(grfKeyState);
144
145 // get hold of the data object
146 m_pIDataObject = pIDataSource;
147 m_pIDataObject->AddRef();
148
149 // give some visual feedback
150 m_pTarget->OnEnter();
151
152 return S_OK;
153}
154
155// Name : wxIDropTarget::DragOver
156// Purpose : Indicates that the mouse was moved inside the window represented
157// by this drop target.
158// Returns : S_OK
159// Params : [in] DWORD grfKeyState kbd & mouse state
160// [in] POINTL pt mouse coordinates
161// [out]LPDWORD pdwEffect effect flag
3f480da3 162// Notes : We're called on every WM_MOUSEMOVE, so this function should be
bbf1f0e5
KB
163// very efficient.
164STDMETHODIMP wxIDropTarget::DragOver(DWORD grfKeyState,
165 POINTL pt,
166 LPDWORD pdwEffect)
167{
168 // there are too many of them... wxLogDebug("IDropTarget::DragOver");
169
3f480da3 170 *pdwEffect = m_pIDataObject == NULL ? DROPEFFECT_NONE
bbf1f0e5
KB
171 : GetDropEffect(grfKeyState);
172 return S_OK;
173}
174
175// Name : wxIDropTarget::DragLeave
176// Purpose : Informs the drop target that the operation has left its window.
177// Returns : S_OK
178// Notes : good place to do any clean-up
179STDMETHODIMP wxIDropTarget::DragLeave()
180{
223d09f6 181 wxLogDebug(wxT("IDropTarget::DragLeave"));
bbf1f0e5
KB
182
183 // remove the UI feedback
184 m_pTarget->OnLeave();
185
186 // release the held object
187 RELEASE_AND_NULL(m_pIDataObject);
3f480da3 188
bbf1f0e5
KB
189 return S_OK;
190}
191
192// Name : wxIDropTarget::Drop
3f480da3 193// Purpose : Instructs the drop target to paste data that was just now
bbf1f0e5
KB
194// dropped on it.
195// Returns : S_OK
196// Params : [in] IDataObject *pIDataSource the data to paste
197// [in] DWORD grfKeyState kbd & mouse state
198// [in] POINTL pt where the drop occured?
199// [ouy]DWORD *pdwEffect operation effect
3f480da3
VZ
200// Notes :
201STDMETHODIMP wxIDropTarget::Drop(IDataObject *pIDataSource,
202 DWORD grfKeyState,
203 POINTL pt,
bbf1f0e5
KB
204 DWORD *pdwEffect)
205{
9e2896e5
VZ
206 wxLogDebug(wxT("IDropTarget::Drop"));
207
208 // TODO I don't know why there is this parameter, but so far I assume
209 // that it's the same we've already got in DragEnter
210 wxASSERT( m_pIDataObject == pIDataSource );
211
212 // by default, nothing happens
213 *pdwEffect = DROPEFFECT_NONE;
214
215 // first ask the drop target if it wants data
216 if ( m_pTarget->OnDrop(pt.x, pt.y) ) {
217 // it does, so give it the data source
218 m_pTarget->SetDataSource(pIDataSource);
219
220 // and now it has the data
221 if ( m_pTarget->OnData(pt.x, pt.y) ) {
222 // operation succeeded
223 *pdwEffect = GetDropEffect(grfKeyState);
224 }
225 //else: *pdwEffect is already DROPEFFECT_NONE
bbf1f0e5 226 }
9e2896e5 227 //else: OnDrop() returned FALSE, no need to copy data
bbf1f0e5 228
9e2896e5
VZ
229 // release the held object
230 RELEASE_AND_NULL(m_pIDataObject);
bbf1f0e5 231
9e2896e5 232 return S_OK;
bbf1f0e5
KB
233}
234
235// ============================================================================
236// wxDropTarget implementation
237// ============================================================================
238
239// ----------------------------------------------------------------------------
240// ctor/dtor
241// ----------------------------------------------------------------------------
242
9e2896e5
VZ
243wxDropTarget::wxDropTarget(wxDataObject *dataObj)
244 : wxDropTargetBase(dataObj)
bbf1f0e5 245{
9e2896e5
VZ
246 // create an IDropTarget implementation which will notify us about d&d
247 // operations.
248 m_pIDropTarget = new wxIDropTarget(this);
249 m_pIDropTarget->AddRef();
bbf1f0e5
KB
250}
251
252wxDropTarget::~wxDropTarget()
253{
9e2896e5 254 ReleaseInterface(m_pIDropTarget);
bbf1f0e5
KB
255}
256
257// ----------------------------------------------------------------------------
258// [un]register drop handler
259// ----------------------------------------------------------------------------
260
261bool wxDropTarget::Register(WXHWND hwnd)
262{
9e2896e5
VZ
263 HRESULT hr = ::CoLockObjectExternal(m_pIDropTarget, TRUE, FALSE);
264 if ( FAILED(hr) ) {
265 wxLogApiError("CoLockObjectExternal", hr);
266 return FALSE;
267 }
bbf1f0e5 268
9e2896e5
VZ
269 hr = ::RegisterDragDrop((HWND) hwnd, m_pIDropTarget);
270 if ( FAILED(hr) ) {
271 ::CoLockObjectExternal(m_pIDropTarget, FALSE, FALSE);
bbf1f0e5 272
9e2896e5
VZ
273 wxLogApiError("RegisterDragDrop", hr);
274 return FALSE;
275 }
bbf1f0e5 276
9e2896e5 277 return TRUE;
bbf1f0e5
KB
278}
279
280void wxDropTarget::Revoke(WXHWND hwnd)
281{
9e2896e5 282 HRESULT hr = ::RevokeDragDrop((HWND) hwnd);
bbf1f0e5 283
9e2896e5
VZ
284 if ( FAILED(hr) ) {
285 wxLogApiError("RevokeDragDrop", hr);
286 }
bbf1f0e5 287
9e2896e5 288 ::CoLockObjectExternal(m_pIDropTarget, FALSE, TRUE);
bbf1f0e5
KB
289}
290
291// ----------------------------------------------------------------------------
9e2896e5 292// base class pure virtuals
bbf1f0e5 293// ----------------------------------------------------------------------------
9e2896e5
VZ
294
295// OnDrop() is called only if we previously returned TRUE from
296// IsAcceptedData(), so no need to check anything here
297bool wxDropTarget::OnDrop(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y))
298{
299 return TRUE;
300}
301
302// copy the data from the data source to the target data object
303bool wxDropTarget::GetData()
bbf1f0e5 304{
9e2896e5
VZ
305 wxDataFormat format = GetSupportedFormat(m_pIDataSource);
306 if ( format == wxDF_INVALID ) {
307 // this is strange because IsAcceptedData() succeeded previously!
308 wxFAIL_MSG(wxT("strange - did supported formats list change?"));
309
310 return FALSE;
311 }
312
313 STGMEDIUM stm;
314 FORMATETC fmtMemory;
315 fmtMemory.cfFormat = format;
316 fmtMemory.ptd = NULL;
317 fmtMemory.dwAspect = DVASPECT_CONTENT;
318 fmtMemory.lindex = -1;
319 fmtMemory.tymed = TYMED_HGLOBAL; // TODO to add other media
320
321 bool rc = FALSE;
322
323 HRESULT hr = m_pIDataSource->GetData(&fmtMemory, &stm);
324 if ( SUCCEEDED(hr) ) {
325 IDataObject *dataObject = m_dataObject->GetInterface();
326
327 hr = dataObject->SetData(&fmtMemory, &stm, TRUE);
328 if ( SUCCEEDED(hr) ) {
329 rc = TRUE;
330 }
331 else {
332 wxLogLastError("IDataObject::SetData()");
333 }
334 }
335 else {
336 wxLogLastError("IDataObject::GetData()");
bbf1f0e5 337 }
bbf1f0e5 338
9e2896e5 339 return rc;
bbf1f0e5
KB
340}
341
9e2896e5
VZ
342// ----------------------------------------------------------------------------
343// callbacks used by wxIDropTarget
344// ----------------------------------------------------------------------------
bbf1f0e5 345
9e2896e5
VZ
346// we need a data source, so wxIDropTarget gives it to us using this function
347void wxDropTarget::SetDataSource(IDataObject *pIDataSource)
bbf1f0e5 348{
9e2896e5 349 m_pIDataSource = pIDataSource;
bbf1f0e5
KB
350}
351
9e2896e5
VZ
352// determine if we accept data of this type
353bool wxDropTarget::IsAcceptedData(IDataObject *pIDataSource) const
bbf1f0e5 354{
9e2896e5 355 return GetSupportedFormat(pIDataSource) != wxDF_INVALID;
bbf1f0e5
KB
356}
357
9e2896e5
VZ
358// ----------------------------------------------------------------------------
359// helper functions
360// ----------------------------------------------------------------------------
361
362wxDataFormat wxDropTarget::GetSupportedFormat(IDataObject *pIDataSource) const
bbf1f0e5 363{
9e2896e5
VZ
364 // this strucutre describes a data of any type (first field will be
365 // changing) being passed through global memory block.
366 static FORMATETC s_fmtMemory = {
367 0,
368 NULL,
369 DVASPECT_CONTENT,
370 -1,
371 TYMED_HGLOBAL // TODO is it worth supporting other tymeds here?
372 };
373
374 // get the list of supported formats
375 size_t nFormats = m_dataObject->GetFormatCount(wxDataObject::Set);
376 wxDataFormat format, *formats;
377 formats = nFormats == 1 ? &format : new wxDataFormat[nFormats];
378
379 m_dataObject->GetAllFormats(formats, wxDataObject::Set);
380
381 // cycle through all supported formats
382 size_t n;
383 for ( n = 0; n < nFormats; n++ ) {
384 s_fmtMemory.cfFormat = formats[n];
385
386 // NB: don't use SUCCEEDED macro here: QueryGetData returns S_FALSE
387 // for file drag and drop (format == CF_HDROP)
388 if ( pIDataSource->QueryGetData(&s_fmtMemory) == S_OK ) {
389 format = formats[n];
390
391 break;
392 }
393 }
394
395 if ( formats != &format ) {
396 // free memory if we allocated it
397 delete [] formats;
398 }
399
400 return n < nFormats ? format : wxDF_INVALID;
bbf1f0e5
KB
401}
402
9e2896e5
VZ
403// ----------------------------------------------------------------------------
404// wxTextDropTarget
405// ----------------------------------------------------------------------------
bbf1f0e5 406
9e2896e5
VZ
407wxTextDropTarget::wxTextDropTarget()
408 : wxDropTarget(new wxTextDataObject)
bbf1f0e5 409{
9e2896e5 410}
bbf1f0e5 411
9e2896e5
VZ
412bool wxTextDropTarget::OnData(wxCoord x, wxCoord y)
413{
414 if ( !GetData() )
415 return FALSE;
bbf1f0e5 416
9e2896e5 417 return OnDropText(x, y, ((wxTextDataObject *)m_dataObject)->GetText());
bbf1f0e5
KB
418}
419
9e2896e5
VZ
420// ----------------------------------------------------------------------------
421// wxFileDropTarget
422// ----------------------------------------------------------------------------
423
424wxFileDropTarget::wxFileDropTarget()
425 : wxDropTarget(new wxFileDataObject)
bbf1f0e5 426{
bbf1f0e5
KB
427}
428
9e2896e5 429bool wxFileDropTarget::OnData(wxCoord x, wxCoord y)
bbf1f0e5 430{
9e2896e5
VZ
431 if ( !GetData() )
432 return FALSE;
433
434 return OnDropFiles(x, y,
435 ((wxFileDataObject *)m_dataObject)->GetFilenames());
bbf1f0e5
KB
436}
437
438#endif
47d67540 439 // wxUSE_DRAG_AND_DROP