#Copyright Massachusetts Institute of technology, 1998.
#Written by Eric Prud'hommeaux for the World Wide Web Consortium

use strict;
#require Exporter;
#require AutoLoader;
require Tk;

$W3C::Rdf::TkVisualizer::REVISION = '$Id: TkVisualizer.pm,v 1.43 2000/12/07 22:45:53 eric Exp $ ';

package W3C::Rdf::TkVisualizer;
use vars qw($VERSION $DSLI @ISA @EXPORT @EXPORT_OK @TODO);
@ISA = qw();
@EXPORT = qw();
@EXPORT_OK = qw();
$VERSION = 0.95;
$DSLI = 'adpO';
@TODO = ('hide internals of -namespaceHandler');

sub Populate {
    require W3C::Rdf::TkVisualizer::Base;
    my($cw, $args) = @_;
    $cw->SUPER::Populate($args);

    my $base = $cw->Base();
    my $windowSet = $cw->WindowSet(%$args, -main => $cw);
    $windowSet->pack;
    $cw->Advertise('base' => $base);
    $cw->ConfigSpecs(-windowSets => ['PASSIVE', undef, undef, undef],

		     -attributionsByInputSource => ['PASSIVE', undef, undef, undef], 
		     -queryOptions => ['PASSIVE', undef, undef, undef], 
		     -algae => ['PASSIVE', undef, undef, undef], 
		     -namespaceHandler => ['PASSIVE', undef, undef, undef], 
		     -RdfDB => ['PASSIVE', undef, undef, undef], 
		     -systemId => ['PASSIVE', undef, undef, undef], 

		     'DEFAULT' => [$base]);
    $cw->Delegates(DEFAULT => $base);
    $cw->configure(-windowSets => [$windowSet]);
}

sub new {
    my ($proto, @parms) = @_;
    my $class = ref($proto) || $proto;
    my $self = {@parms};
    bless ($self, $class);
    return $self;
}

use W3C::Rdf::TkVisualizer::WindowSet;

sub makeWindowSet {
    my ($self) = @_;
    my $dolly = $self->{MAIN_WINDOW}->WindowSet(-RdfDB => $self->{-RdfDB}, -RdfApp => $self->{-RdfApp}, 
						-namespaceHandler => $self->{-namespaceHandler}, 
						-main => $self, -noColumns => $self->{-noColumns}, 
						-queryOptions => $self->{-queryOptions}, 
						-attributionsByInputSource => $self->{-attributionsByInputSource});
    push (@{$self->{-windowSets}}, $dolly);
}

sub browse {
    my ($self) = @_;
    $self->{MAIN_WINDOW} = Tk::MainWindow->new(-title => $self->{-mainWinTitle});
    $self->{MAIN_WINDOW}->withdraw;
    $self->makeWindowSet;
    $self->{-windowSets}[0]->importNamespaces($self->{-namespace});
    $self->{-windowSets}[0]->renderView(join (' ', sort keys %{$self->{-attributionsByInputSource}}));
    $self->{-windowSets}[0]->renderQueries($self->{-algae});
#    push (@{$self->{-windowSets}}, $self->{MAIN_WINDOW}->WindowSet(-RdfDB => $self->{-RdfDB}, -algae => $self->{-algae}, 
#								   -namespaceHandler => $self->{-namespaceHandler}, 
#								   -main => $self, -noColumns => $self->{-noColumns}));
    &Tk::MainLoop;
}

sub notifyExit {
    my ($self, $doomed) = @_;
    $self->{-windowSets} = [grep {$_ != $doomed} @{$self->{-windowSets}}];
    $self->{MAIN_WINDOW}->destroy if (!@{$self->{-windowSets}});
}

1;

# structure:
# RdfVisualizer holds n WindowSets
# WindowSet has:
#   ViewMaster    - selection of current view
#   QueryMaster   - selection of current query
#   StatementList ClientWindow for displaying current view of statements
#   Graph         ClientWindow for rendering highighted statement
#   QueryResults  ClientWindow table view of highlighted query 

# action maps:

# user enters a source view:
# ViewMaster::onReturn
#  if (!view = cache{sourceString})
#    view = new SourceView
#    ViewMaster::add(view)
#  Statements::refreshList
#   SourceView::getStatements

# user re-selects a source view:
# QueryMaster::onArrow
#  QueryView::activate(QueryMaster)
#    QueryView->setActive(QueryView)
#  Statements::refreshList...

# user enters a query:
# QueryMaster::onReturn
#  if (!view = cache{queryString})
#    view = new QueryView
#    QueryMaster::add(view)
#    ViewMaster::add(view)
#  Statements::refreshList
#   QueryView::getStatements
#    Results::addResults
#     resultsView = new ResultsView

