Index: app/controllers/trackers_controller.rb =================================================================== --- app/controllers/trackers_controller.rb (revision 1034) +++ app/controllers/trackers_controller.rb (working copy) @@ -18,6 +18,11 @@ class TrackersController < ApplicationController layout 'base' before_filter :require_admin + + helper :issues + helper IssuesHelper + helper :projects + helper ProjectsHelper def index list @@ -81,4 +86,92 @@ end redirect_to :action => 'list' end + + def gantt + @trackers = Tracker.find(:all, :order => 'position') + retrieve_selected_tracker_ids(@trackers) + + if params[:year] and params[:year].to_i >0 + @year_from = params[:year].to_i + if params[:month] and params[:month].to_i >=1 and params[:month].to_i <= 12 + @month_from = params[:month].to_i + else + @month_from = 1 + end + else + @month_from ||= Date.today.month + @year_from ||= Date.today.year + end + + zoom = (params[:zoom] || User.current.pref[:gantt_zoom]).to_i + @zoom = (zoom > 0 && zoom < 5) ? zoom : 2 + months = (params[:months] || User.current.pref[:gantt_months]).to_i + @months = (months > 0 && months < 25) ? months : 6 + + # Save gantt paramters as user preference (zoom and months count) + if (User.current.logged? && (@zoom != User.current.pref[:gantt_zoom] || @months != User.current.pref[:gantt_months])) + User.current.pref[:gantt_zoom], User.current.pref[:gantt_months] = @zoom, @months + User.current.preference.save + end + + @date_from = Date.civil(@year_from, @month_from, 1) + @date_to = (@date_from >> @months) - 1 + + @events = [] + @events += Issue.find(:all, + :order => "start_date, due_date", + :include => [:tracker, :status, :assigned_to, :priority, :project], + :conditions => ["(((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?) or (start_date?)) and start_date is not null and due_date is not null and #{Issue.table_name}.tracker_id in (#{@selected_tracker_ids.join(',')}))", @date_from, @date_to, @date_from, @date_to, @date_from, @date_to] + ) unless @selected_tracker_ids.empty? +# @events += @project.versions.find(:all, :conditions => ["effective_date BETWEEN ? AND ?", @date_from, @date_to]) + @events.sort! {|x,y| x.start_date <=> y.start_date } + + if params[:format]=='pdf' + @options_for_rfpdf ||= {} + @options_for_rfpdf[:file_name] = "#{@project.identifier}-gantt.pdf" + render :template => "projects/gantt.rfpdf", :layout => false + elsif params[:format]=='png' && respond_to?('gantt_image') + image = gantt_image(@events, @date_from, @months, @zoom) + image.format = 'PNG' + send_data(image.to_blob, :disposition => 'inline', :type => 'image/png', :filename => "#{@project.identifier}-gantt.png") + else + render :template => "trackers/gantt.rhtml" + end + end + + def calendar + @trackers = Tracker.find(:all, :order => 'position') + retrieve_selected_tracker_ids(@trackers) + + if params[:year] and params[:year].to_i > 1900 + @year = params[:year].to_i + if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13 + @month = params[:month].to_i + end + end + @year ||= Date.today.year + @month ||= Date.today.month + @calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), current_language, :month) + + events = [] + events += Issue.find(:all, + :include => [:tracker, :status, :assigned_to, :priority, :project], + :conditions => ["((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?)) AND #{Issue.table_name}.tracker_id IN (#{@selected_tracker_ids.join(',')})", @calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt] + ) unless @selected_tracker_ids.empty? +# events += @project.versions.find(:all, :conditions => ["effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt]) + @calendar.events = events + + render :layout => false if request.xhr? + end + + + +private + def retrieve_selected_tracker_ids(selectable_trackers) + if ids = params[:tracker_ids] + @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s } + else + @selected_tracker_ids = selectable_trackers.collect {|t| t.id.to_s } + end + end end Index: app/views/trackers/gantt.rhtml =================================================================== --- app/views/trackers/gantt.rhtml (revision 0) +++ app/views/trackers/gantt.rhtml (revision 0) @@ -0,0 +1,244 @@ +<% zoom = 1 +@zoom.times { zoom = zoom * 2 } + +subject_width = 330 +header_heigth = 18 + +headers_height = header_heigth +show_weeks = false +show_days = false + +if @zoom >1 + show_weeks = true + headers_height = 2*header_heigth + if @zoom > 2 + show_days = true + headers_height = 3*header_heigth + end +end + +g_width = (@date_to - @date_from + 1)*zoom +g_height = [(20 * @events.length + 6)+150, 206].max +t_height = g_height + headers_height +%> + +
+
+ +

