App-Chart
view release on metacpan or search on metacpan
lib/App/Chart/Gtk2/DownloadDialog.pm view on Meta::CPAN
$jobs_scrolled->add ($treeview);
$treeview->add_events ('button-press-mask');
$treeview->signal_connect
(button_press_event => \&_do_jobs_treeview_button_press);
my $selection = $treeview->get_selection();
$selection->signal_connect (changed => \&_do_selection_changed, $self);
$selection->set_mode ('single');
{
my $column = Gtk2::TreeViewColumn->new;
$column->pack_start ($renderer, 1);
$column->set_cell_data_func ($renderer, \&_job_cell_status);
$treeview->append_column ($column);
}
{ my $label = Gtk2::Label->new(__('Messages'));
$label->set (xalign => 0);
$vbox->pack_start ($label, 0,0,0);
}
my $textbuf = $self->{'textbuf'} = Gtk2::TextBuffer->new();
$textbuf->signal_connect ('changed', \&_do_textbuf_changed, $self);
require Gtk2::Ex::TextView::FollowAppend;
my $textview = $self->{'textview'}
= Gtk2::Ex::TextView::FollowAppend->new_with_buffer ($textbuf);
$textview->set (wrap_mode => 'char',
editable => 0);
my $messages_scrolled = Gtk2::ScrolledWindow->new();
$messages_scrolled->add($textview);
$messages_scrolled->set_policy('never', 'always');
$vbox->pack_start ($messages_scrolled, 1, 1, 0);
# During perl "global destruction" can have App::Chart::Gtk2::Job already
# destroyed enough that it has disconnected the message emission hook
# itself, leading to an unsightly Glib warning if attempting
# signal_remove_emission_hook() in our 'destroy' class closure. So
# instead leave it connected, with a weakened ref, and let it return 0 to
# disconnect itself on the next emission (if any).
#
# App::Chart::Gtk2::Job->signal_add_emission_hook
# (message => \&_do_job_message, App::Chart::Glib::Ex::MoreUtils::ref_weak ($self));
#
require App::Chart::Glib::Ex::EmissionHook;
$self->{'hook'} = App::Chart::Glib::Ex::EmissionHook->new
('App::Chart::Gtk2::Job',
message => \&_do_job_message,
App::Chart::Glib::Ex::MoreUtils::ref_weak($self));
my $hbox = Gtk2::HBox->new (0, 0);
$hbox->pack_start (Gtk2::Label->new (__('What:')), 0,0,0);
$vbox->pack_start ($hbox, 0,0,0);
my $what_model = $self->{'what_model'}
= Gtk2::ListStore->new ('Glib::String', 'Glib::Scalar');
$what_model->set ($what_model->append, 0, __('One symbol'), 1, undef);
$what_model->set ($what_model->append, 0, __('Favourites'), 1, 'favourites');
$what_model->set ($what_model->append, 0, __('All'), 1, 'all');
my $what_combobox = $self->{'what_combobox'}
= Gtk2::ComboBox->new_with_model ($what_model);
my $what_renderer = Gtk2::CellRendererText->new;
$what_combobox->pack_start ($what_renderer, 1);
$what_combobox->set_attributes ($what_renderer, text => 0);
$hbox->pack_start ($what_combobox, 0,0,0);
my $entry = $self->{'entry'} = Gtk2::Entry->new;
$hbox->pack_start ($entry, 1,1, 0.5 * Gtk2::Ex::Units::em($entry));
$what_combobox->signal_connect ('changed', \&_do_what_changed, $self);
$what_combobox->set_active (1);
$hbox->pack_start (Gtk2::Label->new (' ' . __('When:')), 0,0,0);
my $when_model = $self->{'when_model'}
= Gtk2::ListStore->new ('Glib::String', 'Glib::Scalar');
$when_model->insert_with_values (WHEN_UPDATE, 0 => __('Update'));
$when_model->insert_with_values (WHEN_BACKTO, 0 => __('Backto'));
my $when_combobox = $self->{'when_combobox'}
= Gtk2::ComboBox->new_with_model ($when_model);
my $when_renderer = Gtk2::CellRendererText->new;
$when_combobox->pack_start ($when_renderer, 1);
$when_combobox->set_attributes ($when_renderer, text => 0);
$hbox->pack_start ($when_combobox, 0,0,0);
$when_combobox->set_active (WHEN_UPDATE);
$when_combobox->signal_connect ('changed', \&_do_when_changed, $self);
require Date::Calc;
my ($today_year, undef, undef) = Date::Calc::Today();
my $when_adj = Gtk2::Adjustment->new ($today_year-5, # initial
1800, $today_year+1, # min,max
1,10,
0); # page_size
my $when_spin = $self->{'when_spin'}
= Gtk2::SpinButton->new ($when_adj, 10, 0);
$hbox->pack_start ($when_spin, 0,0,0);
$when_spin->set_sensitive (0);
_update_stop_sensitive ($self);
_update_clear_sensitive ($self);
$vbox->show_all;
# with sensible jobs view, message text and entry sizes
# FIXME: the initial proportions don't come out with the plain VBox packing
Gtk2::Ex::Units::set_default_size_with_subsizes
($self,
[$proc_scrolled, -1, '3 lines'],
[$jobs_scrolled, -1, '4 lines'],
[$messages_scrolled, '60 ems', '10 lines'],
[$entry, '10 ems', -1]);
}
# 'destroy' class closure
# this can be called more than once!
sub _do_destroy {
my ($self) = @_;
### DownloadDialog _do_destroy()
delete $self->{'model_ids'};
# break circular references
delete $self->{'textview'};
delete $self->{'textbuf'};
return shift->signal_chain_from_overridden(@_);
}
sub entry_symbol {
my ($self) = @_;
my $entry = $self->{'entry'};
return App::Chart::collapse_whitespace ($entry->get_text());
}
sub _do_textbuf_changed {
my ($textbuf, $self) = @_;
_update_clear_sensitive ($self);
}
sub _do_what_changed {
my ($combobox, $self) = @_;
my $idx = $self->{'what_combobox'}->get_active;
$self->{'entry'}->set_sensitive ($idx == 0);
}
sub _do_when_changed {
my ($combobox, $self) = @_;
my $idx = $self->{'when_combobox'}->get_active;
$self->{'when_spin'}->set_sensitive ($idx == WHEN_BACKTO);
}
# 'message' emission hook on App::Chart::Gtk2::Job
sub _do_job_message {
my ($invocation_hint, $parameters, $ref_weak_self) = @_;
my $self = $$ref_weak_self || return 0; # disconnect
my ($job, $str) = @$parameters;
$self->message ($str);
return 1; # stay connected
}
sub message {
my ($self, $str) = @_;
my $textbuf = $self->{'textview'}->get_buffer;
$textbuf->insert ($textbuf->get_end_iter, $str);
}
sub start {
my ($self, $what, $when) = @_;
$self->{'hide_on_success'} = undef;
my $queue = App::Chart::Gtk2::JobQueue->instance;
$queue->remove_done;
App::Chart::Gtk2::Subprocess->remove_done;
require App::Chart::Gtk2::Job::Download;
my $job = App::Chart::Gtk2::Job::Download->start ($what, $when);
# if this job is the only one then select it
if ($queue->iter_n_children(undef) == 1) {
my $treeview = $self->{'jobs_treeview'};
my $selection = $treeview->get_selection;
$selection->select_path (Gtk2::TreePath->new_from_indices(0));
}
return $job;
}
sub _do_start_button {
my ($self) = @_;
my $what = $self->{'what_combobox'}->get_active;
my $type;
if ($what == 0) {
$what = $self->{'entry'}->get_text;
$what =~ s/$RE{ws}{crop}//g; # leading and trailing whitespace
if ($what eq '') {
my $textbuf = $self->{'textbuf'};
$textbuf->insert ($textbuf->get_end_iter, "No symbol entered.\n");
$self->{'entry'}->grab_focus;
return;
}
$type = $what;
} elsif ($what == 1) {
$type = __('Favourites');
$what = '--favourites';
} else {
$type = __('All');
$what = '--all';
}
my $when_index = $self->{'when_combobox'}->get_active;
my $when = ($when_index == WHEN_BACKTO
? $self->{'when_spin'}->get_value
: undef);
$self->start ($what, $when);
}
# 'response' signal handler
sub _do_response {
my ($self, $response) = @_;
### DownloadDialog _do_response(): $response
if ($response eq RESPONSE_START) {
$self->_do_start_button;
} elsif ($response eq RESPONSE_STOP) {
my $treeview = $self->{'jobs_treeview'};
my $selection = $treeview->get_selection;
my ($model, $iter) = $selection->get_selected;
my $job = $model->get_value ($iter, 0);
$job->stop;
} elsif ($response eq RESPONSE_CLEAR) {
my $textbuf = $self->{'textbuf'};
$textbuf->delete ($textbuf->get_start_iter, $textbuf->get_end_iter);
if (App::Chart::Gtk2::JobQueue->can('remove_done')) { # if loaded
App::Chart::Gtk2::JobQueue->remove_done;
}
if (App::Chart::Gtk2::Subprocess->can('remove_done')) { # if loaded
App::Chart::Gtk2::Subprocess->remove_done;
}
} elsif ($response eq 'close') {
# as per a keyboard close, defaults to raising 'delete-event', which in
# turn defaults to a destroy
$self->signal_emit ('close');
} elsif ($response eq 'help') {
require App::Chart::Manual;
App::Chart::Manual->open(__p('manual-node','Download'), $self);
}
}
sub _update_stop_sensitive {
my ($self) = @_;
my $treeview = $self->{'jobs_treeview'};
my $selection = $treeview->get_selection;
my ($model, $iter) = $selection->get_selected;
my $job = $iter && $model->get_value ($iter, 0);
my $sensitive = $job && $job->is_stoppable;
$self->set_response_sensitive (RESPONSE_STOP, $sensitive);
}
sub _update_clear_sensitive {
my ($self) = @_;
my $anything_to_clear = do {
my $textbuf = $self->{'textbuf'};
$textbuf->get_char_count != 0
} || do {
App::Chart::Gtk2::JobQueue->can('remove_done') # if loaded
( run in 1.035 second using v1.01-cache-2.11-cpan-39bf76dae61 )