File Coverage

blib/lib/Gtk2/Ex/TiedListColumn.pm
Criterion Covered Total %
statement 18 141 12.7
branch 0 28 0.0
condition 0 10 0.0
subroutine 6 23 26.0
pod 3 3 100.0
total 27 205 13.1


line stmt bran cond sub pod time code
1             # Copyright 2008, 2009, 2010 Kevin Ryde
2              
3             # This file is part of Gtk2-Ex-TiedListColumn.
4             #
5             # Gtk2-Ex-TiedListColumn is free software; you can redistribute it and/or
6             # modify it under the terms of the GNU General Public License as published
7             # by the Free Software Foundation; either version 3, or (at your option) any
8             # later version.
9             #
10             # Gtk2-Ex-TiedListColumn is distributed in the hope that it will be useful,
11             # but WITHOUT ANY WARRANTY; without even the implied warranty of
12             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13             # Public License for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Gtk2-Ex-TiedListColumn. If not, see .
17              
18              
19             package Gtk2::Ex::TiedListColumn;
20 2     2   1270 use 5.008;
  2         7  
  2         70  
21 2     2   11 use strict;
  2         3  
  2         54  
22 2     2   11 use warnings;
  2         12  
  2         48  
23 2     2   10 use Carp;
  2         3  
  2         173  
24 2     2   10 use List::Util qw(min max);
  2         3  
  2         381  
25              
26             our $VERSION = 5;
27              
28 2     2   12 use constant DEBUG => 0;
  2         2  
  2         15338  
