~ubuntu-branches/ubuntu/intrepid/horae/intrepid

« back to all changes in this revision

Viewing changes to 0CPAN/Tk-Pod-0.9932/Pod/Tree.pm

  • Committer: Bazaar Package Importer
  • Author(s): Carlo Segre
  • Date: 2008-02-23 23:13:02 UTC
  • mfrom: (2.1.2 hardy)
  • Revision ID: james.westby@ubuntu.com-20080223231302-mnyyxs3icvrus4ke
Tags: 066-3
Apply patch to athena_parts/misc.pl for compatibility with 
perl-tk 804.28.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- perl -*-
2
 
 
3
 
#
4
 
# $Id: Tree.pm,v 5.1 2004/09/08 21:07:25 eserte Exp $
5
 
# Author: Slaven Rezic
6
 
#
7
 
# Copyright (C) 2001,2004 Slaven Rezic. All rights reserved.
8
 
# This package is free software; you can redistribute it and/or
9
 
# modify it under the same terms as Perl itself.
10
 
#
11
 
# Mail: slaven@rezic.de
12
 
# WWW:  http://www.rezic.de/eserte/
13
 
#
14
 
 
15
 
package Tk::Pod::Tree;
16
 
 
17
 
=head1 NAME
18
 
 
19
 
Tk::Pod::Tree - list Pod file hierarchy
20
 
 
21
 
 
22
 
=head1 SYNOPSIS
23
 
 
24
 
    use Tk::Pod::Tree;
25
 
 
26
 
    $parent->PodTree;
27
 
 
28
 
=head1 WIDGET-SPECIFIC OPTIONS
29
 
 
30
 
=over 4
31
 
 
32
 
=item Name: B<-showcommand>
33
 
 
34
 
Specifies a callback for selecting a Pod module (Button-1 binding).
35
 
 
36
 
=item Name: B<-showcommand2>
37
 
 
38
 
Specifies a callback for selecting a Pod module in a different window
39
 
(Button-2 binding).
40
 
 
41
 
=item Name: B<-usecache>
42
 
 
43
 
True, if a cache of Pod modules should be created and used. The
44
 
default is true.
45
 
 
46
 
=back
47
 
 
48
 
=head1 DESCRIPTION
49
 
 
50
 
The B<Tk::Pod::Tree> widget shows all available Perl Pod documentation
51
 
in a tree.
52
 
 
53
 
=cut
54
 
 
55
 
use strict;
56
 
use vars qw($VERSION @ISA @POD %EXTRAPODDIR $FindPods $ExtraFindPods);
57
 
$VERSION = sprintf("%d.%02d", q$Revision: 5.1 $ =~ /(\d+)\.(\d+)/);
58
 
 
59
 
use base 'Tk::Tree';
60
 
 
61
 
use File::Spec;
62
 
 
63
 
use Tk::Pod::FindPods;
64
 
use Tk::ItemStyle;
65
 
use Tk qw(Ev);
66
 
 
67
 
Construct Tk::Widget 'PodTree';
68
 
 
69
 
my $search_history;
70
 
 
71
 
use constant SEP => "/";
72
 
 
73
 
BEGIN { @POD = @INC }
74
 
 
75
 
BEGIN {  # Make a DEBUG constant very first thing...
76
 
  if(defined &DEBUG) {
77
 
  } elsif(($ENV{'TKPODDEBUG'} || '') =~ m/^(\d+)/) { # untaint
78
 
    my $debug = $1;
79
 
    *DEBUG = sub () { $debug };
80
 
  } else {
81
 
    *DEBUG = sub () {0};
82
 
  }
83
 
}
84
 
 
85
 
######################################################################
86
 
use Class::Struct;
87
 
struct '_PodEntry' => [
88
 
    'uri'  => "\$",
89
 
    'type' => "\$",
90
 
    'name' => "\$",
91
 
];
92
 
sub _PodEntry::create {
93
 
    my $e = shift->new;
94
 
    $e->uri(shift);
95
 
    $e;
96
 
}
97
 
sub _PodEntry::file {
98
 
    my $uri = shift->uri;
99
 
    local $^W = 0;
100
 
    ($uri =~ /^file:(.*)/)[0];
101
 
}
102
 
######################################################################
103
 
 
104
 
sub Dir {
105
 
    my $class = shift;
106
 
    unshift @POD, @_;
107
 
    $EXTRAPODDIR{$_} = 1 for (@_);
108
 
}
109
 
 
110
 
