# TreeView browsers of various types #this runs a gui sized to fit on top of the console box, # replaces that with a IE window which loads the selected TV item # robert@bangkokwizard.com 29 Feb, 2000 use strict; use Win32::GUI; use Win32::OLE qw(in with EVENTS OVERLOAD); use vars qw($sys); my $windowtitle="TVBrowser"; my ($hIE, %IE, $tvW, %GUI, $GUI, $dirlist ); $GUI{'usingIE'}=0; $GUI{'Details'}='yes'; my $all; use SnatchGUI; use SnatchUtil; my $alone=0; #my ($wTV, $row1, %sys ); #uncomment this line and make $alone=1 to use standalone my $debug=2; my @LoL = ( [ "fred", "barney" ], [ "george", "jane", "elroy" ], [ "homer", "marge", "bart" ], ); $sys{'ListofLists'}=\@LoL; my %HoL = ( flintstones => [ "fred", "barney" ], jetsons => [ "george", "jane", "elroy" ], simpsons => [ "homer", "marge", "bart" ], ); $sys{'HashofLists'}=\%HoL; my @LoH = ( { Lead => "fred", Friend => "barney", }, { Lead => "george", Wife => "jane", Son => "elroy", }, { Lead => "homer", Wife => "marge", Son => "bart", } ); $sys{'ListofHashes'}=\@LoH; my %HoH = ( flintstones => { lead => "fred", pal => "barney", }, jetsons => { lead => "george", wife => "jane", "his boy" => "elroy", }, simpsons => { lead => "homer", wife => "marge", kid => "bart", }, ); $sys{'HashofHashes'}=\%HoH; ##&############# Menu ############# ##&############# Window ############# $wTV = new GUI::Window( -name => $windowtitle, -text => "TreeView", -left => 10, -top => 0, -width => 655, -title => $windowtitle, -height => 160, ); my $nodeAddress=$wTV->AddRichEdit( -name => "nodeAddress", -left => 0, -top => 1, -width => 400, -height => 18, -background => 16316640, ); my $row1=25; my $Leafbmp = new Win32::GUI::Bitmap("leaf.bmp") or die "bad bitmap"; my $Closedbmp = new Win32::GUI::Bitmap("closed.bmp") or die "bad bitmap"; my $Hash3bmp = new Win32::GUI::Bitmap("hash3.bmp") or die "bad bitmap"; my $Openbmp = new Win32::GUI::Bitmap("open.bmp") or die "bad bitmap"; my $List1bmp = new Win32::GUI::Bitmap("list1.bmp") or die "bad bitmap"; my $IL = new Win32::GUI::ImageList(13, 13, 0, 10, 15); my %images= ( Closed => { bmp => $Closedbmp, position =>0, }, Open => { bmp => $Openbmp, position =>0, }, Leaf => { bmp => $Leafbmp, position =>0, }, Hash => => { bmp => $Hash3bmp, position =>0, }, List => => { bmp => $List1bmp, position =>0, }, ); my $i; foreach (qw|Open Closed Leaf Hash List|) { $IL->Add($images{$_}{bmp}, 0); $images{$_}{position}=$i; $i++; } #$IL->Add($Hash1bmp, 0); my $TV = $wTV->AddTreeView( -name => "Tree", -text => "hello world!", -width => 400, -height => $wTV->ScaleHeight, -left => 0, -top => $row1, -lines => 1, -rootlines => 1, -buttons => 1, -visible => 1, -imagelist => $IL, -checkboxes => 0, ); my $col2=$TV->Width+5+$TV->Left; my $IndentWin = new GUI::Window( -text => "Treeview Indent", -name => "IndentWin", -width => 200, -height => 100, -left => 110, -top => 110, ); my $IndentVal = $IndentWin->AddLabel( -text => "Indent value = ".$TV->Indent(), -name => "IndentVal", -left => 10, -top => 10, ); my $IndentNew = $IndentWin->AddTextfield( -text => $TV->Indent(), -name => "IndentNew", -left => 10, -top => 40, -width => 100, -height => 25, ); my $IndentSet = $IndentWin->AddButton( -text => "Set", -name => "IndentSet", -left => 130, -top => 40 ); my $other; sub Tree_Expand { $other=1; my %t = $TV->GetItem($_[0]); my $text=$t{"-text"}; # print STDOUT "Expanded node $_[0] $text\n"; $wTV->nodeAddress->Text($text); $t{'selectedimage'}=$images{Open}{position}; $t{'image'}=$images{Open}{position}; GUI::Update($GUI{'guiW'}); } sub Tree_Collapse { my %t = $TV->GetItem($_[0]); $t{'selectedimage'}=$images{Closed}{position}; } $wTV->AddButton( -name => "butSize", -left => $wTV->ScaleWidth-65, -top => 0, -width => 60, -text => "Size", ); sub wTV_Resize { $TV->Resize($wTV->ScaleWidth, $wTV->ScaleHeight); print STDERR "RESIZED\n"; } my $toggle=1; sub butSize_Click { my $h; if ($toggle) { $h=$wTV->Top + $wTV->Height + GUI::Height($GUI{'perlW'}); } else { $h=160; } $toggle= not $toggle; $TV->Resize($TV->Width, $h-6); $wTV->Resize($wTV->Width, $h); $wTV->Show(); } $wTV->AddButton( -name => "butDir", -left => $wTV->ScaleWidth-65, -top => 25, -width => 60, -text => "Dir", ); $wTV->AddButton( -name => "butTEST", -left => $wTV->ScaleWidth-65, -top => 50, -width => 60, -text => "TEST", ); $wTV->AddButton( -name => "butNav", -left => $wTV->ScaleWidth-65, -top => 75, -width => 60, -text => "Nav", ); $wTV->AddButton( -name => "butCk", -top => 10, -left => $wTV->ScaleWidth-120, -foreground => [128, 255, 128], -background => [0, 0, 255], -text => "Ck", ); sub butCk_Click { my $ck=$wTV->nodeAddress->Text(); my $all=eval($ck); print STDERR $all, " CK\n"; foreach (in $all) { print "$_ CK\n" if not /HASH/; } my ($errn,$errt) = Win32::OLE->LastError(); print "Error $errt $errn oops\n" if $errn; } $wTV->AddCheckbox( -name => "boxDetails", -text => "Details ", -top => 50, -left => $wTV->ScaleWidth-120, -foreground => [128, 255, 128], -background => [0, 0, 255], ) or die "bad checkbox"; sub boxDetails_Click { if ($wTV->boxDetails->Checked()) { $GUI{'Details'}='yes'; } else { $GUI{'Details'}='no'; } print STDERR "Details $GUI{'Details'}\n"; } $wTV->AddCheckbox( -name => "boxIE", -text => "use IE ", -top => 75, -left => $wTV->ScaleWidth-120, -foreground => [128, 255, 128], -background => [0, 0, 255], ) or die "bad checkbox"; sub boxIE_Click { if ($wTV->boxIE->Checked()) { $GUI{'usingIE'}=1; &initIE if not %IE and $GUI{'usingIE'}; } else { $GUI{'usingIE'}=0; } print STDERR "usingIE $GUI{'usingIE'}\n"; } $wTV->AddButton( -name => "butCloseTV", -left => $wTV->ScaleWidth-65, -top => $wTV->ScaleHeight-25, -width => 60, -text => "CloseTV", ); my $BS_GROUPBOX = 7; $wTV->AddButton( -style => WS_VISIBLE | WS_CHILD | $BS_GROUPBOX, -text => '', -name => "RadioGroup", -left => 411, -top => 0, -width => 70, -height => 120, ); $wTV->AddRadioButton( -name => "Radio1", -left => 415, -top => 15, -width => 60, -text => "%GUI", ); $wTV->AddRadioButton( -name => "Radio2", -left => 415, -top => 35, -width => 60, -text => "%IE", ); $wTV->AddRadioButton( -name => "Radio3", -left => 415, -width => 60, -top => 55, -text => "%sys", ); $wTV->AddRadioButton( -name => "Radio4", -left => 415, -width => 60, -top => 75, -text => "Dir", ); sub Radio1_Click { my $text = ""; if($wTV->Radio1->Checked()) { $text = $wTV->Radio1->Text(); } elsif($wTV->Radio2->Checked()) { $text = $wTV->Radio2->Text(); } elsif($wTV->Radio3->Checked()) { $text = $wTV->Radio3->Text(); } my $v=eval "\\$text"; print STDERR "RAD1>$text $v\n"; fillSysVars($v, $text) if $v; } sub Radio2_Click { my $text = ""; if($wTV->Radio2->Checked()) { $text = $wTV->Radio2->Text(); } elsif($wTV->Radio1->Checked()) { $text = $wTV->Radio1->Text(); } elsif($wTV->Radio3->Checked()) { $text = $wTV->Radio3->Text(); } my $v=eval "\\$text"; print STDERR "RAD2>$text $v\n"; fillSysVars($v, $text) if $v; } sub Radio3_Click { my $text = ""; if($wTV->Radio3->Checked()) { $text = $wTV->Radio3->Text(); } elsif($wTV->Radio1->Checked()) { $text = $wTV->Radio1->Text(); } elsif($wTV->Radio2->Checked()) { $text = $wTV->Radio2->Text(); } my $v=eval "\\$text"; print STDERR "RAD2>$text $v\n"; fillSysVars($v, $text) if $v; } sub Radio4_Click { my $text; if($wTV->Radio4->Checked()) { if ($GUI{'Details'} eq 'no') { filldir(1); } else { &filldir; } } } sub butCloseTV_Click { if ($alone) { print STDERR "Shut Down\n"; GUI::BringWindowToTop($GUI{'perlW'}); return -1; } else { print STDERR "wTV>CLICKED CLOSE\n"; $wTV->Hide(); GUI::Update($sys{'GUI'}->{'guiW'}); return 0; } } my $bounce; my $tick; my $tvTimer = $wTV->AddTimer("tvTimer", 0); sub tvTimer_Timer { $tick++; $bounce=0; $tvTimer->Interval(1000); } ##&########### startup code ############# my $localbase='C:/perl/'; my $localname='snatch'; my $stoplist="\.log|\.bak|\.psp|\.zip"; my $basenode; $wTV->Radio3->Checked(1); $wTV->Show(); $GUI{'name'} = $windowtitle; print STDERR $wTV->ScaleWidth," WIDTH\n"; $GUI=synch(\%GUI); print STDERR $wTV->ScaleWidth," WIDTH\n"; $wTV->butCloseTV->{'Left'}=$wTV->ScaleWidth-5; %GUI=%$GUI; foreach (qw|perlW guiW|) { $GUI{"$_ Left"}=GUI::Left($GUI{$_}); $GUI{"$_ Height"}=GUI::Height($GUI{$_}); $GUI{"$_ Top"}=GUI::Top($GUI{$_}); $GUI{"$_ Width"}=GUI::Width($GUI{$_}); } $sys{'child'}=$GUI{'guiW'}; fillSysVars(\%sys,"\%sys"); GUI::Update($tvW); Win32::GUI::Dialog(); ###################################3 sub butDir_Click { my $dir=$wTV->nodeAddress->Text(); return if $dir=~/\s*[@%\$]+/; $dir=~s!->!/!go; $dir=~s!//!/!go; $dir=~tr!\n!!d; $dir=~m!(.+)/(\w+)[/]*$!go; $localbase=$1; $localname=$2; print STDERR $1,$2," $dir DIRECTORY\n"; &filldir2; } sub filldir { my $mode = shift; my $mask='*.*'; $mask='*.html *.rss *.rdf' if $GUI{'usingIE'}; $dirlist=1; $TV->Clear(); $basenode= insert(0,$localbase,$images{Open}{position}); fillTV($localbase,$localname,$mask,$mode,$basenode); $TV->Sort($basenode); $TV->Expand($basenode); } sub filldir2 { my $mode = shift; my $mask='*.*'; $mask='*.html' if $GUI{'usingIE'}; $dirlist=1; $TV->Clear(); $basenode= insert(0,$localbase,$images{Open}{position}); fillTV2($localbase,$localname,$mask,$mode,$basenode); $TV->Sort($basenode); $TV->Expand($basenode); } my $deep; sub fillSysVars { $dirlist=0; return if $bounce; $bounce++; my ($ref, $name)=@_; $TV->Clear(); $deep=0; $GUI{'usingIE'}=0; my $basenode=fillTVvars($ref,0,$name); $TV->Sort($basenode); $TV->Expand($basenode); return $basenode; } sub fillTVvars { my ($ref, $parent, $name)=@_; $deep++; #avoid recursion return if $deep > 8; my ($node, $image, %r, @dx, $type); print STDERR "\$ref $ref $name ",overload::StrVal($ref),"\n" if $debug>2; if ($ref=~/ARRAY/io) { @dx=@$ref; $image=$images{List}{position}; $type='array'; } elsif ($ref=~/HASH|object/oi) { %r=%$ref; @dx=sort keys %r; $image=$images{Hash}{position}; $type='hash'; } else { push @dx, $ref; $image=$images{Leaf}{position}; $type='scalar'; } #print STDERR "$name $ref ",ref($ref),"REF\n"; if (not $parent) { $parent=$TV->InsertItem( -parent => 0, -name => $name, -ref => $ref, -text => $name, -image => $image, -selectedimage => $image, ); print STDERR "TVNEW>\$ref $ref $name\n"; } my $i; foreach (@dx) { my $chilref; my $lref; if ($ref=~/HASH|object/oi) { $chilref=$r{$_}; $lref=$r{$_}; } elsif ($ref=~/ARRAY/io) { $chilref=ref($_); my @l=@$ref; $lref=@l[$i]; } else { $lref=''; } if ($chilref=~/HASH|object/io) { my $image=3; $image=$images{Hash}{position}; my $newTV=$TV->InsertItem( -parent => $parent, -name => $_, -ref => $lref, -text => "$_", -image => $images{Hash}{position}, -selectedimage => $image, ); fillTVvars($lref,$newTV); } elsif ($chilref=~/ARRAY/io) { $image=$images{List}{position}; my $newTV=$TV->InsertItem( -parent => $parent, -name => $_, -text => "$_", -image => $images{List}{position}, -selectedimage => $image, ); fillTVvars($lref,$newTV); } else { $image=$images{Leaf}{position}; my $t=$_; $t="$_ $lref" if $type eq 'hash'; my $newTV=$TV->InsertItem( -parent => $parent, -name => $_, -text => $t, -image => $image, -selectedimage => $image, ); } print STDERR "\$_ $_ ",$chilref," ref\n" if $debug > 2;; $i++; } $TV->Sort($node); $deep--; } sub fillTV { my ($base,$subdir,$mask,$details,$topnode)=@_; my @dx=(); my $mydir="$base/$subdir"; die "no $mydir\n" unless chdir $mydir; my $node= insert($topnode,$subdir,$images{Closed}{position}); my @d = glob $mask; my $f=""; foreach (@d) { next if m/$stoplist/io; $f=$_; if(-d) { my $subdir2=$_; fillTV("$base/$subdir",$subdir2,$mask,$details,$node); next; } my @s= stat; my $size=$s[7]; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =localtime($s[9]); $mon++; my $t=sprintf "%02d-%02d-%d %02d:%02d",$mday,$mon,$year,$hour,$min; if($details) { insert($node, $_, $images{Leaf}{position}); } else { my $z=commify($s[7]); $z=sprintf "% 12s",$z; my $s= "$f $z $t"; insert($node, $s, $images{Leaf}{position}); } } $TV->Sort($node); die "no parent dir\\n" unless chdir ".."; } my $tvinc; sub fillTV2 { my ($base,$subdir,$mask,$op,$topnode)=@_; my @dx=(); my $mydir="$base/$subdir"; print STDERR "fillTV2>$mydir\n"; die "no $mydir\n" unless chdir $mydir; my $node= insert($topnode,$subdir,$images{Closed}{position}); opendir(DIR, $mydir) or die "no find $mydir"; my @filenames = grep(!/$stoplist/, readdir(DIR)); closedir(DIR); return if $tvinc > 5; $tvinc++; foreach (@filenames) { next if /^\.+$/; if(-d) { my $subdir2=$_; fillTV2("$mydir",$_,$mask,$op,$node); next; } insert($node, $_, $images{Leaf}{position}) if $op; } $TV->Sort($node); die "no parent dir\\n" unless chdir ".."; $tvinc--; } sub insert { my ($parent, $node, $image)=@_; my $newTV=$TV->InsertItem( -parent => $parent, -text => $node, -image => $image, -selectedimage => $image, ); } sub quit { my ($object) = @_; $object->Close(); } sub TVBrowser_Deactivate { } my $Act; sub TVBrowser_Activate { if (defined $GUI{'guiW'} and not $Act) { $Act=1; GUI::BringWindowToTop($GUI{'ieW'}) if defined $GUI{'ieW'}; GUI::BringWindowToTop($GUI{'guiW'}); GUI::Update($GUI{'guiW'}); $Act=1; } } sub initIE { if (not $sys{'hIE'}) { use Win32::OLE qw(in with EVENTS); $hIE = Win32::OLE->new('InternetExplorer.Application',\&quit) or die "fatal oops can't get explorer\n"; $IE{'hIE'}=$sys{'hIE'}=$hIE; } with ($hIE, visible => 0, toolbar => 0, menubar => 0, statusbar => 0, addressbar => 0, titlebar => 0, theatermode => 0, title => 'OLE_IE Setup', left => GUI::Left($GUI{'perlW'}), top => GUI::Top($GUI{'perlW'}), width => GUI::Width($GUI{'perlW'}), height => GUI::Height($GUI{'perlW'}), ); my $Count = Win32::OLE->EnumAllObjects(sub { my $Object = shift; my $Class = Win32::OLE->QueryObjectType($Object); printf "# Object=%s Class=%s\n", $Object, $Class; }); guiTitle('TreeView Browser'); #print STDERR $wTV->ScaleWidth," ScaleW\n"; #print STDERR $wTV->Width," ScaleH\n"; $GUI{'ieW'}=FindWindowByTitle 'OLE IE'; } sub butNav_Click { IENav($wTV->nodeAddress->Text()); } sub Tree_NodeClickforIE { my $t; my $n=$_[0]; my %t = $TV->GetItem($n) or die "$n no good!\n"; my $t=$t{'-text'}; print STDERR "TVClick>$t $n\n"; my $p; while ( $n=$TV->GetParent($n)) { %t = $TV->GetItem($n); $p=$t{'-text'}. $p; print "PARENT> $p\n"; } $p=$p. '/' if $GUI{'usingIE'}; $t= $p. $t; $wTV->nodeAddress->Text($t); IENav($t) if $GUI{'usingIE'}; } sub IENav { my $t=shift; # $t="file://". $t unless $t=~m%^file://%; $t=~ s!/!\\!; print "Clicked on $t\n"; return if not $t=~/\./; # should drop most directories &initIE if not $hIE; $hIE->{Visible}=1; $hIE->Navigate($t); my $stat=0; my $i; do { sleep(1); $stat=$hIE->{'Busy'}; $i++; last if $i > 15; } while ($stat); $IE{'Document'}=$hIE->{'Document'}; print STDERR "Document missing\n" if not $IE{'Document'}; $all=$hIE->{'Document'}->{'all'}; print STDERR "Document missing\n" if not $IE{'Document'}; foreach my $value (in $IE{'all'}) { print "Collection Value all $value\n"; } } sub Nav { my $t=shift; $hIE->Navigate($t); } sub butTEST_Click { my $el=$IE{'Document'}->{'activeElement'}; return if not $el; my %h=%$el; my @idlist; my @nameditems; foreach (sort keys %h) { if ($_ eq 'innerHTML') { $_=$sys{'innerHTML'}=$h{$_} if $h{$_}; @idlist= /id\s*=\s*(\w+)/gsi; $sys{'idlist'}=\@idlist; @nameditems= /name\s*=\s*(\w+)/gsi; $sys{'nameditems'}=\@nameditems; next; } if ($_ eq 'innerText') { $sys{'innerText'}=$h{$_} if $h{$_}; next; } print STDERR $_," $h{$_}\n" if $h{$_}; } my $hIE=$IE{'hIE'}; my $all=$hIE->{'Document'}->{'all'}; print STDERR "all->idlist\n" if @idlist; foreach (@idlist) { my $t=$all->{$_}; my $tx=$t->{'innerText'}; print STDERR "$_ $tx\n"; } print STDERR "all->nameditems\n" if @nameditems; foreach (@nameditems) { my $t=$all->{$_}; my $tx=$t->{'value'}; my $n=$t->{'name'}; print STDERR "$n $tx\n"; } } sub Tree_NodeClick { return &Tree_NodeClickforIE if $GUI{'usingIE'}; my ($t, $p, $sep); my $n=$_[0]; my %t = $TV->GetItem($n) or die "$n no good!\n"; $t=$t{'-text'}; while ( $n=$TV->GetParent($n)) { %t = $TV->GetItem($n); $p=$t{'-text'}. '|'. $p; } $t= $p. $t; if ($t=~/^\s*[\@\%\$]/o) { $sep='->'; $t=~s/^\%/\$/o; } else { $sep='/'; } $t=~s/\|/$sep/og; print "TV>$t\n"; $wTV->nodeAddress->Text($t); }