home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 8090 / ModelEdit.7z / ltwintreemgr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-03-08  |  18.6 KB  |  804 lines

  1. #include "ltwintreemgr.h"
  2. #include "ltwintreeitemiter.h"
  3. #include "ltwintreeitem.h"
  4.  
  5. BEGIN_MESSAGE_MAP(CLTWinTreeMgr, CTreeCtrl)
  6.     ON_NOTIFY_REFLECT(TVN_BEGINLABELEDIT,    OnBeginEditText)
  7.     ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT,        OnEndEditText)
  8.     ON_NOTIFY_REFLECT(TVN_BEGINDRAG,        OnBeginDrag)
  9.     ON_NOTIFY_REFLECT(TVN_SELCHANGED,        OnSelChanged)
  10.     ON_WM_MOUSEMOVE()
  11.     ON_WM_LBUTTONUP()
  12.     ON_WM_LBUTTONDOWN()
  13. END_MESSAGE_MAP()
  14.  
  15. //default constructor
  16. CLTWinTreeMgr::CLTWinTreeMgr() :
  17.     m_pRoot(NULL),
  18.     m_bEditText(FALSE),
  19.     m_bDragDrop(FALSE),
  20.     m_bDragging(FALSE),
  21.     m_pDragImage(NULL),
  22.     m_pDragItem(NULL),
  23.     m_bMultiSelect(FALSE),
  24.     m_pfnChangeSel(NULL),
  25.     m_nChangeSelUserData(0)
  26. {
  27.     //create the image list to hold the icons in
  28.     m_ImageList.Create(16, 16, ILC_COLOR, 1, 1);
  29. }
  30.  
  31. //default destructor
  32. CLTWinTreeMgr::~CLTWinTreeMgr()
  33. {
  34.     DeleteTree();
  35. }
  36.  
  37.  
  38. //adds a newly created item to the tree after belonging to the specified parent
  39. // If the parent is NULLITEM it is added as a sibling to the root. It will fail
  40. // if it cannot find the appropriate parent. This object is then orphaned, and
  41. // it is the tree manager's responsibility to release the memory. Due to this
  42. // all the items MUST be created on the heap using new. The return value is the
  43. // key for the new item, which uniquely identifies it. Keys CANNOT be
  44. // transferred between trees
  45. CLTWinTreeKey CLTWinTreeMgr::AddItem(    CLTWinTreeItem* pNewItem, 
  46.                                         CLTWinTreeKey Parent,
  47.                                         BOOL bSortChildren)
  48. {
  49.     //sanity check
  50.     if(pNewItem == NULL)
  51.     {
  52.         return NULLITEM;
  53.     }
  54.  
  55.     //first add into the tree heiarchy
  56.  
  57.     //create a pointer to the parent
  58.     CLTWinTreeItem* pParent = KeyToItem(Parent);
  59.     HTREEITEM hParent = TVI_ROOT;
  60.  
  61.     //see if it belongs to the root
  62.     if(pParent == NULL)
  63.     {
  64.         //setup the item
  65.         pNewItem->m_pNextSibling    = m_pRoot;
  66.         pNewItem->m_pPrevSibling    = NULL;
  67.         pNewItem->m_pParent            = NULL;
  68.         pNewItem->m_pFirstChild        = NULL;
  69.  
  70.         //setup the back link from the first root item
  71.         if(m_pRoot)
  72.         {
  73.             m_pRoot->m_pPrevSibling = pNewItem;
  74.         }
  75.  
  76.         //setup the owner
  77.         m_pRoot = pNewItem;
  78.     }
  79.     else
  80.     {
  81.         //doesn't belong to root, so add it to the parent item
  82.  
  83.         //setup the item
  84.         pNewItem->m_pNextSibling    = pParent->m_pFirstChild;
  85.         pNewItem->m_pPrevSibling    = NULL;
  86.         pNewItem->m_pParent            = pParent;
  87.         pNewItem->m_pFirstChild        = NULL;
  88.  
  89.         //setup the link of the first sibling back to this one
  90.         if(pParent->m_pFirstChild)
  91.         {
  92.             pParent->m_pFirstChild->m_pPrevSibling = pNewItem;
  93.         }
  94.  
  95.         //setup the owner
  96.         pParent->m_pFirstChild = pNewItem;
  97.         hParent = pParent->m_hTreeItem;
  98.     }    
  99.  
  100.     //add it to the control, use different methods depending on
  101.     //if it has an icon or not
  102.     if(pNewItem->GetIcon() >= 0)
  103.     {
  104.         pNewItem->m_hTreeItem = InsertItem(    pNewItem->GetText(), 
  105.                                         pNewItem->GetIcon(),
  106.                                         pNewItem->GetIcon(),
  107.                                         hParent);
  108.     }
  109.     else
  110.     {
  111.         pNewItem->m_hTreeItem = InsertItem(    pNewItem->GetText(), hParent);
  112.     }
  113.  
  114.     //set the item data as a pointer to the list item
  115.     SetItemData(pNewItem->m_hTreeItem, (DWORD)pNewItem);
  116.  
  117.     if(bSortChildren)
  118.     {
  119.         //make sure the children are in alphabetacal ordering
  120.         SortChildren(hParent);
  121.     }
  122.  
  123.  
  124.     //now give the user the key back
  125.     return ItemToKey(pNewItem);
  126. }
  127.  
  128.  
  129. //deletes a specified item from the tree as well as its children. Returns
  130. //true if it successfully found and deleted the item, false otherwise
  131. BOOL CLTWinTreeMgr::DeleteItem(CLTWinTreeKey Item)
  132. {
  133.     //sanity check
  134.     if(Item == NULLITEM)
  135.     {
  136.         return FALSE;
  137.     }
  138.  
  139.     //get a pointer to the actual object
  140.     CLTWinTreeItem* pItem = KeyToItem(Item);
  141.  
  142.     //start off by recursively deleting all its children
  143.     while(pItem->m_pFirstChild)
  144.     {
  145.         DeleteItem(ItemToKey(pItem->m_pFirstChild));
  146.     }
  147.  
  148.     //unlink the item
  149.     UnlinkFromSiblings(pItem);
  150.  
  151.     //remove the item from the actual control if the window is still valid
  152.     //(this check needs to be done so it can be destroyed, but if it is called
  153.     //after the window has been destroyed and the tree items already freed)
  154.     if(m_hWnd)
  155.     {
  156.         CTreeCtrl::DeleteItem(pItem->m_hTreeItem);
  157.     }
  158.  
  159.     delete pItem;
  160.     return TRUE;
  161. }
  162.  
  163.  
  164. //creates an iterator that begins iterating through the root
  165. CLTWinTreeItemIter* CLTWinTreeMgr::CreateIter()
  166. {
  167.     if(m_pRoot)
  168.     {
  169.         return m_pRoot->CreateSiblingIter();
  170.     }
  171.     return NULL;
  172. }
  173.  
  174.  
  175. //sets the text of an item given a key
  176. BOOL CLTWinTreeMgr::SetItemText(CLTWinTreeKey Item, const char* pszText)
  177. {
  178.     //sanity check
  179.     if(Item == NULLITEM)
  180.     {
  181.         return FALSE;
  182.     }
  183.  
  184.     CLTWinTreeItem* pItem = KeyToItem(Item);
  185.  
  186.     //modify the actual object
  187.     pItem->m_sText = pszText;
  188.  
  189.     //modify the control
  190.     CTreeCtrl::SetItemText(pItem->m_hTreeItem, pszText);
  191.  
  192.     return TRUE;
  193. }
  194.  
  195. //sets the icon of an item given a key
  196. BOOL CLTWinTreeMgr::SetItemIcon(CLTWinTreeKey Item, CLTWinTreeIcon Icon)
  197. {
  198.     //sanity check
  199.     if(Item == NULLITEM)
  200.     {
  201.         return FALSE;
  202.     }
  203.  
  204.     CLTWinTreeItem* pItem = KeyToItem(Item);
  205.  
  206.     //modify the actual object
  207.     pItem->m_Icon = Icon;
  208.  
  209.     //modify the control
  210.     CTreeCtrl::SetItemImage(pItem->m_hTreeItem, Icon, Icon);
  211.  
  212.     return TRUE;
  213. }
  214.  
  215.  
  216.  
  217. //converts a key to an item
  218. CLTWinTreeItem* CLTWinTreeMgr::KeyToItem(CLTWinTreeKey Key)
  219. {
  220.     return (CLTWinTreeItem*)Key;
  221. }
  222.  
  223.  
  224. //converts an item to a key
  225. CLTWinTreeKey CLTWinTreeMgr::ItemToKey(CLTWinTreeItem* pItem)
  226. {
  227.     return (CLTWinTreeKey)pItem;
  228. }
  229.  
  230.  
  231. //deletes the entire tree
  232. void CLTWinTreeMgr::DeleteTree()
  233. {
  234.     //just delete every single item
  235.     while(m_pRoot)
  236.     {
  237.         DeleteItem(ItemToKey(m_pRoot));
  238.     }
  239. }
  240.  
  241. //this will visit each node in turn, and call the passed calback
  242. //in once per item. It will continue iteration as long as the
  243. //function returns true and there are items left to be iterated.
  244. //it performs a depth first search to get each item. In addition,
  245. //the user data will be passed to the function each time it is
  246. //called. It will begin at the passed in node and visit all of the
  247. //children of that node. If it is null, it will start at the root
  248. void CLTWinTreeMgr::VisitEachItem(VisitCallback CallbackFunc, DWORD UserData, CLTWinTreeKey Start)
  249. {
  250.     //first get the iterator
  251.     CLTWinTreeItemIter* pIter;
  252.  
  253.     if(Start == NULLITEM)
  254.     {
  255.         //it is a root iterator we need
  256.         pIter = CreateIter();
  257.     }
  258.     else
  259.     {
  260.         //it is a child iterator
  261.         CLTWinTreeItem* pItem = KeyToItem(Start);
  262.         pIter = pItem->CreateChildIter();
  263.     }
  264.  
  265.     //make sure the iterator is valid
  266.     if(pIter == NULL)
  267.     {
  268.         return;
  269.     }
  270.  
  271.     //now visit each node
  272.     for(; pIter->IsMore(); pIter->Next() )
  273.     {
  274.         CallbackFunc(pIter->Current(), this, UserData);
  275.         //recursively visit the items
  276.         VisitEachItem(CallbackFunc, UserData, ItemToKey(pIter->Current()));
  277.     }
  278.  
  279.     //clean up
  280.     delete pIter;
  281. }
  282.  
  283. //adds an icon to the available list, and returns the index that
  284. //will refer to the icon
  285. int CLTWinTreeMgr::AddIcon(LPCTSTR pszIcon)
  286. {
  287.     //load the icon
  288.     HICON hIcon = LoadIcon(AfxGetInstanceHandle(), pszIcon);
  289.  
  290.     //add it to the image list
  291.     int rv = m_ImageList.Add(hIcon);
  292.  
  293.     //delete the icon
  294.     DestroyIcon(hIcon);
  295.  
  296.     //make sure the image list is installed
  297.     SetImageList(&m_ImageList, TVSIL_NORMAL);
  298.  
  299.     //return the index
  300.     return rv;
  301. }
  302.  
  303.  
  304. //enables the dragging and dropping of items
  305. void CLTWinTreeMgr::EnableDragDrop(BOOL bEnable)
  306. {
  307.     //modify the window flags
  308.     if(bEnable)
  309.     {
  310.         ModifyStyle(TVS_DISABLEDRAGDROP, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);   
  311.     }
  312.     else
  313.     {
  314.         ModifyStyle(0, TVS_DISABLEDRAGDROP, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);   
  315.     }
  316.  
  317.     //save the flag
  318.     m_bDragDrop = bEnable;
  319. }
  320.  
  321. //enables the editing of text in the control
  322. void CLTWinTreeMgr::EnableEditText(BOOL bEnable)
  323. {
  324.     //modify the window flags
  325.     if(bEnable)
  326.     {
  327.         ModifyStyle(0, TVS_EDITLABELS, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);   
  328.     }
  329.     else
  330.     {
  331.         ModifyStyle(TVS_EDITLABELS, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);   
  332.     }
  333.  
  334.     //save the flag
  335.     m_bEditText = bEnable;
  336. }
  337.  
  338.  
  339. void CLTWinTreeMgr::OnBeginEditText(NMHDR* pHdr, LRESULT* pResult)
  340. {
  341.     //get the correct pointer
  342.     LPNMTVDISPINFO pTreeView = (LPNMTVDISPINFO)pHdr;
  343.  
  344.     //get the item it is pointing to
  345.     CLTWinTreeItem* pItem = (CLTWinTreeItem*)(pTreeView->item.lParam);
  346.  
  347.     //if we can't edit the label, return TRUE to cancel it
  348.     *pResult = (m_bEditText && pItem->IsTextEditable()) ? FALSE : TRUE;
  349. }
  350.  
  351. void CLTWinTreeMgr::OnEndEditText(NMHDR* pHdr, LRESULT* pResult)
  352. {
  353.     //get the correct pointer
  354.     LPNMTVDISPINFO pTreeView = (LPNMTVDISPINFO)pHdr;
  355.  
  356.     //get the item it is pointing to
  357.     CLTWinTreeItem* pItem = (CLTWinTreeItem*)(pTreeView->item.lParam);
  358.  
  359.     //see if the user cancelled out of the operation
  360.     if(pTreeView->item.pszText == NULL)
  361.     {
  362.         *pResult = FALSE;
  363.     }
  364.     else
  365.     {
  366.         //they didn't cancel out, so lets set the text
  367.         SetItemText(ItemToKey(pItem), pTreeView->item.pszText);
  368.  
  369.         // let the parent know about the change
  370.         GetParent()->SendMessage( WM_LTTREE_EDITTEXT, (WPARAM)this, (LPARAM)pItem );
  371.  
  372.         *pResult = TRUE;
  373.     }
  374. }
  375.  
  376. void CLTWinTreeMgr::OnBeginDrag(NMHDR* pHdr, LRESULT* pResult)
  377. {
  378.     if(m_bDragDrop)
  379.     {
  380.         ClearSelection();
  381.  
  382.         //get the correct pointer
  383.         LPNMTREEVIEW pTreeView = (LPNMTREEVIEW)pHdr;
  384.  
  385.         //set the flag that we are dragging
  386.         m_bDragging = TRUE;
  387.  
  388.         //save the item being dragged
  389.         m_pDragItem = (CLTWinTreeItem*)(pTreeView->itemNew.lParam);
  390.  
  391.         //create the image list, and make sure it is valid
  392.         m_pDragImage = CreateDragImage(pTreeView->itemNew.hItem);
  393.  
  394.         //capture the mouse to ensure we get the button up command
  395.         SetCapture();
  396.  
  397.         if(m_pDragImage)
  398.         {    
  399.             //setup the drag image list
  400.             if(m_pDragImage->BeginDrag(0, CPoint(0, 0)) == FALSE)
  401.             {
  402.                 delete m_pDragImage;
  403.                 m_pDragImage = NULL;
  404.             }
  405.         }
  406.  
  407.  
  408.     }
  409. }
  410.  
  411. //returns a pointer to a valid drop target if one exists, otherwise
  412. //NULL
  413. CLTWinTreeItem*    CLTWinTreeMgr::GetDropTarget(CPoint pt)
  414. {
  415.     //make sure we are in a drag operation
  416.     if(!IsInDrag())
  417.     {
  418.         return NULL;
  419.     }
  420.  
  421.     //see what item we hit
  422.     HTREEITEM hHit = HitTest(pt);
  423.  
  424.     if(hHit)
  425.     {
  426.         //we hit something, get the item
  427.         CLTWinTreeItem* pItem = (CLTWinTreeItem*)GetItemData(hHit);
  428.  
  429.         //see if this is a drop target
  430.         if(pItem->IsDropTarget(m_pDragItem))
  431.         {
  432.             //it is a drop target, but is it a child of the dragged item,
  433.             //because you can't have them moving itself to a child
  434.             if(m_pDragItem->ContainsObject(pItem) == FALSE)
  435.             {
  436.                 return pItem;
  437.             }
  438.         }
  439.     }
  440.  
  441.     //couldn't find a valid hit target
  442.     return NULL;
  443. }
  444.  
  445.  
  446. void CLTWinTreeMgr::OnMouseMove(UINT nFlags, CPoint pt)
  447. {
  448.     CTreeCtrl::OnMouseMove(nFlags, pt);
  449.  
  450.     //make sure we are in a drag operation
  451.     if(!IsInDrag())
  452.     {
  453.         return;
  454.     }
  455.  
  456.  
  457.     //hilite the drop target if one exists
  458.     CLTWinTreeItem* pHit = GetDropTarget(pt);
  459.  
  460.     if(pHit)
  461.     {
  462.         //this is a valid drop target, so make it look like one
  463.         SelectDropTarget(pHit->m_hTreeItem);
  464.     }
  465.  
  466.     //move the drag image
  467.     if(m_pDragImage)
  468.     {
  469.         m_pDragImage->DragMove(pt);
  470.     }
  471.  
  472.  
  473. }
  474.  
  475. void CLTWinTreeMgr::OnLButtonUp(UINT nFlags, CPoint pt)
  476. {
  477.     CTreeCtrl::OnLButtonUp(nFlags, pt);
  478.  
  479.     //make sure we are in a drag operation
  480.     if(!IsInDrag())
  481.     {
  482.         return;
  483.     }
  484.  
  485.     //see if we have a place to drop it
  486.     CLTWinTreeItem* pHit = GetDropTarget(pt);
  487.  
  488.     if(pHit)
  489.     {
  490.         //we are moving it, so lets make the move
  491.  
  492.         //first erase the old tree
  493.         CTreeCtrl::DeleteItem(m_pDragItem->m_hTreeItem);
  494.  
  495.         //unlink the item
  496.         UnlinkFromSiblings(m_pDragItem);
  497.  
  498.         //now build the new tree  recursively
  499.         RebuildDraggedTree(m_pDragItem, pHit);
  500.  
  501.         //select the moved item
  502.         CTreeCtrl::SelectItem(m_pDragItem->m_hTreeItem);
  503.     }
  504.  
  505.     //clear the drop target
  506.     SelectDropTarget(NULL);
  507.  
  508.     //clean up the drag stuff
  509.     m_bDragging        = FALSE;
  510.     m_pDragItem        = NULL;
  511.  
  512.     //clean up the image list
  513.     if(m_pDragImage)
  514.     {
  515.         m_pDragImage->EndDrag();
  516.         delete m_pDragImage;
  517.         m_pDragImage    = NULL;
  518.     }
  519.  
  520.     //clean up the cursor
  521.     ReleaseCapture();
  522.  
  523.  
  524. }
  525.  
  526. //recursively builds a dragged tree as a parent to the passed in
  527. //item.
  528. void CLTWinTreeMgr::RebuildDraggedTree(CLTWinTreeItem* pItem, CLTWinTreeItem* pParent)
  529. {
  530.     //save the child pointer since it will be lost in add item
  531.     CLTWinTreeItem* pChild = pItem->m_pFirstChild;
  532.  
  533.     //add the item to the parent
  534.     AddItem(pItem, pParent);
  535.  
  536.     //now recurse on all children
  537.     while(pChild)
  538.     {
  539.         //save the next node, since that will be lost in the function
  540.         CLTWinTreeItem* pNext = pChild->m_pNextSibling;
  541.         //recurse
  542.         RebuildDraggedTree(pChild, pItem);
  543.         //move on to the next item
  544.         pChild = pNext;
  545.     }
  546. }
  547.  
  548. //unlinks the item from all surrounding siblings
  549. void CLTWinTreeMgr::UnlinkFromSiblings(CLTWinTreeItem* pItem)
  550. {
  551.     //see if it is first in list
  552.     if(pItem->m_pPrevSibling == NULL)
  553.     {
  554.         //it is, so we need to adjust the parent's first child ptr
  555.         if(pItem->m_pParent)
  556.         {
  557.             //has a parent
  558.             pItem->m_pParent->m_pFirstChild = pItem->m_pNextSibling;
  559.         }
  560.         else
  561.         {
  562.             //doesn't have a parent, belongs to the root, need to adjust
  563.             //starting root node
  564.             m_pRoot = pItem->m_pNextSibling;
  565.         }
  566.     }
  567.     else
  568.     {
  569.         //has a previous sibling, link that to the next sibling
  570.         pItem->m_pPrevSibling->m_pNextSibling = pItem->m_pNextSibling;
  571.     }
  572.  
  573.     //now need to adjust the next sibling to point to the prev
  574.     if(pItem->m_pNextSibling)
  575.     {
  576.         pItem->m_pNextSibling->m_pPrevSibling = pItem->m_pPrevSibling;
  577.     }
  578. }
  579.  
  580.  
  581. void CLTWinTreeMgr::OnLButtonDown(UINT nFlags, CPoint pt)
  582. {
  583.     //determine if we are in multiple node selection. If
  584.     //we aren't, just pass it back to the base class
  585.     if(m_bMultiSelect == FALSE)
  586.     {
  587.         CTreeCtrl::OnLButtonDown(nFlags, pt);
  588.         return;
  589.     }
  590.  
  591.     //get the hit item
  592.     HTREEITEM hHit = HitTest(pt);
  593.  
  594.     //make sure we hit something
  595.     if(hHit == NULL)
  596.     {
  597.         ClearSelection();
  598.         return;
  599.     }
  600.  
  601.     CLTWinTreeItem* pItem = (CLTWinTreeItem*)GetItemData(hHit);
  602.     
  603.  
  604.     if(pItem)
  605.     {
  606.         //see what modifiers are active
  607.  
  608.         //only go into the shift if there is already an item selected, and
  609.         //if the two items are contained under the same parent
  610.         if(    (nFlags & MK_SHIFT) && 
  611.             m_pFirstSelected && 
  612.             (pItem->m_pParent == m_pFirstSelected->m_pParent))
  613.         {
  614.             //get the handle to the parent tree item
  615.             HTREEITEM hParent = (pItem->m_pParent) ? pItem->m_pParent->m_hTreeItem : TVI_ROOT;
  616.             //get the first child
  617.             HTREEITEM hCur = GetChildItem(hParent);
  618.  
  619.             //clear out the entire selection
  620.             ClearSelection();
  621.  
  622.             BOOL bSelect = FALSE;
  623.  
  624.             //go through all children
  625.             while(hCur)
  626.             {
  627.                 //see if we have entered the range
  628.                 if((hCur == m_pFirstSelected->m_hTreeItem) || (hCur == hHit))
  629.                 {
  630.                     //we have, so toggle the flag
  631.                     bSelect = (bSelect) ? FALSE : TRUE;
  632.                     MultiSelectItem(hCur, TRUE);
  633.                 }
  634.                 else if(bSelect)
  635.                 {
  636.                     //we are in the range, so set the item to true
  637.                     MultiSelectItem(hCur, TRUE);
  638.                 }
  639.                 hCur = GetNextSiblingItem(hCur);
  640.             }                        
  641.         }
  642.         else if(nFlags & MK_CONTROL)
  643.         {
  644.             //add this item to the selection
  645.             //or invert it if it is already selected
  646.             CLTWinTreeItem* pItem = (CLTWinTreeItem*)GetItemData(hHit);
  647.  
  648.             if(pItem)
  649.             {
  650.                 MultiSelectItem(hHit, (pItem->m_bSelected) ? FALSE : TRUE);
  651.                 //save the first selected if needed
  652.                 if(!m_pFirstSelected)
  653.                 {
  654.                     m_pFirstSelected = pItem;
  655.                 }
  656.             }
  657.         }
  658.         else
  659.         {
  660.             //they just want to select a single one
  661.             ClearSelection();
  662.             MultiSelectItem(hHit, TRUE);
  663.             //save the first selected
  664.             m_pFirstSelected = (CLTWinTreeItem*)GetItemData(hHit);
  665.         }
  666.     }
  667.  
  668.     CTreeCtrl::OnLButtonDown(nFlags, pt);
  669. }
  670.  
  671. //clears the selection, setting all item's flags for set to false
  672. void CLTWinTreeMgr::ClearSelection()
  673. {
  674.     VisitEachItem(ClearSelectCallback, 0);
  675. }
  676.  
  677. //callback function to visit each node and clear the selection flag
  678. BOOL CLTWinTreeMgr::ClearSelectCallback(CLTWinTreeItem* pItem, CLTWinTreeMgr* pMgr, DWORD)
  679. {
  680.     if(pItem->m_bSelected)
  681.     {
  682.         pMgr->MultiSelectItem(pItem->m_hTreeItem, FALSE);
  683.     }
  684.     return TRUE;
  685. }
  686.  
  687. // expand all items in the tree
  688. void CLTWinTreeMgr::ExpandAll( void )
  689. {
  690.     VisitEachItem( ExpandCollapseCallback, 0 );
  691. }
  692.  
  693. // collapse all items in the tree
  694. void CLTWinTreeMgr::CollapseAll( void )
  695. {
  696.     VisitEachItem( ExpandCollapseCallback, 1 );
  697. }
  698.  
  699. // callback funtion to visit each node and expand or collapse it (0=expand, 1=collapse)
  700. BOOL CLTWinTreeMgr::ExpandCollapseCallback( CLTWinTreeItem* item, CLTWinTreeMgr* mgr, DWORD collapse )
  701. {
  702.     mgr->Expand( item->m_hTreeItem, collapse ? TVE_COLLAPSE : TVE_EXPAND );
  703.     return TRUE;
  704. }
  705.  
  706. //selects a specified node in multiple selection mode
  707. void CLTWinTreeMgr::MultiSelectItem(HTREEITEM hItem, BOOL bSelect)
  708. {
  709.     //get the item
  710.     if(hItem == NULL)
  711.     {
  712.         return;
  713.     }
  714.  
  715.     CLTWinTreeItem* pItem = (CLTWinTreeItem*)GetItemData(hItem);
  716.  
  717.     if(pItem && (pItem->m_bSelected != bSelect))
  718.     {
  719.  
  720.         //save it
  721.         pItem->m_bSelected = bSelect;
  722.  
  723.         //set the flag to the appropriate item
  724.         SetItemState(hItem, (bSelect) ? TVIS_SELECTED : 0, TVIS_SELECTED);
  725.  
  726.         //trigger the callback
  727.         TriggerChangeSel(pItem);
  728.     }
  729. }
  730.  
  731. void CLTWinTreeMgr::OnSelChanged(NMHDR* pHdr, LRESULT* pResult)
  732. {
  733.     if(m_bMultiSelect)
  734.     {
  735.         //in multi select mode, we need to update the view
  736.         //to reflect the selected nodes, otherwise all the
  737.         //others are cleared
  738.         VisitEachItem(UpdateItemCallback, 0);
  739.         Invalidate();
  740.         *pResult = FALSE;
  741.     }
  742.     else
  743.     {
  744.         //in single selection node, we just need to make sure the selected node
  745.         //is tracked in the data tree
  746.  
  747.         //convert the pointer
  748.         LPNMTREEVIEW pView = (LPNMTREEVIEW)pHdr;
  749.  
  750.         //clear out any that could have been selected before
  751.         ClearSelection();
  752.  
  753.         //set the selected flag to true
  754.         MultiSelectItem(pView->itemNew.hItem, TRUE);
  755.     }        
  756. }
  757.  
  758. //callback function to visit each node and update their drawing method
  759. BOOL CLTWinTreeMgr::UpdateItemCallback(CLTWinTreeItem* pItem, CLTWinTreeMgr* pMgr, DWORD)
  760. {
  761.     //set the flag to the appropriate item
  762.     pMgr->SetItemState(pItem->m_hTreeItem, (pItem->m_bSelected) ? TVIS_SELECTED : 0, TVIS_SELECTED);
  763.     return TRUE;
  764. }
  765.  
  766. //enables multiple selection of nodes
  767. void CLTWinTreeMgr::EnableMultiSelect(BOOL bEnable)
  768. {
  769.     ClearSelection();
  770.     m_bMultiSelect = bEnable;
  771. }
  772.  
  773. //registers a callback for when selections change
  774. void CLTWinTreeMgr::RegisterCallback(ChangeSelCallback Callback, DWORD nUserData)
  775. {
  776.     m_pfnChangeSel = Callback;
  777.     m_nChangeSelUserData = nUserData;
  778. }
  779.  
  780. //unregisters the associated callback
  781. void CLTWinTreeMgr::UnregisterCallback()
  782. {
  783.     m_nChangeSelUserData = 0;
  784.     m_pfnChangeSel = NULL;
  785. }
  786. //triggers the change selection callback
  787. void CLTWinTreeMgr::TriggerChangeSel(CLTWinTreeItem* pItem)
  788. {
  789.     if(m_pfnChangeSel)
  790.     {
  791.         m_pfnChangeSel(pItem, this, m_nChangeSelUserData);
  792.     }
  793.  
  794.     // send the message to the parent window
  795.     GetParent()->SendMessage( WM_LTTREE_SELCHANGED, (WPARAM)this );
  796. }
  797.  
  798.  
  799. //determines if an item is currently being dragged
  800. BOOL CLTWinTreeMgr::IsInDrag() const
  801. {
  802.     return (m_bDragging && m_pDragItem) ? TRUE : FALSE;
  803. }
  804.