diff options
Diffstat (limited to 'rpmdrake')
-rwxr-xr-x | rpmdrake | 807 |
1 files changed, 807 insertions, 0 deletions
diff --git a/rpmdrake b/rpmdrake new file mode 100755 index 00000000..17fde1de --- /dev/null +++ b/rpmdrake @@ -0,0 +1,807 @@ +#!/usr/bin/perl +# -*- coding: utf-8 -*- +#***************************************************************************** +# +# Copyright (c) 2002 Guillaume Cottenceau +# Copyright (c) 2002-2008 Thierry Vignaud <tvignaud@mandriva.com> +# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA +# Copyright (c) 2005-2008 Mandriva SA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: rpmdrake 267936 2010-04-26 16:40:21Z jvictor $ + +use strict; +use MDK::Common::Func 'any'; +use lib qw(/usr/lib/libDrakX); +use common; +use utf8; + +use Rpmdrake::init; +use standalone; #- standalone must be loaded very first, for 'explanations', but after rpmdrake::init +use rpmdrake; +use Rpmdrake::open_db; +use Rpmdrake::gui; +use Rpmdrake::rpmnew; +use Rpmdrake::formatting; +use Rpmdrake::pkg; +use urpm::media; + +use mygtk2 qw(gtknew); #- do not import anything else, especially gtkadd() which conflicts with ugtk2 one +use ugtk2 qw(:all); +use Gtk2::Gdk::Keysyms; +use Rpmdrake::widgets; +use feature 'state'; + +$ugtk2::wm_icon = get_icon('installremoverpm', "title-$MODE"); + +our $w; +our $statusbar; + +my %elems; + +sub do_search($$$$$$$) { + my ($find_entry, $tree, $tree_model, $options, $current_search_type, $urpm, $pkgs) = @_; + my $entry = $find_entry->get_text or return; + if (!$use_regexp->[0]) { + $entry = quotemeta $entry; + # enable OR search by default: + $entry =~ s/\\ /|/g if $current_search_type eq 'normal'; + } + # remove leading/trailing spacing when pasting: + if ($entry !~ /\S\s\S/) { + # if spacing in middle, likely a string search in description + $entry =~ s/^\s*//; + $entry =~ s/^\s*$//; + } + my $entry_rx = eval { qr/$entry/i } or return; + reset_search(); + $options->{state}{flat} and $options->{delete_all}->(); + $tree->collapse_all; + my @search_results; + if ($current_search_type eq 'normal') { + my $count; + foreach (@filtered_pkgs) { + if ($NVR_searches->[0]) { + next if !/$entry_rx/; + } else { + next if first(split_fullname($_)) !~ /$entry_rx/; + } + push @search_results, $_; + # FIXME: should be done for all research types + last if $count++ > 2000; + } + } elsif ($current_search_type eq 'summaries') { + my $count; + foreach (@filtered_pkgs) { + next if get_summary($_) !~ /$entry_rx/; + push @search_results, $_; + # FIXME: should be done for all research types + last if $count++ > 2000; + } + } else { + my $searchstop; + my $searchw = ugtk2->new(N("Software Management"), grab => 1, transient => $w->{real_window}); + gtkadd( + $searchw->{window}, + gtkpack__( + gtknew('VBox', spacing => 5), + gtknew('Label', text => N("Please wait, searching...")), + my $searchprogress = gtknew('ProgressBar', width => 300), + gtkpack__( + gtknew('HButtonBox', layout => 'spread'), + gtksignal_connect( + Gtk2::Button->new(but(N("Stop"))), + clicked => sub { $searchstop = 1 }, + ), + ), + ), + ); + $searchw->sync; + # should probably not account backports packages or find a way to search them: + my $total_size = keys %$pkgs; + my $progresscount; + + my $update_search_pb = sub { + $progresscount++; + if (!($progresscount % 100)) { + $progresscount <= $total_size and $searchprogress->set_fraction($progresscount/$total_size); + $searchw->flush; # refresh and handle clicks + } + }; + foreach my $medium (grep { !$_->{ignore} } @{$urpm->{media}}) { + $searchstop and last; + my $gurpm; # per medium download progress bar (if needed) + my $_gurpm_clean_guard = before_leaving { undef $gurpm }; + my $xml_info_file = + urpm::media::any_xml_info($urpm, $medium, + ($current_search_type eq 'files' ? 'files' : 'info'), + undef, + sub { + $gurpm ||= Rpmdrake::gurpm->new(N("Please wait"), + transient => $::main_window); + download_callback($gurpm, @_) or do { + $searchstop = 1; + }; + }); + if (!$xml_info_file) { + $urpm->{error}(N("no xml-info available for medium \"%s\"", $medium->{name})); + next; + } + $searchstop and last; + + require urpm::xml_info; + require urpm::xml_info_pkg; + + $urpm->{log}("getting information from $xml_info_file"); + if ($current_search_type eq 'files') { + # special version for speed (3x faster), hopefully fully compatible + my $F = urpm::xml_info::open_lzma($xml_info_file); + my $fn; + local $_; + while (<$F>) { + if ($searchstop) { + statusbar_msg(N("Search aborted"), 1); + goto end_search; + } + if (m!^<!) { + ($fn) = /fn="(.*)"/; + $update_search_pb->(); + } elsif (/$entry_rx/) { + $fn or $urpm->{fatal}("fast algorithm is broken, please report a bug"); + push @search_results, $fn; + } + } + } else { + eval { + urpm::xml_info::do_something_with_nodes( + 'info', + $xml_info_file, + sub { + $searchstop and die 'search aborted'; + my ($node) = @_; + $update_search_pb->(); + push @search_results, $node->{fn} if $node->{description} =~ $entry_rx; + #$searchstop and last; + return 0 || $searchstop; + }, + ); + }; + my $err = $@; + if ($err =~ /search aborted/) { + statusbar_msg(N("Search aborted"), 1); + } + } + } + + end_search: + @search_results = uniq(@search_results); #- there can be multiple packages with same version/release for different arch's + @search_results = intersection(\@search_results, \@filtered_pkgs); + $searchw->destroy; + } + + my $iter; + if (@search_results) { + $elems{$results_ok} = [ map { [ $_, $results_ok ] } sort { uc($a) cmp uc($b) } @search_results ]; + $iter = $options->{add_parent}->($results_ok); + $options->{add_nodes}->(map { [ $_, $results_ok . ($options->{tree_mode} eq 'by_presence' + ? '|' . ($pkgs->{$_}{pkg}->flag_installed ? N("Upgradable") : N("Addable")) + : ($options->{tree_mode} eq 'by_selection' + ? '|' . ($pkgs->{$_}{selected} ? N("Selected") : N("Not selected")) + : '')) + ] } sort { uc($a) cmp uc($b) } @search_results); + } else { + $iter = $options->{add_parent}->($results_none); + # clear package list: + $options->{add_nodes}->(); + my $string = $default_list_mode eq 'all' && $filter->[0] eq 'all' ? N("No search results.") : + N("No search results. You may want to switch to the '%s' view and to the '%s' filter", + N("All"), N("All"),); + statusbar_msg($string , 1); + gtkset_mousecursor_normal($::w->{rwindow}->window); + } + my $tree_selection = $tree->get_selection; + if (my $path = $tree_model->get_path($iter)) { + $tree_selection->select_path($path); + $tree->scroll_to_cell($path, undef, 1, 0.5, 0); + $tree_selection->signal_emit('changed'); + } +} + +sub quit() { + ($rpmdrake_width->[0], $rpmdrake_height->[0]) = $::w->{real_window}->get_size(); + real_quit(); +} + +sub run_treeview_dialog { + my ($callback_action) = @_; + + my ($options, $tree, $tree_model, $detail_list, $detail_list_model); + (undef, $size_free) = MDK::Common::System::df('/usr'); + + $::main_window = $w->{real_window}; + + $options = { + build_tree => sub { build_tree($tree, $tree_model, \%elems, $options, $force_rebuild, @_) }, + partialsel_unsel => sub { + my ($unsel, $sel) = @_; + @$sel = grep { exists $pkgs->{$_} } @$sel; + @$unsel < @$sel; + }, + get_status => sub { + N("Selected: %s / Free disk space: %s", formatXiB($size_selected), formatXiB($size_free*1024)); + }, + rebuild_tree => sub {}, + }; + + $tree_model = Gtk2::TreeStore->new("Glib::String", "Glib::String", "Gtk2::Gdk::Pixbuf"); + $tree_model->set_sort_column_id($grp_columns{label}, 'ascending'); + $tree = Gtk2::TreeView->new_with_model($tree_model); + $tree->get_selection->set_mode('browse'); + + $tree->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::MDV::CellRendererPixWithLabel->new, 'pixbuf' => $grp_columns{icon}, label => $grp_columns{label})); + $tree->set_headers_visible(0); + + $detail_list_model = Gtk2::ListStore->new("Glib::String", + "Gtk2::Gdk::Pixbuf", + "Glib::String", + "Glib::Boolean", + "Glib::String", + "Glib::String", + "Glib::String", + "Glib::String", + "Glib::Boolean"); + + $detail_list = Gtk2::TreeView->new_with_model($detail_list_model); + $detail_list->append_column( + my $col_sel = Gtk2::TreeViewColumn->new_with_attributes( + undef, + Gtk2::CellRendererToggle->new, + active => $pkg_columns{selected}, + activatable => $pkg_columns{selectable} + )); + $col_sel->set_fixed_width(34); # w/o this the toggle cells are not displayed + $col_sel->set_sizing('fixed'); + $col_sel->set_sort_column_id($pkg_columns{selected}); + + my $display_arch_col = to_bool(arch() =~ /64/); + my @columns = (qw(name version release), if_($display_arch_col, 'arch')); + + my %columns = ( + 'name' => { + title => N("Package"), + markup => $pkg_columns{short_name}, + }, + 'version' => { + title => N("Version"), + text => $pkg_columns{version}, + }, + 'release' => { + title => N("Release"), + text => $pkg_columns{release}, + }, + if_($display_arch_col, 'arch' => { + title => + #-PO: "Architecture" but to be kept *small* !!! + N("Arch."), + text => $pkg_columns{arch}, + }), + ); + foreach my $col (@columns{@columns}) { + $detail_list->append_column( + $col->{widget} = + Gtk2::TreeViewColumn->new_with_attributes( + ' ' . $col->{title} . ' ', + $col->{renderer} = Gtk2::CellRendererText->new, + ($col->{markup} ? (markup => $col->{markup}) : (text => $col->{text})), + ) + ); + $col->{widget}->set_sort_column_id($col->{markup} || $col->{text}); + } + $columns{$_}{widget}->set_sizing('autosize') foreach @columns; + $columns{name}{widget}->set_property('expand', '1'); + $columns{name}{renderer}->set_property('ellipsize', 'end'); + $columns{$_}{renderer}->set_property('xpad', '6') foreach @columns; + $columns{name}{widget}->set_resizable(1); + #$detail_list_model->set_sort_column_id($pkg_columns{text}, 'ascending'); + $detail_list_model->set_sort_func($pkg_columns{version}, \&sort_callback); + $detail_list->set_rules_hint(1); + + $detail_list->append_column( + my $pixcolumn = + Gtk2::TreeViewColumn->new_with_attributes( + #-PO: "Status" should be kept *small* !!! + N("Status"), + my $rdr = Gtk2::CellRendererPixbuf->new, + 'pixbuf' => $pkg_columns{state_icon}) + ); + $rdr->set_fixed_size(34, 24); + $pixcolumn->set_sort_column_id($pkg_columns{state}); + + compute_main_window_size($w); + + my $cursor_to_restore; + $_->signal_connect( + expose_event => sub { + $cursor_to_restore or return; + gtkset_mousecursor_normal($tree->window); + undef $cursor_to_restore; + }, + ) foreach $tree, $detail_list; + $tree->get_selection->signal_connect(changed => sub { + my ($model, $iter) = $_[0]->get_selected; + return if !$iter; + state $current_group; + my $new_group = $model->get_path_str($iter); + return if $current_group eq $new_group && !$force_displaying_group; + undef $force_displaying_group; + $current_group = $new_group; + $model && $iter or return; + my $group = $model->get($iter, 0); + my $parent = $iter; + while ($parent = $model->iter_parent($parent)) { + $group = join('|', $model->get($parent, 0), $group); + } + $detail_list->window->freeze_updates; + $options->{add_nodes}->(@{$elems{$group}}); + $detail_list->window->thaw_updates if $detail_list->window; + }); + + $options->{state}{splited} = 1; + $options->{state}{flat} = $tree_flat->[0]; + + my $is_backports = get_inactive_backport_media(fast_open_urpmi_db()); + + my %filters = (all => N("All"), + installed => N("Installed"), + non_installed => N("Not installed"), + ); + + my %rfilters = reverse %filters; + + + # handle migrating config file from rpmdrake <= 4.9 + if (exists $filters{$default_list_mode}) { + $filter->[0] = $default_list_mode; + $default_list_mode = 'all'; + } + + $options->{tree_mode} = $default_list_mode; + + my %modes = ( + flat => N("All packages, alphabetical"), + by_group => N("All packages, by group"), + by_leaves => N("Leaves only, sorted by install date"), + by_presence => N("All packages, by update availability"), + by_selection => N("All packages, by selection state"), + by_size => N("All packages, by size"), + by_source => N("All packages, by medium repository"), + ); + + + my %views = (all => N("All"), + if_($is_backports, backports => + #-PO: Backports media are newer but less-tested versions of some packages in main + #-PO: See http://wiki.mandriva.com/en/Policies/SoftwareMedia#.2Fmain.2Fbackports + N("Backports")), + meta_pkgs => N("Meta packages"), + gui_pkgs => N("Packages with GUI"), + all_updates => N("All updates"), + security => N("Security updates"), + bugfix => N("Bugfixes updates"), + normal => N("General updates") + ); + my %rviews = reverse %views; + $options->{rviews} = \%rviews; + + my %default_mode = (install => 'all', # we want the new GUI by default instead of "non_installed" + remove => 'installed', + update => 'security', + ); + my %wanted_categories = ( + all_updates => [ qw(security bugfix normal) ], + security => [ 'security' ], + bugfix => [ 'bugfix' ], + normal => [ 'normal' ], + ); + my $old_value; + my $view_box = gtknew( + 'ComboBox', + list => [ + qw(all meta_pkgs gui_pkgs all_updates security bugfix normal), + if_($is_backports, 'backports') + ], + format => sub { $views{$_[0]} }, text => $views{$default_list_mode}, + tip => N("View"), + changed => sub { + my $val = $_[0]->get_text; + return if $val eq $old_value; # workarounding gtk+ sending us sometimes twice events + $old_value = $val; + $default_list_mode = $rviews{$val}; + if (my @cat = $wanted_categories{$rviews{$val}} && @{$wanted_categories{$rviews{$val}}}) { + @$mandrakeupdate_wanted_categories = @cat; + } + + if ($options->{tree_mode} ne $val) { + $tree_mode->[0] = $options->{tree_mode} = $rviews{$val}; + $tree_flat->[0] = $options->{state}{flat}; + reset_search(); + switch_pkg_list_mode($rviews{$val}); + $options->{rebuild_tree}->(); + } + } + ); + + $options->{tree_submode} ||= $default_list_mode; + $options->{tree_subflat} ||= $options->{state}{flat}; + + + my $filter_box = gtknew( + 'ComboBox', + list => [ qw(all installed non_installed) ], text => $filters{$filter->[0]}, + format => sub { $filters{$_[0]} }, + tip => N("Filter"), + changed => sub { + state $oldval; + my $val = $_[0]->get_text; + return if $val eq $oldval; # workarounding gtk+ sending us sometimes twice events + $oldval = $val; + $val = $rfilters{$val}; + if ($filter->[0] ne $val) { + $filter->[0] = $val; + reset_search(); + slow_func($::main_window->window, sub { switch_pkg_list_mode($default_list_mode) }); + $options->{rebuild_tree}->(); + } + } + ); + + my $view_callback = sub { + my ($val) = @_; + return if $val eq $old_value; # workarounding gtk+ sending us sometimes twice events + $old_value = $val; + return if $mode->[0] eq $val; + $mode->[0] = $val; + $tree_flat->[0] = $options->{state}{flat} = member($mode->[0], qw(flat by_leaves by_selection by_size)); + + if ($options->{tree_mode} ne $val) { + reset_search(); + $options->{rebuild_tree}->(); + } + }; + + + my @search_types = qw(normal descriptions summaries files); + my $current_search_type = $search_types[0]; + my $search_menu = Gtk2::Menu->new; + my $i = 0; + my $previous; + foreach (N("in names"), N("in descriptions"), N("in summaries"), N("in file names")) { + my ($name, $val) = ($_, $i); + $search_menu->append(gtksignal_connect(gtkshow( + $previous = Gtk2::RadioMenuItem->new_with_label($previous, $name)), + activate => sub { $current_search_type = $search_types[$val] })); + $i++; + } + + my $info = Gtk2::Mdv::TextView->new; + $info->set_left_margin(2); + $info->set_right_margin(15); #- workaround when right elevator of scrolled window appears + + my $find_callback = sub { + do_search($find_entry, $tree, $tree_model, $options, $current_search_type, $urpm, $pkgs); + }; + + my $hpaned = gtknew('HPaned', position => $typical_width*0.9, + child1 => gtknew('ScrolledWindow', child => $tree), + resize1 => 0, shrink1 => 0, + resize2 => 1, shrink2 => 0, + child2 => gtknew('VPaned', + child1 => gtknew('ScrolledWindow', child => $detail_list), resize1 => 1, shrink1 => 0, + child2 => gtknew('ScrolledWindow', child => $info), resize2 => 1, shrink2 => 0 + ) + ); + + my $reload_db_and_clear_all = sub { + slow_func($w->{real_window}->window, sub { + $force_rebuild = 1; + pkgs_provider({ skip_updating_mu => 1 }, $options->{tree_mode}); + reset_search(); + $size_selected = 0; + $options->{rebuild_tree}->(); + $find_callback->(); + }); + }; + + my $status = gtknew('Label'); + my $checkbox_show_autoselect; + my %check_boxes; + my $auto_select_string = + N("/_Options") . N("/_Select dependencies without asking"); + my $clean_cache_string = + N("/_Options") . "/" . + N("Clear download cache after successful install"); + my $updates_string = N("/_Options") . N("/_Compute updates on startup"); + my $NVR_string = N("/_Options") . "/" . N("Search in _full package names"); + my $regexp_search_string = N("/_Options") . "/" . N("Use _regular expressions in searches"); + my ($menu, $factory) = create_factory_menu( + $w->{real_window}, + [ N("/_File"), undef, undef, undef, '<Branch>' ], + if_( + ! $>, + [ N("/_File") . N("/_Update media"), undef, sub { + update_sources_interactive($urpm, transient => $w->{real_window}) + and $reload_db_and_clear_all->(); + }, undef, '<Item>' ] + ), + [ N("/_File") . N("/_Reset the selection"), undef, sub { + if ($MODE ne 'remove') { + $urpm->disable_selected( + open_rpm_db(), $urpm->{state}, + map { if_($pkgs->{$_}{selected}, $pkgs->{$_}{pkg}) } keys %$pkgs, + ); + } + $pkgs->{$_}{selected} = 0 foreach keys %$pkgs; + reset_search(); + $size_selected = 0; + $force_displaying_group = 1; + my $tree_selection = $tree->get_selection; + $tree_selection->select_path(Gtk2::TreePath->new_from_string('0')) if !$tree_selection->get_selected; + $tree_selection->signal_emit('changed'); + }, undef, '<Item>' ], + [ N("/_File") . N("/Reload the _packages list"), undef, $reload_db_and_clear_all, undef, '<Item>' ], + [ N("/_File") . N("/_Quit"), N("<control>Q"), \&quit, undef, '<Item>', ], + #[ N("/_View"), undef, undef, undef, '<Branch>' ], + if_(!$>, + [ N("/_Options"), undef, undef, undef, '<Branch>' ], + [ $auto_select_string, undef, + sub { + my $box = $check_boxes{$auto_select_string}; + $auto_select->[0] = $box->get_active; + $::rpmdrake_options{auto} = $box->get_active; + $urpm->{options}{auto} = $box->get_active; + }, + undef, '<CheckItem>' ], + [ $clean_cache_string, undef, + sub { + $clean_cache->[0] = + $check_boxes{$clean_cache_string}->get_active; + $::noclean = !$clean_cache->[0]; + }, + undef, '<CheckItem>' ], + [ N("/_Options") . N("/_Media Manager"), undef, sub { + require Rpmdrake::edit_urpm_sources; + Rpmdrake::edit_urpm_sources::run() && $reload_db_and_clear_all->(); + }, undef, '<Item>' ], + [ N("/_Options") . N("/_Show automatically selected packages"), undef, sub { + $dont_show_selections->[0] = !$checkbox_show_autoselect->get_active; + }, undef, '<CheckItem>' ], + + [ $updates_string, undef, sub { + $compute_updates->[0] = $check_boxes{$updates_string}->get_active; + }, undef, '<CheckItem>' ], + [ $NVR_string, undef, sub { + $NVR_searches->[0] = $check_boxes{$NVR_string}->get_active; + }, undef, '<CheckItem>' ], + [ $regexp_search_string, undef, sub { + $use_regexp->[0] = $check_boxes{$regexp_search_string}->get_active; + }, undef, '<CheckItem>' ], + ), + [ N("/_View"), undef, undef, undef, '<Branch>' ], + (map { + state ($idx, $previous); + my $type = $idx ? join('/', N("/_View"), $previous) : '<RadioItem>'; + $type =~ s/_//g; # gtk+ retrieve widgets by their path w/o any shortcut marks + $previous = $modes{$_}; + $idx++; + my $val = $_; + [ N("/_View") . '/' . $modes{$_}, undef, sub { $view_callback->($val) }, 0, $type ]; + } qw(flat by_group by_leaves by_presence by_selection by_size by_source)), + [ N("/_Help"), undef, undef, undef, '<Branch>' ], + [ N("/_Help") . N("/_Report Bug"), undef, sub { run_drakbug('rpmdrake') }, undef, '<Item>' ], + [ N("/_Help") . N("/_Help"), undef, sub { rpmdrake::open_help('') }, undef, '<Item>' ], + [ N("/_Help") . N("/_About..."), undef, sub { + my $license = formatAlaTeX(translate($::license)); + $license =~ s/\n/\n\n/sg; # nicer formatting + my $w = gtknew('AboutDialog', name => N("Rpmdrake"), + version => $Rpmdrake::init::version, + copyright => N("Copyright (C) %s by Mandriva", '2002-2009'), + license => $license, wrap_license => 1, + comments => N("Rpmdrake is Mageia package management tool."), + website => 'http://www.mageia.org', + website_label => N("Mageia"), + authors => 'Thierry Vignaud <vignaud@mandriva.com>', + artists => 'Hélène Durosini <ln@mandriva.com>', + translator_credits => + #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith <jsmith@nowhere.com>") + N("_: Translator(s) name(s) & email(s)\n"), + transient_for => $::main_window, modal => 1, position_policy => 'center-on-parent', + ); + $w->show_all; + $w->run; + }, undef, '<Item>' + ] + + ); + + # to retrieve a path, one must prevent "accelerators completion": + my $get_path = sub { return join('', map { my $i = $_; $i =~ s/_//g; $i } @_) }; + + if (my $widget = $factory->get_item('<main>' . $get_path->(N("/_View") . '/' . $modes{$mode->[0]}))) { + $widget->set_active(1); + } else { + warn "Impossible to set $mode->[0] view as default\n"; + } + + %check_boxes = map { + $_ => $factory->get_widget("<main>" . $get_path->($_)); + } ($auto_select_string, + $clean_cache_string, + $NVR_string, + $updates_string, + $regexp_search_string); + + if (!$>) { + $check_boxes{$regexp_search_string}->set_active($use_regexp->[0]); + $check_boxes{$NVR_string}->set_active($NVR_searches->[0]); + $check_boxes{$auto_select_string}->set_active($auto_select->[0]); + $check_boxes{$updates_string}->set_active($compute_updates->[0]); + $check_boxes{$clean_cache_string}->set_active($clean_cache->[0]); + } + + $checkbox_show_autoselect = $factory->get_widget("<main>" . strip_first_underscore(N("/_Options"), N("/_Show automatically selected packages"))) + and $checkbox_show_autoselect->set_active(!$dont_show_selections->[0]); + + my $accel = Gtk2::AccelGroup->new; + $accel->connect(Gtk2::Gdk->keyval_from_name('F'), ['control-mask'], ['visible'], sub { $find_entry->grab_focus() }); + $w->{real_window}->add_accel_group($accel); + + gtkadd( + $w->{window}, + gtkpack_( + gtknew('VBox', spacing => 3), + 0, $menu, + if_(second(gtkroot()->get_size()) >= 600, 0, getbanner()), + 1, gtkadd( + gtknew('Frame', border_width => 3, shadow_type => 'none'), + gtkpack_( + gtknew('VBox', spacing => 3), + 0, gtkpack_( + gtknew('HBox', spacing => 10), + 0, $view_box, + 0, $filter_box, + 0, gtknew('Label', text => N("Find:")), + 1, $find_entry = gtknew('Entry', width => 260, + primary_icon => 'gtk-find', + secondary_icon => 'gtk-clear', + tip => N("Please type in the string you want to search then press the <enter> key"), + 'icon-release' => $find_callback, + 'icon-press' => sub { + my (undef, $pos, $event) = @_; + # emulate Sexy::IconEntry's clear_button: + if ($pos eq 'secondary') { + $find_entry->set_text(''); + reset_search(); + } + return if $pos ne 'primary'; + $search_menu->popup(undef, undef, undef, undef, $event->button, $event->time); + }, + key_press_event => sub { + member($_[1]->keyval, $Gtk2::Gdk::Keysyms{Return}, $Gtk2::Gdk::Keysyms{KP_Enter}) + and $find_callback->(); + }, + ), + ), + 1, $hpaned, + 0, $status, + 0, gtkpack_( + gtknew('HBox', spacing => 20), + 0, gtksignal_connect( + Gtk2::Button->new(but_(N("Select all"))), + clicked => sub { + toggle_all($options, 1); + }, + ), + 1, gtknew('Label'), + 0, my $action_button = gtksignal_connect( + Gtk2::Button->new(but_(N("Apply"))), + clicked => sub { do_action($options, $callback_action, $info) }, + ), + 0, gtksignal_connect( + Gtk2::Button->new(but_(N("Quit"))), + clicked => \&quit, + ), + ), + ), + ), + 0, $statusbar = Gtk2::Statusbar->new, + ), + ); + $action_button->set_sensitive(0) if $>; + $find_entry->grab_focus; + + gtktext_insert($info, [ + [ $info->render_icon('gtk-dialog-info', 'GTK_ICON_SIZE_DIALOG', undef) ], + @{ ugtk2::markup_to_TextView_format( + formatAlaTeX(join("\n\n\n", format_header(N("Quick Introduction")), + N("You can browse the packages through the categories tree on the left."), + N("You can view information about a package by clicking on it on the right list."), + N("To install, update or remove a package, just click on its \"checkbox\".")))) + } + ]); + + $w->{rwindow}->set_default_size($typical_width*2.7, 500) if !$::isEmbedded; + $find_entry->set_text($rpmdrake_options{search}[0]) if $rpmdrake_options{search}; + + if ($rpmdrake_width->[0] && $rpmdrake_height->[0]) { + # so that we can shrink back: + $w->{real_window}->set_default_size($rpmdrake_width->[0], $rpmdrake_height->[0]); + } + $w->{rwindow}->show_all; + $w->{rwindow}->set_sensitive(0); + + # ensure treeview get realized so that ->get_selection returns something + $detail_list->realize; + gtkflush(); + + slow_func($::main_window->window, sub { pkgs_provider({}, $default_list_mode) }); # default mode + if (@initial_selection) { + $options->{initial_selection} = \@initial_selection; + $pkgs->{$_}{selected} = 0 foreach @initial_selection; + } + + $w->{rwindow}->set_sensitive(1); + + $options->{widgets} = { + w => $w, + tree => $tree, + tree_model => $tree_model, + detail_list_model => $detail_list_model, + detail_list => $detail_list, + info => $info, + status => $status, + }; + $options->{init_callback} = $find_callback if $rpmdrake_options{search}; + + ask_browse_tree_given_widgets_for_rpmdrake($options); +} + + +# -=-=-=---=-=-=---=-=-=-- main -=-=-=---=-=-=---=-=-=- + + +if (my $pid = is_running('rpmdrake')) { + interactive_msg(N("Warning"), N("rpmdrake is already running (pid: %s)", $pid), yesno => [ N("Quit") ]); + exit(0); +} + +$w = ugtk2->new(N("Software Management")); +$w->{rwindow}->show_all if $::isEmbedded; + +readconf(); + +warn_about_user_mode(); + +do_merge_if_needed(); + + +init(); + +run_treeview_dialog(\&perform_installation); + +writeconf(); + +myexit(0); |