]> source.dussan.org Git - redmine.git/commitdiff
Gantt: do not ignore project filter (#7000, #7352), do not display empty projects...
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Thu, 10 Mar 2011 18:07:09 +0000 (18:07 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Thu, 10 Mar 2011 18:07:09 +0000 (18:07 +0000)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5077 e93f8b46-1217-0410-a6f0-8f06a7374b81

lib/redmine/helpers/gantt.rb
test/unit/lib/redmine/helpers/gantt_test.rb

index f551f1c1a5fe3d74afdb8c49ed513f789ac37e23..68f3dfaec7676ff1a638ca2d80de4bbf17eaf8fd 100644 (file)
@@ -1,5 +1,5 @@
 # Redmine - project management software
-# Copyright (C) 2006-2008  Jean-Philippe Lang
+# Copyright (C) 2006-2011  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
@@ -98,51 +98,25 @@ module Redmine
         common_params.merge({:year => (date_from >> months).year, :month => (date_from >> months).month, :zoom => zoom, :months => months })
       end
 
-            ### Extracted from the HTML view/helpers
       # Returns the number of rows that will be rendered on the Gantt chart
       def number_of_rows
         return @number_of_rows if @number_of_rows
         
-        rows = if @project
-          number_of_rows_on_project(@project)
-        else
-          Project.roots.visible.has_module('issue_tracking').inject(0) do |total, project|
-            total += number_of_rows_on_project(project)
-          end
-        end
-        
+        rows = projects.inject(0) {|total, p| total += number_of_rows_on_project(p)}
         rows > @max_rows ? @max_rows : rows
       end
-
+      
       # Returns the number of rows that will be used to list a project on
       # the Gantt chart.  This will recurse for each subproject.
       def number_of_rows_on_project(project)
-        # Remove the project requirement for Versions because it will
-        # restrict issues to only be on the current project.  This
-        # ends up missing issues which are assigned to shared versions.
-        @query.project = nil if @query.project
-
-        # One Root project
+        return 0 unless projects.include?(project)
+        
         count = 1
-        # Issues without a Version
-        count += project.issues.for_gantt.without_version.with_query(@query).count
-
-        # Versions
-        count += project.versions.count
-
-        # Issues on the Versions
-        project.versions.each do |version|
-          count += version.fixed_issues.for_gantt.with_query(@query).count
-        end
-
-        # Subprojects
-        project.children.visible.has_module('issue_tracking').each do |subproject|
-          count += number_of_rows_on_project(subproject)
-        end
-
+        count += project_issues(project).size
+        count += project_versions(project).size
         count
       end
-
+      
       # Renders the subjects of the Gantt chart, the left side.
       def subjects(options={})
         render(options.merge(:only => :subjects)) unless @subjects_rendered
@@ -155,20 +129,60 @@ module Redmine
         @lines
       end
       
+      # Returns issues that will be rendered
+      def issues
+        @issues ||= @query.issues(
+          :include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
+          :order => "#{Project.table_name}.lft ASC, #{Issue.table_name}.id ASC", 
+          :limit => @max_rows
+        )
+      end
+      
+      # Return all the project nodes that will be displayed
+      def projects
+        return @projects if @projects
+        
+        ids = issues.collect(&:project).uniq.collect(&:id)
+        if ids.any?
+          # All issues projects and their visible ancestors
+          @projects = Project.visible.all(
+            :joins => "LEFT JOIN #{Project.table_name} child ON #{Project.table_name}.lft <= child.lft AND #{Project.table_name}.rgt >= child.rgt",
+            :conditions => ["child.id IN (?)", ids],
+            :order => "#{Project.table_name}.lft ASC"
+          ).uniq
+        else
+          @projects = []
+        end
+      end
+      
+      # Returns the issues that belong to +project+
+      def project_issues(project)
+        @issues_by_project ||= issues.group_by(&:project)
+        @issues_by_project[project] || []
+      end
+      
+      # Returns the distinct versions of the issues that belong to +project+
+      def project_versions(project)
+        project_issues(project).collect(&:fixed_version).compact.uniq
+      end
+      
+      # Returns the issues that belong to +project+ and are assigned to +version+
+      def version_issues(project, version)
+        project_issues(project).select {|issue| issue.fixed_version == version}
+      end
+      
       def render(options={})
-        options = {:indent => 4, :render => :subject, :format => :html}.merge(options)
+        options = {:top => 0, :top_increment => 20, :indent_increment => 20, :render => :subject, :format => :html}.merge(options)
+        indent = options[:indent] || 4
         
         @subjects = '' unless options[:only] == :lines
         @lines = '' unless options[:only] == :subjects
         @number_of_rows = 0
         
-        if @project
-          render_project(@project, options)
-        else
-          Project.roots.visible.has_module('issue_tracking').each do |project|
-            render_project(project, options)
-            break if abort?
-          end
+        Project.project_tree(projects) do |project, level|
+          options[:indent] = indent + level * options[:indent_increment]
+          render_project(project, options)
+          break if abort?
         end
         
         @subjects_rendered = true unless options[:only] == :lines
@@ -178,10 +192,6 @@ module Redmine
       end
 
       def render_project(project, options={})
-        options[:top] = 0 unless options.key? :top
-        options[:indent_increment] = 20 unless options.key? :indent_increment
-        options[:top_increment] = 20 unless options.key? :top_increment
-
         subject_for_project(project, options) unless options[:only] == :lines
         line_for_project(project, options) unless options[:only] == :subjects
         
@@ -190,26 +200,18 @@ module Redmine
         @number_of_rows += 1
         return if abort?
         
-        # Second, Issues without a version
-        issues = project.issues.for_gantt.without_version.with_query(@query).all(:limit => current_limit)
+        issues = project_issues(project).select {|i| i.fixed_version.nil?}
         sort_issues!(issues)
         if issues
           render_issues(issues, options)
           return if abort?
         end
-
-        # Third, Versions
-        project.versions.sort.each do |version|
-          render_version(version, options)
-          return if abort?
+        
+        versions = project_versions(project)
+        versions.each do |version|
+          render_version(project, version, options)
         end
 
-        # Fourth, subprojects
-        project.children.visible.has_module('issue_tracking').each do |project|
-          render_project(project, options)
-          return if abort?
-        end unless project.leaf?
-
         # Remove indent to hit the next sibling
         options[:indent] -= options[:indent_increment]
       end
@@ -229,7 +231,7 @@ module Redmine
         options[:indent] -= (options[:indent_increment] * @issue_ancestors.size)
       end
 
-      def render_version(version, options={})
+      def render_version(project, version, options={})
         # Version header
         subject_for_version(version, options) unless options[:only] == :lines
         line_for_version(version, options) unless options[:only] == :subjects
@@ -238,12 +240,7 @@ module Redmine
         @number_of_rows += 1
         return if abort?
         
-        # Remove the project requirement for Versions because it will
-        # restrict issues to only be on the current project.  This
-        # ends up missing issues which are assigned to shared versions.
-        @query.project = nil if @query.project
-        
-        issues = version.fixed_issues.for_gantt.with_query(@query).all(:limit => current_limit)
+        issues = version_issues(project, version)
         if issues
           sort_issues!(issues)
           # Indent issues
index ec9b0651b9b31e6cfbd58f91981039f42bc7ef56..1f6d507b7c4e1662dfc7fa6b3d458478ce90561d 100644 (file)
@@ -1,5 +1,5 @@
-# redMine - project management software
-# Copyright (C) 2006-2008  Jean-Philippe Lang
+# Redmine - project management software
+# Copyright (C) 2006-2011  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
@@ -95,15 +95,9 @@ class Redmine::Helpers::GanttTest < ActiveSupport::TestCase
     setup do
       create_gantt
     end
-    
-    should "clear the @query.project so cross-project issues and versions can be counted" do
-      assert @gantt.query.project
-      @gantt.number_of_rows_on_project(@project)
-      assert_nil @gantt.query.project
-    end
 
-    should "count 1 for the project itself" do
-      assert_equal 1, @gantt.number_of_rows_on_project(@project)
+    should "count 0 for an empty the project" do
+      assert_equal 0, @gantt.number_of_rows_on_project(@project)
     end
 
     should "count the number of issues without a version" do
@@ -111,12 +105,6 @@ class Redmine::Helpers::GanttTest < ActiveSupport::TestCase
       assert_equal 2, @gantt.number_of_rows_on_project(@project)
     end
 
-    should "count the number of versions" do
-      @project.versions << Version.generate!
-      @project.versions << Version.generate!
-      assert_equal 3, @gantt.number_of_rows_on_project(@project)
-    end
-
     should "count the number of issues on versions, including cross-project" do
       version = Version.generate!
       @project.versions << version
@@ -124,21 +112,6 @@ class Redmine::Helpers::GanttTest < ActiveSupport::TestCase
       
       assert_equal 3, @gantt.number_of_rows_on_project(@project)
     end
-    
-    should "recursive and count the number of rows on each subproject" do
-      @project.versions << Version.generate! # +1
-
-      @subproject = Project.generate!(:enabled_module_names => ['issue_tracking']) # +1
-      @subproject.set_parent!(@project)
-      @subproject.issues << Issue.generate_for_project!(@subproject) # +1
-      @subproject.issues << Issue.generate_for_project!(@subproject) # +1
-
-      @subsubproject = Project.generate!(:enabled_module_names => ['issue_tracking']) # +1
-      @subsubproject.set_parent!(@subproject)
-      @subsubproject.issues << Issue.generate_for_project!(@subsubproject) # +1
-
-      assert_equal 7, @gantt.number_of_rows_on_project(@project) # +1 for self
-    end
   end
 
   # TODO: more of an integration test
@@ -183,6 +156,18 @@ class Redmine::Helpers::GanttTest < ActiveSupport::TestCase
         @response.body = @gantt.subjects
         assert_select "div.version-name[style*=left:24px]"
       end
+      
+      context "without assigned issues" do
+        setup do
+          @version = Version.generate!(:effective_date => 2.week.from_now.to_date, :sharing => 'none', :name => 'empty_version')
+          @project.versions << @version
+        end
+      
+        should "not be rendered" do
+          @response.body = @gantt.subjects
+          assert_select "div.version-name a", :text => /#{@version.name}/, :count => 0
+        end
+      end
     end
   
     context "issue" do
@@ -196,6 +181,31 @@ class Redmine::Helpers::GanttTest < ActiveSupport::TestCase
         assert_select "div.issue-subject[style*=left:44px]"
       end
       
+      context "assigned to a shared version of another project" do
+        setup do
+          p = Project.generate!
+          p.trackers << @tracker
+          p.enabled_module_names = [:issue_tracking]
+          @shared_version = Version.generate!(:sharing => 'system')
+          p.versions << @shared_version
+          # Reassign the issue to a shared version of another project
+          
+          @issue = Issue.generate!(:fixed_version => @shared_version,
+                                   :subject => "gantt#assigned_to_shared_version",
+                                   :tracker => @tracker,
+                                   :project => @project,
+                                   :done_ratio => 30,
+                                   :start_date => Date.yesterday,
+                                   :due_date => 1.week.from_now.to_date)
+          @project.issues << @issue
+        end
+        
+        should "be rendered" do
+          @response.body = @gantt.subjects
+          assert_select "div.issue-subject", /#{@issue.subject}/
+        end
+      end
+      
       context "with subtasks" do
         setup do
           attrs = {:project => @project, :tracker => @tracker, :fixed_version => @version}