reverting to vendor branch rt 3.0.4, hopefully
[freeside.git] / rt / lib / RT / Tickets.pm
index dd91126..b6b3491 100755 (executable)
-#$Header: /home/cvs/cvsroot/freeside/rt/lib/RT/Tickets.pm,v 1.1 2002-08-12 06:17:07 ivan Exp $
+# BEGIN LICENSE BLOCK
+# 
+# Copyright (c) 1996-2003 Jesse Vincent <jesse@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
+# Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
+# WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
+# 
+# !! DO NOT EDIT THIS FILE !!
+#
 
-=head1 NAME
+use strict;
 
-  RT::Tickets - A collection of Ticket objects
 
+=head1 NAME
 
+  RT::Tickets -- Class Description
 =head1 SYNOPSIS
 
-  use RT::Tickets;
-  my $tickets = new RT::Tickets($CurrentUser);
+  use RT::Tickets
 
 =head1 DESCRIPTION
 
-   A collection of RT::Tickets.
 
 =head1 METHODS
 
-=begin testing
-
-ok (require RT::TestHarness);
-ok (require RT::Tickets);
-
-=end testing
-
 =cut
 
 package RT::Tickets;
-use RT::EasySearch;
-use RT::Ticket;
-@ISA= qw(RT::EasySearch);
-
-use vars qw(%TYPES @SORTFIELDS);
-
-# {{{ TYPES
-
-%TYPES =    ( Status => 'ENUM',
-             Queue  => 'ENUM',
-             Type => 'ENUM',
-             Creator => 'ENUM',
-             LastUpdatedBy => 'ENUM',
-             Owner => 'ENUM',
-             EffectiveId => 'INT',
-             id => 'INT',
-             InitialPriority => 'INT',
-             FinalPriority => 'INT',
-             Priority => 'INT',
-             TimeLeft => 'INT',
-             TimeWorked => 'INT',
-             MemberOf => 'LINK',
-             DependsOn => 'LINK',
-             HasMember => 'LINK',
-             HasDepender => 'LINK',
-             RelatedTo => 'LINK',
-              Told => 'DATE',
-              StartsBy => 'DATE',
-              Started => 'DATE',
-              Due  => 'DATE',
-              Resolved => 'DATE',
-              LastUpdated => 'DATE',
-              Created => 'DATE',
-              Subject => 'STRING',
-             Type => 'STRING',
-              Content => 'TRANSFIELD',
-             ContentType => 'TRANSFIELD',
-             TransactionDate => 'TRANSDATE',
-             Watcher => 'WATCHERFIELD',
-             LinkedTo => 'LINKFIELD',
-              Keyword => 'KEYWORDFIELD'
-
-           );
-
-
-# }}}
-
-# {{{ sub SortFields
-
-@SORTFIELDS = qw(id Status Owner Created Due Starts Started
-                Queue Subject Told Started 
-                   Resolved LastUpdated Priority TimeWorked TimeLeft);
-
-=head2 SortFields
-
-Returns the list of fields that lists of tickets can easily be sorted by
-
-=cut
-
-
-sub SortFields {
-       my $self = shift;
-       return(@SORTFIELDS);
-}
-
-
-# }}}
-
-# {{{ Limit the result set based on content
-
-# {{{ sub Limit 
-
-=head2 Limit
-
-Takes a paramhash with the fields FIELD, OPERATOR, VALUE and DESCRIPTION
-Generally best called from LimitFoo methods
-
-=cut
-sub Limit {
-    my $self = shift;
-    my %args = ( FIELD => undef,
-                OPERATOR => '=',
-                VALUE => undef,
-                DESCRIPTION => undef,
-                @_
-              );
-   $args{'DESCRIPTION'} = "Autodescribed: ".$args{'FIELD'} . $args{'OPERATOR'} . $args{'VALUE'},
-    if (!defined $args{'DESCRIPTION'}) ;
-
-    my $index = $self->_NextIndex;
-    
-    #make the TicketRestrictions hash the equivalent of whatever we just passed in;
-    
-    %{$self->{'TicketRestrictions'}{$index}} = %args;
-
-    $self->{'RecalcTicketLimits'} = 1;
-
-    # If we're looking at the effective id, we don't want to append the other clause
-    # which limits us to tickets where id = effective id 
-    if ($args{'FIELD'} eq 'EffectiveId') {
-        $self->{'looking_at_effective_id'} = 1;
-    }
-
-    return ($index);
-}
-
-# }}}
-
-
-
-
-=head2 FreezeLimits
-
-Returns a frozen string suitable for handing back to ThawLimits.
-
-=cut
-# {{{ sub FreezeLimits
-
-sub FreezeLimits {
-       my $self = shift;
-       require FreezeThaw;
-       return (FreezeThaw::freeze($self->{'TicketRestrictions'},
-                                  $self->{'restriction_index'}
-                                 ));
-}
-
-# }}}
-
-=head2 ThawLimits
-
-Take a frozen Limits string generated by FreezeLimits and make this tickets
-object have that set of limits.
-
-=cut
-# {{{ sub ThawLimits
-
-sub ThawLimits {
-       my $self = shift;
-       my $in = shift;
-       
-       #if we don't have $in, get outta here.
-       return undef unless ($in);
-
-       $self->{'RecalcTicketLimits'} = 1;
-
-       require FreezeThaw;
-       
-       #We don't need to die if the thaw fails.
-       
-       eval {
-               ($self->{'TicketRestrictions'},
-               $self->{'restriction_index'}
-               ) = FreezeThaw::thaw($in);
-       }
-
-}
-
-# }}}
-
-# {{{ Limit by enum or foreign key
-
-# {{{ sub LimitQueue
-
-=head2 LimitQueue
-
-LimitQueue takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of = or !=. (It defaults to =).
-VALUE is a queue id. 
-
-=cut
-
-sub LimitQueue {
-    my $self = shift;
-    my %args = (VALUE => undef,
-               OPERATOR => '=',
-               @_);
-
-    #TODO  VALUE should also take queue names and queue objects
-    my $queue = new RT::Queue($self->CurrentUser);
-    $queue->Load($args{'VALUE'});
-    
-    #TODO check for a valid queue here
-
-    $self->Limit (FIELD => 'Queue',
-                 VALUE => $queue->id(),
-                 OPERATOR => $args{'OPERATOR'},
-                 DESCRIPTION => 'Queue ' .  $args{'OPERATOR'}. " ". $queue->Name
-                );
-    
-}
-# }}}
-
-# {{{ sub LimitStatus
-
-=head2 LimitStatus
-
-Takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of = or !=.
-VALUE is a status.
-
-=cut
-
-sub LimitStatus {
-    my $self = shift;
-    my %args = ( OPERATOR => '=',
-                  @_);
-    $self->Limit (FIELD => 'Status',
-                 VALUE => $args{'VALUE'},
-                 OPERATOR => $args{'OPERATOR'},
-                 DESCRIPTION => 'Status ' .  $args{'OPERATOR'}. " ". $args{'VALUE'},
-                );
-}
-
-# }}}
-
-# {{{ sub LimitType
-
-=head2 LimitType
-
-Takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of = or !=, it defaults to "=".
-VALUE is a string to search for in the type of the ticket.
-
-=cut
-
-sub LimitType {
-    my $self = shift;
-    my %args = (OPERATOR => '=',
-               VALUE => undef,
-               @_);
-    $self->Limit (FIELD => 'Type',
-                  VALUE => $args{'VALUE'},
-                  OPERATOR => $args{'OPERATOR'},
-                  DESCRIPTION => 'Type ' .  $args{'OPERATOR'}. " ". $args{'Limit'},
-                 );
-}
-
-# }}}
-
-# }}}
-
-# {{{ Limit by string field
-
-# {{{ sub LimitSubject
-
-=head2 LimitSubject
-
-Takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of = or !=.
-VALUE is a string to search for in the subject of the ticket.
-
-=cut
-
-sub LimitSubject {
-    my $self = shift;
-    my %args = (@_);
-    $self->Limit (FIELD => 'Subject',
-                 VALUE => $args{'VALUE'},
-                 OPERATOR => $args{'OPERATOR'},
-                 DESCRIPTION => 'Subject ' .  $args{'OPERATOR'}. " ". $args{'VALUE'},
-                );
-}
-
-# }}}
-
-# }}}
-
-# {{{ Limit based on ticket numerical attributes
-# Things that can be > < = !=
-
-# {{{ sub LimitId
-
-=head2 LimitId
-
-Takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of =, >, < or !=.
-VALUE is a ticket Id to search for
-
-=cut
-
-sub LimitId {
-    my $self = shift;
-    my %args = (OPERATOR => '=',
-                @_);
-    
-    $self->Limit (FIELD => 'id',
-                  VALUE => $args{'VALUE'},
-                  OPERATOR => $args{'OPERATOR'},
-                  DESCRIPTION => 'Id ' .  $args{'OPERATOR'}. " ". $args{'VALUE'},
-                 );
-}
-
-# }}}
-
-# {{{ sub LimitPriority
-
-=head2 LimitPriority
-
-Takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of =, >, < or !=.
-VALUE is a value to match the ticket\'s priority against
-
-=cut
-
-sub LimitPriority {
-    my $self = shift;
-    my %args = (@_);
-    $self->Limit (FIELD => 'Priority',
-                 VALUE => $args{'VALUE'},
-                 OPERATOR => $args{'OPERATOR'},
-                 DESCRIPTION => 'Priority ' .  $args{'OPERATOR'}. " ". $args{'VALUE'},
-                );
-}
-
-# }}}
-
-# {{{ sub LimitInitialPriority
-
-=head2 LimitInitialPriority
-
-Takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of =, >, < or !=.
-VALUE is a value to match the ticket\'s initial priority against
-
-
-=cut
-
-sub LimitInitialPriority {
-    my $self = shift;
-    my %args = (@_);
-    $self->Limit (FIELD => 'InitialPriority',
-                 VALUE => $args{'VALUE'},
-                 OPERATOR => $args{'OPERATOR'},
-                 DESCRIPTION => 'Initial Priority ' .  $args{'OPERATOR'}. " ". $args{'VALUE'},
-                );
-}
-
-# }}}
 
