# -*- perl -*- # # $Id: Cache.pm,v 5.1 2004/09/08 21:09:32 eserte Exp $ # Author: Slaven Rezic # # Copyright (C) 2002 Slaven Rezic. All rights reserved. # This program is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # # Mail: slaven@rezic.de # WWW: http://www.rezic.de/eserte/ # package Tk::Pod::Cache; use strict; use vars qw($VERSION $MAX_CACHE %CACHE); BEGIN { # Make a DEBUG constant very first thing... if(defined &DEBUG) { } elsif(($ENV{'TKPODDEBUG'} || '') =~ m/^(\d+)/) { # untaint my $debug = $1; *DEBUG = sub () { $debug }; } else { *DEBUG = sub () {0}; } } $VERSION = sprintf("%d.%02d", q$Revision: 5.1 $ =~ /(\d+)\.(\d+)/); $MAX_CACHE = 20; # documents # XXX not yet used, LRU etc... sub add_to_cache { my($w, $pod) = @_; $pod = $w->cget(-path) if !defined $pod; return if !defined $pod; return if $CACHE{$pod}; # XXX check for recentness DEBUG and warn "Add contents for $pod to cache.\n"; $CACHE{$pod} = $w->dump_contents; } sub get_from_cache { my($w, $pod) = @_; $pod = $w->cget(-path) if !defined $pod; return 0 if !$CACHE{$pod}; # XXX check for recentness $w->delete("1.0", "end"); DEBUG and warn "Restore contents for $pod from cache.\n"; $w->restore_contents($CACHE{$pod}); 1; } sub delete_from_cache { my($w, $pod) = @_; $pod = $w->cget(-path) if !defined $pod; return if !defined $pod; DEBUG and warn "Delete contents for $pod from cache.\n"; delete $CACHE{$pod}; } sub clear_cache { %CACHE = (); } sub dump_contents { my $w = shift; my @dump = $w->dump('-all', "1.0", "end"); if (@dump == 0) { warn "Workaround strange bug under RedHat 8.0 --- try dump again..."; @dump = $w->dump('-all', "1.0", "end"); if (@dump == 0) { warn "Giving up, cache disabled for current page"; return undef; } } my %tags_def; foreach my $tag ($w->tagNames) { # XXX check for used/existing tags missing my @tag_def; foreach my $item ($w->tagConfigure($tag)) { my $value = $item->[4]; my $option = $item->[0]; push @tag_def, $option, $value; } $tags_def{$tag} = \@tag_def; } return {Dump => \@dump, Tags => \%tags_def, Sections => $w->{'sections'}, PodTitle => $w->{'pod_title'}, }; } sub restore_contents { my($w, $def) = @_; my $dumpref = $def->{Dump}; my $tagref = $def->{Tags}; $w->{'sections'} = $def->{Sections}; $w->{'pod_title'} = $def->{PodTitle}; $w->toplevel->title( "Tkpod: " . $w->{'pod_title'} . " (restoring)"); $w->idletasks; # XXX Is it bad form to manipulate the top level? my $process_no; $w->{ProcessNo}++; $process_no = $w->{ProcessNo}; if ($tagref) { while(my($tag,$def) = each %$tagref) { #XXX tagDelete? $w->tagConfigure($tag, @$def); } } my @taglist; my $last_update = Tk::timeofday(); for(my $i=0; $i<$#$dumpref; $i+=3) { my($key, $val, $index) = @{$dumpref}[$i..$i+2]; if ($key eq 'text') { $w->insert($index, $val, [@taglist]); } elsif ($key eq 'tagon') { unshift @taglist, $val; } elsif ($key eq 'tagoff') { my $j; for (0 .. $#taglist) { if ($taglist[$_] eq $val) { $j = $_; last; } } if (defined $j) { splice @taglist, $j, 1; } $w->tag('remove', $val, 'insert'); } elsif ($key eq 'mark') { $w->markSet($val, $index); # XXX ->see() to current or insert? } elsif ($key eq 'windows') { die "not yet supported"; } elsif ($key eq 'image') { die "not yet supported"; } elsif ($key eq 'imgdef') { die "not yet supported"; } if (Tk::timeofday() > $last_update+0.5) { # XXX make configurable $w->update; $last_update = Tk::timeofday(); do { warn "ABORT!"; return } if $w->{ProcessNo} != $process_no; } } $w->parent->add_section_menu if $w->parent->can('add_section_menu'); $w->Callback('-poddone', $w->cget(-file)); $w->toplevel->title( "Tkpod: " . $w->{'pod_title'}); } 1; __END__ =head1 NAME Tk::Pod::Cache - internal Tk-Pod module for cache control =head1 DESCRIPTION No user-servicable parts here. =cut