Solstice::Tree - A basic tree object.


Solstice documentation Contained in the Solstice distribution.

Index


Code Index:

NAME

Top

Solstice::Tree - A basic tree object.

SYNOPSIS

Top

  use Tree;

  my $tree = new Tree;

  my $child1 = new Tree;

  $tree->addChild($child1);
  $count = $tree->getChildCount();
  my @children = $tree->getChildren();
  my $child = $tree->getChild(0);

  my $parent = $tree->getParent();

  my $child2 = new Tree;
  $tree->addChild($child2);
  $tree->removeChild(1);

  my $boolean = $tree->isRoot();
  my $boolean = $tree->isLeaf();

  my $uniquelabelstring = $tree->getLabel();

  $child1->setValue("sample text");
  $child2->setValue(\$objectref);

  $tree->setValue("root");

  $tree->destroy();

DESCRIPTION

Top

Provides a set of functionality for manipulating trees.

Export

No symbols exported.

Methods

new()

Constructor, creates a new tree object.

getParent()

Returns the parent of a child

getChildren()

Returns an array of all children

childExists($position)

Returns TRUE if a child exists at the passed $position, FALSE otherwise

addChild($child [, $position])

This will add a child to the tree, at optional $position. Returns 1 on success, and thanks to List, dies on error.

removeChild($position, $return_tree)

This will remove a child, taking a flag on whether to return the tree that the child is the root of. If the tree is not wanted, it will be destroyed.

addChildren($list)
removeChildren()

Remove all children from this tree

moveChild($oldposition, $newposition)

This will move a child from one position to another in the tree. Does not wrap, i will return 0 and do nothing if the old or new position is out of range. Fixes positions, then uses List operations. Returns 1 on success.

destroy()

Recursively destroys a tree, depth-first.

getChildCount()

Returns the size of the children list.

getTotalChildCount()

Returns the size of all children recursively down the list.

getChild($position)

Returns the child at position n in the list.

getPosition()

Returns the position of the node, relative to it's siblings.

getRoot()

Recursively crawls up the tree until it hits the root, then returns it.

isRoot()

Returns a boolean describing whether the current tree node is the root.

isLeaf()

Returns a boolean describing whether the current tree node is a leaf.

isFirstChild()

Returns a boolean describing whether the current tree node is the first child.

isLastChild()

Returns a boolean describing whether the current tree node is the last child.

getLabel()

Recursively goes up the tree and gets a unique text string

setValue($value)

Sets the 'value' of this node.

getValue()

Gets the 'value' of this node.

Private Methods

_setParent($parent, $position)

Sets the parent of a child

Modules Used

List (List).

AUTHOR

Top

Catalyst Group, <catalyst@u.washington.edu>

VERSION

Top

$Revision: 2412 $

COPYRIGHT

Top


Solstice documentation Contained in the Solstice distribution.
package Solstice::Tree;

# $Id: Tree.pm 2412 2005-07-28 16:28:57Z mcrawfor $

use 5.006_000;
use strict;
use warnings;

use base qw(Solstice);

use Solstice::List;

use constant TRUE  => 1;
use constant FALSE => 0;

our ($VERSION) = ('$Revision: 2412 $' =~ /^\$Revision:\s*([\d.]*)/);

sub new {
    my $class = shift;
    my $self = $class->SUPER::new();
    
    $self->{'_parent'} = undef;
    $self->{'_children'} = Solstice::List->new();
    $self->{'_position'} = 0;

    return $self;
}

sub getParent {
    my $self = shift;
    return defined $self->{'_parent'} ? $self->{'_parent'} : $self;
}

sub getChildren {
    my $self = shift;
    
    # This is to ensure that during global destruction 
    # we don't get errors if things are destroyed out 
    # of order.
    if (defined $self->{'_children'}) {
        return @{$self->{'_children'}->getAll()};
    }
    return ();
}

sub iterator {
    my $self = shift;
    if (defined $self->{'_children'}) {
        return $self->{'_children'}->iterator();
    }
}


sub childExists {
    my $self     = shift;
    my $position = shift;

    return $self->{'_children'}->exists($position);
}

