File Coverage

blib/lib/Gtk2/Ex/DateRange.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Gtk2::Ex::DateRange;
2              
3             our $VERSION = '0.07';
4              
5 1     1   26430 use strict;
  1         2  
  1         49  
6 1     1   7 use warnings;
  1         1  
  1         38  
7 1     1   531 use Glib qw(TRUE FALSE);
  0            
  0            
8             use Data::Dumper;
9             use Gtk2::Ex::PopupWindow;
10             use Carp;
11              
12             sub new {
13             my ($class, $preselected) = @_;
14             my $self = {};
15             bless ($self, $class);
16             $self->{widget} = $self->_get_widget;
17             return $self;
18             }
19              
20             sub get_model {
21             my ($self) = @_;
22             return $self->{model};
23             }
24              
25             sub set_model {
26             my ($self, $model) = @_;
27             if (!$model) {
28             $self->_clear;
29             return;
30             }
31             $self->{freezesignals} = TRUE;
32             my $commandchoices = $self->{commandchoices};
33             my $joinerchoices = $self->{joinerchoices};
34             my $i = 0; my $commandhash = { map { $_ => $i++ } @$commandchoices };
35             $i = 0; my $joinerhash = { map { $_ => $i++ } @$joinerchoices };
36             _model_error_check($commandhash, $joinerhash, $model);
37            
38             $self->{commandcombo1}->set_active($commandhash->{$model->[0]});
39             _set_calendar_date($self->{calendar1}, $model->[1]);
40             _update_date_label($self->{calendar1}, $self->{datelabel1});
41             if ($#{@$model} == 1) {
42             $self->{freezesignals} = TRUE;
43             $self->{joinercombo}->set_active(0);
44             $self->{commandcombo2}->set_active(-1);
45             $self->{datelabel2}->set_label('(select a date)');
46             $self->{freezesignals} = FALSE;
47             &{ $self->{signals}->{'changed'} } if $self->{signals}->{'changed'};
48             return;
49             }
50            
51             $self->{joinercombo}->set_active($joinerhash->{$model->[2]});
52            
53             $self->{commandcombo2}->set_active($commandhash->{$model->[3]});
54             _set_calendar_date($self->{calendar2}, $model->[4]);
55             _update_date_label($self->{calendar2}, $self->{datelabel2});
56            
57             $self->{freezesignals} = FALSE;
58             &{ $self->{signals}->{'changed'} } if $self->{signals}->{'changed'};
59             }
60              
61             sub to_sql_condition {
62             my ($self, $fieldname, $model) = @_;
63             my $conversion = {
64             'before' => ' < ',
65             'after' => ' > ',
66             'on or before' => ' <= ',
67             'on or after' => ' >= ',
68             };
69             return undef if $#{@$model} < 1;
70             if ($#{@$model} >= 1 and $#{@$model} < 4) {
71             my $str =
72             $fieldname
73             .$conversion->{$model->[0]}
74             .'\''
75             .$model->[1]
76             .'\'';
77             return $str;
78             }
79             if ($#{@$model} == 4) {
80             my $str1 =
81             $fieldname
82             .$conversion->{$model->[0]}
83             .'\''
84             .$model->[1]
85             .'\'';
86             my $str2 = $model->[2];
87             my $str3 =
88             $fieldname
89             .$conversion->{$model->[3]}
90             .'\''
91             .$model->[4]
92             .'\'';
93             my $str = "( $str1 $str2 $str3 )";
94             return $str;
95             }
96             }
97              
98             sub _clear {
99             my ($self) = @_;
100             $self->{freezesignals} = TRUE;
101             $self->{commandcombo1}->set_active(-1);
102             $self->{datelabel1}->set_label('(select a date)');
103             $self->{datelabelbox1}->set_sensitive(FALSE);
104             $self->{joinercombo}->set_active(0);
105             $self->{joinercombo}->set_sensitive(FALSE);
106             $self->{commandcombo2}->set_active(-1);
107             $self->{datelabel2}->set_label('(select a date)');
108             $self->{model} = undef;
109             $self->{freezesignals} = FALSE;
110             &{ $self->{signals}->{'changed'} } if $self->{signals}->{'changed'};
111             }
112              
113             sub attach_popup_to {
114             my ($self, $parent) = @_;
115             my $popupwindow = Gtk2::Ex::PopupWindow->new($parent);
116             $popupwindow->set_move_with_parent(TRUE);
117             my $okbutton = Gtk2::Button->new_from_stock('gtk-ok');
118             $okbutton->signal_connect ('button-release-event' =>
119             sub {
120             $popupwindow->hide;
121             }
122             );
123             my $clearbutton = Gtk2::Button->new_from_stock('gtk-clear');
124             $clearbutton->signal_connect ('button-release-event' =>
125             sub {
126             $self->_clear;
127             }
128             );
129             my $hbox = Gtk2::HBox->new(TRUE, 0);
130             $hbox->pack_start ($clearbutton, TRUE, TRUE, 0);
131             $hbox->pack_start ($okbutton, TRUE, TRUE, 0);
132             my $vbox = Gtk2::VBox->new (FALSE, 0);
133             $vbox->pack_start ($self->{widget}, TRUE, TRUE, 0);
134             $vbox->pack_start ($hbox, FALSE, FALSE, 0);
135             my $frame = Gtk2::Frame->new;
136             $frame->add($vbox);
137             $self->{popup} = $popupwindow;
138             $popupwindow->{window}->add($frame);
139             return $popupwindow;
140             }
141              
142             sub signal_connect {
143             my ($self, $signal, $callback) = @_;
144             $self->{signals}->{$signal} = $callback;
145             }
146              
147             sub _model_error_check {
148             my ($commandhash, $joinerhash, $model) = @_;
149             return warn "Model should contain 2 or 5 parameters"
150             unless ($#{@$model} == 1 or $#{@$model} == 4);
151             return warn "Unknown command in model [@$model]"
152             unless exists($commandhash->{$model->[0]});
153             return if ($#{@$model} == 1);
154             return warn "Unknown joiner command in model [@$model]"
155             unless exists($joinerhash->{$model->[2]});
156             }
157              
158             sub _get_widget {
159             my ($self) = @_;
160            
161             my $commandchoices = ['before', 'after', 'on or after', 'on or before'];
162             my $joinerchoices = ['', 'and', 'or'];
163            
164             my $commandcombo1 = Gtk2::ComboBox->new_text;
165             my $datelabel1 = Gtk2::Label->new('(select a date)');
166             my $calendar1 = Gtk2::Calendar->new;
167             my $datelabelbox1 = $self->_calendar_popup($datelabel1, $calendar1, 1);
168             foreach my $x (@$commandchoices) {
169             $commandcombo1->append_text($x);
170             }
171             $commandcombo1->signal_connect ( 'changed' =>
172             sub {
173             $self->{model}->[0] = $commandchoices->[$commandcombo1->get_active()]
174             unless $commandcombo1->get_active() < 0;
175             $self->{datelabelbox1}->set_sensitive(TRUE);
176             &{ $self->{signals}->{'changed'} }
177             if $self->{signals}->{'changed'} and !$self->{freezesignals};
178             }
179             );
180              
181             my $commandcombo2 = Gtk2::ComboBox->new_text;
182             my $datelabel2 = Gtk2::Label->new('(select a date)');
183             my $calendar2 = Gtk2::Calendar->new;
184             my $datelabelbox2 = $self->_calendar_popup($datelabel2, $calendar2, 4);
185             foreach my $x (@$commandchoices) {
186             $commandcombo2->append_text($x);
187             }
188             $commandcombo2->signal_connect ( 'changed' =>
189             sub {
190             $self->{model}->[3] = $commandchoices->[$commandcombo2->get_active()]
191             unless $commandcombo2->get_active() < 0;
192             $self->{datelabelbox2}->set_sensitive(TRUE);
193             &{ $self->{signals}->{'changed'} }
194             if $self->{signals}->{'changed'} and !$self->{freezesignals};
195             }
196             );
197              
198             my $joinercombo = Gtk2::ComboBox->new_text;
199             foreach my $x (@$joinerchoices) {
200             $joinercombo->append_text($x);
201             }
202             $commandcombo2->set_no_show_all(TRUE);
203             $datelabelbox2->set_no_show_all(TRUE);
204             $joinercombo->signal_connect ( 'changed' =>
205             sub {
206             if ($joinercombo->get_active() == 0) {
207             $commandcombo2->hide_all;
208             $datelabelbox2->hide_all;
209             $commandcombo2->set_no_show_all(TRUE);
210             $datelabelbox2->set_no_show_all(TRUE);
211             $self->{model} = [$self->{model}->[0], $self->{model}->[1]];
212             $commandcombo2->set_active(-1);
213             $datelabel2->set_label('(select a date)');
214             } else {
215             $commandcombo2->set_no_show_all(FALSE);
216             $datelabelbox2->set_no_show_all(FALSE);
217             $commandcombo2->show_all;
218             $datelabelbox2->show_all;
219             $self->{model}->[2] = $joinerchoices->[$joinercombo->get_active()];
220             &{ $self->{signals}->{'changed'} }
221             if $self->{signals}->{'changed'} and !$self->{freezesignals};
222             }
223             }
224             );
225              
226             $self->{commandchoices}= $commandchoices;
227             $self->{joinerchoices} = $joinerchoices;
228            
229             $self->{commandcombo1} = $commandcombo1;
230             $self->{datelabel1} = $datelabel1;
231             $self->{calendar1} = $calendar1;
232             $self->{datelabelbox1} = $datelabelbox1;
233              
234             $self->{commandcombo2} = $commandcombo2;
235             $self->{datelabel2} = $datelabel2;
236             $self->{calendar2} = $calendar2;
237             $self->{datelabelbox2} = $datelabelbox2;
238              
239             $self->{joinercombo} = $joinercombo;
240              
241             $self->{datelabelbox1}->set_sensitive(FALSE);
242             $self->{joinercombo}->set_sensitive(FALSE);
243             $self->{datelabelbox2}->set_sensitive(FALSE);
244            
245             $commandcombo1->set_wrap_width(1);
246             $joinercombo->set_wrap_width(1);
247             $commandcombo2->set_wrap_width(1);
248              
249             my $table = Gtk2::Table->new(3,3,FALSE);
250             $table->set_col_spacings(5);
251             $table->attach($commandcombo1,0,1,0,1, 'expand', 'expand', 0, 0);
252             $table->attach($datelabelbox1,1,2,0,1, 'expand', 'expand', 0, 0);
253             $table->attach($joinercombo ,2,3,0,1, 'expand', 'expand', 0, 0);
254             $table->attach($commandcombo2,0,1,1,2, 'expand', 'expand', 0, 0);
255             $table->attach($datelabelbox2,1,2,1,2, 'expand', 'expand', 0, 0);
256             return $table;
257             }
258              
259             sub _get_date_string {
260             my ($calendar) = @_;
261             my ($year, $month, $day) = $calendar->get_date();
262             $month += 1;
263             $day = "0$day" if $day < 10;
264             $month = "0$month" if $month < 10;
265             return "$year-$month-$day";
266             }
267              
268             sub _set_calendar_date {
269             my ($calendar, $datestr) = @_;
270             my ($year, $month, $day) = split '-', $datestr;
271             $calendar->select_month($month-1, $year);
272             $calendar->select_day($day);
273             }
274              
275             sub _update_date_label {
276             my ($calendar, $datelabel) = @_;
277             my ($year, $month, $day) = $calendar->get_date();
278             $month = _month()->[$month];
279             my $date_str = "$month $day \, $year";
280             $datelabel->set_text($date_str);
281             }
282              
283             sub _calendar_popup {
284             my ($self, $datelabel, $calendar, $num) = @_;
285             my $datelabelbox = _add_button_press(_add_arrow($datelabel));
286             my $datepopup = Gtk2::Ex::PopupWindow->new($datelabel);
287             my $okbutton = Gtk2::Button->new_from_stock('gtk-ok');
288             $okbutton->signal_connect ('button-release-event' =>
289             sub {
290             _update_date_label($calendar, $datelabel);
291             $self->{model}->[$num] = _get_date_string($calendar);
292             $self->{joinercombo}->set_sensitive(TRUE) if ($num == 1);
293             $datepopup->hide;
294             &{ $self->{signals}->{'changed'} }
295             if $self->{signals}->{'changed'} and !$self->{freezesignals};
296             }
297             );
298             $calendar->signal_connect ( 'day-selected' =>
299             sub {
300             _update_date_label($calendar, $datelabel);
301             $self->{model}->[$num] = _get_date_string($calendar);
302             $self->{joinercombo}->set_sensitive(TRUE) if ($num == 1);
303             }
304             );
305             my $hbox = Gtk2::HBox->new (TRUE, 0);
306             $hbox->pack_start ($okbutton, TRUE, TRUE, 0);
307             my $vbox = Gtk2::VBox->new (FALSE, 0);
308             $vbox->pack_start ($calendar, TRUE, TRUE, 0);
309             $vbox->pack_start ($hbox, FALSE, FALSE, 0);
310             $datepopup->{window}->add($vbox);
311             $datelabelbox->signal_connect ('button-release-event' =>
312             sub {
313             $datepopup->show;
314             }
315             );
316            
317             $datepopup->signal_connect('show' =>
318             sub {
319             return unless $self->{popup};
320             if ($^O =~ /Win32/) {
321             $self->{popup}->set_move_with_parent(TRUE);
322             $self->{popup}->show;
323             }
324             }
325             );
326             $datepopup->signal_connect('hide' =>
327             sub {
328             return unless $self->{popup};
329             if ($^O =~ /Win32/) {
330             $self->{popup}->set_move_with_parent(FALSE);
331             }
332             }
333             );
334             if ($self->{popup}) {
335             $self->{popup}->signal_connect('hide' =>
336             sub {
337             $datepopup->hide;
338             }
339             );
340             }
341             return $datelabelbox;
342             }
343              
344             sub _month {
345             return [
346             'January',
347             'February',
348             'March',
349             'April',
350             'May',
351             'June',
352             'July',
353             'August',
354             'September',
355             'October',
356             'November',
357             'December',
358             ];
359             }
360              
361             sub _add_button_press {
362             my ($widget) = @_;
363             my $eventbox = Gtk2::EventBox->new;
364             $eventbox->add ($widget);
365             $eventbox->add_events (['button-release-mask']);
366             return $eventbox;
367             }
368              
369             sub _add_arrow {
370             my ($label) = @_;
371             my $arrow = Gtk2::Arrow -> new('down', 'none');
372             my $labelbox = Gtk2::HBox->new (FALSE, 0);
373             $labelbox->pack_start ($label, FALSE, FALSE, 0);
374             $labelbox->pack_start ($arrow, FALSE, FALSE, 0);
375             return $labelbox;
376             }
377              
378             1;
379              
380             __END__