[Rt-commit] r2204 - in RT-View-Tree: . html html/Callbacks html/Callbacks/RT-Tree-View html/Callbacks/RT-Tree-View/Elements html/Callbacks/RT-Tree-View/Elements/Ticket html/Callbacks/RT-Tree-View/Elements/Ticket/ColumnMap html/Callbacks/RT-Tree-View/NoAuth html/Callbacks/RT-Tree-View/NoAuth/webrt.css html/Callbacks/RT-Tree-View/Ticket html/Callbacks/RT-Tree-View/Ticket/Elements html/Callbacks/RT-Tree-View/Ticket/Elements/Tabs html/Elements html/Elements/Ticket html/NoAuth html/Search html/Search/Elements html/Ticket html/Ticket/Elements inc inc/.author inc/Module inc/Module/Install lib lib/RT lib/RT/View share

jesse at bestpractical.com jesse at bestpractical.com
Thu Feb 10 13:55:29 EST 2005


Author: jesse
Date: Thu Feb 10 13:55:26 2005
New Revision: 2204

Added:
   RT-View-Tree/META.yml
   RT-View-Tree/Makefile.PL
   RT-View-Tree/html/
   RT-View-Tree/html/Callbacks/
   RT-View-Tree/html/Callbacks/RT-Tree-View/
   RT-View-Tree/html/Callbacks/RT-Tree-View/Elements/
   RT-View-Tree/html/Callbacks/RT-Tree-View/Elements/Ticket/
   RT-View-Tree/html/Callbacks/RT-Tree-View/Elements/Ticket/ColumnMap/
   RT-View-Tree/html/Callbacks/RT-Tree-View/Elements/Ticket/ColumnMap/ColumnMap
   RT-View-Tree/html/Callbacks/RT-Tree-View/NoAuth/
   RT-View-Tree/html/Callbacks/RT-Tree-View/NoAuth/webrt.css/
   RT-View-Tree/html/Callbacks/RT-Tree-View/Ticket/
   RT-View-Tree/html/Callbacks/RT-Tree-View/Ticket/Elements/
   RT-View-Tree/html/Callbacks/RT-Tree-View/Ticket/Elements/Tabs/
   RT-View-Tree/html/Callbacks/RT-Tree-View/Ticket/Elements/Tabs/Default
   RT-View-Tree/html/Elements/
   RT-View-Tree/html/Elements/ParseColumnDefs
   RT-View-Tree/html/Elements/Ticket/
   RT-View-Tree/html/Elements/Ticket/ColumnMap
   RT-View-Tree/html/Elements/TicketList
   RT-View-Tree/html/Elements/TicketListHeader
   RT-View-Tree/html/Elements/TicketListRow
   RT-View-Tree/html/NoAuth/
   RT-View-Tree/html/Search/
   RT-View-Tree/html/Search/Elements/
   RT-View-Tree/html/Search/Elements/BuildFormatString
   RT-View-Tree/html/Search/Elements/EditFormat
   RT-View-Tree/html/Search/Tree.html
   RT-View-Tree/html/Ticket/
   RT-View-Tree/html/Ticket/DisplayTree.html
   RT-View-Tree/html/Ticket/Elements/
   RT-View-Tree/html/Ticket/Elements/TreeEntry
   RT-View-Tree/inc/
   RT-View-Tree/inc/.author/
   RT-View-Tree/inc/Module/
   RT-View-Tree/inc/Module/Install/
   RT-View-Tree/inc/Module/Install.pm
   RT-View-Tree/inc/Module/Install/Base.pm
   RT-View-Tree/inc/Module/Install/Can.pm
   RT-View-Tree/inc/Module/Install/Fetch.pm
   RT-View-Tree/inc/Module/Install/Makefile.pm
   RT-View-Tree/inc/Module/Install/Metadata.pm
   RT-View-Tree/inc/Module/Install/RTx.pm
   RT-View-Tree/inc/Module/Install/Win32.pm
   RT-View-Tree/inc/Module/Install/WriteAll.pm
   RT-View-Tree/lib/
   RT-View-Tree/lib/RT/
   RT-View-Tree/lib/RT/View/
   RT-View-Tree/lib/RT/View/Tree.pm
   RT-View-Tree/share/
   RT-View-Tree/testdata
Modified:
   RT-View-Tree/   (props changed)
