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 due_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_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 %> + | +
+
+
+
+
+<%
+#
+# Tasks subjects
+#
+top = headers_height + 8
+@events.each do |i| %>
+
+
+ <% top = top + 20
+end %>
+ |
+
+
+
+
+
+ <%= 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
+ %>
+
+ <%= 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
+ %>
+
+ <%= 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 %>
+ |
+
<%= 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] %> | +
<%= 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 %> ++ <%= 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])} + %> + |
<%= select_month(@month, :prefix => "month", :discard_type => true) %> + <%= select_year(@year, :prefix => "year", :discard_type => true) %>
+ + <% @trackers.each do |tracker| %> +<%= submit_tag l(:button_apply), :class => 'button-small' %>
+ <% end %> +<% end %>