sub addChild {
    my $self = shift;
    my ($child, $position) = @_;
    
    if (!defined $child) {
        $self->warn('addChild(): Child is undefined');
        return FALSE;
    }

    if (!$self->isValidObject($child, 'Solstice::Tree')) {
        $self->warn('addChild(): Child is not a Solstice::Tree');
        return FALSE;
    }

    if (defined $position) {
        $self->{'_children'}->add($position, $child);
        
        for my $i ($position + 1 .. $self->{'_children'}->size() - 1) {
            my $current = $self->getChild($i);
            $current->{'_position'}++;
        }
    } else {
        $self->{'_children'}->push($child);
        $position = $self->{'_children'}->size() - 1;
    }
    $child->_setParent($self, $position);
    
    return TRUE;
}

sub removeChild {
    my $self = shift;
    my ($position, $return) = @_;

    return FALSE unless $self->childExists($position);
    
    my $child = $self->getChild($position);
    
    # Remove the child from the list, and decriment the position 
    # of any children after it in the list.
    $self->{'_children'}->remove($position);
    for my $i ($position .. $self->{'_children'}->size() - 1) {
        my $current = $self->getChild($i);
        $current->{'_position'}--;
    }
    
    if ($return) {
        $child->_setParent($child, 0);
        return $child;
    }
    $child->destroy();
    
    return TRUE;
}

sub addChildren {
    my $self = shift;
    my $list = shift;
    
    return FALSE unless defined $list;

    if ($self->isValidObject($list, 'Solstice::List')) {
        $list = $list->getAll();
    } else {
        return FALSE unless $self->isValidArrayRef($list);
    }

    for my $item (@$list) {
        $self->addChild($item);
    }
    
    return TRUE;
}

sub removeChildren {
    my $self = shift;
    
    $self->{'_children'}->clear();
    
    return TRUE;
}

sub moveChild {
    my $self = shift;
    my ($oldposition, $newposition) = @_;

    return FALSE unless ($self->childExists($oldposition) and $self->childExists($newposition));
    return TRUE if ($oldposition == $newposition);

    if ($oldposition < $newposition) {
        for my $i ($oldposition .. $newposition) {
            $self->getChild($i)->{'_position'}--;
        }
    } else {
        for my $i ($newposition .. $oldposition - 1) {
            $self->getChild($i)->{'_position'}++;
        }
    }
    $self->getChild($oldposition)->{'_position'} = $newposition;
    
    $self->{'_children'}->move($oldposition, $newposition);

    return TRUE;
}

sub destroy {
    my $self = shift;
    
    if (defined $self->{'_children'}) {
        # In case things get destroyed out of order.
        for my $child (@{$self->{'_children'}->getAll()}) {
            if (defined $child) {
                $child->destroy();
            }
        }
        $self->{'_children'}->clear();
    }
    $self->{'_parent'} = undef;
    $self = undef;
    
    return TRUE;
}

sub getChildCount {
    my $self = shift;
    return $self->{'_children'}->size();
}

sub getTotalChildCount {
    my $self = shift;
    
    return 0 if $self->isLeaf();
    
    my $count = 0;
    foreach my $child ($self->getChildren()) {
        $count += $child->getTotalChildCount();
        $count++;
    }
    return $count;
}

sub getChild {
    my $self     = shift;
    my $position = shift;
    return $self->{'_children'}->get($position);
}

sub getPosition {
    my $self = shift;
    return $self->{'_position'};
}

sub getRoot {
    my $self = shift;
    return $self if $self->isRoot();
    return $self->getParent()->getRoot();
}

sub isRoot {
    my $self = shift;
    return ($self == $self->getParent());
}

sub isLeaf {
    my $self = shift;
    return !$self->{'_children'}->size();
}

sub isFirstChild {
    my $self = shift;
    return ($self->{'_position'} == 0);
}

sub isLastChild {
    my $self = shift;
    return TRUE if $self->isRoot();
    return ($self->{'_position'} == ($self->getParent()->getChildCount() - 1));
}

sub getLabel {
    my $self = shift;
    return '1' if $self->isRoot();
    return $self->getParent()->getLabel().'_'.$self->{'_position'};
}

sub setValue {
    my $self  = shift;
    $self->{'_value'} = shift;
}

sub getValue {
    my $self = shift;
    return $self->{'_value'};
}

sub _setParent {
    my $self = shift;
    my ($parent, $position) = @_;

    $self->{'_parent'} = $parent;
    $self->{'_position'} = $position;
}

sub DESTROY {
    my $self = shift;
    $self->destroy();
}


1;

__END__