sub ClassInit {
111
 
    my ($class,$mw) = @_;
112
 
    $class->SUPER::ClassInit($mw);
113
 
    $mw->bind($class, '<3>', ['PostPopupMenu', Ev('X'), Ev('Y')]  )
114
 
        if $Tk::VERSION > 800.014;
115
 
 
116
 
    my $set_anchor_and_sel = sub {
117
 
        my($w, $ent) = @_;
118
 
        $w->anchorSet($ent);
119
 
        $w->selectionClear;
120
 
        $w->selectionSet($ent);
121
 
    };
122
 
 
123
 
    # Force callbacks to be treated as methods. This is done by putting
124
 
    # the $widget reference at the beginning of the Tk::Callback array
125
 
    my $inherited_cb = sub {
126
 
        my($w, $cb) = @_;
127
 
        if (UNIVERSAL::isa($cb, "Tk::Callback")) {
128
 
            my $new_cb = bless [$w, @$cb], 'Tk::Callback';
129
 
            $new_cb->Call;
130
 
        } else {
131
 
            # XXX OK?
132
 
            $cb->($w);
133
 
        }
134
 
    };
135
 
 
136
 
    # Add functionality to some callbacks:
137
 
    my $orig_home = $mw->bind($class, "<Home>");
138
 
    $mw->bind($class, "<Home>" => sub {
139
 
                  my $w = shift;
140
 
                  $inherited_cb->($w, $orig_home);
141
 
                  $set_anchor_and_sel->($w, ($w->infoChildren)[0]);
142
 
              });
143
 
    my $orig_end = $mw->bind($class, "<End>");
144
 
    $mw->bind($class, "<End>" => sub {
145
 
                  my $w = shift;
146
 
                  $inherited_cb->($w, $orig_end);
147
 
                  # get last opened entry
148
 
                  my $last = ($w->infoChildren)[-1];
149
 
                  while ($w->getmode($last) eq "close" && $w->infoChildren($last)) {
150
 
                      $last = ($w->infoChildren($last))[-1];
151
 
                  }
152
 
                  $set_anchor_and_sel->($w, $last);
153
 
              });
154
 
    my $orig_prior = $mw->bind($class, "<Prior>");
155
 
    $mw->bind($class, "<Prior>" => sub {
156
 
                  my $w = shift;
157
 
                  $inherited_cb->($w, $orig_prior);
158
 
                  my $ent = $w->nearest(10); # XXX why 10?
159
 
                  return if !defined $ent;
160
 
                  $set_anchor_and_sel->($w, $ent);
161
 
              });
162
 
    my $orig_next = $mw->bind($class, "<Next>");
163
 
    $mw->bind($class, "<Next>" => sub {
164
 
                  my $w = shift;
165
 
                  $inherited_cb->($w, $orig_next);
166
 
                  my $ent = $w->nearest($w->height - 10); # XXX why 10?
167
 
                  return if !defined $ent;
168
 
                  $set_anchor_and_sel->($w, $ent);
169
 
              });
170
 
}
171
 
 
172
 
