http://qs321.pair.com?node_id=68941
Category: Utility Scripts
Author/Contact Info larsen
Description: Simple module to produce Gantt diagram from XML project descriptions.
Or, what Perl can do to help you if you're planning to conquer the world?.
package Gantt;

use strict;

use XML::Simple;
use Data::Dumper;

BEGIN {
    use Exporter qw();

    use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);

    @ISA = qw( Exporter );

    $VERSION = 0.1;

    @EXPORT_OK = qw();
    @EXPORT = qw();
}

use vars @EXPORT_OK;
use vars qw();

my %marked = ();
my $Debug = 0;

sub new
{
    my $self = {};

    $self->{ Project } = undef;
    $self->{ Start } = undef;

    return bless $self;
}


# Obtains a Directed Acyclic Graph from project description
# It also finds and returns the first task in the project 
# (ATTENTION: this task must be is unique)
sub project_to_dag
{
    my $self = shift;
    
    my $start;
    
    foreach my $task ( keys %{ $self->{ Project }->{task} } ) {
        if (not (defined $self->{Project}->{task}->{$task}->{dependenc
+y})) {
            $start = $task;
        } else {
            
            foreach my $t ( @{$self->{Project}->{task}->{$task}->{depe
+ndency}} ) {   
                push @{ $self->{ Project }->{task}->{$t}->{adjacent}},
+ $task; 
            }
        }
    }
    $self->{Start} = $start;

    print Dumper( $self->{ Project } ) if $Debug;
}


# Topological Sort
# see "Data Structures and Algorithms", A.V.Aho, J.E.Hopcroft, J.D.Ull
+man, p. 221 
sub topsort 
{
    my $self = shift;

    my $task = shift;
    my $pred = shift;

    $marked{ $task } = 1;
    if ( $pred ) {
        $self->{ Project }->{task}->{$task}->{from_start} = 
            $self->{ Project }->{task}->{$pred}->{from_start} + 
            $self->{ Project }->{task}->{$pred}->{duration};
    }

    if (defined @{  $self->{ Project }->{task}->{$task}->{adjacent}} )
+ {

        my @sorted_tasks = sort {
            $self->{Project}->{task}->{$b}->{duration} <=>
            $self->{Project}->{task}->{$a}->{duration}
        } @{ $self->{ Project }->{task}->{$task}->{adjacent}};

        foreach my $t ( @sorted_tasks ) {
            if (not $marked{ $t }) {
                $self->topsort( $t, $task );
            }
            
        }
    }
}


sub load_project 
{
    my $self = shift;
    
    my $project_file_name = shift;

    $self->{ Project } = XMLin( $project_file_name, forcearray => 1)
    || die "Can't load project file - $! ";

    $self->project_to_dag( $self->{ Project } );
    $self->topsort( $self->{ Start });
}


sub length
{
    my $self = shift;

    my @l = sort { $b <=> $a } map {
        $_->{from_start} + $_->{duration}
    } values %{ $self->{ Project }->{task}};

    return $l[0];
}


sub print_as_text 
{
    my $self = shift;
    my $l = $self->length();
    
    print Dumper( $self->{ Project } ) if $Debug;

    print "$self->{ Project }->{ name }\n";
    
    print ' ' x (20+7);
    for my $i ( 1..$l ) {
        print ($i % 5 ? '-' : '+'); 
    }
    print "\n\n";

    foreach my $task ( keys %{ $self->{ Project }->{task} } ) {
        printf "%-20s [%3d] ", $task, $self->{ Project }->{task}->{$ta
+sk}->{duration};
        print '-' x $self->{ Project }->{task}->{$task}->{from_start} 
+.
            '#' x $self->{ Project }->{task}->{$task}->{duration} . "\
+n";    
    }

    print "Total days: $l\n\n";
}


"That's all, folks";
END {
}

=head1 AUTHOR

Stefano Rodighiero, (stefano@filibusta.crema.unimi.it)

=cut

__END__

=head1 NAME

Gantt - Simple module to produce Gantt diagram from
XML project descriptions.

=head1 EXAMPLE

    use Gantt;

    my $g = new Gantt();

    $g->load_project( './project.xml' );
    $g->print_as_text;

Here a simple XML project description in the form expected
by this module

    <project name="Program development">
    <task name="Define Specifics" duration="5">
    </task>

    <task name="Analysis" duration="10">
    <dependency>Define Specifics</dependency>
    </task>

    <task name="Search documentation" duration="3">
    <dependency>Define Specifics</dependency>
    </task>

    <task name="Write code" duration="7">
    <dependency>Analysis</dependency>
    <dependency>Search documentation</dependency>
    </task>

    <task name="Write documentation" duration="5">
    <dependency>Write code</dependency>
    </task>

    <task name="Test" duration="5">
    <dependency>Write code</dependency>
    </task>

    <task name="Release" duration="2">
    <dependency>Test</dependency>
    <dependency>Write documentation</dependency>
    </task>

    </project>

=head1 WHAT I WOULD LIKE TO DO

=item * HTML output

=item * GraphViz output

=item * Graphic output using GD

=item * Tk interface to produce XML project description

=cut