<%= l(:label_gantt) %>

+ +<% form_tag(params.merge(:month => nil, :year => nil, :months => nil)) do %> + + + + + + +
+ + <%= l(:label_months_from) %> + <%= select_month(@month_from, :prefix => "month", :discard_type => true) %> + <%= select_year(@year_from, :prefix => "year", :discard_type => true) %> + <%= hidden_field_tag 'zoom', @zoom %> + <%= submit_tag l(:button_submit), :class => "button-small" %> + +<%= if @zoom < 4 + link_to image_tag('zoom_in.png'), {:zoom => (@zoom+1), :year => @year_from, :month => @month_from, :months => @months, :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects]} + else + image_tag 'zoom_in_g.png' + end %> +<%= if @zoom > 1 + link_to image_tag('zoom_out.png'),{:zoom => (@zoom-1), :year => @year_from, :month => @month_from, :months => @months, :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects]} + else + image_tag 'zoom_out_g.png' + end %> +
+<% end %> + +<% cache(:year => @year_from, :month => @month_from, :months => @months, :zoom => @zoom, :tracker_ids => @selected_tracker_ids, :subprojects => params[:with_subprojects], :lang => current_language) do %> + + + + + + +
+ +
+
+
+<% +# +# Tasks subjects +# +top = headers_height + 8 +@events.each do |i| %> +
+ <% if i.is_a? Issue %> + <%= link_to_issue i %><%= " (#{i.project.name})" unless @project && @project == i.project %>: + <%=h i.subject %> + <% else %> + <%= link_to_version i, :class => "icon icon-package" %> + <% end %> +
+ <% top = top + 20 +end %> +
+
+ +
+
 
+<% +# +# Months headers +# +month_f = @date_from +left = 0 +height = (show_weeks ? header_heigth : header_heigth + g_height) +@months.times do + width = ((month_f >> 1) - month_f) * zoom - 1 + %> +
+ <%= link_to "#{month_f.year}-#{month_f.month}", { :year => month_f.year, :month => month_f.month, :zoom => @zoom, :months => @months, :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects] }, :title => "#{month_name(month_f.month)} #{month_f.year}"%> +
+ <% + left = left + width + 1 + month_f = month_f >> 1 +end %> + +<% +# +# Weeks headers +# +if show_weeks + left = 0 + height = (show_days ? header_heigth-1 : header_heigth-1 + g_height) + if @date_from.cwday == 1 + # @date_from is monday + week_f = @date_from + else + # find next monday after @date_from + week_f = @date_from + (7 - @date_from.cwday + 1) + width = (7 - @date_from.cwday + 1) * zoom-1 + %> +
 
+ <% + left = left + width+1 + end %> + <% + while week_f <= @date_to + width = (week_f + 6 <= @date_to) ? 7 * zoom -1 : (@date_to - week_f + 1) * zoom-1 + %> +
+ <%= week_f.cweek if width >= 16 %> +
+ <% + left = left + width+1 + week_f = week_f+7 + end +end %> + +<% +# +# Days headers +# +if show_days + left = 0 + height = g_height + header_heigth - 1 + wday = @date_from.cwday + (@date_to - @date_from + 1).to_i.times do + width = zoom - 1 + %> +
5 %>" class="gantt_hdr"> + <%= day_name(wday).first %> +
+ <% + left = left + width+1 + wday = wday + 1 + wday = 1 if wday > 7 + end +end %> + +<% +# +# Tasks +# +top = headers_height + 10 +@events.each do |i| + if i.is_a? Issue + i_start_date = (i.start_date >= @date_from ? i.start_date : @date_from ) + i_end_date = (i.due_date <= @date_to ? i.due_date : @date_to ) + + i_done_date = i.start_date + ((i.due_date - i.start_date+1)*i.done_ratio/100).floor + i_done_date = (i_done_date <= @date_from ? @date_from : i_done_date ) + i_done_date = (i_done_date >= @date_to ? @date_to : i_done_date ) + + i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today + + i_left = ((i_start_date - @date_from)*zoom).floor + i_width = ((i_end_date - i_start_date + 1)*zoom).floor - 2 # total width of the issue (- 2 for left and right borders) + d_width = ((i_done_date - i_start_date)*zoom).floor - 2 # done width + l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor - 2 : 0 # delay width + %> +
 
