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
|