File Coverage

blib/lib/Gtk2/GladeXML/OO.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 Gtk2::GladeXML::OO;
2              
3 1     1   692 use vars qw($VERSION $LOG $tmp);
  1         2  
  1         66  
4 1     1   5 use strict;
  1         1  
  1         27  
5 1     1   5 use warnings;
  1         4  
  1         23  
6 1     1   5 use Carp;
  1         2  
  1         81  
7 1     1   1543 use XML::LibXML::Reader;
  0            
  0            
8             use base 'Gtk2::GladeXML';
9             #======================================================================
10             $VERSION = '0.501';
11             #======================================================================
12             use constant TRUE => not undef;
13             use constant FALSE => undef;
14             #======================================================================
15             my ($gladexml, $glade, $objects, $objects_glade, $level, $LOG) = (undef, undef, undef, undef, undef, 1);
16             our $AUTOLOAD;
17             #======================================================================
18             sub new {
19             my $class = shift;
20             $glade = $_[0];
21             $gladexml = Gtk2::GladeXML->new(@_);
22             return bless $gladexml, $class;
23             }
24             #======================================================================
25             sub load_objects {
26             my ($self, $re) = @_;
27              
28             $re ||= qr/^[A-Z]/o;
29              
30             my $reader = XML::LibXML::Reader->new(location => $glade, validation => 0, suppress_warnings => 1 ) or die "Cannot read $glade\n";
31             my $pattern = XML::LibXML::Pattern->new('//widget');
32              
33             no strict;
34             while( $reader->nextPatternMatch($pattern) ){
35             my $widget = $reader->getAttribute('id');
36             next if $widget !~ $re or defined $objects_glade->{ $widget };
37            
38             $objects_glade->{ $widget } = $self->SUPER::get_widget( $widget );
39             *{ q/::/ . $widget } = \ $objects_glade->{ $widget };
40             }
41             use strict;
42              
43             return;
44             }
45             #======================================================================
46             sub debug {
47             my $lvl = defined $_[1] ? $_[1] : 0;
48             croak(qq/Value "$lvl" is not a digit!/) if $lvl !~ /^\d+$/o;
49             $LOG = $_[1];
50             }
51             #======================================================================
52             sub get_widget {
53             my ($self, $widget) = @_;
54             return undef unless defined $widget;
55             $objects_glade->{$widget} = $self->SUPER::get_widget($widget) unless defined $objects_glade->{$widget};
56             return $objects_glade->{$widget};
57             }
58             #======================================================================
59             my $log = sub {
60             my ($name, $object, $method, @params) = @_;
61            
62             $name = '' unless defined $name;
63             $object = '' unless defined $object;
64             $method = '' unless defined $method;
65             @params = () unless scalar @params;
66             for(0..$#params){
67             unless(defined $params[$_]){ $params[$_] = "undef\n"; }
68             else { $params[$_] .= "\n"; }
69             }
70              
71             warn <
72            
73            
74             ####################################
75             # event #
76             #########
77            
78             CALLED: $AUTOLOAD
79            
80             LEVEL: $level
81            
82             PARSING
83             NAME: $name
84             OBJECT: $object
85             METHOD: $method
86             PARAMS: @params
87            
88             ####################################
89            
90             EOF
91             $level++;
92             return;
93             };
94             #======================================================================
95             my $parse_params = sub {
96             my ($params) = @_;
97            
98             $params =~ s/^\(|\)\s*$//g;
99             my @params = split(/(?
100              
101             foreach(0..$#params){
102             $params[$_] =~ s/^\s+|\s+$//g;
103             $params[$_] =~ s/^('|"|")(.*)(\1)$/$2/;
104             $params[$_] =~ s/\\,/,/g;
105             if($params[$_] eq 'FALSE'){ $params[$_] = FALSE; }
106             elsif($params[$_] eq 'TRUE') { $params[$_] = TRUE; }
107             elsif($params[$_] eq 'undef') { $params[$_] = undef; }
108             }
109              
110             return @params;
111             };
112             #======================================================================
113             my $autoload = *main::AUTOLOAD{CODE};
114             *AUTOLOAD = *main::AUTOLOAD{SCALAR};
115              
116             my $imposter = sub {
117             my ($object, $method, $params) = $AUTOLOAD =~ /^main::(.+)-(?:>|>)([^\(]+)(.*)/;
118              
119             # zerujemy poziom wywolania
120             $level = 0;
121              
122             my (@params, $current);
123             if($params){ @params = $parse_params->($params); }
124             else { @params = @_; }
125            
126             if(not defined $object){
127             $log->($object, undef, $method, @params) if $LOG > 1;
128             warn qq/\nNone object was given. Calling user AUTOLOAD if defined.\n\n/ if $LOG;
129             defined $autoload ? return &$autoload : return;
130             }elsif(not defined $method){
131             $log->($object, undef, $method, @params) if $LOG > 1;
132             warn qq/\nNone method was given. Calling user AUTOLOAD if defined.\n\n/ if $LOG;
133             defined $autoload ? return &$autoload : return;
134             }
135              
136             $objects->{$object} = $gladexml->get_widget($object) unless $objects->{$object};
137              
138             if($objects->{$object}){
139             $current = $objects->{$object};
140             }elsif(not $objects->{$object} and defined $main::{$object}){
141             local *tmp = $main::{$object};
142             $objects->{$object} = $tmp;
143             $current = $tmp;
144             }elsif($object =~ /^.+->.+$/o){ # zagniezdzone wywolanie => nie mozemy tego zapamietywac
145             my @obj = split(/->/, $object);
146             $object = shift @obj;
147            
148             if(defined $main::{$object}){
149             local *tmp = $main::{$object};
150             $current = $tmp;
151             }else{ $current = $gladexml->get_widget($object); }
152            
153             unless($current){
154             $log->($object, $current, $method, @params) if $LOG > 1;
155             warn qq/\nUnknown object "$object" in multilevel call! Calling user AUTOLOAD if defined.\n\n/ if $LOG;
156             defined $autoload ? return &$autoload : return;
157             }
158              
159             # przechodzimy po kolejnych zagniezdzeniach
160             for my $idx(0..$#obj){
161             my ($method, $params) = $obj[$idx] =~ /([^\(]+)(.*)/;
162             my @params = ();
163             @params = $parse_params->($params) if $params;
164             $log->($object, $current, $method, @params) if $LOG > 1;
165             # kasujemy nazwe obiektu, by w logach sie nie pojawiala
166             # leczy tylko raz, przy pierwszej iteracji
167             undef $object if $idx == 0;
168             $current = $current->$method(@params);
169             last unless $current;
170             }
171             }
172            
173             if(not $current){
174             warn qq/\nUnknown object "$object"! Calling user AUTOLOAD if defined.\n\n/ if $LOG;
175             defined $autoload ? return &$autoload : return;
176             }elsif(not $current->can($method)){
177             warn qq/\nUnknown method "$method" of object "$object"! Calling user AUTOLOAD if defined.\n\n/ if $LOG;
178             defined $autoload ? return &$autoload : return;
179             }
180            
181             $log->($object, $current, $method, @params) if $LOG > 1;
182             $current->$method(@params);
183             return TRUE;
184             };
185              
186             #-------------------------------------------
187             # redefine main::AUTOLOAD
188             if(exists $ENV{PAR_TEMP}){
189             no warnings 'redefine';
190             *main::AUTOLOAD = $imposter;
191             }
192             # this _must_ be in CHECK block too, otherway someone could redefine our AUTOLOAD
193             #----------------------------------------------------------------------
194             CHECK {
195             no warnings 'redefine';
196             $autoload = *main::AUTOLOAD{CODE};
197             *AUTOLOAD = *main::AUTOLOAD{SCALAR};
198             *main::AUTOLOAD = $imposter;
199             }
200             #----------------------------------------------------------------------
201             # End of CHECK block
202             #======================================================================
203             1;
204              
205             =head1 NAME
206              
207             Gtk2::GladeXML::OO - Drop-in replacement for Gtk2::GladeXML with object oriented interface to Glade.
208              
209              
210             =head1 SYNOPSIS
211              
212             use Gtk2::GladeXML::OO;
213            
214             # exactly as in Gtk2::GladeXML
215             our $gladexml = Gtk2::GladeXML::OO->new('glade/example.glade');
216             $gladexml->signal_autoconnect_from_package('main');
217             $gladexml->load_objects(qw/GUI_/); # insert GUI objects to namespace
218             $gladexml->debug(2);
219              
220             $::GUI_window->show; # method "show" of widget with name "GUI_window"
221              
222             sub gtk_main_quit { Gtk2->main_quit; }
223              
224             # Object _MUST_ be declared as "our"
225             our $myobject = MyObject->new();
226              
227             Gtk2->main;
228              
229              
230             # ...and now callbacks in Glade can be:
231             #
232             # myobject->method <- Gtk2 will pass standard parameters to Your method
233             # myobject->method() <- without any parameters, ie. window->hide()
234             # myobject->method("param0", "param1") <- with Your parameters
235             # myobject->get_it()->do_sth("par0", "par1") <- multilevel call to Your object
236             # tree_view->get_selection->select_all() <- multilevel call to Glade object!!
237             #
238             # gtk_main_quit <- standard function interface, like before
239              
240             # See example.glade and example.pl in example directory!
241              
242             =head1 DESCRIPTION
243              
244             This module provides a clean and easy object-oriented interface in Glade callbacks (automagicaly loads objects and do all dirty work for you, B). Now You can use in callbacks: widgets, Your objects or standard functions like before. Callbacks can be even multilevel!
245              
246             Gtk2::GladeXML::OO is a drop-in replacement for Gtk2::GladeXML, so after a change from Gtk2::GladeXML to Gtk2::GladeXML::OO all Your applications will work fine and will have new functionality.
247              
248             =head1 AUTOLOAD
249              
250             If You are using AUTOLOAD subroutine in main package, Gtk2::GladeXML::OO module will invoke it, when it cound'nt find any matching object in Glade file and Your code.
251              
252             =head1 SUBROUTINES/METHODS
253              
254             =over 4
255              
256             =item B
257              
258             This method should be called exactly as C in Gtk2::GladeXML. In example:
259              
260             # Gtk2::GladeXML::OO object
261             our $gladexml = Gtk2::GladeXML::OO->new('glade/example.glade');
262              
263             =item B
264              
265             This method turns on/off debug. Three levels are acceptable.
266              
267             0 => turns OFF debug
268             1 => turns ON debug (only important information/warnings), DEFAULT
269             2 => turns ON debug in verbose mode, use this when You are in a trouble
270              
271             In example:
272            
273             # tunrs OFF debug
274             $gladexml->debug(0);
275            
276             ...some code...
277              
278             # tunrs ON debug
279             $gladexml->debug(1);
280            
281             ...some code...
282             # turns ON debug in verbose mode
283             $gledexml->debug(2);
284            
285              
286             =item B
287              
288             This method loads to "main::" namespace all objects corresponding to widgets with names compatible with C. Default C is set to C.
289              
290             =item B!>
291              
292             =back
293              
294             =head1 DEPENDENCIES
295              
296             =over 4
297              
298             =item Carp (in standard Perl distribution)
299              
300             =item Gtk2::GladeXML
301              
302             =back
303              
304              
305             =head1 INCOMPATIBILITIES
306              
307             None known. You can even use AUTOLOAD in Your application and all modules.
308              
309             =head1 BUGS AND LIMITATIONS
310              
311             Limitation (will be resolved in a future): For now Your objects are loaded only from main package.
312              
313             =head1 AUTHOR
314              
315             Strzelecki Ɓukasz
316              
317             =head1 LICENCE AND COPYRIGHT
318              
319             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
320              
321             See http://www.perl.com/perl/misc/Artistic.html
322