File Coverage

blib/lib/Gtk2/Ex/History/Dialog.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             # Copyright 2010, 2011 Kevin Ryde
2              
3             # This file is part of Gtk2-Ex-History.
4             #
5             # Gtk2-Ex-History is free software; you can redistribute it and/or modify it
6             # under the terms of the GNU General Public License as published by the Free
7             # Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # Gtk2-Ex-History 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-History. If not, see .
17              
18              
19             # popup menu for items
20             # Goto
21             # Copy to Selection
22              
23              
24             package Gtk2::Ex::History::Dialog;
25 1     1   61320 use 5.008;
  1         4  
  1         47  
26 1     1   6 use strict;
  1         2  
  1         31  
27 1     1   5 use warnings;
  1         2  
  1         34  
28 1     1   1829 use Gtk2;
  0            
  0            
29             use List::Util;
30             use POSIX ();
31              
32             use Gtk2::Ex::History;
33             use Gtk2::Ex::Units;
34              
35             use Locale::TextDomain ('Gtk2-Ex-History');
36             use Locale::Messages;
37             BEGIN {
38             Locale::Messages::bind_textdomain_codeset ('Gtk2-Ex-History','UTF-8');
39             Locale::Messages::bind_textdomain_filter ('Gtk2-Ex-History',
40             \&Locale::Messages::turn_utf_8_on);
41             }
42              
43             # uncomment this to run the ### lines
44             #use Smart::Comments;
45              
46             our $VERSION = 8;
47              
48             use Glib::Object::Subclass
49             'Gtk2::Dialog',
50             properties => [ Glib::ParamSpec->object
51             ('history',
52             __('History object'),
53             'The history object to present and act on.',
54             'Gtk2::Ex::History',
55             Glib::G_PARAM_READWRITE),
56             ];
57              
58             sub INIT_INSTANCE {
59             my ($self) = @_;
60             ### History-Dialog INIT_INSTANCE()
61              
62             $self->set_title (__x('{appname}: History',
63             appname => Glib::get_application_name()));
64             $self->add_buttons ('gtk-close' => 'close');
65             $self->signal_connect (response => \&_do_response);
66              
67             my $vbox = $self->vbox;
68              
69             my $renderer = Gtk2::CellRendererText->new;
70             $renderer->set (xalign => 0, ypad => 0);
71              
72             {
73             my $hbox = Gtk2::HBox->new;
74             $vbox->pack_start ($hbox, 0,0,0);
75              
76             $hbox->pack_start (Gtk2::Label->new (__('Current')),
77             0,0,0);
78              
79             my $treeview = $self->{'current_treeview'} = Gtk2::TreeView->new;
80             $treeview->{'way'} = 'current';
81             $treeview->enable_model_drag_dest
82             (['move'], { target => 'GTK_TREE_MODEL_ROW',
83             flags => ['same-app'] },
84             { target => 'text/plain' });
85             $treeview->signal_connect (row_activated => \&_do_row_activated);
86             # must expand/fill to give a width, otherwise Gtk 2.20.1 gets errors
87             # about width==-1 when model is empty
88             $hbox->pack_start ($treeview, 1,1,
89             POSIX::ceil(Gtk2::Ex::Units::width($treeview,'2 em'))),
90              
91             my $column = Gtk2::TreeViewColumn->new_with_attributes ('', $renderer);
92             $column->set_cell_data_func ($renderer, \&_do_cell_data);
93             $treeview->append_column ($column);
94              
95             $hbox->show_all;
96             }
97              
98             my $table = Gtk2::Table->new (1, 2);
99             $vbox->pack_start ($table, 1,1,0);
100              
101             my $tpos = 0;
102             my @scrolled_list;
103             foreach my $way ('back', 'forward') {
104             my $scrolled = Gtk2::ScrolledWindow->new;
105             push @scrolled_list, $scrolled;
106             $scrolled->set (hscrollbar_policy => 'automatic',
107             vscrollbar_policy => 'automatic');
108             $table->attach ($scrolled, $tpos, $tpos+1, 0,1,
109             ['fill','shrink','expand'],
110             ['fill','shrink','expand'],
111             POSIX::ceil(Gtk2::Ex::Units::width($scrolled,'.2 em')),
112             0);
113             $tpos++;
114              
115             my $treeview = $self->{"${way}_treeview"} = Gtk2::TreeView->new;
116             $treeview->{'way'} = $way;
117             $treeview->set (reorderable => 1);
118             $treeview->enable_model_drag_dest
119             (['move'], { target => 'GTK_TREE_MODEL_ROW',
120             flags => ['same-app'] },
121             { target => 'text/plain' });
122             $treeview->signal_connect (row_activated => \&_do_row_activated);
123             $scrolled->add ($treeview);
124              
125             my $name = ($way eq 'back' ? __('Back') : __('Forward'));
126             my $column = Gtk2::TreeViewColumn->new_with_attributes ($name, $renderer);
127             $column->set_cell_data_func ($renderer, \&_do_cell_data);
128             $column->set (clickable => 1);
129             $treeview->append_column ($column);
130             $column->signal_connect (clicked => \&_do_column_clicked);
131             }
132              
133             $vbox->show_all;
134              
135             Gtk2::Ex::Units::set_default_size_with_subsizes
136             ($self,
137             map {[$_, '20 em', '15 lines']} @scrolled_list);
138             ### default size: $self->get_default_size
139             }
140              
141             sub SET_PROPERTY {
142             my ($self, $pspec, $newval) = @_;
143             my $pname = $pspec->get_name;
144             ### History-Dialog SET_PROPERTY(): $pname
145             $self->{$pname} = $newval; # per default GET_PROPERTY
146              
147             if ($pname eq 'history') {
148             my $history = $newval;
149              
150             foreach my $way ('current', 'back', 'forward') {
151             my $treeview = $self->{"${way}_treeview"};
152             $treeview->set_model ($history && $history->model($way));
153             }
154             # workaround for 2.18 sizing bug
155             $self->{'current_treeview'}->set_headers_visible (! $history);
156             }
157             }
158              
159             # 'response' signal handler
160             sub _do_response {
161             my ($self, $response) = @_;
162             ### HistoryDialog response: $response
163              
164             if ($response eq 'close') {
165             # as per a keyboard close, defaults to raising 'delete-event', which in
166             # turn defaults to a destroy
167             $self->signal_emit ('close');
168             }
169             }
170              
171             # 'set_cell_data' handler on TreeViewColumn
172             sub _do_cell_data {
173             my ($column, $renderer, $model, $iter) = @_;
174             my $treeview = $column->get_tree_view || return;
175             my $self = $treeview->get_ancestor(__PACKAGE__) || return;
176             my $history = $self->{'history'} || return;
177             my $str = $history->signal_emit ('place-to-text', $model->get($iter,0));
178             my $field = ($history->get('use-markup') ? 'markup' : 'text');
179             $renderer->set ($field => $str);
180             }
181              
182             # 'clicked' signal on TreeViewColumn
183             sub _do_column_clicked {
184             my ($column) = @_;
185             my $treeview = $column->get_tree_view;
186             my $self = $treeview->get_ancestor (__PACKAGE__);
187             my $history = $self->{'history'} || return; # perhaps not yet set
188             my $way = $treeview->{'way'};
189             $history->$way;
190             }
191              
192             # 'row-activated' signal on a TreeView
193             sub _do_row_activated {
194             my ($treeview, $path, $treeviewcolumn) = @_;
195             my $self = $treeview->get_ancestor (__PACKAGE__);
196             my $history = $self->{'history'} || return; # in case gone somehow
197             my ($n) = $path->get_indices;
198             my $way = $treeview->{'way'};
199             $history->$way ($n+1);
200             }
201              
202             # Not sure about this yet, might prefer general Gtk2::Ex::ToplevelBits find
203             # and popup.
204             #
205             # =item C<< Gtk2::Ex::History::Dialog->popup ($history) >>
206             #
207             # =item C<< Gtk2::Ex::History::Dialog->popup ($history, $parent) >>
208             #
209             # Popup a C for the given C object,
210             # possibly re-using an existing dialog if there's one showing it already.
211             #
212             # Optional C<$parent> is a widget the popup originates from. If a dialog
213             # already exists on the same screen as C<$parent> (or the default screen) then
214             # it's re-presented, otherwise a new dialog is created on the screen of
215             # C<$parent> (or the default screen).
216              
217             sub popup {
218             my ($class, $history, $parent) = @_;
219             ### History-Dialog popup(): "$history"
220             ### parent: $parent && "$parent"
221              
222             my $screen = ($parent ? $parent->get_screen : Gtk2::Gdk::Screen->get_default);
223             my $dialog = (List::Util::first
224             { $_->isa($class)
225             && $_->get_screen == $screen
226             && $_->get('history') == $history
227             } Gtk2::Window->list_toplevels)
228             || do {
229             ### new dialog
230             $class->new (history => $history,
231             screen => $screen);
232             };
233             ### dialog: "$dialog"
234             ### screen: $dialog->get_screen
235             ### children: $dialog->get_children
236              
237             $dialog->present;
238             return $dialog;
239             }
240              
241             # sub find {
242             # my ($class, $history) = @_;
243             # foreach my $widget (Gtk2::Window->list_toplevels) {
244             # $widget->isa($class) || next;
245             # my $this_history = $widget->get('history') || next;
246             # if ($this_history == $history) {
247             # return $widget;
248             # }
249             # }
250             # return $class->new (history => $history);
251             # }
252              
253             1;
254             __END__