| 36 | 36 |       end | 
  | 37 | 37 |  | 
  | 38 | 38 |       attr_reader :year_from, :month_from, :date_from, :date_to, :zoom, :months, :truncated, :max_rows | 
  |  | 39 |       attr_reader :detailed_groups, :version_groups | 
  | 39 | 40 |       attr_accessor :query | 
  | 40 | 41 |       attr_accessor :project | 
  | 41 | 42 |       attr_accessor :view | 
  | ... | ... |  | 
  | 57 | 58 |         @zoom = (zoom > 0 && zoom < 5) ? zoom : 2 | 
  | 58 | 59 |         months = (options[:months] || User.current.pref[:gantt_months]).to_i | 
  | 59 | 60 |         @months = (months > 0 && months < 25) ? months : 6 | 
  |  | 61 |         detailed_groups = User.current.pref[:gantt_detailed_groups] | 
  |  | 62 |         if options[:set_filter] == '1' | 
  |  | 63 |           detailed_groups = (options[:not_detailed_groups].to_s == 'true') ? false : true | 
  |  | 64 |         end | 
  |  | 65 |         @detailed_groups = (detailed_groups.to_s == 'true') ? true : false | 
  |  | 66 |         version_groups = User.current.pref[:gantt_version_groups].to_s | 
  |  | 67 |         if options[:set_filter] == '1' | 
  |  | 68 |           version_groups = options[:version_groups].to_s | 
  |  | 69 |         end | 
  |  | 70 |         @version_groups = (version_groups == 'true') ? true : false | 
  | 60 | 71 |         # Save gantt parameters as user preference (zoom and months count) | 
  | 61 | 72 |         if (User.current.logged? && (@zoom != User.current.pref[:gantt_zoom] || | 
  | 62 |  |               @months != User.current.pref[:gantt_months])) | 
  |  | 73 |               @months != User.current.pref[:gantt_months]) || | 
  |  | 74 |               @detailed_groups != User.current.pref[:gantt_detailed_groups] || | 
  |  | 75 |               @version_groups != User.current.pref[:gantt_version_groups]) | 
  | 63 | 76 |           User.current.pref[:gantt_zoom], User.current.pref[:gantt_months] = @zoom, @months | 
  |  | 77 |           User.current.pref[:gantt_detailed_groups] = @detailed_groups | 
  |  | 78 |           User.current.pref[:gantt_version_groups] = @version_groups | 
  | 64 | 79 |           User.current.preference.save | 
  | 65 | 80 |         end | 
  | 66 | 81 |         @date_from = Date.civil(@year_from, @month_from, 1) | 
  | ... | ... |  | 
  | 83 | 98 |  | 
  | 84 | 99 |       def params | 
  | 85 | 100 |         common_params.merge({:zoom => zoom, :year => year_from, | 
  | 86 |  |                              :month => month_from, :months => months}) | 
  |  | 101 |                              :month => month_from, :months => months, | 
  |  | 102 |                              :not_detailed_groups => !detailed_groups, | 
  |  | 103 |                              :version_groups => version_groups}) | 
  | 87 | 104 |       end | 
  | 88 | 105 |  | 
  | 89 | 106 |       def params_previous | 
  | 90 | 107 |         common_params.merge({:year => (date_from << months).year, | 
  | 91 | 108 |                              :month => (date_from << months).month, | 
  | 92 |  |                              :zoom => zoom, :months => months}) | 
  |  | 109 |                              :zoom => zoom, :months => months, | 
  |  | 110 |                              :not_detailed_groups => !detailed_groups, | 
  |  | 111 |                              :version_groups => version_groups}) | 
  | 93 | 112 |       end | 
  | 94 | 113 |  | 
  | 95 | 114 |       def params_next | 
  | 96 | 115 |         common_params.merge({:year => (date_from >> months).year, | 
  | 97 | 116 |                              :month => (date_from >> months).month, | 
  | 98 |  |                              :zoom => zoom, :months => months}) | 
  |  | 117 |                              :zoom => zoom, :months => months, | 
  |  | 118 |                              :not_detailed_groups => !detailed_groups, | 
  |  | 119 |                              :version_groups => version_groups}) | 
  | 99 | 120 |       end | 
  | 100 | 121 |  | 
  | 101 | 122 |       # Returns the number of rows that will be rendered on the Gantt chart | 
  | ... | ... |  | 
  | 168 | 189 |         project_issues(project).select {|issue| issue.fixed_version == version} | 
  | 169 | 190 |       end | 
  | 170 | 191 |  | 
  |  | 192 |       # Returns the issues that belong to +project+ and are grouped by +group+ | 
  |  | 193 |       def group_issues!(group, issues) | 
  |  | 194 |         result = issues.take_while {|issue| group_name(issue) == group} | 
  |  | 195 |         issues.reject! {|issue| group_name(issue) == group} | 
  |  | 196 |         result | 
  |  | 197 |       end | 
  |  | 198 |  | 
  | 171 | 199 |       def render(options={}) | 
  | 172 | 200 |         options = {:top => 0, :top_increment => 20, | 
  | 173 | 201 |                    :indent_increment => 20, :render => :subject, | 
  | ... | ... |  | 
  | 193 | 221 |         options[:indent] += options[:indent_increment] | 
  | 194 | 222 |         @number_of_rows += 1 | 
  | 195 | 223 |         return if abort? | 
  | 196 |  |         issues = project_issues(project).select {|i| i.fixed_version.nil?} | 
  | 197 |  |         sort_issues!(issues) | 
  | 198 |  |         if issues | 
  |  | 224 |         issues = project_issues(project).select {|i| i.fixed_version.nil? || (grouped? && !@version_groups) } | 
  |  | 225 |         if issues && grouped? | 
  |  | 226 |           render_groups(issues, options) | 
  |  | 227 |           return if abort? | 
  |  | 228 |         else | 
  |  | 229 |           sort_issues!(issues) | 
  | 199 | 230 |           render_issues(issues, options) | 
  | 200 | 231 |           return if abort? | 
  | 201 | 232 |         end | 
  | ... | ... |  | 
  | 207 | 238 |         options[:indent] -= options[:indent_increment] | 
  | 208 | 239 |       end | 
  | 209 | 240 |  | 
  | 210 |  |       def render_issues(issues, options={}) | 
  | 211 |  |         @issue_ancestors = [] | 
  | 212 |  |         issues.each do |i| | 
  | 213 |  |           subject_for_issue(i, options) unless options[:only] == :lines | 
  | 214 |  |           line_for_issue(i, options) unless options[:only] == :subjects | 
  | 215 |  |           options[:top] += options[:top_increment] | 
  | 216 |  |           @number_of_rows += 1 | 
  | 217 |  |           break if abort? | 
  | 218 |  |         end | 
  | 219 |  |         options[:indent] -= (options[:indent_increment] * @issue_ancestors.size) | 
  | 220 |  |       end | 
  | 221 |  |  | 
  | 222 | 241 |       def render_version(project, version, options={}) | 
  | 223 | 242 |         # Version header | 
  | 224 | 243 |         subject_for_version(version, options) unless options[:only] == :lines | 
  | 225 | 244 |         line_for_version(version, options) unless options[:only] == :subjects | 
  | 226 | 245 |         options[:top] += options[:top_increment] | 
  |  | 246 |         options[:indent] += options[:indent_increment] | 
  | 227 | 247 |         @number_of_rows += 1 | 
  | 228 |  |         return if abort? | 
  |  | 248 |         return if abort? || (grouped? && !@version_groups) | 
  | 229 | 249 |         issues = version_issues(project, version) | 
  | 230 |  |         if issues | 
  |  | 250 |         if issues && grouped? | 
  |  | 251 |           render_groups(issues, options) | 
  |  | 252 |           return if abort? | 
  |  | 253 |         else | 
  | 231 | 254 |           sort_issues!(issues) | 
  | 232 |  |           # Indent issues | 
  | 233 |  |           options[:indent] += options[:indent_increment] | 
  | 234 | 255 |           render_issues(issues, options) | 
  | 235 |  |           options[:indent] -= options[:indent_increment] | 
  |  | 256 |           return if abort? | 
  |  | 257 |         end | 
  |  | 258 |         # Remove indent to hit the next sibling | 
  |  | 259 |         options[:indent] -= options[:indent_increment] | 
  |  | 260 |       end | 
  |  | 261 |  | 
  |  | 262 |       def render_groups(issues, options={}) | 
  |  | 263 |         while !issues.empty? | 
  |  | 264 |           # Group header | 
  |  | 265 |           group = group_name(issues[0]) | 
  |  | 266 |           subject_for_group(group, options) unless options[:only] == :lines | 
  |  | 267 |           options[:top] += options[:top_increment] | 
  |  | 268 |           @number_of_rows += 1 | 
  |  | 269 |           break if abort? | 
  |  | 270 |           gr_issues = group_issues!(group, issues) | 
  |  | 271 |           if gr_issues | 
  |  | 272 |             sort_issues!(gr_issues) | 
  |  | 273 |             # Indent issues | 
  |  | 274 |             options[:indent] += options[:indent_increment] | 
  |  | 275 |             render_issues(gr_issues, options) | 
  |  | 276 |             options[:indent] -= options[:indent_increment] | 
  |  | 277 |           end | 
  |  | 278 |           break if abort? | 
  |  | 279 |         end | 
  |  | 280 |       end | 
  |  | 281 |  | 
  |  | 282 |       def render_issues(issues, options={}) | 
  |  | 283 |         @issue_ancestors = [] | 
  |  | 284 |         if !grouped? || @detailed_groups | 
  |  | 285 |           issues.each do |i| | 
  |  | 286 |             if i.due_before == nil | 
  |  | 287 |               i.due_date = i.start_date | 
  |  | 288 |             end | 
  |  | 289 |             subject_for_issue(i, options) unless options[:only] == :lines | 
  |  | 290 |             line_for_issue(i, options) unless options[:only] == :subjects | 
  |  | 291 |             options[:top] += options[:top_increment] | 
  |  | 292 |             @number_of_rows += 1 | 
  |  | 293 |             break if abort? | 
  |  | 294 |           end | 
  |  | 295 |         else | 
  |  | 296 |           group_start = options[:top] - options[:top_increment] | 
  |  | 297 |           group_max_line = 0 | 
  |  | 298 |           group_write_line = group_max_line | 
  |  | 299 |           dates_in_line = [[]] | 
  |  | 300 |           @number_of_rows += 1 | 
  |  | 301 |           issues.each do |i| | 
  |  | 302 |             if i.leaf? | 
  |  | 303 |               if i.due_before == nil | 
  |  | 304 |                 i.due_date = i.start_date | 
  |  | 305 |               end | 
  |  | 306 |               group_write_line = -1 | 
  |  | 307 |               dates_in_line.each_with_index do |dates, line| | 
  |  | 308 |                 if dates.find {|e| (i.start_date >= e[0] && i.start_date <= e[1]) || (i.start_date <= e[0] && i.due_before >= e[1]) } == nil | 
  |  | 309 |                   group_write_line = line | 
  |  | 310 |                   break | 
  |  | 311 |                 end | 
  |  | 312 |               end | 
  |  | 313 |               if group_write_line == -1 | 
  |  | 314 |                 group_max_line += 1 | 
  |  | 315 |                 group_write_line = group_max_line | 
  |  | 316 |                 dates_in_line.push([]) | 
  |  | 317 |                 @number_of_rows += 1 | 
  |  | 318 |               end | 
  |  | 319 |               options[:top] = group_start + (group_write_line * options[:top_increment]) | 
  |  | 320 |               subject_for_issue(i, options) unless options[:only] == :lines | 
  |  | 321 |               line_for_issue(i, options) unless options[:only] == :subjects | 
  |  | 322 |               dates_in_line[group_write_line].push([i.start_date, i.due_before]) | 
  |  | 323 |             end | 
  |  | 324 |             break if abort? | 
  |  | 325 |           end | 
  |  | 326 |           options[:top] = group_start + ((group_max_line+1) * options[:top_increment]) | 
  | 236 | 327 |         end | 
  |  | 328 |         options[:indent] -= (options[:indent_increment] * @issue_ancestors.size) | 
  | 237 | 329 |       end | 
  | 238 | 330 |  | 
  | 239 | 331 |       def render_end(options={}) | 
  | ... | ... |  | 
  | 262 | 354 |       end | 
  | 263 | 355 |  | 
  | 264 | 356 |       def line_for_project(project, options) | 
  | 265 |  |         # Skip versions that don't have a start_date or due date | 
  |  | 357 |         # Skip projects that don't have a start_date or due date | 
  | 266 | 358 |         if project.is_a?(Project) && project.start_date && project.due_date | 
  | 267 | 359 |           options[:zoom] ||= 1 | 
  | 268 | 360 |           options[:g_width] ||= (self.date_to - self.date_from + 1) * options[:zoom] | 
  | ... | ... |  | 
  | 282 | 374 |         end | 
  | 283 | 375 |       end | 
  | 284 | 376 |  | 
  |  | 377 |       def subject_for_group(group, options) | 
  |  | 378 |         case options[:format] | 
  |  | 379 |         when :html | 
  |  | 380 |           html_class = "" | 
  |  | 381 |           html_class << 'icon icon-package ' | 
  |  | 382 |           s = group.html_safe | 
  |  | 383 |           subject = view.content_tag(:span, s, | 
  |  | 384 |                                      :class => html_class).html_safe | 
  |  | 385 |           html_subject(options, subject, :css => "version-name") | 
  |  | 386 |         when :image | 
  |  | 387 |           image_subject(options, group) | 
  |  | 388 |         when :pdf | 
  |  | 389 |           pdf_new_page?(options) | 
  |  | 390 |           pdf_subject(options, group) | 
  |  | 391 |         end | 
  |  | 392 |       end | 
  |  | 393 |  | 
  | 285 | 394 |       def subject_for_version(version, options) | 
  | 286 | 395 |         case options[:format] | 
  | 287 | 396 |         when :html | 
  | ... | ... |  | 
  | 332 | 441 |         end | 
  | 333 | 442 |         output = case options[:format] | 
  | 334 | 443 |         when :html | 
  | 335 |  |           css_classes = '' | 
  | 336 |  |           css_classes << ' issue-overdue' if issue.overdue? | 
  | 337 |  |           css_classes << ' issue-behind-schedule' if issue.behind_schedule? | 
  | 338 |  |           css_classes << ' icon icon-issue' unless Setting.gravatar_enabled? && issue.assigned_to | 
  | 339 |  |           s = "".html_safe | 
  | 340 |  |           if issue.assigned_to.present? | 
  | 341 |  |             assigned_string = l(:field_assigned_to) + ": " + issue.assigned_to.name | 
  | 342 |  |             s << view.avatar(issue.assigned_to, | 
  | 343 |  |                              :class => 'gravatar icon-gravatar', | 
  | 344 |  |                              :size => 10, | 
  | 345 |  |                              :title => assigned_string).to_s.html_safe | 
  | 346 |  |           end | 
  | 347 |  |           s << view.link_to_issue(issue).html_safe | 
  | 348 |  |           subject = view.content_tag(:span, s, :class => css_classes).html_safe | 
  | 349 |  |           html_subject(options, subject, :css => "issue-subject", | 
  | 350 |  |                        :title => issue.subject) + "\n" | 
  |  | 444 |           if !grouped? || @detailed_groups | 
  |  | 445 |             css_classes = '' | 
  |  | 446 |             css_classes << ' issue-overdue' if issue.overdue? | 
  |  | 447 |             css_classes << ' issue-behind-schedule' if issue.behind_schedule? | 
  |  | 448 |             css_classes << ' icon icon-issue' unless Setting.gravatar_enabled? && issue.assigned_to | 
  |  | 449 |             s = "".html_safe | 
  |  | 450 |             if issue.assigned_to.present? | 
  |  | 451 |               assigned_string = l(:field_assigned_to) + ": " + issue.assigned_to.name | 
  |  | 452 |               s << view.avatar(issue.assigned_to, | 
  |  | 453 |                                :class => 'gravatar icon-gravatar', | 
  |  | 454 |                                :size => 10, | 
  |  | 455 |                                :title => assigned_string).to_s.html_safe | 
  |  | 456 |             end | 
  |  | 457 |             s << view.link_to_issue(issue).html_safe | 
  |  | 458 |             subject = view.content_tag(:span, s, :class => css_classes).html_safe | 
  |  | 459 |             html_subject(options, subject, :css => "issue-subject", | 
  |  | 460 |                          :title => issue.subject) + "\n" | 
  |  | 461 |           end | 
  | 351 | 462 |         when :image | 
  | 352 |  |           image_subject(options, issue.subject) | 
  |  | 463 |           if !grouped? || @detailed_groups | 
  |  | 464 |             image_subject(options, issue.subject) | 
  |  | 465 |           end | 
  | 353 | 466 |         when :pdf | 
  | 354 | 467 |           pdf_new_page?(options) | 
  | 355 |  |           pdf_subject(options, issue.subject) | 
  |  | 468 |           pdf_subject(options, (grouped? || @detailed_groups) ? ' ' : issue.subject) | 
  | 356 | 469 |         end | 
  | 357 | 470 |         unless issue.leaf? | 
  | 358 | 471 |           @issue_ancestors << issue | 
  | ... | ... |  | 
  | 365 | 478 |         # Skip issues that don't have a due_before (due_date or version's due_date) | 
  | 366 | 479 |         if issue.is_a?(Issue) && issue.due_before | 
  | 367 | 480 |           coords = coordinates(issue.start_date, issue.due_before, issue.done_ratio, options[:zoom]) | 
  | 368 |  |           label = "#{issue.status.name} #{issue.done_ratio}%" | 
  |  | 481 |           label = " " | 
  |  | 482 |           if !grouped? || @detailed_groups | 
  |  | 483 |             label = "#{issue.status.name} #{issue.done_ratio}%" | 
  |  | 484 |           end | 
  | 369 | 485 |           case options[:format] | 
  | 370 | 486 |           when :html | 
  | 371 | 487 |             html_task(options, coords, | 
  | ... | ... |  | 
  | 666 | 782 |         end | 
  | 667 | 783 |       end | 
  | 668 | 784 |  | 
  |  | 785 |       def grouped? | 
  |  | 786 |         @query.grouped? | 
  |  | 787 |       end | 
  |  | 788 |  | 
  |  | 789 |       def new_group?(x, y) | 
  |  | 790 |         if grouped? | 
  |  | 791 |           value_x = @query.group_by_column.value(x) | 
  |  | 792 |           value_y = @query.group_by_column.value(y) | 
  |  | 793 |           value_x != value_y | 
  |  | 794 |         else | 
  |  | 795 |           true | 
  |  | 796 |         end | 
  |  | 797 |       end | 
  |  | 798 |  | 
  |  | 799 |       def group_name(issue) | 
  |  | 800 |         if grouped? | 
  |  | 801 |           result = @query.group_by_column.value(issue) | 
  |  | 802 |           if result == nil || result == '' | 
  |  | 803 |             'None' | 
  |  | 804 |           else | 
  |  | 805 |             result.to_s | 
  |  | 806 |           end | 
  |  | 807 |         else | 
  |  | 808 |           issue.subject | 
  |  | 809 |         end | 
  |  | 810 |       end | 
  |  | 811 |  | 
  | 669 | 812 |       def pdf_new_page?(options) | 
  | 670 | 813 |         if options[:top] > 180 | 
  | 671 | 814 |           options[:pdf].Line(15, options[:top], PDF::TotalWidth, options[:top]) |