File Coverage

blib/lib/POE/XUL/Event.pm
Criterion Covered Total %
statement 139 166 83.7
branch 40 60 66.6
condition 13 14 92.8
subroutine 28 36 77.7
pod 6 24 25.0
total 226 300 75.3


line stmt bran cond sub pod time code
1             package POE::XUL::Event;
2             # $Id: Event.pm 1566 2010-11-03 03:13:32Z fil $
3             # Copyright Philip Gwyn 2007-2010. All rights reserved.
4             # Based on code Copyright 2003-2004 Ran Eilam. All rights reserved.
5              
6 15     15   13753 use strict;
  15         17  
  15         386  
7 15     15   56 use warnings;
  15         19  
  15         352  
8              
9 15     15   50 use Carp;
  15         15  
  15         698  
10 15     15   412 use POE::XUL::Logging;
  15         17  
  15         759  
11              
12 15     15   55 use constant DEBUG => 0;
  15         18  
  15         21526  
13              
14             our $VERSION = '0.0601';
15              
16             ##############################################################
17             sub new
18             {
19 1     1 0 9 my( $package, $event_type, $CM, $response ) = @_;
20              
21 1 50       6 croak "Why didn't you give me a ChangeManager" unless $CM;
22 1 50       3 croak "Why didn't you give me a HTTP::Response" unless $response;
23              
24 1         6 my $self = bless {
25             event_type => $event_type,
26             CM => $CM,
27             response => $response,
28             canceled => 0,
29             done => 0
30             }, $package;
31              
32 1         6 $CM->request_start( $self );
33              
34 1         4 DEBUG and xwarn "$self.CM=$self->{CM}";
35              
36 1         2 return $self;
37             }
38              
39             ##############################################################
40             sub __init
41             {
42 8     8   11 my( $self, $req ) = @_;
43              
44 8         15 $self->{app} = $req->param( 'app' );
45 8 100 100     48 if( $self->{event_type} ne 'connect' and
      100        
46             $self->{event_type} ne 'disconnect' and
47             $self->{event_type} ne 'boot' ) {
48              
49 5         9 my $source_id = $req->param( 'source_id' );
50 5         11 my $rc = $self->__source_id( $source_id );
51 5 50       9 die $rc if $rc;
52             }
53 8         15 foreach my $f ( $req->params ) {
54 24 100       30 next if $f eq 'source_id';
55 16         21 $self->set( $f => $req->param( $f ) );
56             # warn "$f=", $self->get( $f );
57             }
58              
59 8 100 100     28 if( $self->{event_type} ne 'connect' and
60             $self->{event_type} ne 'boot' ) {
61 6         11 my $winID = $req->param( 'window' );
62 6         11 my $rc = $self->__window_id( $winID );
63 6 50       13 die $rc if $rc;
64             }
65             }
66              
67              
68             ##############################################################
69             sub __source_id
70             {
71 5     5   6 my( $self, $id ) = @_;
72              
73 5         11 my $node = $self->{CM}->getElementById( $id );
74 5 50       17 unless( $node ) {
75             # xwarn "known = ", join ',', grep { $_ !~ /PXN/ }
76             # keys %{ $self->{CM}{nodes} };
77 0         0 return "Can't find source node $id";
78             }
79 5         7 $self->{source} = $node;
80 5         4 $self->{source_id} = $id;
81 5         6 return;
82             }
83              
84             ##############################################################
85             sub __window_id
86             {
87 6     6   5 my( $self, $id ) = @_;
88              
89 6         6 my $node;
90 6 100       14 if( $id ) {
    50          
91 5         9 $node = $self->{CM}->getElementById( $id );
92 5         12 DEBUG and xwarn "winID=$id node=$node";
93 5 50       9 return "Can't find window node $id" unless $node;
94             }
95             elsif( $self->{CM} ) {
96 1         4 $node = $self->{CM}->window;
97             }
98 6   100     14 $id ||= '';
99 6         5 $self->{window} = $node;
100 6         3 $self->{window_id} = $id;
101 6         7 return;
102             }
103              
104             ##############################################################
105             # Accessors
106 17     17 0 33 sub set { $_[0]->{ $_[1] } = $_[2] }
107 1     1 0 4 sub get { $_[0]->{ $_[1] } }
108             sub name {
109 13 100   13 1 1696 return $_[0]->{event_type} unless 2==@_;
110 6         12 $_[0]->{event_type} = $_[1];
111             }
112             *event = \&name;
113 0     0 1 0 sub type { $_[0]->{event_type} }
114             sub session {
115 0     0 0 0 carp "Please use SID() instead of session()";
116 0         0 shift->SID( @_ )
117             }
118              
119 1     1 0 3 sub resp { $_[0]->{response} }
120 0     0 0 0 sub response { $_[0]->{response} }
121 0     0 0 0 sub req { $_[0]->{response}->connection->request }
122 0     0 0 0 sub request { $_[0]->{response}->connection->request }
123              
124             # general accessor/mutator
125             sub AUTOLOAD {
126 29     29   33 my $self = shift;
127 29         26 my $key = our $AUTOLOAD;
128 29 50       62 return if $key =~ /DESTROY$/;
129 29         89 $key =~ s/^.*:://;
130 29 100       106 return $self->{$key} if @_ == 0;
131 9         16 $self->{$key} = shift;
132             }
133              
134             *target = \&source;
135              
136             ##############################################################
137             sub coderef
138             {
139 3     3 0 13 my( $self, $coderef ) = @_;
140 3         7 $self->{coderef} = $coderef;
141             }
142              
143              
144              
145              
146             ##############################################################
147             sub run
148             {
149 5     5 0 8 my( $self ) = @_;
150              
151 5         11 local $POE::XUL::Logging::SINGLETON->{app} = $self->{app};
152              
153             # Tell the ChangeManager to keep the Node in sync with the browser
154             # elements. This is where event "side-effects" happen
155 5         8 my $method = "handle_" . $self->event;
156 5         23 my $CMm = $self->{CM}->can( $method );
157              
158 5 100       11 if( $CMm ) {
159 1         2 DEBUG and xdebug "$method = $CMm";
160 1     1   5 $self->wrap( sub { $CMm->( $self->{CM}, $self ) } ) ;
  1         3  
161 1 50       5 return if $self->{CM}{responded};
162             }
163              
164             # Call code that our builder thinks we should execute
165 5 100       9 if( $self->{coderef} ) {
166 2         2 DEBUG and
167             xdebug "coderef";
168 2         4 $self->wrap( delete $self->{coderef} );
169             }
170             # Call code that the application thinks we should execute
171             else {
172 3         2 DEBUG and
173             xdebug "do_event";
174 3         6 $self->do_event();
175             }
176             }
177              
178             sub do_event
179             {
180 3     3 0 4 my( $self ) = @_;
181 3         4 local $POE::XUL::Logging::SINGLETON->{app} = $self->{app};
182              
183 3         5 my $bt = delete $self->{bubble_to};
184 3         5 foreach my $N ( $self->{source}, $bt ) {
185 4 50       8 next unless $N;
186              
187 4         8 my $listener = $N->event( $self->{event_type} );
188 4         11 DEBUG and
189             xdebug "========== $N listener=$listener";
190 4 100       8 next unless $listener;
191              
192 3         3 $self->{source} = $N;
193              
194             $self->wrap( sub {
195 3 50   3   7 if( ref $listener ) {
196 3         10 $listener->( $self );
197             }
198             else {
199 0         0 DEBUG and xdebug "Posting to $self->{SID}/$listener";
200             $POE::Kernel::poe_kernel->call( $self->{SID},
201 0         0 $listener,
202             $self
203             );
204             }
205 3         12 } );
206 3         11 last;
207             }
208             }
209              
210              
211             ##############################################################
212             sub wrap
213             {
214 6     6 1 5 my( $self, $coderef ) = @_;
215 6         10 local $POE::XUL::Logging::SINGLETON->{app} = $self->{app};
216              
217 6         6 eval {
218 6         17 local $SIG{__DIE__} = 'DEFAULT';
219 6         5 DEBUG and
220             xcarp "Wrapping user code CM=$self->{CM}";
221 6         6 local $POE::XUL::Node::CM = $self->{CM};
222 6         8 $coderef->( $self );
223             };
224              
225 6 100       773 if( $@ ) {
226 1         3 my $err = "APPLICATION ERROR: $@";
227 1         3 $self->wrapped_error( $err );
228 1         7 return;
229             }
230             }
231              
232             ##############################################################
233             ## Make sure it is still possible to respond to this event
234             sub __respondable
235             {
236 2     2   3 my( $self, $action ) = @_;
237 2 50       5 if( $self->{canceled} ) {
238 0         0 xcarp2 "Attempt to $action a canceled event";
239 0         0 return;
240             }
241 2 50       5 if( $self->has_response ) {
242 0         0 xcarp2 "Attempt to $action to a responded event";
243 0         0 return;
244             }
245 2         6 return 1;
246             }
247              
248              
249             ##############################################################
250             sub cancel
251             {
252 0     0 0 0 my( $self ) = @_;
253 0         0 $self->{canceled} = 1;
254 0 0       0 unless( $self->has_response ) {
255 0         0 xlog "Event canceled before CM responded";
256 0         0 $self->{done} = 1;
257             }
258             else {
259 0         0 xlog "Event canceled";
260             }
261             }
262              
263             ##############################################################
264             sub canceled
265             {
266 0     0 0 0 my( $self ) = @_;
267 0         0 return $self->{canceled};
268             }
269              
270             ##############################################################
271             sub handled
272             {
273 1     1 1 7 my( $self ) = @_;
274 1         4 local $POE::XUL::Logging::SINGLETON->{app} = $self->{app};
275              
276 1         4 $self->done( 1 );
277 1         1 DEBUG and xcarp "Event finished";
278              
279 1         3 $self->flush();
280             }
281             *finish = \&handled;
282              
283             ##############################################################
284             sub has_response
285             {
286 2     2 0 3 my( $self ) = @_;
287 2 50       4 return 1 unless $self->{CM};
288 2 50       6 return 1 if $self->{CM}->responded;
289 2         11 return;
290             }
291              
292             ##############################################################
293             sub defer
294             {
295 1     1 1 2 my( $self ) = @_;
296 1 50       4 return unless $self->__respondable( 'defer' );
297 1         4 $self->done( 0 );
298             }
299              
300             ##############################################################
301             sub flushed
302             {
303 1     1 1 3 my( $self ) = @_;
304 1         3 return $self->{is_flushed};
305             }
306              
307             ##############################################################
308             # Flush is called from Controler->xul_request or from Event->finish/flush
309             sub flush
310             {
311 2     2 0 4 my( $self ) = @_;
312 2         3 local $POE::XUL::Logging::SINGLETON->{app} = $self->{app};
313              
314 2 100 66     9 if( $self->{is_flushed} or not $self->{CM} ) {
315 1         169 Carp::confess "This event was already flushed!";
316             # $self->dispose if $self->{CM}; # TODO is this a good idea?
317 0         0 return;
318             }
319              
320 1 50       3 return unless $self->__respondable( 'flush' );
321 1         3 $self->{is_flushed} = 1;
322              
323 1         1 DEBUG and xdebug "$self->flush";
324              
325             # TODO don't do this in case of error
326 1         3 $self->{CM}->response( $self->{response} );
327             }
328              
329             ##############################################################
330             sub wrapped_error
331             {
332 1     1 0 2 my( $self, $err ) = @_;
333 1         2 local $POE::XUL::Logging::SINGLETON->{app} = $self->{app};
334 1         2 DEBUG and xdebug "wrapped_error via $self->{CM} ($err)";
335 1 50       5 unless( $self->{CM} ) {
336 0         0 xlog "No CM for error response: ", Dumper $err;
337 0         0 return;
338             }
339 1         4 $self->{CM}->error_response( $self->{response}, $err );
340             }
341              
342              
343             ##############################################################
344             sub data_response
345             {
346 0     0 0 0 my( $self, $data ) = @_;
347 0         0 local $POE::XUL::Logging::SINGLETON->{app} = $self->{app};
348 0         0 $self->{CM}->data_response( $self->{response}, $data );
349             }
350              
351             ##############################################################
352             sub dispose
353             {
354 1     1 0 3 my( $self ) = @_;
355 1         2 $self->{is_flushed} = 1;
356 1         2 delete $self->{CM};
357 1         2 delete $self->{response};
358 1         2 DEBUG and xdebug "$self->dispose";
359             }
360              
361             1;
362              
363             __DATA__