# user re-selects a query view:
# QueryMaster::onArrow
#  QueryView::activate(QueryMaster)
#    QueryView->setActive(QueryView)
#  Statements::refreshList...

# user re-selects a query:
# ViewMaster::onArrow
#  QueryView::activate(ViewMaster)
#    QueryView->setActive(QueryView)
#  Statements::refreshList...

# user selects a query result
# QueryResults::onReturn
#  ResultsView::activate(QueryResults)
#   ViewMaster->setActive(ResultsView)
#  Statements::refreshList

# method conventions
#   setActive($newActive) - View tells the ListMaster that the View is active
#   acivate($self) - ListMaster tells the view that the view is active

# Key: class-name [Iimplements] functions
#                 P - pure
#                 V - virual
#                 O - overload
#                 a{b,c}d - abd and acd
#                 <set of un-enumerated functions>
# W3C::Rdf::TkVisualizer::WindowSet makeWindow destroyWindow->makeWindow changeLazyReification render{Statement,Node} <pass-through functions>
# W3C::Rdf::TkVisualizer::MatrixRenderer new->makeWidget PVmakeWidget highlight {startRows,addRow,endRows} destroy
#   W3C::Rdf::TkVisualizer::ListboxMatrixRenderer VmakeWidget V<widget functions>
#   W3C::Rdf::TkVisualizer::ColumnMatrixRenderer VmakeWidget V<widget functions>

# W3C::Rdf::TkVisualizer::ClientWindow new PVpopulateWindow
#   W3C::Rdf::TkVisualizer::StatementList VmakeWindow refreshList
# 
#   W3C::Rdf::TkVisualizer::MainWindow PVgetTitle makeWindow->{getTitle,populateWindow} {hide,show,view,destroy}Window
#     W3C::Rdf::TkVisualizer::Graph !new GraphMaster! VgetTitle VpopulateWindow graphStatement graphNode
#     W3C::Rdf::TkVisualizer::QueryResults VgetTitle VpopulateWindow OdestroyWindow setProofViews refresh
# 
#   W3C::Rdf::TkVisualizer::ListMaster PVmakeEntry makeWindow add onArrow PVonReturn get{ByString,Previous,Next} setActive passed
#     W3C::Rdf::TkVisualizer::ViewMaster VmakeEntry VonReturn getStatements->View::getStatements
#     W3C::Rdf::TkVisualizer::QueryMaster VmakeEntry VonReturn OonArrow
#     W3C::Rdf::TkVisualizer::GraphMaster VmakeEntry VonReturn
# 
# W3C::Rdf::TkVisualizer::View PVgetStatements getString activate
#   W3C::Rdf::TkVisualizer::SourceView VgetStatements
#   W3C::Rdf::TkVisualizer::QueryView VgetStatements Oactivate processAlgaeResults
#   W3C::Rdf::TkVisualizer::ProofView VgetStatements renderData
# 
#   W3C::Rdf::TkVisualizer::GraphView renderData Oactivate PVmatchesNode
#     W3C::Rdf::TkVisualizer::GraphStatementView VrenderGraphView VmatchesNode
#     W3C::Rdf::TkVisualizer::GraphNodeView VrenderGraphView VmatchesNode

# next:
# ViewMaster  -> StatementList frame   -> {Source,ProofView}View    - model on LabEntry
# QueryMaster -> QueryResults  window -> ProofQueryView             - model on ColorEditor
# GraphMaster -> Graph         window -> {Statement,Node}View

__END__

=head1 NAME

W3C::Rdf::TkVisualizer - PerlTk tool to view an RdfDB

=head1 SYNOPSIS

  use W3C::Rdf::RdfDB;
  use W3C::Rdf::TkVisualizer;
  my $rdfDB = new W3C::Rdf::RdfDB;
  my $rdfVisualizer = new W3C::Rdf::TkVisualizer($rdfDB);
  my $desc = $rdfDB->addDescription(...);
  $desc->addPredicateObject($predicate, $object);
  $rdfDB->browse;

=head1 DESCRIPTION

RdfVisualizer was a quick hack to provide a Tk interface to browse the
triples in an RdfDB. It provides a list of triples and a canvas where
the user may click on a triple and explore the surrounding nodes. It's
also my first PerlTk app so if you notice something that may be awry,
assume it is and let me know how to improve it.

This module is part of the W3C::Rdf CPAN module.

=head2 Hack

It's pricipal shortcoming is that I didn't use a defined interface to
NamespaceHandler but instead used its internal variables.

=head1 AUTHOR

Eric Prud\'hommeaux <eric@w3.org>

=head1 SEE ALSO

W3C::Rdf::RdfParser(3) perl(1).

=cut
