#!/usr/bin/perl # -*- coding: utf-8 -*- #***************************************************************************** # # Copyright (c) 2002 Guillaume Cottenceau # Copyright (c) 2002-2014 Thierry Vignaud # 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 mygtk3 qw(gtknew); #- do not import anything else, especially gtkadd() which conflicts with ugtk3 one use ugtk3 qw(:all); use Rpmdrake::widgets; use feature 'state'; $ugtk3::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 = ugtk3->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( Gtk3::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!^(); } 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) { @search_results = sort_packages(@search_results); $elems{$results_ok} = [ map { [ $_, $results_ok ] } @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")) : '')) ] } @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}->get_window); } my $tree_selection = $tree->get_selection; return if !$tree_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 reset_selection { my ($tree) = @_; if ($MODE ne 'remove') { my $db = eval { open_rpm_db() }; if (!ref($db)) { statusbar_msg(N("Reset aborted (RPM DB is locked by another process)"), 1); return; } $urpm->disable_selected( $db, $urpm->{state}, map { if_($pkgs->{$_}{selected}, $pkgs->{$_}{pkg}) } keys %$pkgs, ); } undef $pkgs->{$_}{selected} foreach keys %$pkgs; reset_search(); $size_selected = 0; $force_displaying_group = 1; my $tree_selection = $tree->get_selection; $tree_selection->select_path(Gtk3::TreePath->new_from_string('0')) if !$tree_selection->get_selected; $tree_selection->signal_emit('changed'); } sub show_about_dlg() { 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 the Mageia package management tool."), website => 'http://www.mageia.org', website_label => N("Mageia"), authors => [ 'Thierry Vignaud ' ], artists => [ 'Mageia Team' ], translator_credits => #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith ") N("_: Translator(s) name(s) & email(s)\n"), transient_for => $::main_window, modal => 1, position_policy => 'center-on-parent', ); $w->show_all; $w->run; } 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 = Gtk3::TreeStore->new("Glib::String", "Glib::String", "Gtk3::Gdk::Pixbuf"); $tree_model->set_sort_column_id($grp_columns{label}, 'ascending'); $tree = Gtk3::TreeView->new_with_model($tree_model); $tree->get_selection->set_mode('browse'); $tree->append_column(my $col = Gtk3::TreeViewColumn->new); $col->pack_start(my $img_renderer = Gtk3::CellRendererPixbuf->new, $grp_columns{icon}); $col->set_attributes($img_renderer, pixbuf => $grp_columns{icon}); $col->pack_start(my $text_renderer = Gtk3::CellRendererText->new, $grp_columns{label}); $col->set_attributes($text_renderer, text => $grp_columns{label}); $tree->set_headers_visible(0); $detail_list_model = Gtk3::ListStore->new("Glib::String", "Gtk3::Gdk::Pixbuf", "Glib::String", "Glib::Boolean", "Glib::String", "Glib::String", "Glib::String", "Glib::String", "Glib::Boolean"); $detail_list = Gtk3::TreeView->new_with_model($detail_list_model); $detail_list->append_column( my $col_sel = Gtk3::TreeViewColumn->new_with_attributes( '', Gtk3::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} = Gtk3::TreeViewColumn->new_with_attributes( ' ' . $col->{title} . ' ', $col->{renderer} = Gtk3::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 = Gtk3::TreeViewColumn->new_with_attributes( #-PO: "Status" should be kept *small* !!! N("Status"), my $rdr = Gtk3::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( draw => sub { $cursor_to_restore or return; gtkset_mousecursor_normal($tree->get_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->get_window->freeze_updates; $options->{add_nodes}->(@{$elems{$group}}); $detail_list->get_window->thaw_updates if $detail_list->get_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->get_window, sub { switch_pkg_list_mode($default_list_mode) }); $options->{rebuild_tree}->(); } } ); my $view_callback = sub { my (undef, $current) = @_; my $val = $current->get_name; 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 = Gtk3::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 = Gtk3::RadioMenuItem->new_with_label([ $previous ], $name)), activate => sub { $current_search_type = $search_types[$val] })); $i++; } my $info = Gtk3::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}->get_window, sub { $force_rebuild = 1; pkgs_provider($options->{tree_mode}, skip_updating_mu => 1); reset_search(); $size_selected = 0; $options->{rebuild_tree}->(); $find_callback->(); }); }; my $status = gtknew('Label'); my $checkbox_show_autoselect; my %check_boxes; my @radio_labels = qw(flat by_group by_leaves by_presence by_selection by_size by_source); my @radios = map { [ $_, undef, $modes{$_}, undef, undef, $view_callback ]; } @radio_labels; my $ui = gtknew('UIManager', actions => [ # [name, stock_id, value, label, accelerator, tooltip, callback] [ 'FileMenu', undef, N("_File") ], if_(! $>, [ 'Update_media', undef, N("_Update media"), undef, undef, sub { update_sources_interactive($urpm, transient => $w->{real_window}) and $reload_db_and_clear_all->(); } ] ), [ 'Reset_selection', undef, N("_Reset the selection"), undef, undef, sub { reset_selection($tree) } ], [ 'Reload_the_packages_list', undef, N("Reload the _packages list"), undef, undef, $reload_db_and_clear_all ], [ 'Quit', undef, N("_Quit"), N("Q"), undef, \&quit ], if_(! $>, [ 'OptionsMenu', undef, N("_Options") ], [ 'Media_Manager', undef, N("_Media Manager"), undef, undef, sub { require Rpmdrake::edit_urpm_sources; Rpmdrake::edit_urpm_sources::run() && $reload_db_and_clear_all->(); }, ], ), [ 'ViewMenu', undef, N("_View") ], [ 'HelpMenu', undef, N("_Help") ], [ 'Report_Bug', undef, N("_Report Bug"), undef, undef, sub { run_drakbug('rpmdrake') } ], [ 'Help', undef, N("_Help"), undef, undef, sub { rpmdrake::open_help('') } ], [ 'About', undef, N("_About..."), undef, undef, \&show_about_dlg ], ], radio_actions => [ [ \@radios, undef, # +default choice $view_callback ] ], toggle_actions => [ [ 'Auto_select', undef, N("_Select dependencies without asking"), undef, undef, sub { my $box = $check_boxes{Auto_select}; $auto_select_opt->[0] = $box->get_active; $::rpmdrake_options{auto} = $box->get_active; $urpm->{options}{auto} = $box->get_active; } ], [ 'Clean_Cache', undef, N("Clear download cache after successful install"), undef, undef, sub { $clean_cache->[0] = $check_boxes{Clean_Cache}->get_active; $::noclean = !$clean_cache->[0]; } ], [ 'Show_auto_selected_pkgs', undef, N("_Show automatically selected packages"), undef, undef, sub { $dont_show_selections->[0] = !$checkbox_show_autoselect->get_active; } ], [ 'Compute_updates_on_startup', undef, N("_Compute updates on startup"), undef, undef, sub { $compute_updates->[0] = $check_boxes{Compute_updates_on_startup}->get_active; } ], [ 'NVR_search', undef, N("Search in _full package names"), undef, undef, sub { $NVR_searches->[0] = $check_boxes{NVR_search}->get_active; } ], [ 'Use_RE_in_searches', undef, N("Use _regular expressions in searches"), undef, undef, sub { $use_regexp->[0] = $check_boxes{Use_RE_in_searches}->get_active; } ], ], string => join("\n", qq( ), if_(! $>, ""), qq( ), if_(!$>, qq( )), "", (map { "" } @radio_labels), qq( ))); my $menu = $ui->get_widget('/MenuBar'); if (my $widget = $ui->get_widget('/MenuBar/ViewMenu/' . $modes{$mode->[0]})) { $widget->set_active(1); } else { warn "Impossible to set $mode->[0] view as default\n"; } %check_boxes = map { $_ => $ui->get_widget('/MenuBar/OptionsMenu/' . $_); } ('Auto_select', 'Clean_Cache', 'NVR_search', 'Compute_updates_on_startup', 'Use_RE_in_searches'); if (!$>) { $check_boxes{Use_RE_in_searches}->set_active($use_regexp->[0]); $check_boxes{NVR_search}->set_active($NVR_searches->[0]); $check_boxes{Auto_select}->set_active($auto_select_opt->[0] || ''); $check_boxes{Compute_updates_on_startup}->set_active($compute_updates->[0] || ''); $check_boxes{Clean_Cache}->set_active($clean_cache->[0]); } $checkbox_show_autoselect = $ui->get_widget('/MenuBar/OptionsMenu/Auto_select') and $checkbox_show_autoselect->set_active(!$dont_show_selections->[0]); my $accel = Gtk3::AccelGroup->new; $accel->connect(Gtk3::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(mygtk3::root_window_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 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, Gtk3::Gdk::KEY_Return, Gtk3::Gdk::KEY_KP_Enter) and $find_callback->(); }, ), ), 1, $hpaned, 0, $status, 0, gtkpack_( gtknew('HBox', spacing => 20), 0, gtksignal_connect( Gtk3::Button->new(but_(N("Select all"))), clicked => sub { toggle_all($options, 1); }, ), 1, gtknew('Label'), 0, my $action_button = gtksignal_connect( Gtk3::Button->new(but_(N("Apply"))), clicked => sub { do_action($options, $callback_action, $info) }, ), 0, gtksignal_connect( Gtk3::Button->new(but_(N("Quit"))), clicked => \&quit, ), ), ), ), 0, $statusbar = Gtk3::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) ], @{ ugtk3::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}->add_accel_group($ui->get_accel_group); $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->get_window, sub { pkgs_provider($default_list_mode) }); # default mode if (@initial_selection) { $options->{initial_selection} = \@initial_selection; undef $pkgs->{$_}{selected} 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 = ugtk3->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);