File Coverage

blib/lib/POE/XUL/ChangeManager.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package POE::XUL::ChangeManager;
2              
3 1     1   6 use strict;
  1         2  
  1         31  
4 1     1   6 use warnings;
  1         2  
  1         23  
5 1     1   5 use Carp;
  1         2  
  1         55  
6 1     1   1123 use Aspect;
  1         49084  
  1         7  
7 1     1   1412 use XUL::Node;
  0            
  0            
8             use XUL::Node::State;
9              
10             # creating --------------------------------------------------------------------
11              
12             # windows is list of all top level nodes
13             # destroyed is buffer of all states scheduled for destruction on next flush
14             # next_node_id is next available node ID - 1
15             sub new {
16             my $class = shift;
17             bless { windows => [], destroyed => [], next_node_id => 0 }, $class
18             }
19              
20             # public interface for sessions -----------------------------------------------
21              
22             sub run_and_flush {
23             my ($self, $code) = (shift,shift);
24             local $_;
25             $code->($self,@_);
26             my $out = (join '', map { $self->flush_node($_) } @{$self->windows}).
27             (join '', map { $_->flush } @{$self->{destroyed}});
28             $self->{destroyed} = [];
29             return $out;
30             }
31              
32             sub destroy {
33             my $self = shift;
34             $_->destroy for @{$self->{windows}};
35             delete $self->{windows};
36             }
37              
38             # advice ----------------------------------------------------------------------
39              
40             my $Self_Flow = cflow source => __PACKAGE__.'::run_and_flush';
41              
42             # when node changed register change on state
43             # if it has no state, give it one, give it an id, register the node, and
44             # register the node as a window if node is_window
45             after {
46             my $context = shift;
47             my $self = $context->source->self;
48             my $node = $context->self;
49             my $key = $context->params->[1];
50             my $value = $context->params->[2];
51             my $state = $self->node_state($node);
52              
53             unless ($state) {
54             push @{$self->windows}, $node if $node->is_window;
55             $state = XUL::Node::State->new;
56             my $id = 'E'. ++$self->{next_node_id};
57             $state->set_id($id);
58             $self->node_state($node, $state);
59             $self->event_manager->register_node($id, $node)
60             if $self->event_manager;
61             }
62              
63             if ($key eq 'tag') { $state->set_tag($value) }
64             else { $state->set_attribute($key, $value) }
65              
66             } call 'XUL::Node::set_attribute' & $Self_Flow;
67              
68             # when node added, set parent node state id on child node state
69             before {
70             my $context = shift;
71             my $self = $context->source->self;
72             my $parent = $context->self;
73             my $child = $context->params->[1];
74             my $index = $context->params->[2];
75             my $child_state = $self->node_state($child);
76             $child_state->set_parent_id($self->node_state($parent)->get_id);
77             $child_state->set_index($index);
78             } call 'XUL::Node::_add_child_at_index' & $Self_Flow;
79              
80             # when node destroyed, update state using set_destoyed
81             before {
82             my $context = shift;
83             my $self = $context->source->self;
84             my $parent = $context->self;
85             my $child = $parent->_compute_child_and_index($context->params->[1]);
86             my $child_state = $self->node_state($child);
87             $child_state->set_destroyed;
88             push @{$self->{destroyed}}, $child_state;
89             } call 'XUL::Node::remove_child' & $Self_Flow;
90              
91             # private ---------------------------------------------------------------------
92              
93             sub flush_node {
94             my ($self, $node) = @_;
95             my $out = $self->node_state($node)->flush;
96             $out .= $self->flush_node($_) for $node->children;
97             return $out;
98             }
99              
100             sub node_state {
101             my ($self, $node, $state) = @_;
102             croak "not a node: [$node]" unless UNIVERSAL::isa($node, 'XUL::Node');
103             return $node->{state} unless $state;
104             $node->{state} = $state;
105             }
106              
107             sub event_manager {
108             my ($self, $event_manager) = @_;
109             return $self->{event_manager} unless $event_manager;
110             $self->{event_manager} = $event_manager;
111             }
112              
113             # testing ---------------------------------------------------------------------
114              
115             sub windows { shift->{windows} }
116              
117             1;
118