Puppet::VcsTools::History - TK GUI for VcsTools::History


Puppet-VcsTools-History documentation Contained in the Puppet-VcsTools-History distribution.

Index


Code Index:

NAME

Top

Puppet::VcsTools::History - TK GUI for VcsTools::History

SYNOPSIS

Top

 require VcsTools::DataSpec::HpTnd ; # for instance
 # could be VcsTools::DataSpec::Rcs

 my $ds = new VcsTools::DataSpec::HpTnd ; # ditto

 my $hist = new Puppet::VcsTools::History 
  (
   dbHash => \%dbhash,         # for permanent data storage
   keyRoot => 'history root',  # key for permanent data storage
   'topTk' => $mw,
   name => 'Foo history',
   dataScanner => $ds          # log analyser
  );

DESCRIPTION

Top

This class provides a GUI to the VcsTools::History class.

It contains a GraphWidget to draw the history tree and some key bindings to read the log informations from the tree drawing .

WIDGET USAGE

Top

The display of the history object is made of :

Nodes

Each rectangle in the tree represent a revision (aka a node). The text in the rectangle is bound to some keys :

The node popup menu features :

Arrows

Each arrow is bound to some keys :

The arrow popup menu features :

global features

The graph widget features a global menu invoked on the title of the graph widget. It features :

The VcsTools::File(3) object have also some bindings (See "WIDGET USAGE" in VcsTools::File)

Constructor

Top

new(...)

Will create a new history object.

Parameters are:

Methods

Top

All "Methods" in VcsTools::History plus these ones:

addNewVersion(...)

The call will be delegated to "addNewVersion(...)" in VcsTools::History, then the drawing will be updated with it.

display()

Will launch a widget for this object.

closeDisplay()

Delegated to the "closeDisplay" in Puppet::Body method.

drawTree(...)

Parameters are:

getTreeGraph()

Returns the Tk::TreeGraph ref embedded in History display or undef if the display was not opened.

getInfoWidget()

Returns the Tk::ROText ref embedded in History display or undef if the display was not opened.

TODO

Top

Trigger a history update if the database time stamp is younger than the time of the last history analysis

AUTHOR

Top

Dominique Dumont, Dominique_Dumont@grenoble.hp.com

Copyright (c) 1998-1999 Dominique Dumont. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

Top

perl(1), Tk(3), Puppet::Show(3), VcsTools::DataSpec::HpTnd(3), Puppet::VcsTools::Version(3), Puppet::VcsTools::File(3)


Puppet-VcsTools-History documentation Contained in the Puppet-VcsTools-History distribution.

package Puppet::VcsTools::History ;

use strict;
use Puppet::Show ;
use Puppet::VcsTools::Version ;
use Carp ;

use base 'VcsTools::History' ;

use vars qw($VERSION);

use AutoLoader qw/AUTOLOAD/ ;

$VERSION = sprintf "%d.%03d", q$Revision: 1.5 $ =~ /(\d+)\.(\d+)/;

sub new
  {
    my $type = shift ;
    my %args = @_ ;

    my $self = {};
    $self->{name}=$args{name};

    $self->{body} = new Puppet::Show
      (
       cloth => $self,
       podName => 'Puppet::VcsTools::History',
       podSection => 'WIDGET USAGE',
       @_
      ) ;

    my $usage = $self->{usage} = $args{usage} || 'File' ;

    #carp "new $type $args{name}: usage is deprecated" 
    #  if defined $args{usage};

    # we can't deprecate usage until the version list problem is
    # sorted.  version list is stored in the DB_file, while the SQL
    # interface rebuilds it. This leads to 2 different behaviors,
    # hence the usage parameter.  The solution could be to re-build
    # the version list from the keys of the DB_File even though this
    # is not efficient.

    # then again ,there's the problem of the historyUpdateTime ...

    if (defined $args{storageArgs})
      {
        # transition code, should be removed sooner or later
        my %storeArgs = %{$args{storageArgs}} ;
        carp "new $type $args{name}: storageArgs is deprecated";
        if ($usage eq 'MySql')
          {
            require VcsTools::HistSqlStorage;
            $args{storage} = new VcsTools::HistSqlStorage (%storeArgs) ;
          }
        else
          {
            $args{storage} =  new Puppet::Storage (name => $self->{name},
                                                   %storeArgs) ;
          }
        $self->{storageArgs}=$args{storageArgs};
      }


    # mandatory parameter
    foreach (qw/name dataScanner topTk storage/)
      {
        croak "No $_ passed to $self->{name}\n" unless 
          defined $args{$_};
        $self->{$_} = delete $args{$_} ;
      }

    bless $self,$type ;
  }

