r15374@deathmachine (orig r423): edenc | 2007-12-17 13:43:38 -0500
[catagits/Reaction.git] / lib / Reaction / UI / ViewPort / ActionForm.pm
index 0a413db..484b5c6 100644 (file)
@@ -16,73 +16,66 @@ use aliased 'Reaction::UI::ViewPort::Field::TimeRange';
 
 class ActionForm is 'Reaction::UI::ViewPort', which {
   has action => (
-    isa => 'Reaction::InterfaceModel::Action', is => 'ro', required => 1
-  );
-  
-  has field_names => (isa => 'ArrayRef', is => 'rw', lazy_build => 1);
-  
+                 isa => 'Reaction::InterfaceModel::Action', is => 'ro', required => 1
+                );
+
+  has ordered_fields => (is => 'rw', isa => 'ArrayRef', lazy_build => 1);
+
   has _field_map => (
-    isa => 'HashRef', is => 'rw', init_arg => 'fields',
-    predicate => '_has_field_map', set_or_lazy_build('field_map'),
-  );
-  
+                     isa => 'HashRef', is => 'rw', init_arg => 'fields', lazy_build => 1,
+                    );
+
   has changed => (
-    isa => 'Int', is => 'rw', reader => 'is_changed', default => sub { 0 }
-  );
+                  isa => 'Int', is => 'rw', reader => 'is_changed', default => sub { 0 }
+                 );
 
   has next_action => (
-    isa => 'ArrayRef', is => 'rw', required => 0, predicate => 'has_next_action'
-  );
-  
+                      isa => 'ArrayRef', is => 'rw', required => 0, predicate => 'has_next_action'
+                     );
+
   has on_apply_callback => (
-    isa => 'CodeRef', is => 'rw', required => 0,
-    predicate => 'has_on_apply_callback'
-  );
-  
+                            isa => 'CodeRef', is => 'rw', required => 0,
+                            predicate => 'has_on_apply_callback'
+                           );
+
   has ok_label => (
-    isa => 'Str', is => 'rw', required => 1, default => sub { 'ok' }
-  );
-  
+                   isa => 'Str', is => 'rw', required => 1, default => sub { 'ok' }
+                  );
+
   has apply_label => (
-    isa  => 'Str', is => 'rw', required => 1, default => sub { 'apply' }
-  );
-  
+                      isa  => 'Str', is => 'rw', required => 1, default => sub { 'apply' }
+                     );
+
   has close_label => (isa => 'Str', is => 'rw', lazy_fail => 1);
-  
+
   has close_label_close => (
-    isa => 'Str', is => 'rw', required => 1, default => sub { 'close' }
-  );
-  
+                            isa => 'Str', is => 'rw', required => 1, default => sub { 'close' }
+                           );
+
   has close_label_cancel => (
-    isa => 'Str', is => 'rw', required => 1, default => sub { 'cancel' }
-  );
-  
+                             isa => 'Str', is => 'rw', required => 1, default => sub { 'cancel' }
+                            );
+
   sub fields { shift->_field_map }
-  
+
   implements BUILD => as {
     my ($self, $args) = @_;
     unless ($self->_has_field_map) {
       my @field_map;
       my $action = $self->action;
       foreach my $attr ($action->parameter_attributes) {
-        push(@field_map, $self->build_fields_for($attr => $args));
+        push(@field_map, $self->_build_fields_for($attr => $args));
       }
-  
-      my %field_map = @field_map;
-      my @field_names = @{ $self->sort_by_spec(
-          $args->{column_order}, [keys %field_map] )};
-  
-      $self->_field_map(\%field_map);
-      $self->field_names(\@field_names);
+      $self->_field_map({ @field_map });
     }
     $self->close_label($self->close_label_close);
   };