sub Populate {
173
 
    my($w,$args) = @_;
174
 
 
175
 
    $args->{-separator} = SEP;
176
 
 
177
 
    my $show_command = sub {
178
 
        my($w, $cmd, $ent) = @_;
179
 
 
180
 
        my $data = $w->info('data', $ent);
181
 
        if ($data) {
182
 
            $w->Callback($cmd, $w, $data);
183
 
        }
184
 
    };
185
 
 
186
 
    my $show_command_mouse = sub {
187
 
        my $w = shift;
188
 
        my $cmd = shift || '-showcommand';
189
 
 
190
 
        my $Ev = $w->XEvent;
191
 
        my $ent = $w->GetNearest($Ev->y, 1);
192
 
        return unless (defined $ent and length $ent);
193
 
 
194
 
        my @info = $w->info('item',$Ev->x, $Ev->y);
195
 
        if (defined $info[1] && $info[1] eq 'indicator') {
196
 
            $w->Callback(-indicatorcmd => $ent, '<Arm>');
197
 
            return;
198
 
        }
199
 
 
200
 
        $show_command->($w, $cmd, $ent);
201
 
    };
202
 
 
203
 
    my $show_command_key = sub {
204
 
        my $w = shift;
205
 
        my $cmd = shift || '-showcommand';
206
 
 
207
 
        my($ent) = $w->selectionGet;
208
 
        return unless (defined $ent and length $ent);
209
 
 
210
 
        if ($w->info('children', $ent)) {
211
 
            $w->open($ent);
212
 
        }
213
 
 
214
 
        $show_command->($w, $cmd, $ent);
215
 
    };
216
 
 
217
 
    $w->bind("<1>" => sub { $show_command_mouse->(shift) });
218
 
    foreach (qw/space Return/) {
219
 
        $w->bind("<$_>" => sub { $show_command_key->(shift) });
220
 
    }
221
 
 
222
 
    foreach (qw/2 Shift-1/) {
223
 
        $w->bind("<$_>" => sub { $show_command_mouse->(shift, '-showcommand2') });
224
 
    }
225
 
 
226
 
    $w->SUPER::Populate($args);
227
 
 
228
 
    $w->{Style} = {};
229
 
    $w->{Style}{'core'} = $w->ItemStyle('imagetext',
230
 
                                        -foreground => '#006000',
231
 
                                        -selectforeground => '#006000',
232
 
                                       );
233
 
    $w->{Style}{'site'} = $w->ItemStyle('imagetext',
234
 
                                        -foreground => '#702000',
235
 
                                        -selectforeground => '#702000',
236
 
                                       );
237
 
    $w->{Style}{'cpan'} = $w->ItemStyle('imagetext',
238
 
                                        -foreground => '#000080',
239
 
                                        -selectforeground => '#000080',
240
 
                                       );
241
 
    $w->{Style}{'folder'} = $w->ItemStyle('imagetext',
242
 
                                          -foreground => '#606060',
243
 
                                          -selectforeground => '#606060',
244
 
                                         );
245
 
 
246
 
    my $m = $w->Menu(-tearoff => $Tk::platform ne 'MSWin32');
247
 
    eval { $w->menu($m) }; warn $@ if $@;
248
 
    $m->command(-label => 'Reload', -command => sub {
249
 
                    $w->toplevel->Busy(-recurse => 1);
250
 
                    eval {
251
 
                        $w->Fill(-nocache => 1);
252
 
                    };
253
 
                    my $err = $@;
254
 
                    $w->toplevel->Unbusy(-recurse => 1);
255
 
                    die $err if $err;
256
 
                });
257
 
    $m->command(-label => 'Search...', -command => [$w, 'search_dialog']);
258
 
 
259
 
    $w->ConfigSpecs(
260
 
        -showcommand  => ['CALLBACK', undef, undef, undef],
261
 
        -showcommand2 => ['CALLBACK', undef, undef, undef],
262
 
        -usecache     => ['PASSIVE', undef, undef, 1],
263
 
    );
264
 
}
265
 
 
266
 
=head1 WIDGET METHODS
267
 
 
268
 
=over 4
269
 
 
270
 
=item I<$tree>-E<gt>B<Fill>(?I<-nocache =E<gt> 1>?)
271
 
 
272
 
Find Pod modules and fill the tree widget. If I<-nocache> is
273
 
specified, then no cache will be used for loading.
274
 
 
275
 
A cache of Pod modules is written unless the B<-usecache>
276
 
configuration option of the widget is set to false.
277
 
 
278
 
=cut
279
 
 
280
 
