Fixed issue #1351: Add Hotkey to deselect all files on commit
[TortoiseGit.git] / src / Utils / DragDropImpl.cpp
blob51261893b7d0e3d591dc3cb96cd16b3115bdf882
1 /**************************************************************************
2 THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF
3 ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
4 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
5 PARTICULAR PURPOSE.
6 Author: Leon Finker 1/2001
7 **************************************************************************/
8 // IDataObjectImpl.cpp: implementation of the CIDataObjectImpl class.
9 //////////////////////////////////////////////////////////////////////
10 #include <stdafx.h>
11 #include <shlobj.h>
12 #include <atlbase.h>
13 #include "DragDropImpl.h"
15 //////////////////////////////////////////////////////////////////////
16 // CIDataObject Class
17 //////////////////////////////////////////////////////////////////////
19 CIDataObject::CIDataObject(CIDropSource* pDropSource):
20 m_cRefCount(0), m_pDropSource(pDropSource)
24 CIDataObject::~CIDataObject()
26 for(int i = 0; i < m_StgMedium.GetSize(); ++i)
28 ReleaseStgMedium(m_StgMedium[i]);
29 delete m_StgMedium[i];
31 for(int j = 0; j < m_ArrFormatEtc.GetSize(); ++j)
32 delete m_ArrFormatEtc[j];
35 STDMETHODIMP CIDataObject::QueryInterface(/* [in] */ REFIID riid,
36 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
38 *ppvObject = NULL;
39 if (IID_IUnknown==riid || IID_IDataObject==riid)
40 *ppvObject=this;
41 /*if(riid == IID_IAsyncOperation)
42 *ppvObject=(IAsyncOperation*)this;*/
43 if (NULL!=*ppvObject)
45 ((LPUNKNOWN)*ppvObject)->AddRef();
46 return S_OK;
48 return E_NOINTERFACE;
51 STDMETHODIMP_(ULONG) CIDataObject::AddRef( void)
53 return ++m_cRefCount;
56 STDMETHODIMP_(ULONG) CIDataObject::Release( void)
58 long nTemp;
59 nTemp = --m_cRefCount;
60 if(nTemp==0)
61 delete this;
62 return nTemp;
65 STDMETHODIMP CIDataObject::GetData(
66 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetcIn,
67 /* [out] */ STGMEDIUM __RPC_FAR *pmedium)
69 if(pformatetcIn == NULL || pmedium == NULL)
70 return E_INVALIDARG;
71 pmedium->hGlobal = NULL;
73 ATLASSERT(m_StgMedium.GetSize() == m_ArrFormatEtc.GetSize());
74 for(int i=0; i < m_ArrFormatEtc.GetSize(); ++i)
76 if(pformatetcIn->tymed & m_ArrFormatEtc[i]->tymed &&
77 pformatetcIn->dwAspect == m_ArrFormatEtc[i]->dwAspect &&
78 pformatetcIn->cfFormat == m_ArrFormatEtc[i]->cfFormat)
80 CopyMedium(pmedium, m_StgMedium[i], m_ArrFormatEtc[i]);
81 return S_OK;
84 return DV_E_FORMATETC;
87 STDMETHODIMP CIDataObject::GetDataHere(
88 /* [unique][in] */ FORMATETC __RPC_FAR * /*pformatetc*/,
89 /* [out][in] */ STGMEDIUM __RPC_FAR * /*pmedium*/)
91 return E_NOTIMPL;
94 STDMETHODIMP CIDataObject::QueryGetData(
95 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc)
97 if(pformatetc == NULL)
98 return E_INVALIDARG;
100 //support others if needed DVASPECT_THUMBNAIL //DVASPECT_ICON //DVASPECT_DOCPRINT
101 if (!(DVASPECT_CONTENT & pformatetc->dwAspect))
102 return (DV_E_DVASPECT);
103 HRESULT hr = DV_E_TYMED;
104 for(int i = 0; i < m_ArrFormatEtc.GetSize(); ++i)
106 if(pformatetc->tymed & m_ArrFormatEtc[i]->tymed)
108 if(pformatetc->cfFormat == m_ArrFormatEtc[i]->cfFormat)
109 return S_OK;
110 else
111 hr = DV_E_CLIPFORMAT;
113 else
114 hr = DV_E_TYMED;
116 return hr;
119 STDMETHODIMP CIDataObject::GetCanonicalFormatEtc(
120 /* [unique][in] */ FORMATETC __RPC_FAR * /*pformatectIn*/,
121 /* [out] */ FORMATETC __RPC_FAR *pformatetcOut)
123 if (pformatetcOut == NULL)
124 return E_INVALIDARG;
125 return DATA_S_SAMEFORMATETC;
128 STDMETHODIMP CIDataObject::SetData(
129 /* [unique][in] */ FORMATETC __RPC_FAR *pformatetc,
130 /* [unique][in] */ STGMEDIUM __RPC_FAR *pmedium,
131 /* [in] */ BOOL fRelease)
133 if(pformatetc == NULL || pmedium == NULL)
134 return E_INVALIDARG;
136 ATLASSERT(pformatetc->tymed == pmedium->tymed);
137 FORMATETC* fetc=new FORMATETC;
138 STGMEDIUM* pStgMed = new STGMEDIUM;
140 if(fetc == NULL || pStgMed == NULL)
141 return E_OUTOFMEMORY;
143 SecureZeroMemory(fetc,sizeof(FORMATETC));
144 SecureZeroMemory(pStgMed,sizeof(STGMEDIUM));
146 *fetc = *pformatetc;
147 m_ArrFormatEtc.Add(fetc);
149 if(fRelease)
150 *pStgMed = *pmedium;
151 else
153 CopyMedium(pStgMed, pmedium, pformatetc);
155 m_StgMedium.Add(pStgMed);
157 return S_OK;
159 void CIDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
161 switch(pMedSrc->tymed)
163 case TYMED_HGLOBAL:
164 pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal,pFmtSrc->cfFormat, NULL);
165 break;
166 case TYMED_GDI:
167 pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap,pFmtSrc->cfFormat, NULL);
168 break;
169 case TYMED_MFPICT:
170 pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict,pFmtSrc->cfFormat, NULL);
171 break;
172 case TYMED_ENHMF:
173 pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile,pFmtSrc->cfFormat, NULL);
174 break;
175 case TYMED_FILE:
176 pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName,pFmtSrc->cfFormat, NULL);
177 break;
178 case TYMED_ISTREAM:
179 pMedDest->pstm = pMedSrc->pstm;
180 pMedSrc->pstm->AddRef();
181 break;
182 case TYMED_ISTORAGE:
183 pMedDest->pstg = pMedSrc->pstg;
184 pMedSrc->pstg->AddRef();
185 break;
186 case TYMED_NULL:
187 default:
188 break;
190 pMedDest->tymed = pMedSrc->tymed;
191 pMedDest->pUnkForRelease = NULL;
192 if(pMedSrc->pUnkForRelease != NULL)
194 pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;
195 pMedSrc->pUnkForRelease->AddRef();
198 STDMETHODIMP CIDataObject::EnumFormatEtc(
199 /* [in] */ DWORD dwDirection,
200 /* [out] */ IEnumFORMATETC __RPC_FAR *__RPC_FAR *ppenumFormatEtc)
202 if(ppenumFormatEtc == NULL)
203 return E_POINTER;
205 *ppenumFormatEtc=NULL;
206 switch (dwDirection)
208 case DATADIR_GET:
209 *ppenumFormatEtc= new CEnumFormatEtc(m_ArrFormatEtc);
210 if(*ppenumFormatEtc == NULL)
211 return E_OUTOFMEMORY;
212 (*ppenumFormatEtc)->AddRef();
213 break;
215 case DATADIR_SET:
216 default:
217 return E_NOTIMPL;
218 break;
221 return S_OK;
224 STDMETHODIMP CIDataObject::DAdvise(
225 /* [in] */ FORMATETC __RPC_FAR * /*pformatetc*/,
226 /* [in] */ DWORD /*advf*/,
227 /* [unique][in] */ IAdviseSink __RPC_FAR * /*pAdvSink*/,
228 /* [out] */ DWORD __RPC_FAR * /*pdwConnection*/)
230 return OLE_E_ADVISENOTSUPPORTED;
233 STDMETHODIMP CIDataObject::DUnadvise(
234 /* [in] */ DWORD /*dwConnection*/)
236 return E_NOTIMPL;
239 HRESULT STDMETHODCALLTYPE CIDataObject::EnumDAdvise(
240 /* [out] */ IEnumSTATDATA __RPC_FAR *__RPC_FAR * /*ppenumAdvise*/)
242 return OLE_E_ADVISENOTSUPPORTED;
245 //////////////////////////////////////////////////////////////////////
246 // CIDropSource Class
247 //////////////////////////////////////////////////////////////////////
249 STDMETHODIMP CIDropSource::QueryInterface(/* [in] */ REFIID riid,
250 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
252 *ppvObject = NULL;
253 if (IID_IUnknown==riid || IID_IDropSource==riid)
254 *ppvObject=this;
256 if (*ppvObject != NULL)
258 ((LPUNKNOWN)*ppvObject)->AddRef();
259 return S_OK;
261 return E_NOINTERFACE;
264 STDMETHODIMP_(ULONG) CIDropSource::AddRef( void)
266 return ++m_cRefCount;
269 STDMETHODIMP_(ULONG) CIDropSource::Release( void)
271 long nTemp;
272 nTemp = --m_cRefCount;
273 ATLASSERT(nTemp >= 0);
274 if(nTemp==0)
275 delete this;
276 return nTemp;
279 STDMETHODIMP CIDropSource::QueryContinueDrag(
280 /* [in] */ BOOL fEscapePressed,
281 /* [in] */ DWORD grfKeyState)
283 if(fEscapePressed)
284 return DRAGDROP_S_CANCEL;
285 if(!(grfKeyState & (MK_LBUTTON|MK_RBUTTON)))
287 m_bDropped = true;
288 return DRAGDROP_S_DROP;
291 return S_OK;
295 STDMETHODIMP CIDropSource::GiveFeedback(
296 /* [in] */ DWORD /*dwEffect*/)
298 return DRAGDROP_S_USEDEFAULTCURSORS;
301 //////////////////////////////////////////////////////////////////////
302 // CEnumFormatEtc Class
303 //////////////////////////////////////////////////////////////////////
305 CEnumFormatEtc::CEnumFormatEtc(const CSimpleArray<FORMATETC>& ArrFE):
306 m_cRefCount(0),m_iCur(0)
308 ATLTRACE("CEnumFormatEtc::CEnumFormatEtc()\n");
309 for(int i = 0; i < ArrFE.GetSize(); ++i)
310 m_pFmtEtc.Add(ArrFE[i]);
313 CEnumFormatEtc::CEnumFormatEtc(const CSimpleArray<FORMATETC*>& ArrFE):
314 m_cRefCount(0),m_iCur(0)
316 for(int i = 0; i < ArrFE.GetSize(); ++i)
317 m_pFmtEtc.Add(*ArrFE[i]);
320 STDMETHODIMP CEnumFormatEtc::QueryInterface(REFIID refiid, void FAR* FAR* ppv)
322 *ppv = NULL;
323 if (IID_IUnknown==refiid || IID_IEnumFORMATETC==refiid)
324 *ppv=this;
326 if (*ppv != NULL)
328 ((LPUNKNOWN)*ppv)->AddRef();
329 return S_OK;
331 return E_NOINTERFACE;
334 STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef(void)
336 return ++m_cRefCount;
339 STDMETHODIMP_(ULONG) CEnumFormatEtc::Release(void)
341 long nTemp = --m_cRefCount;
342 ATLASSERT(nTemp >= 0);
343 if(nTemp == 0)
344 delete this;
346 return nTemp;
349 STDMETHODIMP CEnumFormatEtc::Next( ULONG celt,LPFORMATETC lpFormatEtc, ULONG FAR *pceltFetched)
351 if(pceltFetched != NULL)
352 *pceltFetched=0;
354 ULONG cReturn = celt;
356 if(celt <= 0 || lpFormatEtc == NULL || m_iCur >= m_pFmtEtc.GetSize())
357 return S_FALSE;
359 if(pceltFetched == NULL && celt != 1) // pceltFetched can be NULL only for 1 item request
360 return S_FALSE;
362 while (m_iCur < m_pFmtEtc.GetSize() && cReturn > 0)
364 *lpFormatEtc++ = m_pFmtEtc[m_iCur++];
365 --cReturn;
367 if (pceltFetched != NULL)
368 *pceltFetched = celt - cReturn;
370 return (cReturn == 0) ? S_OK : S_FALSE;
373 STDMETHODIMP CEnumFormatEtc::Skip(ULONG celt)
375 if((m_iCur + int(celt)) >= m_pFmtEtc.GetSize())
376 return S_FALSE;
377 m_iCur += celt;
378 return S_OK;
381 STDMETHODIMP CEnumFormatEtc::Reset(void)
383 m_iCur = 0;
384 return S_OK;
387 STDMETHODIMP CEnumFormatEtc::Clone(IEnumFORMATETC FAR * FAR*ppCloneEnumFormatEtc)
389 if(ppCloneEnumFormatEtc == NULL)
390 return E_POINTER;
392 CEnumFormatEtc *newEnum = new CEnumFormatEtc(m_pFmtEtc);
393 if(newEnum ==NULL)
394 return E_OUTOFMEMORY;
395 newEnum->AddRef();
396 newEnum->m_iCur = m_iCur;
397 *ppCloneEnumFormatEtc = newEnum;
398 return S_OK;
401 //////////////////////////////////////////////////////////////////////
402 // CIDropTarget Class
403 //////////////////////////////////////////////////////////////////////
404 CIDropTarget::CIDropTarget(HWND hTargetWnd):
405 m_hTargetWnd(hTargetWnd),
406 m_cRefCount(0), m_bAllowDrop(false),
407 m_pDropTargetHelper(NULL), m_pSupportedFrmt(NULL)
409 if(FAILED(CoCreateInstance(CLSID_DragDropHelper,NULL,CLSCTX_INPROC_SERVER,
410 IID_IDropTargetHelper,(LPVOID*)&m_pDropTargetHelper)))
411 m_pDropTargetHelper = NULL;
414 CIDropTarget::~CIDropTarget()
416 if(m_pDropTargetHelper != NULL)
418 m_pDropTargetHelper->Release();
419 m_pDropTargetHelper = NULL;
423 HRESULT STDMETHODCALLTYPE CIDropTarget::QueryInterface( /* [in] */ REFIID riid,
424 /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
426 *ppvObject = NULL;
427 if (IID_IUnknown==riid || IID_IDropTarget==riid)
428 *ppvObject=this;
430 if (*ppvObject != NULL)
432 ((LPUNKNOWN)*ppvObject)->AddRef();
433 return S_OK;
435 return E_NOINTERFACE;
438 ULONG STDMETHODCALLTYPE CIDropTarget::Release( void)
440 long nTemp;
441 nTemp = --m_cRefCount;
442 ATLASSERT(nTemp >= 0);
443 if(nTemp==0)
444 delete this;
445 return nTemp;
448 bool CIDropTarget::QueryDrop(DWORD grfKeyState, LPDWORD pdwEffect)
450 DWORD dwOKEffects = *pdwEffect;
452 if(!m_bAllowDrop)
454 *pdwEffect = DROPEFFECT_NONE;
455 return false;
457 //CTRL+SHIFT -- DROPEFFECT_LINK
458 //CTRL -- DROPEFFECT_COPY
459 //SHIFT -- DROPEFFECT_MOVE
460 //no modifier -- DROPEFFECT_MOVE or whatever is allowed by src
461 *pdwEffect = (grfKeyState & MK_CONTROL) ?
462 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY ):
463 ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : 0 );
464 if(*pdwEffect == 0)
466 // No modifier keys used by user while dragging.
467 if (DROPEFFECT_MOVE & dwOKEffects)
468 *pdwEffect = DROPEFFECT_MOVE;
469 else if (DROPEFFECT_COPY & dwOKEffects)
470 *pdwEffect = DROPEFFECT_COPY;
471 else if (DROPEFFECT_LINK & dwOKEffects)
472 *pdwEffect = DROPEFFECT_LINK;
473 else
475 *pdwEffect = DROPEFFECT_NONE;
478 else
480 // Check if the drag source application allows the drop effect desired by user.
481 // The drag source specifies this in DoDragDrop
482 if(!(*pdwEffect & dwOKEffects))
483 *pdwEffect = DROPEFFECT_NONE;
486 return (DROPEFFECT_NONE == *pdwEffect)?false:true;
489 HRESULT STDMETHODCALLTYPE CIDropTarget::DragEnter(
490 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
491 /* [in] */ DWORD grfKeyState,
492 /* [in] */ POINTL pt,
493 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
495 if(pDataObj == NULL)
496 return E_INVALIDARG;
498 if(m_pDropTargetHelper)
499 m_pDropTargetHelper->DragEnter(m_hTargetWnd, pDataObj, (LPPOINT)&pt, *pdwEffect);
500 //IEnumFORMATETC* pEnum;
501 //pDataObj->EnumFormatEtc(DATADIR_GET,&pEnum);
502 //FORMATETC ftm;
503 //for()
504 //pEnum->Next(1,&ftm,0);
505 //pEnum->Release();
506 m_pSupportedFrmt = NULL;
507 for(int i =0; i<m_formatetc.GetSize(); ++i)
509 m_bAllowDrop = (pDataObj->QueryGetData(&m_formatetc[i]) == S_OK)?true:false;
510 if(m_bAllowDrop)
512 m_pSupportedFrmt = &m_formatetc[i];
513 break;
517 QueryDrop(grfKeyState, pdwEffect);
518 return S_OK;
521 HRESULT STDMETHODCALLTYPE CIDropTarget::DragOver(
522 /* [in] */ DWORD grfKeyState,
523 /* [in] */ POINTL pt,
524 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
526 if(m_pDropTargetHelper)
527 m_pDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect);
528 QueryDrop(grfKeyState, pdwEffect);
529 return S_OK;
532 HRESULT STDMETHODCALLTYPE CIDropTarget::DragLeave( void)
534 if(m_pDropTargetHelper)
535 m_pDropTargetHelper->DragLeave();
537 m_bAllowDrop = false;
538 m_pSupportedFrmt = NULL;
539 return S_OK;
542 HRESULT STDMETHODCALLTYPE CIDropTarget::Drop(
543 /* [unique][in] */ IDataObject __RPC_FAR *pDataObj,
544 /* [in] */ DWORD grfKeyState, /* [in] */ POINTL pt,
545 /* [out][in] */ DWORD __RPC_FAR *pdwEffect)
547 if (pDataObj == NULL)
548 return E_INVALIDARG;
550 if(m_pDropTargetHelper)
551 m_pDropTargetHelper->Drop(pDataObj, (LPPOINT)&pt, *pdwEffect);
553 if(QueryDrop(grfKeyState, pdwEffect))
555 if(m_bAllowDrop && m_pSupportedFrmt != NULL)
557 STGMEDIUM medium;
558 if(pDataObj->GetData(m_pSupportedFrmt, &medium) == S_OK)
560 if(OnDrop(m_pSupportedFrmt, medium, pdwEffect, pt)) //does derive class wants us to free medium?
561 ReleaseStgMedium(&medium);
565 m_bAllowDrop=false;
566 *pdwEffect = DROPEFFECT_NONE;
567 m_pSupportedFrmt = NULL;
568 return S_OK;
571 //////////////////////////////////////////////////////////////////////
572 // CIDragSourceHelper Class
573 //////////////////////////////////////////////////////////////////////