abdecc4e0c0cd3af983066b8d3cdf053119966da
[catagits/Reaction.git] / lib / Reaction / UI / ViewPort / Collection / Grid.pm
1 package Reaction::UI::ViewPort::Collection::Grid;
2
3 use Reaction::Class;
4
5 use aliased 'Reaction::InterfaceModel::Collection' => 'IM_Collection';
6 use aliased 'Reaction::UI::ViewPort::Collection::Grid::Member::WithActions';
7
8 use namespace::clean -except => [ qw(meta) ];
9 use MooseX::Types::Moose qw/ArrayRef HashRef Int/;
10 extends 'Reaction::UI::ViewPort::Collection';
11
12 has field_order => ( is => 'ro', isa => ArrayRef, lazy_build => 1);
13 has excluded_fields => ( is => 'ro', isa => ArrayRef, lazy_build => 1);
14 has included_fields => ( is => 'ro', isa => ArrayRef, lazy_build => 1);
15 has computed_field_order => (is => 'ro', isa => ArrayRef, lazy_build => 1);
16
17 has _raw_field_labels => (
18   is => 'rw',
19   isa => HashRef,
20   init_arg => 'field_labels',
21   default => sub { {} },
22 );
23
24 has field_labels => (
25   is => 'ro',
26   isa => HashRef,
27   lazy_build => 1,
28   init_arg => undef,
29 );
30
31 has member_action_count => (
32   is => 'rw',
33   isa => Int,
34   required => 1,
35   lazy => 1,
36   default => sub {
37     my $self = shift;
38     for (@{ $self->members }) {
39       my $protos = $_->action_prototypes;
40       return scalar(keys(%$protos));
41     }
42     return 1;
43   },
44 );
45
46 ####################################
47 sub _build_member_class { WithActions };
48
49 sub _build_field_labels {
50   my $self = shift;
51   my %labels = %{$self->_raw_field_labels};
52   for my $field ( @{$self->computed_field_order}) {
53     next if defined $labels{$field};
54     $labels{$field} = join(' ', map{ ucfirst } split('_', $field));
55   }
56   return \%labels;
57 }
58
59 sub _build_field_order { []; }
60
61 sub _build_excluded_fields { []; }
62
63 sub _build_included_fields { [] }
64
65 #this is a total clusterfuck and it sucks we should just eliminate it and have
66 # the grid members not render ArrayRef or Collection fields
67 sub _build_computed_field_order {
68   my ($self) = @_;
69   my %excluded = map { $_ => undef } @{ $self->excluded_fields };
70   my %included = map { $_ => undef } @{ $self->included_fields };
71   #treat _$field_name as private and exclude fields with no reader
72   my @names = grep { $_ !~ /^_/ &&  (!%included || exists( $included{$_}) )
73     && !exists($excluded{$_})} map { $_->name }
74     grep {
75       !($_->has_type_constraint &&
76         ($_->type_constraint->is_a_type_of('ArrayRef') ||
77          eval {$_->type_constraint->name->isa('Reaction::InterfaceModel::Collection')} ||
78          eval { $_->_isa_metadata->isa('Reaction::InterfaceModel::Collection') }
79         )
80        )  }
81       grep { defined $_->get_read_method }
82         $self->current_collection->member_type->parameter_attributes;
83
84   return $self->sort_by_spec($self->field_order, \@names);
85 }
86
87 around _build_members => sub {
88   my $orig = shift;
89   my $self = shift;
90   $self->member_args->{computed_field_order} ||= $self->computed_field_order;
91   my $members = $self->$orig(@_);
92
93   return $members;
94 };
95
96 __PACKAGE__->meta->make_immutable;
97
98
99 1;
100
101 __END__;
102
103 =head1 NAME
104
105 Reaction::UI::ViewPort::Collection
106
107 =head1 DESCRIPTION
108
109 This subclass of L<Reaction::UI::ViewPort::Collection> allows you to display a
110 homogenous collection of Reaction::InterfaceModel::Objects as a grid.
111
112 =head1 ATTRIBUTES
113
114 =head2 field_order
115
116 =head2 excluded_fields
117
118 List of field names to exclude.
119
120 =head2 included_fields
121
122 List of field names to include. If both C<included_fields> and
123 C<excluded_fields> are specified the result is those fields which
124 are in C<included_fields> and not in C<excluded_fields>.
125
126 =head2 included_fields
127
128 List of field names to include. If both C<included_fields> and
129 C<excluded_fields> are specified the result is those fields which
130 are in C<included_fields> and not in C<excluded_fields>.
131
132
133 =head2 field_labels
134
135 =head2 _raw_field_labels
136
137 =head2 computed_field_order
138
139 =head2 member_action_count
140
141 =head1 INTERNAL METHODS
142
143 These methods, although stable, are subject to change without notice. These are meant
144 to be used only by developers. End users should refrain from using these methods to
145 avoid potential breakages.
146
147 =head1 SEE ALSO
148
149 L<Reaction::UI::ViewPort::Collection>
150
151 =head1 AUTHORS
152
153 See L<Reaction::Class> for authors.
154
155 =head1 LICENSE
156
157 See L<Reaction::Class> for the license.
158
159 =cut