package Gapp::Meta::Widget::Native::Trait::Form;
{
$Gapp::Meta::Widget::Native::Trait::Form::VERSION = '0.481';
}
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;
print "CONTEXT", $self->context, "\n";
$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.481';
}
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<context>
=over 4
=item is rw
=item isa L<Gapp::Form::Context>|Undef
=back
The context is used to sync data between your objects or data structures and
the form fields.
=item B<stash>
=over 4
=item is rw
=item isa L<Gapp::Form::Stash>|Undef
=back
The stash is used to store the values of the form fields. Calling C<apply> or C<ok>
on the form will update the values in the stash. Calling C<update> on the form will
update your field values with those in the stash.
=item B<sync>
=over 4
=item is rw
=item isa Bool
=item default 1
=back
If set to C<true> and the form has a C<context>, 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<update_from_context> to see your changes reflected in the form.
=back
=head1 PROVIDED METHODS
=over 4
=item B<apply>
Updates the stash and context with values from the form.
=item B<close>
Destroys the form.
=item B<cancel>
Calls C<close>
=item B<ok>
Calls C<apply> then C<close>.
=item B<find_fields>
Returns a list of all the fields within the form.
=item B<update>
Update the fields widgets with the values contained in the stash.
=item B<update_stash>
Update the stash with values in the field widgets.
=item B<update_from_context>
Updates the stash using the context, then calls C<update>.
=item B<update_stash>
Updates the stash using values in the form fields.
=back
=head1 AUTHORS
Jeffrey Ray Hallock E<lt>jeffrey.hallock at gmail dot comE<gt>
=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