diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb
index fcf8ec2e37f9a5315f3f70f39a1d9ce2fdef00ea..0dcdbb040feb1cef161335ce5d317d427299bb2f 100644
--- a/app/helpers/settings_helper.rb
+++ b/app/helpers/settings_helper.rb
@@ -79,7 +79,12 @@ module SettingsHelper
def setting_label(setting, options={})
label = options.delete(:label)
- label != false ? label_tag("settings_#{setting}", l(label || "setting_#{setting}"), options[:label_options]).html_safe : ''
+ if label == false
+ ''
+ else
+ text = label.is_a?(String) ? label : l(label || "setting_#{setting}")
+ label_tag("settings_#{setting}", text, options[:label_options])
+ end
end
# Renders a notification field for a Redmine::Notifiable option
@@ -123,6 +128,24 @@ module SettingsHelper
[:label_cross_project_descendants, 'descendants']
]
+ options.map {|label, value| [l(label), value.to_s]}
+ end
+
+ def parent_issue_dates_options
+ options = [
+ [:label_parent_task_attributes_derived, 'derived'],
+ [:label_parent_task_attributes_independent, 'independent']
+ ]
+
+ options.map {|label, value| [l(label), value.to_s]}
+ end
+
+ def parent_issue_priority_options
+ options = [
+ [:label_parent_task_attributes_derived, 'derived'],
+ [:label_parent_task_attributes_independent, 'independent']
+ ]
+
options.map {|label, value| [l(label), value.to_s]}
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 9ea7f6c578e3fe804fa4243cb0318bd246c34628..7d04d1e15236deda0b0072b1f8c2c98f17058d69 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -426,6 +426,15 @@ class Issue < ActiveRecord::Base
# Make sure that project_id can always be set for new issues
names |= %w(project_id)
end
+ if dates_derived?
+ names -= %w(start_date due_date)
+ end
+ if priority_derived?
+ names -= %w(priority_id)
+ end
+ unless leaf?
+ names -= %w(done_ratio estimated_hours)
+ end
names
end
@@ -463,10 +472,6 @@ class Issue < ActiveRecord::Base
attrs = delete_unsafe_attributes(attrs, user)
return if attrs.empty?
- unless leaf?
- attrs.reject! {|k,v| %w(priority_id done_ratio start_date due_date estimated_hours).include?(k)}
- end
-
if attrs['parent_issue_id'].present?
s = attrs['parent_issue_id'].to_s
unless (m = s.match(%r{\A#?(\d+)\z})) && (m[1] == parent_id.to_s || Issue.visible(user).exists?(m[1]))
@@ -1094,11 +1099,15 @@ class Issue < ActiveRecord::Base
end
def soonest_start(reload=false)
- @soonest_start = nil if reload
- @soonest_start ||= (
- relations_to(reload).collect{|relation| relation.successor_soonest_start} +
- [(@parent_issue || parent).try(:soonest_start)]
- ).compact.max
+ if @soonest_start.nil? || reload
+ dates = relations_to(reload).collect{|relation| relation.successor_soonest_start}
+ p = @parent_issue || parent
+ if p && Setting.parent_issue_dates == 'derived'
+ dates << p.soonest_start
+ end
+ @soonest_start = dates.compact.max
+ end
+ @soonest_start
end
# Sets start_date on the given date or the next working day
@@ -1114,7 +1123,7 @@ class Issue < ActiveRecord::Base
# If the issue is a parent task, this is done by rescheduling its subtasks.
def reschedule_on!(date)
return if date.nil?
- if leaf?
+ if leaf? || !dates_derived?
if start_date.nil? || start_date != date
if start_date && start_date > date
# Issue can not be moved earlier than its soonest start date
@@ -1144,6 +1153,14 @@ class Issue < ActiveRecord::Base
end
end
+ def dates_derived?
+ !leaf? && Setting.parent_issue_dates == 'derived'
+ end
+
+ def priority_derived?
+ !leaf? && Setting.parent_issue_priority == 'derived'
+ end
+
def <=>(issue)
if issue.nil?
-1
@@ -1430,16 +1447,20 @@ class Issue < ActiveRecord::Base
def recalculate_attributes_for(issue_id)
if issue_id && p = Issue.find_by_id(issue_id)
- # priority = highest priority of children
- if priority_position = p.children.joins(:priority).maximum("#{IssuePriority.table_name}.position")
- p.priority = IssuePriority.find_by_position(priority_position)
+ if p.priority_derived?
+ # priority = highest priority of children
+ if priority_position = p.children.joins(:priority).maximum("#{IssuePriority.table_name}.position")
+ p.priority = IssuePriority.find_by_position(priority_position)
+ end
end
- # start/due dates = lowest/highest dates of children
- p.start_date = p.children.minimum(:start_date)
- p.due_date = p.children.maximum(:due_date)
- if p.start_date && p.due_date && p.due_date < p.start_date
- p.start_date, p.due_date = p.due_date, p.start_date
+ if p.dates_derived?
+ # start/due dates = lowest/highest dates of children
+ p.start_date = p.children.minimum(:start_date)
+ p.due_date = p.children.maximum(:due_date)
+ if p.start_date && p.due_date && p.due_date < p.start_date
+ p.start_date, p.due_date = p.due_date, p.start_date
+ end
end
# done ratio = weighted average ratio of leaves
diff --git a/app/views/issues/_attributes.html.erb b/app/views/issues/_attributes.html.erb
index 61ffa8ae3e8ad422cb8ea92073658dfa2ecaeae7..3d5f85c7bd6da873ec9f85641098cd8574934af4 100644
--- a/app/views/issues/_attributes.html.erb
+++ b/app/views/issues/_attributes.html.erb
@@ -48,25 +48,23 @@
<% if @issue.safe_attribute? 'start_date' %>
- <%= f.text_field(:start_date, :size => 10, :disabled => !@issue.leaf?,
- :required => @issue.required_attribute?('start_date')) %>
+ <%= f.text_field(:start_date, :size => 10, :required => @issue.required_attribute?('start_date')) %>
<%= calendar_for('issue_start_date') if @issue.leaf? %>
<% end %>
<% if @issue.safe_attribute? 'due_date' %>
- <%= f.text_field(:due_date, :size => 10, :disabled => !@issue.leaf?,
- :required => @issue.required_attribute?('due_date')) %>
+ <%= f.text_field(:due_date, :size => 10, :required => @issue.required_attribute?('due_date')) %>
<%= calendar_for('issue_due_date') if @issue.leaf? %>
<% end %>
<% if @issue.safe_attribute? 'estimated_hours' %>
-<%= f.text_field :estimated_hours, :size => 3, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('estimated_hours') %> <%= l(:field_hours) %>
+<%= f.text_field :estimated_hours, :size => 3, :required => @issue.required_attribute?('estimated_hours') %> <%= l(:field_hours) %>
<% end %>
-<% if @issue.safe_attribute?('done_ratio') && @issue.leaf? && Issue.use_field_for_done_ratio? %>
+<% if @issue.safe_attribute?('done_ratio') && Issue.use_field_for_done_ratio? %>
<%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :required => @issue.required_attribute?('done_ratio') %>
<% end %>
diff --git a/app/views/settings/_issues.html.erb b/app/views/settings/_issues.html.erb
index c1e802238c4e4d68d7e9c860d9d87a07b6a5f3a5..a0dfd786c2584ac993373baaebae1c10d544e263 100644
--- a/app/views/settings/_issues.html.erb
+++ b/app/views/settings/_issues.html.erb
@@ -22,6 +22,15 @@
<%= setting_text_field :gantt_items_limit, :size => 6 %>
+
+