File Coverage

blib/lib/Gtk2/Ex/FormFactory/Widget.pm
Criterion Covered Total %
statement 9 357 2.5
branch 0 160 0.0
condition 0 33 0.0
subroutine 3 119 2.5
pod 27 113 23.8
total 39 782 4.9


line stmt bran cond sub pod time code
1             package Gtk2::Ex::FormFactory::Widget;
2              
3 2     2   11 use strict;
  2         5  
  2         57  
4 2     2   9 use Carp;
  2         3  
  2         129  
5 2     2   8 use Scalar::Util qw(weaken);
  2         3  
  2         9903  
6              
7             my $NAME_CNT = 0;
8             my %WIDGET_NAMES;
9              
10             #========================================================================
11             # Accessors for user specified attributes
12             #========================================================================
13 0     0 0   sub get_name { shift->{name} }
14 0     0 0   sub get_object { shift->{object} }
15 0     0 0   sub get_attr { shift->{attr} }
16 0     0 0   sub get_properties { shift->{properties} }
17 0     0 0   sub get_label { shift->{label} }
18 0     0 0   sub get_label_for { shift->{label_for} }
19 0     0 0   sub get_label_markup { shift->{label_markup} }
20 0     0 0   sub get_label_group { shift->{label_group} }
21 0     0 0   sub get_widget_group { shift->{widget_group} }
22 0     0 0   sub get_tip { shift->{tip} }
23 0     0 0   sub get_inactive { shift->{inactive} }
24 0     0 0   sub get_active { shift->{active} }
25 0     0 0   sub get_rules { shift->{rules} }
26 0     0 0   sub get_expand { shift->{expand} }
27 0     0 0   sub get_expand_h { shift->{expand_h} }
28 0     0 0   sub get_expand_v { shift->{expand_v} }
29 0     0 0   sub get_scrollbars { shift->{scrollbars} }
30 0     0 0   sub get_signal_connect { shift->{signal_connect} }
31 0     0 0   sub get_signal_connect_after { shift->{signal_connect_after} }
32 0     0 0   sub get_width { shift->{width} }
33 0     0 0   sub get_height { shift->{height} }
34 0     0 0   sub get_customize_hook { shift->{customize_hook} }
35 0     0 0   sub get_changed_hook { shift->{changed_hook} }
36 0     0 0   sub get_changed_hook_after { shift->{changed_hook_after} }
37 0     0 0   sub get_active_cond { shift->{active_cond} }
38 0     0 0   sub get_active_depends { shift->{active_depends} }
39             #------------------------------------------------------------------------
40 0     0 0   sub set_name { shift->{name} = $_[1] }
41 0     0 0   sub set_object { shift->{object} = $_[1] }
42 0     0 0   sub set_attr { shift->{attr} = $_[1] }
43 0     0 0   sub set_properties { shift->{properties} = $_[1] }
44 0     0 0   sub set_label { shift->{label} = $_[1] }
45 0     0 0   sub set_label_for { shift->{label_for} = $_[1] }
46 0     0 0   sub set_label_markup { shift->{label_markup} = $_[1] }
47 0     0 0   sub set_label_group { shift->{label_group} = $_[1] }
48 0     0 0   sub set_widget_group { shift->{widget_group} = $_[1] }
49 0     0 0   sub set_tip { shift->{tip} = $_[1] }
50 0     0 0   sub set_inactive { shift->{inactive} = $_[1] }
51 0     0 0   sub set_active { shift->{active} = $_[1] }
52 0     0 0   sub set_rules { shift->{rules} = $_[1] }
53 0     0 0   sub set_expand { shift->{expand} = $_[1] }
54 0     0 0   sub set_expand_h { shift->{expand_h} = $_[1] }
55 0     0 0   sub set_expand_v { shift->{expand_v} = $_[1] }
56 0     0 0   sub set_scrollbars { shift->{scrollbars} = $_[1] }
57 0     0 0   sub set_signal_connect { shift->{signal_connect} = $_[1] }
58 0     0 0   sub set_signal_connect_after { shift->{signal_connect_after} = $_[1] }
59 0     0 0   sub set_width { shift->{width} = $_[1] }
60 0     0 0   sub set_height { shift->{height} = $_[1] }
61 0     0 0   sub set_customize_hook { shift->{customize_hook} = $_[1] }
62 0     0 0   sub set_changed_hook { shift->{changed_hook} = $_[1] }
63 0     0 0   sub set_changed_hook_after { shift->{changed_hook_after} = $_[1] }
64 0     0 0   sub set_active_cond { shift->{active_cond} = $_[1] }
65 0     0 0   sub set_active_depends { shift->{active_depends} = $_[1] }
66             #========================================================================
67              
68             #========================================================================
69             # Accessors for internal attributes
70             #========================================================================
71 0     0 0   sub get_context { shift->{form_factory}->get_context }
72 0     0 0   sub get_form_factory { shift->{form_factory} }
73 0     0 0   sub get_parent { shift->{parent} }
74 0     0 0   sub get_gtk_widget { shift->{gtk_widget} }
75 0 0   0 0   sub get_gtk_parent_widget { $_[0]->{gtk_parent_widget} ||
76             $_[0]->{gtk_widget} }
77 0 0   0 1   sub get_gtk_properties_widget { $_[0]->{gtk_properties_widget} ||
78             $_[0]->{gtk_widget} }
79 0     0 0   sub get_gtk_label_widget { shift->{gtk_label_widget} }
80 0     0 0   sub get_layout_data { shift->{layout_data} }
81 0     0 0   sub get_in_update { shift->{in_update} }
82 0     0 0   sub get_no_widget_update { shift->{no_widget_update} }
83 0     0 0   sub get_backup_widget_value { shift->{backup_widget_value} }
84 0     0 0   sub get_widget_activity { shift->{widget_activity} }
85 0     0 0   sub get_built { shift->{built} }
86             #------------------------------------------------------------------------
87 0     0 0   sub set_form_factory { weaken( shift->{form_factory} = $_[1])}
88 0     0 0   sub set_parent { weaken( shift->{parent} = $_[1])}
89 0     0 1   sub set_gtk_widget { shift->{gtk_widget} = $_[1] }
90 0     0 1   sub set_gtk_parent_widget { shift->{gtk_parent_widget} = $_[1] }
91 0     0 0   sub set_gtk_properties_widget { shift->{gtk_properties_widget}= $_[1] }
92 0     0 0   sub set_gtk_label_widget { shift->{gtk_label_widget} = $_[1] }
93 0     0 0   sub set_layout_data { shift->{layout_data} = $_[1] }
94 0     0 0   sub set_in_update { shift->{in_update} = $_[1] }
95 0     0 0   sub set_no_widget_update { shift->{no_widget_update} = $_[1] }
96 0     0 0   sub set_backup_widget_value { shift->{backup_widget_value} = $_[1] }
97 0     0 0   sub set_widget_activity { shift->{widget_activity} = $_[1] }
98 0     0 0   sub set_built { shift->{built} = $_[1] }
99             #========================================================================
100              
101             #========================================================================
102             # Methods, which may be implemented by Widget subclasses
103             #========================================================================
104 0     0 1   sub get_type { die $_[0]." misses type() method" }
105 0     0 1   sub get_gtk_signal_widget { $_[0]->get_gtk_widget }
106 0     0 1   sub get_gtk_tip_widgets { [ $_[0]->get_gtk_widget ] }
107 0     0 1   sub get_gtk_check_widget { $_[0]->get_gtk_widget }
108 0     0 1   sub get_widget_check_value { undef }
109 0     0 1   sub has_additional_attrs { "" }
110 0     0 1   sub has_label { 0 }
111 0     0 1   sub object_to_widget { 1 }
112 0     0 1   sub widget_to_object { 1 }
113 0     0 1   sub empty_widget { 1 }
114 0     0 1   sub backup_widget_value { 1 }
115 0     0 1   sub restore_widget_value { 1 }
116 0     0 0   sub isa_container { 0 }
117 0     0 0   sub widget_data_has_changed { $_[0]->get_backup_widget_value ne
118             $_[0]->get_widget_check_value }
119              
120             #========================================================================
121              
122             #========================================================================
123             # Widget constructor - must be called by subclasses
124             #========================================================================
125             sub new {
126 0     0 0   my $class = shift;
127 0           my %par = @_;
128 0           my ($name, $object, $attr, $properties, $label, $label_group) =
129             @par{'name','object','attr','properties','label','label_group'};
130 0           my ($widget_group, $inactive, $rules, $expand, $scrollbars) =
131             @par{'widget_group','inactive','rules','expand','scrollbars'};
132 0           my ($signal_connect, $width, $height, $customize_hook) =
133             @par{'signal_connect','width','height','customize_hook'};
134 0           my ($changed_hook, $tip, $expand_h, $expand_v, $label_markup) =
135             @par{'changed_hook','tip','expand_h','expand_v','label_markup'};
136 0           my ($active, $signal_connect_after, $label_for) =
137             @par{'active','signal_connect_after','label_for'};
138 0           my ($active_cond, $active_depends, $changed_hook_after) =
139             @par{'active_cond','active_depends','changed_hook_after'};
140              
141 0 0         $active = 1 if not defined $active;
142              
143             #-- Short notation: 'object.attr', so you may omit 'object'
144 0 0 0       if ( $attr and $attr =~ /^([^.]+)\.(.*)/ ) {
145 0           $object = $1;
146 0           $attr = $2;
147             }
148              
149             #-- Set a default for the Widget's name
150 0 0 0       if ( not $name and $object and $attr ) {
    0 0        
151             #-- Default name is object.attr, if both
152             #-- object and attr are set
153 0           my $cnt = 1;
154 0           my $add = "";
155             #-- Add a number, if the name is registered already
156 0           while ( exists $WIDGET_NAMES{"$object.$attr$add"} ) {
157 0           ++$cnt;
158 0           $add="_$cnt";
159             }
160 0           $name = "$object.$attr$add";
161              
162             } elsif ( not $name ) {
163             #-- Widgets non associated with an object and
164             #-- an attribute get a name derived from the
165             #-- Widget's type
166 0   0       $name ||= $class->get_type."_".$NAME_CNT++;
167             }
168              
169             #-- Check if widget name is not already registered
170 0 0         croak "Widget name '$name' is already registered"
171             if exists $WIDGET_NAMES{$name};
172              
173             #-- Store widget name
174 0           $WIDGET_NAMES{$name} = 1;
175              
176             #-- By default make widget insensitive when it's not active
177 0   0       $inactive ||= "insensitive";
178            
179             #-- Expanding defaults
180 0 0         $expand_h = $expand_v = $expand if defined $expand;
181 0 0         $expand = 0 unless defined $expand;
182 0 0         $expand_h = 1 unless defined $expand_h;
183 0 0         $expand_v = 0 unless defined $expand_v;
184            
185 0 0 0       croak "'inactive' must be 'insensitive' or 'invisible'"
186             unless $inactive eq 'insensitive' or
187             $inactive eq 'invisible';
188              
189 0           my $self = bless {
190             name => $name,
191             object => $object,
192             attr => $attr,
193             properties => $properties,
194             label => $label,
195             label_for => $label_for,
196             label_group => $label_group,
197             label_markup => $label_markup,
198             widget_group => $widget_group,
199             tip => $tip,
200             active => $active,
201             inactive => $inactive,
202             rules => $rules,
203             expand => $expand,
204             expand_h => $expand_h,
205             expand_v => $expand_v,
206             scrollbars => $scrollbars,
207             signal_connect => $signal_connect,
208             signal_connect_after => $signal_connect_after,
209             width => $width,
210             height => $height,
211             customize_hook => $customize_hook,
212             changed_hook => $changed_hook,
213             changed_hook_after => $changed_hook_after,
214             active_cond => $active_cond,
215             active_depends => $active_depends,
216             layout_data => {},
217             }, $class;
218            
219 0           return $self;
220             }
221              
222             sub debug_dump {
223 0     0 0   my $self = shift;
224 0           my ($level) = @_;
225 0           print " "x$level;
226 0           print $self->{name}."|".$self->{attr}."\n";
227 0           1;
228             }
229              
230             #========================================================================
231             # Cleanup of widget data; break circular references
232             #========================================================================
233             sub cleanup {
234 0     0 0   my $self = shift;
235            
236 0 0         $Gtk2::Ex::FormFactory::DEBUG &&
237             print "CLEANUP: $self ".$self->get_name."(".$self->get_attr.")\n";
238            
239             #-- Break circular references with the parent object
240 0           $self->set_parent(undef);
241            
242             #-- Cut references to Gtk widgets - otherwise the Perl
243             #-- garbage collector is confused. We have heavy circular
244             #-- referencing from FormFactory widgets to Gtk widgets,
245             #-- e.g. from callback closures.
246 0           $self->set_gtk_widget(undef);
247 0           $self->set_gtk_parent_widget(undef);
248 0           $self->set_gtk_properties_widget(undef);
249 0           $self->set_gtk_label_widget(undef);
250              
251             #-- Deregister the Widget name
252 0           delete $WIDGET_NAMES{$self->get_name};
253              
254             #-- Delete all references to this widget from the
255             #-- associated Context
256 0           $self->get_context->deregister_widget ($self);
257            
258             #-- Destroy reference to the FormFactory
259 0           $self->set_form_factory(undef);
260              
261 0           1;
262             }
263              
264             #========================================================================
265             # Convenience method: get Object Proxy of this Widget
266             #========================================================================
267             sub get_proxy {
268 0     0 1   $_[0]->get_form_factory
269             ->get_context
270             ->get_proxy($_[0]->get_object);
271             }
272              
273             #========================================================================
274             # Build this Widget, using the FormFactory's Layout instance
275             #========================================================================
276             sub build {
277 0     0 0   my $self = shift;
278            
279 0 0         $Gtk2::Ex::FormFactory::DEBUG &&
280             print "$self->build\n";
281            
282             #-- The Layout object actually builds all widgets
283 0           $self->get_form_factory
284             ->get_layouter
285             ->build_widget($self);
286              
287 0           $self->set_built(1);
288              
289 0           1;
290             }
291              
292             #========================================================================
293             # Connect all Gtk signals of this widget
294             #========================================================================
295             sub connect_signals {
296 0     0 0   my $self = shift;
297              
298             #-- Some widgets have not Gtk pendant, so there
299             #-- may be no signal connecting at all
300 0           my $gtk_widget = $self->get_gtk_widget;
301 0 0         return unless $gtk_widget;
302              
303             #-- Need the context
304 0           my $context = $self->get_context;
305              
306             #-- Register the widget here...
307             #-- (deregistering is done in ->cleanup)
308 0           $context->register_widget($self);
309              
310             #-- On focus-in we backup the current object value
311             #-- (probably we need to restore this if the user
312             #-- enters invalid data)
313             $self->get_gtk_check_widget->signal_connect ("focus-in-event", sub {
314 0     0     $self->backup_widget_value;
315 0           0;
316 0           });
317              
318             #-- On focus-out we check for valid data
319             $self->get_gtk_check_widget->signal_connect ("focus-out-event", sub {
320 0     0     $self->check_widget_value;
321 0           0;
322 0           });
323              
324             #-- Connect the changed signal, if the widgets provides
325             #-- a method for this
326 0 0         $self->connect_changed_signal
327             if $self->can("connect_changed_signal");
328              
329             #-- Connect additional user specified signals
330 0           my $signal_connect = $self->get_signal_connect;
331 0 0         if ( $signal_connect ) {
332 0           my $signal_widget = $self->get_gtk_signal_widget;
333 0           while ( my ($signal, $callback) = each %{$signal_connect} ) {
  0            
334 0           $signal_widget->signal_connect ( $signal => $callback );
335             }
336             }
337              
338             #-- Connect additional user specified signals (after)
339 0           my $signal_connect_after = $self->get_signal_connect_after;
340 0 0         if ( $signal_connect_after ) {
341 0           my $signal_widget = $self->get_gtk_signal_widget;
342 0           while ( my ($signal, $callback) = each %{$signal_connect_after} ) {
  0            
343 0           $signal_widget->signal_connect ( $signal => $callback );
344             }
345             }
346 0           1;
347             }
348              
349             #========================================================================
350             # Lookup a widget
351             #========================================================================
352             sub get_widget {
353 0     0 1   my $self = shift;
354 0           my ($name) = @_;
355            
356 0           my $widget;
357 0           my $form_factory = $self->get_form_factory;
358              
359 0 0         croak "Widget '$name' not registered to this ".
360             "form factory ('".$form_factory->get_name."')"
361             unless $widget = $form_factory->get_widgets_by_name->{$name};
362              
363 0           return $widget;
364             }
365              
366              
367             #========================================================================
368             # Lookup a widget reference
369             #========================================================================
370             sub lookup_widget {
371 0     0 1   my $self = shift;
372 0           my ($name) = @_;
373            
374 0 0         if ( $name =~ /sibling\s*\((.*?)\)/ ) {
375 0           my $sibling_idx = $1;
376 0           my $siblings = $self->get_parent->get_content;
377 0           my $self_idx;
378 0           foreach my $sibling ( @{$siblings} ) {
  0            
379 0 0         if ( $sibling eq $self ) {
380 0   0       $self_idx ||= 0;
381 0           last;
382             }
383 0           ++$self_idx;
384             }
385 0 0         die "Impossible" unless defined $self_idx;
386 0           my $sibling = $siblings->[$sibling_idx+$self_idx];
387 0 0         die "Can't find sibling($sibling_idx)" unless $sibling;
388 0           return $sibling;
389             } else {
390 0           return $self->get_form_factory->get_widget($name);
391             }
392             }
393              
394             #========================================================================
395             # Update this widgets resp. transfer the object's value to the Widget
396             #========================================================================
397             sub update {
398 0     0 1   my $self = shift;
399 0           my ($change_state) = @_;
400              
401 0 0         $change_state = '' if not defined $change_state;
402              
403 0 0         $Gtk2::Ex::FormFactory::DEBUG &&
404             print "update_widget(".$self->get_name.", $change_state)\n";
405              
406             #-- Check if widget updating is temoprarily disabled
407             #-- (refer to widget_value_changed() for this)
408 0 0         return if $self->get_no_widget_update;
409            
410             #-- Is no object associated with this widget?
411 0 0         if ( not $self->get_object ) {
412             #-- Only a activity update may be possible, if
413             #-- an Gtk widget is present at all
414 0 0         if ( $self->get_gtk_parent_widget ) {
415 0           my $active = $self->get_active;
416 0 0         $active = $active ? "active" : "inactive";
417 0           $self->update_widget_activity ( $active );
418             }
419 0           return;
420             }
421              
422             #-- We're going to change the widget's state. This will
423             #-- trigger the widget's changed signal. To prevent, that
424             #-- this triggers an object update again, we set this
425             #-- widget into update state (refer to widget_value_changed()
426             #-- for details)
427 0           $self->set_in_update(1);
428              
429             #-- Do we have an activity update? (if $change state is given,
430             #-- and contains the string 'inactive') - Default is to detect
431             #-- activity by the correspondent Proxy method (see below)
432 0           my $active;
433 0 0         $active = $change_state =~ /inactive/ ? 0 : 1
    0          
434             if $change_state ne '';
435              
436             #-- Now transform the object's activity state into a
437             #-- correspondent widget sensivity/visibility.
438 0 0 0       if ( $self->get_object and $self->get_gtk_parent_widget ) {
439             #-- Get object's activity state
440 0 0         $active = $self->get_proxy($self->get_object)
441             ->get_attr_activity($self->get_attr)
442             if not defined $active;
443              
444             #-- And set visibility or sensitivity accordingly,
445             #-- dependend on what's defined in the widget
446 0           $self->update_widget_activity ( $active );
447             }
448              
449             #-- Transfer object value to widget
450 0 0         if ( $change_state eq '' ) {
    0          
451 0 0         $self->object_to_widget
452             if $self->get_proxy->get_object;
453             } elsif ( $change_state =~ /empty/ ) {
454 0           $self->empty_widget;
455             }
456              
457             #-- Set widget into normal update state
458 0           $self->set_in_update(0);
459              
460 0           1;
461             }
462              
463             #========================================================================
464             # Update this widget, and it's child; overwritten by Container class
465             #========================================================================
466             sub update_all {
467 0     0 1   my $self = shift;
468            
469             #-- For a non Container widget, this is the same as update()
470 0           $self->update(@_);
471            
472 0           1;
473             }
474              
475             #========================================================================
476             # Update this widget's activity state: (in)sensitive / (in)visible
477             #========================================================================
478             sub update_widget_activity {
479 0     0 1   my $self = shift;
480 0           my ($active) = @_;
481            
482 0 0         $active = 0 if $active eq 'inactive';
483            
484             #-- Use the Widget's activity value over the given $active
485 0 0         if ( defined $self->get_widget_activity ) {
486 0           $active = $self->get_widget_activity;
487             }
488              
489             #-- Get associated object (if there is one)
490 0           my $object_name = $self->get_object;
491 0 0         my $object = $object_name ? $self->get_proxy->get_object : undef;
492            
493             #-- If there is an object association but the object is
494             #-- currently not defined, set widget inactive
495 0 0 0       if ( $object_name && ! defined $object ) {
496 0           $active = 0;
497             }
498             #-- Otherwise check if an additional condition needs to be applied
499             else {
500 0           my $cond = $self->get_active_cond;
501 0 0         $active = &$cond($object) if $cond;
502             }
503              
504 0           my $action = $self->get_inactive;
505              
506 0 0         if ( $active eq 'insensitive' ) {
    0          
    0          
    0          
507 0           $action = "insensitive";
508 0           $active = 0;
509             }
510             elsif ( $active eq 'invisible' ) {
511 0           $action = "invisible";
512 0           $active = 0;
513             }
514             elsif ( $active eq 'sensitive' ) {
515 0           $action = "insensitive";
516 0           $active = 1;
517             }
518             elsif ( $active eq 'visible' ) {
519 0           $action = "invisible";
520 0           $active = 1;
521             }
522              
523 0 0         if ( $active ) {
524             #-- Make the widget visible resp. sensitive
525 0 0         if ( $action eq 'invisible' ) {
526 0 0         $Gtk2::Ex::FormFactory::DEBUG &&
527             print " update_widget_activity(".
528             $self->get_name.
529             ", show)\n";
530 0           $self->get_gtk_parent_widget->show;
531 0 0         $self->get_gtk_label_widget->show
532             if $self->get_gtk_label_widget;
533             } else {
534 0 0         $Gtk2::Ex::FormFactory::DEBUG &&
535             print " update_widget_activity(".
536             $self->get_name.
537             ", sensitive)\n";
538 0           $self->get_gtk_parent_widget->show;
539 0 0         $self->get_gtk_label_widget->show
540             if $self->get_gtk_label_widget;
541 0           $self->get_gtk_parent_widget->set_sensitive(1);
542 0 0         $self->get_gtk_label_widget->set_sensitive(1)
543             if $self->get_gtk_label_widget;
544             }
545            
546             } else {
547             #-- Make the widget invisible resp. insensitive
548 0 0         if ( $action eq 'invisible' ) {
549 0 0         $Gtk2::Ex::FormFactory::DEBUG &&
550             print " update_widget_activity(".
551             $self->get_name.
552             ", hide)\n";
553 0           $self->get_gtk_parent_widget->hide;
554 0 0         $self->get_gtk_label_widget->hide
555             if $self->get_gtk_label_widget;
556             } else {
557 0 0         $Gtk2::Ex::FormFactory::DEBUG &&
558             print " update_widget_activity(".
559             $self->get_name.
560             ", insensitive)\n";
561 0           $self->get_gtk_parent_widget->set_sensitive(0);
562 0 0         $self->get_gtk_label_widget->set_sensitive(0)
563             if $self->get_gtk_label_widget;
564             }
565             }
566              
567             #-- Remember state
568 0           $self->set_active($active);
569              
570 0           1;
571             }
572              
573             #========================================================================
574             # Convenience method: get the Object's value
575             #========================================================================
576             sub get_object_value {
577 0     0 1   my $self = shift;
578 0           my ($attr) = @_;
579              
580             #-- By default get the primary attribute
581 0   0       $attr ||= $self->get_attr;
582              
583             #-- Return nothing if this widget has no associated Object
584 0 0         return if not $self->get_object;
585              
586             #-- Otherweise use the Proxy to return the Object's value
587 0           return $self->get_proxy($self->get_object)
588             ->get_attr ($attr);
589             }
590              
591             #========================================================================
592             # Convenience method: set the Object's value
593             #========================================================================
594             sub set_object_value {
595 0     0 1   my $self = shift;
596 0           my ($attr, $value) = @_;
597              
598             #-- If only one argument is given this is the value of
599             #-- the default attribute of this widget
600 0 0         if ( @_ == 1 ) {
601 0           $value = $attr;
602 0           $attr = $self->get_attr;
603             }
604              
605             #-- Do nothing if this widget has no associated Object
606 0 0         return if not $self->get_object;
607              
608             #-- Otherwise use the Proxy to set the Object's value
609 0           return $self->get_proxy($self->get_object)
610             ->set_attr ($attr => $value );
611             }
612              
613             #========================================================================
614             # Check the widget value against the specified rules
615             #========================================================================
616             sub check_widget_value {
617 0     0 1   my $self = shift;
618            
619             #-- Return true, if this Widget has no associated rules
620 0           my $rules = $self->get_rules;
621 0 0         return 1 if not defined $rules;
622              
623             #-- Check only if data changed
624 0 0         return 1 unless $self->widget_data_has_changed;
625              
626             #-- Rule checking is done by a Rules Object associated
627             #-- with the FormFactory of this Widget
628 0           my $rule_checker = $self->get_form_factory->get_rule_checker;
629              
630 0           my $message;
631 0 0 0       if ( $self->get_form_factory->get_sync && $self->get_object ) {
632             #-- If the FormFactory is in Sync mode, check
633             #-- the Object's value (access is faster than getting
634             #-- the Widget value)
635 0           $message = $rule_checker->check (
636             $rules,
637             $self->get_label,
638             $self->get_object_value
639             );
640             } else {
641             #-- If the FormFactory is not in Sync mode, the
642             #-- Widget value is checked
643 0           $message = $rule_checker->check (
644             $rules,
645             $self->get_label,
646             $self->get_widget_check_value
647             );
648             }
649              
650             #-- Restore the Widget value and print an error dialog,
651             #-- if the Rule check failed.
652 0 0         if ( $message ) {
653 0           $self->restore_widget_value;
654 0           $self->show_error_message (
655             message => $message,
656             );
657             }
658            
659 0           return 0;
660             }
661              
662             #========================================================================
663             # Callback method, called if the user changed the Widget
664             #========================================================================
665             sub widget_value_changed {
666 0     0 1   my $self = shift;
667              
668             #-- Do nothing if this Widget is already in update state
669             #-- (otherwise recursive updates may be triggered)
670 0 0         return if $self->get_in_update;
671            
672 0 0         $Gtk2::Ex::FormFactory::DEBUG &&
673             print $self->get_type."(".$self->get_name.") value changed\n";
674              
675 0 0         my $object = $self->get_object ? $self->get_proxy->get_object : undef;
676              
677 0 0         if ( $self->get_form_factory->get_sync ) {
678             #-- Call the Widget's change hook
679 0           my $changed_hook = $self->get_changed_hook;
680 0 0         &$changed_hook($object, $self)
681             if $changed_hook;
682              
683             #-- Apply all changes and update dependent
684             #-- widgets accordingly
685 0 0         $self->apply_changes if $object;
686              
687             #-- Call Widget's change_after_hook
688 0           my $changed_hook_after = $self->get_changed_hook_after;
689 0 0         &$changed_hook_after($object, $self)
690             if $changed_hook_after;
691              
692             } else {
693             #-- Changing the object normally triggers this
694             #-- change also in the widget (refer to
695             #-- Context->update_object_attr_widgets). We need
696             #-- to prevent this.
697 0           $self->set_no_widget_update(1);
698              
699             #-- Call the Widget's change hook, if one was set
700 0           my $changed_hook = $self->get_changed_hook;
701 0 0         &$changed_hook($object, $self)
702             if $changed_hook;
703              
704             #-- Now update all dependent widgets
705 0           $self->get_form_factory
706             ->get_context
707             ->update_object_attr_widgets(
708             $self->get_object, $self->get_attr
709             );
710              
711             #-- Set widget into normal update state again
712 0           $self->set_no_widget_update(0);
713              
714             #-- Call Widget's change_after_hook
715 0           my $changed_hook_after = $self->get_changed_hook_after;
716 0 0         &$changed_hook_after($object, $self)
717             if $changed_hook_after;
718             }
719              
720 0           1;
721             }
722              
723             #========================================================================
724             # Transfer the Widget value to the Object; no activity update
725             #========================================================================
726             sub apply_changes {
727 0     0 1   my $self = shift;
728              
729 0 0         $Gtk2::Ex::FormFactory::DEBUG &&
730             print "apply_changes ".$self->get_type."(".$self->get_name.")\n";
731            
732             #-- No widget update when setting the object value
733 0           $self->set_no_widget_update(1);
734              
735             #-- Set object value from current widget value
736 0           $self->widget_to_object;
737              
738             #-- Widget updates allowed again
739 0           $self->set_no_widget_update(0);
740            
741 0           1;
742             }
743              
744             #========================================================================
745             # Apply all changes incl. children
746             # (here the samy as apply, overriden by Container)
747             #========================================================================
748 0     0 0   sub apply_changes_all { shift->apply_changes }
749              
750             #========================================================================
751             # Commit the Widget's Proxy Buffer (if Proxy is buffered at all)
752             #========================================================================
753             sub commit_proxy_buffers {
754 0     0 0   my $self = shift;
755              
756 0 0         return unless $self->get_object;
757              
758             #-- Nothing to do in synced FormFactories
759             #-- where the Proxy doesn't buffer
760 0           my $proxy = $self->get_proxy;
761 0 0         return 1 unless $proxy->get_buffered;
762            
763             #-- Commit the Proxy's attribute buffer to the object
764 0           $proxy->commit_attr($self->get_attr);
765              
766             #-- And probably additional attributes...
767 0 0         if ( $self->has_additional_attrs ) {
768 0           my $add_attrs = $self->has_additional_attrs;
769 0           my $object = $self->get_object;
770 0           foreach my $add_attr ( @{$add_attrs} ) {
  0            
771 0           my $get_attr_name_method = "get_attr_$add_attr";
772 0           my $attr = $self->$get_attr_name_method();
773 0           $proxy->commit_attr($attr);
774             }
775             }
776              
777 0           return 1;
778             }
779              
780             #========================================================================
781             # Commit proxy buffer changes incl. children
782             # (here the samy as apply, overriden by Container)
783             #========================================================================
784 0     0 0   sub commit_proxy_buffers_all { shift->commit_proxy_buffers }
785              
786             #========================================================================
787             # Commit the Widget's Proxy Buffer (if Proxy is buffered at all)
788             #========================================================================
789             sub discard_proxy_buffers {
790 0     0 0   my $self = shift;
791              
792 0 0         return unless $self->get_object;
793              
794             #-- Nothing to do in synced FormFactories
795             #-- where the Proxy doesn't buffer
796 0           my $proxy = $self->get_proxy;
797 0 0         return 1 unless $proxy->get_buffered;
798            
799             #-- Discard the Proxy's attribute buffer
800 0           $proxy->discard_attr($self->get_attr);
801              
802             #-- And probably additional attributes...
803 0 0         if ( $self->has_additional_attrs ) {
804 0           my $add_attrs = $self->has_additional_attrs;
805 0           my $object = $self->get_object;
806 0           foreach my $add_attr ( @{$add_attrs} ) {
  0            
807 0           my $get_attr_name_method = "get_attr_$add_attr";
808 0           my $attr = $self->$get_attr_name_method();
809 0           $proxy->discard_attr($attr);
810             }
811             }
812              
813 0           return 1;
814             }
815              
816             #========================================================================
817             # Commit proxy buffer changes incl. children
818             # (here the samy as apply, overriden by Container)
819             #========================================================================
820 0     0 0   sub discard_proxy_buffers_all { shift->discard_proxy_buffers }
821              
822             #========================================================================
823             # Show an error dialog
824             #========================================================================
825             sub show_error_message {
826 0     0 1   my $self = shift;
827 0           my %par = @_;
828 0           my ($message, $type) = @par{'message','type'};
829              
830 0   0       $type ||= "error";
831              
832 0           $type = "GTK_MESSAGE_".uc($type);
833              
834 0           my $dialog = Gtk2::MessageDialog->new (
835             $self->get_form_factory->get_form_factory_gtk_window,
836             'GTK_DIALOG_DESTROY_WITH_PARENT',
837             $type,
838             'GTK_BUTTONS_CLOSE',
839             $message,
840             );
841              
842 0     0     $dialog->signal_connect( "response", sub { $dialog->destroy } );
  0            
843 0           $dialog->set_position ('center');
844 0           $dialog->set ( modal => 1 );
845 0           $dialog->show;
846              
847 0           1;
848             }
849              
850             1;
851              
852             __END__