Log:
 r2291 at hualien (orig r289):  jesse | 2004-08-28T06:13:22.032283Z
  ----------------------------------------------------------------------
  r8412 at tinbook:  jesse | 2004-08-18T12:50:16.699550Z
   ----------------------------------------------------------------------
   r8313 at tinbook (orig r270):  leira | 2004-07-29T15:35:27.793410Z
   Saffron support center UI.
   
   ----------------------------------------------------------------------
   r8322 at tinbook (orig r272):  leira | 2004-08-02T19:53:24.428536Z
   Added a custom Login element.
   
   ----------------------------------------------------------------------
   r8323 at tinbook (orig r273):  leira | 2004-08-02T19:54:47.745281Z
   Latest changes for Saffron.
   
   ----------------------------------------------------------------------
   r8377 at tinbook (orig r276):  huberth | 2004-08-09T19:36:01.773910Z
    * Fixed a stupid mistake resulting in having only the last topic show up
      in any given category.
   
   
   ----------------------------------------------------------------------
   r8378 at tinbook (orig r277):  jesse | 2004-08-10T01:30:20.163721Z
    ----------------------------------------------------------------------
    r8301 at tinbook:  jesse | 2004-07-26T19:24:11.952576Z
    
    
    
    ----------------------------------------------------------------------
   
   ----------------------------------------------------------------------
   r8406 at tinbook (orig r280):  alexmv | 2004-08-13T15:37:11.843667Z
    * First pass at branding
   
   ----------------------------------------------------------------------
   r8407 at tinbook (orig r281):  leira | 2004-08-15T05:09:40.210996Z
   Latest supportcenter files.
   
   ----------------------------------------------------------------------
   r8408 at tinbook (orig r282):  leira | 2004-08-15T05:11:40.890274Z
   Latest callcenter files.
   
   ----------------------------------------------------------------------
   r8409 at tinbook (orig r283):  leira | 2004-08-15T05:15:29.628265Z
   UPromise templates.
   
   ----------------------------------------------------------------------
   r8410 at tinbook (orig r284):  leira | 2004-08-15T05:19:16.572435Z
   User_Local.pm for Saffron.
   
   ----------------------------------------------------------------------
   r8411 at tinbook (orig r285):  huberth | 2004-08-18T00:55:04.302183Z
    * Quick Ticket + Ticket Templates now should work correctly.  In the past
      not all fields (notably Subject, Content, and DueDate) were not used
      correctly; this should be ok now.
    * Ticket Templates now override Queue/Global defaults, instead of the other
      way around.  (Possible issue: do user-specified basics then override the 
      Ticket Templates?  I haven't tested this enough.)
   
   
   
   ----------------------------------------------------------------------
  
  ----------------------------------------------------------------------
  r8413 at tinbook:  jesse | 2004-08-18T12:57:19.812891Z
  bumped versions
  ----------------------------------------------------------------------
  r8452 at tinbook:  jesse | 2004-08-28T06:12:40.750934Z
  first cut of new wolfram treeview
  ----------------------------------------------------------------------
 


Added: RT-View-Tree/META.yml
==============================================================================
--- (empty file)
+++ RT-View-Tree/META.yml	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,10 @@
+name: RT-View-Tree
+version: 0.2
+abstract: RT View-Tree Extension
+license: unknown
+distribution_type: module
+no_index:
+  directory:
+    - html
+    - inc
+generated_by: Module::Install version 0.33

Added: RT-View-Tree/Makefile.PL
==============================================================================
--- (empty file)
+++ RT-View-Tree/Makefile.PL	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,5 @@
+use inc::Module::Install;
+
+RTx('RT-View-Tree');
+version('0.2');
+&WriteAll;

Added: RT-View-Tree/html/Callbacks/RT-Tree-View/Elements/Ticket/ColumnMap/ColumnMap
==============================================================================
--- (empty file)
+++ RT-View-Tree/html/Callbacks/RT-Tree-View/Elements/Ticket/ColumnMap/ColumnMap	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,6 @@
+<%ARGS>
+$COLUMN_MAP => undef
+</%ARGS>
+<%init>
+$COLUMN_MAP->{'_RT_TreeView_Indent'} = { value => sub { my $ticket = shift; my $depth = shift; return "&nbsp;&nbsp;"x$depth} };
+</%init>

Added: RT-View-Tree/html/Callbacks/RT-Tree-View/Ticket/Elements/Tabs/Default
==============================================================================
--- (empty file)
+++ RT-View-Tree/html/Callbacks/RT-Tree-View/Ticket/Elements/Tabs/Default	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,26 @@
+%# BEGIN LICENSE BLOCK
+%# 
+%#  Copyright (c) 2002-2003 Jesse Vincent <jesse at bestpractical.com>
+%#  
+%#  This program is free software; you can redistribute it and/or modify
+%#  it under the terms of version 2 of the GNU General Public License 
+%#  as published by the Free Software Foundation.
+%# 
+%#  A copy of that license should have arrived with this
+%#  software, but in any event can be snarfed from www.gnu.org.
+%# 
+%#  This program is distributed in the hope that it will be useful,
+%#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+%#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%#  GNU General Public License for more details.
+%# 
+%# END LICENSE BLOCK
+
+<%init>
+$tabs->{'this'}->{'subtabs'}->{'_ZZ-Treeview'} = { title =>loc("Tree"),
+                          path  => "/Search/Tree.html?id=" . $Ticket->id} if ($Ticket->id);
+</%init>
+<%args>
+$tabs =>undef
+$Ticket => undef
+</%args>

Added: RT-View-Tree/html/Elements/ParseColumnDefs
==============================================================================
--- (empty file)
+++ RT-View-Tree/html/Elements/ParseColumnDefs	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,81 @@
+%# BEGIN LICENSE BLOCK;
+%# 
+%# Copyright (c) 1996-2003 Jesse Vincent <jesse at bestpractical.com>
+%# 
+%# (Except where explictly superceded by other copyright notices)
+%# 
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%# 
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+%# General Public License for more details.
+%# 
+%# Unless otherwise specified, all modifications, corrections or
+%# extensions to this work which alter its source code become the
+%# property of Best Practical Solutions, LLC when submitted for
+%# inclusion in the work.
+%# 
+%# 
+%# END LICENSE BLOCK
+
+<%ARGS>
+$Format
+</%ARGS>
+
+<%init>
+use Regexp::Common qw(delimited);
+my @Columns;
+#my $quoted = qr[$RE{delimited}{-delim=>qq{\'\"}}|(?:\{|\}|\w|\.)+];
+my $justquoted = qr[$RE{delimited}{-delim=>qq{\'\"}}];
+#my $quoted =        $RE{quoted}{-esc};
+my $word = qr [(?:\{|\}|\w|\.)+];
+
+while ($Format =~ /($justquoted|$word)/igx) {
+    my $col = $1;
+
+    if ($col =~ /^$RE{quoted}{-esc}$/) {
+        substr($col,0,1) = "";
+        substr($col,-1,1) = "";
+    }
+
+    my $colref;
+    if ( $col =~ s/\/STYLE:(.*?)$//io ) {
+        $colref->{'style'} = $1;
+    }
+    if ( $col =~ s/\/CLASS:(.*?)$//io ) {
+        $colref->{'class'} = $1;
+    }
+    if ( $col =~ s/\/TITLE:(.*?)$//io ) {
+        $colref->{'title'} = $1;
+    }
+    if ( $col =~ /__(.*?)__/gio ) {
+        my @subcols;
+        while ( $col =~ s/^(.*?)__(.*?)__//o ) {
+            push ( @subcols, $1 ) if ($1);
+            push ( @subcols, "__$2__" );
+            $colref->{'attribute'} = $2;
+        }
+        push ( @subcols, $col );
+        @{ $colref->{'output'} } = @subcols;
+    }
+    else {
+        @{ $colref->{'output'} } = ( "__" . $col . "__" );
+        $colref->{'attribute'} = $col;
+    }
+    
+    if ( !$colref->{'title'} && grep { /^__(.*?)__$/io }
+        @{ $colref->{'output'} } )
+    {   
+        $colref->{'title'}     = $1;
+        $colref->{'attribute'} = $1;
+    }
+
+
+    push @Columns, $colref;
+}
+    return(@Columns);
+</%init>

Added: RT-View-Tree/html/Elements/Ticket/ColumnMap
==============================================================================
--- (empty file)
+++ RT-View-Tree/html/Elements/Ticket/ColumnMap	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,387 @@
+%# BEGIN LICENSE BLOCK;
+%# 
+%# Copyright (c) 1996-2003 Jesse Vincent <jesse at bestpractical.com>
+%# 
+%# (Except where explictly superceded by other copyright notices)
+%# 
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%# 
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+%# General Public License for more details.
+%# 
+%# Unless otherwise specified, all modifications, corrections or
+%# extensions to this work which alter its source code become the
+%# property of Best Practical Solutions, LLC when submitted for
+%# inclusion in the work.
+%# 
+%# 
+%# END LICENSE BLOCK
+
+<%ARGS>
+$Name => undef
+$Attr => undef
+</%ARGS>
+
+<%perl>
+return ColumnMap($Name, $Attr);
+</%perl>
+
+<%INIT>
+our ( $COLUMN_MAP, $CUSTOM_FIELD_MAP );
+
+sub ColumnMap {
+    my $name = shift;
+    my $attr = shift;
+
+    # First deal with the simple things from the map
+    if ( $COLUMN_MAP->{$name} ) {
+        return ( $COLUMN_MAP->{$name}->{$attr} );
+    }
+
+    # now, let's deal with harder things, like Custom Fields
+
+    elsif ( $name =~ /^(?:CF|CustomField).(.*)$/ ) {
+        my $field = $1;
+        my $cf;
+        if ( $CUSTOM_FIELD_MAP->{$field} ) {
+            $cf = $CUSTOM_FIELD_MAP->{$field};
+        }
+        else {
+
+            $cf = RT::CustomField->new( $session{'CurrentUser'} );
+
+            if ( $field =~ /^(.+?)\.{(.+)}$/ ) {
+                $cf->LoadByNameAndQueue( Queue => $1, Name => $2 );
+            }
+            else {
+                $field = $1 if $field =~ /^{(.+)}$/;    # trim { }
+                $cf->LoadByNameAndQueue( Queue => "0", Name => $field );
+            }
+            $CUSTOM_FIELD_MAP->{$field} = $cf if ( $cf->id );
+        }
+
+        unless ( $cf->id ) {
+            return undef;
+        }
+
+        if ( $attr eq 'attribute' ) {
+            return (undef);
+        }
+        elsif ( $attr eq 'title' ) {
+            return ( $cf->Name );
+        }
+        elsif ( $attr eq 'value' ) {
+            my $value = eval "sub {
+                    my \$values = \$_[0]->CustomFieldValues('" . $cf->id . "');
+                    return ( join( ', ', map { \$_->Content } \@{ \$values->ItemsArrayRef } ))
+                  }" || die $@;
+            return ($value);
+        }
+    }
+}
+
+$COLUMN_MAP = {
+    QueueName => {
+        attribute => 'Queue',
+        title     => 'Queue',
+        value     => sub { return $_[0]->QueueObj->Name }
+    },
+    OwnerName => {
+        title     => 'Owner',
+        attribute => 'Owner',
+        value     => sub { return $_[0]->OwnerObj->Name }
+    },
+    id => {
+        attribute => 'id',
+        align     => 'right',
+        value     => sub { return $_[0]->id }
+    },
+    Status => {
+        attribute => 'Status',
+        value     => sub { return $_[0]->Status }
+    },
+    Subject => {
+        attribute => 'Subject',
+        value => sub { return $_[0]->Subject || "(" . loc('No subject') . ")" }
+    },
+    ExtendedStatus => {
+        title     => 'Status',
+        attribute => 'Status',
+        value     => sub {
+            my $Ticket = shift;
+
+            if ( $Ticket->HasUnresolvedDependencies ) {
+                if (   $Ticket->HasUnresolvedDependencies( Type => 'approval' )
+                    or $Ticket->HasUnresolvedDependencies( Type => 'code' ) )
+                {
+                    return "<em>" . loc('(pending approval)') . "</em>";
+                }
+                else {
+                    return "<em>" . loc('(pending other Collection)') . "</em>";
+                }
+            }
+            else {
+                return loc( $Ticket->Status );
+            }
+
+          }
+    },
+    Priority => {
+        attribute => 'Priority',
+        value     => sub { return $_[0]->Priority }
+    },
+    InitialPriority => {
+        attribute => 'InitialPriority',
+        value     => sub { return $_[0]->InitialPriority }
+    },
+    FinalPriority => {
+        attribute => 'FinalPriority',
+        value     => sub { return $_[0]->FinalPriority }
+    },
+    EffectiveId => {
+        attribute => 'EffectiveId',
+        value     => sub { return $_[0]->EffectiveId }
+    },
+    Type => {
+        attribute => 'Type',
+        value     => sub { return $_[0]->Type }
+    },
+    TimeWorked => {
+        attribute => 'TimeWorked',
+        value     => sub { return $_[0]->TimeWorked }
+    },
+    TimeLeft => {
+        attribute => 'TimeLeft',
+        value     => sub { return $_[0]->TimeLeft }
+    },
+    TimeEstimated => {
+        attribute => 'TimeEstimated',
+        value     => sub { return $_[0]->TimeEstimated }
+    },
+    Requestors => {
+        value => sub { return $_[0]->Requestors->MemberEmailAddressesAsString }
+    },
+    Cc => {
+        value => sub { return $_[0]->Cc->MemberEmailAddressesAsString }
+    },
+    AdminCc => {
+        value => sub { return $_[0]->AdminCc->MemberEmailAddressesAsString }
+    },
+    StartsRelative => {
+        title     => 'Starts',
+        attribute => 'Starts',
+        value     => sub { return $_[0]->StartsObj->AgeAsString }
+    },
+    StartedRelative => {
+        title     => 'Started',
+        attribute => 'Started',
+        value     => sub { return $_[0]->StartedObj->AgeAsString }
+    },
+    CreatedRelative => {
+        title     => 'Created',
+        attribute => 'Created',
+        value     => sub { return $_[0]->CreatedObj->AgeAsString }
+    },
+    LastUpdatedRelative => {
+        title     => 'LastUpdated',
+        attribute => 'LastUpdated',
+        value     => sub { return $_[0]->LastUpdatedObj->AgeAsString }
+    },
+    ToldRelative => {
+        title     => 'Told',
+        attribute => 'Told',
+        value     => sub { return $_[0]->ToldObj->AgeAsString }
+    },
+    DueRelative => {
+        title     => 'Due',
+        attribute => 'Due',
+        value     => sub { return $_[0]->DueObj->AgeAsString }
+    },
+    ResolvedRelative => {
+        title     => 'Resolved',
+        attribute => 'Resolved',
+        value     => sub { return $_[0]->ResolvedObj->AgeAsString }
+    },
+    Starts => {
+        attribute => 'Starts',
+        value     => sub { return $_[0]->StartsObj->AsString }
+    },
+    Started => {
+        attribute => 'Started',
+        value     => sub { return $_[0]->StartedObj->AsString }
+    },
+    Created => {
+        attribute => 'Created',
+        value     => sub { return $_[0]->CreatedObj->AsString }
+    },
+    CreatedBy => {
+        attribute => 'CreatedBy',
+        value     => sub { return $_[0]->CreatorObj->Name }
+    },
+    LastUpdated => {
+        attribute => 'LastUpdated',
+        value     => sub { return $_[0]->LastUpdatedObj->AsString }
+    },
+    LastUpdatedBy => {
+        attribute => 'LastUpdatedBy',
+        value     => sub { return $_[0]->LastUpdatedByObj->Name }
+    },
+    Told => {
+        attribute => 'Told',
+        value     => sub { return $_[0]->ToldObj->AsString }
+    },
+    Due => {
+        attribute => 'Due',
+        value     => sub { return $_[0]->DueObj->AsString }
+    },
+    Resolved => {
+        attribute => 'Resolved',
+        value     => sub { return $_[0]->ResolvedObj->AsString }
+    },
+
+    DependedOnBy => {
+        value => sub {
+            my $links = $_[0]->DependedOnBy;
+            return (
+                join(
+                    "<br>",
+                    map {
+                            '<A HREF="'
+                          . $_->BaseURI->Resolver->HREF . '">'
+                          . ( $_->BaseIsLocal ? $_->LocalBase : $_->Base )
+                          . '</A>'
+                      } @{ $links->ItemsArrayRef }
+                )
+            );
+          }
+    },
+    Members => {
+        value => sub {
+            my $links = $_[0]->Members;
+            return (
+                join(
+                    "<br>",
+                    map {
+                            '<A HREF="'
+                          . $_->BaseURI->Resolver->HREF . '">'
+                          . ( $_->BaseIsLocal ? $_->LocalBase : $_->Base )
+                          . '</A>'
+                      } @{ $links->ItemsArrayRef }
+                )
+            );
+          }
+    },
+    Children => {
+        value => sub {
+            my $links = $_[0]->Members;
+            return (
+                join(
+                    "<br>",
+                    map {
+                            '<A HREF="'
+                          . $_->BaseURI->Resolver->HREF . '">'
+                          . ( $_->BaseIsLocal ? $_->LocalBase : $_->Base )
+                          . '</A>'
+                      } @{ $links->ItemsArrayRef }
+                )
+            );
+          }
+    },
+    ReferredToBy => {
+        value => sub {
+            my $links = $_[0]->ReferredToBy;
+            return (
+                join(
+                    "<br>",
+                    map {
+                            '<A HREF="'
+                          . $_->BaseURI->Resolver->HREF . '">'
+                          . ( $_->BaseIsLocal ? $_->LocalBase : $_->Base )
+                          . '</A>'
+                      } @{ $links->ItemsArrayRef }
+                )
+            );
+          }
+    },
+
+    DependsOn => {
+        value => sub {
+            my $links = $_[0]->DependsOn;
+            return (
+                join(
+                    "<br>",
+                    map {
+                            '<A HREF="'
+                          . $_->TargetURI->Resolver->HREF . '">'
+                          . ( $_->TargetIsLocal ? $_->LocalTarget : $_->Target )
+                          . '</A>'
+                      } @{ $links->ItemsArrayRef }
+                )
+            );
+          }
+    },
+    MemberOf => {
+        value => sub {
+            my $links = $_[0]->MemberOf;
+            return (
+                join(
+                    "<br>",
+                    map {
+                            '<A HREF="'
+                          . $_->TargetURI->Resolver->HREF . '">'
+                          . ( $_->TargetIsLocal ? $_->LocalTarget : $_->Target )
+                          . '</A>'
+                      } @{ $links->ItemsArrayRef }
+                )
+            );
+          }
+    },
+    Parents => {
+        value => sub {
+            my $links = $_[0]->MemberOf;
+            return (
+                join(
+                    "<br>",
+                    map {
+                            '<A HREF="'
+                          . $_->TargetURI->Resolver->HREF . '">'
+                          . ( $_->TargetIsLocal ? $_->LocalTarget : $_->Target )
+                          . '</A>'
+                      } @{ $links->ItemsArrayRef }
+                )
+            );
+          }
+    },
+    RefersTo => {
+        value => sub {
+            my $links = $_[0]->RefersTo;
+            return (
+                join(
+                    "<br>",
+                    map {
+                            '<A HREF="'
+                          . $_->TargetURI->Resolver->HREF . '">'
+                          . ( $_->TargetIsLocal ? $_->LocalTarget : $_->Target )
+                          . '</A>'
+                      } @{ $links->ItemsArrayRef }
+                )
+            );
+          }
+    },
+
+    '_CLASS' => {
+        value => sub { return $_[1] % 2 ? 'oddline' : 'evenline' }
+    },
+
+};
+
+
+
+# }}}
+$m->comp( '/Elements/Callback', COLUMN_MAP    => $COLUMN_MAP, _CallbackName => 'ColumnMap');
+</%INIT>

Added: RT-View-Tree/html/Elements/TicketList
==============================================================================
--- (empty file)
+++ RT-View-Tree/html/Elements/TicketList	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,121 @@
+%# BEGIN LICENSE BLOCK;
+%# 
+%# Copyright (c) 1996-2003 Jesse Vincent <jesse at bestpractical.com>
+%# 
+%# (Except where explictly superceded by other copyright notices)
+%# 
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%# 
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+%# General Public License for more details.
+%# 
+%# Unless otherwise specified, all modifications, corrections or
+%# extensions to this work which alter its source code become the
+%# property of Best Practical Solutions, LLC when submitted for
+%# inclusion in the work.
+%# 
+%# 
+%# END LICENSE BLOCK
+
+%# If you're having TicketList display a single record, you need
+%# to wrap the calls in your own table(s).
+% unless (defined $SingleRecord) {
+<TABLE BORDER=0 cellspacing=0 cellpadding=1 WIDTH=100%>
+% }
+
+% if ($ShowHeader) {
+<& /Elements/TicketListHeader, 
+    Format => \@Format, 
+    AllowSorting => $AllowSorting, 
+    Order => $Order, 
+    Query => $Query,
+    Rows => $Rows,
+    Page => $Page,
+    OrderBy => $OrderBy , 
+    BaseURL => $BaseURL,
+    maxitems => \$maxitems &> 
+% }
+
+% if (defined $SingleRecord) {
+<&   /Elements/TicketListRow, Format => \@Format, i => 0, record => $SingleRecord, maxitems => $maxitems &>
+% } else {
+%   my $i;
+%   while (my $record = $Collection->Next) {
+%   $i++;
+<&   /Elements/TicketListRow, Format => \@Format, i => $i, record => $record, maxitems => $maxitems &>
+%   }
+% }
+
+% unless (defined $SingleRecord) {
+</TABLE>
+% }
+
+% if ($ShowNavigation) {
+<hr>
+<&|/l, $Page, int($TotalFound/$Rows)+1&>Page [_1] of [_2]</&>
+
+<%perl>
+my $prev =  $m->comp('/Elements/QueryString',
+                     Query => $Query,
+                     Format => $Format,
+                     Rows => $Rows,
+                     OrderBy => $OrderBy,
+                     Order => $Order,
+                     Page => ($Page-1));
+my $next =  $m->comp('/Elements/QueryString',
+                     Query => $Query,
+                     Format => $Format,
+                     Rows => $Rows,
+                     OrderBy => $OrderBy,
+                     Order => $Order,
+                     Page => ($Page+1));
+</%perl>
+% if ($Page > 1) {
+<A href="<%$BaseURL%><%$prev%>"><&|/l&>Previous Page</&></a>
+% }
+% if (($Page * $Rows) < $TotalFound) {
+<A href="<%$BaseURL%><%$next%>"><&|/l&>Next Page</&></a>
+% }
+% }
+<%INIT>
+my $maxitems;
+
+$Format ||= $RT::DefaultSearchResultFormat;
+# Scrub the html of the format string to remove any potential nasties.
+$Format = $m->comp('/Elements/ScrubHTML', Content => $Format);
+
+$Rows ||= '25'; # we need a positive value
+
+unless ($Collection) {
+        $Collection = RT::Tickets->new($session{'CurrentUser'});
+        $Collection->FromSQL($Query);
+}
+
+my (@Format) = $m->comp('/Elements/ParseColumnDefs', Format => $Format);
+
+$Collection->OrderBy(FIELD => $OrderBy, ORDER => $Order); 
+$Collection->RowsPerPage($Rows);
+$Collection->GotoPage($Page-1); # SB uses page 0 as the first page
+my $TotalFound =  $Collection->CountAll();
+
+</%INIT>
+<%ARGS>
+$Query => undef
+$Rows => 10
+$Page => 1
+$Title => 'Ticket Search'
+$Collection => undef
+$SingleRecord => undef
+$AllowSorting => undef
+$Order => undef
+$OrderBy => undef
+$BaseURL => undef
+$Format => $RT::DefaultSearchResultFormat
+$ShowNavigation => 1
+$ShowHeader => 1
+</%ARGS>

Added: RT-View-Tree/html/Elements/TicketListHeader
==============================================================================
--- (empty file)
+++ RT-View-Tree/html/Elements/TicketListHeader	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,91 @@
+%# BEGIN LICENSE BLOCK;
+%# 
+%# Copyright (c) 1996-2003 Jesse Vincent <jesse at bestpractical.com>
+%# 
+%# (Except where explictly superceded by other copyright notices)
+%# 
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%# 
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+%# General Public License for more details.
+%# 
+%# Unless otherwise specified, all modifications, corrections or
+%# extensions to this work which alter its source code become the
+%# property of Best Practical Solutions, LLC when submitted for
+%# inclusion in the work.
+%# 
+%# 
+%# END LICENSE BLOCK
+
+<%ARGS>
+ at Format => undef
+$AllowSorting => undef
+$Order=>undef
+$BaseURL => undef
+$Query => undef
+$Rows => undef
+$Page => undef
+$maxitems => undef
+</%ARGS>
+<TR>
+<%perl>
+
+my %generic_query_args = ( Query => $Query, Rows => $Rows, Page => $Page );
+
+my $item = 0;
+$$maxitems = 0;
+foreach my $col (@Format) {
+    $item++;
+    $$maxitems = $item if $item > $$maxitems;
+    if ( $col->{title} eq 'NEWLINE' ) {
+        $m->out('</TR>       <TR>');
+	$item = 0;
+    }
+    else {
+        $m->out('<TH align="center">');
+        my $title = $col->{title};
+        $title =~ s/^__(.*)__$/$1/o;
+        $title = ( $m->comp('/Elements/Ticket/ColumnMap', 
+                     Name => $title, 
+                     Attr => 'title' 
+                 )  
+                     || $title
+                 );
+        if (   $AllowSorting
+            && $col->{'attribute'}
+            && $m->comp('/Elements/Ticket/ColumnMap',
+                          Name => $col->{'attribute'},
+                          Attr => 'attribute' ) 
+           )
+        {
+
+            $m->out(
+                '<a href="' . $BaseURL 
+                  . $m->comp(
+                    '/Elements/QueryString',
+                    %generic_query_args,
+                    OrderBy => (
+                        $m->comp('/Elements/Ticket/ColumnMap',
+                          Name => $col->{'attribute'},
+                          Attr => 'attribute' 
+                    )
+                          || $col->{'attribute'}
+                    ),
+                    Order => ( $ARGS{'Order'} eq 'ASC' ? 'DESC' : 'ASC' )
+                  ).
+                  '">' . loc($title) . '</a>'
+            );
+        }
+        else {
+            $m->out( loc($title) );
+        }
+        $m->out('</TH>');
+    }
+}
+</%perl>
+</TR>

Added: RT-View-Tree/html/Elements/TicketListRow
==============================================================================
--- (empty file)
+++ RT-View-Tree/html/Elements/TicketListRow	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,69 @@
+%# BEGIN LICENSE BLOCK;
+%# 
+%# Copyright (c) 1996-2003 Jesse Vincent <jesse at bestpractical.com>
+%# 
+%# (Except where explictly superceded by other copyright notices)
+%# 
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%# 
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+%# General Public License for more details.
+%# 
+%# Unless otherwise specified, all modifications, corrections or
+%# extensions to this work which alter its source code become the
+%# property of Best Practical Solutions, LLC when submitted for
+%# inclusion in the work.
+%# 
+%# 
+%# END LICENSE BLOCK
+
+<%ARGS>
+$i => undef
+ at Format => undef
+$record => undef
+$maxitems => undef
+$Depth => undef
+$Warning => undef
+</%ARGS>
+
+<%PERL>
+$m->out( '<TR class="' . ( $Warning ? 'warnline' : $i % 2 ? 'oddline' : 'evenline' ) . '" >' );
+my $item;
+foreach my $column (@Format) {
+    if ( $column->{title} eq 'NEWLINE' ) {
+	while ($item < $maxitems) {
+	    $m->out("<td>&nbsp;</td>\n");
+	    $item++;
+	}
+	$item = 0;
+        $m->out('</TR>');
+        $m->out( '<TR class="' . 
+               ( $Warning ? 'warnline' : $i % 2 ? 'oddline' : 'evenline' ) . '" >' );
+        next;
+    }
+    $item++;
+    $m->out('<td align="left">');
+    foreach my $subcol ( @{ $column->{output} } ) {
+        if ( $subcol =~ /^__(.*?)__$/o ) {
+            my $col = $1;
+            my $value = $m->comp('/Elements/Ticket/ColumnMap', Name => $col, Attr => 'value');
+
+            if ( $value && ref($value)) {
+                $m->out( &{ $value } ( $record, $i ) );
+            } else {
+                $m->out($value );
+            }
+        }
+        else {
+            $m->out( Encode::decode_utf8($subcol) );
+        }
+    }
+    $m->out('</td>');
+}
+$m->out('</TR>');
+</%PERL>

Added: RT-View-Tree/html/Search/Elements/BuildFormatString
==============================================================================
--- (empty file)
+++ RT-View-Tree/html/Search/Elements/BuildFormatString	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,177 @@
+<%args>
+$Format => undef
+%cfqueues => undef
+</%args>
+<%init>
+
+unless ($Format) {         
+    $Format = $RT::DefaultSearchResultFormat;
+}   
+    
+my @fields = (
+    "QueueName",           "OwnerName",
+    "id",                  "Status",
+    "Subject",             "ExtendedStatus",
+    "Priority",            "InitialPriority",
+    "FinalPriority",       "EffectiveId",
+    "Type",                "TimeWorked",
+    "TimeLeft",            "TimeEstimated",
+    "Requestors",          "Cc",
+    "AdminCc",             "StartsRelative",
+    "StartedRelative",     "CreatedRelative",
+    "LastUpdatedRelative", "ToldRelative",
+    "DueRelative",         "ResolvedRelative",
+    "Starts",              "Started",
+    "Created",             "CreatedBy",
+    "LastUpdated",         "LastUpdatedBy",
+    "Told",                "Due",
+    "Resolved",            "NEWLINE",
+    "RefersTo",	           "ReferredToBy",
+    "DependsOn",           "DependedOnBy",
+    "MemberOf",            "Members",
+    "Parents",             "Children",
+    "-",
+);
+
+my $CustomFields = RT::CustomFields->new( $session{'CurrentUser'});
+foreach (keys %cfqueues) {
+    my $id = $_;
+    $id =~ s/^.'*(.*).'*$/$1/;
+    # Gotta load up the $queue object, since queues get stored by name now.
+    my $queue = RT::Queue->new($session{'CurrentUser'});
+    $queue->Load($id);
+    $CustomFields->LimitToQueue($queue->Id);
+}
+$CustomFields->LimitToGlobal;
+
+while ( my $CustomField = $CustomFields->Next ) {
+    my $queuestr;
+    if ($CustomField->QueueObj && $CustomField->QueueObj->Id != 0) {
+	$queuestr = $CustomField->QueueObj->Name . ".";
+    }
+    push @fields, "CustomField." . $queuestr . "{" . $CustomField->Name . "}";
+}
+
+my ( @seen);
+
+my @format = split( /,\s*/, $Format );
+foreach my $field (@format) {
+    my %column = ();
+    $field =~ s/'(.*)'/$1/;
+    my ( $prefix, $suffix );
+    if ( $field =~ m/(.*)__(.*)__(.*)/ ) {
+        $prefix = $1;
+        $suffix = $3;
+        $field  = $2;
+    }
+    $field = "<blank>" if !$field;
+    $column{Prefix} = $prefix;
+    $column{Suffix} = $suffix;
+    $field =~ s/\s*(.*)\s*/$1/;
+    $column{Column} = $field;
+    push @seen, \%column;
+}
+
+if ( $ARGS{"RemoveCol"} ) {
+    my $index  = $ARGS{'CurrentDisplayColumns'};
+    my $column = $seen[$index];
+    if ($index) {
+        delete $seen[$index];
+        my @temp = @seen;
+        @seen = ();
+        foreach my $element (@temp) {
+            next unless $element;
+            push @seen, $element;
+        }
+    }
+}
+elsif ( $ARGS{"AddCol"} ) {
+    if ( defined $ARGS{'SelectDisplayColumns'} ) {
+	my $selected = $ARGS{'SelectDisplayColumns'};
+	my @columns;
+	if (ref($selected) eq 'ARRAY') {
+	    @columns = @$selected;
+	} else {
+	    push @columns, $selected;
+	}
+	foreach my $col (@columns) {
+	    my %column = ();
+	    $column{Column} = $fields[ $col ];
+	    
+	    if ( $ARGS{Face} eq "Bold" ) {
+		$column{Prefix} .= "<B>";
+	    }
+	    if ( $ARGS{Face} eq "Italic" ) {
+		$column{Prefix} .= "<I>";
+	    }
+	    if ( $ARGS{Size} ) {
+		$column{Prefix} .= "<" . $ARGS{Size} . ">";
+	    }
+	    if ( $ARGS{Link} eq "Display" ) {
+		$column{Prefix} .= "<A HREF=\"".$RT::WebPath."/Ticket/Display.html?id=__id__\">";
+	    }
+	    elsif ( $ARGS{Link} eq "Take" ) {
+		$column{Prefix} .=
+		    "<A HREF=\"".$RT::WebPath."/Ticket/Display.html?Action=Take&id=__id__\">";
+	    }
+	    elsif ( $ARGS{Link} eq "Tree" ) {
+		$column{Prefix} .=
+		    "<A HREF=\"".$RT::WebPath."/Ticket/DisplayTree.html?id=__id__&UseFormat=1\">";
+	    }
+    
+	    my $suffix;
+	    if ( $ARGS{'Link'} eq "Display" || 
+             $ARGS{'Link'} eq "Take"    ||
+             $ARGS{'Link'} eq "Tree"
+           ) {
+		$column{Suffix} .= "</a>";
+	    }
+	    if ( $ARGS{Size} ) {
+		$column{Suffix} .= "</" . $ARGS{Size} . ">";
+	    }
+	    if ( $ARGS{Face} eq "Italic" ) {
+		$column{Suffix} .= "</I>";
+	    }
+	    if ( $ARGS{Face} eq "Bold" ) {
+		$column{Suffix} .= "</B>";
+	    }
+	    if ( $ARGS{Title} ) {
+		$column{Suffix} .= "/TITLE:" . $ARGS{Title};
+	    }
+	    push @seen, \%column;
+	}
+    }
+}
+elsif ( $ARGS{"ColUp"} ) {
+    my $index = $ARGS{'CurrentDisplayColumns'};
+    if ( defined $index && ( $index - 1 ) >= 0 ) {
+        my $column = $seen[$index];
+        $seen[$index]       = $seen[ $index - 1 ];
+        $seen[ $index - 1 ] = $column;
+        $ARGS{CurrentDisplayColumns}     = $index - 1;
+    }
+}
+elsif ( $ARGS{"ColDown"} ) {
+    my $index = $ARGS{'CurrentDisplayColumns'};
+    if ( defined $index && ( $index + 1 ) < scalar @seen ) {
+        my $column = $seen[$index];
+        $seen[$index]       = $seen[ $index + 1 ];
+        $seen[ $index + 1 ] = $column;
+        $ARGS{CurrentDisplayColumns}     = $index + 1;
+    }
+}
+
+$Format = "";
+foreach my $field (@seen) {
+    next unless $field;
+    $Format .= ", \n" if $Format;
+    $Format .= "'";
+    $Format .= $field->{Prefix};
+    $Format .= "__" . $field->{Column} . "__" if ( $field->{Column} ne "<blank>" ) ;
+    $Format .= $field->{Suffix};
+    $Format .= "'";
+}
+return($Format, \@fields, \@seen);
+
+</%init>
+

Added: RT-View-Tree/html/Search/Elements/EditFormat
==============================================================================
--- (empty file)
+++ RT-View-Tree/html/Search/Elements/EditFormat	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,78 @@
+<table>
+<tr>
+<td>
+<&|/l&>Available Columns</&>:
+</td>
+<td>
+Format:
+</td>
+<td></td>
+<td>
+<&|/l&>Show Columns</&>:
+</td>
+<tr>
+<td valign=top>
+<select size="6" name="SelectDisplayColumns" multiple>
+% my $i = 0;
+% while ($i < scalar @$AvailableColumns) {
+% my $field = $AvailableColumns->[$i];
+% if ($field) {
+<option value=<%$i%>
+><%$field%></option>
+% }
+% $i++;
+% }
+</select>
+</td>
+<td>
+Link:
+<select name=Link>
+<option value="None">-</option>
+<option value="Display">Display</option>
+<option value="Take">Take</option>
+<option value="Tree">Tree</option>
+</select>
+<br>Title: <input name="Title" size=10>
+<br>Size:
+<select name=Size>
+<option value="">-</option>
+<option value="Small">Small</option>
+<option value="Large">Large</option>
+</select>
+<br>Face:
+<select name=Face>
+<option value="">-</option>
+<option value="Bold">Bold</option>
+<option value="Italic">Italic</option>
+</select>
+</td>
+<td>
+<input type=submit name="AddCol" value="->">
+</td>
+<td valign=top>
+<select size=4 name="CurrentDisplayColumns" style="width : 100%">
+% $i = 0;
+% while ($i < scalar @$CurrentFormat) {
+% my $field = $CurrentFormat->[$i];
+% if ($field) {
+<option value=<%$i%>><%$field->{Column}%></option>
+% }
+% $i++;
+% }
+</select>
+<br>
+<center>
+<input type="submit" name="ColUp" value="^">
+<input type="submit" name="ColDown" value="v">
+<input type="submit" name="RemoveCol" value="<%loc('Delete')%>">
+</center>
+</td>
+<td colspan=3 align=center>
+</td>
+</tr>
+</table>
+
+<%ARGS>
+$CurrentFormat => undef
+$AvailableColumns => undef
+</%ARGS>

Added: RT-View-Tree/html/Search/Tree.html
==============================================================================
--- (empty file)
+++ RT-View-Tree/html/Search/Tree.html	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,79 @@
+<& /Elements/Header &>
+<TABLE BORDER=0 cellspacing=0 cellpadding=1 WIDTH=100%>
+
+<%perl>
+
+my ($title, $ticketcount);
+my $tickets = RT::Tickets->new($session{'CurrentUser'});
+$tickets->FromSQL($Query );
+my $top_tickets = ();
+foreach my $ticket ( @{ $tickets->ItemsArrayRef } ) {
+    $top_tickets->{ $ticket->id } = $ticket;
+}
+
+# for each ticket found by our search, check to see if it depends on any
+# others. if so, discard it
+foreach my $ticket (@{$tickets->ItemsArrayRef}) {
+    next unless exists $top_tickets->{$ticket->id};
+    my $deps = RT::Tickets->new( $session{'CurrentUser'} );
+    $deps->FromSQL( 'MemberOf = ' . $ticket->id );
+    while (my $dep = $deps->Next) {
+        # Discard
+        delete $top_tickets->{$dep->id};
+    }
+}
+foreach my $ticket (values %$top_tickets ) {
+    $m->comp( '.entry', Ticket => $ticket, Depth => 0 );
+
+}
+
+</%perl>
+</table>
+<%ARGS>
+$Query => 'Subject LIKE "TreeView"'
+</%ARGS>
+<%DEF .entry>
+<%args>
+$Ticket
+$Depth => 0
+$Parents => undef
+</%args>
+<%init>
+my $kids = RT::Tickets->new($session{'CurrentUser'});
+$kids->FromSQL('MemberOf = '.$Ticket->id);
+my @Format = $m->comp('/Elements/ParseColumnDefs', Format => 'id, "___RT_TreeView_Indent__ __Subject__"');
+
+</%init>
+<& /Elements/TicketListRow, Format => \@Format, i => $Depth, record => $Ticket&>
+<%perl>
+    if ( $Parents->{ $Ticket->id } ) {
+        my @Blank;
+        foreach my $entry (@Format) {
+            my @output = [ '&nbsp;'];
+            foreach my $item (@{$entry->{'output'}}){ 
+                if ($item =~ /Subject/i) {
+                    @output = ['___RT_TreeView_Indent__' ,'...'];
+            }
+        }
+                push @Blank, {output => @output };
+       } 
+ $m->comp('/Elements/TicketListRow', Format => \@Blank, i => $Depth+1, record => $Ticket);
+
+    }
+    else {
+        $Parents->{ $Ticket->id } = 1;
+        while ( my $kid = $kids->Next ) {
+
+            #        look to see if the child is a parent up the tree
+            $m->comp(
+                '.entry',
+                Ticket  => $kid,
+                Depth   => ( $Depth + 1 ),
+                Parents => $Parents
+            );
+        }
+    }
+</%perl>
+</%DEF>
+
+

Added: RT-View-Tree/html/Ticket/DisplayTree.html
==============================================================================
--- (empty file)
+++ RT-View-Tree/html/Ticket/DisplayTree.html	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,124 @@
+<& /Elements/Header, Title => $ProjectObj->Subject . " / Tree View" &> 
+<& Elements/Tabs, Ticket => $ProjectObj, current_tab => 'Ticket/DisplayTree.html?id='.$ProjectObj->Id &>
+
+<form method="post" action="DisplayTree.html">
+<input type="hidden" name="Project" value="<%$Project%>">
+<input type="hidden" name="id" value="<%$id%>">
+<div align="right">
+<input type="submit" name="Redisplay" value="Re-display">
+this tree with a maximum depth of 
+<input type="text" name="MaxDepth" value="<% $MaxDepth %>" size="2">
+tickets, showing 
+<select name="TreeType">
+<option value="MemberOf" <% lc($TreeType) eq "memberof" ? "selected" : "" %>>MemberOf</option>
+<option value="DependsOn" <% lc($TreeType) eq "dependson" ? "selected" : "" %>>DependsOn</option>
+<option value="Both" <% lc($TreeType) eq "both" ? "selected" : "" %>>Both</option>
+</select>
+relationships.
+</div>
+</form>
+
+<TABLE WIDTH=100% CELLSPACING=0 BORDER=0 CELLPADDING=2>
+
+<%perl>
+my $parents;
+if (lc($TreeType) eq 'memberof') { 
+  $parents = $task->MemberOf;
+} elsif (lc($TreeType) eq 'dependson') {
+  $parents = $task->DependedOnBy;
+} elsif (lc($TreeType) eq 'both') {
+# # # TBD
+  die "'Both' - Not implemented yet.";
+# # # TBD
+}
+</%perl>
+
+% while (my $link = $parents->Next) {
+% unless ($link->TargetObj->MemberOf->First) {
+<TR><TD colspan=7 BGCOLOR="#cccccc">Top</TD></TR>
+% } else {
+<TR><TD colspan=7 BGCOLOR="#cccccc"><a HREF="DisplayTree.html?Project=<%$Project%>&id=<%$link->TargetObj->Id%>&MaxDepth=<%$MaxDepth%>&TreeType=<%$TreeType%>">Up</A></TD></TR>
+% }
+
+% }
+% unless ($task->MemberOf->First) {
+<TR><TD colspan=7 BGCOLOR="#cccccc">Top</TD></TR>
+% }
+<HR>
+<& /Elements/TicketListHeader, Format => \@Format, maxitems => undef
+    &> 
+
+%# This hash will hold the downward tree we build.
+% my %loopcheck = ();
+<& Elements/TreeEntry, 
+    Root     => $task, 
+    Depth    => 0, 
+    MaxDepth => $MaxDepth,
+    Project  => $Project,
+    TreeType => $TreeType,
+    Format => \@Format,
+    LoopCheck => \%loopcheck
+    &>
+</TABLE>
+<HR>
+
+<%INIT>
+
+my (@messages);
+my @tix_to_update;
+
+if ($UseFormat and exists $session{'CurrentSearchHash'}->{'Format'}) {
+  $Format = $session{'CurrentSearchHash'}->{'Format'};
+}
+
+# Scrub the html of the format string to remove any potential nasties.
+
+$Format = $m->comp('/Elements/ScrubHTML', Content => $Format);
+my @Format = $m->comp('/Elements/ParseColumnDefs', Format => $Format);
+
+ grep { /^Ticket-(\d+)-/ && push @tix_to_update, $1 } (keys %ARGS);
+foreach my $ticket_id (@tix_to_update) {
+    my $ticket=    LoadTicket($ticket_id);
+    my %ticket_args;
+    grep { /^Ticket-$ticket_id-(.*)$/ && ($ticket_args{$1} = $ARGS{$_})} (keys %ARGS);
+    ProcessTicketDates ( TicketObj =>$ticket, ARGSRef => \%ticket_args);
+    ProcessTicketBasics ( TicketObj =>$ticket, ARGSRef => \%ticket_args);
+}
+
+my $task = LoadTicket($id);
+$Project = $task->Id unless ($Project); 
+my $ProjectObj = LoadTicket($Project);
+
+if ($ARGS{'CreateTask'}) {
+   
+    $ARGS{'Queue'} = $task->QueueObj->id;
+my     ($new_id, $new_msg) = CreateTicket(%ARGS);
+push (@messages, $new_msg);
+}
+</%INIT>
+
+<%ARGS>
+$Project => undef
+$AddChildOf => undef
+$id => undef
+$UseFormat => undef
+$Format => $RT::DefaultTreeDisplayFormat
+$MaxDepth => 8
+$TreeType => "MemberOf"
+</%ARGS>
+
+<%ONCE>
+$RT::DefaultTreeDisplayFormat = qq{
+   '<B><A HREF="$RT::WebPath/Ticket/Display.html?id=__id__">__id__</a></B>/TITLE:#',
+   '<B><A HREF="$RT::WebPath/Ticket/DisplayTree.html?id=__id__&UseFormat=1">__Subject__</a></B>/TITLE:Subject',
+   QueueName,
+   Priority,
+   Status,
+   '__NEWLINE__',
+   '',
+   '<small>__OwnerName__</small>',
+   '<small>__CreatedRelative__</small>',
+   '<small>__Starts__</small>',
+   '<small>__Due__</small>',
+   ''};
+</%ONCE>

Added: RT-View-Tree/html/Ticket/Elements/TreeEntry
==============================================================================
--- (empty file)
+++ RT-View-Tree/html/Ticket/Elements/TreeEntry	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,75 @@
+<%perl>
+
+my $tasks = RT::Tickets->new($session{'CurrentUser'});
+# # # This needs to be flexible, user-selected, etc.
+if ( lc($TreeType) eq 'dependson' ) {
+  $tasks->FromSQL('DependsOn = '.$Root->id);
+} elsif ( lc($TreeType) eq 'memberof' ) {
+  $tasks->FromSQL('MemberOf = '.$Root->id);
+} elsif ( lc($TreeType) eq 'both' ) {
+  $tasks->FromSQL('MemberOf = '.$Root->id . ' OR  DependsOn = '.$Root->id);
+
+}
+# We want a copy of this, not the original, so:
+my %LoopCheck;
+%LoopCheck = %$LoopCheck if defined $LoopCheck;
+
+my $warning;
+
+# We check to see whether we've seen this ID in this branch of the
+# tree - it should be _impossible_ for the value of the sighting to
+# be greater than the current depth, so just in case:
+if ( exists $LoopCheck{ $Root->id } and $LoopCheck{ $Root->id } < $Depth ) {
+    $warning = "Loop detected:";
+}
+
+$m->comp(
+    '/Elements/TicketListRow',
+    Format  => $Format,
+    record  => $Root,
+    i       => ( $Depth % 2 ),
+    Depth   => $Depth,
+    Warning => $warning,
+);
+
+#  We only recurse further if there's not been a problem above.
+#  Currently the only problem that would cause this would be if
+#  we've detected a loop.
+if ( $Depth < $MaxDepth and not $warning ) {
+    while ( my $link = $tasks->Next() ) {
+
+        # We record that we've seen this ID before and at what depth.
+        $LoopCheck{ $Root->id } = $Depth;
+        $m->comp(
+            'TreeEntry', %ARGS,
+            Root      => $link,
+            Depth     => ( $Depth + 1 ),
+            MaxDepth  => $MaxDepth,
+            Project   => $Project,
+            TreeType  => $TreeType,
+            LoopCheck => \%LoopCheck
+        );
+    }
+
+}
+</%perl>
+
+<%doc>
+ARGS:
+Format needs to be handled in the caller.
+Depth controls how deeply the first element is indented.
+MaxDepth is how deeply we are allowed to indent. 
+Root is the id we start from - the ticket we're viewing at the top. 
+I forget what Project is, but I think it's no longer completely relevant.  We leave it in for future use.
+TreeType is a required element, passing in what relationship we want to look up.
+</%doc>
+<%ARGS>
+$Depth => 0
+$MaxDepth => 8
+$Header => 0
+$Root => undef
+$Project => undef
+$Format
+$LoopCheck => undef
+$TreeType => undef
+</%ARGS>

Added: RT-View-Tree/inc/Module/Install.pm
==============================================================================
--- (empty file)
+++ RT-View-Tree/inc/Module/Install.pm	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,171 @@
+#line 1 "inc/Module/Install.pm - /opt/perl-5.8.3/lib/site_perl/5.8.3/Module/Install.pm"
+# $File: //depot/cpan/Module-Install/lib/Module/Install.pm $ $Author: autrijus $
+# $Revision: #67 $ $Change: 1885 $ $DateTime: 2004/03/11 05:55:27 $ vim: expandtab shiftwidth=4
+
+package Module::Install;
+$VERSION = '0.33';
+
+die << "." unless $INC{join('/', inc => split(/::/, __PACKAGE__)).'.pm'};
+Please invoke ${\__PACKAGE__} with:
+
+    use inc::${\__PACKAGE__};
+
+not:
+
+    use ${\__PACKAGE__};
+
+.
+
+use strict 'vars';
+use Cwd ();
+use File::Find ();
+use File::Path ();
+
+ at inc::Module::Install::ISA = 'Module::Install';
+
+#line 129
+
+sub import {
+    my $class = shift;
+    my $self = $class->new(@_);
+
+    if (not -f $self->{file}) {
+        require "$self->{path}/$self->{dispatch}.pm";
+        File::Path::mkpath("$self->{prefix}/$self->{author}");
+        $self->{admin} = 
+          "$self->{name}::$self->{dispatch}"->new(_top => $self);
+        $self->{admin}->init;
+        @_ = ($class, _self => $self);
+        goto &{"$self->{name}::import"};
+    }
+
+    *{caller(0) . "::AUTOLOAD"} = $self->autoload;
+
+    # Unregister loader and worker packages so subdirs can use them again
+    delete $INC{"$self->{file}"};
+    delete $INC{"$self->{path}.pm"};
+}
+
+#line 156
+
+sub autoload {
+    my $self = shift;
+    my $caller = caller;
+
+    my $cwd = Cwd::cwd();
+    my $sym = "$caller\::AUTOLOAD";
+
+    $sym->{$cwd} = sub {
+        my $pwd = Cwd::cwd();
+        if (my $code = $sym->{$pwd}) {
+            goto &$code unless $cwd eq $pwd; # delegate back to parent dirs
+        }
+        $$sym =~ /([^:]+)$/ or die "Cannot autoload $caller";
+        unshift @_, ($self, $1);
+        goto &{$self->can('call')} unless uc($1) eq $1;
+    };
+}
+
+#line 181
+
+sub new {
+    my ($class, %args) = @_;
+
+    return $args{_self} if $args{_self};
+
+    $args{dispatch} ||= 'Admin';
+    $args{prefix}   ||= 'inc';
+    $args{author}   ||= '.author';
+    $args{bundle}   ||= 'inc/BUNDLES';
+
+    $class =~ s/^\Q$args{prefix}\E:://;
+    $args{name}     ||= $class;
+    $args{version}  ||= $class->VERSION;
+
+    unless ($args{path}) {
+        $args{path}  = $args{name};
+        $args{path}  =~ s!::!/!g;
+    }
+    $args{file}     ||= "$args{prefix}/$args{path}.pm";
+
+    bless(\%args, $class);
+}
+
+#line 210
+
+sub call {
+    my $self   = shift;
+    my $method = shift;
+    my $obj = $self->load($method) or return;
+
+    unshift @_, $obj;
+    goto &{$obj->can($method)};
+}
+
+#line 225
+
+sub load {
+    my ($self, $method) = @_;
+
+    $self->load_extensions(
+        "$self->{prefix}/$self->{path}", $self
+    ) unless $self->{extensions};
+
+    foreach my $obj (@{$self->{extensions}}) {
+        return $obj if $obj->can($method);
+    }
+
+    my $admin = $self->{admin} or die << "END";
+The '$method' method does not exist in the '$self->{prefix}' path!
+Please remove the '$self->{prefix}' directory and run $0 again to load it.
+END
+
+    my $obj = $admin->load($method, 1);
+    push @{$self->{extensions}}, $obj;
+
+    $obj;
+}
+
+#line 255
+
+sub load_extensions {
+    my ($self, $path, $top_obj) = @_;
+
+    unshift @INC, $self->{prefix}
+        unless grep { $_ eq $self->{prefix} } @INC;
+
+    local @INC = ($path, @INC);
+    foreach my $rv ($self->find_extensions($path)) {
+        my ($file, $pkg) = @{$rv};
+        next if $self->{pathnames}{$pkg};
+
+        eval { require $file; 1 } or (warn($@), next);
+        $self->{pathnames}{$pkg} = delete $INC{$file};
+        push @{$self->{extensions}}, $pkg->new( _top => $top_obj );
+    }
+}
+
+#line 279
+
+sub find_extensions {
+    my ($self, $path) = @_;
+    my @found;
+
+    File::Find::find(sub {
+        my $file = $File::Find::name;
+        return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is;
+        return if $1 eq $self->{dispatch};
+
+        $file = "$self->{path}/$1.pm";
+        my $pkg = "$self->{name}::$1"; $pkg =~ s!/!::!g;
+        push @found, [$file, $pkg];
+    }, $path) if -d $path;
+
+    @found;
+}
+
+1;
+
+__END__
+
+#line 614

Added: RT-View-Tree/inc/Module/Install/Base.pm
==============================================================================
--- (empty file)
+++ RT-View-Tree/inc/Module/Install/Base.pm	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,57 @@
+#line 1 "inc/Module/Install/Base.pm - /opt/perl-5.8.3/lib/site_perl/5.8.3/Module/Install/Base.pm"
+# $File: //depot/cpan/Module-Install/lib/Module/Install/Base.pm $ $Author: autrijus $
+# $Revision: #10 $ $Change: 1847 $ $DateTime: 2003/12/31 23:14:54 $ vim: expandtab shiftwidth=4
+
+package Module::Install::Base;
+
+#line 31
+
+sub new {
+    my ($class, %args) = @_;
+
+    foreach my $method (qw(call load)) {
+        *{"$class\::$method"} = sub {
+            +shift->_top->$method(@_);
+        } unless defined &{"$class\::$method"};
+    }
+
+    bless(\%args, $class);
+}
+
+#line 49
+
+sub AUTOLOAD {
+    my $self = shift;
+    goto &{$self->_top->autoload};
+}
+
+#line 60
+
+sub _top { $_[0]->{_top} }
+
+#line 71
+
+sub admin {
+    my $self = shift;
+    $self->_top->{admin} or Module::Install::Base::FakeAdmin->new;
+}
+
+sub is_admin {
+    my $self = shift;
+    $self->admin->VERSION;
+}
+
+sub DESTROY {}
+
+package Module::Install::Base::FakeAdmin;
+
+my $Fake;
+sub new { $Fake ||= bless(\@_, $_[0]) }
+sub AUTOLOAD {}
+sub DESTROY {}
+
+1;
+
+__END__
+
+#line 115

Added: RT-View-Tree/inc/Module/Install/Can.pm
==============================================================================
--- (empty file)
+++ RT-View-Tree/inc/Module/Install/Can.pm	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,41 @@
+#line 1 "inc/Module/Install/Can.pm - /opt/perl-5.8.3/lib/site_perl/5.8.3/Module/Install/Can.pm"
+# $File: //depot/cpan/Module-Install/lib/Module/Install/Can.pm $ $Author: autrijus $
+# $Revision: #6 $ $Change: 1840 $ $DateTime: 2003/12/28 19:42:02 $ vim: expandtab shiftwidth=4
+
+package Module::Install::Can;
+use Module::Install::Base; @ISA = qw(Module::Install::Base);
+$VERSION = '0.01';
+
+use strict;
+use Config ();
+use File::Spec ();
+use ExtUtils::MakeMaker ();
+
+# check if we can run some command
+sub can_run {
+    my ($self, $cmd) = @_;
+
+    my $_cmd = $cmd;
+    return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd));
+
+    for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') {
+        my $abs = File::Spec->catfile($dir, $_[1]);
+        return $abs if (-x $abs or $abs = MM->maybe_command($abs));
+    }
+
+    return;
+}
+
+sub can_cc {
+    my $self = shift;
+    my @chunks = split(/ /, $Config::Config{cc}) or return;
+
+    # $Config{cc} may contain args; try to find out the program part
+    while (@chunks) {
+        return $self->can_run("@chunks") || (pop(@chunks), next);
+    }
+
+    return;
+}
+
+1;

