aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Rpmdrake/gui.pm270
-rwxr-xr-xrpmdrake1
2 files changed, 271 insertions, 0 deletions
diff --git a/Rpmdrake/gui.pm b/Rpmdrake/gui.pm
new file mode 100644
index 00000000..a7e24ae7
--- /dev/null
+++ b/Rpmdrake/gui.pm
@@ -0,0 +1,270 @@
+package Rpmdrake::gui;
+#*****************************************************************************
+#
+# Copyright (c) 2002 Guillaume Cottenceau
+# Copyright (c) 2002-2007 Thierry Vignaud <tvignaud@mandriva.com>
+# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA
+# Copyright (c) 2005-2007 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$
+
+use strict;
+our @ISA = qw(Exporter);
+use lib qw(/usr/lib/libDrakX);
+
+use common;
+use mygtk2 qw(gtknew); #- do not import gtkadd which conflicts with ugtk2 version
+
+use ugtk2 qw(:helpers :wrappers);
+use Gtk2::Gdk::Keysyms;
+
+our @EXPORT = qw(ask_browse_tree_info_given_widgets_for_rpmdrake);
+
+
+# ask_browse_tree_info_given_widgets will run gtk+ loop. its main parameter "common" is a hash containing:
+# - a "widgets" subhash which holds:
+# o a "w" reference on a ugtk2 object
+# o "tree" & "info" references a TreeView
+# o "info" is a TextView
+# o "tree_model" is the associated model of "tree"
+# o "status" references a Label
+# - some methods: get_info, node_state, build_tree, grep_allowed_to_toggle, partialsel_unsel, grep_unselected, rebuild_tree, toggle_nodes, check_interactive_to_toggle, get_status
+# - "tree_submode": the default mode (by group, mandriva choice), ...
+# - "state": a hash of misc flags: => { flat => '0' },
+# o "flat": is the tree flat or not
+# - "tree_mode": mode of the tree ("mandrake_choices", "by_group", ...) (mainly used by rpmdrake)
+
+sub ask_browse_tree_info_given_widgets_for_rpmdrake {
+ my ($common) = @_;
+ my $w = $common->{widgets};
+
+ $w->{detail_list} ||= $w->{tree};
+ $w->{detail_list_model} ||= $w->{tree_model};
+
+ my ($prev_label);
+ my (%wtree, %ptree, %pix, %node_state, %state_stats);
+ my $update_size = sub {
+ if ($w->{status}) {
+ my $new_label = $common->{get_status}();
+ $prev_label ne $new_label and $w->{status}->set($prev_label = $new_label);
+ }
+ };
+
+ my $set_node_state_flat = sub {
+ my ($iter, $state, $model) = @_;
+ $state eq 'XXX' and return;
+ $pix{$state} ||= gtkcreate_pixbuf($state);
+ $model ||= $w->{tree_model};
+ $model->set($iter, 1 => $pix{$state});
+ $model->set($iter, 2 => $state);
+ };
+ my $set_node_state_tree; $set_node_state_tree = sub {
+ my ($iter, $state, $model) = @_;
+ $model ||= $w->{tree_model};
+ my $iter_str = $model->get_path_str($iter);
+ ($state eq 'XXX' || !$state) and return;
+ $pix{$state} ||= gtkcreate_pixbuf('state_' . $state);
+ if ($node_state{$iter_str} ne $state) {
+ my $parent;
+ if (!$model->iter_has_child($iter) && ($parent = $model->iter_parent($iter))) {
+ my $parent_str = $model->get_path_str($parent);
+ my $stats = $state_stats{$parent_str} ||= {}; $stats->{$node_state{$iter_str}}--; $stats->{$state}++;
+ my @list = grep { $stats->{$_} > 0 } keys %$stats;
+ my $new_state = @list == 1 ? $list[0] : 'semiselected';
+ $node_state{$parent_str} ne $new_state and
+ $set_node_state_tree->($parent, $new_state);
+ }
+ $model->set($iter, 1 => $pix{$state});
+ $model->set($iter, 2 => $state);
+ #$node_state{$iter_str} = $state; #- cache for efficiency
+ } else {
+ }
+ };
+ my $set_node_state =
+ $common->{state}{splited} || $common->{state}{flat} ? $set_node_state_flat : $set_node_state_tree;
+
+ my $set_leaf_state = sub {
+ my ($leaf, $state, $model) = @_;
+ $set_node_state->($_, $state, $model) foreach @{$ptree{$leaf}};
+ };
+ my $add_parent; $add_parent = sub {
+ my ($root, $state) = @_;
+ $root or return undef;
+ if (my $w = $wtree{$root}) { return $w }
+ my $s; foreach (split '\|', $root) {
+ my $s2 = $s ? "$s|$_" : $_;
+ $wtree{$s2} ||= do {
+ my $pixbuf = $common->{get_icon}->($s2, $s);
+ my $iter = $w->{tree_model}->append_set($s ? $add_parent->($s, $state, $common->{get_icon}->($s)) : undef, [ 0 => $_, if_($pixbuf, 2 => $pixbuf) ]);
+ $iter;
+ };
+ $s = $s2;
+ }
+ $set_node_state->($wtree{$s}, $state); #- use this state by default as tree is building.
+ $wtree{$s};
+ };
+ $common->{add_parent} = $add_parent;
+ my $add_node = sub {
+ my ($leaf, $root, $options) = @_;
+ my $state = $common->{node_state}($leaf) or return;
+ if ($leaf) {
+ my $iter;
+ if ($common->{is_a_package}->($leaf)) {
+ $iter = $w->{detail_list_model}->append_set([ 0 => $leaf ]);
+ $set_node_state->($iter, $state, $w->{detail_list_model});
+ } else {
+ $iter = $w->{tree_model}->append_set($add_parent->($root, $state), [ 0 => $leaf ]);
+ }
+ push @{$ptree{$leaf}}, $iter;
+ } else {
+ my $parent = $add_parent->($root, $state);
+ #- hackery for partial displaying of trees, used in rpmdrake:
+ #- if leaf is void, we may create the parent and one child (to have the [+] in front of the parent in the ctree)
+ #- though we use '' as the label of the child; then rpmdrake will connect on tree_expand, and whenever
+ #- the first child has '' as the label, it will remove the child and add all the "right" children
+ $options->{nochild} or $w->{tree_model}->append_set($parent, [ 0 => '' ]); # test $leaf?
+ }
+ };
+ my $clear_all_caches = sub {
+ foreach (values %ptree) {
+ foreach my $n (@$_) {
+ delete $node_state{$w->{detail_list_model}->get_path_str($n)};
+ }
+ }
+ foreach (values %wtree) {
+ foreach my $model ($w->{tree_model}) {
+ my $iter_str = $model->get_path_str($_);
+ delete $node_state{$iter_str};
+ delete $state_stats{$iter_str};
+ }
+ }
+ %ptree = %wtree = ();
+ };
+ $common->{delete_all} = sub {
+ $clear_all_caches->();
+ $w->{detail_list_model}->clear;
+ $w->{tree_model}->clear;
+ };
+ $common->{rebuild_tree} = sub {
+ $common->{delete_all}->();
+ $set_node_state = $common->{state}{flat} ? $set_node_state_flat : $set_node_state_tree;
+ $common->{build_tree}($add_node, $common->{state}{flat}, $common->{tree_mode});
+ &$update_size;
+ };
+ $common->{delete_category} = sub {
+ my ($cat) = @_;
+ exists $wtree{$cat} or return;
+ foreach (keys %ptree) {
+ my @to_remove;
+ foreach my $node (@{$ptree{$_}}) {
+ my $category;
+ my $parent = $node;
+ my @parents;
+ while ($parent = $w->{tree_model}->iter_parent($parent)) { #- LEAKS
+ my $parent_name = $w->{tree_model}->get($parent, 0);
+ $category = $category ? "$parent_name|$category" : $parent_name;
+ $_->[1] = "$parent_name|$_->[1]" foreach @parents;
+ push @parents, [ $parent, $category ];
+ }
+ if ($category =~ /^\Q$cat/) {
+ push @to_remove, $node;
+ foreach (@parents) {
+ next if $_->[1] eq $cat || !exists $wtree{$_->[1]};
+ delete $wtree{$_->[1]};
+ delete $node_state{$w->{tree_model}->get_path_str($_->[0])};
+ delete $state_stats{$w->{tree_model}->get_path_str($_->[0])};
+ }
+ }
+ }
+ foreach (@to_remove) {
+ delete $node_state{$w->{tree_model}->get_path_str($_)};
+ }
+ @{$ptree{$_}} = difference2($ptree{$_}, \@to_remove);
+ }
+ if (exists $wtree{$cat}) {
+ my $iter_str = $w->{tree_model}->get_path_str($wtree{$cat});
+ delete $node_state{$iter_str};
+ delete $state_stats{$iter_str};
+ $w->{tree_model}->remove($wtree{$cat});
+ delete $wtree{$cat};
+ }
+ &$update_size;
+ };
+ $common->{add_nodes} = sub {
+ my (@nodes) = @_;
+ $w->{detail_list_model}->clear;
+ $w->{detail_list}->scroll_to_point(0, 0);
+ $add_node->($_->[0], $_->[1], $_->[2]) foreach @nodes;
+ &$update_size;
+ };
+
+ $common->{display_info} = sub {
+ gtktext_insert($w->{info}, $common->{get_info}($_[0]));
+ $w->{info}->scroll_to_iter($w->{info}->get_buffer->get_start_iter, 0, 0, 0, 0);
+ 0;
+ };
+ my $children = sub { map { $w->{detail_list_model}->get($_, 0) } gtktreeview_children($w->{detail_list_model}, $_[0]) };
+ $common->{toggle_all} = sub {
+ my ($_val) = @_;
+ my @l = $common->{grep_allowed_to_toggle}($children->()) or return;
+
+ my @unsel = $common->{grep_unselected}(@l);
+ my @p = @unsel ?
+ #- not all is selected, select all if no option to potentially override
+ (exists $common->{partialsel_unsel} && $common->{partialsel_unsel}->(\@unsel, \@l) ? difference2(\@l, \@unsel) : @unsel)
+ : @l;
+ $common->{toggle_nodes}($set_leaf_state, undef, @p);
+ &$update_size;
+ };
+ my $fast_toggle = sub {
+ my ($iter) = @_;
+ gtkset_mousecursor_wait($w->{w}{rwindow}->window);
+ $common->{check_interactive_to_toggle}($iter) and $common->{toggle_nodes}($set_leaf_state, $w->{detail_list_model}->get($iter, 2), $w->{detail_list_model}->get($iter, 0));
+ &$update_size;
+ gtkset_mousecursor_normal($w->{w}{rwindow}->window);
+ };
+ $w->{detail_list}->get_selection->signal_connect(changed => sub {
+ my ($model, $iter) = $_[0]->get_selected;
+ $model && $iter or return;
+ $common->{display_info}($model->get($iter, 0));
+ });
+ $w->{detail_list}->signal_connect(button_press_event => sub { #- not too good, but CellRendererPixbuf does not have the needed signals :(
+ my ($path, $column) = $w->{detail_list}->get_path_at_pos($_[1]->x, $_[1]->y);
+ if ($path && $column && $column->{is_pix}) {
+ my $iter = $w->{detail_list_model}->get_iter($path);
+ $fast_toggle->($iter) if $iter;
+ }
+ 0;
+ });
+ $w->{detail_list}->signal_connect(key_press_event => sub {
+ my $c = chr($_[1]->keyval & 0xff);
+ if ($_[1]->keyval >= 0x100 ? $c eq "\r" || $c eq "\x8d" : $c eq ' ') {
+ my ($model, $iter) = $w->{detail_list}->get_selection->get_selected;
+ $fast_toggle->($iter) if $model && $iter;
+ }
+ 0;
+ });
+ $common->{rebuild_tree}->();
+ &$update_size;
+ $common->{initial_selection} and $common->{toggle_nodes}($set_leaf_state, undef, @{$common->{initial_selection}});
+ #my $_b = before_leaving { $clear_all_caches->() };
+ $common->{init_callback}->() if $common->{init_callback};
+ $w->{w}->main;
+}
+
+1;
diff --git a/rpmdrake b/rpmdrake
index 7304214f..2667b0f3 100755
--- a/rpmdrake
+++ b/rpmdrake
@@ -34,6 +34,7 @@ use standalone;
use Rpmdrake::init;
use rpmdrake;
+use Rpmdrake::gui;
use Rpmdrake::rpmnew;
use Rpmdrake::formatting;
use Rpmdrake::pkg;