1;

__END__



#internal do not call from outside because there's no sanity checks
sub createVersionObj
  {
    my $self = shift ;
    my $rev = shift ;

    $self->{body}->printDebug("Creating puppet version object for rev $rev\n");
    
    my @store = defined $self->{storageArgs} ? 
      (storageArgs => $self->{storageArgs}) :
      (storage => $self->{storage} -> child(name => $rev)) ;

    return new Puppet::VcsTools::Version  
      (
       name => $rev,
       title => "$self->{name} v$rev",
       topTk => $self->{topTk},
       dataFormat => $self->{dataScanner}->getDescription,
       usage => $self->{usage},
       # this closure could be improved for performance with a cache
       # but the cleanup of cached versions object can be a problem
       getBrotherSub => sub{$self->getVersionObj(@_);},
       @store,
       revision => $rev
      ) ;
  }

sub getTreeGraph
  {
    my $self = shift ;
    return undef unless defined $self->{body}->myDisplay();

    return  $self->{body}->myDisplay()->getSlave($self->{treeName}) ;
  }

sub getInfoWidget
  {
    my $self = shift ;
    return undef unless defined $self->{body}->myDisplay();
    return  $self->{body}->myDisplay()->getSlave($self->{textName});
  }


sub display
  {
    my $self = shift ;

    my $top = $self->{body}->display (@_);

    return unless defined $top;
 
    require Puppet::VcsTools::GraphWidget ;

    $self->{treeName} = 'history graph';
    my $tree = $top ->newSlave
      (
       type => 'MultiVcsGraph', 
       title => $self->{treeName}
      );

    require Tk::Menubutton;

    $tree->addRev(@{$self->{storage}->getDbInfo('versionList')}) ;

    # a garder TBD ?
    $self->{textName}=$self->{name};
    $top -> newSlave
        (
         'type' => 'MultiText', 
         'title' => $self->{textName},
         'hidden' => 0 ,
         'help' => 'This text window display the results of the operations '.
         'invoked within the History graph widget'
        );


    # must add menu button related to the graph funcionnality
    # i.e draw, merge, show diff
    # these function will ask for currently selected nodes


    $tree->command(on => 'menu', -label=>'unselect all', 
                   command => sub{$tree->unselectAllNodes();});

    $tree->command
      (
       on => 'menu',
       -label=>'show cumulated log', 
       command => sub
       {
         my $info = $self->buildCumulatedInfo($tree->getSelectedNodes()) ;
         my $str = $self->{dataScanner}->buildLogString($info) ;
         $self->showResult($self->{dataScanner}->buildLogString($info));
       }
      );

    $tree->Subwidget('list')->bind
      (
       '<Double-1>' => sub 
       {
         my $item = shift ;
         my $rev = $item->get ('active') ;
         $self->body()->printEvent("drawing tree from rev $rev\n") ;
         $self->drawTree(revision =>$rev) ;
       }
      ) ;

    my $showLog = sub 
      {
        my %args = @_ ;
        my $str = $self->getLog(version => $args{to} || $args{nodeId}, 
                                key => 'log');
        $self->showResult($str) ;
      } ;
    
    my $showFullLog = sub 
      {
        my %args = @_ ;
        my $str = $self->getLog(version => $args{to}|| $args{nodeId});
        $self->showResult($str) ;
      } ;
    
    $tree->arrowBind
      (
       button => '<1>',
       color => 'red', 
       command => $showLog
      ) ;

    $tree->command 
      (
       on => 'arrow', 
       label => 'show log', 
       command => $showLog
      ) ;

    $tree->command 
      (
       on => 'arrow', 
       label => 'show full log', 
       command => $showFullLog
      ) ;
    
    $tree->command 
      (
       on => 'node', 
       label => 'show log', 
       command => $showLog
      ) ;

    $tree->command 
      (
       on => 'node', 
       label => 'show full log', 
       command => $showFullLog
      ) ;
    
    $tree->arrowBind
      (
       button => '<3>',
       color => 'orange', 
       command => sub {$tree->popupMenu(@_);}
      ) ;

    # bind double-1 to redraw the whole graph 
    $tree->nodeBind
      (
       button =>  '<Double-1>',
       color =>   'black', 
       command => sub {$self->drawTree(@_)}
      );

    # bind button <3> on nodes to pop up a menu
    $tree->nodeBind
      (
       button =>  '<3>',
       color =>   'red', 
       command => sub {$tree->popupMenu(@_);}
      ) ;

    $tree->command
      (
       on => 'node',
       label =>'draw from here',
       command => sub {$self->drawTree(@_)}
      );

    $tree->command
      (
       on => 'node',
       label => 'open version object',
       command => sub 
       {
         my %args = @_ ;
         $self->{body}->getContent($args{nodeId})->cloth()->display() ;
       }
      ) ;

    return $top ;
  }