29              
30             sub new {
31 0     0 1   my ($class, $model, $column) = @_;
32 0           tie (my @array, $class, $model, $column);
33 0           return \@array;
34             }
35              
36             sub TIEARRAY {
37 0     0     my ($class, $model, $column) = @_;
38 0   0       return bless { model => $model,
39             column => ($column||0)
40             }, $class;
41             }
42             # optional, not needed
43             # sub UNTIE { }
44              
45             # tied object funcs
46             sub model {
47 0     0 1   my ($self) = @_;
48 0           return $self->{'model'};
49             }
50             sub column {
51 0     0 1   my ($self) = @_;
52 0           return $self->{'column'};
53             }
54              
55             # negative indices already normalized to >=0 by the time they get here
56             sub FETCH {
57 0     0     my ($self, $index) = @_;
58 0           if (DEBUG >= 2) { print "FETCH $index\n"; }
59 0           my $model = $self->{'model'};
60 0   0       my $iter = $model->get_iter (Gtk2::TreePath->new ($index))
61             || return undef;
62 0           return $model->get_value ($iter, $self->{'column'});
63             }
64              
65             # negative indices already normalized to >=0 by the time they get here
66             sub STORE {
67 0     0     my ($self, $index, $value) = @_;
68 0           if (DEBUG) { print "STORE $index $value\n"; }
69 0           my $model = $self->{'model'};
70 0           my $iter = $model->get_iter (Gtk2::TreePath->new ($index));
71 0 0         if (! $iter) {
72 0           my $len = $model->iter_n_children (undef);
73 0           while ($len <= $index) {
74 0           $iter = $model->insert ($len);
75 0           $len++;
76             }
77             }
78 0           $model->set_value ($iter, $self->{'column'}, $value);
79             }
80              
81             sub FETCHSIZE {
82 0     0     my ($self) = @_;
83 0           if (DEBUG) { print "FETCHSIZE\n"; }
84 0           my $model = $self->{'model'};
85 0           return $model->iter_n_children (undef);
86             }
87              
88             # big negatives already normalized to 0 by the time they get here
89             sub STORESIZE {
90 0     0     my ($self, $want_size) = @_;
91 0           if (DEBUG) { print "STORESIZE $want_size, currently ",
92             $self->{'model'}->iter_n_children (undef),"\n"; }
93 0           my $model = $self->{'model'};
94 0           my $got_size = $model->iter_n_children (undef);
95 0           while ($got_size < $want_size) {
96 0           $model->append;
97 0           $got_size++;
98             }
99 0           while ($got_size > $want_size) {
100 0           my $iter = $model->get_iter (Gtk2::TreePath->new($got_size-1));
101 0           $model->remove ($iter);
102 0           $got_size--;
103             }
104             }
105              
106 0     0     sub EXTEND {
107             }
108              
109             # negative indices already normalized to >=0 by the time they get here
110             sub EXISTS {
111 0     0     my ($self, $index) = @_;
112 0           if (DEBUG) { print "EXISTS $index\n"; }
113 0           my $model = $self->{'model'};
114 0           return $index < $model->iter_n_children(undef);
115             }
116              
117             sub DELETE {
118 0     0     my ($self, $index) = @_;
119 0           if (DEBUG) { print "DELETE $index\n"; }
120 0           my $model = $self->{'model'};
121              
122 0   0       my $iter = $model->get_iter (Gtk2::TreePath->new ($index))
123             || return undef;
124 0           my $ret = $model->get_value ($iter);
125 0           my $len = $model->iter_n_children (undef);
126 0 0         if ($index == $len-1) {
127 0           $model->remove ($iter);
128             } else {
129 0           $model->set ($iter, $self->{'column'}, undef);
130             }
131 0           return $ret;
132             }
133              
134             sub CLEAR {
135 0     0     my ($self) = @_;
136 0           if (DEBUG) { print "CLEAR\n"; }
137 0           my $model = $self->{'model'};
138 0           $model->clear;
139             }
140              
141             sub PUSH {
142 0     0     my $self = shift;
143 0           my $model = $self->{'model'};
144 0           my $column = $self->{'column'};
145 0           my $pos = $model->iter_n_children (undef);
146 0           foreach my $value (@_) {
147 0           $model->insert_with_values ($pos++, $column, $value);
148             }
149             }
150              
151             sub POP {
152 0     0     my ($self) = @_;
153 0           if (DEBUG) { print "POP\n"; }
154 0           my $model = $self->{'model'};
155 0   0       my $len = $model->iter_n_children (undef) || return undef; # if empty
156 0           my $iter = $model->iter_nth_child (undef, $len-1);
157 0           my $value = $model->get_value ($iter, $self->{'column'});
158 0           $model->remove ($iter);
159 0           return $value;
160             }
161              
162             sub SHIFT {
163 0     0     my ($self) = @_;
164 0           my $model = $self->{'model'};
165 0   0       my $iter = $model->get_iter_first || return undef; # if empty
166 0           my $value = $model->get_value ($iter, $self->{'column'});
167 0           $model->remove ($iter);
168 0           return $value;
169             }
170              
171             # don't have to return the new size here, FETCHSIZE is called separately
172             sub UNSHIFT {
173 0     0     my $self = shift;
174 0           if (DEBUG) { print "UNSHIFT\n"; }
175 0           my $model = $self->{'model'};
176 0           my $column = $self->{'column'};
177 0           my $pos = 0;
178 0           foreach my $value (@_) {
179 0           $model->insert_with_values ($pos++, $column, $value);
180             }
181             }
182              
183             sub SPLICE {
184 0     0     my $self = shift;
185 0           my $offset = shift;
186 0           my $length = shift;
187 0           if (DEBUG) { print "SPLICE ",defined $offset ? $offset : 'undef',
188             " ", defined $length ? $length : 'undef', "\n"; }
189              
190 0           my $model = $self->{'model'};
191 0           my $column = $self->{'column'};
192 0           my $total = $model->iter_n_children (undef);
193              
194             # carp similar to "use warnings" on ordinary arrays
195 0 0         if (! defined $offset) {
    0          
    0          
    0          
196 0           $offset = 0;
197             } elsif ($offset < -$total) {
198 0           carp "TiedListColumn: offset $offset before start of array";
199 0           $offset = 0;
200             } elsif ($offset < 0) {
201 0           $offset += $total;
202             } elsif ($offset > $total) {
203 0           carp "TiedListColumn: offset $offset past end of array";
204 0           $offset = $total;
205             }
206              
207 0 0         if (! defined $length) {
    0          
208 0           $length = $total - $offset;
209             } elsif ($length < 0) {
210 0           $length = max (0, $total + $length - $offset);
211             } else {
212 0           $length = min ($length, $total - $offset);
213             }
214              
215 0           if (DEBUG) { print " norm to $offset, $length\n"; }
216              
217 0           my @ret;
218 0 0         if ($length > 0) {
219 0           my $iter = $model->iter_nth_child (undef, $offset);
220 0 0         if (wantarray) {
221 0           $#ret = $length-1;
222 0           foreach my $i (0 .. $length-1) {
223 0           $ret[$i] = $model->get_value ($iter, $column);
224 0 0         $model->remove ($iter) or last;
225             }
226              
227             } else {
228 0           $ret[0] = undef;
229 0           foreach (0 .. $length-2) {
230 0 0         if (! $model->remove ($iter)) {
231 0           $iter = undef;
232 0           last;
233             }
234             }
235 0 0         if ($iter) {
236 0           $ret[0] = $model->get_value ($iter, $column);
237 0           $model->remove ($iter);
238             }
239             }
240             }
241              
242 0           foreach my $value (@_) {
243 0           $model->insert_with_values ($offset++, $column, $value);
244             }
245              
246             # here in scalar context $ret[0] is the last removed as per what splice()
247             # should return
248 0 0         return (wantarray ? @ret : $ret[0]);
249             }
250              
251             1;
252             __END__