sub Fill {
281
 
    my $w = shift;
282
 
    my(%args) = @_;
283
 
    $w->delete("all");
284
 
 
285
 
    my $usecache = ($w->cget('-usecache') && !$args{'-nocache'});
286
 
 
287
 
    # fills %pods hash:
288
 
    $FindPods = Tk::Pod::FindPods->new unless $FindPods;
289
 
    my $pods = $FindPods->pod_find(-categorized => 1,
290
 
                                   -usecache => $usecache,
291
 
                                  );
292
 
 
293
 
    if (keys %EXTRAPODDIR) {
294
 
        $ExtraFindPods = Tk::Pod::FindPods->new unless $ExtraFindPods;
295
 
        my $extra_pods = $ExtraFindPods->pod_find
296
 
            (-categorized => 0,
297
 
             -category => "local dirs",
298
 
             -directories => [keys %EXTRAPODDIR],
299
 
             -usecache => 0,
300
 
            );
301
 
        while(my($k,$v) = each %$extra_pods) {
302
 
            $pods->{$k} = $v;
303
 
        }
304
 
    }
305
 
 
306
 
    my %category_seen;
307
 
 
308
 
    foreach (['perl',   'Perl language'],
309
 
             ['pragma', 'Pragmata'],
310
 
             ['mod',    'Modules'],
311
 
             ['script', 'Scripts'],
312
 
             keys(%$pods),
313
 
            ) {
314
 
        my($category, $title) = (ref $_ ? @$_ : ($_, $_));
315
 
        next if $category_seen{$category};
316
 
 
317
 
        $w->add($category, -text => $title);
318
 
 
319
 
        my $hash = $pods->{$category};
320
 
        foreach my $pod (sort keys %$hash) {
321
 
            my $treepath = $category . SEP . $pod;
322
 
            (my $title = $pod) =~ s|/|::|g;
323
 
            $w->_add_parents($treepath);
324
 
 
325
 
            my $loc = Tk::Pod::FindPods::module_location($hash->{$pod});
326
 
            my $is = $w->{Style}{$loc};
327
 
            my @entry_args = ($treepath,
328
 
                              -text => $title,
329
 
                              -data => _PodEntry->create($hash->{$pod}),
330
 
                              ($is ? (-style => $is) : ()),
331
 
                             );
332
 
            if ($w->info('exists', $treepath)) {
333
 
                $w->entryconfigure(@entry_args);
334
 
            } else {
335
 
                $w->add(@entry_args);
336
 
            }
337
 
        }
338
 
 
339
 
        $category_seen{$category}++;
340
 
    }
341
 
 
342
 
    for(my $entry = ($w->info('children'))[0];
343
 
           defined $entry && $entry ne "";
344
 
           $entry = $w->info('next', $entry)) {
345
 
        if ($w->info('children', $entry) ||
346
 
            $w->entrycget($entry, -text) eq 'perlfunc') {
347
 
            $w->folderentry($entry);
348
 
        } else {
349
 
            $w->entryconfigure($entry, -image => $w->Getimage("file"));
350
 
            $w->hide('entry', $entry);
351
 
        }
352
 
    }
353
 
 
354
 
    if ($w->cget('-usecache') && !$FindPods->has_cache) {
355
 
        $FindPods->WriteCache;
356
 
    }
357
 
 
358
 
    $w->{Filled}++;
359
 
}
360
 
 
361
 
sub folderentry {
362
 
    my($w, $entry) = @_;
363
 
    $w->entryconfigure($entry, -image => $w->Getimage("folder"));
364
 
    $w->setmode($entry, 'open');
365
 
    if ($entry =~ m|/|) { # XXX SEP?
366
 
        $w->hide('entry', $entry);
367
 
    }
368
 
}
369
 
 
370
 
sub Filled { shift->{Filled} }
371
 
 
372
 
