home *** CD-ROM | disk | FTP | other *** search
/ Mastering MFC Development / MMD.ISO / samples / c07 / treelist / treeview.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-20  |  11.4 KB  |  392 lines

  1. // TreeView.cpp : implementation file
  2. //
  3.  
  4. #include "stdafx.h"
  5. #include "tree.h"
  6.  
  7. #include "AnmlData.h"
  8. #include "treedoc.h"
  9.  
  10. #include "TreeView.h"
  11. #include "ListView.h"
  12.  
  13. #include "dialogs.h"
  14.  
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20.  
  21. /////////////////////////////////////////////////////////////////////////////
  22. // CSimpleTreeView
  23.  
  24. IMPLEMENT_DYNCREATE(CSimpleTreeView, CTreeView)
  25.  
  26. CSimpleTreeView::CSimpleTreeView()
  27. {
  28. }
  29.  
  30. CSimpleTreeView::~CSimpleTreeView()
  31. {
  32. }
  33.  
  34. BEGIN_MESSAGE_MAP(CSimpleTreeView, CTreeView)
  35.     //{{AFX_MSG_MAP(CSimpleTreeView)
  36.     ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged)
  37.     ON_WM_CREATE()
  38.     //}}AFX_MSG_MAP
  39. END_MESSAGE_MAP()
  40.  
  41. /////////////////////////////////////////////////////////////////////////////
  42. // CSimpleTreeView message handlers
  43.  
  44. void CSimpleTreeView::OnInitialUpdate() 
  45. {
  46.     CTreeView::OnInitialUpdate();
  47.  
  48.     GetTreeCtrl().ModifyStyle(NULL,
  49.                             TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT);
  50. }
  51.  
  52. void CSimpleTreeView::PopulateTree()
  53. {
  54.     GetTreeCtrl().DeleteAllItems();
  55.     GetDocument()->m_pListView->EraseList();
  56.     InsertRootNodes();
  57.     InsertDataNodes();
  58. }
  59.  
  60. void CSimpleTreeView::InsertRootNodes()
  61. {    
  62.     // For this simple program, where the tree goes at most 2 levels deep,
  63.     // item data will be 0 at all root nodes and -1 at all first level nodes.
  64.     // At second level nodes, item data will be the POSITION of a given node
  65.     // in the document object's CList member. Each node also contains a string.
  66.     // See OnSelchanged to see how these 2 pieces of information are extracted
  67.     // and used when the user clicks on a node in the tree control.
  68.  
  69.     CString s;
  70.     for (int i = IDS_AMPHIBIANS; i <= IDS_REPTILES; i++)
  71.     {
  72.         s.LoadString(i);
  73.         InsertNode(TVI_ROOT, s, 0);
  74.     }
  75. }
  76.  
  77. void CSimpleTreeView::InsertDataNodes()
  78. {
  79.     CTreeDoc* pDoc = GetDocument();
  80.  
  81.     // The idea here is to iterate over the document's CList object    and
  82.     // insert some data from each member of the CList into the tree control.
  83.     // Data not inserted in the tree will be shown in the list view when the
  84.     // user selects an item from the tree. The leaf nodes of the tree control
  85.     // will store a POSITION member that will facilitate searching the
  86.     // document's CList by the list view.
  87.     POSITION current, pos = pDoc->m_AnimalList.GetHeadPosition();
  88.     while (NULL != pos)
  89.     {
  90.         current = pos;
  91.         CAnimalInfo & rAnimal = pDoc->m_AnimalList.GetNext(pos);
  92.         LocateAndInsert(rAnimal, current);
  93.     }
  94. }
  95.  
  96. BOOL CSimpleTreeView::LocateAndInsert(const CAnimalInfo & Animal, const POSITION pos)
  97. {
  98.     HTREEITEM classnode, typenode;
  99.  
  100.     // Begin by locating the node where the item will be inserted.
  101.     // If the root node doesn't exist, return from function.
  102.     if ((classnode = FindNode(NULL, Animal.m_class)) == 0)
  103.         return FALSE;
  104.  
  105.     // Next, iterate over that node looking for the type,
  106.     // and insert type if it doesn't exist.
  107.     if ((typenode = FindNode(classnode, Animal.m_type)) == 0)
  108.         typenode = InsertNode(classnode, Animal.m_type, (DWORD)-1);
  109.  
  110.     if (0 == typenode)
  111.         return FALSE;
  112.  
  113.     // By this time we know we've got the class and the type.
  114.     // If the animal itself isn't already inserted, insert it.
  115.     if ((FindNode(typenode, Animal.m_animal)) == 0)
  116.         if (InsertNode(typenode, Animal.m_animal, (DWORD) pos) != 0)
  117.             return TRUE;
  118.     return FALSE;
  119. }
  120.  
  121. // The function iterates over the children of ParentNode looking for a match.
  122. // If ParentNode is NULL, the search starts in the root, otherwise it starts
  123. // in the designated node. Returns NULL if not found, the HTREEITEM if found.
  124. HTREEITEM CSimpleTreeView::FindNode(const HTREEITEM ParentNode, const CString &str) const
  125. {
  126.     CTreeCtrl & ctc = GetTreeCtrl();
  127.     HTREEITEM node;
  128.     CString s;
  129.  
  130.     if (NULL == ParentNode)
  131.         node = ctc.GetRootItem();
  132.     else
  133.         if (ctc.GetRootItem() == ParentNode)
  134.             node = ParentNode;
  135.         else
  136.             node = ctc.GetChildItem(ParentNode);
  137.     
  138.     while (node != NULL)
  139.     {
  140.         s = ctc.GetItemText(node);
  141.         // Halt the search when we find what we're looking for.
  142.         if (0 == s.CompareNoCase(str))
  143.             return node;
  144.         node = ctc.GetNextItem(node, TVGN_NEXT);
  145.     }
  146.     // If we get to here, string was never found, and node == NULL.
  147.     return node;
  148. }
  149.  
  150. HTREEITEM CSimpleTreeView::InsertNode(const HTREEITEM ParentNode,  const CString &str, const DWORD itemData)
  151. {
  152.     CTreeCtrl & ctc = GetTreeCtrl();
  153.     HTREEITEM node;
  154.  
  155.     node = ctc.InsertItem(str, ParentNode, TVI_SORT);
  156.     ctc.SetItemData(node, itemData);
  157.  
  158.     return node;
  159. }
  160.  
  161. void CSimpleTreeView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) 
  162. {
  163.     NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  164.  
  165.     *pResult = 0;
  166.  
  167.     // Obtain a reference to the CTreeControl object that is
  168.     // embedded in this view class.
  169.     CTreeCtrl & ctlTree = GetTreeCtrl();
  170.     
  171.     // Determining which item the user has selected is a 2-step
  172.     // process. You first obtain the handle to the selected item.
  173.     HTREEITEM selectedNode = ctlTree.GetSelectedItem();
  174.  
  175.     // In the second step, you call a specific function
  176.     // (GetItemText, GetItemData, GetItemState or GetItemImage)
  177.     // to obtain a specific piece of information from the selected item,
  178.     DWORD itemData = ctlTree.GetItemData(selectedNode);
  179.  
  180.     CTreeDoc * pDoc = GetDocument();
  181.     switch (itemData)
  182.     {
  183.         case 0:
  184.             // For root nodes, the list will iterate over the selected
  185.             // item and display all the types it contains.
  186.             pDoc->m_pListView->DisplayClassInfo(selectedNode);
  187.             break;
  188.         case -1:
  189.             // In the case of a level 1 node, give it the HTREEITEM
  190.             // and let it iterate over that node's children.
  191.             pDoc->m_pListView->DisplayTypeInfo(selectedNode);
  192.             break;
  193.         default:
  194.             // For level 2 nodes, the selected item's data contains
  195.             // its POSITION in the document object's CList.
  196.             pDoc->m_pListView->DisplayAnimalInfo(itemData);
  197.     }
  198. }
  199.  
  200. int CSimpleTreeView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  201. {
  202.     if (CTreeView::OnCreate(lpCreateStruct) == -1)
  203.         return -1;
  204.     
  205.     // Initialize the document object's pointer to the tree
  206.     // view object.
  207.     GetDocument()->m_pTreeView = this;
  208.  
  209.     return 0;
  210. }
  211. void CSimpleTreeView::ModifySelection()
  212. {
  213.     // Obtain a reference to the CTreeControl object.
  214.     CTreeCtrl & ctlTree = GetTreeCtrl();
  215.     
  216.     // Obtain the handle of the selected item.
  217.     HTREEITEM selectedNode = ctlTree.GetSelectedItem();
  218.  
  219.     // If item data indicates it's at level 0, do nothing.
  220.     // At level one, let the user change the spelling of the animal's type. 
  221.     // Otherwise, let the user modify the animal's name or weight,
  222.     // but not its class or type.
  223.     DWORD itemData = ctlTree.GetItemData(selectedNode);
  224.     switch (itemData)
  225.     {
  226.         case 0:
  227.             break;
  228.         case -1:
  229.             ModifyType(selectedNode, itemData);
  230.             break;
  231.         default:
  232.             ModifyAnimal(selectedNode, itemData);
  233.     }
  234. }
  235.  
  236. void CSimpleTreeView::DeleteSelection()
  237. {
  238.     // Obtain a reference to the CTreeControl object.
  239.     CTreeCtrl & ctlTree = GetTreeCtrl();
  240.     
  241.     // Obtain the handle of the selected item.
  242.     HTREEITEM selectedNode = ctlTree.GetSelectedItem();
  243.  
  244.     // If item data indicates it's at level 0 or -1 do nothing.
  245.     // Otherwise, confirm the deletion, delete the item from the tree,
  246.     // then delete it from the CList.
  247.     DWORD itemData = ctlTree.GetItemData(selectedNode);
  248.  
  249.     if (0 == itemData || -1 == itemData)
  250.         return;
  251.  
  252.     CString AnimalName = ctlTree.GetItemText(selectedNode);
  253.     CString s;
  254.     s.Format("Are you sure you want to delete '%s' from the database?",
  255.              AnimalName);
  256.     int rc = MessageBox(s, "Confirm Deletion", MB_YESNO | MB_ICONQUESTION);
  257.     if (IDNO == rc)
  258.         return;
  259.  
  260.     // Before deleting the selected item, obtain a handle to its parent.
  261.     HTREEITEM parent = ctlTree.GetParentItem(selectedNode);
  262.  
  263.     // Remove the selected item from the tree.
  264.     ctlTree.DeleteItem(selectedNode);
  265.  
  266.     // Then remove it from the document's CList and set the modified flag.
  267.     CTreeDoc * pDoc = GetDocument();
  268.     pDoc->m_AnimalList.RemoveAt((POSITION)itemData);
  269.     pDoc->SetModifiedFlag();
  270.  
  271.     // Finally, select the deleted node's parent.
  272.     ctlTree.SelectItem(parent);
  273. }
  274.  
  275. void CSimpleTreeView::EditSelection()
  276. {
  277.     CAnimalDlg dlg;
  278.  
  279.     if (IDOK == dlg.DoModal())
  280.     {
  281.         // Construct CAnimalInfo object with 4 values from the dialog object.
  282.         CAnimalInfo my_object(dlg.m_class, dlg.m_type,
  283.                                 dlg.m_animal, dlg.m_weight);
  284.         
  285.         // Insert the object into the document class.
  286.         CTreeDoc * pDoc = GetDocument();
  287.         POSITION pos = pDoc->InsertData(my_object);
  288.         
  289.         // Then insert it into the tree view.
  290.         LocateAndInsert(my_object, pos);
  291.     }
  292. }
  293.  
  294. void CSimpleTreeView::ModifyType(const HTREEITEM selectedNode, const DWORD itemData)
  295. {
  296.     CTreeCtrl & ctlTree = GetTreeCtrl();
  297.     CString AnimalType = ctlTree.GetItemText(selectedNode);
  298.  
  299.     CModifyTypeDlg dlg;
  300.     dlg.m_type = AnimalType;
  301.  
  302.     if (IDOK == dlg.DoModal())
  303.     {
  304.         // First, change the text in the selected node of the tree.
  305.         ctlTree.SetItemText(selectedNode, dlg.m_type);
  306.         
  307.         // Second, sort the parent of the selected node, since the
  308.         // new spelling may require a re-sort.
  309.         HTREEITEM parent = ctlTree.GetParentItem(selectedNode);
  310.         ctlTree.SortChildren(parent);
  311.         
  312.         // Iterate over the CList and change any node with the old spelling.
  313.         CTreeDoc * pDoc = GetDocument();
  314.         POSITION current, pos = pDoc->m_AnimalList.GetHeadPosition();
  315.         while (NULL != pos)
  316.         {
  317.             // Since GetNext advances its POSITION argument, save it.
  318.             current = pos;
  319.  
  320.             // Grab the current object.
  321.             CAnimalInfo & rAnimal2 = pDoc->m_AnimalList.GetNext(pos);
  322.  
  323.             // If its type is that same as the selected node,
  324.             // change the spelling.
  325.             if (rAnimal2.m_type == AnimalType)
  326.                 pDoc->m_AnimalList.GetAt(current).m_type = dlg.m_type;
  327.         }
  328.         pDoc->SetModifiedFlag();
  329.     }
  330. }
  331.  
  332. void CSimpleTreeView::ModifyAnimal(const HTREEITEM selectedNode, const DWORD itemData)
  333. {
  334.     CTreeDoc * pDoc = GetDocument();
  335.  
  336.     // Obtain, from the document's Clist, the selected item.
  337.     // The node in the tree contains that object's POSITION in the CList.
  338.     CAnimalInfo & rAnimal = pDoc->m_AnimalList.GetAt((POSITION)itemData);
  339.  
  340.     // Create the modifying dialog box and initialize it.
  341.     CModifyDlg dlg;
  342.     dlg.m_animal = rAnimal.m_animal;
  343.     dlg.m_weight = rAnimal.m_weight;
  344.  
  345.     // If user chooses OK, modify object in the CList, and
  346.     // modify the object in the tree view.
  347.     if (IDOK == dlg.DoModal())
  348.     {
  349.         rAnimal.m_animal = dlg.m_animal;
  350.         rAnimal.m_weight = dlg.m_weight;
  351.  
  352.         // Since the CList is not const, GetAt() can be used as an lvalue.
  353.         pDoc->m_AnimalList.GetAt((POSITION)itemData) = rAnimal;
  354.         pDoc->SetModifiedFlag();
  355.  
  356.         // Since the tree doesn't store the weight, there's only
  357.         // one thing to update in the tree.
  358.         CTreeCtrl & ctlTree = GetTreeCtrl();
  359.         ctlTree.SetItemText(selectedNode, rAnimal.m_animal);
  360.  
  361.         // The selected node will refresh itself. However, changing
  362.         // the spelling may require that the parent of the selected
  363.         // node have its children sorted.
  364.         HTREEITEM parent = ctlTree.GetParentItem(selectedNode);
  365.         ctlTree.SortChildren(parent);
  366.  
  367.         // The list must be manually refreshed. This is the
  368.         // same line of code used in CTreeView::OnSelchanged.
  369.         pDoc->m_pListView->DisplayAnimalInfo(itemData);
  370.     }
  371. }
  372. /////////////////////////////////////////////////////////////////////////////
  373. // CSimpleTreeView diagnostics
  374. #ifdef _DEBUG
  375. void CSimpleTreeView::AssertValid() const
  376. {
  377.     CTreeView::AssertValid();
  378. }
  379.  
  380. void CSimpleTreeView::Dump(CDumpContext& dc) const
  381. {
  382.     CTreeView::Dump(dc);
  383. }
  384.  
  385. CTreeDoc* CSimpleTreeView::GetDocument() // non-debug version is inline
  386. {
  387.     ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTreeDoc)));
  388.     return (CTreeDoc*)m_pDocument;
  389. }
  390.  
  391. #endif //_DEBUG
  392.