#
# $Id: node.icn,v 1.6 2006-07-09 23:43:08 rparlett Exp $
#
# This file is in the public domain.
#
# Author: Robert Parlett (parlett@dial.pipex.com)
#

package gui
link graphics
import lang
import util

$include "guih.icn"

#
# This class represents a node in a {Tree} object.
#
class Node : SetFields : Object(
   label,
   bmps,
   always_expandable_flag,
   depth,
   is_expanded_flag,
   subnodes,
   draw_line,
   parent_node
   )

   #
   # Generate all the {Nodes} in this subtree, including this {Node},
   # in preorder ordering.
   #
   method generate_all_preorder()
      suspend self | (!subnodes).generate_all_preorder()
   end

   #
   # Generate all the {Nodes} in this subtree, including this {Node},
   # in postorder ordering.
   #
   method generate_all_postorder()
      suspend (!subnodes).generate_all_postorder() | self
   end

   #
   # Generate all the open {Nodes} in this subtree, including this {Node},
   # in preorder ordering.
   #
   method generate_open_preorder()
      suspend self
      if \self.is_expanded_flag then
         suspend (!subnodes).generate_open_preorder()
   end

   #
   # Generate all open {Nodes} in this subtree, including this {Node},
   # in postorder ordering.
   #
   method generate_open_postorder()
      if \self.is_expanded_flag then
         suspend (!subnodes).generate_open_postorder()
      suspend self
   end

   #
   # Expand all the {Nodes} below this node.
   #
   method expand()
      local n
      every n := generate_all_postorder() do
         if *n.subnodes > 0 then
            n.is_expanded_flag := 1
   end

   #
   # Set the label for this node.
   #
   method set_label(x)
      return self.label := x
   end

   #
   # Return the label
   #
   method get_label()
      return self.label
   end

   #
   # Set the bitmaps for this node.  The parameter should provide a list of 3
   # bitmaps.  The first is displayed if the {Node} is open and has subnodes, the 
   # second is displayed if the {Node} is closed and has subnodes, and the third is
   # displayed if the node has no subnodes.
   # @param x  A list of 3 bitmaps.
   #
   method set_bmps(x)
      return self.bmps := x
   end

   #
   # Add the given {Node} to this {Node}'s list of subnodes.
   # @param  The {Node} to add.
   #
   method add(n)
      n.parent_node := self
      return put(subnodes, n)
   end

   #
   # Get the parent node, or fail if there is none.
   #
   method get_parent_node()
      return \self.parent_node
   end

   #
   # Get the child nodes
   #
   method get_children()
      return subnodes
   end

   #
   # This configures the {Node} so that it is always treated as though it has subnodes
   # for display purposes, event though it may in fact have no subnodes.
   #
   method set_always_expandable()
      return always_expandable_flag := 1
   end

   #
   # This turns off the always_expandable feature (the default).
   #
   method clear_always_expandable()
      return always_expandable_flag := &null
   end

   #
   # Set the expanded flag.  Note that this will not update the GUI, to do that
   # call tree.tree_structure_changed() on the tree in which the node resides.
   #
   method set_expanded()
      return is_expanded_flag := 1
   end

   #
   # Clear the expanded flag.  Note that this will not update the GUI, to do that
   # call tree.tree_structure_changed() on the tree in which the node resides.
   #
   method clear_expanded()
      return is_expanded_flag := &null
   end
      
   #
   # Toggle the opened status of the {Node}. Note that this will not update the GUI, to do that
   # call tree.tree_structure_changed() on the tree in which the node resides.
   #
   method toggle_expanded()
      return is_expanded_flag := if /is_expanded_flag then 1 else &null
   end

   #
   # Succeed iff the node is opened
   #
   method is_expanded()
      return \is_expanded_flag
   end

   #
   # Clear all the subnodes
   #
   method clear_children()
      subnodes := []
   end

   #
   # Delete the given {Node} from the subnodes.
   #
   method delete_node(n)
      local i
      every i := 1 to *self.subnodes do {
         if n === self.subnodes[i] then {
            delete(self.subnodes, i)
            return
         }
      }
   end

   method set_one(attr, val)
      case attr of {
         "label" : set_label(string_val(attr, val))
         "always_expandable" :
            if test_flag(attr, val) then
               set_always_expandable() 
            else
               clear_always_expandable()
         "expanded" :
            if test_flag(attr, val) then
               set_expanded() 
            else
               clear_expanded()
         default : field_error("Unknown attribute " || attr)
      }
   end

   initially(a[])
      subnodes := []
      set_fields(a)
end