-# {{{ sub LimitFinalPriority
-
-=head2 LimitFinalPriority
-
-Takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of =, >, < or !=.
-VALUE is a value to match the ticket\'s final priority against
-
-=cut
-
-sub LimitFinalPriority {
-    my $self = shift;
-    my %args = (@_);
-    $self->Limit (FIELD => 'FinalPriority',
-                 VALUE => $args{'VALUE'},
-                 OPERATOR => $args{'OPERATOR'},
-                 DESCRIPTION => 'Final Priority ' .  $args{'OPERATOR'}. " ". $args{'VALUE'},
-                );
-}
-
-# }}}
-
-# {{{ sub LimitTimeWorked
-
-=head2 LimitTimeWorked
-
-Takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of =, >, < or !=.
-VALUE is a value to match the ticket's TimeWorked attribute
-
-=cut
-
-sub LimitTimeWorked {
-    my $self = shift;
-    my %args = (@_);
-    $self->Limit (FIELD => 'TimeWorked',
-                 VALUE => $args{'VALUE'},
-                 OPERATOR => $args{'OPERATOR'},
-                 DESCRIPTION => 'Time worked ' .  $args{'OPERATOR'}. " ". $args{'VALUE'},
-                );
-}
-
-# }}}
-
-# {{{ sub LimitTimeLeft
-
-=head2 LimitTimeLeft
-
-Takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of =, >, < or !=.
-VALUE is a value to match the ticket's TimeLeft attribute
-
-=cut
-
-sub LimitTimeLeft {
-    my $self = shift;
-    my %args = (@_);
-    $self->Limit (FIELD => 'TimeLeft',
-                 VALUE => $args{'VALUE'},
-                 OPERATOR => $args{'OPERATOR'},
-                 DESCRIPTION => 'Time left ' .  $args{'OPERATOR'}. " ". $args{'VALUE'},
-                );
-}
-
-# }}}
-
-# }}}
-
-# {{{ Limiting based on attachment attributes
-
-# {{{ sub LimitContent
-
-=head2 LimitContent
-
-Takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of =, LIKE, NOT LIKE or !=.
-VALUE is a string to search for in the body of the ticket
-
-=cut
-sub LimitContent {
-    my $self = shift;
-    my %args = (@_);
-    $self->Limit (FIELD => 'Content',
-                 VALUE => $args{'VALUE'},
-                 OPERATOR => $args{'OPERATOR'},
-                 DESCRIPTION => 'Ticket content ' .  $args{'OPERATOR'}. " ". $args{'VALUE'},
-                );
-}
-
-# }}}
-# {{{ sub LimitContentType
-
-=head2 LimitContentType
-
-Takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of =, LIKE, NOT LIKE or !=.
-VALUE is a content type to search ticket attachments for
-
-=cut
-  
-sub LimitContentType {
-    my $self = shift;
-    my %args = (@_);
-    $self->Limit (FIELD => 'ContentType',
-                 VALUE => $args{'VALUE'},
-                 OPERATOR => $args{'OPERATOR'},
-                 DESCRIPTION => 'Ticket content type ' .  $args{'OPERATOR'}. " ". $args{'VALUE'},
-                );
-}
-# }}}
-
-# }}}
-
-# {{{ Limiting based on people
-
-# {{{ sub LimitOwner
-
-=head2 LimitOwner
-
-Takes a paramhash with the fields OPERATOR and VALUE.
-OPERATOR is one of = or !=.
-VALUE is a user id.
-
-=cut
-
-sub LimitOwner {
-    my $self = shift;
-    my %args = ( OPERATOR => '=',
-                 @_);
-    
-    my $owner = new RT::User($self->CurrentUser);
-    $owner->Load($args{'VALUE'});
-    $self->Limit (FIELD => 'Owner',
-                 VALUE => $owner->Id,
-                 OPERATOR => $args{'OPERATOR'},
-                 DESCRIPTION => 'Owner ' .  $args{'OPERATOR'}. " ". $owner->Name()
-                );
-    
-}
-
-# }}}
-
-# {{{ Limiting watchers
-
-# {{{ sub LimitWatcher
+use RT::SearchBuilder;
+use RT::Ticket;
 
