diff lib/redmine/helpers/gantt.rb @ 1295:622f24f53b42 redmine-2.3

Update to Redmine SVN revision 11972 on 2.3-stable branch
author Chris Cannam
date Fri, 14 Jun 2013 09:02:21 +0100
parents 433d4f72a19b
children
line wrap: on
line diff
--- a/lib/redmine/helpers/gantt.rb	Fri Jun 14 09:01:12 2013 +0100
+++ b/lib/redmine/helpers/gantt.rb	Fri Jun 14 09:02:21 2013 +0100
@@ -1,5 +1,5 @@
 # Redmine - project management software
-# Copyright (C) 2006-2012  Jean-Philippe Lang
+# Copyright (C) 2006-2013  Jean-Philippe Lang
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -23,6 +23,12 @@
       include Redmine::I18n
       include Redmine::Utils::DateCalculation
 
+      # Relation types that are rendered
+      DRAW_TYPES = {
+        IssueRelation::TYPE_BLOCKS   => { :landscape_margin => 16, :color => '#F34F4F' },
+        IssueRelation::TYPE_PRECEDES => { :landscape_margin => 20, :color => '#628FEA' }
+      }.freeze
+
       # :nodoc:
       # Some utility methods for the PDF export
       class PDF
@@ -136,6 +142,20 @@
         )
       end
 
+      # Returns a hash of the relations between the issues that are present on the gantt
+      # and that should be displayed, grouped by issue ids.
+      def relations
+        return @relations if @relations
+        if issues.any?
+          issue_ids = issues.map(&:id)
+          @relations = IssueRelation.
+            where(:issue_from_id => issue_ids, :issue_to_id => issue_ids, :relation_type => DRAW_TYPES.keys).
+            group_by(&:issue_from_id)
+        else
+          @relations = {}
+        end
+      end
+
       # Return all the project nodes that will be displayed
       def projects
         return @projects if @projects
@@ -277,7 +297,6 @@
             pdf_task(options, coords, :label => label, :markers => true, :height => 0.8)
           end
         else
-          ActiveRecord::Base.logger.debug "Gantt#line_for_project was not given a project with a start_date"
           ''
         end
       end
@@ -289,10 +308,18 @@
           html_class << 'icon icon-package '
           html_class << (version.behind_schedule? ? 'version-behind-schedule' : '') << " "
           html_class << (version.overdue? ? 'version-overdue' : '')
+          html_class << ' version-closed' unless version.open?
+          if version.start_date && version.due_date && version.completed_pourcent
+            progress_date = calc_progress_date(version.start_date,
+                                               version.due_date, version.completed_pourcent)
+            html_class << ' behind-start-date' if progress_date < self.date_from
+            html_class << ' over-end-date' if progress_date > self.date_to
+          end
           s = view.link_to_version(version).html_safe
           subject = view.content_tag(:span, s,
                                      :class => html_class).html_safe
-          html_subject(options, subject, :css => "version-name")
+          html_subject(options, subject, :css => "version-name",
+                       :id => "version-#{version.id}")
         when :image
           image_subject(options, version.to_s_with_project)
         when :pdf
@@ -303,24 +330,24 @@
 
       def line_for_version(version, options)
         # Skip versions that don't have a start_date
-        if version.is_a?(Version) && version.start_date && version.due_date
+        if version.is_a?(Version) && version.due_date && version.start_date
           options[:zoom] ||= 1
           options[:g_width] ||= (self.date_to - self.date_from + 1) * options[:zoom]
           coords = coordinates(version.start_date,
-                               version.due_date, version.completed_pourcent,
+                               version.due_date, version.completed_percent,
                                options[:zoom])
-          label = "#{h version} #{h version.completed_pourcent.to_i.to_s}%"
+          label = "#{h version} #{h version.completed_percent.to_i.to_s}%"
           label = h("#{version.project} -") + label unless @project && @project == version.project
           case options[:format]
           when :html
-            html_task(options, coords, :css => "version task", :label => label, :markers => true)
+            html_task(options, coords, :css => "version task",
+                      :label => label, :markers => true, :version => version)
           when :image
             image_task(options, coords, :label => label, :markers => true, :height => 3)
           when :pdf
             pdf_task(options, coords, :label => label, :markers => true, :height => 0.8)
           end
         else
-          ActiveRecord::Base.logger.debug "Gantt#line_for_version was not given a version with a start_date"
           ''
         end
       end
@@ -336,6 +363,13 @@
           css_classes << ' issue-overdue' if issue.overdue?
           css_classes << ' issue-behind-schedule' if issue.behind_schedule?
           css_classes << ' icon icon-issue' unless Setting.gravatar_enabled? && issue.assigned_to
