diff options
Diffstat (limited to 'lib/Reaction/UI/ViewPort/GridView.pm')
-rw-r--r-- | lib/Reaction/UI/ViewPort/GridView.pm | 203 |
1 files changed, 176 insertions, 27 deletions
diff --git a/lib/Reaction/UI/ViewPort/GridView.pm b/lib/Reaction/UI/ViewPort/GridView.pm index 542af62..5691ff1 100644 --- a/lib/Reaction/UI/ViewPort/GridView.pm +++ b/lib/Reaction/UI/ViewPort/GridView.pm @@ -2,8 +2,14 @@ package Reaction::UI::ViewPort::GridView; use Reaction::Class; -use aliased 'Reaction::UI::ViewPort::GridView::Row'; -use aliased 'Reaction::InterfaceModel::Collection'; +use aliased 'Reaction::UI::ViewPort::DisplayField::Text'; +use aliased 'Reaction::UI::ViewPort::DisplayField::Number'; +use aliased 'Reaction::UI::ViewPort::DisplayField::Boolean'; +use aliased 'Reaction::UI::ViewPort::DisplayField::String'; +use aliased 'Reaction::UI::ViewPort::DisplayField::DateTime'; +use aliased 'Reaction::UI::ViewPort::DisplayField::RelatedObject'; + +use aliased 'Reaction::InterfaceModel::Collection' => 'IM_Collection'; class GridView is 'Reaction::UI::ViewPort', which { @@ -12,38 +18,23 @@ class GridView is 'Reaction::UI::ViewPort', which { has rows => ( isa => 'ArrayRef', is => 'ro', lazy_build => 1); has row_args => ( isa => 'HashRef', is => 'ro'); - has collection => (isa => Collection, is => 'ro', required => 1); - has current_collection => (isa => Collection, is => 'rw', lazy_build => 1); - - implements build_rows => as{ - my $self = shift; + has collection => (isa => IM_Collection, is => 'ro', required => 1); + has current_collection => (isa => IM_Collection, is => 'rw', lazy_build => 1); - my (@rows, $i); - for my $object ( $self->current_collection->members ){ - my $row = Row->new - ( - ctx => $self->ctx, - object => $object, - location => join('-', $self->location, 'row', ++$i), - column_order => $self->column_order, #XXX clean from ViewPort - exclude_fields => $self->exclude_columns || [], - $self->has_row_args ? %{ $self->row_args } : (), - - ); - push(@rows, $row); - } - return \@rows; - }; + has ordered_columns => (is => 'ro', isa => 'ArrayRef', lazy_build => 1); - implements build_column_names => as { + implements build_ordered_columns => as { my ($self) = @_; my %excluded = map { $_ => undef } @{ $self->has_exclude_columns ? $self->exclude_columns : [] }; #XXX this abuse of '_im_class' needs to be fixed ASAP my $object_class = $self->collection->_im_class; - my @fields = $object_class->meta->compute_all_applicable_attributes; + my @fields = $object_class->meta->parameter_attributes; + #obviously only get fields with readers. + @fields = grep { $_->get_read_method } @fields; #eliminate excluded fields & treat names that start with an underscore as private @fields = grep {$_->name !~ /^_/ && !exists $excluded{$_->name} } @fields; + #eliminate fields marked as collections, or fields that are arrayrefs @fields = grep { !($_->has_type_constraint && @@ -54,14 +45,172 @@ class GridView is 'Reaction::UI::ViewPort', which { ) } @fields; #order the columns all nice and pretty, and only get fields with readers, duh - return $self->sort_by_spec - ( $self->column_order, [ map { (($_->get_read_method) || ()) } @fields] ); + my $ordered = $self->sort_by_spec + ( $self->column_order, [ map { (($_->name) || ()) } @fields] ); + + return $ordered; }; implements build_current_collection => as { shift->collection; }; + implements build_column_names => as { + my $self = shift; + [ map{ join(' ', map{ ucfirst } split('_', $_)) } @{$self->ordered_columns} ]; + } + + implements build_rows => as { + my ($self) = @_; + my @columns = @{ $self->ordered_columns }; + + my (@rows, $i); + my $builders = {}; + for my $obj ( $self->current_collection->members ) { + $i++; + my @cells; + for my $col (@columns) { + my $attr = $obj->meta->find_attribute_by_name($col); + my $build_meth = $builders->{$col} ||= $self->build_fields_for($attr); + my $loc = join('-', $self->location, 'row', $i, 'field', $attr->name); + my $args = {Field => { $attr->name => {location => $loc} } }; + my $cell = $self->$build_meth($obj, $attr, $args); + push(@cells, $cell) if $cell; + } + push(@rows,\@cells) + } + + return \@rows; + }; + + implements build_fields_for => as { + my ($self, $attr) = @_; + my $attr_name = $attr->name; + my $builder = "build_fields_for_name_${attr_name}"; + return $builder if $self->can($builder); + if ($attr->has_type_constraint) { + my $constraint = $attr->type_constraint; + my $base_name = $constraint->name; + my $tried_isa = 0; + CONSTRAINT: while (defined($constraint)) { + my $name = $constraint->name; + 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}"; + return $builder if $self->can($builder); + } + } + if (defined($name)) { + unless (defined($base_name)) { + $base_name = "(anon subtype of ${name})"; + } + my $mangled_name = $name; + $mangled_name =~ s/:+/_/g; + my $builder = "build_fields_for_type_${mangled_name}"; + return $builder if $self->can($builder); + } + $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"; + } + } else { + confess "Can't build field ${attr} without $builder method or type constraint"; + } + }; + + + implements build_simple_field => as { + my ($self, $class, $obj, $attr, $args) = @_; + my $attr_name = $attr->name; + my %extra; + if (my $config = $args->{Field}{$attr_name}) { + %extra = %$config; + } + + return $class->new( + object => $obj, + attribute => $attr, + name => $attr->name, + ctx => $self->ctx, + %extra + ); + }; + + implements build_fields_for_type_Num => as { + my ($self, $obj, $attr, $args) = @_; + $args->{Field}{$attr->name}{layout} = 'value/number' + unless( exists $args->{Field}{$attr->name} && + exists $args->{Field}{$attr->name}{layout} && + defined $args->{Field}{$attr->name}{layout} + ); + return $self->build_simple_field(Number, $obj, $attr, $args); + }; + + implements build_fields_for_type_Int => as { + my ($self, $obj, $attr, $args) = @_; + $args->{Field}{$attr->name}{layout} = 'value/number' + unless( exists $args->{Field}{$attr->name} && + exists $args->{Field}{$attr->name}{layout} && + defined $args->{Field}{$attr->name}{layout} + ); + return $self->build_simple_field(Number, $obj, $attr, $args); + }; + + implements build_fields_for_type_Bool => as { + my ($self, $obj, $attr, $args) = @_; + $args->{Field}{$attr->name}{layout} = 'value/boolean' + unless( exists $args->{Field}{$attr->name} && + exists $args->{Field}{$attr->name}{layout} && + defined $args->{Field}{$attr->name}{layout} + ); + return $self->build_simple_field(Boolean, $obj, $attr, $args); + }; + + implements build_fields_for_type_Password => as { return }; + + implements build_fields_for_type_Str => as { + my ($self, $obj, $attr, $args) = @_; + $args->{Field}{$attr->name}{layout} = 'value/string' + unless( exists $args->{Field}{$attr->name} && + exists $args->{Field}{$attr->name}{layout} && + defined $args->{Field}{$attr->name}{layout} + ); + return $self->build_simple_field(String, $obj, $attr, $args); + }; + + implements build_fields_for_type_SimpleStr => as { + my ($self, $obj, $attr, $args) = @_; + $args->{Field}{$attr->name}{layout} = 'value/string' + unless( exists $args->{Field}{$attr->name} && + exists $args->{Field}{$attr->name}{layout} && + defined $args->{Field}{$attr->name}{layout} + ); + return $self->build_simple_field(String, $obj, $attr, $args); + }; + + implements build_fields_for_type_DateTime => as { + my ($self, $obj, $attr, $args) = @_; + $args->{Field}{$attr->name}{layout} = 'value/date_time' + unless( exists $args->{Field}{$attr->name} && + exists $args->{Field}{$attr->name}{layout} && + defined $args->{Field}{$attr->name}{layout} + ); + return $self->build_simple_field(DateTime, $obj, $attr, $args); + }; + + implements build_fields_for_type_Enum => as { + my ($self, $obj, $attr, $args) = @_; + $args->{Field}{$attr->name}{layout} = 'value/string' + unless( exists $args->{Field}{$attr->name} && + exists $args->{Field}{$attr->name}{layout} && + defined $args->{Field}{$attr->name}{layout} + ); + return $self->build_simple_field(String, $obj, $attr, $args); + }; + }; |