GME  13
TreeCtrlEx.cpp
Go to the documentation of this file.
00001 
00002 // 
00003 // CTreeCtrlEx - Multiple selection tree control for MFC
00004 // 
00005 // Copyright © 1997-2003 Bendik Engebretsen
00006 // bendik@techsoft.no
00007 // http://www.techsoft.no/bendik/
00008 //
00009 // Oct 9,  1997 : Fixed problem with notification to parent (TVN_BEGINDRAG)
00010 // Oct 17, 1997 : Fixed bug with deselection when collapsing node with no sibling
00011 // Nov 5,  1997 : Fixed problem with label editing
00012 // Feb 17, 1998 : Fixed another notfication to parent (TVN_KEYDOWN)
00013 // Apr 27, 1998 : Added TVN_SELCHANGED notification to parent in SelectMultiple()
00014 // Dec 21, 1998 : Fixed incorrect use of LVHT_... constants. Now using TVHT_...
00015 // Mar 15, 1999 : Fixed problems when there is no selected item.
00016 //                Fixed new problem with label editing
00017 // Apr 16, 1999 : Fixed problem with double TVN_SELCHANGED notifications
00018 //                                Many thanx to Roel Schroeven for providing the solution!!
00019 // Jul 2, 1999  : Added TVN_SELCHANGING notification when selecting/deselecting 
00020 //                                selected item
00021 // Oct 11, 1999 : Fixed quirks with Shift+Arrow Key selection. Thanx to Yariv Elani !
00022 //                                Also changed behaviour of Ctrl+Mouse click selection: The item is 
00023 //                                unselected, but NOT 'focused' (i.e. same behaviour as a listctrl).
00024 // Nov 16, 1999 : Fixed another quirk with Ctrl+Mouse click selection. Thanks to 
00025 //                                Yariv Ben-Tovim!
00026 // May 21, 2001 : Now supports Shift PgUp and PgDn selection. Thanks to Sergei 
00027 //                                Antonov. Also fixed the too early TVN_SELCHANGED when key-selecting.
00028 // May 31, 2001 : Fixed bug with uninitialized m_ptClick in OnLButtonDown. Thanks to
00029 //                                Cristian Rodriguez!
00030 // Jun 20, 2001 : Fixed quirk with label editing/doubleclick. Once more, thanks 
00031 //                                to Cristian Rodriguez. Also added treectrl wndclass registration.
00032 // Jan 24, 2003 : Fixed bug when treeview has the TVS_DISABLEDRAGDROP style. Thanks to
00033 //                                Fernanda Diniz Tavarez
00034 // Mar 20, 2003 : Fixed 'blinking' problem with TVS_SINGLEEXPAND style. Thanks to 
00035 //                                H.-Joachim Riedel.
00036 // Jun 10, 2003 : Migrated to Visual C++.NET / MFC 7.X
00037 
00038 #include "stdafx.h"
00039 #include "TreeCtrlEx.h"
00040 
00041 #ifdef _DEBUG
00042 #define new DEBUG_NEW
00043 #undef THIS_FILE
00044 static char THIS_FILE[] = __FILE__;
00045 #endif
00046 
00047 #define TCEX_EDITLABEL 1                // Edit label timer event
00048 
00050 // CTreeCtrlEx
00051 
00052 CTreeCtrlEx::CTreeCtrlEx() : m_bSelectPending(FALSE), m_hClickedItem(NULL), m_hFirstSelectedItem(NULL), m_bSelectionComplete(TRUE), m_bEditLabelPending(FALSE) 
00053 {
00054         //m_pchTip = NULL;
00055         //m_pwchTip = NULL;
00056 }
00057 
00058 CTreeCtrlEx::~CTreeCtrlEx()
00059 {
00060         /*if(m_pwchTip != NULL)
00061                 delete m_pwchTip;
00062         
00063         if(m_pchTip != NULL)
00064                 delete m_pchTip;*/
00065 }
00066 
00067 BEGIN_MESSAGE_MAP(CTreeCtrlEx, CTreeCtrl)
00068         //{{AFX_MSG_MAP(CTreeCtrlEx)
00069         //ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
00070         //ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
00071         ON_WM_LBUTTONDOWN()
00072         ON_WM_LBUTTONUP()
00073         ON_WM_MOUSEMOVE()
00074         ON_WM_KEYDOWN()
00075         ON_NOTIFY_REFLECT_EX(TVN_ITEMEXPANDING, OnItemexpanding)
00076         ON_NOTIFY_REFLECT_EX(NM_SETFOCUS, OnSetfocus)
00077         ON_NOTIFY_REFLECT_EX(NM_KILLFOCUS, OnKillfocus)
00078         ON_NOTIFY_REFLECT_EX(TVN_SELCHANGED, OnSelchanged)
00079         ON_WM_RBUTTONDOWN()
00080         ON_WM_RBUTTONUP()
00081         ON_WM_LBUTTONDBLCLK()
00082         ON_WM_TIMER()
00083         ON_WM_NCHITTEST()
00084         //}}AFX_MSG_MAP
00085 END_MESSAGE_MAP()
00086 
00087 IMPLEMENT_DYNAMIC(CTreeCtrlEx, CTreeCtrl)
00088 
00089 BOOL CTreeCtrlEx::Create(DWORD dwStyle, DWORD dwExStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
00090 {
00091         return CTreeCtrl::CreateEx( dwExStyle, dwStyle, rect, pParentWnd, nID );
00092 }
00093 
00094 BOOL CTreeCtrlEx::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
00095 {
00096         return CTreeCtrl::Create(dwStyle, rect, pParentWnd, nID);
00097 }
00098 
00099 
00101 // CTreeCtrlEx message handlers
00102 
00103 void CTreeCtrlEx::PreSubclassWindow()
00104 {
00105         CTreeCtrl::PreSubclassWindow();
00106         //EnableToolTips(TRUE);
00107 }
00108 
00109 /*int CTreeCtrlEx::OnToolHitTest(CPoint point, TOOLINFO * pTI) const
00110 {
00111         RECT rect;
00112         
00113         UINT nFlags;
00114         HTREEITEM hitem = HitTest( point, &nFlags );
00115         if( nFlags & TVHT_ONITEM)
00116         {
00117                 GetItemRect( hitem, &rect, TRUE );
00118                 pTI->hwnd = m_hWnd;
00119                 pTI->uId = (UINT)hitem;
00120                 pTI->lpszText = LPSTR_TEXTCALLBACK;
00121                 pTI->rect = rect;
00122                 return pTI->uId;
00123         }
00124         
00125         return -1;
00126 }*/
00127 
00128 /*BOOL CTreeCtrlEx::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
00129 {
00130         // need to handle both ANSI and UNICODE versions of the message
00131         TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
00132         TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
00133         CString strTipText;
00134         UINT nID = pNMHDR->idFrom;
00135         
00136         // Do not process the message from built in tooltip 
00137         if( nID == (UINT)m_hWnd &&
00138                 (( pNMHDR->code == TTN_NEEDTEXTA && pTTTA->uFlags & TTF_IDISHWND ) ||
00139                 ( pNMHDR->code == TTN_NEEDTEXTW && pTTTW->uFlags & TTF_IDISHWND ) ) )
00140                 return FALSE;
00141         
00142         // Get the mouse position
00143         const MSG* pMessage;
00144         CPoint pt;
00145         pMessage = GetCurrentMessage();
00146         ASSERT ( pMessage );
00147         pt = pMessage->pt;
00148         ScreenToClient( &pt );
00149         
00150         UINT nFlags;
00151         HTREEITEM hitem = HitTest( pt, &nFlags );
00152         if( nFlags & TVHT_ONITEM)
00153         {
00154                 CString strTxt = GetItemText((HTREEITEM)nID);
00155                 strTipText = strTxt;
00156         }
00157         
00158 #ifndef _UNICODE
00159         if(pNMHDR->code == TTN_NEEDTEXTA)
00160         {
00161                 if(m_pchTip != NULL)
00162                         delete m_pchTip;
00163                 
00164                 m_pchTip = new TCHAR[strTipText.GetLength()+1];
00165                 lstrcpyn(m_pchTip, strTipText, strTipText.GetLength());
00166                 m_pchTip[strTipText.GetLength()] = 0;
00167                 pTTTW->lpszText = (WCHAR*)m_pchTip;
00168         }
00169         else
00170         {
00171                 if(m_pwchTip != NULL)
00172                         delete m_pwchTip;
00173                 
00174                 m_pwchTip = new WCHAR[strTipText.GetLength()+1];
00175                 _mbstowcsz(m_pwchTip, strTipText, strTipText.GetLength());
00176                 m_pwchTip[strTipText.GetLength()] = 0; // end of text
00177                 pTTTW->lpszText = (WCHAR*)m_pwchTip;
00178         }
00179 #else
00180         if(pNMHDR->code == TTN_NEEDTEXTA)
00181         {
00182                 if(m_pchTip != NULL)
00183                         delete m_pchTip;
00184                 
00185                 m_pchTip = new TCHAR[strTipText.GetLength()+1];
00186                 _wcstombsz(m_pchTip, strTipText, strTipText.GetLength());
00187                 m_pchTip[strTipText.GetLength()] = 0; // end of text
00188                 pTTTA->lpszText = (LPTSTR)m_pchTip;
00189         }
00190         else
00191         {
00192                 if(m_pwchTip != NULL)
00193                         delete m_pwchTip;
00194                 
00195                 m_pwchTip = new WCHAR[strTipText.GetLength()+1];
00196                 lstrcpyn(m_pwchTip, strTipText, strTipText.GetLength());
00197                 m_pwchTip[strTipText.GetLength()] = 0;
00198                 pTTTA->lpszText = (LPTSTR) m_pwchTip;
00199         }
00200 #endif
00201         
00202         *pResult = 0;
00203         
00204         return TRUE;    // message was handled
00205 }*/
00206 
00208 // The tree control dosn't support multiple selection. However we can simulate 
00209 // it by taking control of the left mouse click and arrow key press before the
00210 // control gets them, and setting/clearing the TVIS_SELECTED style on the items
00211 
00212 void CTreeCtrlEx::OnLButtonDown( UINT nFlags, CPoint point )
00213 {
00214 
00215         UINT nHitFlags = 0;
00216         HTREEITEM hClickedItem = HitTest( point, &nHitFlags );
00217 
00218         // Must invoke label editing explicitly. The base class OnLButtonDown would normally
00219         // do this, but we can't call it here because of the multiple selection...
00220         if( !( nFlags&( MK_CONTROL|MK_SHIFT ) ) && ( GetStyle() & TVS_EDITLABELS ) && ( nHitFlags & TVHT_ONITEMLABEL ) )
00221                 if ( hClickedItem == GetSelectedItem() )
00222                 {
00223                         // Clear multple selection before label editing
00224                         ClearSelection();
00225                         SelectItem( hClickedItem );
00226 
00227                         // Invoke label editing
00228                         m_bEditLabelPending = TRUE;
00229                         m_idTimer = SetTimer(TCEX_EDITLABEL, GetDoubleClickTime(), NULL);
00230 
00231                         return;
00232                 }
00233 
00234         m_bEditLabelPending = FALSE;
00235 
00236         if( nHitFlags & TVHT_ONITEM )
00237         {
00238                 SetFocus();
00239 
00240                 m_hClickedItem = hClickedItem;
00241 
00242                 // Is the clicked item already selected ?
00243                 BOOL bIsClickedItemSelected = GetItemState( hClickedItem, TVIS_SELECTED ) & TVIS_SELECTED;
00244 
00245                 if ( bIsClickedItemSelected )
00246                 {
00247                         // Maybe user wants to drag/drop multiple items!
00248                         // So, wait until OnLButtonUp() to do the selection stuff. 
00249                         m_bSelectPending=TRUE;
00250                 }
00251                 else
00252                 {
00253                         SelectMultiple( hClickedItem, nFlags, point );
00254                         m_bSelectPending=FALSE;
00255                 }
00256 
00257                 m_ptClick=point;
00258         }
00259         else
00260         {
00261                 // Modified: 01/29/2002 Tihamer Levendovszky////////
00262                 
00263                 if(nHitFlags&TVHT_NOWHERE || nHitFlags&TVHT_ONITEMRIGHT )
00264                 {
00265                         ClearSelection();
00266                 }
00268                 CTreeCtrl::OnLButtonDown( nFlags, point );
00269         }
00270 }
00271 
00272 void CTreeCtrlEx::OnLButtonUp( UINT nFlags, CPoint point )
00273 {
00274         if ( m_bSelectPending )
00275         {
00276                 // A select has been waiting to be performed here
00277                 SelectMultiple( m_hClickedItem, nFlags, point );
00278                 m_bSelectPending=FALSE;
00279         }
00280 
00281         m_hClickedItem=NULL;
00282 
00283         CTreeCtrl::OnLButtonUp( nFlags, point );
00284 }
00285 
00286 
00287 void CTreeCtrlEx::OnMouseMove( UINT nFlags, CPoint point )
00288 {
00289         // If there is a select pending, check if cursor has moved so much away from the 
00290         // down-click point that we should cancel the pending select and initiate
00291         // a drag/drop operation instead!
00292 
00293         // FIXME: need to look at NC too, since if the user moves fast enough, we won't get this message
00294         if ( m_hClickedItem )
00295         {
00296                 CSize sizeMoved = m_ptClick-point;
00297 
00298                 if ( abs(sizeMoved.cx) > GetSystemMetrics( SM_CXDRAG ) || abs(sizeMoved.cy) > GetSystemMetrics( SM_CYDRAG ) )
00299                 {
00300                         m_bSelectPending=FALSE;
00301 
00302                         // Notify parent that he may begin drag operation
00303                         // Since we have taken over OnLButtonDown(), the default handler doesn't
00304                         // do the normal work when clicking an item, so we must provide our own
00305                         // TVN_BEGINDRAG notification for the parent!
00306 
00307                         CWnd* pWnd = GetParent();
00308                         if ( pWnd && !( GetStyle() & TVS_DISABLEDRAGDROP ) )
00309                         {
00310                                 NM_TREEVIEW tv;
00311 
00312                                 tv.hdr.hwndFrom = GetSafeHwnd();
00313                                 tv.hdr.idFrom = GetWindowLong( GetSafeHwnd(), GWL_ID );
00314                                 tv.hdr.code = TVN_BEGINDRAG;
00315 
00316                                 tv.itemNew.hItem = m_hClickedItem;
00317                                 tv.itemNew.state = GetItemState( m_hClickedItem, 0xffffffff );
00318                                 tv.itemNew.lParam = GetItemData( m_hClickedItem );
00319 
00320                                 tv.ptDrag.x = point.x;
00321                                 tv.ptDrag.y = point.y;
00322 
00323                                 pWnd->SendMessage( WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv );
00324                         }
00325 
00326                         m_hClickedItem=NULL;
00327                 }
00328         }
00329 
00330         CTreeCtrl::OnMouseMove( nFlags, point );
00331 }
00332 
00333 
00334 void CTreeCtrlEx::SelectMultiple( HTREEITEM hClickedItem, UINT nFlags, CPoint point )
00335 {
00336         // Start preparing an NM_TREEVIEW struct to send a notification after selection is done
00337         NM_TREEVIEW tv;
00338         memset(&tv.itemOld, 0, sizeof(tv.itemOld));
00339 
00340         CWnd* pWnd = GetParent();
00341 
00342         HTREEITEM hOldItem = GetSelectedItem();
00343 
00344         if ( hOldItem )
00345         {
00346                 tv.itemOld.hItem = hOldItem;
00347                 tv.itemOld.state = GetItemState( hOldItem, 0xffffffff );
00348                 tv.itemOld.lParam = GetItemData( hOldItem );
00349                 tv.itemOld.mask = TVIF_HANDLE|TVIF_STATE|TVIF_PARAM;
00350         }
00351 
00352         // Flag signaling that selection process is NOT complete.
00353         // (Will prohibit TVN_SELCHANGED from being sent to parent)
00354         m_bSelectionComplete = FALSE;
00355 
00356         // Action depends on whether the user holds down the Shift or Ctrl key
00357         if ( nFlags & MK_SHIFT )
00358         {
00359                 // Select from first selected item to the clicked item
00360                 if ( !m_hFirstSelectedItem )
00361                         m_hFirstSelectedItem = GetSelectedItem();
00362 
00363                 SelectItems( m_hFirstSelectedItem, hClickedItem );
00364         }
00365         else if ( nFlags & MK_CONTROL )
00366         {
00367                 // Find which item is currently selected
00368                 HTREEITEM hSelectedItem = GetSelectedItem();
00369 
00370                 // Is the clicked item already selected ?
00371                 BOOL bIsClickedItemSelected = GetItemState( hClickedItem, TVIS_SELECTED ) & TVIS_SELECTED;
00372                 BOOL bIsSelectedItemSelected = FALSE;
00373                 if ( hSelectedItem )
00374                         bIsSelectedItemSelected = GetItemState( hSelectedItem, TVIS_SELECTED ) & TVIS_SELECTED;
00375 
00376                 // Must synthesize a TVN_SELCHANGING notification
00377                 if ( pWnd )
00378                 {
00379                         tv.hdr.hwndFrom = GetSafeHwnd();
00380                         tv.hdr.idFrom = GetWindowLong( GetSafeHwnd(), GWL_ID );
00381                         tv.hdr.code = TVN_SELCHANGING;
00382 
00383                         tv.itemNew.hItem = hClickedItem;
00384                         tv.itemNew.state = GetItemState( hClickedItem, 0xffffffff );
00385                         tv.itemNew.lParam = GetItemData( hClickedItem );
00386 
00387                         tv.itemOld.hItem = NULL;
00388                         tv.itemOld.mask = 0;
00389 
00390                         tv.action = TVC_BYMOUSE;
00391 
00392                         tv.ptDrag.x = point.x;
00393                         tv.ptDrag.y = point.y;
00394 
00395                         pWnd->SendMessage( WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv );
00396                 }
00397 
00398                 // If the previously selected item was selected, re-select it
00399                 if ( bIsSelectedItemSelected )
00400                         SetItemState( hSelectedItem, TVIS_SELECTED, TVIS_SELECTED );
00401 
00402                 // We want the newly selected item to toggle its selected state,
00403                 // so unselect now if it was already selected before
00404                 if ( bIsClickedItemSelected )
00405                         SetItemState( hClickedItem, 0, TVIS_SELECTED );
00406                 else
00407                 {
00408                         SetItemState( hClickedItem, TVIS_SELECTED, TVIS_SELECTED );
00409                 }
00410 
00411                 // If the previously selected item was selected, re-select it
00412                 if ( bIsSelectedItemSelected && hSelectedItem != hClickedItem )
00413                         SetItemState( hSelectedItem, TVIS_SELECTED, TVIS_SELECTED );
00414 
00415                 // Store as first selected item (if not already stored)
00416                 if ( m_hFirstSelectedItem==NULL )
00417                         m_hFirstSelectedItem = hClickedItem;
00418         }
00419         else
00420         {
00421                 // Clear selection of all "multiple selected" items first
00422                 ClearSelection(true);
00423 
00424                 // Then select the clicked item
00425                 SelectItem( hClickedItem );
00426                 SetItemState( hClickedItem, TVIS_SELECTED, TVIS_SELECTED );
00427 
00428                 // Store as first selected item
00429                 m_hFirstSelectedItem = hClickedItem;
00430         }
00431 
00432         // Selection process is now complete. Since we have 'eaten' the TVN_SELCHANGED 
00433         // notification provided by Windows' treectrl, we must now produce one ourselves,
00434         // so that our parent gets to know about the change of selection.
00435         m_bSelectionComplete = TRUE;
00436 
00437         if ( pWnd )
00438         {
00439                 tv.hdr.hwndFrom = GetSafeHwnd();
00440                 tv.hdr.idFrom = GetWindowLong( GetSafeHwnd(), GWL_ID );
00441                 tv.hdr.code = TVN_SELCHANGED;
00442 
00443                 tv.itemNew.hItem = m_hClickedItem;
00444                 tv.itemNew.state = GetItemState( m_hClickedItem, 0xffffffff );
00445                 tv.itemNew.lParam = GetItemData( m_hClickedItem );
00446                 tv.itemNew.mask = TVIF_HANDLE|TVIF_STATE|TVIF_PARAM;
00447 
00448                 tv.action = TVC_UNKNOWN;
00449 
00450                 pWnd->SendMessage( WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv );
00451         }
00452 }
00453 
00454 void CTreeCtrlEx::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags ) 
00455 {
00456         CWnd* pWnd = GetParent();
00457 
00458         if ( nChar==VK_NEXT || nChar==VK_PRIOR )
00459         {
00460                 if ( !( GetKeyState( VK_SHIFT )&0x8000 ) )
00461                 {
00462                         // User pressed Pg key without holding 'Shift':
00463                         // Clear multiple selection (if multiple) and let base class do 
00464                         // normal selection work!
00465                         if ( GetSelectedCount()>1 )
00466                                 ClearSelection( TRUE );
00467 
00468                         CTreeCtrl::OnKeyDown( nChar, nRepCnt, nFlags );
00469                         m_hFirstSelectedItem = GetSelectedItem();
00470                         return;
00471                 }
00472 
00473                 // Flag signaling that selection process is NOT complete.
00474                 // (Will prohibit TVN_SELCHANGED from being sent to parent)
00475                 m_bSelectionComplete = FALSE;
00476 
00477                 // Let base class select the item
00478                 CTreeCtrl::OnKeyDown( nChar, nRepCnt, nFlags );
00479                 HTREEITEM hSelectedItem = GetSelectedItem();
00480 
00481                 // Then select items in between
00482                 SelectItems( m_hFirstSelectedItem, hSelectedItem );
00483 
00484                 // Selection process is now complete. Since we have 'eaten' the TVN_SELCHANGED 
00485                 // notification provided by Windows' treectrl, we must now produce one ourselves,
00486                 // so that our parent gets to know about the change of selection.
00487                 m_bSelectionComplete = TRUE;
00488 
00489                 if (pWnd)
00490                 {
00491                         NM_TREEVIEW tv;
00492                         memset(&tv.itemOld, 0, sizeof(tv.itemOld));
00493 
00494                         tv.hdr.hwndFrom = GetSafeHwnd();
00495                         tv.hdr.idFrom = GetWindowLong(GetSafeHwnd(), GWL_ID);
00496                         tv.hdr.code = TVN_SELCHANGED;
00497 
00498                         tv.itemNew.hItem = hSelectedItem;
00499                         tv.itemNew.state = GetItemState(hSelectedItem, 0xffffffff);
00500                         tv.itemNew.lParam = GetItemData(hSelectedItem);
00501                         tv.itemNew.mask = TVIF_HANDLE|TVIF_STATE|TVIF_PARAM;
00502 
00503                         tv.action = TVC_UNKNOWN;
00504 
00505                         pWnd->SendMessage(WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv);
00506                 }
00507         }
00508         else if ( nChar==VK_UP || nChar==VK_DOWN )
00509         {
00510                 // Find which item is currently selected
00511                 HTREEITEM hSelectedItem = GetSelectedItem();
00512 
00513                 HTREEITEM hNextItem;
00514                 if ( nChar==VK_UP )
00515                         hNextItem = GetPrevVisibleItem( hSelectedItem );
00516                 else
00517                         hNextItem = GetNextVisibleItem( hSelectedItem );
00518 
00519                 if ( !( GetKeyState( VK_SHIFT )&0x8000 ) )
00520                 {
00521                         // User pressed arrow key without holding 'Shift':
00522                         // Clear multiple selection (if multiple) and let base class do 
00523                         // normal selection work!
00524                         if ( GetSelectedCount()>1 )
00525                                 ClearSelection( TRUE );
00526 
00527                         if ( hNextItem )
00528                                 CTreeCtrl::OnKeyDown( nChar, nRepCnt, nFlags );
00529                         m_hFirstSelectedItem = GetSelectedItem();
00530                         return;
00531                 }
00532 
00533                 if ( hNextItem )
00534                 {
00535                         // Flag signaling that selection process is NOT complete.
00536                         // (Will prohibit TVN_SELCHANGED from being sent to parent)
00537                         m_bSelectionComplete = FALSE;
00538 
00539                         // If the next item is already selected, we assume user is
00540                         // "moving back" in the selection, and thus we should clear 
00541                         // selection on the previous one
00542                         BOOL bSelect = !( GetItemState( hNextItem, TVIS_SELECTED ) & TVIS_SELECTED );
00543 
00544                         // Select the next item (this will also deselect the previous one!)
00545                         SelectItem( hNextItem );
00546 
00547                         // Now, re-select the previously selected item
00548                         if ( bSelect || ( !( GetItemState( hSelectedItem, TVIS_SELECTED ) & TVIS_SELECTED ) ) )
00549                                 SelectItems( m_hFirstSelectedItem, hNextItem );
00550 
00551                         // Selection process is now complete. Since we have 'eaten' the TVN_SELCHANGED 
00552                         // notification provided by Windows' treectrl, we must now produce one ourselves,
00553                         // so that our parent gets to know about the change of selection.
00554                         m_bSelectionComplete = TRUE;
00555 
00556                         if (pWnd)
00557                         {
00558                                 NM_TREEVIEW tv;
00559                                 memset(&tv.itemOld, 0, sizeof(tv.itemOld));
00560 
00561                                 tv.hdr.hwndFrom = GetSafeHwnd();
00562                                 tv.hdr.idFrom = GetWindowLong(GetSafeHwnd(), GWL_ID);
00563                                 tv.hdr.code = TVN_SELCHANGED;
00564 
00565                                 tv.itemNew.hItem = hNextItem;
00566                                 tv.itemNew.state = GetItemState(hNextItem, 0xffffffff);
00567                                 tv.itemNew.lParam = GetItemData(hNextItem);
00568                                 tv.itemNew.mask = TVIF_HANDLE|TVIF_STATE|TVIF_PARAM;
00569 
00570                                 tv.action = TVC_UNKNOWN;
00571 
00572                                 pWnd->SendMessage(WM_NOTIFY, tv.hdr.idFrom, (LPARAM)&tv);
00573                         }
00574                 }
00575 
00576                 // Since the base class' OnKeyDown() isn't called in this case,
00577                 // we must provide our own TVN_KEYDOWN notification to the parent
00578 
00579                 CWnd* pWnd = GetParent();
00580                 if ( pWnd )
00581                 {
00582                         NMTVKEYDOWN tvk;
00583 
00584                         tvk.hdr.hwndFrom = GetSafeHwnd();
00585                         tvk.hdr.idFrom = GetWindowLong( GetSafeHwnd(), GWL_ID );
00586                         tvk.hdr.code = TVN_KEYDOWN;
00587 
00588                         tvk.wVKey = nChar;
00589                         tvk.flags = 0;
00590 
00591                         pWnd->SendMessage( WM_NOTIFY, tvk.hdr.idFrom, (LPARAM)&tvk );
00592                 }
00593         }
00594         else
00595                 // Behave normally
00596                 CTreeCtrl::OnKeyDown( nChar, nRepCnt, nFlags );
00597 }
00598 
00599 
00601 // I want clicking on an item with the right mouse button to select the item,
00602 // but not if there is currently a multiple selection
00603 
00604 void CTreeCtrlEx::OnRButtonDown( UINT nFlags, CPoint point )
00605 {
00606         UINT nHitFlags = 0;
00607         HTREEITEM hClickedItem = HitTest( point, &nHitFlags );
00608 
00609         if( nHitFlags&TVHT_ONITEM )
00610         {
00611                 if ( GetSelectedCount()<2 )
00612                 {
00613                         SelectItem( hClickedItem );
00614                 }
00615                 // Modified: 01/26/2002 Tihamer Levendovszky
00616                 else
00617                 {
00618                         if(!( GetItemState( hClickedItem, TVIS_SELECTED ) & TVIS_SELECTED ))
00619                         {
00620                                 ClearSelection(TRUE);
00621                                 SelectItem( hClickedItem );
00622                         }
00623                 }
00624                 m_hClickedItem = hClickedItem;
00625                 m_ptClick = point;
00626         }
00627         // Modified: 01/26/2002 Tihamer Levendovszky
00628         else
00629         {
00630                 ClearSelection();
00631         }
00632 
00633 // Modified: 01/26/2002 Tihamer Levendovszky
00634 /*      CTreeCtrl::OnRButtonDown( nFlags, point ); */
00635 }
00636 
00637 void CTreeCtrlEx::OnRButtonUp(UINT nFlags, CPoint point)
00638 {
00639         m_hClickedItem = NULL;
00640         __super::OnRButtonUp(nFlags, point);
00641 }
00642 
00643 
00645 // Get number of selected items
00646 
00647 UINT CTreeCtrlEx::GetSelectedCount() const
00648 {
00649         // Only visible items should be selected!
00650         UINT uCount=0;
00651         for ( HTREEITEM hItem = GetRootItem(); hItem!=NULL; hItem = GetNextVisibleItem( hItem ) )
00652                 if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )
00653                         uCount++;
00654 
00655         return uCount;
00656 }
00657 
00658 
00660 // Overloaded to catch our own special code
00661 
00662 HTREEITEM CTreeCtrlEx::GetNextItem(HTREEITEM hItem, UINT nCode)
00663 {
00664         if (nCode==TVGN_EX_ALL)
00665         {
00666                 // This special code lets us iterate through ALL tree items regardless 
00667                 // of their parent/child relationship (very handy)
00668                 HTREEITEM hNextItem;
00669 
00670                 // If it has a child node, this will be the next item
00671                 hNextItem = GetChildItem( hItem );
00672                 if (hNextItem)
00673                         return hNextItem;
00674 
00675                 // Otherwise, see if it has a next sibling item
00676                 hNextItem = GetNextSiblingItem(hItem);
00677                 if (hNextItem)
00678                         return hNextItem;
00679 
00680                 // Finally, look for next sibling to the parent item
00681                 HTREEITEM hParentItem=hItem;
00682                 while (!hNextItem && hParentItem)
00683                 {
00684                         // No more children: Get next sibling to parent
00685                         hParentItem = GetParentItem(hParentItem);
00686                         hNextItem = GetNextSiblingItem(hParentItem);
00687                 }
00688 
00689                 return hNextItem; // will return NULL if no more parents
00690         }
00691         else
00692                 return CTreeCtrl::GetNextItem(hItem, nCode);    // standard processing
00693 }
00694 
00696 // Helpers to list out selected items. (Use similar to GetFirstVisibleItem(), 
00697 // GetNextVisibleItem() and GetPrevVisibleItem()!)
00698 
00699 HTREEITEM CTreeCtrlEx::GetFirstSelectedItem()
00700 {
00701         for ( HTREEITEM hItem = GetRootItem(); hItem!=NULL; hItem = GetNextVisibleItem( hItem ) )
00702                 if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )
00703                         return hItem;
00704 
00705         return NULL;
00706 }
00707 
00708 HTREEITEM CTreeCtrlEx::GetNextSelectedItem( HTREEITEM hItem )
00709 {
00710         for ( hItem = GetNextVisibleItem( hItem ); hItem!=NULL; hItem = GetNextVisibleItem( hItem ) )
00711                 if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )
00712                         return hItem;
00713 
00714         return NULL;
00715 }
00716 
00717 HTREEITEM CTreeCtrlEx::GetPrevSelectedItem( HTREEITEM hItem )
00718 {
00719         for ( hItem = GetPrevVisibleItem( hItem ); hItem!=NULL; hItem = GetPrevVisibleItem( hItem ) )
00720                 if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )
00721                         return hItem;
00722 
00723         return NULL;
00724 }
00725 
00726 
00728 // Select/unselect item without unselecting other items
00729 
00730 BOOL CTreeCtrlEx::SelectItemEx(HTREEITEM hItem, BOOL bSelect/*=TRUE*/)
00731 {
00732         HTREEITEM hSelItem = GetSelectedItem();
00733 
00734         if ( hItem==hSelItem )
00735         {
00736                 if ( !bSelect )
00737                 {
00738                         SelectItem( NULL );
00739                         return TRUE;
00740                 }
00741 
00742                 return FALSE;
00743         }
00744 
00745         SelectItem( hItem );
00746         m_hFirstSelectedItem=hItem;
00747 
00748         // Reselect previous "real" selected item which was unselected byt SelectItem()
00749         if ( hSelItem )
00750                 SetItemState( hSelItem, TVIS_SELECTED, TVIS_SELECTED );
00751 
00752         return TRUE;
00753 }
00754 
00756 // Select visible items between specified 'from' and 'to' item (including these!)
00757 // If the 'to' item is above the 'from' item, it traverses the tree in reverse 
00758 // direction. Selection on other items is cleared!
00759 
00760 BOOL CTreeCtrlEx::SelectItems( HTREEITEM hFromItem, HTREEITEM hToItem )
00761 {
00762         // Determine direction of selection 
00763         // (see what item comes first in the tree)
00764         HTREEITEM hItem = GetRootItem();
00765 
00766         while ( hItem && hItem!=hFromItem && hItem!=hToItem )
00767                 hItem = GetNextVisibleItem( hItem );
00768 
00769         if ( !hItem )
00770                 return FALSE;   // Items not visible in tree
00771 
00772         BOOL bReverse = hItem==hToItem;
00773 
00774         // "Really" select the 'to' item (which will deselect 
00775         // the previously selected item)
00776 
00777         SelectItem( hToItem );
00778 
00779         // Go through all visible items again and select/unselect
00780 
00781         hItem = GetRootItem();
00782         BOOL bSelect = FALSE;
00783 
00784         while ( hItem )
00785         {
00786                 if ( hItem == ( bReverse ? hToItem : hFromItem ) )
00787                         bSelect = TRUE;
00788 
00789                 if ( bSelect )
00790                 {
00791                         if ( !( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED ) )
00792                                 SetItemState( hItem, TVIS_SELECTED, TVIS_SELECTED );
00793                 }
00794                 else
00795                 {
00796                         if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )
00797                                 SetItemState( hItem, 0, TVIS_SELECTED );
00798                 }
00799 
00800                 if ( hItem == ( bReverse ? hFromItem : hToItem ) )
00801                         bSelect = FALSE;
00802 
00803                 hItem = GetNextVisibleItem( hItem );
00804         }
00805 
00806         return TRUE;
00807 }
00808 
00809 
00811 // Clear selected state on all visible items
00812 
00813 void CTreeCtrlEx::ClearSelection(BOOL bMultiOnly/*=FALSE*/)
00814 {
00815         // TZS - entropia decreased
00816         if ( !bMultiOnly )
00817                 return;
00818 //              SelectItem( NULL );
00819 
00820         for ( HTREEITEM hItem=GetRootItem(); hItem!=NULL; hItem=GetNextVisibleItem( hItem ) )
00821                 if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )
00822                         SetItemState( hItem, 0, TVIS_SELECTED );
00823         SelectItem( NULL );
00824 }
00825 
00826 
00828 // If a node is collapsed, we should clear selections of its child items 
00829 
00830 BOOL CTreeCtrlEx::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult) 
00831 {
00832         NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
00833 
00834         if ( pNMTreeView->action == TVE_COLLAPSE )
00835         {
00836                 HTREEITEM hItem = GetChildItem( pNMTreeView->itemNew.hItem );
00837 
00838                 while ( hItem )
00839                 {
00840                         if ( GetItemState( hItem, TVIS_SELECTED ) & TVIS_SELECTED )
00841                                 SetItemState( hItem, 0, TVIS_SELECTED );
00842 
00843                         // Get the next node: First see if current node has a child
00844                         HTREEITEM hNextItem = GetChildItem( hItem );
00845                         if ( !hNextItem )
00846                         {
00847                                 // No child: Get next sibling item
00848                                 if ( !( hNextItem = GetNextSiblingItem( hItem ) ) )
00849                                 {
00850                                         HTREEITEM hParentItem = hItem;
00851                                         while ( !hNextItem )
00852                                         {
00853                                                 // No more children: Get parent
00854                                                 if ( !( hParentItem = GetParentItem( hParentItem ) ) )
00855                                                         break;
00856 
00857                                                 // Quit when parent is the collapsed node
00858                                                 // (Don't do anything to siblings of this)
00859                                                 if ( hParentItem == pNMTreeView->itemNew.hItem )
00860                                                         break;
00861 
00862                                                 // Get next sibling to parent
00863                                                 hNextItem = GetNextSiblingItem( hParentItem );
00864                                         }
00865 
00866                                         // Quit when parent is the collapsed node
00867                                         if ( hParentItem == pNMTreeView->itemNew.hItem )
00868                                                 break;
00869                                 }
00870                         }
00871 
00872                         hItem = hNextItem;
00873                 }
00874         }
00875         
00876         *pResult = 0;
00877         return FALSE;   // Allow parent to handle this notification as well
00878 }
00879 
00880 
00882 // Intercept TVN_SELCHANGED and pass it only to the parent window of the
00883 // selection process is finished
00884 
00885 BOOL CTreeCtrlEx::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
00886 {
00887         // Return TRUE if selection is not complete. This will prevent the 
00888         // notification from being sent to parent.
00889         return !m_bSelectionComplete;   
00890 }
00891 
00892 
00894 // Ensure the multiple selected items are drawn correctly when loosing/getting
00895 // the focus
00896 
00897 BOOL CTreeCtrlEx::OnSetfocus(NMHDR* pNMHDR, LRESULT* pResult) 
00898 {
00899         Invalidate();
00900         *pResult = 0;
00901         return FALSE;
00902 }
00903 
00904 BOOL CTreeCtrlEx::OnKillfocus(NMHDR* pNMHDR, LRESULT* pResult) 
00905 {
00906         Invalidate();
00907         *pResult = 0;
00908         return FALSE;
00909 }
00910 
00911 void CTreeCtrlEx::OnLButtonDblClk(UINT nFlags, CPoint point)
00912 {
00913         // We stop label editing.
00914         m_bEditLabelPending = FALSE;
00915         CTreeCtrl::OnLButtonDblClk(nFlags, point);
00916 }
00917 
00918 void CTreeCtrlEx::OnTimer(UINT_PTR nIDEvent)
00919 {
00920         if (nIDEvent == TCEX_EDITLABEL)
00921         {
00922                 // Stop the timer.
00923                 KillTimer(m_idTimer);
00924 
00925                 // Invoke label editing.
00926                 if (m_bEditLabelPending)
00927                         EditLabel(GetSelectedItem());
00928 
00929                 m_bEditLabelPending = FALSE;
00930                 return;
00931         }
00932 
00933         CTreeCtrl::OnTimer(nIDEvent);
00934 }
00935 
00937 // Retrieves a sorted list of the item text and item handles
00938 // Returns the number of matched items
00939 // Tihamer Levendovszky 12/07/2001
00940 int CTreeCtrlEx::FindTextInItems(CString &strText, HTREEITEM hStartAtItem,
00941                                         CStringArrayEx &strResults, CArray<HTREEITEM, HTREEITEM>& hResults)
00942 {
00943         strResults.RemoveAll();
00944         hResults.RemoveAll();
00945         // Traverse all items in tree control
00946         HTREEITEM hItem;
00947         if ( hStartAtItem )
00948                 hItem = hStartAtItem;
00949         else
00950                 hItem = GetRootItem();
00951 
00952         while ( hItem )
00953         {
00954                 CString strItemText = GetItemText( hItem );
00955                 if ( strItemText.Find(strText) == 0 )   // Item text starts with strText
00956                 {
00957                         // Insert at the same position the item handle and the string
00958                         hResults.InsertAt(strResults.InsertAtOrder(strItemText), hItem);
00959                 }                       
00960 
00961                 // Get first child node
00962                 HTREEITEM hNextItem = GetChildItem( hItem );
00963 
00964                 if ( !hNextItem )
00965                 {
00966                         // Get next sibling child
00967                         hNextItem = GetNextSiblingItem( hItem );
00968 
00969                         if ( !hNextItem )
00970                         {
00971                                 HTREEITEM hParentItem=hItem;
00972                                 while ( !hNextItem && hParentItem )
00973                                 {
00974                                         // No more children: Get next sibling to parent
00975                                         hParentItem = GetParentItem( hParentItem );
00976                                         hNextItem = GetNextSiblingItem( hParentItem );
00977                                 }
00978                         }
00979                 }
00980 
00981                 hItem = hNextItem;
00982         }
00983 
00984         return strResults.GetSize();
00985 
00986 }
00987 
00988 
00990 // Retreives a tree ctrl item given the item's data
00991 
00992 HTREEITEM CTreeCtrlEx::ItemFromData(DWORD_PTR dwData, HTREEITEM hStartAtItem/*=NULL*/) const
00993 {
00994         // Traverse all items in tree control
00995         HTREEITEM hItem;
00996         if ( hStartAtItem )
00997                 hItem = hStartAtItem;
00998         else
00999                 hItem = GetRootItem();
01000 
01001         while ( hItem )
01002         {
01003                 if ( dwData == GetItemData( hItem ) )
01004                         return hItem;
01005 
01006                 // Get first child node
01007                 HTREEITEM hNextItem = GetChildItem( hItem );
01008 
01009                 if ( !hNextItem )
01010                 {
01011                         // Get next sibling child
01012                         hNextItem = GetNextSiblingItem( hItem );
01013 
01014                         if ( !hNextItem )
01015                         {
01016                                 HTREEITEM hParentItem=hItem;
01017                                 while ( !hNextItem && hParentItem )
01018                                 {
01019                                         // No more children: Get next sibling to parent
01020                                         hParentItem = GetParentItem( hParentItem );
01021                                         hNextItem = GetNextSiblingItem( hParentItem );
01022                                 }
01023                         }
01024                 }
01025 
01026                 hItem = hNextItem;
01027         }
01028 
01029         return NULL;
01030 }
01031 
01032 
01034 // Global function to retreive a HTREEITEM from a tree control, given the 
01035 // item's itemdata.
01036 
01037 HTREEITEM GetTreeItemFromData(CTreeCtrl& treeCtrl, DWORD_PTR dwData, HTREEITEM hStartAtItem /*=NULL*/)
01038 {
01039         // Traverse from given item (or all items if hFromItem is NULL)
01040         HTREEITEM hItem;
01041         if ( hStartAtItem )
01042                 hItem=hStartAtItem;
01043         else
01044                 hItem = treeCtrl.GetRootItem();
01045 
01046         while ( hItem )
01047         {
01048                 if ( dwData == treeCtrl.GetItemData( hItem ) )
01049                         return hItem;
01050 
01051                 // Get first child node
01052                 HTREEITEM hNextItem = treeCtrl.GetChildItem( hItem );
01053 
01054                 if ( !hNextItem )
01055                 {
01056                         // Get next sibling child
01057                         hNextItem = treeCtrl.GetNextSiblingItem( hItem );
01058 
01059                         if ( !hNextItem )
01060                         {
01061                                 HTREEITEM hParentItem=hItem;
01062                                 while ( !hNextItem && hParentItem )
01063                                 {
01064                                         // No more children: Get next sibling to parent
01065                                         hParentItem = treeCtrl.GetParentItem( hParentItem );
01066                                         hNextItem = treeCtrl.GetNextSiblingItem( hParentItem );
01067                                 }
01068                         }
01069                 }
01070                 hItem = hNextItem;
01071         }
01072         return NULL;
01073 }
01074 
01075 
01076 // Tihamer Levendovszky 02/25/02
01077 BOOL CTreeCtrlEx::CreateDragImageEx(CPoint ptDragPoint)
01078 {
01079          if (GetSelectedCount() <= 0)
01080           return FALSE; // no row selected
01081 
01082          CRect rectSingle;
01083          CRect rectText;
01084          CRect rectComplete(0,0,0,0);
01085 
01086          HTREEITEM hItem;
01087 
01088          // Putting together the bounding rectangle
01089          for(hItem=GetFirstSelectedItem();hItem;hItem=GetNextSelectedItem(hItem))
01090          {
01091                 CImageList* pSingleImageList = CreateDragImage(hItem);
01092                 IMAGEINFO ImageInfo;
01093                 
01094                 // The image bounding rectangle is zero based - but has the correct size
01095                 // GetItemRect correct in offset, but does not contain icon size
01096                 pSingleImageList->GetImageInfo(0,&ImageInfo);                           
01097                 GetItemRect(hItem,rectSingle,TRUE);     
01098                 rectSingle.left=rectSingle.right-ImageInfo.rcImage.right;
01099 
01100                 pSingleImageList->DeleteImageList();
01101                 delete pSingleImageList;
01102                 
01103                 rectComplete.UnionRect(rectComplete, rectSingle);
01104          }
01105 
01106          CClientDC dcClient(this);
01107          CDC dcMem;
01108          CBitmap Bitmap;
01109 
01110          if (!dcMem.CreateCompatibleDC(&dcClient))
01111           return FALSE;
01112 
01113          if (!Bitmap.CreateCompatibleBitmap(&dcClient, 
01114                  rectComplete.Width(), 
01115                  rectComplete.Height()))
01116           return FALSE;
01117 
01118          CBitmap *pOldMemDCBitmap = dcMem.SelectObject(&Bitmap);
01119 
01120          COLORREF cMaskColor=RGB(0,255,0);
01121          dcMem.FillSolidRect(0, 0, 
01122                                                  rectComplete.Width(), 
01123                                                  rectComplete.Height(), 
01124                                                  cMaskColor);
01125 
01126          // Paint each DragImage in the DC
01127          for(hItem=GetFirstSelectedItem();hItem;hItem=GetNextSelectedItem(hItem))
01128          {                
01129                   CImageList* pSingleImageList = CreateDragImage(hItem);
01130 
01131                   if (pSingleImageList)
01132                   {
01133                                                 
01134                         // The image bounding rectangle is zero based - but has the correct size
01135                         // GetItemRect correct in offset, but does not contain icon size
01136                         IMAGEINFO ImageInfo;
01137                         pSingleImageList->GetImageInfo(0,&ImageInfo);                           
01138                         GetItemRect(hItem,rectSingle,TRUE);     
01139                         rectSingle.left=rectSingle.right-ImageInfo.rcImage.right;
01140 
01141                     pSingleImageList->Draw(&dcMem, 
01142                         0, 
01143                         CPoint(rectSingle.left - rectComplete.left,
01144                         rectSingle.top - rectComplete.top), 
01145                         ILD_TRANSPARENT);
01146 
01147 /*                      #ifdef _DEBUG
01148                                    CDC *pWndDC=GetDC();
01149                                    pSingleImageList->Draw(pWndDC,
01150                                         0, 
01151                                         CPoint(rectSingle.left - rectComplete.left,
01152                                         rectSingle.top - rectComplete.top), 
01153                                         ILD_TRANSPARENT);       
01154                                    ReleaseDC(pWndDC);
01155                         #endif
01156 */
01157                    pSingleImageList->DeleteImageList();
01158                    delete pSingleImageList;
01159                   }
01160          }
01161 /*
01162                         #ifdef _DEBUG
01163                                    CDC *pWndDC=GetDC();
01164                                    BitBlt(pWndDC->GetSafeHdc(),0,0,rectComplete.Width(),rectComplete.Height(),dcMem.GetSafeHdc(),0,0,SRCCOPY);
01165                                    ReleaseDC(pWndDC);
01166                         #endif
01167 */
01168          dcMem.SelectObject(pOldMemDCBitmap);
01169 
01170 
01171          if(m_CurrentDragImage.GetSafeHandle()!=NULL)
01172          {
01173                  m_CurrentDragImage.DeleteImageList();
01174          }
01175 
01176          m_CurrentDragImage.Create(rectComplete.Width(), 
01177                                                                 rectComplete.Height(), 
01178                                                                 ILC_COLOR | ILC_MASK, 
01179                                                                 0, 1);
01180 
01181          // Green is used as mask color
01182          m_CurrentDragImage.Add(&Bitmap, cMaskColor); 
01183 
01184 
01185 
01186          Bitmap.DeleteObject();
01187 
01188          m_ptHotSpot.x = ptDragPoint.x-rectComplete.left;
01189          m_ptHotSpot.y = ptDragPoint.y-rectComplete.top;
01190 
01191 
01192          return TRUE;
01193 
01194 }
01195 
01196 // Tihamer Levendovszky 02/25/02
01197 void CTreeCtrlEx::DeleteDragImageEx()
01198 {
01199         m_CurrentDragImage.DeleteImageList();
01200 }
01201 
01202 // Tihamer Levendovszky 02/25/02
01203 void CTreeCtrlEx::ScrollUp()
01204 {
01205 
01206         HTREEITEM hItem=GetFirstVisibleItem();
01207         HTREEITEM hPrevSibling=GetPrevSiblingItem(hItem);
01208         HTREEITEM hParent=GetParentItem(hItem);
01209 
01210         if(hItem)
01211         {
01212                 if(hPrevSibling)
01213                 {
01214                         SelectSetFirstVisible(hPrevSibling);
01215                 }
01216                 else if(hParent)
01217                 {
01218                         SelectSetFirstVisible(hParent);
01219                 }
01220         }
01221                          
01222 }