aboutsummaryrefslogtreecommitdiffstats
path: root/rpmdrake
diff options
context:
space:
mode:
Diffstat (limited to 'rpmdrake')
-rwxr-xr-xrpmdrake807
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);