home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / OWLSRC.PAK / TREEWIND.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  15.5 KB  |  747 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1995, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.26  $
  6. //
  7. // Implements TTreeWindow, TTreeNode, TTreeItem
  8. //
  9. //----------------------------------------------------------------------------
  10. #include <owl/pch.h>
  11. #if !defined(OWL_TREEWIND_H)
  12. # include <owl/treewind.h>
  13. #endif
  14. #if !defined(WINSYS_SYSTEM_H)
  15. # include <winsys/system.h>
  16. #endif
  17. #if !defined(__TCHAR_H)
  18. # include <tchar.h>
  19. #endif
  20. #if !defined(__CHECKS_H)
  21. # include <checks.h>
  22. #endif
  23.  
  24. OWL_DIAGINFO;
  25. DIAG_DECLARE_GROUP(OwlCommCtrl);          // CommonCtrl diagnostic group
  26.  
  27. #if !defined(SECTION) || SECTION == 1
  28.  
  29. // Cache size for node text (static; default = _MAX_PATH)
  30. //
  31. uint TTreeNode::NodeTextCacheSize = _MAX_PATH;
  32.  
  33. //
  34. // Construct a new node given the node's text
  35. //
  36. TTreeNode::TTreeNode(TTreeWindow& tree, const char far* text)
  37. :
  38.   TreeView(&tree)
  39. {
  40.   SetText(text, false);
  41. }
  42.  
  43. //
  44. // Construct a new node given the node's text and image info
  45. //
  46. TTreeNode::TTreeNode(TTreeWindow& tree, const char far* text, int index,
  47.   int selIndex)
  48. :
  49.   TreeView(&tree)
  50. {
  51.   SetText(text, false);
  52.   SetImageIndex(index, false);
  53.   SetSelectedImageIndex(selIndex, false);
  54. }
  55.  
  56. //
  57. // Construct based on an item.
  58. //
  59. TTreeNode::TTreeNode(TTreeWindow& tree, TV_ITEM item)
  60. :
  61.   ItemStruct(item),
  62.   TreeView(&tree)
  63. {
  64.   if (item.mask & TVIF_TEXT) {
  65.     SetText(item.pszText);
  66.   }
  67. }
  68.  
  69. //
  70. //
  71. //
  72. TTreeNode::TTreeNode(TTreeWindow& tw, HTREEITEM hItem)
  73. :
  74.   TreeView(&tw)
  75. {
  76.   WARNX(OwlCommCtrl, !hItem, 0, "Constructed TTreeNode passing a null hItem");
  77.   ItemStruct.hItem = hItem;
  78.   ItemStruct.mask = TVIF_HANDLE;
  79. }
  80.  
  81. //
  82. // Copy constructor: create a new node by copying another node
  83. // Called implicitly by functions that return a TTreeNode by value;
  84. // otherwise, shouldn't be needed.
  85. //
  86. TTreeNode::TTreeNode(const TTreeNode& other)
  87. {
  88.   CopyNode(other);
  89. }
  90.  
  91. //
  92. //  Assignment operator
  93. //
  94. TTreeNode& TTreeNode::operator=(const TTreeNode& other)
  95. {
  96.   CopyNode(other);
  97.   return *this;
  98. }
  99.  
  100. //
  101. //  Reset node to make it a copy of another node
  102. //
  103. TTreeNode&
  104. TTreeNode::CopyNode(const TTreeNode& node)
  105. {
  106.   TreeView    = node.TreeView;
  107.   ItemStruct  = node.ItemStruct;
  108.   FlushCache();
  109.  
  110.   // can't do "n.CacheText" on a const object (TAPointer prevents it)
  111.   //
  112.   TTreeNode& n = CONST_CAST(TTreeNode&, node);
  113.   if (n.CacheText) {
  114.     CacheText = new char[_tcslen(n.CacheText) + 1];
  115.     _tcscpy(CacheText, n.CacheText);
  116.   }
  117.   return *this;
  118. }
  119.  
  120. //
  121. // Construct the node neighboring a given node.  The flag indicates
  122. // whether to create the next, previous, parent, or first child node.
  123. //
  124. TTreeNode::TTreeNode(const TTreeNode& tn, uint32 flag)
  125. :
  126.   ItemStruct(tn.ItemStruct),
  127.   TreeView(tn.TreeView)
  128. {
  129.   TreeView->GetNextItem(flag, *this);
  130. }
  131.  
  132. //
  133. // Adds the item above this item.
  134. //
  135. TTreeNode
  136. TTreeNode::AddSibling(const TTreeItem& item) const
  137. {
  138.   return InsertItem(item);
  139. }
  140.  
  141.  
  142. TTreeNode
  143. TTreeNode::AddSibling(const TTreeNode& node) const
  144. {
  145.    return InsertItem( node );
  146. }
  147.  
  148. //
  149. // Inserts a child before the passed item.
  150. //
  151. // If the function fails, the handle in object returned is NULL.  Here's how
  152. // to check for errors:
  153. //
  154. //    node = InsertChild(TTreeItem("node text"), Last);
  155. //    if (!node)                // the HTREEITEM() conversion operator kicks in
  156. //      DoErrorHandling();
  157. //
  158. // Incidentally, the node returned has only the TVIF_HANDLE mask bit
  159. // set, even if the item passed in contained more attributes.  All the
  160. // attributes are correctly sent to the control, but only a handle is
  161. // returned.
  162. //
  163. TTreeNode
  164. TTreeNode::InsertChild(const TTreeItem& item, THowToInsert how) const
  165. {
  166.   TV_INSERTSTRUCT tvis;
  167.   tvis.hParent      = *this;
  168.   tvis.hInsertAfter = (HTREEITEM)how;
  169.   tvis.item         = item;
  170.   HTREEITEM hItem = TreeView->InsertItem(&tvis);
  171.   return TTreeNode(*TreeView, hItem);
  172. }
  173.  
  174. //
  175. // Inserts an item before this item.
  176. //
  177. TTreeNode
  178. TTreeNode::InsertItem(const TTreeItem& item) const
  179. {
  180.   TV_INSERTSTRUCT tvis;
  181.   TTreeNode parent = GetParent();
  182.  
  183.   tvis.hParent      = parent;
  184.   tvis.hInsertAfter = *this;
  185.   tvis.item         = item;
  186.   HTREEITEM hItem = TreeView->InsertItem(&tvis);
  187.   return TTreeNode(*TreeView, hItem);
  188. }
  189.  
  190. //
  191. // Create a temporary structure to store additional information for the
  192. // comparison object.
  193. //
  194. struct TreeCompareThunk {
  195.   const TTwComparator* This;
  196.   uint32             ItemData;
  197. };
  198.  
  199. //
  200. //
  201. //
  202. int CALLBACK
  203. OwlTreeWindCompare(uint32 itemData1, uint32 itemData2, uint32 lParam)
  204. {
  205.   TreeCompareThunk* ct = (TreeCompareThunk*)lParam;
  206.   return ct->This->Compare(itemData1, itemData2, ct->ItemData);
  207. }
  208.  
  209. //
  210. // Recursively sort the children of the nodes.
  211. //
  212. bool
  213. TTreeNode::SortChildren(const TTwComparator& comparator, bool recurse, uint32 lParam)
  214. {
  215.   TreeCompareThunk ct;
  216.   ct.This = &comparator;
  217.   ct.ItemData = lParam;
  218.   return TreeView->SortChildren((PFNTVCOMPARE)OwlTreeWindCompare, *this,
  219.                                 recurse, (uint32)&ct);
  220. }
  221.  
  222. //
  223. //
  224. //
  225. bool
  226. TTreeNode::GetState(uint& state, bool getNew)
  227. {
  228.   PRECONDITION(ItemStruct.hItem || !getNew);
  229.   PRECONDITION(TreeView || !getNew);
  230.  
  231.   // Send a request message to the control if a) the user asked for the
  232.   // message to be sent, or b) the ItemStruct doesn't yet contain
  233.   // the state data.
  234.   //
  235.   if (getNew || !ItemStruct.mask & TVIF_STATE) {
  236.     ItemStruct.mask |= TVIF_STATE;
  237.     if (!GetItem()) {
  238.       ItemStruct.mask &= ~TVIF_STATE;
  239.       return false;
  240.     }
  241.   }
  242.  
  243.   state = ItemStruct.state;
  244.   return true;
  245. }
  246.  
  247. //
  248. //
  249. //
  250. bool
  251. TTreeNode::SetState(uint state, bool sendNow /*=true*/ )
  252. {
  253.   PRECONDITION(ItemStruct.hItem || !sendNow);
  254.   PRECONDITION(TreeView || !sendNow);
  255.  
  256.   ItemStruct.state = state;
  257.   ItemStruct.stateMask |= state;
  258.   ItemStruct.mask |= TVIF_STATE;
  259.  
  260.   if (sendNow)
  261.     if (!SetItem())
  262.       return false;
  263.  
  264.   return true;
  265. }
  266.  
  267. //
  268. // Set the node's text.
  269. // If sendNow is false, the text is merely cached.  It will be
  270. // sent to the control on the next call to SetItem.
  271. //
  272. bool
  273. TTreeNode::SetText(const char far* text, bool sendNow /*=true*/)
  274. {
  275.   PRECONDITION(TreeView || !sendNow);
  276.  
  277.   if( (uint)ItemStruct.cchTextMax < _tcslen(text) + 1 )
  278.      FlushCache();
  279.  
  280.   if (!CacheText) {
  281.     CacheText = new char[_tcslen(text) + 1];
  282.   }
  283.  
  284.   uint length = _tcslen(text) + 1;
  285.   _tcsncpy(CacheText, text, length);
  286.   ItemStruct.pszText    = CacheText;
  287.   ItemStruct.cchTextMax = length;
  288.   ItemStruct.mask      |= TVIF_TEXT;
  289.   return sendNow ? SetItem() : true;
  290. }
  291.  
  292. //
  293. // Get the node's text.
  294. //
  295. // The text is copied into the "text" buffer.  The caller is responsible
  296. // for creating and managing this buffer.
  297. //
  298. // If getNew if false, the text is simply retrieved from the cache.
  299. // If true, GetText queries the control for the node's current text.
  300. // If the TTreeNode doesn't yet have any text cached, it always ignores
  301. // getNew and queries the control directly.
  302. //
  303. bool
  304. TTreeNode::GetText(char far* text, uint length, bool getNew /*=false*/)
  305. {
  306.   // Update the cache if necessary
  307.   //
  308.   GetText(getNew);
  309.  
  310.   if (CacheText) {
  311.     _tcsncpy(text, CacheText, length);
  312.   }
  313.   return CacheText != 0;
  314. }
  315.  
  316. // Retrieve a pointer to the node's text string.  The node object
  317. // owns the buffer pointed to.  The caller should not delete it.
  318. // If GetText fails, it returns 0.
  319. //
  320. char far*
  321. TTreeNode::GetText(bool getNew /*=false*/)
  322. {
  323.   PRECONDITION(TreeView || !getNew);
  324.  
  325.   // Send a request message to the control if a) the user asked for the
  326.   // message to be sent, or b) the ItemStruct hasn't yet received
  327.   // the text data.
  328.   //
  329.   if (getNew || !CacheText || !(ItemStruct.mask & TVIF_TEXT))  {
  330.     FlushCache();
  331.     CacheText             = new char[NodeTextCacheSize];
  332.     ItemStruct.mask      |= TVIF_TEXT;
  333.     ItemStruct.pszText    = CacheText;
  334.     ItemStruct.cchTextMax = NodeTextCacheSize;
  335.     if (!GetItem()) {
  336.       ItemStruct.mask &= ~TVIF_TEXT;
  337.       return 0;
  338.     }
  339.   }
  340.   return CacheText;
  341. }
  342.  
  343. //
  344. //  Set the node's image indexes.
  345. //
  346. bool
  347. TTreeNode::SetImageIndex(int index, bool sendNow /*=true*/)
  348. {
  349.   PRECONDITION(TreeView || !sendNow);
  350.   ItemStruct.mask  |= TVIF_IMAGE;
  351.   ItemStruct.iImage = index;
  352.   return sendNow ? SetItem() : true;
  353. }
  354.  
  355. //
  356. //
  357. //
  358. bool
  359. TTreeNode::SetSelectedImageIndex(int index, bool sendNow)
  360. {
  361.   PRECONDITION(TreeView || !sendNow);
  362.   ItemStruct.mask |= TVIF_SELECTEDIMAGE;
  363.   ItemStruct.iSelectedImage = index;
  364.   return sendNow ? SetItem() : true;
  365. }
  366.  
  367. //
  368. // Set and Get the user-defined node data.
  369. //
  370.  
  371. bool
  372. TTreeNode::SetItemData(uint32 data, bool sendNow)
  373. {
  374.   PRECONDITION(TreeView || !sendNow);
  375.   ItemStruct.mask  |= TVIF_PARAM;
  376.   ItemStruct.lParam = data;
  377.   return sendNow ? SetItem() : true;
  378. }
  379.  
  380. //
  381. //
  382. //
  383. bool
  384. TTreeNode::GetItemData(uint32& data, bool getNew)
  385. {
  386.   PRECONDITION(ItemStruct.hItem || !getNew);
  387.   PRECONDITION(TreeView || !getNew);
  388.  
  389.   // Send a request message to the control if a) the user asked for the
  390.   // message to be sent, or b) the ItemStruct doesn't yet contain
  391.   // the lParam data.
  392.   //
  393.   if (getNew || !ItemStruct.mask & TVIF_PARAM) {
  394.     ItemStruct.mask |= TVIF_PARAM;
  395.     if (!GetItem()) {
  396.       ItemStruct.mask &= ~TVIF_PARAM;
  397.       return false;
  398.     }
  399.   }
  400.  
  401.   data = ItemStruct.lParam;
  402.   return true;
  403. }
  404.  
  405. //
  406. // Set and Get the node's HasChildren info (TV_ITEM.cChildren).
  407. //
  408.  
  409. bool
  410. TTreeNode::GetHasChildren(int& hasChildren, bool getNew)
  411. {
  412.   PRECONDITION(ItemStruct.hItem || !getNew);
  413.   PRECONDITION(TreeView || !getNew);
  414.  
  415.   // Send a request message to the control if a) the user asked for the
  416.   // message to be sent, or b) the ItemStruct doesn't yet contain
  417.   // the cChildren data.
  418.   //
  419.   if (getNew || !ItemStruct.mask & TVIF_CHILDREN) {
  420.     ItemStruct.mask |= TVIF_CHILDREN;
  421.     if (!GetItem()) {
  422.       ItemStruct.mask &= ~TVIF_CHILDREN;
  423.       return false;
  424.     }
  425.   }
  426.  
  427.   hasChildren = ItemStruct.cChildren;
  428.   return true;
  429. }
  430.  
  431. //
  432. //
  433. //
  434. bool
  435. TTreeNode::SetHasChildren(int count, bool sendNow)
  436. {
  437.   PRECONDITION(TreeView || !sendNow);
  438.   ItemStruct.mask |= TVIF_CHILDREN;
  439.   ItemStruct.cChildren = count;
  440.   return sendNow ? SetItem(&ItemStruct) : true;
  441. }
  442.  
  443. //
  444. // Return the selected node.
  445. //
  446. TTreeNode
  447. TTreeWindow::GetSelection()
  448. {
  449.   return GetRoot().GetNextItem(TTreeNode::Caret);
  450. }
  451.  
  452. //
  453. // Return the drop target node.
  454. //
  455. TTreeNode
  456. TTreeWindow::GetDropHilite()
  457. {
  458.   return GetRoot().GetNextItem(TTreeNode::DropHilite);
  459. }
  460.  
  461. //
  462. // Return the first visible node.
  463. //
  464. TTreeNode
  465. TTreeWindow::GetFirstVisible()
  466. {
  467.   return GetRoot().GetNextItem(TTreeNode::FirstVisible);
  468. }
  469.  
  470. //
  471. // Retrieve an item's bounding rectangle
  472. //
  473. bool
  474. TTreeNode::GetItemRect(TRect& rect, bool textOnly /*=true*/) const
  475. {
  476.   PRECONDITION(TreeView);
  477.   PRECONDITION(ItemStruct.hItem);
  478.  
  479.   // The control expects to receive the HTREEITEM in the LPARAM
  480.   //
  481.   *(REINTERPRET_CAST(HTREEITEM*, &rect)) = ItemStruct.hItem;
  482.  
  483.   return TreeView->SendMessage(TVM_GETITEMRECT, TParam1(textOnly), TParam2(&rect));
  484. }
  485.  
  486. //
  487. // Empty the node's text cache
  488. //
  489. void
  490. TTreeNode::FlushCache()
  491. {
  492.   CacheText = 0;          // CacheText is a smart pointer
  493. }
  494.  
  495. //
  496. // Delete the item from the control.
  497. //
  498. bool
  499. TTreeNode::Delete()
  500. {
  501.   PRECONDITION(TreeView);
  502.   if (TreeView->Delete(*this)) {
  503.     ItemStruct.hItem = 0;
  504.     ItemStruct.mask &= ~TVIF_HANDLE;
  505.     return true;
  506.   }
  507.   else
  508.     return false;
  509. }
  510.  
  511. //----------------------------------------------------------------------------
  512. // TTreeWindow
  513.  
  514. //
  515. // Dynamically create the window.
  516. //
  517. TTreeWindow::TTreeWindow(TWindow* parent, int id, int x, int y, int w, int h,
  518.                          uint32 style, TModule* module)
  519. :
  520.   TListBox(parent, id, x, y, w, h, module)
  521. {
  522.   if (!TCommCtrl::IsAvailable())
  523.     throw TXCommCtrl();
  524.  
  525.   SetStyle(WS_CHILD | WS_VISIBLE | style);
  526.  
  527.   if (TSystem::Has3dUI()) {
  528.     uint32 exStyle = GetExStyle();
  529.     SetExStyle(exStyle |= WS_EX_CLIENTEDGE);
  530.   }
  531. }
  532.  
  533. //
  534. // Create the TTreeWindow object from a resource.
  535. //
  536. TTreeWindow::TTreeWindow(TWindow* parent, int resourceId, TModule* module)
  537. :
  538.   TListBox(parent, resourceId, module)
  539. {
  540.   if (!TCommCtrl::IsAvailable())
  541.     throw TXCommCtrl();
  542. }
  543.  
  544. //
  545. // Destructor
  546. //
  547. TTreeWindow::~TTreeWindow()
  548. {
  549. }
  550.  
  551. //
  552. // Sets the style of the control.
  553. //
  554. void
  555. TTreeWindow::SetStyle(uint32 style)
  556. {
  557.   TWindow::SetStyle(WS_CHILD | WS_VISIBLE | style);
  558. }
  559.  
  560. //
  561. // Returns true if a particular style is set.
  562. //
  563. bool
  564. TTreeWindow::HasStyle(uint32 style)
  565. {
  566.   return (GetStyle() & style) ? true : false;
  567. }
  568.  
  569. //
  570. // Returns the common control class name WC_TREEVIEW
  571. //
  572. char far*
  573. TTreeWindow::GetClassName()
  574. {
  575.   return WC_TREEVIEW;
  576. }
  577.  
  578. //
  579. // Recursively sort the children nodes.
  580. //
  581. bool
  582. TTreeWindow::SortChildren(PFNTVCOMPARE func, HTREEITEM parent, bool recurse, uint32 lParam)
  583. {
  584.   TV_SORTCB cb;
  585.   cb.hParent     = parent;
  586.   cb.lpfnCompare = func;
  587.   cb.lParam      = lParam;
  588.  
  589.   return ToBool(SendMessage(TVM_SORTCHILDRENCB, TParam1(recurse), TParam2(&cb)));
  590. }
  591.  
  592. //
  593. // Private Init function to zero out the data members.
  594. //
  595. void
  596. TTreeItem::Init()
  597. {
  598.   memset(this, 0, sizeof(TV_ITEM));
  599. }
  600.  
  601. //
  602. // Default constructor.
  603. //
  604. TTreeItem::TTreeItem()
  605. {
  606.   Init();
  607. }
  608.  
  609. //
  610. // Initialize based on an existing item.
  611. //
  612. TTreeItem::TTreeItem(TV_ITEM item)
  613. {
  614.   Init();
  615.   *(TV_ITEM*)this = item;
  616. }
  617.  
  618. //
  619. // Construct using only text.
  620. //
  621. TTreeItem::TTreeItem(const char far* text, int len)
  622. {
  623.   Init();
  624.   SetText(text, len);
  625. }
  626.  
  627. //
  628. // Construct based on text, an image index, and a selected index.
  629. //
  630. TTreeItem::TTreeItem(const char far* text, int index, int selIndex)
  631. {
  632.   Init();
  633.   SetText(text);
  634.   SetImageIndex(index);
  635.   SetSelectedImageIndex(selIndex);
  636. }
  637.  
  638. //
  639. // Sets the text of the item.
  640. //
  641. void
  642. TTreeItem::SetText(const char far* buffer, int size)
  643. {
  644.   mask      |= TVIF_TEXT;
  645.   pszText    = CONST_CAST(char far*, buffer);
  646.   cchTextMax = max(_tcslen(buffer) + 1, size);
  647. }
  648.  
  649. //
  650. // Returns the text of the item.
  651. //
  652. void
  653. TTreeItem::GetText(char far* buffer, int size)
  654. {
  655.   if (mask & TVIF_TEXT) {
  656.     _tcsncpy(buffer, pszText, size);
  657.   }
  658. }
  659.  
  660. //
  661. // Sets the magic cookie for the item.
  662. //
  663. void
  664. TTreeItem::SetHTreeItem(HTREEITEM item)
  665. {
  666.   mask |= TVIF_HANDLE;
  667.   hItem = item;
  668. }
  669.  
  670. //
  671. // Returns the magic cookie of the item.
  672. //
  673. HTREEITEM
  674. TTreeItem::GetHTreeitem() const
  675. {
  676.   return (mask & TVIF_HANDLE) ? hItem : 0;
  677. }
  678.  
  679. //
  680. // Sets the extra data of the item.
  681. //
  682. void
  683. TTreeItem::SetItemData(uint32 data)
  684. {
  685.   mask  |= TVIF_PARAM;
  686.   lParam = data;
  687. }
  688.  
  689. //
  690. // Sets the image index of the item.
  691. //
  692. void
  693. TTreeItem::SetImageIndex(int index)
  694. {
  695.   mask  |= TVIF_IMAGE;
  696.   iImage = index;
  697. }
  698.  
  699. //
  700. // Sets the selected image index of the item.
  701. //
  702. void
  703. TTreeItem::SetSelectedImageIndex(int index)
  704. {
  705.   mask          |= TVIF_SELECTEDIMAGE;
  706.   iSelectedImage = index;
  707. }
  708.  
  709. //
  710. // Returns the extra data.
  711. //
  712. uint32
  713. TTreeItem::GetItemData() const
  714. {
  715.   return (mask & TVIF_PARAM) ? lParam : 0;
  716. }
  717.  
  718. #endif // section 1
  719. #if !defined(SECTION) || SECTION == 2
  720.  
  721. IMPLEMENT_STREAMABLE1(TTreeWindow, TListBox);
  722.  
  723. #if !defined(BI_NO_OBJ_STREAMING)
  724.  
  725. //
  726. // Reads an instance of TTreeWindow from the passed ipstream
  727. //
  728. void*
  729. TTreeWindow::Streamer::Read(ipstream& is, uint32 /*version*/) const
  730. {
  731.   ReadBaseObject((TListBox*)GetObject(), is);
  732.   return GetObject();
  733. }
  734.  
  735. //
  736. // Writes the TTreeWindow to the passed opstream
  737. //
  738. void
  739. TTreeWindow::Streamer::Write(opstream& os) const
  740. {
  741.   WriteBaseObject((TListBox*)GetObject(), os);
  742. }
  743.  
  744. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  745.  
  746. #endif // section 2
  747.