+use vars qw( @ISA );
+@ISA= qw(RT::SearchBuilder);
 
-=head2 LimitWatcher
-  
-  Takes a paramhash with the fields OPERATOR, TYPE and VALUE.
-  OPERATOR is one of =, LIKE, NOT LIKE or !=.
-  VALUE is a value to match the ticket\'s watcher email addresses against
-  TYPE is the sort of watchers you want to match against. Leave it undef if you want to search all of them
 
-=cut
-   
-sub LimitWatcher {
+sub _Init {
     my $self = shift;
-    my %args = ( OPERATOR => '=',
-                VALUE => undef,
-                TYPE => undef,
-               @_);
-
-
-    #build us up a description
-    my ($watcher_type, $desc);
-    if ($args{'TYPE'}) {
-       $watcher_type = $args{'TYPE'};
-    }
-    else {
-       $watcher_type = "Watcher";
-    }
-    $desc = "$watcher_type ".$args{'OPERATOR'}." ".$args{'VALUE'};
-
-
-    $self->Limit (FIELD => 'Watcher',
-                 VALUE => $args{'VALUE'},
-                 OPERATOR => $args{'OPERATOR'},
-                 TYPE => $args{'TYPE'},
-                 DESCRIPTION => "$desc"
-                );
-}
-
-# }}}
-
-# {{{ sub LimitRequestor
+    $self->{'table'} = 'Tickets';
+    $self->{'primary_key'} = 'id';
 
-=head2 LimitRequestor
 
-It\'s like LimitWatcher, but it presets TYPE to Requestor
-
-=cut
-
-
-sub LimitRequestor {
-    my $self = shift;
-    $self->LimitWatcher(TYPE=> 'Requestor', @_);
+    return ( $self->SUPER::_Init(@_) );
 }
 
-# }}}
-
-# {{{ sub LimitCc
 
-=head2 LimitCC
+=item NewItem
 
-It\'s like LimitWatcher, but it presets TYPE to Cc
+Returns an empty new RT::Ticket item
 
 =cut
 
-sub LimitCc {
-    my $self = shift;
-    $self->LimitWatcher(TYPE=> 'Cc', @_);
-}
-
-# }}}
-
-# {{{ sub LimitAdminCc
-
-=head2 LimitAdminCc
-
-It\'s like LimitWatcher, but it presets TYPE to AdminCc
-
-=cut
-  
-sub LimitAdminCc {
+sub NewItem {
     my $self = shift;
-    $self->LimitWatcher(TYPE=> 'AdminCc', @_);
+    return(RT::Ticket->new($self->CurrentUser));
 }
 
-# }}}
-
-# }}}
-
-# }}}
+        eval "require RT::Tickets_Overlay";
+        if ($@ && $@ !~ qr{^Can't locate RT/Tickets_Overlay.pm}) {
+            die $@;
+        };
 
-# {{{ Limiting based on links
+        eval "require RT::Tickets_Vendor";
+        if ($@ && $@ !~ qr{^Can't locate RT/Tickets_Vendor.pm}) {
+            die $@;
+        };
 
-# {{{ LimitLinkedTo
+        eval "require RT::Tickets_Local";
+        if ($@ && $@ !~ qr{^Can't locate RT/Tickets_Local.pm}) {
+            die $@;
+        };
 
-=head2 LimitLinkedTo
 
-LimitLinkedTo takes a paramhash with two fields: TYPE and TARGET
-TYPE limits the sort of relationship we want to search on
 
-TARGET is the id or URI of the TARGET of the link
-(TARGET used to be 'TICKET'.  'TICKET' is deprecated, but will be treated as TARGET
 
-=cut
-
-sub LimitLinkedTo {
-    my $self = shift;
-    my %args = ( 
-               TICKET => undef,
-               TARGET => undef,
-               TYPE => undef,
-                @_);
-
-
-    $self->Limit( FIELD => 'LinkedTo',
-                 BASE => undef,
-                 TARGET => ($args{'TARGET'} || $args{'TICKET'}),
-                 TYPE => $args{'TYPE'},
-                 DESCRIPTION => "Tickets ".$args{'TYPE'}." by ".($args{'TARGET'} || $args{'TICKET'})
-               );
-}
-
-
-# }}}
+=head1 SEE ALSO
 
-# {{{ LimitLinkedFrom
+This class allows "overlay" methods to be placed
+into the following files _Overlay is for a System overlay by the original author,
+_Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customizations.  
 
-=head2 LimitLinkedFrom
+These overlay files can contain new subs or subs to replace existing subs in this module.
 
-LimitLinkedFrom takes a paramhash with two fields: TYPE and BASE
-TYPE limits the sort of relationship we want to search on
+If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line 
 
+   no warnings qw(redefine);
 
-BASE is the id or URI of the BASE of the link
-(BASE used to be 'TICKET'.  'TICKET' is deprecated, but will be treated as BASE
+so that perl does not kick and scream when you redefine a subroutine or variable in your overlay.
 
+RT::Tickets_Overlay, RT::Tickets_Vendor, RT::Tickets_Local
 
 =cut
 
-sub LimitLinkedFrom {
-    my $self = shift;
-    my %args = ( BASE => undef,
-                TICKET => undef,
-                TYPE => undef,
-                @_);
-
-    
-    $self->Limit( FIELD => 'LinkedTo',
-                 TARGET => undef,
-                 BASE => ($args{'BASE'} || $args{'TICKET'}),
-                 TYPE => $args{'TYPE'},
-                 DESCRIPTION => "Tickets " .($args{'BASE'} || $args{'TICKET'}) ." ".$args{'TYPE'}
-               );
-}
-
-
-# }}}
-
-# {{{ LimitMemberOf 
-sub LimitMemberOf {
-    my $self = shift;
-    my $ticket_id = shift;
-    $self->LimitLinkedTo ( TARGET=> "$ticket_id",
-                          TYPE => 'MemberOf',
-                         );
-    
-}
-# }}}
-
-# {{{ LimitHasMember
-sub LimitHasMember {
-    my $self = shift;
-    my $ticket_id =shift;
-    $self->LimitLinkedFrom ( BASE => "$ticket_id",
-                            TYPE => 'MemberOf',
-                            );
-    
-}
-# }}}
-
-# {{{ LimitDependsOn
-
-sub LimitDependsOn {
-    my $self = shift;
-    my $ticket_id = shift;
-    $self->LimitLinkedTo ( TARGET => "$ticket_id",
-                           TYPE => 'DependsOn',
-                          );
-    
-}
-
-# }}}
-
-# {{{ LimitDependedOnBy
-
-sub LimitDependedOnBy {
-    my $self = shift;
-    my $ticket_id = shift;
-    $self->LimitLinkedFrom (  BASE => "$ticket_id",
-                               TYPE => 'DependsOn',
-                            );
-    
-}
-
-# }}}
-
-
-# {{{ LimitRefersTo
-
-sub LimitRefersTo {
-    my $self = shift;
-    my $ticket_id = shift;
-    $self->LimitLinkedTo ( TARGET => "$ticket_id",
-                           TYPE => 'RefersTo',
-                          );
-    
-}
-
-# }}}
-
-# {{{ LimitReferredToBy
-
-sub LimitReferredToBy {
-    my $self = shift;
-    my $ticket_id = shift;
-    $self->LimitLinkedFrom (  BASE=> "$ticket_id",
-                               TYPE => 'RefersTo',
-                            );
-    
-}
-
-# }}}
-
-# }}}
-
-# {{{ limit based on ticket date attribtes
-
-# {{{ sub LimitDate
-
-=head2 LimitDate (FIELD => 'DateField', OPERATOR => $oper, VALUE => $ISODate)
-
-Takes a paramhash with the fields FIELD OPERATOR and VALUE.
-
-OPERATOR is one of > or < 
-VALUE is a date and time in ISO format in GMT
-FIELD is one of Starts, Started, Told, Created, Resolved, LastUpdated
-
-There are also helper functions of the form LimitFIELD that eliminate
-the need to pass in a FIELD argument.
-
-=cut
-
-sub LimitDate {
-    my $self = shift;
-    my %args = (
-                  FIELD => undef,
-                 VALUE => $args{'VALUE'},
-                 OPERATOR => $args{'OPERATOR'},
-
-                  @_);
-
-    #Set the description if we didn't get handed it above
-    unless ($args{'DESCRIPTION'} ) {
-       $args{'DESCRIPTION'} = $args{'FIELD'} . " " .$args{'OPERATOR'}. " ". $args{'VALUE'} . " GMT"
-    }
-
-    $self->Limit (%args);
-
-}
-
-# }}}
-
-
-
-
-sub LimitCreated {
-    my $self = shift;
-    $self->LimitDate( FIELD => 'Created', @_);
-}
-sub LimitDue {
-    my $self = shift;
-    $self->LimitDate( FIELD => 'Due', @_);
-
-}
-sub LimitStarts {
-    my $self = shift;
-    $self->LimitDate( FIELD => 'Starts', @_);
-
-}
-sub LimitStarted {
-    my $self = shift;
-    $self->LimitDate( FIELD => 'Started', @_);
-}
-sub LimitResolved { 
-    my $self = shift;
-    $self->LimitDate( FIELD => 'Resolved', @_);
-}
-sub LimitTold {
-    my $self = shift;
-    $self->LimitDate( FIELD => 'Told', @_);
-}
-sub LimitLastUpdated {
-    my $self = shift;
-    $self->LimitDate( FIELD => 'LastUpdated', @_);
-}
-#
-# {{{ sub LimitTransactionDate
-
-=head2 LimitTransactionDate (OPERATOR => $oper, VALUE => $ISODate)
-
-Takes a paramhash with the fields FIELD OPERATOR and VALUE.
-
-OPERATOR is one of > or < 
-VALUE is a date and time in ISO format in GMT
-
-
-=cut
-
-sub LimitTransactionDate {
-    my $self = shift;
-    my %args = (
-                  FIELD => 'TransactionDate',
-                 VALUE => $args{'VALUE'},
-                 OPERATOR => $args{'OPERATOR'},
-
-                  @_);
-
-    #Set the description if we didn't get handed it above
-    unless ($args{'DESCRIPTION'} ) {
-       $args{'DESCRIPTION'} = $args{'FIELD'} . " " .$args{'OPERATOR'}. " ". $args{'VALUE'} . " GMT"
-    }
-
-    $self->Limit (%args);
-
-}
-
-# }}}
-
-# }}}
-
-# {{{ sub LimitKeyword
-
-=head2 LimitKeyword 
-
-Takes a paramhash of key/value pairs with the following keys:
-
-=over 4
-
-=item KEYWORDSELECT - KeywordSelect id
-
-=item OPERATOR - (for KEYWORD only - KEYWORDSELECT operator is always `=')
-
-=item KEYWORD - Keyword id
-
-=back
-
-=cut
-
-sub LimitKeyword {
-    my $self = shift;
-    my %args = ( KEYWORD => undef,
-                 KEYWORDSELECT => undef,
-                OPERATOR => '=',
-                DESCRIPTION => undef,
-                FIELD => 'Keyword',
-                QUOTEVALUE => 1,
-                @_
-              );
-
-    use RT::KeywordSelect;
-    my $KeywordSelect = RT::KeywordSelect->new($self->CurrentUser);
-    $KeywordSelect->Load($args{KEYWORDSELECT});
-    
-
-    # Below, We're checking to see whether the keyword we're searching for
-    # is null or not.
-    # This could probably be rewritten to be easier to read and  understand
-
-    
-    #If we are looking to compare with a null value.
-    if ($args{'OPERATOR'} =~ /is/i)  {
-       if ($args{'OPERATOR'} =~ /^is$/i) {
-           $args{'DESCRIPTION'} ||= "Keyword Selection ". $KeywordSelect->Name . " has no value";
-       }
-       elsif ($args{'OPERATOR'} =~ /^is not$/i) {
-           $args{'DESCRIPTION'} ||= "Keyword Selection ". $KeywordSelect->Name . " has a value";
-       }
-    }
-       # if we're not looking to compare with a null value
-    else {     
-        use RT::Keyword;
-       my $Keyword = RT::Keyword->new($self->CurrentUser);
-       $Keyword->Load($args{KEYWORD});
-       $args{'DESCRIPTION'} ||= "Keyword Selection " . $KeywordSelect->Name.  " $args{OPERATOR} ". $Keyword->Name;
-    }
-    
-    $args{SingleValued} = $KeywordSelect->Single();
-    
-    my $index = $self->_NextIndex;
-    %{$self->{'TicketRestrictions'}{$index}} = %args;
-    
-    $self->{'RecalcTicketLimits'} = 1;
-    return ($index);
-}
-
-# }}}
-
-# {{{ sub _NextIndex
-
-=head2 _NextIndex
-
-Keep track of the counter for the array of restrictions
-
-=cut
-
-sub _NextIndex {
-    my $self = shift;
-    return ($self->{'restriction_index'}++);
-}
-# }}}
-
-# }}} 
-
-# {{{ Core bits to make this a DBIx::SearchBuilder object
-
-# {{{ sub _Init 
-sub _Init  {
-    my $self = shift;
-    $self->{'table'} = "Tickets";
-    $self->{'RecalcTicketLimits'} = 1;
-    $self->{'looking_at_effective_id'} = 0;
-    $self->{'restriction_index'} =1;
-    $self->{'primary_key'} = "id";
-    $self->SUPER::_Init(@_);
-
-}
-# }}}
-
-# {{{ sub NewItem 
-sub NewItem  {
-  my $self = shift;
-  return(RT::Ticket->new($self->CurrentUser));
-
-}
-# }}}
-
-# {{{ sub Count
-sub Count {
-  my $self = shift;
-  $self->_ProcessRestrictions if ($self->{'RecalcTicketLimits'} == 1 );
-  return($self->SUPER::Count());
-}
-# }}}
-
-# {{{ sub ItemsArrayRef
-
-=head2 ItemsArrayRef
-
-Returns a reference to the set of all items found in this search
-
-=cut
-
-sub ItemsArrayRef {
-    my $self = shift;
-    my @items;
-    
-    my $placeholder = $self->_ItemsCounter;
-    $self->GotoFirstItem();
-    while (my $item = $self->Next) { 
-       push (@items, $item);
-    }
-    
-    $self->GotoItem($placeholder);
-    return(\@items);
-}
-# }}}
-
-# {{{ sub Next 
-sub Next {
-       my $self = shift;
-       
-       $self->_ProcessRestrictions if ($self->{'RecalcTicketLimits'} == 1 );
-
-       my $Ticket = $self->SUPER::Next();
-       if ((defined($Ticket)) and (ref($Ticket))) {
-
-           #Make sure we _never_ show dead tickets
-           #TODO we should be doing this in the where clause.
-           #but you can't do multiple clauses on the same field just yet :/
-
-           if ($Ticket->Status eq 'dead') {
-               return($self->Next());
-           }
-           elsif ($Ticket->CurrentUserHasRight('ShowTicket')) {
-               return($Ticket);
-           }
-
-           #If the user doesn't have the right to show this ticket
-           else {      
-               return($self->Next());
-           }
-       }
-       #if there never was any ticket
-       else {
-               return(undef);
-       }       
-
-}
-# }}}
-
-# }}}
-
-# {{{ Deal with storing and restoring restrictions
-
-# {{{ sub LoadRestrictions
-
-=head2 LoadRestrictions
-
-LoadRestrictions takes a string which can fully populate the TicketRestrictons hash.
-TODO It is not yet implemented
-
-=cut
-
-# }}}
-
-# {{{ sub DescribeRestrictions
-
-=head2 DescribeRestrictions
-
-takes nothing.
-Returns a hash keyed by restriction id. 
-Each element of the hash is currently a one element hash that contains DESCRIPTION which
-is a description of the purpose of that TicketRestriction
-
-=cut
-
-sub DescribeRestrictions  {
-    my $self = shift;
-    
-    my ($row, %listing);
-    
-    foreach $row (keys %{$self->{'TicketRestrictions'}}) {
-       $listing{$row} = $self->{'TicketRestrictions'}{$row}{'DESCRIPTION'};
-    }
-    return (%listing);
-}
-# }}}
-
-# {{{ sub RestrictionValues
-
-=head2 RestrictionValues FIELD
-
-Takes a restriction field and returns a list of values this field is restricted
-to.
-
-=cut
-
-sub RestrictionValues {
-    my $self = shift;
-    my $field = shift;
-    map $self->{'TicketRestrictions'}{$_}{'VALUE'},
-      grep {
-             $self->{'TicketRestrictions'}{$_}{'FIELD'} eq $field
-             && $self->{'TicketRestrictions'}{$_}{'OPERATOR'} eq "="
-           }
-        keys %{$self->{'TicketRestrictions'}};
-}
-
-# }}}
-
-# {{{ sub ClearRestrictions
-
-=head2 ClearRestrictions
-
-Removes all restrictions irretrievably
-
-=cut
-  
-sub ClearRestrictions {
-    my $self = shift;
-    delete $self->{'TicketRestrictions'};
-    $self->{'looking_at_effective_id'} = 0;
-    $self->{'RecalcTicketLimits'} =1;
-}
-
-# }}}
-
-# {{{ sub DeleteRestriction
-
-=head2 DeleteRestriction
-
-Takes the row Id of a restriction (From DescribeRestrictions' output, for example.
-Removes that restriction from the session's limits.
-
-=cut
-
-
-sub DeleteRestriction {
-    my $self = shift;
-    my $row = shift;
-    delete $self->{'TicketRestrictions'}{$row};
-    
-    $self->{'RecalcTicketLimits'} = 1;
-    #make the underlying easysearch object forget all its preconceptions
-}
-
-# }}}
-
-# {{{ sub _ProcessRestrictions 
-
-sub _ProcessRestrictions {
-    my $self = shift;
-
-    #Need to clean the EasySearch slate because it makes things too sticky
-    $self->CleanSlate();
-
-    #Blow away ticket aliases since we'll need to regenerate them for a new search
-    delete $self->{'TicketAliases'};
-    delete $self->{KeywordsAliases};
-
-    my $row;
-    
-    foreach $row (keys %{$self->{'TicketRestrictions'}}) {
-        my $restriction = $self->{'TicketRestrictions'}{$row};
-       # {{{ if it's an int
-       
-       if ($TYPES{$restriction->{'FIELD'}} eq 'INT' ) {
-           if ($restriction->{'OPERATOR'} =~ /^(=|!=|>|<|>=|<=)$/) {
-               $self->SUPER::Limit( FIELD => $restriction->{'FIELD'},
-                             ENTRYAGGREGATOR => 'AND',
-                             OPERATOR => $restriction->{'OPERATOR'},
-                             VALUE => $restriction->{'VALUE'},
-                             );
-           }
-       }
-       # }}}
-       # {{{ if it's an enum
-       elsif ($TYPES{$restriction->{'FIELD'}} eq 'ENUM') {
-           
-           if ($restriction->{'OPERATOR'} eq '=') {
-               $self->SUPER::Limit( FIELD => $restriction->{'FIELD'},
-                             ENTRYAGGREGATOR => 'OR',
-                             OPERATOR => '=',
-                             VALUE => $restriction->{'VALUE'},
-                           );
-           }
-           elsif ($restriction->{'OPERATOR'} eq '!=') {
-               $self->SUPER::Limit( FIELD => $restriction->{'FIELD'},
-                             ENTRYAGGREGATOR => 'AND',
-                             OPERATOR => '!=',
-                             VALUE => $restriction->{'VALUE'},
-                           );
-           }
-           
-       }
-       # }}}
-       # {{{ if it's a date
-
-       elsif ($TYPES{$restriction->{'FIELD'}} eq 'DATE') {
-           $self->SUPER::Limit( FIELD => $restriction->{'FIELD'},
-                                ENTRYAGGREGATOR => 'AND',
-                                OPERATOR => $restriction->{'OPERATOR'},
-                                VALUE => $restriction->{'VALUE'},
-                              );
-       }
-       # }}}
-       # {{{ if it's a string
-
-       elsif ($TYPES{$restriction->{'FIELD'}} eq 'STRING') {
-           
-           if ($restriction->{'OPERATOR'} eq '=') {
-               $self->SUPER::Limit( FIELD => $restriction->{'FIELD'},
-                             ENTRYAGGREGATOR => 'OR',
-                             OPERATOR => '=',
-                             VALUE => $restriction->{'VALUE'},
-                             CASESENSITIVE => 0
-                           );
-           }
-           elsif ($restriction->{'OPERATOR'} eq '!=') {
-               $self->SUPER::Limit( FIELD => $restriction->{'FIELD'},
-                             ENTRYAGGREGATOR => 'AND',
-                             OPERATOR => '!=',
-                             VALUE => $restriction->{'VALUE'},
-                             CASESENSITIVE => 0
-                           );
-           }
-           elsif ($restriction->{'OPERATOR'} eq 'LIKE') {
-               $self->SUPER::Limit( FIELD => $restriction->{'FIELD'},
-                             ENTRYAGGREGATOR => 'AND',
-                             OPERATOR => 'LIKE',
-                             VALUE => $restriction->{'VALUE'},
-                             CASESENSITIVE => 0
-                           );
-           }
-           elsif ($restriction->{'OPERATOR'} eq 'NOT LIKE') {
-               $self->SUPER::Limit( FIELD => $restriction->{'FIELD'},
-                             ENTRYAGGREGATOR => 'AND',
-                             OPERATOR => 'NOT LIKE',
-                             VALUE => $restriction->{'VALUE'},
-                             CASESENSITIVE => 0
-                           );
-           }
-       }
-
-       # }}}
-       # {{{ if it's Transaction content that we're hunting for
-       elsif ($TYPES{$restriction->{'FIELD'}} eq 'TRANSFIELD') {
-
-           #Basically, we want to make sure that the limits apply to the same attachment,
-           #rather than just another attachment for the same ticket, no matter how many 
-           #clauses we lump on. 
-           #We put them in TicketAliases so that they get nuked when we redo the join.
-           
-           unless (defined $self->{'TicketAliases'}{'TransFieldAlias'}) {
-               $self->{'TicketAliases'}{'TransFieldAlias'} = $self->NewAlias ('Transactions');
-           }
-           unless (defined $self->{'TicketAliases'}{'TransFieldAttachAlias'}){
-               $self->{'TicketAliases'}{'TransFieldAttachAlias'} = $self->NewAlias('Attachments');
-               
-           }
-           #Join transactions to attachments
-           $self->Join( ALIAS1 => $self->{'TicketAliases'}{'TransFieldAttachAlias'},  
-                        FIELD1 => 'TransactionId',
-                        ALIAS2 => $self->{'TicketAliases'}{'TransFieldAlias'}, FIELD2=> 'id');
-           
-           #Join transactions to tickets
-           $self->Join( ALIAS1 => 'main', FIELD1 => $self->{'primary_key'},
-                        ALIAS2 =>$self->{'TicketAliases'}{'TransFieldAlias'}, FIELD2 => 'Ticket');
-           
-           #Search for the right field
-           $self->SUPER::Limit(ALIAS => $self->{'TicketAliases'}{'TransFieldAttachAlias'},
-                                 ENTRYAGGREGATOR => 'AND',
-                                 FIELD =>    $restriction->{'FIELD'},
-                                 OPERATOR => $restriction->{'OPERATOR'} ,
-                                 VALUE =>    $restriction->{'VALUE'},
-                                 CASESENSITIVE => 0
-                               );
-           
-
-       }
-
-       # }}}
-       # {{{ if it's a Transaction date that we're hunting for
-       elsif ($TYPES{$restriction->{'FIELD'}} eq 'TRANSDATE') {
-
-           #Basically, we want to make sure that the limits apply to the same attachment,
-           #rather than just another attachment for the same ticket, no matter how many 
-           #clauses we lump on. 
-           #We put them in TicketAliases so that they get nuked when we redo the join.
-           
-           unless (defined $self->{'TicketAliases'}{'TransFieldAlias'}) {
-               $self->{'TicketAliases'}{'TransFieldAlias'} = $self->NewAlias ('Transactions');
-           }
-
-           #Join transactions to tickets
-           $self->Join( ALIAS1 => 'main', FIELD1 => $self->{'primary_key'},
-                        ALIAS2 =>$self->{'TicketAliases'}{'TransFieldAlias'}, FIELD2 => 'Ticket');
-           
-           #Search for the right field
-           $self->SUPER::Limit(ALIAS => $self->{'TicketAliases'}{'TransFieldAlias'},
-                               ENTRYAGGREGATOR => 'AND',
-                               FIELD =>    'Created',
-                               OPERATOR => $restriction->{'OPERATOR'} ,
-                               VALUE =>    $restriction->{'VALUE'} );
-       }
-
-       # }}}
-       # {{{ if it's a relationship that we're hunting for
-       
-       # Takes FIELD: which is something like "LinkedTo"
-       # takes TARGET or BASE which is the TARGET or BASE id that we're searching for
-       # takes TYPE which is the type of link we're looking for.
-
-       elsif ($TYPES{$restriction->{'FIELD'}} eq 'LINKFIELD') {
-
-           
-           my $LinkAlias = $self->NewAlias ('Links');
-
-           
-           #Make sure we get the right type of link, if we're restricting it
-           if ($restriction->{'TYPE'}) {
-               $self->SUPER::Limit(ALIAS => $LinkAlias,
-                                   ENTRYAGGREGATOR => 'AND',
-                                   FIELD =>   'Type',
-                                   OPERATOR => '=',
-                                   VALUE =>    $restriction->{'TYPE'} );
-           }
-           
-           #If we're trying to limit it to things that are target of
-           if ($restriction->{'TARGET'}) {
-               
-
-               # If the TARGET is an integer that means that we want to look at the LocalTarget
-               # field. otherwise, we want to look at the "Target" field
-
-               my ($matchfield);
-               if ($restriction->{'TARGET'} =~/^(\d+)$/) {
-                   $matchfield = "LocalTarget";
-               }       
-               else {
-                   $matchfield = "Target";
-               }       
-
-               $self->SUPER::Limit(ALIAS => $LinkAlias,
-                                   ENTRYAGGREGATOR => 'AND',
-                                   FIELD =>   $matchfield,
-                                   OPERATOR => '=',
-                                   VALUE =>    $restriction->{'TARGET'} );
-
-               
-               #If we're searching on target, join the base to ticket.id
-               $self->Join( ALIAS1 => 'main', FIELD1 => $self->{'primary_key'},
-                            ALIAS2 => $LinkAlias,
-                            FIELD2 => 'LocalBase');
-
-           
-
-
-           }
-           #If we're trying to limit it to things that are base of
-           elsif ($restriction->{'BASE'}) {
-
-
-               # If we're trying to match a numeric link, we want to look at LocalBase,
-               # otherwise we want to look at "Base"
-
-               my ($matchfield);
-               if ($restriction->{'BASE'} =~/^(\d+)$/) {
-                   $matchfield = "LocalBase";
-               }       
-               else {
-                   $matchfield = "Base";
-               }       
-
-
-               $self->SUPER::Limit(ALIAS => $LinkAlias,
-                                   ENTRYAGGREGATOR => 'AND',
-                                   FIELD => $matchfield,
-                                   OPERATOR => '=',
-                                   VALUE =>    $restriction->{'BASE'} );
-               
-               #If we're searching on base, join the target to ticket.id
-               $self->Join( ALIAS1 => 'main', FIELD1 => $self->{'primary_key'},
-                            ALIAS2 => $LinkAlias,
-                            FIELD2 => 'LocalTarget');
-               
-           }
-
-       }
-               
-       # }}}
-       # {{{ if it's a watcher that we're hunting for
-       elsif ($TYPES{$restriction->{'FIELD'}} eq 'WATCHERFIELD') {
-
-           my $Watch = $self->NewAlias('Watchers');
-
-           #Join watchers to users
-           my $User = $self->Join( TYPE => 'left',
-                                    ALIAS1 => $Watch, 
-                                    FIELD1 => 'Owner',
-                                    TABLE2 => 'Users', 
-                                    FIELD2 => 'id',
-                                  );
-
-           #Join Ticket to watchers
-           $self->Join( ALIAS1 => 'main', FIELD1 => 'id',
-                        ALIAS2 => $Watch, FIELD2 => 'Value');
-
-
-           #Make sure we're only talking about ticket watchers
-           $self->SUPER::Limit( ALIAS => $Watch,
-                                FIELD => 'Scope',
-                                VALUE => 'Ticket',
-                                OPERATOR => '=');
-
-
-           # Find email address watchers
-           $self->SUPER::Limit( SUBCLAUSE => 'WatcherEmailAddress',
-                                ALIAS => $Watch,
-                                FIELD => 'Email',
-                                ENTRYAGGREGATOR => 'OR',
-                                VALUE => $restriction->{'VALUE'},
-                                OPERATOR => $restriction->{'OPERATOR'},
-                                CASESENSITIVE => 0
-                       );
-
-
-
-           #Find user watchers
-           $self->SUPER::Limit(
-                               SUBCLAUSE => 'WatcherEmailAddress',
-                               ALIAS => $User,
-                               FIELD => 'EmailAddress',
-                               ENTRYAGGREGATOR => 'OR',
-                               VALUE => $restriction->{'VALUE'},
-                               OPERATOR => $restriction->{'OPERATOR'},
-                               CASESENSITIVE => 0
-                              );
-
-           
-           #If we only want a specific type of watchers, then limit it to that
-           if ($restriction->{'TYPE'}) {
-               $self->SUPER::Limit( ALIAS => $Watch,
-                                    FIELD => 'Type',
-                                    ENTRYAGGREGATOR => 'OR',
-                                    VALUE => $restriction->{'TYPE'},
-                                    OPERATOR => '=');
-           }
-       }
-
-       # }}}
-       # {{{ if it's a keyword
-       elsif ($TYPES{$restriction->{'FIELD'}} eq 'KEYWORDFIELD') {
-           my $null_columns_ok;
-
-            my $ObjKeywordsAlias;
-           $ObjKeywordsAlias = $self->{KeywordsAliases}{$restriction->{'KEYWORDSELECT'}}
-             if $restriction->{SingleValued};
-           unless (defined $ObjKeywordsAlias) {
-             $ObjKeywordsAlias = $self->Join(
-                                              TYPE => 'left',
-                                              ALIAS1 => 'main',
-                                              FIELD1 => 'id',
-                                              TABLE2 => 'ObjectKeywords',
-                                              FIELD2 => 'ObjectId'
-                                             );
-             if ($restriction->{'SingleValued'}) {
-               $self->{KeywordsAliases}{$restriction->{'KEYWORDSELECT'}} 
-                 = $ObjKeywordsAlias;
-             }
-           }
-
-         
-            $self->SUPER::Limit(
-                               ALIAS => $ObjKeywordsAlias,
-                               FIELD => 'Keyword',
-                               OPERATOR => $restriction->{'OPERATOR'},
-                               VALUE => $restriction->{'KEYWORD'},
-                               QUOTEVALUE => $restriction->{'QUOTEVALUE'},
-                               ENTRYAGGREGATOR => 'OR',
-                               );
-           
-            if  ( ($restriction->{'OPERATOR'} =~ /^IS$/i) or 
-                 ($restriction->{'OPERATOR'} eq '!=') ) {
-               
-               $null_columns_ok=1;
-
-           } 
-
-           #If we're trying to find tickets where the keyword isn't somethng, also check ones where it _IS_ null
-           if ( $restriction->{'OPERATOR'} eq '!=') {
-               $self->SUPER::Limit(
-                                   ALIAS => $ObjKeywordsAlias,
-                                   FIELD => 'Keyword',
-                                   OPERATOR => 'IS',
-                                   VALUE => 'NULL',
-                                   QUOTEVALUE => 0,
-                                   ENTRYAGGREGATOR => 'OR',
-                                  );
-             }
-
-
-            $self->SUPER::Limit(LEFTJOIN => $ObjKeywordsAlias,
-                               FIELD => 'KeywordSelect',
-                               VALUE => $restriction->{'KEYWORDSELECT'},
-                               ENTRYAGGREGATOR => 'OR');
-
-
-            $self->SUPER::Limit( ALIAS => $ObjKeywordsAlias,
-                                 FIELD => 'ObjectType',
-                                 VALUE => 'Ticket',
-                                 ENTRYAGGREGATOR => 'AND');
-           
-           if ($null_columns_ok) {
-                $self->SUPER::Limit(ALIAS => $ObjKeywordsAlias,
-                                    FIELD => 'ObjectType',
-                                   OPERATOR => 'IS',
-                                    VALUE => 'NULL',
-                                   QUOTEVALUE => 0,
-                                    ENTRYAGGREGATOR => 'OR');
-           }
-          
-        }
-        # }}}
-
-    
-     }
-
-     
-     # here, we make sure we don't get any tickets that have been merged  into other tickets
-     # (Ticket Id == Ticket EffectiveId
-     # note that we _really_ don't want to do this if we're already looking at the effectiveid
-     if ($self->_isLimited && (! $self->{'looking_at_effective_id'})) {
-        $self->SUPER::Limit( FIELD => 'EffectiveId', 
-              OPERATOR => '=',
-              QUOTEVALUE => 0,
-              VALUE => 'main.id');   #TODO, we shouldn't be hard coding the tablename to main.
-      } 
-    $self->{'RecalcTicketLimits'} = 0;
-}
-
-# }}}
-
-# }}}
-
-# {{{ Deal with displaying rows of the listing 
-
-#
-#  Everything in this section is stub code for 2.2
-# It's not part of the API. It's not for your use
-# It's not for our use.
-#
-
-
-# {{{ sub SetListingFormat
-
-=head2 SetListingFormat
-
-Takes a single Format string as specified below. parses that format string and makes the various listing output
-things DTRT.
-
-=item Format strings
-
-Format strings are made up of a chain of Elements delimited with vertical pipes (|).
-Elements of a Format string 
-
-
-FormatString:    Element[::FormatString]
-
-Element:         AttributeName[;HREF=<URL>][;TITLE=<TITLE>]
-
-AttributeName    Id | Subject | Status | Owner | Priority | InitialPriority | TimeWorked | TimeLeft |
-  
-                 Keywords[;SELECT=<KeywordSelect>] | 
-       
-                <Created|Starts|Started|Contacted|Due|Resolved>Date<AsString|AsISO|AsAge>
-
-
-=cut
-
-
-
-
-#accept a format string
-
-
-
-sub SetListingFormat {
-    my $self = shift;
-    my $listing_format = shift;
-    
-    my ($element, $attribs);
-    my $i = 0;
-    foreach $element (split (/::/,$listing_format)) {
-       if ($element =~ /^(.*?);(.*)$/) {
-           $element = $1;
-           $attribs = $2;
-       }       
-       $self->{'format_string'}->[$i]->{'Element'} = $element;
-       foreach $attrib (split (/;/, $attribs)) {
-           my $value = "";
-           if ($attrib =~ /^(.*?)=(.*)$/) {
-               $attrib = $1;
-               $value = $2;
-           }   
-           $self->{'format_string'}->[$i]->{"$attrib"} = $val;
-           
-       }
-    
-    }
-    return(1);
-}
-
-# }}}
-
-# {{{ sub HeaderAsHTML
-sub HeaderAsHTML {
-    my $self = shift;
-    my $header = "";
-    my $col;
-    foreach $col ( @{[ $self->{'format_string'} ]}) {
-       $header .= "<TH>" . $self->_ColumnTitle($self->{'format_string'}->[$col]) . "</TH>";
-       
-    }
-    return ($header);
-}
-# }}}
-
-# {{{ sub HeaderAsText
-#Print text header
-sub HeaderAsText {
-    my $self = shift;
-    my ($header);
-    
-    return ($header);
-}
-# }}}
-
-# {{{ sub TicketAsHTMLRow
-#Print HTML row
-sub TicketAsHTMLRow {
-    my $self = shift;
-    my $Ticket = shift;
-    my ($row, $col);
-    foreach $col (@{[$self->{'format_string'}]}) {
-       $row .= "<TD>" . $self->_TicketColumnValue($ticket,$self->{'format_string'}->[$col]) . "</TD>";
-       
-    }
-    return ($row);
-}
-# }}}
-
-# {{{ sub TicketAsTextRow
-#Print text row
-sub TicketAsTextRow {
-    my $self = shift;
-    my ($row);
-
-    #TODO implement
-    
-    return ($row);
-}
-# }}}
-
-# {{{ _ColumnTitle {
-
-sub _ColumnTitle {
-    my $self = shift;
-    
-    # Attrib is a hash 
-    my $attrib = shift;
-    
-    # return either attrib->{'TITLE'} or..
-    if ($attrib->{'TITLE'}) {
-       return($attrib->{'TITLE'});
-    }  
-    # failing that, Look up the title in a hash
-    else {
-       #TODO create $self->{'ColumnTitles'};
-       return ($self->{'ColumnTitles'}->{$attrib->{'Element'}});
-    }  
-    
-}
-
-# }}}
-
-# {{{ _TicketColumnValue
-sub _TicketColumnValue {
-    my $self = shift;
-    my $Ticket = shift;
-    my $attrib = shift;
-
-    
-    my $out;
-
-  SWITCH: {
-       /^id/i && do {
-           $out = $Ticket->id;
-           last SWITCH; 
-       };
-       /^subj/i && do {
-           last SWITCH; 
-           $Ticket->Subject;
-                  };   
-       /^status/i && do {
-           last SWITCH; 
-           $Ticket->Status;
-       };
-       /^prio/i && do {
-           last SWITCH; 
-           $Ticket->Priority;
-       };
-       /^finalprio/i && do {
-           
-           last SWITCH; 
-           $Ticket->FinalPriority
-       };
-       /^initialprio/i && do {
-           
-           last SWITCH; 
-           $Ticket->InitialPriority;
-       };      
-       /^timel/i && do {
-           
-           last SWITCH; 
-           $Ticket->TimeWorked;
-       };
-       /^timew/i && do {
-           
-           last SWITCH; 
-           $Ticket->TimeLeft;
-       };
-       
-       /^(.*?)date(.*)$/i && do {
-           my $o = $1;
-           my $m = $2;
-           my ($obj);
-           #TODO: optimize
-           $obj = $Ticket->DueObj         if $o =~ /due/i;
-           $obj = $Ticket->CreatedObj     if $o =~ /created/i;
-           $obj = $Ticket->StartsObj      if $o =~ /starts/i;
-           $obj = $Ticket->StartedObj     if $o =~ /started/i;
-           $obj = $Ticket->ToldObj        if $o =~ /told/i;
-           $obj = $Ticket->LastUpdatedObj if $o =~ /lastu/i;
-           
-           $method = 'ISO' if $m =~ /iso/i;
-           
-           $method = 'AsString' if $m =~ /asstring/i;
-           $method = 'AgeAsString' if $m =~ /age/i;
-           last SWITCH;
-           $obj->$method();
-             
-       };
-         
-         /^watcher/i && do {
-             last SWITCH; 
-             $Ticket->WatchersAsString();
-         };    
-       
-       /^requestor/i && do {
-           last SWITCH; 
-           $Ticket->RequestorsAsString();
-       };      
-       /^cc/i && do {
-           last SWITCH; 
-           $Ticket->CCAsString();
-       };      
-       
-       
-       /^admincc/i && do {
-           last SWITCH; 
-           $Ticket->AdminCcAsString();
-       };
-       
-       /^keywords/i && do {
-           last SWITCH; 
-           #Limit it to the keyword select we're talking about, if we've got one.
-           my $objkeys =$Ticket->KeywordsObj($attrib->{'SELECT'});
-           $objkeys->KeywordRelativePathsAsString();
-       };
-       
-    }
-      
-}
-
-# }}}
-
-# }}}
-
-# {{{ POD
-=head2 notes
-"Enum" Things that get Is, IsNot
-
-
-"Int" Things that get Is LessThan and GreaterThan
-id
-InitialPriority
-FinalPriority
-Priority
-TimeLeft
-TimeWorked
-
-"Text" Things that get Is, Like
-Subject
-TransactionContent
-
-
-"Link" OPERATORs
-
-
-"Date" OPERATORs Is, Before, After
 
-  =cut
-# }}}
 1;