I am looking for a way to display large tree structure - 60-70,000
nodes
resulting from parsing source code for an OO language. I tried Tk
widget
in the best but it would choke. I know it can be done in VB but I was
curious
if there are any GUI toolkits in Perl capable of doing it.
At the beginning I would like the tree nodes to be all collapsed and I
would
like to be able to do regexp searh for a node that would result in
expansion
of intermediate nodes. Essentially I need a source code browser for
a proprietary (Java like) language.
TIA for any pointers/info/references,
JT
Gtk2 will probably handle it better than Tk. Try this, pulled from some
maillist. The Perl code can be converted to c for more speed.
Or google for "Gtk2 xmlviewer" for other Perl viewers.
#!/usr/bin/perl
use strict;
use warnings;
use constant TRUE => 1;
use constant FALSE => !TRUE;
use Gtk2 -init;
use XML::Simple;
# Read the xml file into a hash using the XML::Simplemodule
my $tree_xml_file = 'tree-from-xml-data.xml'; # or use shift
my $data_tree = XMLin( $tree_xml_file, forcearray => 1 );
# Define the columns in the order to be seen
my $all_columns = [
{ ColumnName => 'Name' },
{ ColumnName => 'Color' },
{ ColumnName => 'Price' },
{ ColumnName => 'Taste' },
{ ColumnName => 'Source' }
];
# Let us choose to freeze the first column
my $frozen_columns = [ $all_columns->[ 0 ] ];
# Create two arrays for sending into the Gtk2::TreeStore->new method
my @tree_store_full_types =
map { 'Glib::String' } @$all_columns;
my @tree_store_frozen_types = map { 'Glib::String' } @$frozen_columns;
# Create the 'full' tree on the right side pane
my $tree_store_full = Gtk2::TreeStore->new( @tree_store_full_types );
my $tree_view_full = Gtk2::TreeView->new( $tree_store_full );
my $column_count = 0;
for my $column ( @$all_columns ) {
my $column_name = $column->{ ColumnName };
my $column = Gtk2::TreeViewColumn->new_with_attributes(
$column_name,
Gtk2::CellRendererText->new(),
text => $column_count
);
$column->set_resizable( TRUE );
$tree_view_full->append_column( $column );
# Hide the first column
# Ensure that the expander is fixed to the first
# column( and hence is hidden too )
if ( $column_count == 0 )
{
$column->set_visible( FALSE );
$tree_view_full->set_expander_column( $column );
}
$column_count++;
}
# Create the single column tree for the left side pane
my $tree_store_frozen = Gtk2::TreeStore->new( @tree_store_frozen_types
);
my $tree_view_frozen = Gtk2::TreeView->new( $tree_store_frozen );
# There is only one column (the first column) in this case
my $column_name = $frozen_columns->[ 0 ]->{ ColumnName };
my $column =
Gtk2::TreeViewColumn->new_with_attributes( $column_name,
Gtk2::CellRendererText->new(),
text => 0 );
$column->set_resizable( TRUE );
$tree_view_frozen->append_column( $column );
# Synchronize the frozen-tree with the full-tree
$tree_view_frozen->signal_connect(
'row-expanded' => sub {
my ( $view, $iter, $path ) = @_;
$tree_view_full->expand_row( $path, 0 );
}
);
$tree_view_frozen->signal_connect(
'row-collapsed' => sub {
my ( $view, $iter, $path ) = @_;
$tree_view_full->collapse_row( $path );
}
);
# Recursive function to actually create the tree
append_children( $tree_view_full->get_model(), undef, $data_tree,
$all_columns );
append_children( $tree_view_frozen->get_model(),
undef, $data_tree, $frozen_columns );
# Add the frozen-tree to the left side of the pane
my $paned = Gtk2::HPaned->new;
$paned->add1( $tree_view_frozen );
# we set the vertical size request very small, and it ill fill up the
# available space when we set the default size of the window .
$tree_view_frozen->set_size_request( -1, 10 );
# Add the full-tree to a scrolled window in the right pane
my $scroll = Gtk2::ScrolledWindow->new;
$scroll->add( $tree_view_full );
$paned->add2( $scroll );
# Synchronize the scrolling
$tree_view_frozen->set( vadjustment => $tree_view_full->get_vadjustment
);
# Create a new window and add the pane into it
my $window = Gtk2::Window->new;
$window->signal_connect(
destroy => sub {
Gtk2->main_quit;
}
);
$window->add( $paned );
$window->set_default_size( 300, 100 );
$window->show_all;
Gtk2->main;
# The obligatory recursive function to display the tree
# I don't know the performance implications of using recursion,
# but it seems easy to write and understand
sub append_children {
my ( $tree_store, $iter, $data_tree, $columns ) = @_;
if ( $data_tree ) {
my $count = 0;
my $child_iter = $tree_store->append( $iter );
for my $column ( @$columns ) {
my $column_name = $column->{ ColumnName };
if ( $data_tree->{ $column_name } ) {
$tree_store->set( $child_iter, $count,
$data_tree->{ $column_name } );
}
$count++;
}
foreach my $child ( @{ $data_tree->{ 'Node' } } ) {
append_children( $tree_store, $child_iter, $child, $columns );
}
}
}
__END__
zentara