+ <% if l_width > 0 %> +
 
+ <% end %> + <% if d_width > 0 %> +
 
+ <% end %> +
+ <%= i.status.name %> + <%= (i.done_ratio).to_i %>% +
+ <% # === tooltip === %> +
+ + <%= render_issue_tooltip i %> +
+<% else + i_left = ((i.start_date - @date_from)*zoom).floor + %> +
 
+
+ <%= i.name %> +
+<% end %> + <% top = top + 20 +end %> + +<% end # cache +%> + +<% +# +# Today red line (excluded from cache) +# +if Date.today >= @date_from and Date.today <= @date_to %> +
 
+<% end %> + +
+
+ + + + + + +
<%= link_to ('« ' + l(:label_previous)), :year => (@date_from << @months).year, :month => (@date_from << @months).month, :zoom => @zoom, :months => @months, :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects] %><%= link_to (l(:label_next) + ' »'), :year => (@date_from >> @months).year, :month => (@date_from >> @months).month, :zoom => @zoom, :months => @months, :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects] %>
+ +
<%= l(:label_export_to) %> +<%= link_to 'PDF', {:zoom => @zoom, :year => @year_from, :month => @month_from, :months => @months, :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects], :format => 'pdf'}, :class => 'icon icon-pdf' %> +<%= link_to 'PNG', {:zoom => @zoom, :year => @year_from, :month => @month_from, :months => @months, :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects], :format => 'png'}, :class => 'icon icon-image' if respond_to?('gantt_image') %> +
+ +<% content_for :sidebar do %> +

<%= l(:label_gantt) %>

+ <% form_tag(params.merge(:tracker_ids => nil, :with_subprojects => nil)) do %> + <% @trackers.each do |tracker| %> +
+ <% end %> +

<%= submit_tag l(:button_apply), :class => 'button-small' %>

+ <% end %> +<% end %> Index: app/views/trackers/calendar.rhtml =================================================================== --- app/views/trackers/calendar.rhtml (revision 0) +++ app/views/trackers/calendar.rhtml (revision 0) @@ -0,0 +1,37 @@ +<% cache(:year => @year, :month => @month, :tracker_ids => @selected_tracker_ids, :subprojects => params[:with_subprojects], :lang => current_language) do %> +

<%= l(:label_calendar) %>: <%= "#{month_name(@month).downcase} #{@year}" %>

+ + + +
+ <%= link_to_remote ('« ' + (@month==1 ? "#{month_name(12)} #{@year-1}" : "#{month_name(@month-1)}")), + {:update => "content", :url => { :year => (@month==1 ? @year-1 : @year), :month =>(@month==1 ? 12 : @month-1), :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects] }}, + {:href => url_for(:action => 'calendar', :year => (@month==1 ? @year-1 : @year), :month =>(@month==1 ? 12 : @month-1), :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects])} + %> + + <%= link_to_remote ((@month==12 ? "#{month_name(1)} #{@year+1}" : "#{month_name(@month+1)}") + ' »'), + {:update => "content", :url => { :year => (@month==12 ? @year+1 : @year), :month =>(@month==12 ? 1 : @month+1), :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects] }}, + {:href => url_for(:action => 'calendar', :year => (@month==12 ? @year+1 : @year), :month =>(@month==12 ? 1 : @month+1), :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects])} + %> +
+ +<%= render :partial => 'common/calendar', :locals => {:calendar => @calendar} %> + +<%= image_tag 'arrow_from.png' %>  <%= l(:text_tip_task_begin_day) %>
+<%= image_tag 'arrow_to.png' %>  <%= l(:text_tip_task_end_day) %>
+<%= image_tag 'arrow_bw.png' %>  <%= l(:text_tip_task_begin_end_day) %>
+<% end %> + +<% content_for :sidebar do %> +

<%= l(:label_calendar) %>

+ + <% form_tag() do %> +

<%= select_month(@month, :prefix => "month", :discard_type => true) %> + <%= select_year(@year, :prefix => "year", :discard_type => true) %>

+ + <% @trackers.each do |tracker| %> +
+ <% end %> +

<%= submit_tag l(:button_apply), :class => 'button-small' %>

+ <% end %> +<% end %>