1 |
dmorgan |
535 |
package Rpmdrake::gui; |
2 |
|
|
#***************************************************************************** |
3 |
|
|
# |
4 |
|
|
# Copyright (c) 2002 Guillaume Cottenceau |
5 |
|
|
# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com> |
6 |
|
|
# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA |
7 |
|
|
# Copyright (c) 2005-2007 Mandriva SA |
8 |
|
|
# |
9 |
|
|
# This program is free software; you can redistribute it and/or modify |
10 |
|
|
# it under the terms of the GNU General Public License version 2, as |
11 |
|
|
# published by the Free Software Foundation. |
12 |
|
|
# |
13 |
|
|
# This program is distributed in the hope that it will be useful, |
14 |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 |
|
|
# GNU General Public License for more details. |
17 |
|
|
# |
18 |
|
|
# You should have received a copy of the GNU General Public License |
19 |
|
|
# along with this program; if not, write to the Free Software |
20 |
|
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21 |
|
|
# |
22 |
|
|
#***************************************************************************** |
23 |
|
|
# |
24 |
|
|
# $Id$ |
25 |
|
|
|
26 |
|
|
use strict; |
27 |
|
|
our @ISA = qw(Exporter); |
28 |
|
|
use lib qw(/usr/lib/libDrakX); |
29 |
|
|
|
30 |
|
|
use common; |
31 |
|
|
use mygtk2 qw(gtknew); #- do not import gtkadd which conflicts with ugtk2 version |
32 |
|
|
|
33 |
|
|
use ugtk2 qw(:helpers :wrappers); |
34 |
|
|
use rpmdrake; |
35 |
|
|
use Rpmdrake::open_db; |
36 |
|
|
use Rpmdrake::formatting; |
37 |
|
|
use Rpmdrake::init; |
38 |
|
|
use Rpmdrake::icon; |
39 |
|
|
use Rpmdrake::pkg; |
40 |
|
|
use feature 'state'; |
41 |
|
|
|
42 |
|
|
our @EXPORT = qw( |
43 |
|
|
$descriptions |
44 |
|
|
$find_entry |
45 |
|
|
$force_displaying_group |
46 |
|
|
$force_rebuild |
47 |
|
|
$pkgs |
48 |
|
|
$results_ok |
49 |
|
|
$results_none |
50 |
|
|
$size_free |
51 |
|
|
$size_selected |
52 |
|
|
$urpm |
53 |
|
|
%grp_columns |
54 |
|
|
%pkg_columns |
55 |
|
|
@filtered_pkgs |
56 |
|
|
@initial_selection |
57 |
|
|
ask_browse_tree_given_widgets_for_rpmdrake |
58 |
|
|
build_tree |
59 |
|
|
callback_choices |
60 |
|
|
compute_main_window_size |
61 |
|
|
do_action |
62 |
|
|
get_info |
63 |
|
|
get_summary |
64 |
|
|
is_locale_available |
65 |
|
|
node_state |
66 |
|
|
pkgs_provider |
67 |
|
|
real_quit |
68 |
|
|
reset_search |
69 |
|
|
set_node_state |
70 |
|
|
sort_callback |
71 |
|
|
switch_pkg_list_mode |
72 |
|
|
toggle_all |
73 |
|
|
toggle_nodes |
74 |
|
|
); |
75 |
|
|
|
76 |
|
|
our ($descriptions, %filters, @filtered_pkgs, %filter_methods, $force_displaying_group, $force_rebuild, @initial_selection, $pkgs, $size_free, $size_selected, $urpm); |
77 |
|
|
our ($results_ok, $results_none) = (N("Search results"), N("Search results (none)")); |
78 |
|
|
|
79 |
|
|
our %grp_columns = ( |
80 |
|
|
label => 0, |
81 |
|
|
icon => 2, |
82 |
|
|
); |
83 |
|
|
|
84 |
|
|
our %pkg_columns = ( |
85 |
|
|
text => 0, |
86 |
|
|
state_icon => 1, |
87 |
|
|
state => 2, |
88 |
|
|
selected => 3, |
89 |
|
|
short_name => 4, |
90 |
|
|
version => 5, |
91 |
|
|
release => 6, |
92 |
|
|
'arch' => 7, |
93 |
|
|
selectable => 8, |
94 |
|
|
); |
95 |
|
|
|
96 |
|
|
|
97 |
|
|
sub compute_main_window_size { |
98 |
|
|
my ($w) = @_; |
99 |
|
|
($typical_width) = string_size($w->{real_window}, translate("Graphical Environment") . "xmms-more-vis-plugins"); |
100 |
|
|
$typical_width > 600 and $typical_width = 600; #- try to not being crazy with a too large value |
101 |
|
|
$typical_width < 150 and $typical_width = 150; |
102 |
|
|
} |
103 |
|
|
|
104 |
|
|
sub get_summary { |
105 |
|
|
my ($key) = @_; |
106 |
tv |
6088 |
my $summary = translate($pkgs->{$key}{pkg}->summary); |
107 |
tv |
5516 |
require utf8; |
108 |
tv |
3617 |
utf8::valid($summary) ? $summary : @{[]}; |
109 |
dmorgan |
535 |
} |
110 |
|
|
|
111 |
|
|
sub build_expander { |
112 |
|
|
my ($pkg, $label, $type, $get_data, $o_installed_version) = @_; |
113 |
|
|
my $textview; |
114 |
|
|
gtkadd( |
115 |
|
|
gtkshow(my $exp = gtksignal_connect( |
116 |
|
|
Gtk2::Expander->new(format_field($label)), |
117 |
|
|
activate => sub { |
118 |
|
|
state $first; |
119 |
|
|
return if $first; |
120 |
|
|
$first = 1; |
121 |
|
|
slow_func($::main_window->window, sub { |
122 |
|
|
extract_header($pkg, $urpm, $type, $o_installed_version); |
123 |
|
|
gtktext_insert($textview, $get_data->() || [ [ N("(Not available)") ] ]); |
124 |
|
|
}); |
125 |
|
|
})), |
126 |
|
|
$textview = gtknew('TextView') |
127 |
|
|
); |
128 |
|
|
$exp->set_use_markup(1); |
129 |
|
|
$exp; |
130 |
|
|
} |
131 |
|
|
|
132 |
|
|
|
133 |
|
|
sub get_advisory_link { |
134 |
|
|
my ($update_descr) = @_; |
135 |
|
|
my $link = gtkshow(Gtk2::LinkButton->new($update_descr->{URL}, N("Security advisory"))); |
136 |
|
|
$link->set_uri_hook(\&run_help_callback); |
137 |
|
|
[ $link ]; |
138 |
|
|
} |
139 |
|
|
|
140 |
|
|
sub get_description { |
141 |
|
|
my ($pkg, $update_descr) = @_; |
142 |
|
|
@{ ugtk2::markup_to_TextView_format(join("\n", |
143 |
|
|
(eval { |
144 |
|
|
escape_text_for_TextView_markup_format( |
145 |
|
|
$pkg->{description} |
146 |
|
|
|| $update_descr->{description}); |
147 |
|
|
} || '<i>' . N("No description") . '</i>') |
148 |
|
|
)) }; |
149 |
|
|
} |
150 |
|
|
|
151 |
|
|
sub get_string_from_keywords { |
152 |
tv |
3609 |
my ($medium, $name) = @_; |
153 |
|
|
my @media_types; |
154 |
|
|
if ($medium->{mediacfg}) { |
155 |
tv |
6532 |
my ($distribconf, $medium_path) = @{$medium->{mediacfg}}; |
156 |
|
|
@media_types = split(':', $distribconf->getvalue($medium_path, 'media_type')) if $distribconf; |
157 |
tv |
3609 |
} |
158 |
dmorgan |
535 |
|
159 |
dmorgan |
594 |
my $unsupported = N("It is <b>not supported</b> by Mageia."); |
160 |
dmorgan |
535 |
my $dangerous = N("It may <b>break</b> your system."); |
161 |
|
|
my $s; |
162 |
|
|
$s .= N("This package is not free software") . "\n" if member('non-free', @media_types); |
163 |
tv |
3611 |
if ($pkgs->{$name}{is_backport} || member('backport', @media_types)) { |
164 |
dmorgan |
535 |
return join("\n", |
165 |
|
|
N("This package contains a new version that was backported."), |
166 |
|
|
$unsupported, $dangerous, $s); |
167 |
|
|
} elsif (member('testing', @media_types)) { |
168 |
|
|
return join("\n", |
169 |
|
|
N("This package is a potential candidate for an update."), |
170 |
|
|
$unsupported, $dangerous, $s); |
171 |
|
|
} elsif (member('updates', @media_types)) { |
172 |
|
|
return join("\n", |
173 |
|
|
(member('official', @media_types) ? |
174 |
tv |
1033 |
N("This is an official update which is supported by Mageia.") |
175 |
|
|
: (N("This is an unofficial update."), $unsupported)) |
176 |
dmorgan |
535 |
, |
177 |
|
|
$s); |
178 |
|
|
} else { |
179 |
dmorgan |
594 |
$s .= N("This is an official package supported by Mageia") . "\n" if member('official', @media_types); |
180 |
dmorgan |
535 |
return $s; |
181 |
|
|
} |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
sub get_main_text { |
185 |
tv |
3611 |
my ($medium, $fullname, $name, $summary, $is_update, $update_descr) = @_; |
186 |
dmorgan |
535 |
|
187 |
tv |
3611 |
my $txt = get_string_from_keywords($medium, $fullname); |
188 |
dmorgan |
535 |
|
189 |
|
|
ugtk2::markup_to_TextView_format( |
190 |
|
|
# force align "name - summary" to the right with RTL languages (#33603): |
191 |
|
|
if_(lang::text_direction_rtl(), "\x{200f}") . |
192 |
|
|
join("\n", |
193 |
|
|
format_header(join(' - ', $name, $summary)) . |
194 |
|
|
# workaround gtk+ bug where GtkTextView wronly limit embedded widget size to bigger line's width (#25533): |
195 |
|
|
"\x{200b} \x{feff}" . ' ' x 120, |
196 |
|
|
if_($txt, format_field(N("Notice: ")) . $txt), |
197 |
|
|
if_($is_update, # is it an update? |
198 |
|
|
format_field(N("Importance: ")) . format_update_field($update_descr->{importance}), |
199 |
|
|
format_field(N("Reason for update: ")) . format_update_field(rpm_description($update_descr->{pre})), |
200 |
|
|
), |
201 |
|
|
'' # extra empty line |
202 |
|
|
)); |
203 |
|
|
} |
204 |
|
|
|
205 |
|
|
sub get_details { |
206 |
tv |
5515 |
my ($pkg, $upkg, $installed_version, $raw_medium) = @_; |
207 |
dmorgan |
535 |
my $a = ugtk2::markup_to_TextView_format( |
208 |
|
|
$spacing . join("\n$spacing", |
209 |
tv |
5997 |
format_field(N("Version: ")) . $upkg->EVR, |
210 |
dmorgan |
535 |
($upkg->flag_installed ? |
211 |
|
|
format_field(N("Currently installed version: ")) . $installed_version : () |
212 |
|
|
), |
213 |
|
|
format_field(N("Group: ")) . translate_group($upkg->group), |
214 |
|
|
format_field(N("Architecture: ")) . $upkg->arch, |
215 |
|
|
format_field(N("Size: ")) . N("%s KB", int($upkg->size/1024)), |
216 |
|
|
eval { format_field(N("Medium: ")) . $raw_medium->{name} }, |
217 |
|
|
), |
218 |
|
|
); |
219 |
|
|
my @link = get_url_link($upkg, $pkg); |
220 |
|
|
push @$a, @link if @link; |
221 |
|
|
$a; |
222 |
|
|
} |
223 |
|
|
|
224 |
|
|
sub get_new_deps { |
225 |
|
|
my ($urpm, $upkg) = @_; |
226 |
|
|
my $deps_textview; |
227 |
|
|
my @a = [ gtkadd( |
228 |
|
|
gtksignal_connect( |
229 |
|
|
gtkshow(my $dependencies = Gtk2::Expander->new(format_field(N("New dependencies:")))), |
230 |
|
|
activate => sub { |
231 |
|
|
slow_func($::main_window->window, sub { |
232 |
|
|
my $state = {}; |
233 |
tv |
5743 |
my $db = open_rpm_db(); |
234 |
tv |
5921 |
my @requested = $urpm->resolve_requested__no_suggests_( |
235 |
tv |
5743 |
$db, $state, |
236 |
dmorgan |
535 |
{ $upkg->id => 1 }, |
237 |
|
|
); |
238 |
tv |
5943 |
@requested = $urpm->resolve_requested_suggests($db, $state, \@requested); |
239 |
tv |
5743 |
undef $db; |
240 |
dmorgan |
535 |
my @nodes_with_deps = map { urpm_name($_) } @requested; |
241 |
|
|
my @deps = sort { $a cmp $b } difference2(\@nodes_with_deps, [ urpm_name($upkg) ]); |
242 |
tv |
5953 |
@deps = N("All dependencies installed.") if !@deps; |
243 |
dmorgan |
535 |
gtktext_insert($deps_textview, join("\n", @deps)); |
244 |
|
|
}); |
245 |
|
|
} |
246 |
|
|
), |
247 |
|
|
$deps_textview = gtknew('TextView') |
248 |
|
|
) ]; |
249 |
|
|
$dependencies->set_use_markup(1); |
250 |
|
|
@a; |
251 |
|
|
} |
252 |
|
|
|
253 |
|
|
sub get_url_link { |
254 |
|
|
my ($upkg, $pkg) = @_; |
255 |
|
|
|
256 |
|
|
my $url = $upkg->url || $pkg->{url}; |
257 |
|
|
|
258 |
|
|
if (!$url) { |
259 |
tv |
5389 |
open_rpm_db()->traverse_tag_find('name', $upkg->name, sub { $url = $_[0]->url }); |
260 |
dmorgan |
535 |
} |
261 |
|
|
|
262 |
|
|
return if !$url; |
263 |
|
|
|
264 |
|
|
my @a = |
265 |
|
|
(@{ ugtk2::markup_to_TextView_format(format_field("\n$spacing" . N("URL: "))) }, |
266 |
|
|
[ my $link = gtkshow(Gtk2::LinkButton->new($url, $url)) ]); |
267 |
|
|
$link->set_uri_hook(\&run_help_callback); |
268 |
|
|
@a; |
269 |
|
|
} |
270 |
|
|
|
271 |
|
|
sub files_format { |
272 |
|
|
my ($files) = @_; |
273 |
|
|
ugtk2::markup_to_TextView_format( |
274 |
|
|
'<tt>' . $spacing #- to highlight information |
275 |
|
|
. join("\n$spacing", map { "\x{200e}$_" } @$files) |
276 |
|
|
. '</tt>'); |
277 |
|
|
} |
278 |
|
|
|
279 |
|
|
sub format_pkg_simplifiedinfo { |
280 |
|
|
my ($pkgs, $key, $urpm, $descriptions) = @_; |
281 |
|
|
my ($name) = split_fullname($key); |
282 |
|
|
my $pkg = $pkgs->{$key}; |
283 |
|
|
my $upkg = $pkg->{pkg}; |
284 |
|
|
return if !$upkg; |
285 |
|
|
my $raw_medium = pkg2medium($upkg, $urpm); |
286 |
|
|
my $medium = !$raw_medium->{fake} ? $raw_medium->{name} : undef; |
287 |
|
|
my $update_descr = $descriptions->{$medium}{$name}; |
288 |
|
|
# discard update fields if not matching: |
289 |
|
|
my $is_update = ($upkg->flag_upgrade && $update_descr && $update_descr->{pre}); |
290 |
|
|
my $summary = get_summary($key); |
291 |
tv |
3611 |
my $s = get_main_text($raw_medium, $key, $name, $summary, $is_update, $update_descr); |
292 |
dmorgan |
535 |
push @$s, get_advisory_link($update_descr) if $is_update; |
293 |
|
|
|
294 |
|
|
push @$s, get_description($pkg, $update_descr); |
295 |
|
|
push @$s, [ "\n" ]; |
296 |
|
|
my $installed_version = eval { find_installed_version($upkg) }; |
297 |
|
|
|
298 |
|
|
push @$s, [ gtkadd(gtkshow(my $details_exp = Gtk2::Expander->new(format_field(N("Details:")))), |
299 |
tv |
5515 |
gtknew('TextView', text => get_details($pkg, $upkg, $installed_version, $raw_medium))) ]; |
300 |
dmorgan |
535 |
$details_exp->set_use_markup(1); |
301 |
|
|
push @$s, [ "\n\n" ]; |
302 |
|
|
push @$s, [ build_expander($pkg, N("Files:"), 'files', sub { files_format($pkg->{files}) }) ]; |
303 |
|
|
push @$s, [ "\n\n" ]; |
304 |
|
|
push @$s, [ build_expander($pkg, N("Changelog:"), 'changelog', sub { $pkg->{changelog} }, $installed_version) ]; |
305 |
|
|
|
306 |
|
|
push @$s, [ "\n\n" ]; |
307 |
|
|
if ($upkg->id) { # If not installed |
308 |
|
|
push @$s, get_new_deps($urpm, $upkg); |
309 |
|
|
} |
310 |
|
|
$s; |
311 |
|
|
} |
312 |
|
|
|
313 |
|
|
sub format_pkg_info { |
314 |
|
|
my ($pkgs, $key, $urpm, $descriptions) = @_; |
315 |
|
|
my $pkg = $pkgs->{$key}; |
316 |
|
|
my $upkg = $pkg->{pkg}; |
317 |
|
|
my ($name, $version) = split_fullname($key); |
318 |
|
|
my @files = ( |
319 |
|
|
format_field(N("Files:\n")), |
320 |
|
|
exists $pkg->{files} |
321 |
|
|
? '<tt>' . join("\n", map { "\x{200e}$_" } @{$pkg->{files}}) . '</tt>' #- to highlight information |
322 |
|
|
: N("(Not available)"), |
323 |
|
|
); |
324 |
|
|
my @chglo = (format_field(N("Changelog:\n")), ($pkg->{changelog} ? @{$pkg->{changelog}} : N("(Not available)"))); |
325 |
|
|
my @source_info = ( |
326 |
|
|
$MODE eq 'remove' || !@$max_info_in_descr |
327 |
|
|
? () |
328 |
|
|
: ( |
329 |
|
|
format_field(N("Medium: ")) . pkg2medium($upkg, $urpm)->{name}, |
330 |
|
|
format_field(N("Currently installed version: ")) . find_installed_version($upkg), |
331 |
|
|
) |
332 |
|
|
); |
333 |
|
|
my @max_info = @$max_info_in_descr && $changelog_first ? (@chglo, @files) : (@files, '', @chglo); |
334 |
|
|
ugtk2::markup_to_TextView_format(join("\n", format_field(N("Name: ")) . $name, |
335 |
|
|
format_field(N("Version: ")) . $version, |
336 |
|
|
format_field(N("Architecture: ")) . $upkg->arch, |
337 |
|
|
format_field(N("Size: ")) . N("%s KB", int($upkg->size/1024)), |
338 |
|
|
if_( |
339 |
|
|
$MODE eq 'update', |
340 |
|
|
format_field(N("Importance: ")) . $descriptions->{$name}{importance} |
341 |
|
|
), |
342 |
|
|
@source_info, |
343 |
|
|
'', # extra empty line |
344 |
tv |
6088 |
format_field(N("Summary: ")) . $upkg->summary, |
345 |
dmorgan |
535 |
'', # extra empty line |
346 |
|
|
if_( |
347 |
|
|
$MODE eq 'update', |
348 |
|
|
format_field(N("Reason for update: ")) . rpm_description($descriptions->{$name}{pre}), |
349 |
|
|
), |
350 |
|
|
format_field(N("Description: ")), ($pkg->{description} || $descriptions->{$name}{description} || N("No description")), |
351 |
|
|
@max_info, |
352 |
|
|
)); |
353 |
|
|
} |
354 |
|
|
|
355 |
tv |
3603 |
sub warn_if_no_pkg { |
356 |
dmorgan |
535 |
my ($name) = @_; |
357 |
tv |
3603 |
my ($short_name) = split_fullname($name); |
358 |
|
|
state $warned; |
359 |
|
|
if (!$warned) { |
360 |
|
|
$warned = 1; |
361 |
|
|
interactive_msg(N("Warning"), |
362 |
dmorgan |
535 |
join("\n", |
363 |
|
|
N("The package \"%s\" was found.", $name), |
364 |
|
|
N("However this package is not in the package list."), |
365 |
|
|
N("You may want to update your urpmi database."), |
366 |
|
|
'', |
367 |
|
|
N("Matching packages:"), |
368 |
|
|
'', |
369 |
|
|
join("\n", sort map { |
370 |
|
|
#-PO: this is list fomatting: "- <package_name> (medium: <medium_name>)" |
371 |
|
|
#-PO: eg: "- rpmdrake (medium: "Main Release" |
372 |
|
|
N("- %s (medium: %s)", $_, pkg2medium($pkgs->{$_}{pkg}, $urpm)->{name}); |
373 |
tv |
3603 |
} grep { /^$short_name/ } keys %$pkgs), |
374 |
dmorgan |
535 |
), |
375 |
|
|
scroll => 1, |
376 |
|
|
); |
377 |
|
|
} |
378 |
tv |
3603 |
return 'XXX'; |
379 |
|
|
} |
380 |
|
|
|
381 |
|
|
sub node_state { |
382 |
|
|
my ($name) = @_; |
383 |
tv |
3606 |
#- checks $_[0] -> hack for partial tree displaying |
384 |
|
|
return 'XXX' if !$name; |
385 |
tv |
3603 |
my $pkg = $pkgs->{$name}; |
386 |
|
|
my $urpm_obj = $pkg->{pkg}; |
387 |
|
|
return warn_if_no_pkg($name) if !$urpm_obj; |
388 |
dmorgan |
535 |
$pkg->{selected} ? |
389 |
|
|
($urpm_obj->flag_installed ? |
390 |
|
|
($urpm_obj->flag_upgrade ? 'to_install' : 'to_remove') |
391 |
|
|
: 'to_install') |
392 |
|
|
: ($urpm_obj->flag_installed ? |
393 |
tv |
3846 |
($pkgs->{$name}{is_backport} ? 'backport' : |
394 |
dmorgan |
535 |
($urpm_obj->flag_upgrade ? 'to_update' |
395 |
tv |
3846 |
: ($urpm_obj->flag_base ? 'base' : 'installed'))) |
396 |
dmorgan |
535 |
: 'uninstalled'); |
397 |
|
|
} |
398 |
|
|
|
399 |
|
|
my ($common, $w, %wtree, %ptree, %pix); |
400 |
|
|
|
401 |
|
|
sub set_node_state { |
402 |
|
|
my ($iter, $state, $model) = @_; |
403 |
tv |
3604 |
return if $state eq 'XXX' || !$state; |
404 |
dmorgan |
535 |
$pix{$state} ||= gtkcreate_pixbuf('state_' . $state); |
405 |
|
|
$model->set($iter, $pkg_columns{state_icon} => $pix{$state}); |
406 |
|
|
$model->set($iter, $pkg_columns{state} => $state); |
407 |
|
|
$model->set($iter, $pkg_columns{selected} => to_bool(member($state, qw(base installed to_install)))); #$pkg->{selected})); |
408 |
|
|
$model->set($iter, $pkg_columns{selectable} => to_bool($state ne 'base')); |
409 |
|
|
} |
410 |
|
|
|
411 |
|
|
sub set_leaf_state { |
412 |
|
|
my ($leaf, $state, $model) = @_; |
413 |
|
|
set_node_state($_, $state, $model) foreach @{$ptree{$leaf}}; |
414 |
|
|
} |
415 |
|
|
|
416 |
|
|
sub grep_unselected { grep { exists $pkgs->{$_} && !$pkgs->{$_}{selected} } @_ } |
417 |
|
|
|
418 |
|
|
sub add_parent { |
419 |
|
|
my ($root, $state) = @_; |
420 |
|
|
$root or return undef; |
421 |
|
|
if (my $w = $wtree{$root}) { return $w } |
422 |
|
|
my $s; foreach (split '\|', $root) { |
423 |
|
|
my $s2 = $s ? "$s|$_" : $_; |
424 |
|
|
$wtree{$s2} ||= do { |
425 |
|
|
my $pixbuf = get_icon($s2, $s); |
426 |
tv |
3871 |
my $iter = $w->{tree_model}->append_set($s ? add_parent($s, $state) : undef, |
427 |
dmorgan |
535 |
[ $grp_columns{label} => $_, if_($pixbuf, $grp_columns{icon} => $pixbuf) ]); |
428 |
|
|
$iter; |
429 |
|
|
}; |
430 |
|
|
$s = $s2; |
431 |
|
|
} |
432 |
|
|
set_node_state($wtree{$s}, $state, $w->{tree_model}); #- use this state by default as tree is building. # |
433 |
|
|
$wtree{$s}; |
434 |
|
|
} |
435 |
|
|
|
436 |
|
|
sub add_node { |
437 |
tv |
3872 |
my ($leaf, $root, $o_options) = @_; |
438 |
dmorgan |
535 |
my $state = node_state($leaf) or return; |
439 |
|
|
if ($leaf) { |
440 |
|
|
my $iter; |
441 |
|
|
if (is_a_package($leaf)) { |
442 |
|
|
my ($name, $version, $release, $arch) = split_fullname($leaf); |
443 |
|
|
$iter = $w->{detail_list_model}->append_set([ $pkg_columns{text} => $leaf, |
444 |
|
|
$pkg_columns{short_name} => format_name_n_summary($name, get_summary($leaf)), |
445 |
|
|
$pkg_columns{version} => $version, |
446 |
|
|
$pkg_columns{release} => $release, |
447 |
|
|
$pkg_columns{arch} => $arch, |
448 |
|
|
]); |
449 |
|
|
set_node_state($iter, $state, $w->{detail_list_model}); |
450 |
|
|
$ptree{$leaf} = [ $iter ]; |
451 |
|
|
} else { |
452 |
|
|
$iter = $w->{tree_model}->append_set(add_parent($root, $state), [ $grp_columns{label} => $leaf ]); |
453 |
|
|
push @{$wtree{$leaf}}, $iter; |
454 |
|
|
} |
455 |
|
|
} else { |
456 |
|
|
my $parent = add_parent($root, $state); |
457 |
|
|
#- hackery for partial displaying of trees, used in rpmdrake: |
458 |
|
|
#- if leaf is void, we may create the parent and one child (to have the [+] in front of the parent in the ctree) |
459 |
|
|
#- though we use '' as the label of the child; then rpmdrake will connect on tree_expand, and whenever |
460 |
|
|
#- the first child has '' as the label, it will remove the child and add all the "right" children |
461 |
tv |
3872 |
$o_options->{nochild} or $w->{tree_model}->append_set($parent, [ $grp_columns{label} => '' ]); # test $leaf? |
462 |
dmorgan |
535 |
} |
463 |
|
|
} |
464 |
|
|
|
465 |
|
|
my ($prev_label); |
466 |
|
|
sub update_size { |
467 |
|
|
my ($common) = shift @_; |
468 |
|
|
if ($w->{status}) { |
469 |
|
|
my $new_label = $common->{get_status}(); |
470 |
|
|
$prev_label ne $new_label and $w->{status}->set($prev_label = $new_label); |
471 |
|
|
} |
472 |
|
|
} |
473 |
|
|
|
474 |
|
|
sub children { |
475 |
|
|
my ($w) = @_; |
476 |
|
|
map { $w->{detail_list_model}->get($_, $pkg_columns{text}) } gtktreeview_children($w->{detail_list_model}); |
477 |
|
|
} |
478 |
|
|
|
479 |
|
|
sub toggle_all { |
480 |
|
|
my ($common, $_val) = @_; |
481 |
|
|
my $w = $common->{widgets}; |
482 |
|
|
my @l = children($w) or return; |
483 |
|
|
|
484 |
|
|
my @unsel = grep_unselected(@l); |
485 |
|
|
my @p = @unsel ? |
486 |
|
|
#- not all is selected, select all if no option to potentially override |
487 |
|
|
(exists $common->{partialsel_unsel} && $common->{partialsel_unsel}->(\@unsel, \@l) ? difference2(\@l, \@unsel) : @unsel) |
488 |
|
|
: @l; |
489 |
|
|
toggle_nodes($w->{detail_list}->window, $w->{detail_list_model}, \&set_leaf_state, node_state($p[0]), @p); |
490 |
|
|
update_size($common); |
491 |
|
|
} |
492 |
|
|
|
493 |
|
|
# ask_browse_tree_given_widgets_for_rpmdrake will run gtk+ loop. its main parameter "common" is a hash containing: |
494 |
|
|
# - a "widgets" subhash which holds: |
495 |
|
|
# o a "w" reference on a ugtk2 object |
496 |
|
|
# o "tree" & "info" references a TreeView |
497 |
|
|
# o "info" is a TextView |
498 |
|
|
# o "tree_model" is the associated model of "tree" |
499 |
|
|
# o "status" references a Label |
500 |
|
|
# - some methods: get_info, node_state, build_tree, partialsel_unsel, grep_unselected, rebuild_tree, toggle_nodes, get_status |
501 |
|
|
# - "tree_submode": the default mode (by group, ...), ... |
502 |
|
|
# - "state": a hash of misc flags: => { flat => '0' }, |
503 |
|
|
# o "flat": is the tree flat or not |
504 |
|
|
# - "tree_mode": mode of the tree ("gui_pkgs", "by_group", ...) (mainly used by rpmdrake) |
505 |
|
|
|
506 |
|
|
sub ask_browse_tree_given_widgets_for_rpmdrake { |
507 |
|
|
($common) = @_; |
508 |
|
|
$w = $common->{widgets}; |
509 |
|
|
|
510 |
|
|
$w->{detail_list} ||= $w->{tree}; |
511 |
|
|
$w->{detail_list_model} ||= $w->{tree_model}; |
512 |
|
|
|
513 |
|
|
$common->{add_parent} = \&add_parent; |
514 |
|
|
my $clear_all_caches = sub { |
515 |
|
|
%ptree = %wtree = (); |
516 |
|
|
}; |
517 |
|
|
$common->{clear_all_caches} = $clear_all_caches; |
518 |
|
|
$common->{delete_all} = sub { |
519 |
|
|
$clear_all_caches->(); |
520 |
|
|
$w->{detail_list_model}->clear; |
521 |
|
|
$w->{tree_model}->clear; |
522 |
|
|
}; |
523 |
|
|
$common->{rebuild_tree} = sub { |
524 |
|
|
$common->{delete_all}->(); |
525 |
|
|
$common->{build_tree}($common->{state}{flat}, $common->{tree_mode}); |
526 |
|
|
update_size($common); |
527 |
|
|
}; |
528 |
|
|
$common->{delete_category} = sub { |
529 |
|
|
my ($cat) = @_; |
530 |
|
|
exists $wtree{$cat} or return; |
531 |
|
|
%ptree = (); |
532 |
|
|
|
533 |
|
|
if (exists $wtree{$cat}) { |
534 |
|
|
my $_iter_str = $w->{tree_model}->get_path_str($wtree{$cat}); |
535 |
|
|
$w->{tree_model}->remove($wtree{$cat}); |
536 |
|
|
delete $wtree{$cat}; |
537 |
|
|
} |
538 |
|
|
update_size($common); |
539 |
|
|
}; |
540 |
|
|
$common->{add_nodes} = sub { |
541 |
|
|
my (@nodes) = @_; |
542 |
|
|
$w->{detail_list_model}->clear; |
543 |
|
|
$w->{detail_list}->scroll_to_point(0, 0); |
544 |
|
|
add_node($_->[0], $_->[1], $_->[2]) foreach @nodes; |
545 |
|
|
update_size($common); |
546 |
|
|
}; |
547 |
|
|
|
548 |
|
|
$common->{display_info} = sub { |
549 |
|
|
gtktext_insert($w->{info}, get_info($_[0], $w->{tree}->window)); |
550 |
|
|
$w->{info}->scroll_to_iter($w->{info}->get_buffer->get_start_iter, 0, 0, 0, 0); |
551 |
|
|
0; |
552 |
|
|
}; |
553 |
|
|
|
554 |
|
|
my $fast_toggle = sub { |
555 |
|
|
my ($iter) = @_; |
556 |
|
|
gtkset_mousecursor_wait($w->{w}{rwindow}->window); |
557 |
|
|
my $_cleaner = before_leaving { gtkset_mousecursor_normal($w->{w}{rwindow}->window) }; |
558 |
|
|
my $name = $w->{detail_list_model}->get($iter, $pkg_columns{text}); |
559 |
|
|
my $urpm_obj = $pkgs->{$name}{pkg}; |
560 |
|
|
|
561 |
|
|
if ($urpm_obj->flag_base) { |
562 |
|
|
interactive_msg(N("Warning"), |
563 |
|
|
N("Removing package %s would break your system", $name)); |
564 |
|
|
return ''; |
565 |
|
|
} |
566 |
|
|
|
567 |
|
|
if ($urpm_obj->flag_skip) { |
568 |
|
|
interactive_msg(N("Warning"), N("The \"%s\" package is in urpmi skip list.\nDo you want to select it anyway?", $name), yesno => 1) or return ''; |
569 |
|
|
$urpm_obj->set_flag_skip(0); |
570 |
|
|
} |
571 |
|
|
|
572 |
|
|
if ($Rpmdrake::pkg::need_restart && !$priority_up_alread_warned) { |
573 |
|
|
$priority_up_alread_warned = 1; |
574 |
|
|
interactive_msg(N("Warning"), '<b>' . N("Rpmdrake or one of its priority dependencies needs to be updated first. Rpmdrake will then restart.") . '</b>' . "\n\n"); |
575 |
|
|
} |
576 |
|
|
|
577 |
|
|
toggle_nodes($w->{tree}->window, $w->{detail_list_model}, \&set_leaf_state, $w->{detail_list_model}->get($iter, $pkg_columns{state}), |
578 |
|
|
$w->{detail_list_model}->get($iter, $pkg_columns{text})); |
579 |
|
|
update_size($common); |
580 |
|
|
}; |
581 |
|
|
$w->{detail_list}->get_selection->signal_connect(changed => sub { |
582 |
|
|
my ($model, $iter) = $_[0]->get_selected; |
583 |
|
|
$model && $iter or return; |
584 |
|
|
$common->{display_info}($model->get($iter, $pkg_columns{text})); |
585 |
|
|
}); |
586 |
|
|
($w->{detail_list}->get_column(0)->get_cell_renderers)[0]->signal_connect(toggled => sub { |
587 |
|
|
my ($_cell, $path) = @_; #text_ |
588 |
|
|
my $iter = $w->{detail_list_model}->get_iter_from_string($path); |
589 |
|
|
$fast_toggle->($iter) if $iter; |
590 |
|
|
1; |
591 |
|
|
}); |
592 |
|
|
$common->{rebuild_tree}->(); |
593 |
|
|
update_size($common); |
594 |
|
|
$common->{initial_selection} and toggle_nodes($w->{tree}->window, $w->{detail_list_model}, \&set_leaf_state, undef, @{$common->{initial_selection}}); |
595 |
|
|
#my $_b = before_leaving { $clear_all_caches->() }; |
596 |
|
|
$common->{init_callback}->() if $common->{init_callback}; |
597 |
|
|
$w->{w}->main; |
598 |
|
|
} |
599 |
|
|
|
600 |
|
|
our $find_entry; |
601 |
|
|
|
602 |
|
|
sub reset_search() { |
603 |
|
|
return if !$common; |
604 |
|
|
$common->{delete_category}->($_) foreach $results_ok, $results_none; |
605 |
|
|
# clear package list: |
606 |
|
|
$common->{add_nodes}->(); |
607 |
|
|
} |
608 |
|
|
|
609 |
|
|
sub is_a_package { |
610 |
|
|
my ($pkg) = @_; |
611 |
|
|
return exists $pkgs->{$pkg}; |
612 |
|
|
} |
613 |
|
|
|
614 |
|
|
sub switch_pkg_list_mode { |
615 |
|
|
my ($mode) = @_; |
616 |
|
|
return if !$mode; |
617 |
|
|
return if !$filter_methods{$mode}; |
618 |
|
|
$force_displaying_group = 1; |
619 |
|
|
$filter_methods{$mode}->(); |
620 |
|
|
} |
621 |
|
|
|
622 |
|
|
sub is_updatable { |
623 |
|
|
my $p = $pkgs->{$_[0]}; |
624 |
|
|
$p->{pkg} && !$p->{selected} && $p->{pkg}->flag_installed && $p->{pkg}->flag_upgrade; |
625 |
|
|
} |
626 |
|
|
|
627 |
|
|
sub pkgs_provider { |
628 |
tv |
3837 |
my ($mode, %options) = @_; |
629 |
dmorgan |
535 |
return if !$mode; |
630 |
tv |
3839 |
my $h = &get_pkgs(%options); |
631 |
dmorgan |
535 |
($urpm, $descriptions) = @$h{qw(urpm update_descr)}; |
632 |
|
|
$pkgs = $h->{all_pkgs}; |
633 |
|
|
%filters = ( |
634 |
|
|
non_installed => $h->{installable}, |
635 |
|
|
installed => $h->{installed}, |
636 |
|
|
all => [ keys %$pkgs ], |
637 |
|
|
); |
638 |
|
|
my %tmp_filter_methods = ( |
639 |
|
|
all => sub { |
640 |
tv |
3604 |
[ difference2([ keys %$pkgs ], $h->{inactive_backports}) ]; |
641 |
dmorgan |
535 |
}, |
642 |
|
|
all_updates => sub { |
643 |
|
|
# potential "updates" from media not tagged as updates: |
644 |
|
|
if (!$options{pure_updates} && !$Rpmdrake::pkg::need_restart) { |
645 |
|
|
[ @{$h->{updates}}, |
646 |
|
|
difference2([ grep { is_updatable($_) } @{$h->{installable}} ], $h->{backports}) ]; |
647 |
|
|
} else { |
648 |
|
|
[ difference2($h->{updates}, $h->{inactive_backports}) ]; |
649 |
|
|
} |
650 |
|
|
}, |
651 |
|
|
backports => sub { $h->{backports} }, |
652 |
|
|
meta_pkgs => sub { |
653 |
tv |
3604 |
[ difference2($h->{meta_pkgs}, $h->{inactive_backports}) ]; |
654 |
dmorgan |
535 |
}, |
655 |
|
|
gui_pkgs => sub { |
656 |
tv |
3604 |
[ difference2($h->{gui_pkgs}, $h->{inactive_backports}) ]; |
657 |
dmorgan |
535 |
}, |
658 |
|
|
); |
659 |
|
|
foreach my $importance (qw(bugfix security normal)) { |
660 |
|
|
$tmp_filter_methods{$importance} = sub { |
661 |
|
|
my @media = keys %$descriptions; |
662 |
|
|
[ grep { |
663 |
|
|
my ($name) = split_fullname($_); |
664 |
|
|
my $medium = find { $descriptions->{$_}{$name} } @media; |
665 |
|
|
$medium && $descriptions->{$medium}{$name}{importance} eq $importance } @{$h->{updates}} ]; |
666 |
|
|
}; |
667 |
|
|
} |
668 |
|
|
|
669 |
|
|
undef %filter_methods; |
670 |
|
|
foreach my $type (keys %tmp_filter_methods) { |
671 |
|
|
$filter_methods{$type} = sub { |
672 |
|
|
$force_rebuild = 1; # force rebuilding tree since we changed filter (FIXME: switch to SortModel) |
673 |
|
|
@filtered_pkgs = intersection($filters{$filter->[0]}, $tmp_filter_methods{$type}->()); |
674 |
|
|
}; |
675 |
|
|
} |
676 |
|
|
|
677 |
|
|
switch_pkg_list_mode($mode); |
678 |
|
|
} |
679 |
|
|
|
680 |
|
|
sub closure_removal { |
681 |
|
|
local $urpm->{state} = {}; |
682 |
|
|
urpm::select::find_packages_to_remove($urpm, $urpm->{state}, \@_); |
683 |
|
|
} |
684 |
|
|
|
685 |
|
|
sub is_locale_available { |
686 |
tv |
3613 |
my ($name) = @_; |
687 |
|
|
any { $urpm->{depslist}[$_]->flag_selected } keys %{$urpm->{provides}{$name} || {}} and return 1; |
688 |
dmorgan |
535 |
my $found; |
689 |
tv |
3615 |
open_rpm_db()->traverse_tag_find('name', $name, sub { $found = 1 }); |
690 |
dmorgan |
535 |
return $found; |
691 |
|
|
} |
692 |
|
|
|
693 |
|
|
sub callback_choices { |
694 |
|
|
my (undef, undef, undef, $choices) = @_; |
695 |
|
|
return $choices->[0] if $::rpmdrake_options{auto}; |
696 |
|
|
foreach my $pkg (@$choices) { |
697 |
|
|
foreach ($pkg->requires_nosense) { |
698 |
|
|
/locales-/ or next; |
699 |
|
|
is_locale_available($_) and return $pkg; |
700 |
|
|
} |
701 |
|
|
} |
702 |
|
|
my $callback = sub { interactive_msg(N("More information on package..."), get_info($_[0]), scroll => 1) }; |
703 |
|
|
$choices = [ sort { $a->name cmp $b->name } @$choices ]; |
704 |
|
|
my @choices = interactive_list_(N("Please choose"), (scalar(@$choices) == 1 ? |
705 |
|
|
N("The following package is needed:") : N("One of the following packages is needed:")), |
706 |
|
|
[ map { urpm_name($_) } @$choices ], $callback, nocancel => 1); |
707 |
|
|
defined $choices[0] ? $choices->[$choices[0]] : undef; |
708 |
|
|
} |
709 |
|
|
|
710 |
|
|
sub deps_msg { |
711 |
|
|
return 1 if $dont_show_selections->[0]; |
712 |
|
|
my ($title, $msg, $nodes, $nodes_with_deps) = @_; |
713 |
|
|
my @deps = sort { $a cmp $b } difference2($nodes_with_deps, $nodes); |
714 |
|
|
@deps > 0 or return 1; |
715 |
|
|
deps_msg_again: |
716 |
|
|
my $results = interactive_msg( |
717 |
|
|
$title, $msg . |
718 |
|
|
format_list(map { scalar(urpm::select::translate_why_removed_one($urpm, $urpm->{state}, $_)) } @deps) |
719 |
|
|
. "\n\n" . format_size($urpm->selected_size($urpm->{state})), |
720 |
|
|
yesno => [ N("Cancel"), N("More info"), N("Ok") ], |
721 |
|
|
scroll => 1, |
722 |
|
|
); |
723 |
|
|
if ($results eq |
724 |
|
|
#-PO: Keep it short, this is gonna be on a button |
725 |
|
|
N("More info")) { |
726 |
|
|
interactive_packtable( |
727 |
|
|
N("Information on packages"), |
728 |
|
|
$::main_window, |
729 |
|
|
undef, |
730 |
|
|
[ map { my $pkg = $_; |
731 |
|
|
[ gtknew('HBox', children_tight => [ gtkset_selectable(gtknew('Label', text => $pkg), 1) ]), |
732 |
|
|
gtknew('Button', text => N("More information on package..."), |
733 |
|
|
clicked => sub { |
734 |
|
|
interactive_msg(N("More information on package..."), get_info($pkg), scroll => 1); |
735 |
|
|
}) ] } @deps ], |
736 |
|
|
[ gtknew('Button', text => N("Ok"), |
737 |
|
|
clicked => sub { Gtk2->main_quit }) ] |
738 |
|
|
); |
739 |
|
|
goto deps_msg_again; |
740 |
|
|
} else { |
741 |
|
|
return $results eq N("Ok"); |
742 |
|
|
} |
743 |
|
|
} |
744 |
|
|
|
745 |
|
|
sub toggle_nodes { |
746 |
|
|
my ($widget, $model, $set_state, $old_state, @nodes) = @_; |
747 |
|
|
@nodes = grep { exists $pkgs->{$_} } @nodes |
748 |
|
|
or return; |
749 |
|
|
#- avoid selecting too many packages at once |
750 |
|
|
return if !$dont_show_selections->[0] && @nodes > 2000; |
751 |
|
|
my $new_state = !$pkgs->{$nodes[0]}{selected}; |
752 |
|
|
|
753 |
|
|
my @nodes_with_deps; |
754 |
|
|
|
755 |
|
|
my $bar_id = statusbar_msg(N("Checking dependencies of package..."), 0); |
756 |
|
|
|
757 |
|
|
my $warn_about_additional_packages_to_remove = sub { |
758 |
|
|
my ($msg) = @_; |
759 |
|
|
statusbar_msg_remove($bar_id); |
760 |
|
|
deps_msg(N("Some additional packages need to be removed"), |
761 |
|
|
formatAlaTeX($msg) . "\n\n", |
762 |
|
|
\@nodes, \@nodes_with_deps) or @nodes_with_deps = (); |
763 |
|
|
}; |
764 |
|
|
|
765 |
|
|
if (member($old_state, qw(to_remove installed))) { # remove pacckages |
766 |
|
|
if ($new_state) { |
767 |
|
|
my @remove; |
768 |
|
|
slow_func($widget, sub { @remove = closure_removal(@nodes) }); |
769 |
|
|
@nodes_with_deps = grep { !$pkgs->{$_}{selected} && !/^basesystem/ } @remove; |
770 |
|
|
$warn_about_additional_packages_to_remove->( |
771 |
|
|
N("Because of their dependencies, the following package(s) also need to be removed:")); |
772 |
|
|
my @impossible_to_remove; |
773 |
|
|
foreach (grep { exists $pkgs->{$_}{base} } @remove) { |
774 |
|
|
${$pkgs->{$_}{base}} == 1 ? push @impossible_to_remove, $_ : ${$pkgs->{$_}{base}}--; |
775 |
|
|
} |
776 |
tv |
2028 |
@impossible_to_remove and interactive_msg(N("Some packages cannot be removed"), |
777 |
dmorgan |
535 |
N("Removing these packages would break your system, sorry:\n\n") . |
778 |
|
|
format_list(@impossible_to_remove)); |
779 |
|
|
@nodes_with_deps = difference2(\@nodes_with_deps, \@impossible_to_remove); |
780 |
|
|
} else { |
781 |
|
|
slow_func($widget, |
782 |
|
|
sub { @nodes_with_deps = grep { intersection(\@nodes, [ closure_removal($_) ]) } |
783 |
|
|
grep { $pkgs->{$_}{selected} && !member($_, @nodes) } keys %$pkgs }); |
784 |
|
|
push @nodes_with_deps, @nodes; |
785 |
|
|
$warn_about_additional_packages_to_remove->( |
786 |
|
|
N("Because of their dependencies, the following package(s) must be unselected now:\n\n")); |
787 |
|
|
$pkgs->{$_}{base} && ${$pkgs->{$_}{base}}++ foreach @nodes_with_deps; |
788 |
|
|
} |
789 |
|
|
} else { |
790 |
|
|
if ($new_state) { |
791 |
|
|
if (@nodes > 1) { |
792 |
|
|
#- unselect i18n packages of which locales is not already present (happens when user clicks on KDE group) |
793 |
|
|
my @bad_i18n_pkgs; |
794 |
|
|
foreach my $sel (@nodes) { |
795 |
|
|
foreach ($pkgs->{$sel}{pkg}->requires_nosense) { |
796 |
|
|
/locales-([^-]+)/ or next; |
797 |
|
|
$sel =~ /-$1[-_]/ && !is_locale_available($_) and push @bad_i18n_pkgs, $sel; |
798 |
|
|
} |
799 |
|
|
} |
800 |
|
|
@nodes = difference2(\@nodes, \@bad_i18n_pkgs); |
801 |
|
|
} |
802 |
|
|
my @requested; |
803 |
|
|
slow_func( |
804 |
|
|
$widget, |
805 |
|
|
sub { |
806 |
|
|
@requested = $urpm->resolve_requested( |
807 |
|
|
open_rpm_db(), $urpm->{state}, |
808 |
|
|
{ map { $pkgs->{$_}{pkg}->id => 1 } @nodes }, |
809 |
|
|
callback_choices => \&callback_choices, |
810 |
|
|
); |
811 |
|
|
}, |
812 |
|
|
); |
813 |
|
|
@nodes_with_deps = map { urpm_name($_) } @requested; |
814 |
|
|
statusbar_msg_remove($bar_id); |
815 |
|
|
if (!deps_msg(N("Additional packages needed"), |
816 |
|
|
formatAlaTeX(N("To satisfy dependencies, the following package(s) also need to be installed:\n\n")) . "\n\n", |
817 |
|
|
\@nodes, \@nodes_with_deps)) { |
818 |
|
|
@nodes_with_deps = (); |
819 |
|
|
$urpm->disable_selected(open_rpm_db(), $urpm->{state}, @requested); |
820 |
|
|
goto packages_selection_ok; |
821 |
|
|
} |
822 |
|
|
|
823 |
|
|
if (my $conflicting_msg = urpm::select::conflicting_packages_msg($urpm, $urpm->{state})) { |
824 |
|
|
if (!interactive_msg(N("Conflicting Packages"), $conflicting_msg, yesno => 1, scroll => 1)) { |
825 |
|
|
@nodes_with_deps = (); |
826 |
|
|
$urpm->disable_selected(open_rpm_db(), $urpm->{state}, @requested); |
827 |
|
|
goto packages_selection_ok; |
828 |
|
|
} |
829 |
|
|
} |
830 |
|
|
|
831 |
|
|
if (my @cant = sort(difference2(\@nodes, \@nodes_with_deps))) { |
832 |
tv |
5493 |
my @ask_unselect = urpm::select::unselected_packages($urpm->{state}); |
833 |
dmorgan |
535 |
my @reasons = map { |
834 |
|
|
my $cant = $_; |
835 |
|
|
my $unsel = find { $_ eq $cant } @ask_unselect; |
836 |
|
|
$unsel |
837 |
|
|
? join("\n", urpm::select::translate_why_unselected($urpm, $urpm->{state}, $unsel)) |
838 |
|
|
: ($pkgs->{$_}{pkg}->flag_skip ? N("%s (belongs to the skip list)", $cant) : $cant); |
839 |
|
|
} @cant; |
840 |
|
|
my $count = @reasons; |
841 |
|
|
interactive_msg( |
842 |
tv |
6102 |
($count == 1 ? N("One package cannot be installed") : N("Some packages cannot be installed")), |
843 |
dmorgan |
535 |
($count == 1 ? |
844 |
|
|
N("Sorry, the following package cannot be selected:\n\n%s", format_list(@reasons)) |
845 |
misc |
1124 |
: N("Sorry, the following packages cannot be selected:\n\n%s", format_list(@reasons))), |
846 |
dmorgan |
535 |
scroll => 1, |
847 |
|
|
); |
848 |
|
|
foreach (@cant) { |
849 |
|
|
next unless $pkgs->{$_}{pkg}; |
850 |
|
|
$pkgs->{$_}{pkg}->set_flag_requested(0); |
851 |
|
|
$pkgs->{$_}{pkg}->set_flag_required(0); |
852 |
|
|
} |
853 |
|
|
} |
854 |
|
|
packages_selection_ok: |
855 |
|
|
} else { |
856 |
|
|
my @unrequested; |
857 |
|
|
slow_func($widget, |
858 |
|
|
sub { @unrequested = $urpm->disable_selected(open_rpm_db(), $urpm->{state}, |
859 |
|
|
map { $pkgs->{$_}{pkg} } @nodes) }); |
860 |
|
|
@nodes_with_deps = map { urpm_name($_) } @unrequested; |
861 |
|
|
statusbar_msg_remove($bar_id); |
862 |
|
|
if (!deps_msg(N("Some packages need to be removed"), |
863 |
|
|
N("Because of their dependencies, the following package(s) must be unselected now:\n\n"), |
864 |
|
|
\@nodes, \@nodes_with_deps)) { |
865 |
|
|
@nodes_with_deps = (); |
866 |
|
|
$urpm->resolve_requested(open_rpm_db(), $urpm->{state}, { map { $_->id => 1 } @unrequested }); |
867 |
|
|
goto packages_unselection_ok; |
868 |
|
|
} |
869 |
|
|
packages_unselection_ok: |
870 |
|
|
} |
871 |
|
|
} |
872 |
|
|
|
873 |
|
|
foreach (@nodes_with_deps) { |
874 |
|
|
#- some deps may exist on some packages which aren't listed because |
875 |
|
|
#- not upgradable (older than what currently installed) |
876 |
|
|
exists $pkgs->{$_} or next; |
877 |
|
|
if (!$pkgs->{$_}{pkg}) { #- can't be removed # FIXME; what about next packages in the loop? |
878 |
tv |
6096 |
undef $pkgs->{$_}{selected}; |
879 |
dmorgan |
535 |
log::explanations("can't be removed: $_"); |
880 |
|
|
} else { |
881 |
|
|
$pkgs->{$_}{selected} = $new_state; |
882 |
|
|
} |
883 |
|
|
$set_state->($_, node_state($_), $model); |
884 |
|
|
if (my $pkg = $pkgs->{$_}{pkg}) { |
885 |
|
|
# FIXME: shouldn't we threat all of them as POSITIVE (as selected size) |
886 |
|
|
$size_selected += $pkg->size * ($pkg->flag_installed && !$pkg->flag_upgrade ? ($new_state ? -1 : 1) : ($new_state ? 1 : -1)); |
887 |
|
|
} |
888 |
|
|
} |
889 |
|
|
} |
890 |
|
|
|
891 |
|
|
sub is_there_selected_packages() { |
892 |
|
|
int(grep { $pkgs->{$_}{selected} } keys %$pkgs); |
893 |
|
|
} |
894 |
|
|
|
895 |
|
|
sub real_quit() { |
896 |
|
|
if (is_there_selected_packages()) { |
897 |
|
|
interactive_msg(N("Some packages are selected."), N("Some packages are selected.") . "\n" . N("Do you really want to quit?"), yesno => 1) or return; |
898 |
|
|
} |
899 |
|
|
Gtk2->main_quit; |
900 |
|
|
} |
901 |
|
|
|
902 |
|
|
sub do_action__real { |
903 |
|
|
my ($options, $callback_action, $o_info) = @_; |
904 |
|
|
require urpm::sys; |
905 |
|
|
if (!urpm::sys::check_fs_writable()) { |
906 |
|
|
$urpm->{fatal}(1, N("Error: %s appears to be mounted read-only.", $urpm::sys::mountpoint)); |
907 |
|
|
return 1; |
908 |
|
|
} |
909 |
|
|
if (!$Rpmdrake::pkg::need_restart && !is_there_selected_packages()) { |
910 |
|
|
interactive_msg(N("You need to select some packages first."), N("You need to select some packages first.")); |
911 |
|
|
return 1; |
912 |
|
|
} |
913 |
|
|
my $size_added = sum(map { if_($_->flag_selected && !$_->flag_installed, $_->size) } @{$urpm->{depslist}}); |
914 |
|
|
if ($MODE eq 'install' && $size_free - $size_added/1024 < 50*1024) { |
915 |
|
|
interactive_msg(N("Too many packages are selected"), |
916 |
misc |
1124 |
N("Warning: it seems that you are attempting to add so many |
917 |
dmorgan |
535 |
packages that your filesystem may run out of free diskspace, |
918 |
|
|
during or after package installation ; this is particularly |
919 |
|
|
dangerous and should be considered with care. |
920 |
|
|
|
921 |
|
|
Do you really want to install all the selected packages?"), yesno => 1) |
922 |
|
|
or return 1; |
923 |
|
|
} |
924 |
|
|
my $res = $callback_action->($urpm, $pkgs); |
925 |
|
|
if (!$res) { |
926 |
|
|
$force_rebuild = 1; |
927 |
tv |
3837 |
pkgs_provider($options->{tree_mode}, if_($Rpmdrake::pkg::probe_only_for_updates, pure_updates => 1), skip_updating_mu => 1); |
928 |
dmorgan |
535 |
reset_search(); |
929 |
|
|
$size_selected = 0; |
930 |
|
|
(undef, $size_free) = MDK::Common::System::df('/usr'); |
931 |
|
|
$options->{rebuild_tree}->() if $options->{rebuild_tree}; |
932 |
|
|
gtktext_insert($o_info, '') if $o_info; |
933 |
|
|
} |
934 |
|
|
$res; |
935 |
|
|
} |
936 |
|
|
|
937 |
|
|
sub do_action { |
938 |
|
|
my ($options, $callback_action, $o_info) = @_; |
939 |
|
|
my $res = eval { do_action__real($options, $callback_action, $o_info) }; |
940 |
|
|
my $err = $@; |
941 |
|
|
# FIXME: offer to report the problem into bugzilla: |
942 |
|
|
if ($err && $err !~ /cancel_perform/) { |
943 |
|
|
interactive_msg(N("Fatal error"), |
944 |
|
|
N("A fatal error occurred: %s.", $err)); |
945 |
|
|
} |
946 |
|
|
$res; |
947 |
|
|
} |
948 |
|
|
|
949 |
|
|
sub translate_group { |
950 |
|
|
join('/', map { translate($_) } split m|/|, $_[0]); |
951 |
|
|
} |
952 |
|
|
|
953 |
|
|
sub ctreefy { |
954 |
|
|
join('|', map { translate($_) } split m|/|, $_[0]); |
955 |
|
|
} |
956 |
|
|
|
957 |
|
|
sub _build_tree { |
958 |
|
|
my ($elems, @elems) = @_; |
959 |
|
|
#- we populate all the groups tree at first |
960 |
|
|
%$elems = (); |
961 |
|
|
# better loop on packages, create groups tree and push packages in the proper place: |
962 |
|
|
foreach my $pkg (@elems) { |
963 |
|
|
my $grp = $pkg->[1]; |
964 |
tv |
3873 |
# no state for groups (they're not packages and thus have no state) |
965 |
|
|
add_parent($grp, undef); |
966 |
dmorgan |
535 |
$elems->{$grp} ||= []; |
967 |
|
|
push @{$elems->{$grp}}, $pkg; |
968 |
|
|
} |
969 |
|
|
} |
970 |
|
|
|
971 |
|
|
|
972 |
|
|
sub build_tree { |
973 |
|
|
my ($tree, $tree_model, $elems, $options, $force_rebuild, $flat, $mode) = @_; |
974 |
|
|
state $old_mode; |
975 |
|
|
$mode = $options->{rmodes}{$mode} || $mode; |
976 |
|
|
return if $old_mode eq $mode && !$force_rebuild; |
977 |
|
|
$old_mode = $mode; |
978 |
|
|
undef $force_rebuild; |
979 |
|
|
my @elems; |
980 |
|
|
my $wait; $wait = statusbar_msg(N("Please wait, listing packages...")) if $MODE ne 'update'; |
981 |
|
|
gtkflush(); |
982 |
|
|
{ |
983 |
|
|
my @keys = @filtered_pkgs; |
984 |
|
|
if (member($mode, qw(all_updates security bugfix normal))) { |
985 |
|
|
@keys = grep { |
986 |
|
|
my ($name) = split_fullname($_); |
987 |
|
|
member($descriptions->{$name}{importance}, @$mandrakeupdate_wanted_categories) |
988 |
|
|
|| ! $descriptions->{$name}{importance}; |
989 |
|
|
} @keys; |
990 |
|
|
if (@keys == 0) { |
991 |
|
|
add_node('', N("(none)"), { nochild => 1 }); |
992 |
|
|
state $explanation_only_once; |
993 |
|
|
$explanation_only_once or interactive_msg(N("No update"), |
994 |
|
|
N("The list of updates is empty. This means that either there is |
995 |
|
|
no available update for the packages installed on your computer, |
996 |
|
|
or you already installed all of them.")); |
997 |
|
|
$explanation_only_once = 1; |
998 |
|
|
} |
999 |
|
|
} |
1000 |
tv |
2977 |
# FIXME: better do this on first group access for faster startup... |
1001 |
|
|
@elems = map { [ $_, !$flat && ctreefy($pkgs->{$_}{pkg}->group) ] } sort_packages(@keys); |
1002 |
dmorgan |
535 |
} |
1003 |
|
|
my %sortmethods = ( |
1004 |
|
|
by_size => sub { sort { $pkgs->{$b->[0]}{pkg}->size <=> $pkgs->{$a->[0]}{pkg}->size } @_ }, |
1005 |
|
|
by_selection => sub { sort { $pkgs->{$b->[0]}{selected} <=> $pkgs->{$a->[0]}{selected} |
1006 |
|
|
|| uc($a->[0]) cmp uc($b->[0]) } @_ }, |
1007 |
|
|
by_leaves => sub { |
1008 |
|
|
# inlining part of MDK::Common::Data::difference2(): |
1009 |
|
|
my %l; @l{map { $_->[0] } @_} = (); |
1010 |
|
|
my @pkgs_times = ('rpm', '-q', '--qf', '%{name}-%{version}-%{release}.%{arch} %{installtime}\n', |
1011 |
|
|
map { chomp_($_) } run_program::get_stdout('urpmi_rpm-find-leaves')); |
1012 |
|
|
sort { $b->[1] <=> $a->[1] } grep { exists $l{$_->[0]} } map { chomp; [ split ] } run_rpm(@pkgs_times); |
1013 |
|
|
}, |
1014 |
|
|
flat => sub { no locale; sort { uc($a->[0]) cmp uc($b->[0]) } @_ }, |
1015 |
|
|
by_medium => sub { sort { $a->[2] <=> $b->[2] || uc($a->[0]) cmp uc($b->[0]) } @_ }, |
1016 |
|
|
); |
1017 |
|
|
if ($flat) { |
1018 |
|
|
add_node($_->[0], '') foreach $sortmethods{$::mode->[0] || 'flat'}->(@elems); |
1019 |
|
|
} else { |
1020 |
|
|
if (0 && $MODE eq 'update') { |
1021 |
|
|
add_node($_->[0], N("All")) foreach $sortmethods{flat}->(@elems); |
1022 |
|
|
$tree->expand_row($tree_model->get_path($tree_model->get_iter_first), 0); |
1023 |
|
|
} elsif ($::mode->[0] eq 'by_source') { |
1024 |
|
|
_build_tree($elems, $sortmethods{by_medium}->(map { |
1025 |
|
|
my $m = pkg2medium($pkgs->{$_->[0]}{pkg}, $urpm); [ $_->[0], $m->{name}, $m->{priority} ]; |
1026 |
|
|
} @elems)); |
1027 |
|
|
} elsif ($::mode->[0] eq 'by_presence') { |
1028 |
|
|
_build_tree($elems, map { |
1029 |
|
|
my $pkg = $pkgs->{$_->[0]}{pkg}; |
1030 |
|
|
[ $_->[0], $pkg->flag_installed ? |
1031 |
|
|
(!$pkg->flag_skip && $pkg->flag_upgrade ? N("Upgradable") : N("Installed")) |
1032 |
|
|
: N("Addable") ]; |
1033 |
|
|
} $sortmethods{flat}->(@elems)); |
1034 |
|
|
} else { |
1035 |
|
|
_build_tree($elems, @elems); |
1036 |
|
|
} |
1037 |
|
|
} |
1038 |
|
|
statusbar_msg_remove($wait) if defined $wait; |
1039 |
|
|
} |
1040 |
|
|
|
1041 |
|
|
sub get_info { |
1042 |
|
|
my ($key, $widget) = @_; |
1043 |
|
|
#- the package information hasn't been loaded. Instead of rescanning the media, just give up. |
1044 |
|
|
exists $pkgs->{$key} or return [ [ N("Description not available for this package\n") ] ]; |
1045 |
|
|
#- get the description if needed: |
1046 |
tv |
5986 |
exists $pkgs->{$key}{description} or slow_func($widget, sub { extract_header($pkgs->{$key}, $urpm, 'info', find_installed_version($pkgs->{$key}{pkg})) }); |
1047 |
dmorgan |
535 |
format_pkg_simplifiedinfo($pkgs, $key, $urpm, $descriptions); |
1048 |
|
|
} |
1049 |
|
|
|
1050 |
|
|
sub sort_callback { |
1051 |
|
|
my ($store, $treeiter1, $treeiter2) = @_; |
1052 |
|
|
URPM::rpmvercmp(map { $store->get_value($_, $pkg_columns{version}) } $treeiter1, $treeiter2); |
1053 |
|
|
} |
1054 |
|
|
|
1055 |
|
|
sub run_help_callback { |
1056 |
|
|
my (undef, $url) = @_; |
1057 |
tv |
2342 |
my ($user) = grep { $_->[2] eq $ENV{USERHELPER_UID} } list_passwd(); |
1058 |
|
|
local $ENV{HOME} = $user->[7] if $user && $ENV{USERHELPER_UID}; |
1059 |
dmorgan |
535 |
run_program::raw({ detach => 1, as_user => 1 }, 'www-browser', $url); |
1060 |
|
|
} |
1061 |
|
|
|
1062 |
|
|
1; |