package Gapp::Meta::Widget::Native::Trait::Form; { $Gapp::Meta::Widget::Native::Trait::Form::VERSION = '0.484'; } use Moose::Role; use MooseX::SemiAffordanceAccessor; use Gapp::Form::Stash; use Gapp::Types qw( FormContext FormField FormStash ); with 'Gapp::Meta::Widget::Native::Role::FormElement'; use Gapp::Types qw(GappCallback); use MooseX::Types::Moose qw(Undef CodeRef); use Gapp::Actions::Util qw( parse_action ); # defines how to transfer values from form to object has 'context' => ( is => 'rw', isa => FormContext, ); # a registry of fields and values has 'stash' => ( is => 'rw', isa => FormStash, lazy_build => 1, ); # whether or not to sync the *context* - the stash is always synced has 'sync' => ( is => 'rw', isa => 'Bool', default => 0, ); has [qw( apply_action cancel_action ok_action ) ] => ( is => 'rw', isa => GappCallback|Undef, ); sub _build_stash { my $self = shift; my $stash = Gapp::Form::Stash->new; # traverse the form and get field names to populate the stash with # these field names must be in the stash in order to retrieve the # starting values from the context for my $w ( $self->find_fields ) { next if ! $w->field; $stash->store( $w->field, undef ) if ! $stash->contains( $w->field ); } # update the values in the stash via the context $stash->update( $self->context ) if $self->context; $stash->set_modified( 0 ); return $stash; } # update the user variables sub apply { my ( $self ) = @_; $self->sync_stash; $self->context->update( $self->stash ) if $self->context; $self->do_apply_action; } sub cancel { my ( $self ) = @_; return if $self->do_cancel_action; $self->close; } sub close { my ( $self ) = @_; $self->gobject->destroy; } sub ok { my ( $self ) = @_; $self->apply; $self->do_ok_action; $self->close; } sub do_apply_action { my ( $self ) = @_; return if ! $self->apply_action; my ( $action, @args ) = parse_action ( $self->cancel_action ); return if ! $action; if ( is_CodeRef ( $action ) ) { $action->( $self, \@args ); } else { $action->perform( $self, \@args ); } } sub do_cancel_action { my ( $self ) = @_; return if ! $self->cancel_action; my ( $action, @args ) = parse_action ( $self->cancel_action ); if ( is_CodeRef ($action) ) { $action->( $self, \@args ); } else { $action->perform( $self, \@args ); } } sub do_ok_action { my ( $self ) = @_; return if ! $self->ok_action; my ( $action, @args ) = parse_action ( $self->ok_action ); if ( is_CodeRef $action ) { $action->( $self, \@args ); } else { $action->perform( $self, \@args ); } } sub find_fields { my ( $self ) = ( @ _ ); my @fields; for my $w ( $self->find_descendants ) { push @fields, $w if is_FormField( $w ); } return @fields; } sub _initialize_stash { my ( $self ) = @_; my $stash = $self->stash; for my $w ( $self->find_fields ) { $stash->store( $w->field, undef ) if ! $stash->contains( $w->field ); } $stash->set_modified( 0 ); } # update the values in the form sub update { my ( $self ) = ( @_ ); # update the stash if we have a context $self->stash->update( $self->context ) if $self->context; # update the values in the form for my $w ( $self->find_fields ) { $w->set_is_updating( 1 ); $w->stash_to_widget( $self->stash ) if $w->field; $w->set_is_updating( 0 ); } } sub update_stash { my ( $self ) = shift; warn '$form->update_stash deprecated, use $form->sync_stash'; $self->sync_stash( @_ ); } sub sync_stash { my ( $self ) = @_; my $stash = $self->stash; for my $w ( $self->find_fields ) { $w->widget_to_stash( $stash ) if $w->field; } } package Gapp::Meta::Widget::Custom::Trait::Form; { $Gapp::Meta::Widget::Custom::Trait::Form::VERSION = '0.484'; } sub register_implementation { 'Gapp::Meta::Widget::Native::Trait::Form' }; 1; __END__ =pod =head1 NAME Gapp::Meta::Widget::Native::Trait::Form - Form trait for widgets =head1 DESCRIPTION Apply this traits to widgets that you want to use as forms. =head1 SYNOPSIS use Gapp::Actions::Form qw( Ok ); Gapp::Window->new( traits => [qw( Form )], content => [ Gapp::HBox->new( Gapp::Entry->new( field => 'user.name' ), Gapp::Button->new( action => Ok ), ) ], ); =head1 PROVIDED ATTRIBUTES =over 4 =item B =over 4 =item is rw =item isa L|Undef =back The context is used to sync data between your objects or data structures and the form fields. =item B =over 4 =item is rw =item isa L|Undef =back The stash is used to store the values of the form fields. Calling C or C on the form will update the values in the stash. Calling C on the form will update your field values with those in the stash. =item B =over 4 =item is rw =item isa Bool =item default 1 =back If set to C and the form has a C, the objects in the context will be updated as the user updates the form. If you make changes to the objects, you will need to call C to see your changes reflected in the form. =back =head1 PROVIDED METHODS =over 4 =item B Updates the stash and context with values from the form. =item B Destroys the form. =item B Calls C =item B Calls C then C. =item B Returns a list of all the fields within the form. =item B Update the fields widgets with the values contained in the stash. =item B Update the stash with values in the field widgets. =item B Updates the stash using the context, then calls C. =item B Updates the stash using values in the form fields. =back =head1 AUTHORS Jeffrey Ray Hallock Ejeffrey.hallock at gmail dot comE =head1 COPYRIGHT & LICENSE Copyright (c) 2011-2012 Jeffrey Ray Hallock. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut