summaryrefslogtreecommitdiffstats
path: root/app/helpers/projects_helper.rb
blob: 2657c7e0a5d1a4c92d3c5db11895a7e82de4c995 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# redMine - project management software
# Copyright (C) 2006  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
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

module ProjectsHelper
  def link_to_version(version, options = {})
    return '' unless version && version.is_a?(Version)
    link_to version.name, {:controller => 'projects',
                           :action => 'roadmap',
                           :id => version.project_id,
                           :completed => (version.completed? ? 1 : nil),
                           :anchor => version.name
                          }, options
  end
  
  # Generates a gantt image
  # Only defined if RMagick is avalaible
  def gantt_image(events, date_from, months, zoom)
    date_to = (date_from >> months)-1    
    show_weeks = zoom > 1
    show_days = zoom > 2
    
    subject_width = 320
    header_heigth = 18
    # width of one day in pixels
    zoom = zoom*2
    g_width = (date_to - date_from + 1)*zoom
    g_height = 20 * events.length + 20
    headers_heigth = (show_weeks ? 2*header_heigth : header_heigth)
    height = g_height + headers_heigth
        
    imgl = Magick::ImageList.new
    imgl.new_image(subject_width+g_width+1, height)
    gc = Magick::Draw.new
    
    # Subjects
    top = headers_heigth + 20
    gc.fill('black')
    gc.stroke('transparent')
    gc.stroke_width(1)
    events.each do |i|
      gc.text(4, top + 2, (i.is_a?(Issue) ? i.subject : i.name))
      top = top + 20
    end

    # Months headers
    month_f = date_from
    left = subject_width
    months.times do 
      width = ((month_f >> 1) - month_f) * zoom
      gc.fill('white')
      gc.stroke('grey')
      gc.stroke_width(1)
      gc.rectangle(left, 0, left + width, height)
      gc.fill('black')
      gc.stroke('transparent')
      gc.stroke_width(1)
      gc.text(left.round + 8, 14, "#{month_f.year}-#{month_f.month}")
      left = left + width
      month_f = month_f >> 1
    end
    
    # Weeks headers
    if show_weeks
    	left = subject_width
    	height = header_heigth
    	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
            gc.fill('white')
            gc.stroke('grey')
            gc.stroke_width(1)
            gc.rectangle(left, header_heigth, left + width, 2*header_heigth + g_height-1)
    		left = left + width
    	end
    	while week_f <= date_to
    		width = (week_f + 6 <= date_to) ? 7 * zoom : (date_to - week_f + 1) * zoom
            gc.fill('white')
            gc.stroke('grey')
            gc.stroke_width(1)
            gc.rectangle(left.round, header_heigth, left.round + width, 2*header_heigth + g_height-1)
            gc.fill('black')
            gc.stroke('transparent')
            gc.stroke_width(1)
            gc.text(left.round + 2, header_heigth + 14, week_f.cweek.to_s)
    		left = left + width
    		week_f = week_f+7
    	end
    end
    
    # Days details (week-end in grey)
    if show_days
    	left = subject_width
    	height = g_height + header_heigth - 1
    	wday = date_from.cwday
    	(date_to - date_from + 1).to_i.times do 
          width =  zoom
          gc.fill(wday == 6 || wday == 7 ? '#eee' : 'white')
          gc.stroke('grey')
          gc.stroke_width(1)
          gc.rectangle(left, 2*header_heigth, left + width, 2*header_heigth + g_height-1)
          left = left + width
          wday = wday + 1
          wday = 1 if wday > 7
    	end
    end

    # border
    gc.fill('transparent')
    gc.stroke('grey')
    gc.stroke_width(1)
    gc.rectangle(0, 0, subject_width+g_width, headers_heigth)
    gc.stroke('black')
    gc.rectangle(0, 0, subject_width+g_width, g_height+ headers_heigth-1)
        
    # content
    top = headers_heigth + 20
    gc.stroke('transparent')
    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 = subject_width + ((i_start_date - date_from)*zoom).floor 	
        i_width = ((i_end_date - i_start_date + 1)*zoom).floor                  # total width of the issue
        d_width = ((i_done_date - i_start_date)*zoom).floor                     # done width
        l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor : 0 # delay width
  
        gc.fill('grey')
        gc.rectangle(i_left, top, i_left + i_width, top - 6)
        gc.fill('red')
        gc.rectangle(i_left, top, i_left + l_width, top - 6) if l_width > 0
        gc.fill('blue')
        gc.rectangle(i_left, top, i_left + d_width, top - 6) if d_width > 0
        gc.fill('black')
        gc.text(i_left + i_width + 5,top + 1, "#{i.status.name} #{i.done_ratio}%")
      else
        i_left = subject_width + ((i.start_date - date_from)*zoom).floor
        gc.fill('green')
        gc.rectangle(i_left, top, i_left + 6, top - 6)        
        gc.fill('black')
        gc.text(i_left + 11, top + 1, i.name)
      end
      top = top + 20
    end
    
    # today red line
    if Date.today >= @date_from and Date.today <= @date_to
      gc.stroke('red')
      x = (Date.today-@date_from+1)*zoom + subject_width
      gc.line(x, headers_heigth, x, headers_heigth + g_height-1)      
    end    
    
    gc.draw(imgl)
    imgl
  end if Object.const_defined?(:Magick)
  
  def new_issue_selector
    trackers = Tracker.find(:all, :order => 'position')
    # can't use form tag inside helper
    content_tag('form',
      select_tag('tracker_id', '<option></option>' + options_from_collection_for_select(trackers, 'id', 'name'), :onchange => "if (this.value != '') {this.form.submit()}"),
      :action => url_for(:controller => 'projects', :action => 'add_issue', :id => @project), :method => 'get')
  end
end