##// END OF EJS Templates
Fixed: private method 'gsub' called for nil:NilClass on activity (#1519)....
Jean-Philippe Lang -
r1568:c97a5efde911
parent child
Show More
@@ -1,198 +1,198
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 module ProjectsHelper
19 19 def link_to_version(version, options = {})
20 20 return '' unless version && version.is_a?(Version)
21 21 link_to h(version.name), { :controller => 'versions', :action => 'show', :id => version }, options
22 22 end
23 23
24 24 def format_activity_title(text)
25 25 h(truncate_single_line(text, 100))
26 26 end
27 27
28 28 def format_activity_day(date)
29 29 date == Date.today ? l(:label_today).titleize : format_date(date)
30 30 end
31 31
32 32 def format_activity_description(text)
33 h(truncate(text, 250).gsub(%r{<(pre|code)>.*$}m, '...'))
33 h(truncate(text.to_s, 250).gsub(%r{<(pre|code)>.*$}m, '...'))
34 34 end
35 35
36 36 def project_settings_tabs
37 37 tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural},
38 38 {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural},
39 39 {:name => 'members', :action => :manage_members, :partial => 'projects/settings/members', :label => :label_member_plural},
40 40 {:name => 'versions', :action => :manage_versions, :partial => 'projects/settings/versions', :label => :label_version_plural},
41 41 {:name => 'categories', :action => :manage_categories, :partial => 'projects/settings/issue_categories', :label => :label_issue_category_plural},
42 42 {:name => 'wiki', :action => :manage_wiki, :partial => 'projects/settings/wiki', :label => :label_wiki},
43 43 {:name => 'repository', :action => :manage_repository, :partial => 'projects/settings/repository', :label => :label_repository},
44 44 {:name => 'boards', :action => :manage_boards, :partial => 'projects/settings/boards', :label => :label_board_plural}
45 45 ]
46 46 tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)}
47 47 end
48 48
49 49 # Generates a gantt image
50 50 # Only defined if RMagick is avalaible
51 51 def gantt_image(events, date_from, months, zoom)
52 52 date_to = (date_from >> months)-1
53 53 show_weeks = zoom > 1
54 54 show_days = zoom > 2
55 55
56 56 subject_width = 320
57 57 header_heigth = 18
58 58 # width of one day in pixels
59 59 zoom = zoom*2
60 60 g_width = (date_to - date_from + 1)*zoom
61 61 g_height = 20 * events.length + 20
62 62 headers_heigth = (show_weeks ? 2*header_heigth : header_heigth)
63 63 height = g_height + headers_heigth
64 64
65 65 imgl = Magick::ImageList.new
66 66 imgl.new_image(subject_width+g_width+1, height)
67 67 gc = Magick::Draw.new
68 68
69 69 # Subjects
70 70 top = headers_heigth + 20
71 71 gc.fill('black')
72 72 gc.stroke('transparent')
73 73 gc.stroke_width(1)
74 74 events.each do |i|
75 75 gc.text(4, top + 2, (i.is_a?(Issue) ? i.subject : i.name))
76 76 top = top + 20
77 77 end
78 78
79 79 # Months headers
80 80 month_f = date_from
81 81 left = subject_width
82 82 months.times do
83 83 width = ((month_f >> 1) - month_f) * zoom
84 84 gc.fill('white')
85 85 gc.stroke('grey')
86 86 gc.stroke_width(1)
87 87 gc.rectangle(left, 0, left + width, height)
88 88 gc.fill('black')
89 89 gc.stroke('transparent')
90 90 gc.stroke_width(1)
91 91 gc.text(left.round + 8, 14, "#{month_f.year}-#{month_f.month}")
92 92 left = left + width
93 93 month_f = month_f >> 1
94 94 end
95 95
96 96 # Weeks headers
97 97 if show_weeks
98 98 left = subject_width
99 99 height = header_heigth
100 100 if date_from.cwday == 1
101 101 # date_from is monday
102 102 week_f = date_from
103 103 else
104 104 # find next monday after date_from
105 105 week_f = date_from + (7 - date_from.cwday + 1)
106 106 width = (7 - date_from.cwday + 1) * zoom
107 107 gc.fill('white')
108 108 gc.stroke('grey')
109 109 gc.stroke_width(1)
110 110 gc.rectangle(left, header_heigth, left + width, 2*header_heigth + g_height-1)
111 111 left = left + width
112 112 end
113 113 while week_f <= date_to
114 114 width = (week_f + 6 <= date_to) ? 7 * zoom : (date_to - week_f + 1) * zoom
115 115 gc.fill('white')
116 116 gc.stroke('grey')
117 117 gc.stroke_width(1)
118 118 gc.rectangle(left.round, header_heigth, left.round + width, 2*header_heigth + g_height-1)
119 119 gc.fill('black')
120 120 gc.stroke('transparent')
121 121 gc.stroke_width(1)
122 122 gc.text(left.round + 2, header_heigth + 14, week_f.cweek.to_s)
123 123 left = left + width
124 124 week_f = week_f+7
125 125 end
126 126 end
127 127
128 128 # Days details (week-end in grey)
129 129 if show_days
130 130 left = subject_width
131 131 height = g_height + header_heigth - 1
132 132 wday = date_from.cwday
133 133 (date_to - date_from + 1).to_i.times do
134 134 width = zoom
135 135 gc.fill(wday == 6 || wday == 7 ? '#eee' : 'white')
136 136 gc.stroke('grey')
137 137 gc.stroke_width(1)
138 138 gc.rectangle(left, 2*header_heigth, left + width, 2*header_heigth + g_height-1)
139 139 left = left + width
140 140 wday = wday + 1
141 141 wday = 1 if wday > 7
142 142 end
143 143 end
144 144
145 145 # border
146 146 gc.fill('transparent')
147 147 gc.stroke('grey')
148 148 gc.stroke_width(1)
149 149 gc.rectangle(0, 0, subject_width+g_width, headers_heigth)
150 150 gc.stroke('black')
151 151 gc.rectangle(0, 0, subject_width+g_width, g_height+ headers_heigth-1)
152 152
153 153 # content
154 154 top = headers_heigth + 20
155 155 gc.stroke('transparent')
156 156 events.each do |i|
157 157 if i.is_a?(Issue)
158 158 i_start_date = (i.start_date >= date_from ? i.start_date : date_from )
159 159 i_end_date = (i.due_date <= date_to ? i.due_date : date_to )
160 160 i_done_date = i.start_date + ((i.due_date - i.start_date+1)*i.done_ratio/100).floor
161 161 i_done_date = (i_done_date <= date_from ? date_from : i_done_date )
162 162 i_done_date = (i_done_date >= date_to ? date_to : i_done_date )
163 163 i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today
164 164
165 165 i_left = subject_width + ((i_start_date - date_from)*zoom).floor
166 166 i_width = ((i_end_date - i_start_date + 1)*zoom).floor # total width of the issue
167 167 d_width = ((i_done_date - i_start_date)*zoom).floor # done width
168 168 l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor : 0 # delay width
169 169
170 170 gc.fill('grey')
171 171 gc.rectangle(i_left, top, i_left + i_width, top - 6)
172 172 gc.fill('red')
173 173 gc.rectangle(i_left, top, i_left + l_width, top - 6) if l_width > 0
174 174 gc.fill('blue')
175 175 gc.rectangle(i_left, top, i_left + d_width, top - 6) if d_width > 0
176 176 gc.fill('black')
177 177 gc.text(i_left + i_width + 5,top + 1, "#{i.status.name} #{i.done_ratio}%")
178 178 else
179 179 i_left = subject_width + ((i.start_date - date_from)*zoom).floor
180 180 gc.fill('green')
181 181 gc.rectangle(i_left, top, i_left + 6, top - 6)
182 182 gc.fill('black')
183 183 gc.text(i_left + 11, top + 1, i.name)
184 184 end
185 185 top = top + 20
186 186 end
187 187
188 188 # today red line
189 189 if Date.today >= date_from and Date.today <= date_to
190 190 gc.stroke('red')
191 191 x = (Date.today-date_from+1)*zoom + subject_width
192 192 gc.line(x, headers_heigth, x, headers_heigth + g_height-1)
193 193 end
194 194
195 195 gc.draw(imgl)
196 196 imgl
197 197 end if Object.const_defined?(:Magick)
198 198 end
General Comments 0
You need to be logged in to leave comments. Login now