Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

338 lines
8.3 KiB

  1. #include <windows.h>
  2. #include <commctrl.h>
  3. #include <shlobj.h>
  4. #include "debug.h"
  5. #include "common.h"
  6. #include "autoscrl.h"
  7. #include "nsc.h"
  8. // BUGBUG: do nothing for now
  9. #define DAD_DragLeave()
  10. #define DAD_DragEnterEx(hwndLock, pt)
  11. #define DAD_ShowDragImage(f)
  12. #define DAD_DragMove(pt)
  13. typedef struct { // tdt
  14. IDropTarget dtgt;
  15. UINT cRef;
  16. NSC *pns;
  17. RECT _rcLockWindow;
  18. HTREEITEM _htiCur; // current tree item (dragging over)
  19. IDropTarget *_pdtgtCur; // current drop target
  20. IDataObject *_pdtobjCur; // current data object
  21. DWORD _dwEffectCur; // current drag effect
  22. DWORD _dwEffectIn; // *pdwEffect passed-in on last Move/Enter
  23. DWORD _grfKeyState; // cached key state
  24. POINT _ptLast; // last dragged over position
  25. DWORD _dwLastTime;
  26. AUTO_SCROLL_DATA asd;
  27. } CTreeDropTarget;
  28. STDMETHODIMP CTreeDropTarget_QueryInterface(IDropTarget *pdtgt, REFIID riid, void **ppvObj)
  29. {
  30. CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  31. if (IsEqualIID(riid, &IID_IDropTarget) || IsEqualIID(riid, &IID_IUnknown))
  32. {
  33. *ppvObj = pdtgt;
  34. this->cRef++;
  35. return S_OK;
  36. }
  37. *ppvObj = NULL;
  38. return E_NOINTERFACE;
  39. }
  40. STDMETHODIMP_(ULONG) CTreeDropTarget_AddRef(IDropTarget *pdtgt)
  41. {
  42. CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  43. this->cRef++;
  44. return this->cRef;
  45. }
  46. void CTreeDropTarget_ReleaseDataObject(CTreeDropTarget *this)
  47. {
  48. if (this->_pdtobjCur)
  49. Release(this->_pdtobjCur);
  50. this->_pdtobjCur = NULL;
  51. }
  52. void CTreeDropTarget_ReleaseCurrentDropTarget(CTreeDropTarget *this)
  53. {
  54. if (this->_pdtgtCur)
  55. {
  56. this->_pdtgtCur->lpVtbl->DragLeave(this->_pdtgtCur);
  57. Release(this->_pdtgtCur);
  58. this->_pdtgtCur = NULL;
  59. this->_htiCur = NULL;
  60. }
  61. else
  62. {
  63. Assert(this->_htiCur == NULL);
  64. }
  65. }
  66. STDMETHODIMP_(ULONG) CTreeDropTarget_Release(IDropTarget * pdtgt)
  67. {
  68. CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  69. this->cRef--;
  70. if (this->cRef > 0)
  71. return this->cRef;
  72. AssertMsg(this->_pdtgtCur == NULL, "drag leave was not called properly");
  73. // if above is true we can remove this...
  74. CTreeDropTarget_ReleaseCurrentDropTarget(this);
  75. LocalFree(this);
  76. return 0;
  77. }
  78. STDMETHODIMP CTreeDropTarget_DragEnter(IDropTarget *pdtgt, IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  79. {
  80. CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  81. POINT pt;
  82. HWND hwndLock;
  83. DebugMsg(DM_TRACE, "sh - TR CTreeDropTarget::DragEnter called");
  84. CTreeDropTarget_ReleaseDataObject(this);
  85. this->_pdtobjCur = pdtobj;
  86. this->_grfKeyState = grfKeyState;
  87. AddRef(pdtobj);
  88. Assert(this->_pdtgtCur == NULL);
  89. Assert(this->_htiCur == NULL);
  90. hwndLock = this->pns->hwndTree; // clip to this
  91. GetWindowRect(hwndLock, &this->_rcLockWindow);
  92. pt.x = ptl.x-this->_rcLockWindow.left;
  93. pt.y = ptl.y-this->_rcLockWindow.top;
  94. DAD_DragEnterEx(hwndLock, pt);
  95. this->_ptLast.x = this->_ptLast.y = 0x7ffffff; // set bogus position
  96. return S_OK;
  97. }
  98. STDMETHODIMP CTreeDropTarget_DragOver(IDropTarget *pdtgt, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  99. {
  100. HRESULT hres = S_OK;
  101. CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  102. TV_HITTESTINFO tvht;
  103. HTREEITEM htiNew;
  104. POINT pt = { ptl.x, ptl.y };
  105. BOOL fSameImage = FALSE;
  106. DWORD dwEffectScroll = 0;
  107. ScreenToClient(this->pns->hwndTree, &pt);
  108. if (DAD_AutoScroll(this->pns->hwndTree, &this->asd, &pt))
  109. dwEffectScroll = DROPEFFECT_SCROLL;
  110. tvht.pt = pt;
  111. htiNew = TreeView_HitTest(this->pns->hwndTree, &tvht);
  112. // don't allow droping on the item being dragged
  113. if (htiNew == this->pns->htiDragging)
  114. htiNew = NULL;
  115. if (this->_htiCur != htiNew)
  116. {
  117. // change in target
  118. this->_dwLastTime = GetTickCount(); // keep track for auto-expanding the tree
  119. CTreeDropTarget_ReleaseCurrentDropTarget(this);
  120. this->_dwEffectCur = 0; // assume error
  121. DAD_ShowDragImage(FALSE);
  122. TreeView_SelectDropTarget(this->pns->hwndTree, htiNew);
  123. DAD_ShowDragImage(TRUE);
  124. if (htiNew)
  125. {
  126. // get the drop target for the item we hit
  127. LPITEMIDLIST pidl = _CacheParentShellFolder(this->pns, htiNew, NULL);
  128. if (pidl)
  129. {
  130. IShellFolder *psf = this->pns->psfCache;
  131. AddRef(psf);
  132. if (pidl->mkid.cb == 0)
  133. {
  134. hres = psf->lpVtbl->CreateViewObject(psf, this->pns->hwnd, &IID_IDropTarget, &this->_pdtgtCur);
  135. }
  136. else
  137. {
  138. UINT dwAttr = SFGAO_DROPTARGET;
  139. hres = psf->lpVtbl->GetAttributesOf(psf, 1, &pidl, &dwAttr);
  140. if (SUCCEEDED(hres) && (dwAttr & SFGAO_DROPTARGET))
  141. {
  142. hres = psf->lpVtbl->GetUIObjectOf(psf, this->pns->hwnd, 1, &pidl, &IID_IDropTarget, NULL, &this->_pdtgtCur);
  143. }
  144. else
  145. {
  146. hres = E_INVALIDARG;
  147. }
  148. }
  149. Release(psf);
  150. }
  151. if (SUCCEEDED(hres))
  152. {
  153. this->_htiCur = htiNew;
  154. this->_dwEffectCur = *pdwEffect; // pdwEffect is In/Out
  155. hres = this->_pdtgtCur->lpVtbl->DragEnter(this->_pdtgtCur, this->_pdtobjCur, grfKeyState, ptl, &this->_dwEffectCur);
  156. }
  157. }
  158. }
  159. else
  160. {
  161. // No target change
  162. // auto expand the tree
  163. if (this->_htiCur)
  164. {
  165. DWORD dwNow = GetTickCount();
  166. if ((dwNow - this->_dwLastTime) >= 1000)
  167. {
  168. this->_dwLastTime = dwNow;
  169. DAD_ShowDragImage(FALSE);
  170. this->pns->fAutoExpanding = TRUE;
  171. TreeView_Expand(this->pns->hwndTree, this->_htiCur, TVE_EXPAND);
  172. this->pns->fAutoExpanding = FALSE;
  173. DAD_ShowDragImage(TRUE);
  174. }
  175. }
  176. // maybe the key state changed
  177. if ((this->_grfKeyState != grfKeyState) && this->_pdtgtCur)
  178. {
  179. this->_dwEffectCur = *pdwEffect;
  180. hres = this->_pdtgtCur->lpVtbl->DragOver(this->_pdtgtCur, grfKeyState, ptl, &this->_dwEffectCur);
  181. }
  182. else
  183. {
  184. fSameImage = TRUE;
  185. hres = S_OK;
  186. }
  187. }
  188. DebugMsg(DM_TRACE, "sh TR - CTreeDropTarget_DragOver (In=%x, Out=%x)", *pdwEffect, this->_dwEffectCur);
  189. this->_grfKeyState = grfKeyState;
  190. *pdwEffect = this->_dwEffectCur | dwEffectScroll;
  191. // We need pass pt relative to the locked window (not the client).
  192. pt.x = ptl.x-this->_rcLockWindow.left;
  193. pt.y = ptl.y-this->_rcLockWindow.top;
  194. if (!(fSameImage && this->_ptLast.x == pt.x && this->_ptLast.y == pt.y))
  195. {
  196. DAD_DragMove(pt);
  197. this->_ptLast.x = pt.x;
  198. this->_ptLast.y = pt.y;
  199. }
  200. return hres;
  201. }
  202. STDMETHODIMP CTreeDropTarget_DragLeave(IDropTarget *pdtgt)
  203. {
  204. CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  205. DebugMsg(DM_TRACE, "sh - TR CTreeDropTarget::DragLeave called");
  206. CTreeDropTarget_ReleaseCurrentDropTarget(this);
  207. CTreeDropTarget_ReleaseDataObject(this);
  208. DAD_DragLeave();
  209. TreeView_SelectDropTarget(this->pns->hwndTree, NULL);
  210. return S_OK;
  211. }
  212. STDMETHODIMP CTreeDropTarget_Drop(IDropTarget *pdtgt, IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  213. {
  214. HRESULT hres;
  215. CTreeDropTarget * this = IToClass(CTreeDropTarget, dtgt, pdtgt);
  216. if (this->_pdtgtCur)
  217. {
  218. hres = this->_pdtgtCur->lpVtbl->Drop(this->_pdtgtCur, pdtobj, grfKeyState, pt, pdwEffect);
  219. }
  220. else
  221. {
  222. DebugMsg(DM_TRACE, "sh TR - CTreeDropTarget::Drop - this->_pdtgtCur==NULL");
  223. *pdwEffect = 0;
  224. hres = S_OK;
  225. }
  226. CTreeDropTarget_DragLeave(pdtgt);
  227. return hres;
  228. }
  229. const IDropTargetVtbl c_CTreeDropTargetVtbl = {
  230. CTreeDropTarget_QueryInterface, CTreeDropTarget_AddRef, CTreeDropTarget_Release,
  231. CTreeDropTarget_DragEnter,
  232. CTreeDropTarget_DragOver,
  233. CTreeDropTarget_DragLeave,
  234. CTreeDropTarget_Drop
  235. };
  236. HRESULT CTreeDropTarget_Create(NSC *pns, IDropTarget **ppdtgt)
  237. {
  238. CTreeDropTarget * this = LocalAlloc(LPTR, sizeof(CTreeDropTarget));
  239. if (this)
  240. {
  241. this->dtgt.lpVtbl = (IDropTargetVtbl *)&c_CTreeDropTargetVtbl;
  242. this->cRef = 1;
  243. this->pns = pns;
  244. *ppdtgt = &this->dtgt;
  245. return S_OK;
  246. }
  247. *ppdtgt = NULL;
  248. return E_OUTOFMEMORY;
  249. }
  250. void CTreeDropTarget_Register(NSC *pns)
  251. {
  252. IDropTarget *pdtgt;
  253. if (SUCCEEDED(CTreeDropTarget_Create(pns, &pdtgt)))
  254. {
  255. RegisterDragDrop(pns->hwndTree, pdtgt);
  256. Release(pdtgt);
  257. }
  258. }
  259. void CTreeDropTarget_Revoke(NSC *pns)
  260. {
  261. RevokeDragDrop(pns->hwndTree);
  262. }