sub _add_parents {
373
 
    my($w, $entry) = @_;
374
 
    (my $parent = $entry) =~ s|/[^/]*$||; # XXX SEP?
375
 
    return if $parent eq '';
376
 
    do{warn "XXX Should not happen: $entry eq $parent";return} if $parent eq $entry;
377
 
    return if $w->info('exists', $parent);
378
 
    my @parent = split SEP, $parent;
379
 
    my $title = join "::", @parent[1..$#parent];
380
 
    $w->_add_parents($parent);
381
 
    $w->add($parent, -text => $title,
382
 
            ($w->{Style}{'folder'} ? (-style => $w->{Style}{'folder'}) : ()));
383
 
}
384
 
 
385
 
sub _open_parents {
386
 
    my($w, $entry) = @_;
387
 
    (my $parent = $entry) =~ s|/[^/]+$||; # XXX SEP?
388
 
    return if $parent eq '' || $parent eq $entry;
389
 
    $w->_open_parents($parent);
390
 
    $w->open($parent);
391
 
}
392
 
 
393
 
=item I<$tree>-E<gt>B<SeePath>($path)
394
 
 
395
 
Move the anchor/selection and view to the given C<$path> and open
396
 
subtrees to make the C<$path> visible, if necessary.
397
 
 
398
 
=cut
399
 
 
400
 
sub SeePath {
401
 
    my($w,$path) = @_;
402
 
    my $fs_case_tolerant =
403
 
        ($^O eq 'MSWin32' ||
404
 
         (File::Spec->can("case_tolerant") && File::Spec->case_tolerant)
405
 
        );
406
 
    if ($^O eq 'MSWin32') {
407
 
        $path =~ s/\\/\//g;
408
 
    }
409
 
    if ($fs_case_tolerant) {
410
 
        $path = lc $path;
411
 
    }
412
 
    DEBUG and warn "Call SeePath with $path\n";
413
 
    return if !$w->Filled; # not yet filled
414
 
    return if !$FindPods;
415
 
    my $pods = $FindPods->pods;
416
 
    return if !$pods;
417
 
 
418
 
    my $see_treepath = sub {
419
 
        my $treepath = shift;
420
 
        $w->open($treepath);
421
 
        $w->_open_parents($treepath);
422
 
        $w->anchorSet($treepath);
423
 
        $w->selectionClear;
424
 
        $w->selectionSet($treepath);
425
 
        $w->see($treepath);
426
 
    };
427
 
 
428
 
    foreach my $category (keys %$pods) {
429
 
        foreach my $pod (keys %{ $pods->{$category} }) {
430
 
            my $podpath = $pods->{$category}->{$pod};
431
 
            $podpath = lc $podpath if $fs_case_tolerant;
432
 
            if ($path eq $podpath) {
433
 
                my $treepath = $category . SEP . $pod;
434
 
                $see_treepath->($treepath);
435
 
                return 1;
436
 
            }
437
 
        }
438
 
    }
439
 
    DEBUG and warn "SeePath: cannot find $path in tree\n";
440
 
    0;
441
 
}
442
 
 
443
 
sub GetCurrentPodPath {
444
 
    my $w = shift;
445
 
    my $sel_entry = ($w->selectionGet)[0];
446
 
    if (defined $sel_entry) {
447
 
        my @c = split m{/}, $sel_entry;
448
 
        shift @c;
449
 
        my $pod = join "::", @c;
450
 
        return $pod;
451
 
    }
452
 
}
453
 
 
454
 
sub search_dialog {
455
 
    my($w) = @_;
456
 
    my $t = $w->Toplevel(-title => "Search");
457
 
    $t->transient($w);
458
 
    $t->Label(-text => "Search module:")->pack(-side => "left");
459
 
    my $term;
460
 
 
461
 
    my $Entry = 'Entry';
462
 
    eval {
463
 
        require Tk::HistEntry;
464
 
        Tk::HistEntry->VERSION(0.40);
465
 
        $Entry = "HistEntry";
466
 
    };
467
 
 
468
 
    my $e = $t->$Entry(-textvariable => \$term)->pack(-side => "left");
469
 
    if ($e->can('history') && $search_history) {
470
 
        $e->history($search_history);
471
 
    }
472
 
    $e->focus;
473
 
    $e->bind("<Escape>" => sub { $t->destroy });
474
 
 
475
 
    my $do_search = sub {
476
 
        if ($e->can('historyAdd')) {
477
 
            $e->historyAdd($term);
478
 
            $search_history = [ $e->history ];
479
 
        }
480
 
        $w->search($term);
481
 
    };
482
 
 
483
 
    $e->bind("<Return>" => $do_search);
484
 
 
485
 
    {
486
 
        my $f = $t->Frame->pack(-fill => "x");
487
 
        Tk::grid($f->Button(-text => "Search",
488
 
                            -command => $do_search,
489
 
                           ),
490
 
                 $f->Button(-text => "Close",
491
 
                            -command => sub { $t->destroy },
492
 
                           ),
493
 
                 -sticky => "ew");
494
 
    }
495
 
}
496
 
 
497
 
sub search {
498
 
    my($w, $rx) = @_;
499
 
    return if $rx eq '';
500
 
    my($entry) = ($w->info('selection'))[0];
501
 
    if (!defined $entry) {
502
 
        $entry = ($w->info('children'))[0];
503
 
        return if (!defined $entry);
504
 
    }
505
 
    my $wrapped = 0;
506
 
    while(1) {
507
 
        $entry = $w->info('next', $entry);
508
 
        if (!defined $entry) {
509
 
            if ($wrapped) {
510
 
                $w->bell;
511
 
                return;
512
 
            }
513
 
            $wrapped++;
514
 
            $entry = ($w->info('children'))[0];
515
 
        }
516
 
        my $text = $w->entrycget($entry, '-text');
517
 
        if ($text =~ /$rx/i) {
518
 
            my $p = $entry;
519
 
            while(1) {
520
 
                $p = $w->info('parent', $p);
521
 
                if (defined $p) {
522
 
                    $w->open($p);
523
 
                } else {
524
 
                    last;
525
 
                }
526
 
            }
527
 
            $w->selectionClear;
528
 
            $w->selectionSet($entry);
529
 
            $w->anchorSet($entry);
530
 
            $w->see($entry);
531
 
            return;
532
 
        }
533
 
    }
534
 
}
535
 
 
536
 
sub IndicatorCmd {
537
 
    my($w, $ent, $event) = @_;
538
 
    my $podentry = $w->entrycget($ent, "-data");
539
 
    my $file = $podentry && $podentry->file;
540
 
    my $type = $podentry && $podentry->type;
541
 
 
542
 
    # Dynamically create children for perlfunc entry
543
 
    if (defined $type && $type =~ /^func_/ && !$w->info('children', $ent)) {
544
 
        require Pod::Functions;
545
 
 
546
 
        my $add_func = sub {
547
 
            my($ent, $func) = @_;
548
 
            my $podentry = _PodEntry->new;
549
 
            $podentry->type("func");
550
 
            $podentry->name($func);
551
 
            (my $safe_name = $func) =~ s{[^a-zA-Z]}{_}g;
552
 
            $ent = $ent . SEP . $safe_name;
553
 
            $w->add($ent, -text => $func, -data => $podentry,
554
 
                    -style => $w->{Style}{'core'});
555
 
        };
556
 
 
557
 
        if ($type eq 'func_alphabetically') {
558
 
            my $last_func;
559
 
            my @funcs = map { if (!defined $last_func || $last_func ne $_) {
560
 
                                  $last_func = $_;
561
 
                                  ($_);
562
 
                              } else {
563
 
                                  $last_func = $_;
564
 
                                  ();
565
 
                              }
566
 
                            }
567
 
                        sort
568
 
                        map { @{ $Pod::Functions::Kinds{$_} } }
569
 
                        keys %Pod::Functions::Kinds;
570
 
            for my $func (@funcs) {
571
 
                $add_func->($ent, $func);
572
 
            }
573
 
        } else { # by category
574
 
            for my $cat (sort keys %Pod::Functions::Kinds) {
575
 
                (my $safe_name = $cat) =~ s{[^a-zA-Z]}{_}g;
576
 
                my $ent = $ent . SEP . $safe_name;
577
 
                $w->add($ent, -text => $cat, -style => $w->{Style}{'folder'});
578
 
                my $funcs = $Pod::Functions::Kinds{$cat};
579
 
                for my $func (@$funcs) {
580
 
                    $add_func->($ent, $func);
581
 
                }
582
 
            }
583
 
        }
584
 
    } elsif (defined $file && $file =~ /perlfunc\.pod$/ && !$w->info('children', $ent)) {
585
 
        my($treepath, $podentry);
586
 
 
587
 
        $treepath = $ent . SEP. "func_alphabetically";
588
 
        $podentry = _PodEntry->new;
589
 
        $podentry->type("func_alphabetically");
590
 
        $w->add($treepath, -text => "Alphabetically", -data => $podentry,
591
 
                -style => $w->{Style}{'folder'});
592
 
        $w->folderentry($treepath);
593
 
 
594
 
        $treepath = $ent . SEP. "func_by_category";
595
 
        $podentry = _PodEntry->new;
596
 
        $podentry->type("func_by_category");
597
 
        $w->add($treepath, -text => "By category", -data => $podentry,
598
 
                -style => $w->{Style}{'folder'});
599
 
        $w->folderentry($treepath);
600
 
    }
601
 
    $w->SUPER::IndicatorCmd($ent, $event);
602
 
}
603
 
 
604
 
1;
605
 
 
606
 
__END__
607
 
 
608
 
=back
609
 
 
610
 
=head1 SEE ALSO
611
 
 
612
 
Tk::Tree(3), Tk::Pod(3), tkpod(1), Tk::Pod::FindPods(3).
613
 
 
614
 
=head1 AUTHOR
615
 
 
616
 
Slaven Rezic <F<slaven@rezic.de>>
617
 
 
618
 
Copyright (c) 2001,2004 Slaven Rezic.  All rights reserved.  This program
619
 
is free software; you can redistribute it and/or modify it under the same
620
 
terms as Perl itself.
621
 
 
622
 
=cut