Added: RT-View-Tree/inc/Module/Install/Fetch.pm
==============================================================================
--- (empty file)
+++ RT-View-Tree/inc/Module/Install/Fetch.pm	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,89 @@
+#line 1 "inc/Module/Install/Fetch.pm - /opt/perl-5.8.3/lib/site_perl/5.8.3/Module/Install/Fetch.pm"
+# $File: //depot/cpan/Module-Install/lib/Module/Install/Fetch.pm $ $Author: autrijus $
+# $Revision: #8 $ $Change: 1374 $ $DateTime: 2003/03/18 11:50:15 $ vim: expandtab shiftwidth=4
+
+package Module::Install::Fetch;
+use Module::Install::Base; @ISA = qw(Module::Install::Base);
+
+$VERSION = '0.01';
+
+sub get_file {
+    my ($self, %args) = @_;
+    my ($scheme, $host, $path, $file) = 
+        $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return;
+
+    if ($scheme eq 'http' and !eval { require LWP::Simple; 1 }) {
+        $args{url} = $args{ftp_url}
+            or (warn("LWP support unavailable!\n"), return);
+        ($scheme, $host, $path, $file) = 
+            $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return;
+    }
+
+    $|++;
+    print "Fetching '$file' from $host... ";
+
+    unless (eval { require Socket; Socket::inet_aton($host) }) {
+        warn "'$host' resolve failed!\n";
+        return;
+    }
+
+    return unless $scheme eq 'ftp' or $scheme eq 'http';
+
+    require Cwd;
+    my $dir = Cwd::getcwd();
+    chdir $args{local_dir} or return if exists $args{local_dir};
+
+    if (eval { require LWP::Simple; 1 }) {
+        LWP::Simple::mirror($args{url}, $file);
+    }
+    elsif (eval { require Net::FTP; 1 }) { eval {
+        # use Net::FTP to get past firewall
+        my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600);
+        $ftp->login("anonymous", 'anonymous at example.com');
+        $ftp->cwd($path);
+        $ftp->binary;
+        $ftp->get($file) or (warn("$!\n"), return);
+        $ftp->quit;
+    } }
+    elsif (my $ftp = $self->can_run('ftp')) { eval {
+        # no Net::FTP, fallback to ftp.exe
+        require FileHandle;
+        my $fh = FileHandle->new;
+
+        local $SIG{CHLD} = 'IGNORE';
+        unless ($fh->open("|$ftp -n")) {
+            warn "Couldn't open ftp: $!\n";
+            chdir $dir; return;
+        }
+
+        my @dialog = split(/\n/, << ".");
+open $host
+user anonymous anonymous\@example.com
+cd $path
+binary
+get $file $file
+quit
+.
+        foreach (@dialog) { $fh->print("$_\n") }
+        $fh->close;
+    } }
+    else {
+        warn "No working 'ftp' program available!\n";
+        chdir $dir; return;
+    }
+
+    unless (-f $file) {
+        warn "Fetching failed: $@\n";
+        chdir $dir; return;
+    }
+
+    return if exists $args{size} and -s $file != $args{size};
+    system($args{run}) if exists $args{run};
+    unlink($file) if $args{remove};
+
+    print(((!exists $args{check_for} or -e $args{check_for})
+        ? "done!" : "failed! ($!)"), "\n");
+    chdir $dir; return !$?;
+}
+
+1;

