Subversion Repositories DevTools

Rev

Rev 1295 | Blame | Compare with Previous | Last modification | View Log | RSS feed

###############################################################################
# Codestriker: Copyright (c) 2001, 2002 David Sitsky.  All rights reserved.
# sits@users.sourceforge.net
#
# This program is free software; you can redistribute it and modify it under
# the terms of the GPL.

# Action object for handling the viewing of a topic.

package Codestriker::Action::ViewTopic;

use strict;

use Codestriker::Model::Topic;
use Codestriker::Model::Comment;
use Codestriker::Http::UrlBuilder;
use Codestriker::Http::Render;
use Codestriker::Repository::RepositoryFactory;
use Codestriker::TopicListeners::Manager;

# If the input is valid, display the topic.
sub process($$$) {
    my ($type, $http_input, $http_response) = @_;

    my $query = $http_response->get_query();
    
    my $topicid = $http_input->get('topic');
    my $mode = $http_input->get('mode');
    my $brmode = $http_input->get('brmode');
    my $fview = $http_input->get('fview');
    my $tabwidth = $http_input->get('tabwidth');
    my $email = $http_input->get('email');
    my $feedback = $http_input->get('feedback');

    if (Codestriker::Model::Topic::exists($topicid) == 0) {
        # Topic no longer exists, most likely its been deleted.
        $http_response->error("Topic no longer exists.");
    }

    # Retrieve the appropriate topic details.           
    my $topic = Codestriker::Model::Topic->new($topicid);     

    # Retrieve the comment details for this topic, firstly determine how
    # many distinct comment lines are there.
    my @comments = $topic->read_comments();
    my %comment_map = ();
    foreach my $comment (@comments) {
        my $key = $comment->{filenumber} . "|" . $comment->{fileline} . "|" .
            $comment->{filenew};
        if (! exists $comment_map{$key}) {
            $comment_map{$key} = 1;
        }
    }

    # Retrieve the changed files which are a part of this review.
    my (@filenames, @revisions, @offsets, @binary, @numchanges);
    $topic->get_filestable(
                \@filenames,
                \@revisions,
                \@offsets,
                \@binary,
                \@numchanges);

    # Retrieve line-by-line versions of the data and description.
    my @document_description = split /\n/, $topic->{description};

    $http_response->generate_header(topic=>$topic,
                                    comments=>\@comments,
                                    topic_title=>"Topic Text: $topic->{title}",
                                    mode=>$mode, tabwidth=>$tabwidth,
                                    fview=>$fview,
                                    reload=>0, cache=>1);

    # Retrieve the repository object, if repository functionality is enabled.
    my $repository;
    if (scalar(@Codestriker::valid_repositories)) {
        $repository =
            Codestriker::Repository::RepositoryFactory->get($topic->{repository});
    } else {
        # Indicate not to activate any repository-related links.
        $topic->{repository} = "";
    }

    # Create the hash for the template variables.
    my $vars = {};
    $vars->{'feedback'} = $feedback;

    # Create the necessary template variables for generating the heading part
    # of the view topic display.

    # Obtain a new URL builder object.
    my $url_builder = Codestriker::Http::UrlBuilder->new($query);

    ProcessTopicHeader($vars, $topic, $url_builder);

    # Display the "update" message if the topic state has been changed.
    $vars->{'updated'} = $http_input->get('updated');
    $vars->{'rc_ok'} = $Codestriker::OK;
    $vars->{'rc_stale_version'} = $Codestriker::STALE_VERSION;
    $vars->{'rc_invalid_topic'} = $Codestriker::INVALID_TOPIC;

    if ($topic->{bug_ids} ne "") {
        my @bugs = split ', ', $topic->{bug_ids};
        my $bug_string = "";
        for (my $i = 0; $i <= $#bugs; $i++) {
            $bug_string .=
                $query->a({href=>"$Codestriker::bugtracker$bugs[$i]"},
                          $bugs[$i]);
            $bug_string .= ', ' unless ($i == $#bugs);
        }
        $vars->{'bug_string'} = $bug_string;
    } else {
        $vars->{'bug_string'} = "";
    }

    $vars->{'document_reviewers'} = 
        Codestriker->filter_email($topic->{reviewers});
    $vars->{'project_name'} = $topic->{project_name};
    $vars->{'number_of_lines'} = $topic->get_topic_size_in_lines();

    $vars->{'suggested_topic_size_lines'} =
        $Codestriker::suggested_topic_size_lines eq "" ? 0 :
        $Codestriker::suggested_topic_size_lines;    

    # Prepare the data for displaying the state update option.
    # Make sure the old mode setting is no longer used.
    if ((! defined $mode) || $mode == $Codestriker::NORMAL_MODE) {
        $mode = $Codestriker::COLOURED_MODE;
    }
    if (! defined $brmode) {
        $brmode = $Codestriker::default_topic_br_mode;
    }
    if (! defined $fview) {
            $fview = $Codestriker::default_file_to_view;
            if (! defined $fview) {
                $fview = -1;
            }
    }
    $vars->{'mode'} = $mode;
    $vars->{'brmode'} = $brmode;
    $vars->{'states'} = \@Codestriker::topic_states;
    $vars->{'default_state'} = $topic->{state};

    # Set the description of the topic.
    my $data = "";
    for (my $i = 0; $i <= $#document_description; $i++) {
        $data .= $document_description[$i] . "\n";
    }
    $vars->{'description'} = $data;

    # Obtain the link to download the actual document text.
    $vars->{'download_url'} = $url_builder->download_url($topicid);

    # Fire the template on the topic heading information.
    my $template = Codestriker::Http::Template->new("viewtopic");
    $template->process($vars);

    # The rest of the output is non-template driven, as it is quite
    # complex.

    # Give the user the option of swapping between diff view modes.
    # If there are no files associated with the review, remove this
    # option.
    my $coloured_url =
        $url_builder->view_url($topicid, -1, $Codestriker::COLOURED_MODE,
                               $brmode, $fview);
    my $coloured_mono_url =
        $url_builder->view_url($topicid, -1,
                               $Codestriker::COLOURED_MONO_MODE, $brmode, $fview);
    my $br_normal_url =
        $url_builder->view_url($topicid, -1, $mode,
                               $Codestriker::LINE_BREAK_NORMAL_MODE, $fview);
    my $br_assist_url =
        $url_builder->view_url($topicid, -1, $mode,
                               $Codestriker::LINE_BREAK_ASSIST_MODE, $fview);
        
    if ($mode == $Codestriker::COLOURED_MODE) {
        print " View in " .
            $query->a({href=>$coloured_mono_url}, "monospace font") .
            " | ";
    } elsif ($mode == $Codestriker::COLOURED_MONO_MODE) {
        print " View in " .
            $query->a({href=>$coloured_url}, "variable-width font") .
            " | ";
    }

    if ($brmode == $Codestriker::LINE_BREAK_NORMAL_MODE) {
        print " View with " .
            $query->a({href=>$br_assist_url}, "minimal screen width") . ".";
    } elsif ($brmode == $Codestriker::LINE_BREAK_ASSIST_MODE) {
        print " View with " .
            $query->a({href=>$br_normal_url}, "minimal line breaks") . ".";
    }
    print " | ";

    # Display the option to change the tab width.
    my $newtabwidth = ($tabwidth == 4) ? 8 : 4;
    my $change_tabwidth_url;
    $change_tabwidth_url =
        $url_builder->view_url_extended($topicid, -1, $mode, $newtabwidth,
                                        "", "", 0, $brmode, $fview);

    print " Tab width set to $tabwidth (";
    print $query->a({href=>"$change_tabwidth_url"},"change to $newtabwidth");
    print ")\n";

    print $query->p if ($mode == $Codestriker::NORMAL_MODE);

    # Number of characters the line number should take, need the real lines
    # not the number of changed lines.
    my @document = split /\n/, $topic->{document};
    my $max_digit_width = length($#document+1);

    # Build the render which will be used to build this page.
    my $render = Codestriker::Http::Render->new($query, $url_builder, 1,
                                                $max_digit_width, $topicid,
                                                $mode, \@comments, $tabwidth,
                                                $repository, \@filenames,
                                                \@revisions, \@binary,
                                                \@numchanges, -1,
                                                $brmode, $fview);

    # Display the data that is being reviewed.
    $render->start();

    # Retrieve the delta set comprising this review.

    my $old_filename = "";
    
    # Determine which deltas are to be retrieved.
    my @deltas = ();
    if ($fview != -1) {
        # Get only the deltas for the selected file.    
        @deltas = Codestriker::Model::Delta->get_delta_set($topicid, $fview);
    }
    else {
        # Get the whole delta data.
        @deltas = Codestriker::Model::Delta->get_delta_set($topicid, -1);
    }

    # Now render the selected deltas.
    for (my $i = 0; $i <= $#deltas; $i++) {
        my $delta =  $deltas[$i];
        $render->delta($delta);
    }

    $render->finish();

    # Render the HTML trailer.
    my $trailer = Codestriker::Http::Template->new("trailer");
    $trailer->process();

    print $query->end_html();

    $http_response->generate_footer();

    # Fire the topic listener to indicate that the user has viewed the topic.
    Codestriker::TopicListeners::Manager::topic_viewed($email, $topic);
}

# This function is used by all of the view topic tabs to fill out the
# common template items that are required by all, in addition to the view
# topic file action.
sub ProcessTopicHeader
{
    my ($vars, $topic, $url_builder) = @_;

    # Handle the links in the three topic tabs.
    $vars->{'view_topicinfo_url'} =
        $url_builder->view_topicinfo_url($topic->{topicid});
    $vars->{'view_topic_url'} =
        ## XX mode, last param
        $url_builder->view_url($topic->{topicid}, -1, 0);
    
    $vars->{'view_comments_url'} =
        $url_builder->view_comments_url($topic->{topicid});
    
    $vars->{'view_topic_properties_url'} =
        $url_builder->view_topic_properties_url($topic->{topicid});
    
    my @project_ids = ($topic->{project_id});
    $vars->{'list_open_topics_in_project_url'} =
        $url_builder->list_topics_url("", "", "", "", "", "", "", "", "",
                                      "", [ 0 ], \@project_ids);
    
    # Retrieve the comment details for this topic.
    my @comments = $topic->read_comments();
    
    # Obtains how many comments there are, and the internal link to them.
    $vars->{'number_comments'} = $#comments + 1;
    
    # Obtain the view topic summary information, the title, bugs it relates
    # to, and who the participants are.
    $vars->{'title'} = $topic->{title};
    
    $vars->{'author'} = Codestriker->filter_email($topic->{author});
    
    $vars->{'document_creation_time'} = 
        Codestriker->format_timestamp($topic->{creation_ts});
    
    $vars->{'topic'} = $topic->{topicid};
    
    $vars->{'reviewers'} = Codestriker->filter_email($topic->{reviewers});
    $vars->{'cc'} =  Codestriker->filter_email($topic->{cc});
    
    # Get the list of obsoleted topics.
    my @obsoleted_topics = ();
    foreach my $id (@{ $topic->{obsoleted_topics} }) {
        my $obsoleted_topic = Codestriker::Model::Topic->new($id);
        my $entry = {};
        $entry->{title} = $obsoleted_topic->{title};
        $entry->{view_url} = $url_builder->view_url($id, -1);
        push @obsoleted_topics, $entry;
    }
    $vars->{'obsoleted_topics'} = \@obsoleted_topics;
    
    # Get the list of topics this has been obsoleted by.
    my @obsoleted_by = ();
    foreach my $id (@{ $topic->{obsoleted_by} }) {
        my $superseeded_topic = Codestriker::Model::Topic->new($id);
        my $entry = {};
        $entry->{title} = $superseeded_topic->{title};
        $entry->{view_url} = $url_builder->view_url($id, -1);
        push @obsoleted_by, $entry;
    }
    $vars->{'obsoleted_by'} = \@obsoleted_by;
    #
    # 29-Aug-07 SJK: Add optional URL 
    #
    $vars->{'desc_url'} = $topic->{desc_url};
}


1;