App-Widget

 view release on metacpan or  search on metacpan

lib/App/Widget/HierSelector.pm  view on Meta::CPAN


######################################################################
## $Id: HierSelector.pm 10070 2007-10-10 18:55:12Z spadkins $
######################################################################

package App::Widget::HierSelector;
$VERSION = (q$Revision: 10070 $ =~ /(\d[\d\.]*)/)[0];  # VERSION numbers generated by svn

use App;
use App::Widget;
@ISA = ( "App::Widget" );

use strict;

=head1 NAME

App::Widget::HierSelector - A generic hierarchical view

=head1 SYNOPSIS

   use App::Widget::HierSelector;

   $name = "tree";
   $w = App::Widget::HierSelector->new($name);
   print $w->html();

=cut

######################################################################
# CONSTANTS
######################################################################

######################################################################
# ATTRIBUTES
######################################################################
# {node}{number}{type}       # whether open or closed
# {node}{number}{open}       # 1=open 0=closed
# {node}{number}{value}      #
# {node}{number}{label}      #
# {node}{number}{icon}       # icon to use (default, closed)
# {node}{number}{openicon}   # icon to use when open (optional)
# {node}{number}{hovericon}  # icon to use when cursor over icon

# INPUTS FROM THE ENVIRONMENT

=head1 DESCRIPTION

This class implements a generic hierarchical view such as is useful
for a TreeSelector, a Menu, a ToolbarSet, or an IconPaneSelector.
The main function of a HierSelector is to display a hierarchical set of
data and allow the user to generate events based on that view.

=cut

######################################################################
# INITIALIZATION
######################################################################

# uncomment this when I need to do more than just call SUPER::_init()
sub _init {
    &App::sub_entry if ($App::trace);
    my $self = shift;
    $self->SUPER::_init(@_);
    &App::sub_exit() if ($App::trace);
}

######################################################################
# EVENTS
######################################################################

# Usage: $widget->handle_event($wname, $event, @args);
sub handle_event {
    &App::sub_entry if ($App::trace);
    my ($self, $wname, $event, @args) = @_;
    my ($nodenumber, $x, $y);

    my $node = $self->node_list(1);

    if ($event eq "open") {
        ($nodenumber, $x, $y) = @args;
        $node->{$nodenumber}{open} = 1;
    }
    elsif ($event eq "open_exclusively") {
        ($nodenumber, $x, $y) = @args;
        $self->open_exclusively($nodenumber);
    }
    elsif ($event eq "close") {
        ($nodenumber, $x, $y) = @args;
        $node->{$nodenumber}{open} = 0;
    }
    elsif ($event eq "select") {
        ($nodenumber, $x, $y) = @args;
        $self->set("selected", $nodenumber);  # save node number
        # intentionally bubble "select" event to the container
        if ($wname =~ /^(.*)-([^.]+)$/) {
            my $parent = $1;
            my $result = $self->{context}->widget($parent)->handle_event($wname, $event, @args);
            return $result;
        }
    }
    else {
        return $self->SUPER::handle_event($wname, $event, @args);
    }
    &App::sub_exit() if ($App::trace);

lib/App/Widget/HierSelector.pm  view on Meta::CPAN

            if ($node->{$nodenumber}{open} && $authorized) {
                $nodebase = $nodenumber;
                $nodeidx  = 1;
                $first_auth_nodeidx = undef;
            }
            else {
                $first_auth_nodeidx = $nodeidx if (!defined $first_auth_nodeidx && $authorized);
                $nodeidx++;
            }
        }
    }
    &App::sub_exit() if ($App::trace);
    #$self->{debug} .= "select_first_open_leaf($selected_nodenumber): [$nodenumber]<br>";
}

######################################################################
# METHODS
######################################################################

sub get_selected {
    &App::sub_entry if ($App::trace);
    my ($self, $nodeattrib) = @_;
    my ($nodenumber);

    $nodenumber = $self->{selected};  # might be a tag or a nodenumber

    return undef if (!defined $nodenumber);
    return $nodenumber if (!defined $nodeattrib);

    my $node = $self->node_list();
    $nodenumber = $self->get_tag_nodenumber($nodenumber);

    &App::sub_exit($node->{$nodenumber}{$nodeattrib}) if ($App::trace);
    return $node->{$nodenumber}{$nodeattrib};
}

sub get_tag_nodenumber {
    &App::sub_entry if ($App::trace);
    my ($self, $tag) = @_;

    my $node = $self->node_list();

    my ($nodenumber);
    if ($tag !~ /^\d+/) {  # if $tag is not a $nodenumber already ...
        foreach my $nodenum (keys %$node) {
            if ( $node->{$nodenum}{tag} && $node->{$nodenum}{tag} eq $tag) {
                $nodenumber = $nodenum;
                last;
            }
        } 
    }
    else {
        $nodenumber = $tag;
    }
   
    &App::sub_exit($nodenumber) if ($App::trace);
    return $nodenumber;
}

######################################################################
# OUTPUT METHODS
######################################################################

sub html {
    &App::sub_entry if ($App::trace);
    my $self = shift;
    my ($html, $label);

    my $node = $self->node_list();

    my ($nodebase, $nodeidx, $nodenumber, $nodelevel);
    my (@nextnodebase, @nextnodeidx, @nextnodelevel);

    @nextnodebase  = ("");   # the next nodenumber to check is "$nodebase$nodeidx" (nodenumber = "1" is first)
    @nextnodeidx   = (1);    # check nodenumber "1" next
    @nextnodelevel = (1);    # index into the resulting table that the folder icon will go

    $html = "";
    while ($#nextnodebase > -1) {
        $nodebase  = pop(@nextnodebase);   # get info about next node to check
        $nodeidx   = pop(@nextnodeidx);
        $nodelevel = pop(@nextnodelevel);
        $nodenumber = "$nodebase$nodeidx"; # create its node number
        if (defined $node->{$nodenumber}) {      # if the node exists...
            $label = $node->{$nodenumber}{label};
            $label = $node->{$nodenumber}{value} if (!defined $label);
            $label = "" if (!defined $label);
            $html .= ("&nbsp;&nbsp;" x ($nodelevel-1)) if ($nodelevel > 1);
            $html .= $label;
            $html .= $node->{$nodenumber}{open} ? " (open)" : " (closed)";
            $html .= "<br>\n";

            push(@nextnodebase,    $nodebase);   #   let's search for the node's brother (same depth, next idx)
            push(@nextnodeidx,     $nodeidx+1);  #   (next idx)
            push(@nextnodelevel,   $nodelevel);  #   (same level)

            push(@nextnodebase,  "${nodenumber}."); #   let's search for the node's children (1 deeper, idx 1)
            push(@nextnodeidx,   1);                #   (idx is 1)
            push(@nextnodelevel, $nodelevel+1);     #   (1 deeper)
        }
    }

    &App::sub_exit() if ($App::trace);
    $html;    
}

1;



( run in 0.772 second using v1.01-cache-2.11-cpan-39bf76dae61 )