Added: RT-View-Tree/inc/Module/Install/Makefile.pm
==============================================================================
--- (empty file)
+++ RT-View-Tree/inc/Module/Install/Makefile.pm	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,146 @@
+#line 1 "inc/Module/Install/Makefile.pm - /opt/perl-5.8.3/lib/site_perl/5.8.3/Module/Install/Makefile.pm"
+# $File: //depot/cpan/Module-Install/lib/Module/Install/Makefile.pm $ $Author: autrijus $
+# $Revision: #53 $ $Change: 1847 $ $DateTime: 2003/12/31 23:14:54 $ vim: expandtab shiftwidth=4
+
+package Module::Install::Makefile;
+use Module::Install::Base; @ISA = qw(Module::Install::Base);
+
+$VERSION = '0.01';
+
+use strict 'vars';
+use vars '$VERSION';
+
+use ExtUtils::MakeMaker ();
+
+sub Makefile { $_[0] }
+
+sub prompt { 
+    shift;
+    goto &ExtUtils::MakeMaker::prompt;
+}
+
+sub makemaker_args {
+    my $self = shift;
+    my $args = ($self->{makemaker_args} ||= {});
+    %$args = ( %$args, @_ ) if @_;
+    $args;
+}
+
+sub clean_files {
+    my $self = shift;
+    my $clean = $self->makemaker_args->{clean} ||= {};
+    %$clean = (
+        %$clean, 
+        FILES => join(" ", grep length, $clean->{FILES}, @_),
+    );
+}
+
+sub libs {
+    my $self = shift;
+    my $libs = ref $_[0] ? shift : [shift];
+    $self->makemaker_args( LIBS => $libs );
+}
+
+sub inc {
+    my $self = shift;
+    $self->makemaker_args( INC => shift );
+}
+
+sub write {
+    my $self = shift;
+    die "&Makefile->write() takes no arguments\n" if @_;
+
+    my $args = $self->makemaker_args;
+
+    $args->{DISTNAME} = $self->name;
+    $args->{NAME} = $self->module_name || $self->name || $self->determine_NAME($args);
+    $args->{VERSION} = $self->version || $self->determine_VERSION($args);
+    $args->{NAME} =~ s/-/::/g;
+
+    if ($] >= 5.005) {
+	$args->{ABSTRACT} = $self->abstract;
+	$args->{AUTHOR} = $self->author;
+    }
+    if ( eval($ExtUtils::MakeMaker::VERSION) >= 6.10 ) {
+        $args->{NO_META} = 1;
+    }
+    if ( eval($ExtUtils::MakeMaker::VERSION) > 6.17 ) {
+	$args->{SIGN} = 1 if $self->sign;
+    }
+    delete $args->{SIGN} unless $self->is_admin;
+
+    # merge both kinds of requires into prereq_pm
+    my $prereq = ($args->{PREREQ_PM} ||= {});
+    %$prereq = ( %$prereq, map { @$_ } map { @$_ } grep $_,
+                 ($self->build_requires, $self->requires) );
+
+    # merge both kinds of requires into prereq_pm
+    my $dir = ($args->{DIR} ||= []);
+    if ($self->bundles) {
+        push @$dir, map "$_->[1]", @{$self->bundles};
+        delete $prereq->{$_->[0]} for @{$self->bundles};
+    }
+
+    if (my $perl_version = $self->perl_version) {
+        eval "use $perl_version; 1"
+            or die "ERROR: perl: Version $] is installed, ".
+                   "but we need version >= $perl_version";
+    }
+
+    my %args = map {($_ => $args->{$_})} grep {defined($args->{$_})} keys %$args;
+
+    if ($self->admin->preop) {
+        $args{dist} = $self->admin->preop;
+    }
+
+    ExtUtils::MakeMaker::WriteMakefile(%args);
+
+    $self->fix_up_makefile();
+}
+
+sub fix_up_makefile {
+    my $self = shift;
+    my $top_class = ref($self->_top) || '';
+    my $top_version = $self->_top->VERSION || '';
+
+    my $preamble = $self->preamble 
+       ? "# Preamble by $top_class $top_version\n" . $self->preamble
+       : '';
+    my $postamble = "# Postamble by $top_class $top_version\n" . 
+                    ($self->postamble || '');
+
+    open MAKEFILE, '< Makefile' or die $!;
+    my $makefile = do { local $/; <MAKEFILE> };
+    close MAKEFILE;
+
+    $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /;
+    $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g;
+    $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g;
+
+    $makefile =~ s/^(FULLPERL = .*)/$1 -Iinc/m;
+    $makefile =~ s/^(PERL = .*)/$1 -Iinc/m;
+
+    open MAKEFILE, '> Makefile' or die $!;
+    print MAKEFILE "$preamble$makefile$postamble";
+    close MAKEFILE;
+}
+
+sub preamble {
+    my ($self, $text) = @_;
+    $self->{preamble} = $text . $self->{preamble} if defined $text;
+    $self->{preamble};
+}
+
+sub postamble {
+    my ($self, $text) = @_;
+
+    $self->{postamble} ||= $self->admin->postamble;
+    $self->{postamble} .= $text if defined $text;
+    $self->{postamble}
+}
+
+1;
+
+__END__
+
+#line 276