-  
-  implements build_fields_for => as {
+
+  implements _build_fields_for => as {
     my ($self, $attr, $args) = @_;
     my $attr_name = $attr->name;
     #TODO: DOCUMENT ME!!!!!!!!!!!!!!!!!
-    my $builder = "build_fields_for_name_${attr_name}";
+    my $builder = "_build_fields_for_name_${attr_name}";
     my @fields;
     if ($self->can($builder)) {
       @fields = $self->$builder($attr, $args); # re-use coderef from can()
@@ -90,13 +83,14 @@ class ActionForm is 'Reaction::UI::ViewPort', which {
       my $constraint = $attr->type_constraint;
       my $base_name = $constraint->name;
       my $tried_isa = 0;
-      CONSTRAINT: while (defined($constraint)) {
+    CONSTRAINT: while (defined($constraint)) {
         my $name = $constraint->name;
+        $name = $attr->_isa_metadata if($name eq '__ANON__');
         if (eval { $name->can('meta') } && !$tried_isa++) {
           foreach my $class ($name->meta->class_precedence_list) {
             my $mangled_name = $class;
             $mangled_name =~ s/:+/_/g;
-            my $builder = "build_fields_for_type_${mangled_name}";
+            my $builder = "_build_fields_for_type_${mangled_name}";
             if ($self->can($builder)) {
               @fields = $self->$builder($attr, $args);
               last CONSTRAINT;
@@ -109,7 +103,7 @@ class ActionForm is 'Reaction::UI::ViewPort', which {
           }
           my $mangled_name = $name;
           $mangled_name =~ s/:+/_/g;
-          my $builder = "build_fields_for_type_${mangled_name}";
+          my $builder = "_build_fields_for_type_${mangled_name}";
           if ($self->can($builder)) {
             @fields = $self->$builder($attr, $args);
             last CONSTRAINT;
@@ -118,49 +112,53 @@ class ActionForm is 'Reaction::UI::ViewPort', which {
         $constraint = $constraint->parent;
       }
       if (!defined($constraint)) {
-        confess "Can't build field ${attr_name} of type ${base_name} without $builder method or build_fields_for_type_<type> method for type or any supertype";
+        confess "Can't build field ${attr_name} of type ${base_name} without $builder method or _build_fields_for_type_<type> method for type or any supertype";
       }
     } else {
       confess "Can't build field ${attr} without $builder method or type constraint";
     }
     return @fields;
   };
-  
-  implements build_field_map => as {
+
+  implements _build_field_map => as {
     confess "Lazy field map building not supported by default";
   };
-  
+
+  implements _build_ordered_fields => as {
+    my $self = shift;
+    my $ordered = $self->sort_by_spec($self->column_order, [keys %{$self->_field_map}]);
+    return [@{$self->_field_map}{@$ordered}];
+  };
+
   implements can_apply => as {
     my ($self) = @_;
-    foreach my $field (values %{$self->_field_map}) {
+    foreach my $field ( @{ $self->ordered_fields } ) {
       return 0 if $field->needs_sync;
-        # if e.g. a datetime field has an invalid value that can't be re-assembled
-        # into a datetime object, the action may be in a consistent state but
-        # not synchronized from the fields; in this case, we must not apply
+      # if e.g. a datetime field has an invalid value that can't be re-assembled
+      # into a datetime object, the action may be in a consistent state but
+      # not synchronized from the fields; in this case, we must not apply
     }
     return $self->action->can_apply;
   };
-  
+
   implements do_apply => as {
     my $self = shift;
     return $self->action->do_apply;
   };
-  
+
   implements ok => as {
     my $self = shift;
     if ($self->apply(@_)) {
       $self->close(@_);
     }
   };
-  
+
   implements apply => as {
     my $self = shift;
     if ($self->can_apply && (my $result = $self->do_apply)) {
       $self->changed(0);
       $self->close_label($self->close_label_close);
-      if ($self->has_on_apply_callback) {
-        $self->on_apply_callback->($self => $result);
-      }
+      $self->on_apply_callback->($self => $result) if $self->has_on_apply_callback;
       return 1;
     } else {
       $self->changed(1);
@@ -168,33 +166,33 @@ class ActionForm is 'Reaction::UI::ViewPort', which {
       return 0;
     }
   };
-  
+
   implements close => as {
     my $self = shift;
     my ($controller, $name, @args) = @{$self->next_action};
     $controller->pop_viewport;
     $controller->$name($self->action->ctx, @args);
   };
-  
+
   sub can_close { 1 }
-  
+
   override accept_events => sub {
     (($_[0]->has_next_action ? ('ok', 'close') : ()), 'apply', super());
   }; # can't do a close-type operation if there's nowhere to go afterwards
-  
+
   override child_event_sinks => sub {
     my ($self) = @_;
     return ((grep { ref($_) =~ 'Hidden' } values %{$self->_field_map}),
             (grep { ref($_) !~ 'Hidden' } values %{$self->_field_map}),
             super());
   };
-  
+
   after apply_child_events => sub {
     # interrupt here because fields will have been updated
     my ($self) = @_;
     $self->sync_action_from_fields;
   };
-  
+
   implements sync_action_from_fields => as {
     my ($self) = @_;
     my $field_map = $self->_field_map;
@@ -207,8 +205,8 @@ class ActionForm is 'Reaction::UI::ViewPort', which {
       $field->sync_from_action; # get errors from $action if applicable
     }
   };
-  
-  implements build_simple_field => as {
+
+  implements _build_simple_field => as {
     my ($self, $class, $attr, $args) = @_;
     my $attr_name = $attr->name;
     my %extra;
@@ -216,91 +214,92 @@ class ActionForm is 'Reaction::UI::ViewPort', which {
       %extra = %$config;
     }
     my $field = $class->new(
-                  action => $self->action,
-                  attribute => $attr,
-                  name => $attr->name,
-                 location => join('-', $self->location, 'field', $attr->name),
-                  ctx => $self->ctx,
-                  %extra
-                );
+                            action => $self->action,
+                            attribute => $attr,
+                            name => $attr->name,
+                            location => join('-', $self->location, 'field', $attr->name),
+                            ctx => $self->ctx,
+                            %extra
+                           );
     return ($attr_name => $field);
   };
-  
-  implements build_fields_for_type_Num => as {
+
+  implements _build_fields_for_type_Num => as {
     my ($self, $attr, $args) = @_;
-    return $self->build_simple_field(Number, $attr, $args);
+    return $self->_build_simple_field(Number, $attr, $args);
   };
-  
-  implements build_fields_for_type_Int => as {
+
+  implements _build_fields_for_type_Int => as {
     my ($self, $attr, $args) = @_;
-    return $self->build_simple_field(Number, $attr, $args);
+    return $self->_build_simple_field(Number, $attr, $args);
   };
-  
-  implements build_fields_for_type_Bool => as {
+
+  implements _build_fields_for_type_Bool => as {
     my ($self, $attr, $args) = @_;
-    return $self->build_simple_field(Boolean, $attr, $args);
+    return $self->_build_simple_field(Boolean, $attr, $args);
   };
-  
-  implements build_fields_for_type_File => as {
+
+  implements _build_fields_for_type_File => as {
     my ($self, $attr, $args) = @_;
-    return $self->build_simple_field(File, $attr, $args);
+    return $self->_build_simple_field(File, $attr, $args);
   };
-  
-  implements build_fields_for_type_Str => as {
+
+  implements _build_fields_for_type_Str => as {
     my ($self, $attr, $args) = @_;
     if ($attr->has_valid_values) { # There's probably a better way to do this
-      return $self->build_simple_field(ChooseOne, $attr, $args);
+      return $self->_build_simple_field(ChooseOne, $attr, $args);
     }
-    return $self->build_simple_field(Text, $attr, $args);
+    return $self->_build_simple_field(Text, $attr, $args);
   };
-  
-  implements build_fields_for_type_SimpleStr => as {
+
+  implements _build_fields_for_type_SimpleStr => as {
     my ($self, $attr, $args) = @_;
-    return $self->build_simple_field(String, $attr, $args);
+    return $self->_build_simple_field(String, $attr, $args);
   };
-  
-  implements build_fields_for_type_Password => as {
+
+  implements _build_fields_for_type_Password => as {
     my ($self, $attr, $args) = @_;
-    return $self->build_simple_field(Password, $attr, $args);
+    return $self->_build_simple_field(Password, $attr, $args);
   };
-  
-  implements build_fields_for_type_DateTime => as {
+
+  implements _build_fields_for_type_DateTime => as {
     my ($self, $attr, $args) = @_;
-    return $self->build_simple_field(DateTime, $attr, $args);
+    return $self->_build_simple_field(DateTime, $attr, $args);
   };
-  
-  implements build_fields_for_type_Enum => as {
+
+  implements _build_fields_for_type_Enum => as {
     my ($self, $attr, $args) = @_;
-    return $self->build_simple_field(ChooseOne, $attr, $args);
+    return $self->_build_simple_field(ChooseOne, $attr, $args);
   };
-  
-  implements build_fields_for_type_DBIx_Class_Row => as {
+
+  #implements build_fields_for_type_Reaction_InterfaceModel_Object => as {
+  implements _build_fields_for_type_DBIx_Class_Row => as {
     my ($self, $attr, $args) = @_;
-    return $self->build_simple_field(ChooseOne, $attr, $args);
+    return $self->_build_simple_field(ChooseOne, $attr, $args);
   };
-  
-  implements build_fields_for_type_ArrayRef => as {
+
+  implements _build_fields_for_type_ArrayRef => as {
     my ($self, $attr, $args) = @_;
     if ($attr->has_valid_values) {
-      return $self->build_simple_field(ChooseMany, $attr, $args)
+      return $self->_build_simple_field(ChooseMany, $attr, $args)
     } else {
-      return $self->build_simple_field(HiddenArray, $attr, $args)
+      return $self->_build_simple_field(HiddenArray, $attr, $args)
     }
   };
-  
-  implements build_fields_for_type_DateTime_Spanset => as {
+
+  implements _build_fields_for_type_DateTime_Spanset => as {
     my ($self, $attr, $args) = @_;
-    return $self->build_simple_field(TimeRange, $attr, $args);
+    return $self->_build_simple_field(TimeRange, $attr, $args);
   };
-  
+
   no Moose;
-  
+
   no strict 'refs';
   delete ${__PACKAGE__ . '::'}{inner};
 
 };
 
-1;
+  1;
 
 =head1 NAME
 
@@ -351,10 +350,6 @@ Default: 'cancel'
 
 =head2 fields
 
-=head2 field_names
-
-Returns: Arrayref of field names.
-
 =head2 can_apply
 
 =head2 can_close