+          css_classes << ' issue-closed' if issue.closed?
+          if issue.start_date && issue.due_before && issue.done_ratio
+            progress_date = calc_progress_date(issue.start_date,
+                                               issue.due_before, issue.done_ratio)
+            css_classes << ' behind-start-date' if progress_date < self.date_from
+            css_classes << ' over-end-date' if progress_date > self.date_to
+          end
           s = "".html_safe
           if issue.assigned_to.present?
             assigned_string = l(:field_assigned_to) + ": " + issue.assigned_to.name
@@ -347,7 +381,7 @@
           s << view.link_to_issue(issue).html_safe
           subject = view.content_tag(:span, s, :class => css_classes).html_safe
           html_subject(options, subject, :css => "issue-subject",
-                       :title => issue.subject) + "\n"
+                       :title => issue.subject, :id => "issue-#{issue.id}") + "\n"
         when :image
           image_subject(options, issue.subject)
         when :pdf
@@ -378,7 +412,6 @@
             pdf_task(options, coords, :label => label)
         end
         else
-          ActiveRecord::Base.logger.debug "GanttHelper#line_for_issue was not given an issue with a due_before"
           ''
         end
       end
@@ -611,7 +644,7 @@
             coords[:bar_end] = self.date_to - self.date_from + 1
           end
           if progress
-            progress_date = start_date + (end_date - start_date + 1) * (progress / 100.0)
+            progress_date = calc_progress_date(start_date, end_date, progress)
             if progress_date > self.date_from && progress_date > start_date
               if progress_date < self.date_to
                 coords[:bar_progress_end] = progress_date - self.date_from
@@ -638,7 +671,11 @@
         coords
       end
 
-      # Sorts a collection of issues by start_date, due_date, id for gantt rendering
+      def calc_progress_date(start_date, end_date, progress)
+        start_date + (end_date - start_date + 1) * (progress / 100.0)
+      end
+
+      # TODO: Sorts a collection of issues by start_date, due_date, id for gantt rendering
       def sort_issues!(issues)
         issues.sort! { |a, b| gantt_issue_compare(a, b) }
       end
@@ -678,9 +715,10 @@
       def html_subject(params, subject, options={})
         style = "position: absolute;top:#{params[:top]}px;left:#{params[:indent]}px;"
         style << "width:#{params[:subject_width] - params[:indent]}px;" if params[:subject_width]
-        output = view.content_tag('div', subject,
+        output = view.content_tag(:div, subject,
                                   :class => options[:css], :style => style,
-                                  :title => options[:title])
+                                  :title => options[:title],
+                                  :id => options[:id])
         @subjects << output
         output
       end
@@ -705,6 +743,16 @@
         params[:image].text(params[:indent], params[:top] + 2, subject)
       end
 
+      def issue_relations(issue)
+        rels = {}
+        if relations[issue.id]
+          relations[issue.id].each do |relation|
+            (rels[relation.relation_type] ||= []) << relation.issue_to_id
+          end
+        end
+        rels
+      end
+
       def html_task(params, coords, options={})
         output = ''
         # Renders the task bar, with progress and late
@@ -714,9 +762,18 @@
           style << "top:#{params[:top]}px;"
           style << "left:#{coords[:bar_start]}px;"
           style << "width:#{width}px;"
-          output << view.content_tag(:div, '&nbsp;'.html_safe,
-                                     :style => style,
-                                     :class => "#{options[:css]} task_todo")
+          html_id = "task-todo-issue-#{options[:issue].id}" if options[:issue]
+          html_id = "task-todo-version-#{options[:version].id}" if options[:version]
+          content_opt = {:style => style,
+                         :class => "#{options[:css]} task_todo",
+                         :id => html_id}
+          if options[:issue]
+            rels = issue_relations(options[:issue])
+            if rels.present?
+              content_opt[:data] = {"rels" => rels.to_json}
+            end
+          end
+          output << view.content_tag(:div, '&nbsp;'.html_safe, content_opt)
           if coords[:bar_late_end]
             width = coords[:bar_late_end] - coords[:bar_start] - 2
             style = ""
@@ -733,9 +790,12 @@
             style << "top:#{params[:top]}px;"
             style << "left:#{coords[:bar_start]}px;"
             style << "width:#{width}px;"
+            html_id = "task-done-issue-#{options[:issue].id}" if options[:issue]
+            html_id = "task-done-version-#{options[:version].id}" if options[:version]
             output << view.content_tag(:div, '&nbsp;'.html_safe,
                                        :style => style,
-                                       :class => "#{options[:css]} task_done")
+                                       :class => "#{options[:css]} task_done",
+                                       :id => html_id)
           end
         end
         # Renders the markers