TLinkList - Doubly-Linked Tree List

Source: source/classes/linklist.prg

TLinkList implements a doubly-linked list with hierarchical (tree) capabilities. Each node in the list has a Cargo DATA for arbitrary user data and supports nesting via children. Nodes can store a prompt string, bitmap handles, open/close state, an action codeblock, and a nesting level. The class provides tree traversal, searching, sorting, and recursive expansion or collapse of nodes.

DATA Members

DATATypeDescription
oFirstObjectFirst node in the list
oLastObjectLast node in the list
CargoAnyArbitrary user data attached to the list (or to each node)

Methods

MethodDescription
Add( cPrompt, nLevel, hBmpOpen, hBmpClose, lOpen, bAction, uCargo )Add a new node with prompt, nesting level, bitmap handles, open state, action codeblock and cargo
Eval( bAction, bFor, bWhile, lRecurs )Evaluate a codeblock for each node, with optional filter (bFor), condition (bWhile) and recursive traversal
Find( uFind, lRecurs )Find a node by cargo value (or by other criteria), optionally recursing into children
Sort( lAsc, lRecurs, nCol )Sort nodes by prompt, ascending (lAsc=.T.) or descending, optionally recursive and by column
OpenAll()Recursively open all nodes (set lOpen=.T.)
Expand( nLev )Expand (open) nodes down to level nLev
Collapse( nLev )Collapse (close) nodes above level nLev
nCount()Return the total number of nodes
Levels()Return the maximum nesting depth

Example: Build a Tree Structure

#include "FiveWin.ch"

function Main()

   local oList := TLinkList():New()

   // Add nodes: prompt, level, bitmap handles (0=none), open, action, cargo
   oList:Add( "Root",       0, 0, 0, .T., nil, "root" )
   oList:Add( "Documents",  1, 0, 0, .T., nil, "docs" )
   oList:Add( " Report.txt", 2, 0, 0, .F., nil, "report" )
   oList:Add( " Invoices",  2, 0, 0, .T., nil, "invoices" )
   oList:Add( " Photos",    1, 0, 0, .F., nil, "photos" )

   ? "Total nodes:", oList:nCount()
   ? "Max levels:",  oList:Levels()

   // Traverse the tree
   oList:Eval( {|oNode| QOut( oNode:Cargo ) }, nil, nil, .T. )

   // Find a node by cargo
   local oFound := oList:Find( "invoices", .T. )
   if oFound != nil
      ? "Found:", oFound:Cargo
   endif

return nil

See Also