File Coverage

blib/lib/Gtk2/Ex/DateSpinner.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             # Copyright 2008, 2009, 2010, 2013 Kevin Ryde
2              
3             # This file is part of Gtk2-Ex-DateSpinner.
4             #
5             # Gtk2-Ex-DateSpinner 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-DateSpinner is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Gtk2-Ex-DateSpinner. If not, see .
17              
18             package Gtk2::Ex::DateSpinner;
19 3     3   2784 use 5.008;
  3         13  
  3         6958  
20 3     3   29 use strict;
  3         10  
  3         149  
21 3     3   17 use warnings;
  3         8  
  3         116  
22 3     3   3400 use Date::Calc;
  3         287491  
  3         152  
23 3     3   7266 use Gtk2;
  0            
  0            
24             use Glib::Ex::ObjectBits 'set_property_maybe';
25             # 1.16 for turn_utf_8_on()
26             use Locale::Messages 1.16 'dgettext', 'turn_utf_8_on';
27              
28             our $VERSION = 9;
29              
30             # uncomment this to run the ### lines
31             # use Smart::Comments;
32              
33             use Glib::Object::Subclass
34             'Gtk2::HBox',
35             properties => [Glib::ParamSpec->string
36             ('value',
37             'Date value',
38             'ISO format date string like 2008-07-25.',
39             '2000-01-01',
40             Glib::G_PARAM_READWRITE),
41             ];
42              
43             sub INIT_INSTANCE {
44             my ($self) = @_;
45             ### DateSpinner INIT_INSTANCE() ...
46              
47             $self->{'value'} = '2000-01-01';
48              
49             my $year_adj = Gtk2::Adjustment->new (2000, # initial
50             0, 9999, # range
51             1, # step increment
52             10, # page_increment
53             0); # page_size (not applicable)
54             my $year = $self->{'year'} = Gtk2::SpinButton->new ($year_adj, 1, 0);
55             $year->signal_connect (insert_text => \&_do_spin_insert_text);
56             $year->show;
57             $self->pack_start ($year, 0,0,0);
58              
59             my $month_adj = Gtk2::Adjustment->new (1, # initial
60             0, 99, # range
61             1, # step_increment
62             1, # page_increment
63             0); # page_size (not applicable)
64             my $month = $self->{'month'} = Gtk2::SpinButton->new ($month_adj, 1, 0);
65             $month->signal_connect (insert_text => \&_do_spin_insert_text);
66             $month->show;
67             $self->pack_start ($month, 0,0,0);
68              
69             my $day_adj = Gtk2::Adjustment->new (1, # initial
70             0, 99, # range
71             1, # step_increment
72             1, # page_increment
73             0); # page_size (not applicable)
74             my $day = $self->{'day'} = Gtk2::SpinButton->new ($day_adj, 1, 0);
75             $day->signal_connect (insert_text => \&_do_spin_insert_text);
76             $day->show;
77             $self->pack_start ($day, 0,0,0);
78              
79             # translations from Gtk itself
80             # eg. from /usr/share/locale/de/LC_MESSAGES/gtk20-properties.mo
81             # tooltip-text new in Gtk 2.10
82             set_property_maybe ($year, tooltip_text =>
83             turn_utf_8_on(dgettext('gtk20-properties','Year')));
84             set_property_maybe ($month, tooltip_text =>
85             turn_utf_8_on(dgettext('gtk20-properties','Month')));
86             set_property_maybe ($day, tooltip_text =>
87             turn_utf_8_on(dgettext('gtk20-properties','Day')));
88              
89             my $dow = $self->{'dayofweek_label'}
90             = Gtk2::Label->new (_ymd_to_wday_str(2000,1,1));
91             $dow->show;
92             $self->pack_start ($dow, 0,0,0);
93              
94             $year->signal_connect (value_changed => \&_spin_value_changed);
95             $month->signal_connect (value_changed => \&_spin_value_changed);
96             $day->signal_connect (value_changed => \&_spin_value_changed);
97             }
98              
99             sub SET_PROPERTY {
100             my ($self, $pspec, $newval) = @_;
101             ### DateSpinner SET_PROPERTY() ...
102              
103             my $pname = $pspec->get_name;
104             $self->{$pname} = $newval; # per default GET_PROPERTY
105              
106             if ($pname eq 'value') {
107             my ($year, $month, $day) = split /-/, $newval;
108             $self->{'year'}->set_value ($year);
109             $self->{'month'}->set_value ($month);
110             $self->{'day'}->set_value ($day);
111             }
112             }
113              
114             sub _do_spin_insert_text {
115             my ($spin, $text, $len) = @_;
116             ### DateSpinner insert: $text
117             $text =~ s/^\s+//;
118             $text =~ s/\s+$//;
119             if ($text =~ /^\d\d\d\d-\d\d-\d\d$/) {
120             my $self = $spin->parent;
121             $self->set (value => $text);
122             $spin->signal_stop_emission_by_name ('insert-text');
123             }
124             return;
125             }
126              
127             # Signal handler for 'value-changed' on the year,month,day SpinButtons.
128             # $spin is one of $self->{'year'},'month', or 'day
129             sub _spin_value_changed {
130             my ($spin) = @_;
131             ### DateSpinner _spin_value_changed() ...
132             my $self = $spin->parent;
133              
134             if ($self->{'update_in_progress'}) { return; }
135             local $self->{'update_in_progress'} = 1;
136              
137             my $year_spin = $self->{'year'};
138             my $month_spin = $self->{'month'};
139             my $day_spin = $self->{'day'};
140              
141             my $year = $year_spin->get_value;
142             my $month = $month_spin->get_value;
143             my $day = $day_spin->get_value;
144             ### DateSpinner update: "$year, $month, $day"
145              
146             ($year, $month, $day) = Date::Calc::Add_Delta_YMD
147             (2000, 1, 1, $year-2000, $month-1, $day-1);
148              
149             $year_spin->set_value ($year);
150             $month_spin->set_value ($month);
151             $day_spin->set_value ($day);
152              
153             $self->{'dayofweek_label'}->set_text (_ymd_to_wday_str($year,$month,$day));
154              
155             my $value = sprintf ('%04d-%02d-%02d', $year, $month, $day);
156             ### new value: $value
157             ### old value: $self->{'value'}
158             if ($value ne $self->{'value'}) {
159             ### notify ...
160             $self->{'value'} = $value;
161             $self->notify('value');
162             }
163             }
164              
165             # $year is 2000 etc, $month is 1 to 12, $day is 1 to 31.
166             # Return a wide-char string which is the short name of the day of the week
167             # to show, such as " Fri ".
168             #
169             # Prefer strftime over Date::Calc's localized names, on the basis that
170             # strftime will probably know more languages, and setlocale() is done
171             # automatically when perl starts.
172             #
173             # These modules are required for the initial value when a DateSpinner is
174             # created. Deferring them until this time (rather than BEGIN time) might
175             # let you load DateSpinner without yet dragging in the other big stuff.
176             #
177             sub _ymd_to_wday_str {
178             my ($year,$month,$day) = @_;
179             require POSIX;
180             require I18N::Langinfo;
181             require Encode;
182             my $wday = Date::Calc::Day_of_Week ($year, $month, $day); # 1=Mon,7=Sun,...
183             my $str = POSIX::strftime (' %a ', 0,0,0, 1,1,100, $wday%7);# 0=Sun,1=Mon,..
184             my $charset = I18N::Langinfo::langinfo (I18N::Langinfo::CODESET());
185             return Encode::decode ($charset, $str);
186             }
187              
188             sub get_value {
189             my ($self) = @_;
190             return $self->{'value'};
191             }
192              
193             sub set_today {
194             my ($self) = @_;
195             my ($year, $month, $day) = Date::Calc::Today();
196             $self->set (value => sprintf ('%04d-%02d-%02d', $year, $month, $day));
197             }
198              
199             1;
200             __END__