Added: RT-View-Tree/inc/Module/Install/Metadata.pm
==============================================================================
--- (empty file)
+++ RT-View-Tree/inc/Module/Install/Metadata.pm	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,190 @@
+#line 1 "inc/Module/Install/Metadata.pm - /opt/perl-5.8.3/lib/site_perl/5.8.3/Module/Install/Metadata.pm"
+# $File: //depot/cpan/Module-Install/lib/Module/Install/Metadata.pm $ $Author: autrijus $
+# $Revision: #32 $ $Change: 1885 $ $DateTime: 2004/03/11 05:55:27 $ vim: expandtab shiftwidth=4
+
+package Module::Install::Metadata;
+use Module::Install::Base; @ISA = qw(Module::Install::Base);
+
+$VERSION = '0.04';
+
+use strict 'vars';
+use vars qw($VERSION);
+
+sub Meta { shift }
+
+my @scalar_keys = qw(
+    name module_name version abstract author license
+    distribution_type sign perl_version
+);
+my @tuple_keys  = qw(build_requires requires recommends bundles);
+
+foreach my $key (@scalar_keys) {
+    *$key = sub {
+        my $self = shift;
+        return $self->{'values'}{$key} unless @_;
+        $self->{'values'}{$key} = shift;
+        return $self;
+    };
+}
+
+foreach my $key (@tuple_keys) {
+    *$key = sub {
+        my $self = shift;
+        return $self->{'values'}{$key} unless @_;
+        my @rv;
+        while (@_) {
+            my $module  = shift or last;
+            my $version = shift || 0;
+            if ($module eq 'perl') {
+                $version =~ s{^(\d+)\.(\d+)\.(\d+)}
+                             {$1 + $2/1_000 + $3/1_000_000}e;
+                $self->perl_version($version);
+                next;
+            }
+            my $rv = [$module, $version];
+            push @{$self->{'values'}{$key}}, $rv;
+            push @rv, $rv;
+        }
+        return @rv;
+    };
+}
+
+sub features {
+    my $self = shift;
+    while (my ($name, $mods) = splice(@_, 0, 2)) {
+        my $count = 0;
+        push @{$self->{'values'}{'features'}}, ($name => [
+            map { (++$count % 2 and ref($_) and ($count += $#$_)) ? @$_ : $_ } @$mods
+        ] );
+    }
+    return @{$self->{'values'}{'features'}};
+}
+
+sub no_index {
+    my $self = shift;
+    my $type = shift;
+    push @{$self->{'values'}{'no_index'}{$type}}, @_ if $type;
+    return $self->{'values'}{'no_index'};
+}
+
+sub _dump {
+    my $self = shift;
+    my $package = ref($self->_top);
+    my $version = $self->_top->VERSION;
+    my %values = %{$self->{'values'}};
+
+    delete $values{sign};
+    if (my $perl_version = delete $values{perl_version}) {
+        # Always canonical to three-dot version 
+        $perl_version =~ s{^(\d+)\.(\d\d\d)(\d*)}{join('.', $1, int($2), int($3))}e
+            if $perl_version >= 5.006;
+        $values{requires} = [
+            [perl => $perl_version],
+            @{$values{requires}||[]},
+        ];
+    }
+
+    warn "No license specified, setting license = 'unknown'\n"
+        unless $values{license};
+
+    $values{license} ||= 'unknown';
+    $values{distribution_type} ||= 'module';
+    $values{name} ||= do {
+        my $name = $values{module_name};
+        $name =~ s/::/-/g;
+        $name;
+    } if $values{module_name};
+
+    if ($values{name} =~ /::/) {
+        my $name = $values{name};
+        $name =~ s/::/-/g;
+        die "Error in name(): '$values{name}' should be '$name'!\n";
+    }
+
+    my $dump = '';
+    foreach my $key (@scalar_keys) {
+        $dump .= "$key: $values{$key}\n" if exists $values{$key};
+    }
+    foreach my $key (@tuple_keys) {
+        next unless exists $values{$key};
+        $dump .= "$key:\n";
+        foreach (@{$values{$key}}) {
+            $dump .= "  $_->[0]: $_->[1]\n";
+        }
+    }
+
+    if (my $no_index = $values{no_index}) {
+        push @{$no_index->{'directory'}}, 'inc';
+        require YAML;
+        local $YAML::UseHeader = 0;
+        $dump .= YAML::Dump({ no_index => $no_index});
+    }
+    else {
+        $dump .= << "META";
+no_index:
+  directory:
+    - inc
+META
+    }
+    
+    $dump .= "generated_by: $package version $version\n";
+    return $dump;
+}
+
+sub read {
+    my $self = shift;
+    $self->include_deps( 'YAML', 0 );
+    require YAML;
+    my $data = YAML::LoadFile( 'META.yml' );
+    # Call methods explicitly in case user has already set some values.
+    while ( my ($key, $value) = each %$data ) {
+        next unless $self->can( $key );
+        if (ref $value eq 'HASH') {
+            while (my ($module, $version) = each %$value) {
+                $self->$key( $module => $version );
+            }
+        }
+        else {
+            $self->$key( $value );
+        }
+    }
+    return $self;
+}
+
+sub write {
+    my $self = shift;
+    return $self unless $self->is_admin;
+
+    META_NOT_OURS: {
+        local *FH;
+        if (open FH, "META.yml") {
+            while (<FH>) {
+                last META_NOT_OURS if /^generated_by: Module::Install\b/;
+            }
+            return $self if -s FH;
+        }
+    }
+
+    warn "Writing META.yml\n";
+    open META, "> META.yml" or warn "Cannot write to META.yml: $!";
+    print META $self->_dump;
+    close META;
+    return $self;
+}
+
+sub version_from {
+    my ($self, $version_from) = @_;
+    require ExtUtils::MM_Unix;
+    $self->version(ExtUtils::MM_Unix->parse_version($version_from));
+}
+
+sub abstract_from {
+    my ($self, $abstract_from) = @_;
+    require ExtUtils::MM_Unix;
+    $self->abstract(
+        bless( { DISTNAME => $self->name }, 'ExtUtils::MM_Unix')
+            ->parse_abstract($abstract_from)
+    );
+}
+
+1;

Added: RT-View-Tree/inc/Module/Install/RTx.pm
==============================================================================
--- (empty file)
+++ RT-View-Tree/inc/Module/Install/RTx.pm	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,158 @@
+#line 1 "inc/Module/Install/RTx.pm - /opt/perl-5.8.3/lib/site_perl/5.8.3/Module/Install/RTx.pm"
+# $File: //member/autrijus/Module-Install-RTx/lib/Module/Install/RTx.pm $ $Author: autrijus $
+# $Revision: #17 $ $Change: 10722 $ $DateTime: 2004/05/31 16:38:57 $ vim: expandtab shiftwidth=4
+
+package Module::Install::RTx;
+use Module::Install::Base; @ISA = qw(Module::Install::Base);
+
+$Module::Install::RTx::VERSION = '0.08';
+
+use strict;
+use FindBin;
+use File::Glob ();
+use File::Basename ();
+
+sub RTx {
+    my ($self, $name) = @_;
+    my $RTx = 'RTx';
+    $RTx = $1 if $name =~ s/^(\w+)-//;
+    my $fname = $name;
+    $fname =~ s!-!/!g;
+
+    $self->name("$RTx-$name")
+        unless $self->name;
+    $self->abstract("RT $name Extension")
+        unless $self->abstract;
+    $self->version_from (-e "$name.pm" ? "$name.pm" : "lib/$RTx/$fname.pm")
+        unless $self->version;
+
+    my @prefixes = (qw(/opt /usr/local /home /usr /sw ));
+    my $prefix = $ENV{PREFIX};
+    @ARGV = grep { /PREFIX=(.*)/ ? (($prefix = $1), 0) : 1 } @ARGV;
+
+    if ($prefix) {
+        $RT::LocalPath = $prefix;
+        $INC{'RT.pm'} = "$RT::LocalPath/lib/RT.pm";
+    }
+    else {
+        local @INC = (
+            @INC,
+            $ENV{RTHOME},
+            map {( "$_/rt3/lib", "$_/lib/rt3", "$_/lib" )} grep $_, @prefixes
+        );
+        until ( eval { require RT; $RT::LocalPath } ) {
+            warn "Cannot find the location of RT.pm that defines \$RT::LocalPath. ($@)\n";
+            $_ = $self->prompt("Path to your RT.pm:") or exit;
+            push @INC, $_, "$_/rt3/lib", "$_/lib/rt3";
+        }
+    }
+
+    my $lib_path = File::Basename::dirname($INC{'RT.pm'});
+    print "Using RT configurations from $INC{'RT.pm'}:\n";
+
+    $RT::LocalVarPath	||= $RT::VarPath;
+    $RT::LocalPoPath	||= $RT::LocalLexiconPath;
+    $RT::LocalHtmlPath	||= $RT::MasonComponentRoot;
+
+    my %path;
+    my $with_subdirs = $ENV{WITH_SUBDIRS};
+    @ARGV = grep { /WITH_SUBDIRS=(.*)/ ? (($with_subdirs = $1), 0) : 1 } @ARGV;
+    my %subdirs = map { $_ => 1 } split(/\s*,\s*/, $with_subdirs);
+
+    foreach (qw(bin etc html po sbin var)) {
+        next unless -d "$FindBin::Bin/$_";
+        next if %subdirs and !$subdirs{$_};
+        $self->no_index( directory => $_ );
+
+        no strict 'refs';
+        my $varname = "RT::Local" . ucfirst($_) . "Path";
+        $path{$_} = ${$varname} || "$RT::LocalPath/$_";
+    }
+
+    $path{$_} .= "/$name" for grep $path{$_}, qw(etc po var);
+    my $args = join(', ', map "q($_)", %path);
+    $path{lib} = "$RT::LocalPath/lib" unless %subdirs and !$subdirs{'lib'};
+    print "./$_\t=> $path{$_}\n" for sort keys %path;
+
+    if (my @dirs = map { (-D => $_) } grep $path{$_}, qw(bin html sbin)) {
+        my @po = map { (-o => $_) } grep -f, File::Glob::bsd_glob("po/*.po");
+        $self->postamble(<< ".") if @po;
+lexicons ::
+\t\$(NOECHO) \$(PERL) -MLocale::Maketext::Extract::Run=xgettext -e \"xgettext(qw(@dirs @po))\"
+.
+    }
+
+    my $postamble = << ".";
+install ::
+\t\$(NOECHO) \$(PERL) -MExtUtils::Install -e \"install({$args})\"
+.
+
+    if ($path{var} and -d $RT::MasonDataDir) {
+        my ($uid, $gid) = (stat($RT::MasonDataDir))[4, 5];
+        $postamble .= << ".";
+\t\$(NOECHO) chown -R $uid:$gid $path{var}
+.
+    }
+
+    my %has_etc;
+    if (File::Glob::bsd_glob("$FindBin::Bin/etc/schema.*")) {
+        # got schema, load factory module
+        $has_etc{schema}++;
+        $self->load('RTxFactory');
+        $self->postamble(<< ".");
+factory ::
+\t\$(NOECHO) \$(PERL) -Ilib -I"$lib_path" -Minc::Module::Install -e"RTxFactory(qw($RTx $name))"
+
+dropdb ::
+\t\$(NOECHO) \$(PERL) -Ilib -I"$lib_path" -Minc::Module::Install -e"RTxFactory(qw($RTx $name drop))"
+
+.
+    }
+    if (File::Glob::bsd_glob("$FindBin::Bin/etc/acl.*")) {
+        $has_etc{acl}++;
+    }
+    if (-e 'etc/initialdata') {
+        $has_etc{initialdata}++;
+    }
+
+    $self->postamble("$postamble\n");
+    if (%subdirs and !$subdirs{'lib'}) {
+        $self->makemaker_args(
+            PM => { "" => "" },
+        )
+    }
+    else {
+        $self->makemaker_args( INSTALLSITELIB => "$RT::LocalPath/lib" );
+    }
+
+    if (%has_etc) {
+        $self->load('RTxInitDB');
+        print "For first-time installation, type 'make initdb'.\n";
+        my $initdb = "initdb ::\n";
+        $initdb .= <<"." if $has_etc{schema};
+\t\$(NOECHO) \$(PERL) -Ilib -I"$lib_path" -Minc::Module::Install -e"RTxInitDB(qw(schema))"
+.
+        $initdb .= <<"." if $has_etc{acl};
+\t\$(NOECHO) \$(PERL) -Ilib -I"$lib_path" -Minc::Module::Install -e"RTxInitDB(qw(acl))"
+.
+        $initdb .= <<"." if $has_etc{initialdata};
+\t\$(NOECHO) \$(PERL) -Ilib -I"$lib_path" -Minc::Module::Install -e"RTxInitDB(qw(insert))"
+.
+        $self->postamble("$initdb\n");
+    }
+}
+
+sub RTxInit {
+    unshift @INC, substr(delete($INC{'RT.pm'}), 0, -5) if $INC{'RT.pm'};
+    require RT;
+    RT::LoadConfig();
+    RT::ConnectToDatabase();
+
+    die "Cannot load RT" unless $RT::Handle and $RT::DatabaseType;
+}
+
+1;
+
+__END__
+
+#line 234

Added: RT-View-Tree/inc/Module/Install/Win32.pm
==============================================================================
--- (empty file)
+++ RT-View-Tree/inc/Module/Install/Win32.pm	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,66 @@
+#line 1 "inc/Module/Install/Win32.pm - /opt/perl-5.8.3/lib/site_perl/5.8.3/Module/Install/Win32.pm"
+# $File: //depot/cpan/Module-Install/lib/Module/Install/Win32.pm $ $Author: autrijus $
+# $Revision: #9 $ $Change: 1789 $ $DateTime: 2003/11/11 01:22:54 $ vim: expandtab shiftwidth=4
+
+package Module::Install::Win32;
+use Module::Install::Base; @ISA = qw(Module::Install::Base);
+
+$VERSION = '0.02';
+
+use strict;
+
+# determine if the user needs nmake, and download it if needed
+sub check_nmake {
+    my $self = shift;
+    $self->load('can_run');
+    $self->load('get_file');
+
+    require Config;
+    return unless (
+        $Config::Config{make}                   and
+        $Config::Config{make} =~ /^nmake\b/i    and
+        $^O eq 'MSWin32'                        and
+        !$self->can_run('nmake')
+    );
+
+    print "The required 'nmake' executable not found, fetching it...\n";
+
+    require File::Basename;
+    my $rv = $self->get_file(
+        url         => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe',
+        ftp_url     => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe',
+        local_dir   => File::Basename::dirname($^X),
+        size        => 51928,
+        run         => 'Nmake15.exe /o > nul',
+        check_for   => 'Nmake.exe',
+        remove      => 1,
+    );
+
+    if (!$rv) {
+        die << '.';
+
+-------------------------------------------------------------------------------
+
+Since you are using Microsoft Windows, you will need the 'nmake' utility
+before installation. It's available at:
+
+  http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe
+      or
+  ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe
+
+Please download the file manually, save it to a directory in %PATH% (e.g.
+C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to
+that directory, and run "Nmake15.exe" from there; that will create the
+'nmake.exe' file needed by this module.
+
+You may then resume the installation process described in README.
+
+-------------------------------------------------------------------------------
+.
+    }
+}
+
+1;
+
+__END__
+

Added: RT-View-Tree/inc/Module/Install/WriteAll.pm
==============================================================================
--- (empty file)
+++ RT-View-Tree/inc/Module/Install/WriteAll.pm	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,39 @@
+#line 1 "inc/Module/Install/WriteAll.pm - /opt/perl-5.8.3/lib/site_perl/5.8.3/Module/Install/WriteAll.pm"
+# $File: //depot/cpan/Module-Install/lib/Module/Install/WriteAll.pm $ $Author: autrijus $
+# $Revision: #3 $ $Change: 1885 $ $DateTime: 2004/03/11 05:55:27 $ vim: expandtab shiftwidth=4
+
+package Module::Install::WriteAll;
+use Module::Install::Base; @ISA = qw(Module::Install::Base);
+
+sub WriteAll {
+    my $self = shift;
+    my %args = (
+        meta => 1,
+        sign => 0,
+        inline => 0,
+        check_nmake => 1,
+        @_
+    );
+
+    $self->sign(1) if $args{sign};
+    $self->Meta->write if $args{meta};
+    $self->admin->WriteAll(%args) if $self->is_admin;
+
+    if ($0 =~ /Build.PL$/i) {
+	$self->Build->write;
+    }
+    else {
+	$self->check_nmake if $args{check_nmake};
+        $self->makemaker_args( PL_FILES => {} )
+            unless $self->makemaker_args->{'PL_FILES'};
+
+        if ($args{inline}) {
+            $self->Inline->write;
+        }
+        else {
+            $self->Makefile->write;
+        }
+    }
+}
+
+1;

Added: RT-View-Tree/lib/RT/View/Tree.pm
==============================================================================
--- (empty file)
+++ RT-View-Tree/lib/RT/View/Tree.pm	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,6 @@
+
+package RT::View::Tree;
+
+our $VERSION = '0.2';
+
+1;

Added: RT-View-Tree/testdata
==============================================================================
--- (empty file)
+++ RT-View-Tree/testdata	Thu Feb 10 13:55:26 2005
@@ -0,0 +1,27 @@
+#!/usr/bin/perl -w
+use strict;
+
+use lib qw(/opt/rt3/lib);
+
+use RT;
+RT::LoadConfig;
+RT::Init;
+use RT::Ticket;
+
+my $top = RT::Ticket->new( $RT::SystemUser);
+$top->Create(Queue => 'general', Subject => 'Top TreeView Ticket');
+my $child_1 = new_child($top->id, 'second level #1');
+my $child_2 = new_child($top->id, 'second level #2');
+
+my $kid2 = RT::Ticket->new( $RT::SystemUser);
+$kid2->Create(Queue => 'general', Subject => 'another Second level TreeView Ticket', MemberOf => $top->id);
+
+
+
+sub new_child {
+    my $parent_id = shift;
+    my $subject = shift;
+    my $kid1 = RT::Ticket->new( $RT::SystemUser);
+    $kid1->Create(Queue => 'general', Subject => $subject.'-TreeView', MemberOf => $parent_id);
+    return($kid1->id);
+}


More information about the Rt-commit mailing list