Re: Directory/file browser as TreeView
- From: zentara <zentara1 sbcglobal net>
- To: "Ratcliffe, Jeffrey (Peters)" <Jeffrey Ratcliffe External eads com>
- Cc: gtk-perl-list gnome org
- Subject: Re: Directory/file browser as TreeView
- Date: Thu, 28 Sep 2006 14:59:17 -0400
On Thu, 28 Sep 2006 15:49:20 +0200
"Ratcliffe, Jeffrey (Peters)" <Jeffrey Ratcliffe External eads com> wrote:
OK. I realised that fully populating the subdirectories to show the arrow might be slow. Here is a version
that just looks far enough ahead to see whether there is a subdirectory there and puts a dummy child in the
tree, only filling it fully when required.
As you will see from the debugging messages I have put in, the tree is being properly populated. But for
reasons I don't understand, you can't expand the tree.
Any ideas?
Hi again, this was as far as I got with my "dummy" insertion
method. It seems to work, but still suffers from some slow loading.
See below.
However, I did some testing with rebooting in between, and I was unfair
with my speed comparisons, since I always did my Tk test second. :-)
As Joe Smith said:
"As for speeding up access to large directories, it is well known that
such directory operations are much much faster on the second pass, once
the OS has cached all the inodes in memory. "
So with the rebooting in between tests, to absolutely clear the cache,
the times came more inline with each other, but Tk canvas was slightly
faster for me.
#################################################
My dummy insertion attempt, run from /
It's been about 6 months since I worked on this, so it
the details are fading from my active memory. :-)
#!/usr/bin/perl
use warnings;
use strict;
use Gtk2 '-init';
use Glib qw/TRUE FALSE/;
use File::Spec;
#Gtk2::Rc->parse_string(<<__);
#
#style "default" {
#font_name ="sans bold 14"
#}
#__
my $window = Gtk2::Window->new('toplevel');
$window->signal_connect('delete_event' => sub { Gtk2->main_quit; });
$window->set_border_width(5);
$window->set_default_size(600,400);
my $vbox = Gtk2::VBox->new(0,1);
my $hbox = Gtk2::HBox->new(0,5);
#these vboxs will return the bulk of the gui
my ($tbox, $tree_view, $treestore) = &ret_tree(); #the dir selector
$hbox->pack_start($tbox,0,0,0);
my ($zbox,$text,$buffer) = &ret_text1(); # display box
$hbox->pack_start($zbox,1,1,1);
$vbox->pack_start($hbox,1,1,0);
#add and show the vbox
$window->add($vbox);
$window->show_all();
&make_trunk('.');
#our main event-loop
Gtk2->main();
###################################################################
sub ret_tree {
my $vbox = Gtk2::VBox->new(FALSE,5);
#create a scrolled window that will host the treeview
my $sw = Gtk2::ScrolledWindow->new (undef, undef);
$sw->set_shadow_type ('etched-out');
$sw->set_policy ('automatic','always');
$sw->set_placement('top-right');
$sw->set_size_request (200, 300);
$sw->set_border_width(0);
my $treestore = Gtk2::TreeStore->new(qw/Glib::String/);
my $tree_view = Gtk2::TreeView->new($treestore);
my $tree_column = Gtk2::TreeViewColumn->new();
$tree_column->set_title('Select');
my $renderer = Gtk2::CellRendererText->new;
$tree_column->pack_start ($renderer, FALSE);
$tree_column->add_attribute($renderer, text => 0);
$tree_view->append_column ($tree_column);
$tree_view->set('headers-visible' => 0);
$sw->add($tree_view);
$tree_view->get_selection->signal_connect(
changed =>\&cell_selected,$treestore );
$tree_view->signal_connect(
row_expanded => \&add_subdirs );
$vbox->pack_start($sw,1,1,0);
$vbox->show_all();
return ($vbox, $tree_view, $treestore);
}
######################################################################
sub ret_text1{
my $vbox = Gtk2::VBox->new(TRUE,5);
my $sw = Gtk2::ScrolledWindow->new (undef, undef);
$sw->set_shadow_type ('etched-out');
$sw->set_policy ('always', 'always');
$sw->set_placement('top-right');
$sw->set_size_request (300, 300);
$sw->set_border_width(0);
my $tview = Gtk2::TextView->new();
my $buffer = $tview->get_buffer();
$sw->add($tview);
$vbox->pack_start($sw,TRUE,TRUE,0);
$vbox->show_all();
return ($vbox,$tview,$buffer);
}
######################################################################
sub cell_selected{
my ($tree_selection, $model ) = @_ ;
my $sel = $tree_selection->get_selected_rows;
my $value='';
if( defined $sel ){
my $path = $sel->to_string;
my @path_ele = split /:/, $path;
#reconstruct filesystem path from model path
while( @path_ele ){
$path = join ':', @path_ele;
#print "path $path\n";
my $iter = $model->get_iter_from_string($path);
my $val = $model->get($iter,0);
$value = $val.'/'.$value;
pop @path_ele;
}
}
print "$value\n";
return FALSE;
}
##################################################################
sub get_subdirs{
my ($dir) = @_;
my @subdirs;
opendir my $dh, $dir or warn $!;
while ( my $file = readdir($dh) ) {
next if $file =~ m[^\.{1,2}$];
if(-d "$dir/$file"){
push @subdirs, $file;
}else{ next }
}
return @subdirs;
}
###########################################################
sub check_depth_2{
my ($abs_path) = @_;
my $put_ind = 0;
opendir my $dh, $abs_path or warn $!;
while ( my $file = readdir($dh) ) {
next if $file =~ m[^\.{1,2}$];
if(-d "$abs_path/$file"){
$put_ind = 1;
last;
}
}
return $put_ind;
}
#############################################################
sub make_trunk{
my $dir = shift;
my $abs_root = File::Spec->rel2abs( $dir );
#for windows compat
$abs_root =~ tr#\\#/#;
#handle special case when toplevel is / or C:/, D:/, etc
if($abs_root eq '/'){$abs_root = ''}
#for windows compat
if ( $abs_root =~ m#^([ABCDEFGHIJKLMNOPQRSTUVWXYZ])\:\/$# )
{$abs_root = "$1:"}
my @subdirs = get_subdirs($dir);
foreach my $subdir ( sort @subdirs ){
my $abs_path = "$abs_root/$subdir";
#see if any depth 2 subdir exists
my $put_ind = &check_depth_2($abs_path);
my $iter = $treestore->append(undef);
$treestore->set ($iter,0 => $subdir);
if($put_ind){ add_dummy($iter) }
}
} # end make_trunk
############################################################################
sub add_dummy{
my $iter = shift;
my $iter_child = $treestore->append($iter);
$treestore->set ($iter_child, 0 => '1' );
}
#############################################################################
sub add_subdirs{
my ($treeview, $iter, $path) = @_;
$tree_view->window->set_cursor( Gtk2::Gdk::Cursor->new('watch') );
#clean out old values
&del_subdirs(@_);
my $dir_in = '';
#reconstruct filesystem path from model path
my @path_ele = $path->get_indices;
while( @path_ele ){
my $path1 = join ':', @path_ele;
my $iter = $treestore->get_iter_from_string($path1);
my $val = $treestore->get($iter,0);
$dir_in = $val.'/'.$dir_in;
pop @path_ele;
}
my $abs_root = File::Spec->rel2abs( $dir_in );
#for windows compat
$abs_root =~ tr#\\#/#;
#handle special case when toplevel is / or C:/, D:/, etc
if($abs_root eq '/'){$abs_root = ''}
#for windows compat
if ( $abs_root =~ m#^([ABCDEFGHIJKLMNOPQRSTUVWXYZ])\:\/$# )
{$abs_root = "$1:"}
my @subdirs = get_subdirs( $dir_in );
my $dummy = $treestore->iter_nth_child ($iter, 0);
foreach my $subd (sort @subdirs){
my $abs_path = "$abs_root/$subd";
#see if any depth 2 subdir exists
my $put_ind = &check_depth_2($abs_path);
my $iter_child = $treestore->append($iter);
$treestore->set($iter_child, 0 => $subd );
if($put_ind){ add_dummy($iter_child) }
}
$treestore->remove($dummy);
$tree_view->window->set_cursor (undef);
}
##############################################################################
sub del_subdirs{
my ($treeview, $iter, $path) = @_;
my $num_childs = $treestore->iter_n_children($iter);
my $treeiter = $treestore->iter_children($iter);
my $iter1 = $treestore->iter_next($treeiter);
while(defined $iter1){
$treestore->remove($iter1);
$iter1 = $treestore->iter_next($treeiter);
my $num_childs = $treestore->iter_n_children($iter);
}
return 1;
}
##########################################################################
__END__
--
I'm not really a human, but I play one on earth.
http://zentara.net/japh.html
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]