File Coverage

blib/lib/FBP/Parser.pm
Criterion Covered Total %
statement 86 90 95.5
branch 11 18 61.1
condition 2 2 100.0
subroutine 21 21 100.0
pod 3 15 20.0
total 123 146 84.2


line stmt bran cond sub pod time code
1             package FBP::Parser;
2              
3 3     3   95 use 5.008005;
  3         12  
  3         134  
4 3     3   19 use strict;
  3         6  
  3         133  
5 3     3   21 use warnings;
  3         8  
  3         130  
6 3     3   19 use Params::Util ();
  3         8  
  3         48  
7 3     3   9393 use XML::SAX::Base ();
  3         96443  
  3         80  
8 3     3   45 use FBP ();
  3         7  
  3         3587  
9              
10             our $VERSION = '0.41';
11             our @ISA = 'XML::SAX::Base';
12              
13             # Object XML class to Perl class mapping
14             my %OBJECT_CLASS = (
15             Project => 'FBP::Project',
16             Dialog => 'FBP::Dialog',
17             Frame => 'FBP::Frame',
18             Panel => 'FBP::FormPanel',
19              
20             # Direct Mappings
21             wxAnimationCtrl => 'FBP::AnimationCtrl',
22             wxBitmapButton => 'FBP::BitmapButton',
23             wxBoxSizer => 'FBP::BoxSizer',
24             wxButton => 'FBP::Button',
25             wxCalendarCtrl => 'FBP::CalendarCtrl',
26             wxCheckBox => 'FBP::CheckBox',
27             wxChoice => 'FBP::Choice',
28             wxChoicebook => 'FBP::Choicebook',
29             wxComboBox => 'FBP::ComboBox',
30             wxColourPickerCtrl => 'FBP::ColourPickerCtrl',
31             wxDatePickerCtrl => 'FBP::DatePickerCtrl',
32             wxDirPickerCtrl => 'FBP::DirPickerCtrl',
33             wxFilePickerCtrl => 'FBP::FilePickerCtrl',
34             wxFlexGridSizer => 'FBP::FlexGridSizer',
35             wxFontPickerCtrl => 'FBP::FontPickerCtrl',
36             wxGauge => 'FBP::Gauge',
37             wxGenericDirCtrl => 'FBP::GenericDirCtrl',
38             wxGrid => 'FBP::Grid',
39             wxGridBagSizer => 'FBP::GridBagSizer',
40             wxGridSizer => 'FBP::GridSizer',
41             wxHtmlWindow => 'FBP::HtmlWindow',
42             wxHyperlinkCtrl => 'FBP::HyperlinkCtrl',
43             wxListbook => 'FBP::Listbook',
44             wxListBox => 'FBP::ListBox',
45             wxListCtrl => 'FBP::ListCtrl',
46             wxMenu => 'FBP::Menu',
47             wxMenuBar => 'FBP::MenuBar',
48             wxMenuItem => 'FBP::MenuItem',
49             wxNotebook => 'FBP::Notebook',
50             wxPanel => 'FBP::Panel',
51             wxRadioBox => 'FBP::RadioBox',
52             wxRadioButton => 'FBP::RadioButton',
53             wxRichTextCtrl => 'FBP::RichTextCtrl',
54             wxScrollBar => 'FBP::ScrollBar',
55             wxScrolledWindow => 'FBP::ScrolledWindow',
56             wxSearchCtrl => 'FBP::SearchCtrl',
57             wxSlider => 'FBP::Slider',
58             wxSpinButton => 'FBP::SpinButton',
59             wxSpinCtrl => 'FBP::SpinCtrl',
60             wxSplitterWindow => 'FBP::SplitterWindow',
61             wxStaticBitmap => 'FBP::StaticBitmap',
62             wxStaticBoxSizer => 'FBP::StaticBoxSizer',
63             wxStaticText => 'FBP::StaticText',
64             wxStaticLine => 'FBP::StaticLine',
65             wxStatusBar => 'FBP::StatusBar',
66             wxStdDialogButtonSizer => 'FBP::StdDialogButtonSizer',
67             wxTextCtrl => 'FBP::TextCtrl',
68             wxToggleButton => 'FBP::ToggleButton',
69             wxToolBar => 'FBP::ToolBar',
70             wxTreeCtrl => 'FBP::TreeCtrl',
71              
72             # Special Mappings
73             choicebookpage => 'FBP::ChoicebookPage',
74             gbsizeritem => 'FBP::GridBagSizerItem',
75             listbookpage => 'FBP::ListbookPage',
76             notebookpage => 'FBP::NotebookPage',
77             sizeritem => 'FBP::SizerItem',
78             submenu => 'FBP::Menu',
79             separator => 'FBP::MenuSeparator',
80             spacer => 'FBP::Spacer',
81             splitteritem => 'FBP::SplitterItem',
82             tool => 'FBP::Tool',
83             toolSeparator => 'FBP::ToolSeparator',
84             CustomControl => 'FBP::CustomControl',
85             );
86              
87              
88              
89              
90              
91             ######################################################################
92             # Constructor and Accessors
93              
94             sub new {
95 5     5 0 195 my $class = Params::Util::_CLASS(shift);
96 5         108 my $parent = Params::Util::_INSTANCE(shift, 'FBP');
97 5 50       65 unless ( $parent ) {
98 0         0 die("Did not provide a parent FBP object");
99             }
100              
101             # Create the basic parsing object
102 5         27 my $self = bless {
103             raw => 0,
104             stack => [ $parent ],
105             }, $class;
106              
107 5         22 $self;
108             }
109              
110             sub parent {
111 6627     6627 0 29100 $_[0]->{stack}->[-1];
112             }
113              
114              
115              
116              
117              
118             ######################################################################
119             # Generic SAX Handlers
120              
121             sub start_element {
122 10798     10798 1 7057453 my $self = shift;
123 10798         13928 my $element = shift;
124              
125             # We don't support namespaces
126 10798 50       24923 if ( $element->{Prefix} ) {
127 0         0 die(__PACKAGE__ . ' does not support XML namespaces');
128             }
129              
130             # Flatten the Attributes into a simple hash
131 11269         48208 my %hash = map { $_->{LocalName}, $_->{Value} }
  11269         28988  
132 11269         22492 grep { $_->{Value} =~ s/^\s+//; $_->{Value} =~ s/\s+$//; 1; }
  11269         19165  
  11269         40388  
133 10798         22917 grep { ! $_->{Prefix} }
134 10798         12095 values %{$element->{Attributes}};
135              
136             # Handle off to the appropriate tag-specific handler
137 10798         32635 my $handler = 'start_element_' . lc $element->{LocalName};
138 10798 50       47205 unless ( $self->can($handler) ) {
139 0         0 die("No handler for tag $element->{LocalName}");
140             }
141              
142 10798         31453 return $self->$handler( \%hash );
143             }
144              
145             sub end_element {
146 10798     10798 1 2209053 my ($self, $element) = @_;
147              
148             # Hand off to the optional tag-specific handler
149 10798         36640 my $handler = 'end_element_' . lc $element->{LocalName};
150 10798 50       49356 if ( $self->can($handler) ) {
151             # If there is anything in the character buffer, trim whitespace
152 10798 50       24671 if ( defined $self->{character_buffer} ) {
153 10798         18269 $self->{character_buffer} =~ s/^\s+//;
154 10798         16629 $self->{character_buffer} =~ s/\s+$//;
155             }
156              
157 10798         27179 $self->$handler();
158             }
159              
160             # Clean up
161 10798         19490 delete $self->{character_buffer};
162              
163 10798         28426 1;
164             }
165              
166             # Because we don't know in what context this will be called,
167             # we just store all character data in a character buffer
168             # and deal with it in the various end_element methods.
169             sub characters {
170             # Add to the buffer
171 14302     14302 1 1098563 $_[0]->{character_buffer} .= $_[1]->{Data};
172             }
173              
174              
175              
176              
177              
178             ######################################################################
179             # Tag-Specific SAX Handlers
180              
181             #
182             # Top level contain, appears to serve no useful purpose.
183             # So lets just set the container context to be the root.
184             # This can just be ignored.
185             sub start_element_wxformbuilder_project {
186 5     5 0 24 return 1;
187             }
188              
189             sub end_element_wxformbuilder_project {
190 5     5 0 10 return 1;
191             }
192              
193             #
194             # Ignore the file version for now.
195             sub start_element_fileversion {
196 5     5 0 20 return 1;
197             }
198              
199             sub end_element_fileversion {
200 5     5 0 9 return 1;
201             }
202              
203             #
204             # Primary tag for useful elements in a GUI, such as windows and buttons.
205             sub start_element_object {
206 471     471 0 881 my $self = shift;
207 471         746 my $attr = shift;
208              
209             # Identify the type of object to create
210 471 50       2173 unless ( $OBJECT_CLASS{$attr->{class}} ) {
211 0         0 die("Unknown or unsupported object class '$attr->{class}'");
212             }
213              
214             # Store the raw hash until the closing tag
215 471         1418 $attr->{CLASS} = $OBJECT_CLASS{$attr->{class}};
216 471         611 push @{$self->{stack}}, $attr;
  471         2202  
217             }
218              
219             sub end_element_object {
220 471     471 0 742 my $self = shift;
221 471         641 my $attr = pop @{$self->{stack}};
  471         1001  
222 471         1164 my $class = delete $attr->{CLASS};
223 471         921 my $children = delete $attr->{children};
224 471 50       21254 my $object = $class->new(
    100          
225             %$attr,
226             $self->{raw} ? ( raw => $attr ) : ( ),
227             $children ? ( children => $children ) : ( ),
228             );
229 471   100     51002 $self->parent->{children} ||= [ ];
230 471         712 push @{$self->parent->{children}}, $object;
  471         904  
231             }
232              
233             #
234             # Primary tag for attributes of objects
235             sub start_element_property {
236 5673     5673 0 7464 my $self = shift;
237 5673         5996 my $attr = shift;
238              
239             # Add a naked atribute hash to the stack
240 5673         11993 $self->{character_buffer} = '';
241 5673         5764 push @{$self->{stack}}, $attr->{name};
  5673         25757  
242             }
243              
244             sub end_element_property {
245 5673     5673 0 7401 my $self = shift;
246 5673         10634 my $name = pop @{$self->{stack}};
  5673         10840  
247 5673         9279 my $value = $self->{character_buffer};
248 5673         11686 $self->parent->{$name} = $value;
249             }
250              
251             #
252             # Primary tag for events bound to objects
253             sub start_element_event {
254 4644     4644 0 6257 my $self = shift;
255 4644         5185 my $attr = shift;
256              
257             # Add a naked atribute hash to the stack
258 4644         7056 $self->{character_buffer} = '';
259 4644         4718 push @{$self->{stack}}, $attr->{name};
  4644         20869  
260             }
261              
262             sub end_element_event {
263 4644     4644 0 5951 my $self = shift;
264 4644         4951 my $name = pop @{$self->{stack}};
  4644         8886  
265 4644         7576 my $value = $self->{character_buffer};
266 4644 100       12204 $self->parent->{$name} = $value if length $value;
267             }
268              
269             1;