sub closeDisplay
  {
    my $self = shift ;
    $self->{body}->closeDisplay();
  }
  

#internal
sub showResult
  {
    my $self = shift ;
    
    return unless defined $self->{body}->myDisplay();

    my $txt = $self->{body}->myDisplay()->getSlave($self->{textName}) ;
    $txt -> clear();
    my $ref =shift ;
    my $str = ref($ref) eq 'ARRAY' ? join("\n",@$ref) : $ref ;

    $txt->insertText($str) ;
  }

sub drawTree
  {
    my $self = shift ;
    my %args = @_ ;

    return unless defined $self->{body}->myDisplay();
    my $tree = $self->{body}->myDisplay()->getSlave($self->{treeName});
    $self->{drawRoot}=$args{revision} || $args{nodeId} || $self->{drawRoot} ;
    return unless defined $self->{drawRoot};

    $self->getVersionObj($self->{drawRoot})->drawTree($tree);
  }

# called to add a new version of the file (after an archive)
sub addNewVersion
   {
     my $self = shift ;

     my $obj = $self->SUPER::addNewVersion(@_);

     return unless defined $self->{body}->myDisplay();
     my $tree = $self->{body}->myDisplay()->getSlave($self->{treeName});
     $tree->addRev($obj->getRevision()) ;
     
     $self->drawTree();
   }

sub update
  {
    my $self = shift ;
    
    if (defined $self->{body}->myDisplay())
      {
        my $tree = $self->{body}->myDisplay()->getSlave($self->{treeName});
        $tree->Subwidget('graph')-> clear ;
        $tree->Subwidget('list')->delete(0,'end');
      } ;
    
    $self->SUPER::update(@_);
    
    if (defined $self->{body}->myDisplay())
      {
        my $tree = $self->{body}->myDisplay()->getSlave($self->{treeName});
        $tree->addRev(@{$self->{storage}->getDbInfo('versionList')}) ;

        $self->drawTree;
      }
  }
1;



# Pas testee
# sub findMerge
#   {
#     my $self = shift ;
#     my $rev1 = shift ;
#     my $rev2 = shift ;

#     # find in history if rev1 and rev2 are merged. return the merge version
#     foreach (("$rev1-$rev2","$rev2-$rev1"))
#       {
#         if (defined $self->{myDbHash}{info}{mergeList}{$_}) 
#           {
#             my $rev =  $self->{myDbHash}{info}{mergeList}{$_} ;

#             while ($self->{myDbHash}{state} eq 'Dead')
#               {
#                 my $old = $rev ;
#                 $rev = $self->{myDbHash}{lower} ;
#                 unless (defined $rev)
#                   {
#                     croak "Found Dead $self->{name} version $old for merge\n"  ;
#                     return undef ;
#                   } 
#               }
#             return $rev ;
#           }
#       }

#     return undef ;
#   }