update for HEAD-2003091401
[reactos.git] / subsys / system / explorer / Seashell / SeaShellExt / UIDragDropTree.cpp
1 //*******************************************************************************
2 // COPYRIGHT NOTES
3 // ---------------
4 // You may use this source code, compile or redistribute it as part of your application 
5 // for free. You cannot redistribute it as a part of a software development 
6 // library without the agreement of the author. If the sources are 
7 // distributed along with the application, you should leave the original 
8 // copyright notes in the source code without any changes.
9 // This code can be used WITHOUT ANY WARRANTIES at your own risk.
10 // 
11 // For the latest updates to this code, check this site:
12 // http://www.masmex.com 
13 // after Sept 2000
14 // 
15 // Copyright(C) 2000 Philip Oldaker <email: philip@masmex.com>
16 //*******************************************************************************
17
18 //////////////////////////////////////////////////////////////////////////////////////--*/
19 // UIDragDropTree.cpp : implementation file
20 //
21
22 #include "stdafx.h"
23 #include "UICtrl.h"
24 #include "UIDragDropTree.h"
25 #include "cbformats.h"
26 #include "UIRes.h"
27
28 #ifdef _DEBUG
29 #define new DEBUG_NEW
30 #undef THIS_FILE
31 static char THIS_FILE[] = __FILE__;
32 #endif
33
34 IMPLEMENT_DYNAMIC(CUIDragDropTree,CTreeCtrl)
35 /////////////////////////////////////////////////
36 //
37 // For OLE drag and drop 
38 //
39 /////////////////////////////////////////////////
40 void CUI_TreeDropTarget::OnDragLeave(CWnd* pWnd)
41 {
42         CUIDragDropTree *pTree = static_cast<CUIDragDropTree*>(pWnd);
43         if (pTree == NULL)
44                 return;
45         pTree->KillDragTimer();
46         pTree->SelectDropTarget(NULL);
47         CDD_OleDropTargetInfo Info(pWnd->GetSafeHwnd());
48         Info.SetItem(pTree->GetDropHilightItem());
49         BOOL bRet = pTree->SendMessage(WM_APP_OLE_DD_LEAVE,(WPARAM)&Info);
50         if (bRet == FALSE)
51                 bRet = pTree->GetParent()->SendMessage(WM_APP_OLE_DD_LEAVE,(WPARAM)&Info);      
52 }
53
54 DROPEFFECT CUI_TreeDropTarget::OnDragEnter( CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point )
55 {
56 //      ASSERT_KINDOF(CUIDragDropTree,pWnd);
57         CUIDragDropTree *pTree = static_cast<CUIDragDropTree*>(pWnd);
58         if (pTree == NULL)
59                 return DROPEFFECT_NONE;
60         ((CUIDragDropTree*)pWnd)->SetDragTimer();
61         CDD_OleDropTargetInfo Info(pWnd->GetSafeHwnd(),point,pDataObject);
62         m_dwEnterKeyboardState = dwKeyState;
63         Info.SetKeyboardState(dwKeyState);
64         Info.SetItem(pTree->GetDropHilightItem());
65         BOOL bRet = pTree->SendMessage(WM_APP_OLE_DD_ENTER,(WPARAM)&Info);
66         if (bRet == FALSE)
67                 bRet = pTree->GetParent()->SendMessage(WM_APP_OLE_DD_ENTER,(WPARAM)&Info);
68         return Info.GetDropEffect();
69 }
70
71 DROPEFFECT CUI_TreeDropTarget::OnDragOver( CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point )
72 {
73         // disallow if the control key pressed
74         EraseOldImage();
75         CUIDragDropTree *pTree = static_cast<CUIDragDropTree*>(pWnd);
76         if (pTree == NULL)
77                 return DROPEFFECT_NONE;
78 //      ASSERT_KINDOF(CUIDragDropTree,pWnd);
79         CDD_OleDropTargetInfo Info(pWnd->GetSafeHwnd(),point,pDataObject);
80         m_dwKeyboardState = dwKeyState;
81         Info.SetKeyboardState(dwKeyState);
82         // WM_APP_OLE_DD_OVER message sent in SelectCurrentTarget
83         DROPEFFECT dropEffect = pTree->SelectCurrentTarget(&Info);
84         CUI_ImageDropTarget::OnDragOver(pWnd,pDataObject,dwKeyState,point);
85         return dropEffect;
86 }
87
88 BOOL CUI_TreeDropTarget::OnDrop( CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point )
89 {
90         CUIDragDropTree *pTree = static_cast<CUIDragDropTree*>(pWnd);
91         if (pTree == NULL)
92                 return FALSE;
93 //      ASSERT_KINDOF(CUIDragDropTree,pWnd);
94         pTree->KillDragTimer();
95         HTREEITEM hItem = pTree->GetDropHilightItem();
96         BOOL bRet=FALSE;
97         if (hItem) 
98         {
99                 CDD_OleDropTargetInfo Info(pWnd->GetSafeHwnd(),point,pDataObject);
100                 Info.SetDropEffect(dropEffect);
101                 Info.SetItem(hItem);
102         if (m_dwEnterKeyboardState & MK_RBUTTON)
103                         m_dwKeyboardState |= MK_RBUTTON;
104         if (m_dwEnterKeyboardState & MK_LBUTTON)
105                         m_dwKeyboardState |= MK_LBUTTON;
106                 Info.SetKeyboardState(m_dwKeyboardState);
107                 bRet = pTree->SendMessage(WM_APP_OLE_DD_DROP,(WPARAM)&Info);
108                 if (bRet == FALSE)
109                         bRet = pTree->GetParent()->SendMessage(WM_APP_OLE_DD_DROP,(WPARAM)&Info);
110         }
111         pTree->SelectDropTarget(NULL);
112         return bRet;
113 }
114
115 // During slow scroll, process every third message.
116 #define SLOWSCROLL_FREQUENCY 3
117 /////////////////////////////////////////////////////////////////////////////
118 // CUIDragDropTree
119
120 CUIDragDropTree::CUIDragDropTree(bool bDragDrop): m_nUpperYCoor(0), 
121                                                                 m_nLowerYCoor(0), 
122                                                                 m_nSlowScrollTimeout(0),
123                                                                 m_nTimerID(0),
124                                                                 m_bDragging(FALSE),
125                                                                 m_pImageList(NULL),
126                                                                 m_hitemDrag(NULL),
127                                                                 m_hitemDrop(NULL),
128                                                                 m_bDragDrop(bDragDrop),
129                                                                 m_bDropFiles(true)
130
131 {
132         m_nScrollBarSize = GetSystemMetrics( SM_CYHSCROLL );
133         m_CopyMode = eDDCancel;
134 }
135
136 CUIDragDropTree::~CUIDragDropTree()
137 {
138 }
139
140 void CUIDragDropTree::OnDropFile(HTREEITEM hItem,LPCTSTR pszFile,UINT nFlags)
141 {
142 }
143
144 BEGIN_MESSAGE_MAP(CUIDragDropTree, CTreeCtrl)
145         //{{AFX_MSG_MAP(CUIDragDropTree)
146         ON_NOTIFY_REFLECT_EX(TVN_BEGINDRAG, OnBegindrag)
147         ON_NOTIFY_REFLECT_EX(TVN_BEGINRDRAG, OnBeginRDrag)
148         ON_WM_TIMER()
149         ON_WM_RBUTTONUP()
150         ON_WM_MOUSEMOVE()
151         ON_WM_DESTROY()
152         ON_WM_CREATE()
153         ON_WM_DROPFILES()
154         //}}AFX_MSG_MAP
155 END_MESSAGE_MAP()
156
157 /////////////////////////////////////////////////////////////////////////////
158 // CUIDragDropTree message handlers
159 void CUIDragDropTree::OnDropFiles(HDROP hDropInfo)
160 {
161         UINT wNumFilesDropped = DragQueryFile(hDropInfo, 0XFFFFFFFF, NULL, 0);
162         TCHAR szFile[MAX_PATH];
163         UINT nLen;
164         UINT nFlags;
165         POINT pt;
166         ::DragQueryPoint(hDropInfo,&pt);
167         HTREEITEM hitemDrag = HitTest(CPoint(pt), &nFlags);
168         for(UINT i=0; i < wNumFilesDropped;i++)
169         {
170                 nLen = DragQueryFile(hDropInfo,i,szFile,sizeof(szFile)/sizeof(TCHAR));
171                 if (nLen)
172                         OnDropFile(hitemDrag,szFile,nFlags);
173         }
174 }
175
176 BOOL CUIDragDropTree::OnBeginRDrag(NMHDR* pNMHDR, LRESULT* pResult) 
177 {
178         NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
179         return StartDragDrop(pNMTreeView);
180 }
181
182 BOOL CUIDragDropTree::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult) 
183 {
184         NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
185         return StartDragDrop(pNMTreeView);
186 }
187
188 BOOL CUIDragDropTree::StartDragDrop(NM_TREEVIEW* pNMTreeView)
189 {
190         if (GetDragDrop() == false || pNMTreeView->itemNew.hItem == GetRootItem())
191                 return FALSE;
192         // See if COM drag drop is implemented in this window or parent window
193         DWORD dwDragEffect = SendMessage(WM_APP_OLE_DD_DODRAGDROP,(WPARAM)pNMTreeView,(LPARAM)&m_OleDataSource);
194         if (dwDragEffect == 0)
195                 dwDragEffect = GetParent()->SendMessage(WM_APP_OLE_DD_DODRAGDROP,(WPARAM)pNMTreeView,(LPARAM)&m_OleDataSource);
196         if (dwDragEffect)
197         {
198                 CRect rcDrag; 
199                 m_hitemDrag = pNMTreeView->itemNew.hItem;
200                 // Define starting rect
201                 GetItemRect(pNMTreeView->itemNew.hItem,rcDrag,TRUE);
202                 // Start the DragDrop
203                 DWORD dwEffect = m_OleDataSource.DoDragDrop(dwDragEffect,rcDrag);
204                 // Clear the cache
205                 m_OleDataSource.Empty();        
206         }
207         else // otherwise start local drag drop
208         {
209                 CPoint          ptAction;
210                 UINT            nFlags;
211
212                 GetCursorPos(&ptAction);
213                 ScreenToClient(&ptAction);
214                 
215                 m_bDragging = TRUE;
216                 m_hitemDrag = HitTest(pNMTreeView->ptDrag, &nFlags);
217                 m_hitemDrop = NULL;
218
219                 // Create drag image and begin dragging
220                 m_pImageList = CreateDragImage(m_hitemDrag);  
221                 m_pImageList->BeginDrag(0, CPoint(0,0));
222                 m_pImageList->DragEnter(GetDesktopWindow(), ptAction);
223                 SetCapture();
224
225                 SetDragTimer();
226         }
227         return TRUE;
228 }
229
230 void CUIDragDropTree::SetDragTimer()
231 {
232         // Set the timer to slow down the scrolling when the dragging cursor
233         // is close to the top/bottom border of the tree control
234         if (!m_nTimerID) 
235         {
236                 m_nTimerID = SetTimer(1, 75, NULL);
237                 CRect rect;
238                 GetClientRect(&rect);
239                 ClientToScreen(&rect);
240                 m_nUpperYCoor = rect.top;
241                 m_nLowerYCoor = rect.bottom;
242         }
243 }
244
245 void CUIDragDropTree::KillDragTimer()
246 {
247         if (m_nTimerID)
248         {
249                 KillTimer(m_nTimerID);
250         }
251         m_nTimerID = 0;
252         m_nUpperYCoor = 0;
253         m_nLowerYCoor = 0;
254         m_nSlowScrollTimeout = 0;
255 }
256
257 void CUIDragDropTree::OnTimer(UINT nIDEvent) 
258 {
259         // TODO: Add your message handler code here and/or call default
260         if (nIDEvent != m_nTimerID)
261         {
262                 CTreeCtrl::OnTimer(nIDEvent);
263                 return;
264         }
265         
266         // Get the "current" mouse position
267         const MSG* pMessage;
268         CPoint ptMouse;
269         pMessage = GetCurrentMessage();
270         ASSERT(pMessage);
271         ptMouse = pMessage->pt;
272
273         // Move the ghost image
274         if (m_pImageList)
275                 m_pImageList->DragMove(ptMouse);
276
277         // Find out if scrolling is needed.
278         // Scrolling is not needed for example, if the dragging cursor is 
279         // within the tree control itself
280         if(!NeedToScroll(ptMouse))
281         {
282                 CTreeCtrl::OnTimer(nIDEvent);
283                 return;
284         }
285         if (!m_bDragging)
286                 m_OleDropTarget.EraseOldImage();
287
288         // Refine the scrolling mode -
289         // Scroll Up/Down, Slow/Normal
290         int nScrollMode = RefineScrollMode(ptMouse);
291
292         switch(nScrollMode) 
293         {
294                 case SCROLL_UP_SLOW:
295                 case SCROLL_DOWN_SLOW:
296                         if( m_nSlowScrollTimeout == 0)
297                                 SendMessage( WM_VSCROLL, 
298                                         nScrollMode == SCROLL_UP_SLOW ? SB_LINEUP : SB_LINEDOWN);
299                         m_nSlowScrollTimeout = ++m_nSlowScrollTimeout%SLOWSCROLL_FREQUENCY;
300                         break;
301                 case SCROLL_UP_NORMAL:
302                 case SCROLL_DOWN_NORMAL:
303                         SendMessage( WM_VSCROLL, 
304                                 nScrollMode == SCROLL_UP_NORMAL ? SB_LINEUP : SB_LINEDOWN);
305                         break;
306                 default:
307                         ASSERT(FALSE);
308                         return;
309                         break;
310         }       
311         if (m_bDragging)
312         {
313                 // Select the drop target
314                 if (m_pImageList)
315                         m_pImageList->DragLeave(this);
316                 HTREEITEM hitem = GetFirstVisibleItem();
317
318                 switch( nScrollMode )
319                   {
320                         case SCROLL_UP_SLOW:
321                         case SCROLL_UP_NORMAL:
322                           {
323                                 SelectDropTarget(hitem);
324                                 m_hitemDrop = hitem;
325                                 break;
326                           }
327                         case SCROLL_DOWN_SLOW:
328                         case SCROLL_DOWN_NORMAL:
329                           {
330                 // Get the last visible item in the control
331                                 int nCount = GetVisibleCount();
332                                 for ( int i=0; i<nCount-1; ++i )
333                                         hitem = GetNextVisibleItem(hitem);
334                                 SelectDropTarget(hitem);
335                                 m_hitemDrop = hitem;
336                                 break;
337                           }
338                         default:
339                                 ASSERT(FALSE);
340                                 return;
341                                 break;
342                   }
343
344                 if (m_pImageList)
345                         m_pImageList->DragEnter(this, ptMouse); CTreeCtrl::OnTimer(nIDEvent);
346         }
347 }
348
349 void CUIDragDropTree::OnRButtonUp(UINT nFlags, CPoint point) 
350 {
351         if (!m_bDragging)
352                 return;
353         // Kill the timer and reset all variables
354         EndDragging();
355         CMenu menu;
356         VERIFY(menu.LoadMenu(IDR_POPUPMENU_DRAGDROP));
357         CMenu* pPopup = menu.GetSubMenu(0);
358         ASSERT(pPopup != NULL);
359         pPopup->SetDefaultItem(ID_POPUP_DD_MOVE);
360         CPoint pts(point);
361         ClientToScreen(&pts);
362         if (GetRDragMenu(pPopup))
363         {
364                 UINT nCmd = pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_NONOTIFY | TPM_RIGHTBUTTON | TPM_RETURNCMD, pts.x, pts.y,this);
365                 if (nCmd == ID_POPUP_DD_MOVE)
366                 {
367                         OnButtonUp(true);
368                 }
369                 else if (nCmd == ID_POPUP_DD_COPY)
370                 {
371                         OnButtonUp(false);
372                 }
373         }
374         else
375         {
376                 // otherwise just move
377                 OnButtonUp(true);
378         }       
379         SelectDropTarget(NULL);
380         CTreeCtrl::OnRButtonUp(nFlags, point);
381 }
382
383 void CUIDragDropTree::OnMouseMove(UINT nFlags, CPoint point) 
384 {
385         // TODO: Add your message handler code here and/or call default
386         HTREEITEM                       hItem;
387         UINT                            flags;
388
389         if (!m_bDragging)
390                 return;
391         CPoint ptScreen(point);
392         ClientToScreen(&ptScreen);
393
394         m_pImageList->DragMove(ptScreen);
395
396         m_pImageList->DragShowNolock(FALSE);
397
398         if ((hItem = HitTest(point, &flags)) != NULL)
399         {
400                 CDD_OleDropTargetInfo Info(this->GetSafeHwnd(),point,NULL);
401                 Info.SetItem(hItem);
402                 LRESULT lResult = SendMessage(WM_APP_OLE_DD_OVER,(WPARAM)&Info);
403                 if (lResult == 0)
404                 {
405                         lResult = GetParent()->SendMessage(WM_APP_OLE_DD_OVER,(WPARAM)&Info);
406                 }
407                 if (lResult)
408                 {
409                         SelectDropTarget(hItem);
410                         m_hitemDrop = hItem;
411                 }
412         }
413         m_pImageList->DragShowNolock(TRUE);
414         
415         CTreeCtrl::OnMouseMove(nFlags, point);
416 }
417
418 void CUIDragDropTree::OnButtonUp(bool bMove)
419 {
420         if (!m_bDragging)
421                 return;
422         EndDragging();
423         if (m_hitemDrag && m_hitemDrag != m_hitemDrop && !IsChildNodeOf(m_hitemDrop, m_hitemDrag) && 
424                                                                 GetParentItem(m_hitemDrag) != m_hitemDrop)
425         {
426                 CDD_OleDropTargetInfo Info(GetSafeHwnd(),CPoint(),NULL);
427                 Info.SetDropEffect(bMove ? DROPEFFECT_MOVE : DROPEFFECT_COPY);
428                 Info.SetItem(m_hitemDrop);
429                 LRESULT lResult = SendMessage(WM_APP_OLE_DD_DROP,(WPARAM)&Info);
430                 if (lResult == 0)
431                         lResult = GetParent()->SendMessage(WM_APP_OLE_DD_DROP,(WPARAM)&Info);
432         }
433 }
434
435 void CUIDragDropTree::EndDragging()
436 {
437         if (!m_bDragging)
438                 return;
439         m_bDragging = FALSE;
440         if (m_pImageList)
441         {
442                 m_pImageList->DragLeave(this);
443                 m_pImageList->EndDrag();
444         }
445         delete m_pImageList;
446         m_pImageList = NULL;
447         ReleaseCapture();
448         KillDragTimer();
449 }
450
451 void CUIDragDropTree::NewTransferItem(HTREEITEM hNewItem)
452 {
453 }
454
455 BOOL CUIDragDropTree::TransferItem(HTREEITEM hitemDrag, HTREEITEM hitemDrop)
456 {
457         TV_INSERTSTRUCT         tvstruct;
458         TCHAR                           sztBuffer[256];
459         HTREEITEM                       hNewItem, hFirstChild;
460
461                 // avoid an infinite recursion situation
462         tvstruct.item.hItem = hitemDrag;
463         tvstruct.item.cchTextMax = sizeof(sztBuffer)-1;
464         tvstruct.item.pszText = sztBuffer;
465         tvstruct.item.mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_PARAM;
466         GetItem(&tvstruct.item);  
467         tvstruct.hParent = hitemDrop;
468         tvstruct.hInsertAfter = TVI_SORT;
469         tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_PARAM;
470         hNewItem = InsertItem(&tvstruct);
471         NewTransferItem(hNewItem);
472
473         while ((hFirstChild = GetChildItem(hitemDrag)) != NULL)
474         {
475                 // recursively transfer all the items
476                 TransferItem(hFirstChild, hNewItem);  
477                 // delete the first child and all its children
478                 DeleteItem(hFirstChild);                
479         }
480         return TRUE;
481 }
482
483
484
485 BOOL CUIDragDropTree::NeedToScroll( CPoint ptMouse )
486 {
487         if (m_bDragging)
488         {
489                 return ptMouse.y < m_nUpperYCoor || ptMouse.y > m_nLowerYCoor;
490         }
491         else
492         {
493                 return ptMouse.y < m_nUpperYCoor+10 || ptMouse.y > m_nLowerYCoor-30;
494         }
495 }
496
497
498 CUIDragDropTree::SCROLLMODE CUIDragDropTree::RefineScrollMode( CPoint ptMouse )
499 {
500         int nYCoor = ptMouse.y;
501         CUIDragDropTree::SCROLLMODE nScrollMode;
502
503         if (m_bDragging)
504         {
505                 nScrollMode = nYCoor > m_nLowerYCoor + m_nScrollBarSize ? SCROLL_DOWN_NORMAL :
506                                           nYCoor > m_nLowerYCoor ? SCROLL_DOWN_SLOW :
507                                           nYCoor < m_nUpperYCoor - m_nScrollBarSize ? SCROLL_UP_NORMAL :
508                                           SCROLL_UP_SLOW;
509         }
510         else
511         {
512                 nScrollMode = nYCoor > m_nLowerYCoor-30 ? SCROLL_DOWN_NORMAL : 
513                                         nYCoor < m_nUpperYCoor-10 ? SCROLL_UP_NORMAL : SCROLL_UP_NORMAL;
514         }
515         return nScrollMode;
516 }
517
518 BOOL CUIDragDropTree::IsChildNodeOf(HTREEITEM hitemChild, HTREEITEM hitemSuspectedParent)
519 {
520         do
521         {
522                 if (hitemChild == hitemSuspectedParent)
523                         break;
524         }
525         while ((hitemChild = GetParentItem(hitemChild)) != NULL);
526
527         return (hitemChild != NULL);
528 }
529
530 void CUIDragDropTree::RegisterDropTarget()
531 {
532         if (GetDragDrop())
533         {
534                 VERIFY(m_OleDropTarget.Register(this));
535                 if (GetDropFiles())
536                         DragAcceptFiles();
537         }
538 }
539
540 DROPEFFECT CUIDragDropTree::SelectCurrentTarget(CDD_OleDropTargetInfo *pInfo)
541 {
542         HTREEITEM hItem;
543         UINT flags;
544         if ((hItem = HitTest(pInfo->GetPoint(), &flags)) != NULL) 
545         {
546                 // select it
547                 SelectDropTarget(hItem);
548                 // save it
549                 m_hitemDrop = hItem;
550                 // returns 1 if allowed
551                 pInfo->SetItem(hItem);
552                 LRESULT lResult = SendMessage(WM_APP_OLE_DD_OVER,(WPARAM)pInfo);
553                 if (lResult == 0)
554                 {
555                         lResult = GetParent()->SendMessage(WM_APP_OLE_DD_OVER,(WPARAM)pInfo);
556                 }
557                 if (lResult)
558                 {
559                         if (::GetKeyState(VK_LCONTROL) < 0) 
560                         {
561                                 if (ItemHasChildren(hItem))
562                                 {
563                                         Expand(hItem, TVE_EXPAND);
564                                 }
565                         }
566                         return pInfo->GetDropEffect();
567                 }
568         }
569         return DROPEFFECT_NONE;
570 }
571
572 void CUIDragDropTree::OnDestroy() 
573 {
574
575         CTreeCtrl::OnDestroy();
576         
577         // TODO: Add your message handler code here
578         
579 }
580
581 int CUIDragDropTree::OnCreate(LPCREATESTRUCT lpCreateStruct) 
582 {
583         if (CTreeCtrl::OnCreate(lpCreateStruct) == -1)
584                 return -1;
585         
586         // TODO: Add your specialized creation code here
587         RegisterDropTarget();
588         
589         return 0;
590 }
591
592 bool CUIDragDropTree::GetRDragMenu(CMenu *pMenu)
593 {
594         return true;
595 }
596
597 void CUIDragDropTree::OnDDMove()
598 {
599         m_CopyMode = eDDMove;
600 }
601
602 void CUIDragDropTree::OnDDCopy()
603 {
604         m_CopyMode = eDDCopy;
605 }
606
607 void CUIDragDropTree::OnDDCancel()
608 {
609         m_CopyMode = eDDCancel;
610 }