Re: Directory/file browser as TreeView



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]