##// END OF EJS Templates
Added versions due dates on gantt chart....
Jean-Philippe Lang -
r425:708c3c9ec6ef
parent child
Show More
@@ -1,688 +1,690
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'csv'
18 require 'csv'
19
19
20 class ProjectsController < ApplicationController
20 class ProjectsController < ApplicationController
21 layout 'base'
21 layout 'base'
22 before_filter :find_project, :authorize, :except => [ :index, :list, :add ]
22 before_filter :find_project, :authorize, :except => [ :index, :list, :add ]
23 before_filter :require_admin, :only => [ :add, :destroy ]
23 before_filter :require_admin, :only => [ :add, :destroy ]
24
24
25 helper :sort
25 helper :sort
26 include SortHelper
26 include SortHelper
27 helper :custom_fields
27 helper :custom_fields
28 include CustomFieldsHelper
28 include CustomFieldsHelper
29 helper :ifpdf
29 helper :ifpdf
30 include IfpdfHelper
30 include IfpdfHelper
31 helper IssuesHelper
31 helper IssuesHelper
32 helper :queries
32 helper :queries
33 include QueriesHelper
33 include QueriesHelper
34
34
35 def index
35 def index
36 list
36 list
37 render :action => 'list' unless request.xhr?
37 render :action => 'list' unless request.xhr?
38 end
38 end
39
39
40 # Lists public projects
40 # Lists public projects
41 def list
41 def list
42 sort_init "#{Project.table_name}.name", "asc"
42 sort_init "#{Project.table_name}.name", "asc"
43 sort_update
43 sort_update
44 @project_count = Project.count(:all, :conditions => ["is_public=?", true])
44 @project_count = Project.count(:all, :conditions => ["is_public=?", true])
45 @project_pages = Paginator.new self, @project_count,
45 @project_pages = Paginator.new self, @project_count,
46 15,
46 15,
47 params['page']
47 params['page']
48 @projects = Project.find :all, :order => sort_clause,
48 @projects = Project.find :all, :order => sort_clause,
49 :conditions => ["#{Project.table_name}.is_public=?", true],
49 :conditions => ["#{Project.table_name}.is_public=?", true],
50 :include => :parent,
50 :include => :parent,
51 :limit => @project_pages.items_per_page,
51 :limit => @project_pages.items_per_page,
52 :offset => @project_pages.current.offset
52 :offset => @project_pages.current.offset
53
53
54 render :action => "list", :layout => false if request.xhr?
54 render :action => "list", :layout => false if request.xhr?
55 end
55 end
56
56
57 # Add a new project
57 # Add a new project
58 def add
58 def add
59 @custom_fields = IssueCustomField.find(:all)
59 @custom_fields = IssueCustomField.find(:all)
60 @root_projects = Project.find(:all, :conditions => "parent_id is null")
60 @root_projects = Project.find(:all, :conditions => "parent_id is null")
61 @project = Project.new(params[:project])
61 @project = Project.new(params[:project])
62 if request.get?
62 if request.get?
63 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project) }
63 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project) }
64 else
64 else
65 @project.custom_fields = CustomField.find(params[:custom_field_ids]) if params[:custom_field_ids]
65 @project.custom_fields = CustomField.find(params[:custom_field_ids]) if params[:custom_field_ids]
66 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
66 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
67 @project.custom_values = @custom_values
67 @project.custom_values = @custom_values
68 if params[:repository_enabled] && params[:repository_enabled] == "1"
68 if params[:repository_enabled] && params[:repository_enabled] == "1"
69 @project.repository = Repository.new
69 @project.repository = Repository.new
70 @project.repository.attributes = params[:repository]
70 @project.repository.attributes = params[:repository]
71 end
71 end
72 if "1" == params[:wiki_enabled]
72 if "1" == params[:wiki_enabled]
73 @project.wiki = Wiki.new
73 @project.wiki = Wiki.new
74 @project.wiki.attributes = params[:wiki]
74 @project.wiki.attributes = params[:wiki]
75 end
75 end
76 if @project.save
76 if @project.save
77 flash[:notice] = l(:notice_successful_create)
77 flash[:notice] = l(:notice_successful_create)
78 redirect_to :controller => 'admin', :action => 'projects'
78 redirect_to :controller => 'admin', :action => 'projects'
79 end
79 end
80 end
80 end
81 end
81 end
82
82
83 # Show @project
83 # Show @project
84 def show
84 def show
85 @custom_values = @project.custom_values.find(:all, :include => :custom_field)
85 @custom_values = @project.custom_values.find(:all, :include => :custom_field)
86 @members = @project.members.find(:all, :include => [:user, :role], :order => 'position')
86 @members = @project.members.find(:all, :include => [:user, :role], :order => 'position')
87 @subprojects = @project.children if @project.children.size > 0
87 @subprojects = @project.children if @project.children.size > 0
88 @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
88 @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
89 @trackers = Tracker.find(:all, :order => 'position')
89 @trackers = Tracker.find(:all, :order => 'position')
90 @open_issues_by_tracker = Issue.count(:group => :tracker, :joins => "INNER JOIN #{IssueStatus.table_name} ON #{IssueStatus.table_name}.id = #{Issue.table_name}.status_id", :conditions => ["project_id=? and #{IssueStatus.table_name}.is_closed=?", @project.id, false])
90 @open_issues_by_tracker = Issue.count(:group => :tracker, :joins => "INNER JOIN #{IssueStatus.table_name} ON #{IssueStatus.table_name}.id = #{Issue.table_name}.status_id", :conditions => ["project_id=? and #{IssueStatus.table_name}.is_closed=?", @project.id, false])
91 @total_issues_by_tracker = Issue.count(:group => :tracker, :conditions => ["project_id=?", @project.id])
91 @total_issues_by_tracker = Issue.count(:group => :tracker, :conditions => ["project_id=?", @project.id])
92 end
92 end
93
93
94 def settings
94 def settings
95 @root_projects = Project::find(:all, :conditions => ["parent_id is null and id <> ?", @project.id])
95 @root_projects = Project::find(:all, :conditions => ["parent_id is null and id <> ?", @project.id])
96 @custom_fields = IssueCustomField.find(:all)
96 @custom_fields = IssueCustomField.find(:all)
97 @issue_category ||= IssueCategory.new
97 @issue_category ||= IssueCategory.new
98 @member ||= @project.members.new
98 @member ||= @project.members.new
99 @roles = Role.find(:all, :order => 'position')
99 @roles = Role.find(:all, :order => 'position')
100 @users = User.find_active(:all) - @project.users
100 @users = User.find_active(:all) - @project.users
101 @custom_values ||= ProjectCustomField.find(:all).collect { |x| @project.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) }
101 @custom_values ||= ProjectCustomField.find(:all).collect { |x| @project.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) }
102 end
102 end
103
103
104 # Edit @project
104 # Edit @project
105 def edit
105 def edit
106 if request.post?
106 if request.post?
107 @project.custom_fields = IssueCustomField.find(params[:custom_field_ids]) if params[:custom_field_ids]
107 @project.custom_fields = IssueCustomField.find(params[:custom_field_ids]) if params[:custom_field_ids]
108 if params[:custom_fields]
108 if params[:custom_fields]
109 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
109 @custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
110 @project.custom_values = @custom_values
110 @project.custom_values = @custom_values
111 end
111 end
112 if params[:repository_enabled]
112 if params[:repository_enabled]
113 case params[:repository_enabled]
113 case params[:repository_enabled]
114 when "0"
114 when "0"
115 @project.repository = nil
115 @project.repository = nil
116 when "1"
116 when "1"
117 @project.repository ||= Repository.new
117 @project.repository ||= Repository.new
118 @project.repository.update_attributes params[:repository]
118 @project.repository.update_attributes params[:repository]
119 end
119 end
120 end
120 end
121 if params[:wiki_enabled]
121 if params[:wiki_enabled]
122 case params[:wiki_enabled]
122 case params[:wiki_enabled]
123 when "0"
123 when "0"
124 @project.wiki.destroy if @project.wiki
124 @project.wiki.destroy if @project.wiki
125 when "1"
125 when "1"
126 @project.wiki ||= Wiki.new
126 @project.wiki ||= Wiki.new
127 @project.wiki.update_attributes params[:wiki]
127 @project.wiki.update_attributes params[:wiki]
128 end
128 end
129 end
129 end
130 @project.attributes = params[:project]
130 @project.attributes = params[:project]
131 if @project.save
131 if @project.save
132 flash[:notice] = l(:notice_successful_update)
132 flash[:notice] = l(:notice_successful_update)
133 redirect_to :action => 'settings', :id => @project
133 redirect_to :action => 'settings', :id => @project
134 else
134 else
135 settings
135 settings
136 render :action => 'settings'
136 render :action => 'settings'
137 end
137 end
138 end
138 end
139 end
139 end
140
140
141 # Delete @project
141 # Delete @project
142 def destroy
142 def destroy
143 if request.post? and params[:confirm]
143 if request.post? and params[:confirm]
144 @project.destroy
144 @project.destroy
145 redirect_to :controller => 'admin', :action => 'projects'
145 redirect_to :controller => 'admin', :action => 'projects'
146 end
146 end
147 end
147 end
148
148
149 # Add a new issue category to @project
149 # Add a new issue category to @project
150 def add_issue_category
150 def add_issue_category
151 if request.post?
151 if request.post?
152 @issue_category = @project.issue_categories.build(params[:issue_category])
152 @issue_category = @project.issue_categories.build(params[:issue_category])
153 if @issue_category.save
153 if @issue_category.save
154 flash[:notice] = l(:notice_successful_create)
154 flash[:notice] = l(:notice_successful_create)
155 redirect_to :action => 'settings', :tab => 'categories', :id => @project
155 redirect_to :action => 'settings', :tab => 'categories', :id => @project
156 else
156 else
157 settings
157 settings
158 render :action => 'settings'
158 render :action => 'settings'
159 end
159 end
160 end
160 end
161 end
161 end
162
162
163 # Add a new version to @project
163 # Add a new version to @project
164 def add_version
164 def add_version
165 @version = @project.versions.build(params[:version])
165 @version = @project.versions.build(params[:version])
166 if request.post? and @version.save
166 if request.post? and @version.save
167 flash[:notice] = l(:notice_successful_create)
167 flash[:notice] = l(:notice_successful_create)
168 redirect_to :action => 'settings', :tab => 'versions', :id => @project
168 redirect_to :action => 'settings', :tab => 'versions', :id => @project
169 end
169 end
170 end
170 end
171
171
172 # Add a new member to @project
172 # Add a new member to @project
173 def add_member
173 def add_member
174 @member = @project.members.build(params[:member])
174 @member = @project.members.build(params[:member])
175 if request.post?
175 if request.post?
176 if @member.save
176 if @member.save
177 flash[:notice] = l(:notice_successful_create)
177 flash[:notice] = l(:notice_successful_create)
178 redirect_to :action => 'settings', :tab => 'members', :id => @project
178 redirect_to :action => 'settings', :tab => 'members', :id => @project
179 else
179 else
180 settings
180 settings
181 render :action => 'settings'
181 render :action => 'settings'
182 end
182 end
183 end
183 end
184 end
184 end
185
185
186 # Show members list of @project
186 # Show members list of @project
187 def list_members
187 def list_members
188 @members = @project.members.find(:all)
188 @members = @project.members.find(:all)
189 end
189 end
190
190
191 # Add a new document to @project
191 # Add a new document to @project
192 def add_document
192 def add_document
193 @categories = Enumeration::get_values('DCAT')
193 @categories = Enumeration::get_values('DCAT')
194 @document = @project.documents.build(params[:document])
194 @document = @project.documents.build(params[:document])
195 if request.post? and @document.save
195 if request.post? and @document.save
196 # Save the attachments
196 # Save the attachments
197 params[:attachments].each { |a|
197 params[:attachments].each { |a|
198 Attachment.create(:container => @document, :file => a, :author => logged_in_user) unless a.size == 0
198 Attachment.create(:container => @document, :file => a, :author => logged_in_user) unless a.size == 0
199 } if params[:attachments] and params[:attachments].is_a? Array
199 } if params[:attachments] and params[:attachments].is_a? Array
200 flash[:notice] = l(:notice_successful_create)
200 flash[:notice] = l(:notice_successful_create)
201 Mailer.deliver_document_add(@document) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
201 Mailer.deliver_document_add(@document) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
202 redirect_to :action => 'list_documents', :id => @project
202 redirect_to :action => 'list_documents', :id => @project
203 end
203 end
204 end
204 end
205
205
206 # Show documents list of @project
206 # Show documents list of @project
207 def list_documents
207 def list_documents
208 @documents = @project.documents.find :all, :include => :category
208 @documents = @project.documents.find :all, :include => :category
209 end
209 end
210
210
211 # Add a new issue to @project
211 # Add a new issue to @project
212 def add_issue
212 def add_issue
213 @tracker = Tracker.find(params[:tracker_id])
213 @tracker = Tracker.find(params[:tracker_id])
214 @priorities = Enumeration::get_values('IPRI')
214 @priorities = Enumeration::get_values('IPRI')
215
215
216 default_status = IssueStatus.default
216 default_status = IssueStatus.default
217 @issue = Issue.new(:project => @project, :tracker => @tracker)
217 @issue = Issue.new(:project => @project, :tracker => @tracker)
218 @issue.status = default_status
218 @issue.status = default_status
219 @allowed_statuses = default_status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
219 @allowed_statuses = default_status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
220 if request.get?
220 if request.get?
221 @issue.start_date = Date.today
221 @issue.start_date = Date.today
222 @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue) }
222 @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue) }
223 else
223 else
224 @issue.attributes = params[:issue]
224 @issue.attributes = params[:issue]
225
225
226 requested_status = IssueStatus.find_by_id(params[:issue][:status_id])
226 requested_status = IssueStatus.find_by_id(params[:issue][:status_id])
227 @issue.status = (@allowed_statuses.include? requested_status) ? requested_status : default_status
227 @issue.status = (@allowed_statuses.include? requested_status) ? requested_status : default_status
228
228
229 @issue.author_id = self.logged_in_user.id if self.logged_in_user
229 @issue.author_id = self.logged_in_user.id if self.logged_in_user
230 # Multiple file upload
230 # Multiple file upload
231 @attachments = []
231 @attachments = []
232 params[:attachments].each { |a|
232 params[:attachments].each { |a|
233 @attachments << Attachment.new(:container => @issue, :file => a, :author => logged_in_user) unless a.size == 0
233 @attachments << Attachment.new(:container => @issue, :file => a, :author => logged_in_user) unless a.size == 0
234 } if params[:attachments] and params[:attachments].is_a? Array
234 } if params[:attachments] and params[:attachments].is_a? Array
235 @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
235 @custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
236 @issue.custom_values = @custom_values
236 @issue.custom_values = @custom_values
237 if @issue.save
237 if @issue.save
238 @attachments.each(&:save)
238 @attachments.each(&:save)
239 flash[:notice] = l(:notice_successful_create)
239 flash[:notice] = l(:notice_successful_create)
240 Mailer.deliver_issue_add(@issue) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
240 Mailer.deliver_issue_add(@issue) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
241 redirect_to :action => 'list_issues', :id => @project
241 redirect_to :action => 'list_issues', :id => @project
242 end
242 end
243 end
243 end
244 end
244 end
245
245
246 # Show filtered/sorted issues list of @project
246 # Show filtered/sorted issues list of @project
247 def list_issues
247 def list_issues
248 sort_init "#{Issue.table_name}.id", "desc"
248 sort_init "#{Issue.table_name}.id", "desc"
249 sort_update
249 sort_update
250
250
251 retrieve_query
251 retrieve_query
252
252
253 @results_per_page_options = [ 15, 25, 50, 100 ]
253 @results_per_page_options = [ 15, 25, 50, 100 ]
254 if params[:per_page] and @results_per_page_options.include? params[:per_page].to_i
254 if params[:per_page] and @results_per_page_options.include? params[:per_page].to_i
255 @results_per_page = params[:per_page].to_i
255 @results_per_page = params[:per_page].to_i
256 session[:results_per_page] = @results_per_page
256 session[:results_per_page] = @results_per_page
257 else
257 else
258 @results_per_page = session[:results_per_page] || 25
258 @results_per_page = session[:results_per_page] || 25
259 end
259 end
260
260
261 if @query.valid?
261 if @query.valid?
262 @issue_count = Issue.count(:include => [:status, :project], :conditions => @query.statement)
262 @issue_count = Issue.count(:include => [:status, :project], :conditions => @query.statement)
263 @issue_pages = Paginator.new self, @issue_count, @results_per_page, params['page']
263 @issue_pages = Paginator.new self, @issue_count, @results_per_page, params['page']
264 @issues = Issue.find :all, :order => sort_clause,
264 @issues = Issue.find :all, :order => sort_clause,
265 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
265 :include => [ :assigned_to, :status, :tracker, :project, :priority ],
266 :conditions => @query.statement,
266 :conditions => @query.statement,
267 :limit => @issue_pages.items_per_page,
267 :limit => @issue_pages.items_per_page,
268 :offset => @issue_pages.current.offset
268 :offset => @issue_pages.current.offset
269 end
269 end
270 @trackers = Tracker.find :all, :order => 'position'
270 @trackers = Tracker.find :all, :order => 'position'
271 render :layout => false if request.xhr?
271 render :layout => false if request.xhr?
272 end
272 end
273
273
274 # Export filtered/sorted issues list to CSV
274 # Export filtered/sorted issues list to CSV
275 def export_issues_csv
275 def export_issues_csv
276 sort_init "#{Issue.table_name}.id", "desc"
276 sort_init "#{Issue.table_name}.id", "desc"
277 sort_update
277 sort_update
278
278
279 retrieve_query
279 retrieve_query
280 render :action => 'list_issues' and return unless @query.valid?
280 render :action => 'list_issues' and return unless @query.valid?
281
281
282 @issues = Issue.find :all, :order => sort_clause,
282 @issues = Issue.find :all, :order => sort_clause,
283 :include => [ :assigned_to, :author, :status, :tracker, :priority, {:custom_values => :custom_field} ],
283 :include => [ :assigned_to, :author, :status, :tracker, :priority, {:custom_values => :custom_field} ],
284 :conditions => @query.statement,
284 :conditions => @query.statement,
285 :limit => Setting.issues_export_limit
285 :limit => Setting.issues_export_limit
286
286
287 ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
287 ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
288 export = StringIO.new
288 export = StringIO.new
289 CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
289 CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
290 # csv header fields
290 # csv header fields
291 headers = [ "#", l(:field_status),
291 headers = [ "#", l(:field_status),
292 l(:field_tracker),
292 l(:field_tracker),
293 l(:field_priority),
293 l(:field_priority),
294 l(:field_subject),
294 l(:field_subject),
295 l(:field_assigned_to),
295 l(:field_assigned_to),
296 l(:field_author),
296 l(:field_author),
297 l(:field_start_date),
297 l(:field_start_date),
298 l(:field_due_date),
298 l(:field_due_date),
299 l(:field_done_ratio),
299 l(:field_done_ratio),
300 l(:field_created_on),
300 l(:field_created_on),
301 l(:field_updated_on)
301 l(:field_updated_on)
302 ]
302 ]
303 for custom_field in @project.all_custom_fields
303 for custom_field in @project.all_custom_fields
304 headers << custom_field.name
304 headers << custom_field.name
305 end
305 end
306 csv << headers.collect {|c| ic.iconv(c) }
306 csv << headers.collect {|c| ic.iconv(c) }
307 # csv lines
307 # csv lines
308 @issues.each do |issue|
308 @issues.each do |issue|
309 fields = [issue.id, issue.status.name,
309 fields = [issue.id, issue.status.name,
310 issue.tracker.name,
310 issue.tracker.name,
311 issue.priority.name,
311 issue.priority.name,
312 issue.subject,
312 issue.subject,
313 (issue.assigned_to ? issue.assigned_to.name : ""),
313 (issue.assigned_to ? issue.assigned_to.name : ""),
314 issue.author.name,
314 issue.author.name,
315 issue.start_date ? l_date(issue.start_date) : nil,
315 issue.start_date ? l_date(issue.start_date) : nil,
316 issue.due_date ? l_date(issue.due_date) : nil,
316 issue.due_date ? l_date(issue.due_date) : nil,
317 issue.done_ratio,
317 issue.done_ratio,
318 l_datetime(issue.created_on),
318 l_datetime(issue.created_on),
319 l_datetime(issue.updated_on)
319 l_datetime(issue.updated_on)
320 ]
320 ]
321 for custom_field in @project.all_custom_fields
321 for custom_field in @project.all_custom_fields
322 fields << (show_value issue.custom_value_for(custom_field))
322 fields << (show_value issue.custom_value_for(custom_field))
323 end
323 end
324 csv << fields.collect {|c| ic.iconv(c.to_s) }
324 csv << fields.collect {|c| ic.iconv(c.to_s) }
325 end
325 end
326 end
326 end
327 export.rewind
327 export.rewind
328 send_data(export.read, :type => 'text/csv; header=present', :filename => 'export.csv')
328 send_data(export.read, :type => 'text/csv; header=present', :filename => 'export.csv')
329 end
329 end
330
330
331 # Export filtered/sorted issues to PDF
331 # Export filtered/sorted issues to PDF
332 def export_issues_pdf
332 def export_issues_pdf
333 sort_init "#{Issue.table_name}.id", "desc"
333 sort_init "#{Issue.table_name}.id", "desc"
334 sort_update
334 sort_update
335
335
336 retrieve_query
336 retrieve_query
337 render :action => 'list_issues' and return unless @query.valid?
337 render :action => 'list_issues' and return unless @query.valid?
338
338
339 @issues = Issue.find :all, :order => sort_clause,
339 @issues = Issue.find :all, :order => sort_clause,
340 :include => [ :author, :status, :tracker, :priority ],
340 :include => [ :author, :status, :tracker, :priority ],
341 :conditions => @query.statement,
341 :conditions => @query.statement,
342 :limit => Setting.issues_export_limit
342 :limit => Setting.issues_export_limit
343
343
344 @options_for_rfpdf ||= {}
344 @options_for_rfpdf ||= {}
345 @options_for_rfpdf[:file_name] = "export.pdf"
345 @options_for_rfpdf[:file_name] = "export.pdf"
346 render :layout => false
346 render :layout => false
347 end
347 end
348
348
349 def move_issues
349 def move_issues
350 @issues = @project.issues.find(params[:issue_ids]) if params[:issue_ids]
350 @issues = @project.issues.find(params[:issue_ids]) if params[:issue_ids]
351 redirect_to :action => 'list_issues', :id => @project and return unless @issues
351 redirect_to :action => 'list_issues', :id => @project and return unless @issues
352 @projects = []
352 @projects = []
353 # find projects to which the user is allowed to move the issue
353 # find projects to which the user is allowed to move the issue
354 @logged_in_user.memberships.each {|m| @projects << m.project if Permission.allowed_to_role("projects/move_issues", m.role)}
354 @logged_in_user.memberships.each {|m| @projects << m.project if Permission.allowed_to_role("projects/move_issues", m.role)}
355 # issue can be moved to any tracker
355 # issue can be moved to any tracker
356 @trackers = Tracker.find(:all)
356 @trackers = Tracker.find(:all)
357 if request.post? and params[:new_project_id] and params[:new_tracker_id]
357 if request.post? and params[:new_project_id] and params[:new_tracker_id]
358 new_project = Project.find(params[:new_project_id])
358 new_project = Project.find(params[:new_project_id])
359 new_tracker = Tracker.find(params[:new_tracker_id])
359 new_tracker = Tracker.find(params[:new_tracker_id])
360 @issues.each { |i|
360 @issues.each { |i|
361 # project dependent properties
361 # project dependent properties
362 unless i.project_id == new_project.id
362 unless i.project_id == new_project.id
363 i.category = nil
363 i.category = nil
364 i.fixed_version = nil
364 i.fixed_version = nil
365 end
365 end
366 # move the issue
366 # move the issue
367 i.project = new_project
367 i.project = new_project
368 i.tracker = new_tracker
368 i.tracker = new_tracker
369 i.save
369 i.save
370 }
370 }
371 flash[:notice] = l(:notice_successful_update)
371 flash[:notice] = l(:notice_successful_update)
372 redirect_to :action => 'list_issues', :id => @project
372 redirect_to :action => 'list_issues', :id => @project
373 end
373 end
374 end
374 end
375
375
376 def add_query
376 def add_query
377 @query = Query.new(params[:query])
377 @query = Query.new(params[:query])
378 @query.project = @project
378 @query.project = @project
379 @query.user = logged_in_user
379 @query.user = logged_in_user
380
380
381 params[:fields].each do |field|
381 params[:fields].each do |field|
382 @query.add_filter(field, params[:operators][field], params[:values][field])
382 @query.add_filter(field, params[:operators][field], params[:values][field])
383 end if params[:fields]
383 end if params[:fields]
384
384
385 if request.post? and @query.save
385 if request.post? and @query.save
386 flash[:notice] = l(:notice_successful_create)
386 flash[:notice] = l(:notice_successful_create)
387 redirect_to :controller => 'reports', :action => 'issue_report', :id => @project
387 redirect_to :controller => 'reports', :action => 'issue_report', :id => @project
388 end
388 end
389 render :layout => false if request.xhr?
389 render :layout => false if request.xhr?
390 end
390 end
391
391
392 # Add a news to @project
392 # Add a news to @project
393 def add_news
393 def add_news
394 @news = News.new(:project => @project)
394 @news = News.new(:project => @project)
395 if request.post?
395 if request.post?
396 @news.attributes = params[:news]
396 @news.attributes = params[:news]
397 @news.author_id = self.logged_in_user.id if self.logged_in_user
397 @news.author_id = self.logged_in_user.id if self.logged_in_user
398 if @news.save
398 if @news.save
399 flash[:notice] = l(:notice_successful_create)
399 flash[:notice] = l(:notice_successful_create)
400 redirect_to :action => 'list_news', :id => @project
400 redirect_to :action => 'list_news', :id => @project
401 end
401 end
402 end
402 end
403 end
403 end
404
404
405 # Show news list of @project
405 # Show news list of @project
406 def list_news
406 def list_news
407 @news_pages, @news = paginate :news, :per_page => 10, :conditions => ["project_id=?", @project.id], :include => :author, :order => "#{News.table_name}.created_on DESC"
407 @news_pages, @news = paginate :news, :per_page => 10, :conditions => ["project_id=?", @project.id], :include => :author, :order => "#{News.table_name}.created_on DESC"
408 render :action => "list_news", :layout => false if request.xhr?
408 render :action => "list_news", :layout => false if request.xhr?
409 end
409 end
410
410
411 def add_file
411 def add_file
412 if request.post?
412 if request.post?
413 @version = @project.versions.find_by_id(params[:version_id])
413 @version = @project.versions.find_by_id(params[:version_id])
414 # Save the attachments
414 # Save the attachments
415 @attachments = []
415 @attachments = []
416 params[:attachments].each { |file|
416 params[:attachments].each { |file|
417 next unless file.size > 0
417 next unless file.size > 0
418 a = Attachment.create(:container => @version, :file => file, :author => logged_in_user)
418 a = Attachment.create(:container => @version, :file => file, :author => logged_in_user)
419 @attachments << a unless a.new_record?
419 @attachments << a unless a.new_record?
420 } if params[:attachments] and params[:attachments].is_a? Array
420 } if params[:attachments] and params[:attachments].is_a? Array
421 Mailer.deliver_attachments_add(@attachments) if !@attachments.empty? and Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
421 Mailer.deliver_attachments_add(@attachments) if !@attachments.empty? and Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
422 redirect_to :controller => 'projects', :action => 'list_files', :id => @project
422 redirect_to :controller => 'projects', :action => 'list_files', :id => @project
423 end
423 end
424 @versions = @project.versions
424 @versions = @project.versions
425 end
425 end
426
426
427 def list_files
427 def list_files
428 @versions = @project.versions
428 @versions = @project.versions
429 end
429 end
430
430
431 # Show changelog for @project
431 # Show changelog for @project
432 def changelog
432 def changelog
433 @trackers = Tracker.find(:all, :conditions => ["is_in_chlog=?", true], :order => 'position')
433 @trackers = Tracker.find(:all, :conditions => ["is_in_chlog=?", true], :order => 'position')
434 retrieve_selected_tracker_ids(@trackers)
434 retrieve_selected_tracker_ids(@trackers)
435
435
436 @fixed_issues = @project.issues.find(:all,
436 @fixed_issues = @project.issues.find(:all,
437 :include => [ :fixed_version, :status, :tracker ],
437 :include => [ :fixed_version, :status, :tracker ],
438 :conditions => [ "#{IssueStatus.table_name}.is_closed=? and #{Issue.table_name}.tracker_id in (#{@selected_tracker_ids.join(',')}) and #{Issue.table_name}.fixed_version_id is not null", true],
438 :conditions => [ "#{IssueStatus.table_name}.is_closed=? and #{Issue.table_name}.tracker_id in (#{@selected_tracker_ids.join(',')}) and #{Issue.table_name}.fixed_version_id is not null", true],
439 :order => "#{Version.table_name}.effective_date DESC, #{Issue.table_name}.id DESC"
439 :order => "#{Version.table_name}.effective_date DESC, #{Issue.table_name}.id DESC"
440 ) unless @selected_tracker_ids.empty?
440 ) unless @selected_tracker_ids.empty?
441 @fixed_issues ||= []
441 @fixed_issues ||= []
442 end
442 end
443
443
444 def roadmap
444 def roadmap
445 @trackers = Tracker.find(:all, :conditions => ["is_in_roadmap=?", true], :order => 'position')
445 @trackers = Tracker.find(:all, :conditions => ["is_in_roadmap=?", true], :order => 'position')
446 retrieve_selected_tracker_ids(@trackers)
446 retrieve_selected_tracker_ids(@trackers)
447
447
448 @versions = @project.versions.find(:all,
448 @versions = @project.versions.find(:all,
449 :conditions => [ "#{Version.table_name}.effective_date>?", Date.today],
449 :conditions => [ "#{Version.table_name}.effective_date>?", Date.today],
450 :order => "#{Version.table_name}.effective_date ASC"
450 :order => "#{Version.table_name}.effective_date ASC"
451 )
451 )
452 end
452 end
453
453
454 def activity
454 def activity
455 if params[:year] and params[:year].to_i > 1900
455 if params[:year] and params[:year].to_i > 1900
456 @year = params[:year].to_i
456 @year = params[:year].to_i
457 if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13
457 if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13
458 @month = params[:month].to_i
458 @month = params[:month].to_i
459 end
459 end
460 end
460 end
461 @year ||= Date.today.year
461 @year ||= Date.today.year
462 @month ||= Date.today.month
462 @month ||= Date.today.month
463
463
464 @date_from = Date.civil(@year, @month, 1)
464 @date_from = Date.civil(@year, @month, 1)
465 @date_to = (@date_from >> 1)-1
465 @date_to = (@date_from >> 1)-1
466
466
467 @events_by_day = {}
467 @events_by_day = {}
468
468
469 unless params[:show_issues] == "0"
469 unless params[:show_issues] == "0"
470 @project.issues.find(:all, :include => [:author, :status], :conditions => ["#{Issue.table_name}.created_on>=? and #{Issue.table_name}.created_on<=?", @date_from, @date_to] ).each { |i|
470 @project.issues.find(:all, :include => [:author, :status], :conditions => ["#{Issue.table_name}.created_on>=? and #{Issue.table_name}.created_on<=?", @date_from, @date_to] ).each { |i|
471 @events_by_day[i.created_on.to_date] ||= []
471 @events_by_day[i.created_on.to_date] ||= []
472 @events_by_day[i.created_on.to_date] << i
472 @events_by_day[i.created_on.to_date] << i
473 }
473 }
474 @show_issues = 1
474 @show_issues = 1
475 end
475 end
476
476
477 unless params[:show_news] == "0"
477 unless params[:show_news] == "0"
478 @project.news.find(:all, :conditions => ["#{News.table_name}.created_on>=? and #{News.table_name}.created_on<=?", @date_from, @date_to], :include => :author ).each { |i|
478 @project.news.find(:all, :conditions => ["#{News.table_name}.created_on>=? and #{News.table_name}.created_on<=?", @date_from, @date_to], :include => :author ).each { |i|
479 @events_by_day[i.created_on.to_date] ||= []
479 @events_by_day[i.created_on.to_date] ||= []
480 @events_by_day[i.created_on.to_date] << i
480 @events_by_day[i.created_on.to_date] << i
481 }
481 }
482 @show_news = 1
482 @show_news = 1
483 end
483 end
484
484
485 unless params[:show_files] == "0"
485 unless params[:show_files] == "0"
486 Attachment.find(:all, :select => "#{Attachment.table_name}.*", :joins => "LEFT JOIN #{Version.table_name} ON #{Version.table_name}.id = #{Attachment.table_name}.container_id", :conditions => ["#{Attachment.table_name}.container_type='Version' and #{Version.table_name}.project_id=? and #{Attachment.table_name}.created_on>=? and #{Attachment.table_name}.created_on<=?", @project.id, @date_from, @date_to], :include => :author ).each { |i|
486 Attachment.find(:all, :select => "#{Attachment.table_name}.*", :joins => "LEFT JOIN #{Version.table_name} ON #{Version.table_name}.id = #{Attachment.table_name}.container_id", :conditions => ["#{Attachment.table_name}.container_type='Version' and #{Version.table_name}.project_id=? and #{Attachment.table_name}.created_on>=? and #{Attachment.table_name}.created_on<=?", @project.id, @date_from, @date_to], :include => :author ).each { |i|
487 @events_by_day[i.created_on.to_date] ||= []
487 @events_by_day[i.created_on.to_date] ||= []
488 @events_by_day[i.created_on.to_date] << i
488 @events_by_day[i.created_on.to_date] << i
489 }
489 }
490 @show_files = 1
490 @show_files = 1
491 end
491 end
492
492
493 unless params[:show_documents] == "0"
493 unless params[:show_documents] == "0"
494 @project.documents.find(:all, :conditions => ["#{Document.table_name}.created_on>=? and #{Document.table_name}.created_on<=?", @date_from, @date_to] ).each { |i|
494 @project.documents.find(:all, :conditions => ["#{Document.table_name}.created_on>=? and #{Document.table_name}.created_on<=?", @date_from, @date_to] ).each { |i|
495 @events_by_day[i.created_on.to_date] ||= []
495 @events_by_day[i.created_on.to_date] ||= []
496 @events_by_day[i.created_on.to_date] << i
496 @events_by_day[i.created_on.to_date] << i
497 }
497 }
498 Attachment.find(:all, :select => "attachments.*", :joins => "LEFT JOIN #{Document.table_name} ON #{Document.table_name}.id = #{Attachment.table_name}.container_id", :conditions => ["#{Attachment.table_name}.container_type='Document' and #{Document.table_name}.project_id=? and #{Attachment.table_name}.created_on>=? and #{Attachment.table_name}.created_on<=?", @project.id, @date_from, @date_to], :include => :author ).each { |i|
498 Attachment.find(:all, :select => "attachments.*", :joins => "LEFT JOIN #{Document.table_name} ON #{Document.table_name}.id = #{Attachment.table_name}.container_id", :conditions => ["#{Attachment.table_name}.container_type='Document' and #{Document.table_name}.project_id=? and #{Attachment.table_name}.created_on>=? and #{Attachment.table_name}.created_on<=?", @project.id, @date_from, @date_to], :include => :author ).each { |i|
499 @events_by_day[i.created_on.to_date] ||= []
499 @events_by_day[i.created_on.to_date] ||= []
500 @events_by_day[i.created_on.to_date] << i
500 @events_by_day[i.created_on.to_date] << i
501 }
501 }
502 @show_documents = 1
502 @show_documents = 1
503 end
503 end
504
504
505 unless params[:show_wiki_edits] == "0"
505 unless params[:show_wiki_edits] == "0"
506 select = "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comment, " +
506 select = "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comment, " +
507 "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title"
507 "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title"
508 joins = "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
508 joins = "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
509 "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id "
509 "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id "
510 conditions = ["#{Wiki.table_name}.project_id = ? AND #{WikiContent.versioned_table_name}.updated_on BETWEEN ? AND ?",
510 conditions = ["#{Wiki.table_name}.project_id = ? AND #{WikiContent.versioned_table_name}.updated_on BETWEEN ? AND ?",
511 @project.id, @date_from, @date_to]
511 @project.id, @date_from, @date_to]
512
512
513 WikiContent.versioned_class.find(:all, :select => select, :joins => joins, :conditions => conditions).each { |i|
513 WikiContent.versioned_class.find(:all, :select => select, :joins => joins, :conditions => conditions).each { |i|
514 # We provide this alias so all events can be treated in the same manner
514 # We provide this alias so all events can be treated in the same manner
515 def i.created_on
515 def i.created_on
516 self.updated_on
516 self.updated_on
517 end
517 end
518
518
519 @events_by_day[i.created_on.to_date] ||= []
519 @events_by_day[i.created_on.to_date] ||= []
520 @events_by_day[i.created_on.to_date] << i
520 @events_by_day[i.created_on.to_date] << i
521 }
521 }
522 @show_wiki_edits = 1
522 @show_wiki_edits = 1
523 end
523 end
524
524
525 unless @project.repository.nil? || params[:show_changesets] == "0"
525 unless @project.repository.nil? || params[:show_changesets] == "0"
526 @project.repository.changesets.find(:all, :conditions => ["#{Changeset.table_name}.committed_on BETWEEN ? AND ?", @date_from, @date_to]).each { |i|
526 @project.repository.changesets.find(:all, :conditions => ["#{Changeset.table_name}.committed_on BETWEEN ? AND ?", @date_from, @date_to]).each { |i|
527 def i.created_on
527 def i.created_on
528 self.committed_on
528 self.committed_on
529 end
529 end
530 @events_by_day[i.created_on.to_date] ||= []
530 @events_by_day[i.created_on.to_date] ||= []
531 @events_by_day[i.created_on.to_date] << i
531 @events_by_day[i.created_on.to_date] << i
532 }
532 }
533 @show_changesets = 1
533 @show_changesets = 1
534 end
534 end
535
535
536 render :layout => false if request.xhr?
536 render :layout => false if request.xhr?
537 end
537 end
538
538
539 def calendar
539 def calendar
540 @trackers = Tracker.find(:all, :order => 'position')
540 @trackers = Tracker.find(:all, :order => 'position')
541 retrieve_selected_tracker_ids(@trackers)
541 retrieve_selected_tracker_ids(@trackers)
542
542
543 if params[:year] and params[:year].to_i > 1900
543 if params[:year] and params[:year].to_i > 1900
544 @year = params[:year].to_i
544 @year = params[:year].to_i
545 if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13
545 if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13
546 @month = params[:month].to_i
546 @month = params[:month].to_i
547 end
547 end
548 end
548 end
549 @year ||= Date.today.year
549 @year ||= Date.today.year
550 @month ||= Date.today.month
550 @month ||= Date.today.month
551
551
552 @date_from = Date.civil(@year, @month, 1)
552 @date_from = Date.civil(@year, @month, 1)
553 @date_to = (@date_from >> 1)-1
553 @date_to = (@date_from >> 1)-1
554 # start on monday
554 # start on monday
555 @date_from = @date_from - (@date_from.cwday-1)
555 @date_from = @date_from - (@date_from.cwday-1)
556 # finish on sunday
556 # finish on sunday
557 @date_to = @date_to + (7-@date_to.cwday)
557 @date_to = @date_to + (7-@date_to.cwday)
558
558
559 @project.issues_with_subprojects(params[:with_subprojects]) do
559 @project.issues_with_subprojects(params[:with_subprojects]) do
560 @issues = Issue.find(:all,
560 @issues = Issue.find(:all,
561 :include => [:tracker, :status, :assigned_to, :priority],
561 :include => [:tracker, :status, :assigned_to, :priority],
562 :conditions => ["((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?)) and #{Issue.table_name}.tracker_id in (#{@selected_tracker_ids.join(',')})", @date_from, @date_to, @date_from, @date_to]
562 :conditions => ["((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?)) and #{Issue.table_name}.tracker_id in (#{@selected_tracker_ids.join(',')})", @date_from, @date_to, @date_from, @date_to]
563 ) unless @selected_tracker_ids.empty?
563 ) unless @selected_tracker_ids.empty?
564 end
564 end
565 @issues ||=[]
565 @issues ||=[]
566
566
567 @ending_issues_by_days = @issues.group_by {|issue| issue.due_date}
567 @ending_issues_by_days = @issues.group_by {|issue| issue.due_date}
568 @starting_issues_by_days = @issues.group_by {|issue| issue.start_date}
568 @starting_issues_by_days = @issues.group_by {|issue| issue.start_date}
569
569
570 render :layout => false if request.xhr?
570 render :layout => false if request.xhr?
571 end
571 end
572
572
573 def gantt
573 def gantt
574 @trackers = Tracker.find(:all, :order => 'position')
574 @trackers = Tracker.find(:all, :order => 'position')
575 retrieve_selected_tracker_ids(@trackers)
575 retrieve_selected_tracker_ids(@trackers)
576
576
577 if params[:year] and params[:year].to_i >0
577 if params[:year] and params[:year].to_i >0
578 @year_from = params[:year].to_i
578 @year_from = params[:year].to_i
579 if params[:month] and params[:month].to_i >=1 and params[:month].to_i <= 12
579 if params[:month] and params[:month].to_i >=1 and params[:month].to_i <= 12
580 @month_from = params[:month].to_i
580 @month_from = params[:month].to_i
581 else
581 else
582 @month_from = 1
582 @month_from = 1
583 end
583 end
584 else
584 else
585 @month_from ||= (Date.today << 1).month
585 @month_from ||= (Date.today << 1).month
586 @year_from ||= (Date.today << 1).year
586 @year_from ||= (Date.today << 1).year
587 end
587 end
588
588
589 @zoom = (params[:zoom].to_i > 0 and params[:zoom].to_i < 5) ? params[:zoom].to_i : 2
589 @zoom = (params[:zoom].to_i > 0 and params[:zoom].to_i < 5) ? params[:zoom].to_i : 2
590 @months = (params[:months].to_i > 0 and params[:months].to_i < 25) ? params[:months].to_i : 6
590 @months = (params[:months].to_i > 0 and params[:months].to_i < 25) ? params[:months].to_i : 6
591
591
592 @date_from = Date.civil(@year_from, @month_from, 1)
592 @date_from = Date.civil(@year_from, @month_from, 1)
593 @date_to = (@date_from >> @months) - 1
593 @date_to = (@date_from >> @months) - 1
594
594
595 @events = []
595 @project.issues_with_subprojects(params[:with_subprojects]) do
596 @project.issues_with_subprojects(params[:with_subprojects]) do
596 @issues = Issue.find(:all,
597 @events += Issue.find(:all,
597 :order => "start_date, due_date",
598 :order => "start_date, due_date",
598 :include => [:tracker, :status, :assigned_to, :priority],
599 :include => [:tracker, :status, :assigned_to, :priority],
599 :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]
600 :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]
600 ) unless @selected_tracker_ids.empty?
601 ) unless @selected_tracker_ids.empty?
601 end
602 end
602 @issues ||=[]
603 @events += @project.versions.find(:all, :conditions => ["effective_date BETWEEN ? AND ?", @date_from, @date_to])
604 @events.sort! {|x,y| x.start_date <=> y.start_date }
603
605
604 if params[:output]=='pdf'
606 if params[:output]=='pdf'
605 @options_for_rfpdf ||= {}
607 @options_for_rfpdf ||= {}
606 @options_for_rfpdf[:file_name] = "gantt.pdf"
608 @options_for_rfpdf[:file_name] = "gantt.pdf"
607 render :template => "projects/gantt.rfpdf", :layout => false
609 render :template => "projects/gantt.rfpdf", :layout => false
608 else
610 else
609 render :template => "projects/gantt.rhtml"
611 render :template => "projects/gantt.rhtml"
610 end
612 end
611 end
613 end
612
614
613 def search
615 def search
614 @question = params[:q] || ""
616 @question = params[:q] || ""
615 @question.strip!
617 @question.strip!
616 @all_words = params[:all_words] || (params[:submit] ? false : true)
618 @all_words = params[:all_words] || (params[:submit] ? false : true)
617 @scope = params[:scope] || (params[:submit] ? [] : %w(issues changesets news documents wiki) )
619 @scope = params[:scope] || (params[:submit] ? [] : %w(issues changesets news documents wiki) )
618 # tokens must be at least 3 character long
620 # tokens must be at least 3 character long
619 @tokens = @question.split.uniq.select {|w| w.length > 2 }
621 @tokens = @question.split.uniq.select {|w| w.length > 2 }
620 if !@tokens.empty?
622 if !@tokens.empty?
621 # no more than 5 tokens to search for
623 # no more than 5 tokens to search for
622 @tokens.slice! 5..-1 if @tokens.size > 5
624 @tokens.slice! 5..-1 if @tokens.size > 5
623 # strings used in sql like statement
625 # strings used in sql like statement
624 like_tokens = @tokens.collect {|w| "%#{w}%"}
626 like_tokens = @tokens.collect {|w| "%#{w}%"}
625 operator = @all_words ? " AND " : " OR "
627 operator = @all_words ? " AND " : " OR "
626 limit = 10
628 limit = 10
627 @results = []
629 @results = []
628 @results += @project.issues.find(:all, :limit => limit, :include => :author, :conditions => [ (["(LOWER(subject) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'issues'
630 @results += @project.issues.find(:all, :limit => limit, :include => :author, :conditions => [ (["(LOWER(subject) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'issues'
629 @results += @project.news.find(:all, :limit => limit, :conditions => [ (["(LOWER(title) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort], :include => :author ) if @scope.include? 'news'
631 @results += @project.news.find(:all, :limit => limit, :conditions => [ (["(LOWER(title) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort], :include => :author ) if @scope.include? 'news'
630 @results += @project.documents.find(:all, :limit => limit, :conditions => [ (["(LOWER(title) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'documents'
632 @results += @project.documents.find(:all, :limit => limit, :conditions => [ (["(LOWER(title) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'documents'
631 @results += @project.wiki.pages.find(:all, :limit => limit, :include => :content, :conditions => [ (["(LOWER(title) like ? OR LOWER(text) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @project.wiki && @scope.include?('wiki')
633 @results += @project.wiki.pages.find(:all, :limit => limit, :include => :content, :conditions => [ (["(LOWER(title) like ? OR LOWER(text) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @project.wiki && @scope.include?('wiki')
632 @results += @project.repository.changesets.find(:all, :limit => limit, :conditions => [ (["(LOWER(comment) like ?)"] * like_tokens.size).join(operator), * (like_tokens).sort] ) if @project.repository && @scope.include?('changesets')
634 @results += @project.repository.changesets.find(:all, :limit => limit, :conditions => [ (["(LOWER(comment) like ?)"] * like_tokens.size).join(operator), * (like_tokens).sort] ) if @project.repository && @scope.include?('changesets')
633 @question = @tokens.join(" ")
635 @question = @tokens.join(" ")
634 else
636 else
635 @question = ""
637 @question = ""
636 end
638 end
637 end
639 end
638
640
639 def feeds
641 def feeds
640 @queries = @project.queries.find :all, :conditions => ["is_public=? or user_id=?", true, (logged_in_user ? logged_in_user.id : 0)]
642 @queries = @project.queries.find :all, :conditions => ["is_public=? or user_id=?", true, (logged_in_user ? logged_in_user.id : 0)]
641 @key = logged_in_user.get_or_create_rss_key.value if logged_in_user
643 @key = logged_in_user.get_or_create_rss_key.value if logged_in_user
642 end
644 end
643
645
644 private
646 private
645 # Find project of id params[:id]
647 # Find project of id params[:id]
646 # if not found, redirect to project list
648 # if not found, redirect to project list
647 # Used as a before_filter
649 # Used as a before_filter
648 def find_project
650 def find_project
649 @project = Project.find(params[:id])
651 @project = Project.find(params[:id])
650 @html_title = @project.name
652 @html_title = @project.name
651 rescue ActiveRecord::RecordNotFound
653 rescue ActiveRecord::RecordNotFound
652 render_404
654 render_404
653 end
655 end
654
656
655 def retrieve_selected_tracker_ids(selectable_trackers)
657 def retrieve_selected_tracker_ids(selectable_trackers)
656 if ids = params[:tracker_ids]
658 if ids = params[:tracker_ids]
657 @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s }
659 @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s }
658 else
660 else
659 @selected_tracker_ids = selectable_trackers.collect {|t| t.id.to_s }
661 @selected_tracker_ids = selectable_trackers.collect {|t| t.id.to_s }
660 end
662 end
661 end
663 end
662
664
663 # Retrieve query from session or build a new query
665 # Retrieve query from session or build a new query
664 def retrieve_query
666 def retrieve_query
665 if params[:query_id]
667 if params[:query_id]
666 @query = @project.queries.find(params[:query_id])
668 @query = @project.queries.find(params[:query_id])
667 session[:query] = @query
669 session[:query] = @query
668 else
670 else
669 if params[:set_filter] or !session[:query] or session[:query].project_id != @project.id
671 if params[:set_filter] or !session[:query] or session[:query].project_id != @project.id
670 # Give it a name, required to be valid
672 # Give it a name, required to be valid
671 @query = Query.new(:name => "_")
673 @query = Query.new(:name => "_")
672 @query.project = @project
674 @query.project = @project
673 if params[:fields] and params[:fields].is_a? Array
675 if params[:fields] and params[:fields].is_a? Array
674 params[:fields].each do |field|
676 params[:fields].each do |field|
675 @query.add_filter(field, params[:operators][field], params[:values][field])
677 @query.add_filter(field, params[:operators][field], params[:values][field])
676 end
678 end
677 else
679 else
678 @query.available_filters.keys.each do |field|
680 @query.available_filters.keys.each do |field|
679 @query.add_short_filter(field, params[field]) if params[field]
681 @query.add_short_filter(field, params[field]) if params[field]
680 end
682 end
681 end
683 end
682 session[:query] = @query
684 session[:query] = @query
683 else
685 else
684 @query = session[:query]
686 @query = session[:query]
685 end
687 end
686 end
688 end
687 end
689 end
688 end
690 end
@@ -1,32 +1,40
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Version < ActiveRecord::Base
18 class Version < ActiveRecord::Base
19 before_destroy :check_integrity
19 before_destroy :check_integrity
20 belongs_to :project
20 belongs_to :project
21 has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id'
21 has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id'
22 has_many :attachments, :as => :container, :dependent => :destroy
22 has_many :attachments, :as => :container, :dependent => :destroy
23
23
24 validates_presence_of :name
24 validates_presence_of :name
25 validates_uniqueness_of :name, :scope => [:project_id]
25 validates_uniqueness_of :name, :scope => [:project_id]
26 validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :activerecord_error_not_a_date
26 validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :activerecord_error_not_a_date
27
27
28 def start_date
29 effective_date
30 end
31
32 def due_date
33 effective_date
34 end
35
28 private
36 private
29 def check_integrity
37 def check_integrity
30 raise "Can't delete version" if self.fixed_issues.find(:first)
38 raise "Can't delete version" if self.fixed_issues.find(:first)
31 end
39 end
32 end
40 end
@@ -1,169 +1,188
1 <%
1 <%
2 pdf=IfpdfHelper::IFPDF.new(current_language)
2 pdf=IfpdfHelper::IFPDF.new(current_language)
3 pdf.SetTitle("#{@project.name} - #{l(:label_gantt)}")
3 pdf.SetTitle("#{@project.name} - #{l(:label_gantt)}")
4 pdf.AliasNbPages
4 pdf.AliasNbPages
5 pdf.footer_date = format_date(Date.today)
5 pdf.footer_date = format_date(Date.today)
6 pdf.AddPage("L")
6 pdf.AddPage("L")
7 pdf.SetFontStyle('B',12)
7 pdf.SetFontStyle('B',12)
8 pdf.SetX(15)
8 pdf.SetX(15)
9 pdf.Cell(70, 20, @project.name)
9 pdf.Cell(70, 20, @project.name)
10 pdf.Ln
10 pdf.Ln
11 pdf.SetFontStyle('B',9)
11 pdf.SetFontStyle('B',9)
12
12
13 subject_width = 70
13 subject_width = 70
14 header_heigth = 5
14 header_heigth = 5
15
15
16 headers_heigth = header_heigth
16 headers_heigth = header_heigth
17 show_weeks = false
17 show_weeks = false
18 show_days = false
18 show_days = false
19
19
20 if @months < 7
20 if @months < 7
21 show_weeks = true
21 show_weeks = true
22 headers_heigth = 2*header_heigth
22 headers_heigth = 2*header_heigth
23 if @months < 3
23 if @months < 3
24 show_days = true
24 show_days = true
25 headers_heigth = 3*header_heigth
25 headers_heigth = 3*header_heigth
26 end
26 end
27 end
27 end
28
28
29 g_width = 210
29 g_width = 210
30 zoom = (g_width) / (@date_to - @date_from + 1)
30 zoom = (g_width) / (@date_to - @date_from + 1)
31 g_height = 120
31 g_height = 120
32 t_height = g_height + headers_heigth
32 t_height = g_height + headers_heigth
33
33
34 y_start = pdf.GetY
34 y_start = pdf.GetY
35
35
36
36
37 #
37 #
38 # Months headers
38 # Months headers
39 #
39 #
40 month_f = @date_from
40 month_f = @date_from
41 left = subject_width
41 left = subject_width
42 height = header_heigth
42 height = header_heigth
43 @months.times do
43 @months.times do
44 width = ((month_f >> 1) - month_f) * zoom
44 width = ((month_f >> 1) - month_f) * zoom
45 pdf.SetY(y_start)
45 pdf.SetY(y_start)
46 pdf.SetX(left)
46 pdf.SetX(left)
47 pdf.Cell(width, height, "#{month_f.year}-#{month_f.month}", "LTR", 0, "C")
47 pdf.Cell(width, height, "#{month_f.year}-#{month_f.month}", "LTR", 0, "C")
48 left = left + width
48 left = left + width
49 month_f = month_f >> 1
49 month_f = month_f >> 1
50 end
50 end
51
51
52 #
52 #
53 # Weeks headers
53 # Weeks headers
54 #
54 #
55 if show_weeks
55 if show_weeks
56 left = subject_width
56 left = subject_width
57 height = header_heigth
57 height = header_heigth
58 if @date_from.cwday == 1
58 if @date_from.cwday == 1
59 # @date_from is monday
59 # @date_from is monday
60 week_f = @date_from
60 week_f = @date_from
61 else
61 else
62 # find next monday after @date_from
62 # find next monday after @date_from
63 week_f = @date_from + (7 - @date_from.cwday + 1)
63 week_f = @date_from + (7 - @date_from.cwday + 1)
64 width = (7 - @date_from.cwday + 1) * zoom-1
64 width = (7 - @date_from.cwday + 1) * zoom-1
65 pdf.SetY(y_start + header_heigth)
65 pdf.SetY(y_start + header_heigth)
66 pdf.SetX(left)
66 pdf.SetX(left)
67 pdf.Cell(width + 1, height, "", "LTR")
67 pdf.Cell(width + 1, height, "", "LTR")
68 left = left + width+1
68 left = left + width+1
69 end
69 end
70 while week_f <= @date_to
70 while week_f <= @date_to
71 width = (week_f + 6 <= @date_to) ? 7 * zoom : (@date_to - week_f + 1) * zoom
71 width = (week_f + 6 <= @date_to) ? 7 * zoom : (@date_to - week_f + 1) * zoom
72 pdf.SetY(y_start + header_heigth)
72 pdf.SetY(y_start + header_heigth)
73 pdf.SetX(left)
73 pdf.SetX(left)
74 pdf.Cell(width, height, (width >= 5 ? week_f.cweek.to_s : ""), "LTR", 0, "C")
74 pdf.Cell(width, height, (width >= 5 ? week_f.cweek.to_s : ""), "LTR", 0, "C")
75 left = left + width
75 left = left + width
76 week_f = week_f+7
76 week_f = week_f+7
77 end
77 end
78 end
78 end
79
79
80 #
80 #
81 # Days headers
81 # Days headers
82 #
82 #
83 if show_days
83 if show_days
84 left = subject_width
84 left = subject_width
85 height = header_heigth
85 height = header_heigth
86 wday = @date_from.cwday
86 wday = @date_from.cwday
87 pdf.SetFontStyle('B',7)
87 pdf.SetFontStyle('B',7)
88 (@date_to - @date_from + 1).to_i.times do
88 (@date_to - @date_from + 1).to_i.times do
89 width = zoom
89 width = zoom
90 pdf.SetY(y_start + 2 * header_heigth)
90 pdf.SetY(y_start + 2 * header_heigth)
91 pdf.SetX(left)
91 pdf.SetX(left)
92 pdf.Cell(width, height, day_name(wday)[0,1], "LTR", 0, "C")
92 pdf.Cell(width, height, day_name(wday)[0,1], "LTR", 0, "C")
93 left = left + width
93 left = left + width
94 wday = wday + 1
94 wday = wday + 1
95 wday = 1 if wday > 7
95 wday = 1 if wday > 7
96 end
96 end
97 end
97 end
98
98
99 pdf.SetY(y_start)
99 pdf.SetY(y_start)
100 pdf.SetX(15)
100 pdf.SetX(15)
101 pdf.Cell(subject_width+g_width-15, headers_heigth, "", 1)
101 pdf.Cell(subject_width+g_width-15, headers_heigth, "", 1)
102
102
103
103
104 #
104 #
105 # Tasks
105 # Tasks
106 #
106 #
107 top = headers_heigth + y_start
107 top = headers_heigth + y_start
108 pdf.SetFontStyle('B',7)
108 pdf.SetFontStyle('B',7)
109 @issues.each do |i|
109 @events.each do |i|
110 pdf.SetY(top)
110 pdf.SetY(top)
111 pdf.SetX(15)
111 pdf.SetX(15)
112 pdf.Cell(subject_width-15, 5, "#{i.tracker.name} #{i.id}: #{i.subject}".sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)'), "LR")
112
113 if i.is_a? Issue
114 pdf.Cell(subject_width-15, 5, "#{i.tracker.name} #{i.id}: #{i.subject}".sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)'), "LR")
115 else
116 pdf.Cell(subject_width-15, 5, "#{l(:label_version)}: #{i.name}", "LR")
117 end
113
118
114 pdf.SetY(top)
119 pdf.SetY(top)
115 pdf.SetX(subject_width)
120 pdf.SetX(subject_width)
116 pdf.Cell(g_width, 5, "", "LR")
121 pdf.Cell(g_width, 5, "", "LR")
122
123 pdf.SetY(top+1.5)
117
124
118 i_start_date = (i.start_date >= @date_from ? i.start_date : @date_from )
125 if i.is_a? Issue
119 i_end_date = (i.due_date <= @date_to ? i.due_date : @date_to )
126 i_start_date = (i.start_date >= @date_from ? i.start_date : @date_from )
120
127 i_end_date = (i.due_date <= @date_to ? i.due_date : @date_to )
121 i_done_date = i.start_date + ((i.due_date - i.start_date+1)*i.done_ratio/100).floor
128
122 i_done_date = (i_done_date <= @date_from ? @date_from : i_done_date )
129 i_done_date = i.start_date + ((i.due_date - i.start_date+1)*i.done_ratio/100).floor
123 i_done_date = (i_done_date >= @date_to ? @date_to : i_done_date )
130 i_done_date = (i_done_date <= @date_from ? @date_from : i_done_date )
131 i_done_date = (i_done_date >= @date_to ? @date_to : i_done_date )
132
133 i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today
134
135 i_left = ((i_start_date - @date_from)*zoom)
136 i_width = ((i_end_date - i_start_date + 1)*zoom)
137 d_width = ((i_done_date - i_start_date)*zoom)
138 l_width = ((i_late_date - i_start_date+1)*zoom) if i_late_date
139 l_width ||= 0
124
140
125 i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today
141 pdf.SetX(subject_width + i_left)
142 pdf.SetFillColor(200,200,200)
143 pdf.Cell(i_width, 2, "", 0, 0, "", 1)
126
144
127 i_left = ((i_start_date - @date_from)*zoom)
145 if l_width > 0
128 i_width = ((i_end_date - i_start_date + 1)*zoom)
146 pdf.SetY(top+1.5)
129 d_width = ((i_done_date - i_start_date)*zoom)
147 pdf.SetX(subject_width + i_left)
130 l_width = ((i_late_date - i_start_date+1)*zoom) if i_late_date
148 pdf.SetFillColor(255,100,100)
131 l_width ||= 0
149 pdf.Cell(l_width, 2, "", 0, 0, "", 1)
132
150 end
133 pdf.SetY(top+1.5)
151 if d_width > 0
134 pdf.SetX(subject_width + i_left)
152 pdf.SetY(top+1.5)
135 pdf.SetFillColor(200,200,200)
153 pdf.SetX(subject_width + i_left)
136 pdf.Cell(i_width, 2, "", 0, 0, "", 1)
154 pdf.SetFillColor(100,100,255)
137
155 pdf.Cell(d_width, 2, "", 0, 0, "", 1)
138 if l_width > 0
156 end
157
139 pdf.SetY(top+1.5)
158 pdf.SetY(top+1.5)
159 pdf.SetX(subject_width + i_left + i_width)
160 pdf.Cell(30, 2, "#{i.status.name} #{i.done_ratio}%")
161 else
162 i_left = ((i.start_date - @date_from)*zoom)
163
140 pdf.SetX(subject_width + i_left)
164 pdf.SetX(subject_width + i_left)
141 pdf.SetFillColor(255,100,100)
165 pdf.SetFillColor(50,200,50)
142 pdf.Cell(l_width, 2, "", 0, 0, "", 1)
166 pdf.Cell(2, 2, "", 0, 0, "", 1)
143 end
167
144 if d_width > 0
145 pdf.SetY(top+1.5)
168 pdf.SetY(top+1.5)
146 pdf.SetX(subject_width + i_left)
169 pdf.SetX(subject_width + i_left + 3)
147 pdf.SetFillColor(100,100,255)
170 pdf.Cell(30, 2, "#{i.name}")
148 pdf.Cell(d_width, 2, "", 0, 0, "", 1)
149 end
171 end
150
172
151 pdf.SetY(top+1.5)
152 pdf.SetX(subject_width + i_left + i_width)
153 pdf.Cell(30, 2, "#{i.status.name} #{i.done_ratio}%")
154
173
155 top = top + 5
174 top = top + 5
156 pdf.SetDrawColor(200, 200, 200)
175 pdf.SetDrawColor(200, 200, 200)
157 pdf.Line(15, top, subject_width+g_width, top)
176 pdf.Line(15, top, subject_width+g_width, top)
158 if pdf.GetY() > 180
177 if pdf.GetY() > 180
159 pdf.AddPage("L")
178 pdf.AddPage("L")
160 top = 20
179 top = 20
161 pdf.Line(15, top, subject_width+g_width, top)
180 pdf.Line(15, top, subject_width+g_width, top)
162 end
181 end
163 pdf.SetDrawColor(0, 0, 0)
182 pdf.SetDrawColor(0, 0, 0)
164 end
183 end
165
184
166 pdf.Line(15, top, subject_width+g_width, top)
185 pdf.Line(15, top, subject_width+g_width, top)
167
186
168 %>
187 %>
169 <%= pdf.Output %> No newline at end of file
188 <%= pdf.Output %>
@@ -1,227 +1,239
1 <div class="contextual">
1 <div class="contextual">
2 <%= l(:label_export_to) %>
2 <%= l(:label_export_to) %>
3 <%= link_to 'PDF', {:zoom => @zoom, :year => @year_from, :month => @month_from, :months => @months, :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects], :output => 'pdf'}, :class => 'icon icon-pdf' %>
3 <%= link_to 'PDF', {:zoom => @zoom, :year => @year_from, :month => @month_from, :months => @months, :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects], :output => 'pdf'}, :class => 'icon icon-pdf' %>
4 </div>
4 </div>
5
5
6 <h2><%= l(:label_gantt) %></h2>
6 <h2><%= l(:label_gantt) %></h2>
7
7
8 <% form_tag do %>
8 <% form_tag do %>
9 <table width="100%">
9 <table width="100%">
10 <tr>
10 <tr>
11 <td align="left">
11 <td align="left">
12 <input type="text" name="months" size="2" value="<%= @months %>" />
12 <input type="text" name="months" size="2" value="<%= @months %>" />
13 <%= l(:label_months_from) %>
13 <%= l(:label_months_from) %>
14 <%= select_month(@month_from, :prefix => "month", :discard_type => true) %>
14 <%= select_month(@month_from, :prefix => "month", :discard_type => true) %>
15 <%= select_year(@year_from, :prefix => "year", :discard_type => true) %>
15 <%= select_year(@year_from, :prefix => "year", :discard_type => true) %>
16 <%= hidden_field_tag 'zoom', @zoom %>
16 <%= hidden_field_tag 'zoom', @zoom %>
17 <%= submit_tag l(:button_submit), :class => "button-small" %>
17 <%= submit_tag l(:button_submit), :class => "button-small" %>
18 </td>
18 </td>
19 <td>
19 <td>
20 <a href="#" onclick="Element.toggle('trackerselect')"><%= l(:label_options) %></a>
20 <a href="#" onclick="Element.toggle('trackerselect')"><%= l(:label_options) %></a>
21 <div id="trackerselect" class="rightbox overlay" style="width:140px; display: none;">
21 <div id="trackerselect" class="rightbox overlay" style="width:140px; display: none;">
22 <p><strong><%=l(:label_tracker_plural)%></strong></p>
22 <p><strong><%=l(:label_tracker_plural)%></strong></p>
23 <% @trackers.each do |tracker| %>
23 <% @trackers.each do |tracker| %>
24 <%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %>
24 <%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %>
25 <%= tracker.name %><br />
25 <%= tracker.name %><br />
26 <% end %>
26 <% end %>
27 <% if @project.children.any? %>
27 <% if @project.children.any? %>
28 <p><strong><%=l(:label_subproject_plural)%></strong></p>
28 <p><strong><%=l(:label_subproject_plural)%></strong></p>
29 <%= check_box_tag "with_subprojects", 1, params[:with_subprojects] %> <%= l(:general_text_Yes) %>
29 <%= check_box_tag "with_subprojects", 1, params[:with_subprojects] %> <%= l(:general_text_Yes) %>
30 <% end %>
30 <% end %>
31 <p><center><%= submit_tag l(:button_apply), :class => 'button-small' %></center></p>
31 <p><center><%= submit_tag l(:button_apply), :class => 'button-small' %></center></p>
32 </div>
32 </div>
33 </td>
33 </td>
34 <td align="right">
34 <td align="right">
35 <%= if @zoom < 4
35 <%= if @zoom < 4
36 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]}
36 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]}
37 else
37 else
38 image_tag 'zoom_in_g.png'
38 image_tag 'zoom_in_g.png'
39 end %>
39 end %>
40 <%= if @zoom > 1
40 <%= if @zoom > 1
41 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]}
41 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]}
42 else
42 else
43 image_tag 'zoom_out_g.png'
43 image_tag 'zoom_out_g.png'
44 end %>
44 end %>
45 </td>
45 </td>
46 </tr>
46 </tr>
47 </table>
47 </table>
48 <% end %>
48 <% end %>
49
49
50 <% zoom = 1
50 <% zoom = 1
51 @zoom.times { zoom = zoom * 2 }
51 @zoom.times { zoom = zoom * 2 }
52
52
53 subject_width = 260
53 subject_width = 260
54 header_heigth = 18
54 header_heigth = 18
55
55
56 headers_height = header_heigth
56 headers_height = header_heigth
57 show_weeks = false
57 show_weeks = false
58 show_days = false
58 show_days = false
59
59
60 if @zoom >1
60 if @zoom >1
61 show_weeks = true
61 show_weeks = true
62 headers_height = 2*header_heigth
62 headers_height = 2*header_heigth
63 if @zoom > 2
63 if @zoom > 2
64 show_days = true
64 show_days = true
65 headers_height = 3*header_heigth
65 headers_height = 3*header_heigth
66 end
66 end
67 end
67 end
68
68
69 g_width = (@date_to - @date_from + 1)*zoom
69 g_width = (@date_to - @date_from + 1)*zoom
70 g_height = [(20 * @issues.length + 6)+150, 206].max
70 g_height = [(20 * @events.length + 6)+150, 206].max
71 t_height = g_height + headers_height
71 t_height = g_height + headers_height
72 %>
72 %>
73
73
74 <table width="100%" style="border:0; border-collapse: collapse;">
74 <table width="100%" style="border:0; border-collapse: collapse;">
75 <tr>
75 <tr>
76 <td style="width:260px;">
76 <td style="width:260px;">
77
77
78 <div style="position:relative;height:<%= t_height + 24 %>px;width:<%= subject_width + 1 %>px;">
78 <div style="position:relative;height:<%= t_height + 24 %>px;width:<%= subject_width + 1 %>px;">
79 <div style="right:-2px;width:<%= subject_width %>px;height:<%= headers_height %>px;background: #eee;" class="gantt_hdr"></div>
79 <div style="right:-2px;width:<%= subject_width %>px;height:<%= headers_height %>px;background: #eee;" class="gantt_hdr"></div>
80 <div style="right:-2px;width:<%= subject_width %>px;height:<%= t_height %>px;border-left: 1px solid #c0c0c0;overflow:hidden;" class="gantt_hdr"></div>
80 <div style="right:-2px;width:<%= subject_width %>px;height:<%= t_height %>px;border-left: 1px solid #c0c0c0;overflow:hidden;" class="gantt_hdr"></div>
81 <%
81 <%
82 #
82 #
83 # Tasks subjects
83 # Tasks subjects
84 #
84 #
85 top = headers_height + 8
85 top = headers_height + 8
86 @issues.each do |i| %>
86 @events.each do |i| %>
87 <div style="position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;left:4px;overflow:hidden;">
87 <div style="position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;left:4px;overflow:hidden;"><small>
88 <small><%= link_to "#{i.tracker.name} ##{i.id}", { :controller => 'issues', :action => 'show', :id => i }, :title => "#{i.subject}" %>:
88 <% if i.is_a? Issue %>
89 <%=h i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %></small>
89 <%= link_to "#{i.tracker.name} ##{i.id}", { :controller => 'issues', :action => 'show', :id => i }, :title => "#{i.subject}" %>:
90 </div>
90 <%=h i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %>
91 <% else %>
92 <strong><%= "#{l(:label_version)}: #{i.name}" %></strong>
93 <% end %>
94 </small></div>
91 <% top = top + 20
95 <% top = top + 20
92 end %>
96 end %>
93 </div>
97 </div>
94 </td>
98 </td>
95 <td>
99 <td>
96
100
97 <div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;">
101 <div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;">
98 <div style="width:<%= g_width-1 %>px;height:<%= headers_height %>px;background: #eee;" class="gantt_hdr">&nbsp;</div>
102 <div style="width:<%= g_width-1 %>px;height:<%= headers_height %>px;background: #eee;" class="gantt_hdr">&nbsp;</div>
99 <%
103 <%
100 #
104 #
101 # Months headers
105 # Months headers
102 #
106 #
103 month_f = @date_from
107 month_f = @date_from
104 left = 0
108 left = 0
105 height = (show_weeks ? header_heigth : header_heigth + g_height)
109 height = (show_weeks ? header_heigth : header_heigth + g_height)
106 @months.times do
110 @months.times do
107 width = ((month_f >> 1) - month_f) * zoom - 1
111 width = ((month_f >> 1) - month_f) * zoom - 1
108 %>
112 %>
109 <div style="left:<%= left %>px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">
113 <div style="left:<%= left %>px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">
110 <%= 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}"%>
114 <%= 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}"%>
111 </div>
115 </div>
112 <%
116 <%
113 left = left + width + 1
117 left = left + width + 1
114 month_f = month_f >> 1
118 month_f = month_f >> 1
115 end %>
119 end %>
116
120
117 <%
121 <%
118 #
122 #
119 # Weeks headers
123 # Weeks headers
120 #
124 #
121 if show_weeks
125 if show_weeks
122 left = 0
126 left = 0
123 height = (show_days ? header_heigth-1 : header_heigth-1 + g_height)
127 height = (show_days ? header_heigth-1 : header_heigth-1 + g_height)
124 if @date_from.cwday == 1
128 if @date_from.cwday == 1
125 # @date_from is monday
129 # @date_from is monday
126 week_f = @date_from
130 week_f = @date_from
127 else
131 else
128 # find next monday after @date_from
132 # find next monday after @date_from
129 week_f = @date_from + (7 - @date_from.cwday + 1)
133 week_f = @date_from + (7 - @date_from.cwday + 1)
130 width = (7 - @date_from.cwday + 1) * zoom-1
134 width = (7 - @date_from.cwday + 1) * zoom-1
131 %>
135 %>
132 <div style="left:<%= left %>px;top:19px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">&nbsp;</div>
136 <div style="left:<%= left %>px;top:19px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">&nbsp;</div>
133 <%
137 <%
134 left = left + width+1
138 left = left + width+1
135 end %>
139 end %>
136 <%
140 <%
137 while week_f <= @date_to
141 while week_f <= @date_to
138 width = (week_f + 6 <= @date_to) ? 7 * zoom -1 : (@date_to - week_f + 1) * zoom-1
142 width = (week_f + 6 <= @date_to) ? 7 * zoom -1 : (@date_to - week_f + 1) * zoom-1
139 %>
143 %>
140 <div style="left:<%= left %>px;top:19px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">
144 <div style="left:<%= left %>px;top:19px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">
141 <small><%= week_f.cweek if width >= 16 %></small>
145 <small><%= week_f.cweek if width >= 16 %></small>
142 </div>
146 </div>
143 <%
147 <%
144 left = left + width+1
148 left = left + width+1
145 week_f = week_f+7
149 week_f = week_f+7
146 end
150 end
147 end %>
151 end %>
148
152
149 <%
153 <%
150 #
154 #
151 # Days headers
155 # Days headers
152 #
156 #
153 if show_days
157 if show_days
154 left = 0
158 left = 0
155 height = g_height + header_heigth - 1
159 height = g_height + header_heigth - 1
156 wday = @date_from.cwday
160 wday = @date_from.cwday
157 (@date_to - @date_from + 1).to_i.times do
161 (@date_to - @date_from + 1).to_i.times do
158 width = zoom - 1
162 width = zoom - 1
159 %>
163 %>
160 <div style="left:<%= left %>px;top:37px;width:<%= width %>px;height:<%= height %>px;font-size:0.7em;<%= "background:#f1f1f1;" if wday > 5 %>" class="gantt_hdr">
164 <div style="left:<%= left %>px;top:37px;width:<%= width %>px;height:<%= height %>px;font-size:0.7em;<%= "background:#f1f1f1;" if wday > 5 %>" class="gantt_hdr">
161 <%= day_name(wday)[0,1] %>
165 <%= day_name(wday)[0,1] %>
162 </div>
166 </div>
163 <%
167 <%
164 left = left + width+1
168 left = left + width+1
165 wday = wday + 1
169 wday = wday + 1
166 wday = 1 if wday > 7
170 wday = 1 if wday > 7
167 end
171 end
168 end %>
172 end %>
169
173
170 <%
174 <%
171 #
175 #
172 # Today red line
176 # Today red line
173 #
177 #
174 if Date.today >= @date_from and Date.today <= @date_to %>
178 if Date.today >= @date_from and Date.today <= @date_to %>
175 <div style="position: absolute;height:<%= g_height %>px;top:<%= headers_height + 1 %>px;left:<%= ((Date.today-@date_from+1)*zoom).floor()-1 %>px;width:10px;border-left: 1px dashed red;">&nbsp;</div>
179 <div style="position: absolute;height:<%= g_height %>px;top:<%= headers_height + 1 %>px;left:<%= ((Date.today-@date_from+1)*zoom).floor()-1 %>px;width:10px;border-left: 1px dashed red;">&nbsp;</div>
176 <% end %>
180 <% end %>
177
181
178 <%
182 <%
179 #
183 #
180 # Tasks
184 # Tasks
181 #
185 #
182 top = headers_height + 10
186 top = headers_height + 10
183 @issues.each do |i| %>
187 @events.each do |i|
184 <%
188 if i.is_a? Issue
185 i_start_date = (i.start_date >= @date_from ? i.start_date : @date_from )
189 i_start_date = (i.start_date >= @date_from ? i.start_date : @date_from )
186 i_end_date = (i.due_date <= @date_to ? i.due_date : @date_to )
190 i_end_date = (i.due_date <= @date_to ? i.due_date : @date_to )
187
191
188 i_done_date = i.start_date + ((i.due_date - i.start_date+1)*i.done_ratio/100).floor
192 i_done_date = i.start_date + ((i.due_date - i.start_date+1)*i.done_ratio/100).floor
189 i_done_date = (i_done_date <= @date_from ? @date_from : i_done_date )
193 i_done_date = (i_done_date <= @date_from ? @date_from : i_done_date )
190 i_done_date = (i_done_date >= @date_to ? @date_to : i_done_date )
194 i_done_date = (i_done_date >= @date_to ? @date_to : i_done_date )
191
195
192 i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today
196 i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today
193
197
194 i_left = ((i_start_date - @date_from)*zoom).floor
198 i_left = ((i_start_date - @date_from)*zoom).floor
195 i_width = ((i_end_date - i_start_date + 1)*zoom).floor - 2 # total width of the issue (- 2 for left and right borders)
199 i_width = ((i_end_date - i_start_date + 1)*zoom).floor - 2 # total width of the issue (- 2 for left and right borders)
196 d_width = ((i_done_date - i_start_date)*zoom).floor - 2 # done width
200 d_width = ((i_done_date - i_start_date)*zoom).floor - 2 # done width
197 l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor - 2 : 0 # delay width
201 l_width = i_late_date ? ((i_late_date - i_start_date+1)*zoom).floor - 2 : 0 # delay width
198 %>
202 %>
199 <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;" class="task task_todo">&nbsp;</div>
203 <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;" class="task task_todo">&nbsp;</div>
200 <% if l_width > 0 %>
204 <% if l_width > 0 %>
201 <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= l_width %>px;" class="task task_late">&nbsp;</div>
205 <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= l_width %>px;" class="task task_late">&nbsp;</div>
202 <% end %>
206 <% end %>
203 <% if d_width > 0 %>
207 <% if d_width > 0 %>
204 <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= d_width %>px;" class="task task_done">&nbsp;</div>
208 <div style="top:<%= top %>px;left:<%= i_left %>px;width:<%= d_width %>px;" class="task task_done">&nbsp;</div>
205 <% end %>
209 <% end %>
206 <div style="top:<%= top %>px;left:<%= i_left + i_width + 5 %>px;background:#fff;" class="task">
210 <div style="top:<%= top %>px;left:<%= i_left + i_width + 5 %>px;background:#fff;" class="task">
207 <%= i.status.name %>
211 <%= i.status.name %>
208 <%= (i.done_ratio).to_i %>%
212 <%= (i.done_ratio).to_i %>%
209 </div>
213 </div>
210 <% # === tooltip === %>
214 <% # === tooltip === %>
211 <div class="tooltip" style="position: absolute;top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;height:12px;">
215 <div class="tooltip" style="position: absolute;top:<%= top %>px;left:<%= i_left %>px;width:<%= i_width %>px;height:12px;">
212 <span class="tip">
216 <span class="tip">
213 <%= render :partial => "issues/tooltip", :locals => { :issue => i }%>
217 <%= render :partial => "issues/tooltip", :locals => { :issue => i }%>
214 </span></div>
218 </span></div>
219 <% else
220 i_left = ((i.start_date - @date_from)*zoom).floor
221 %>
222 <div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone">&nbsp;</div>
223 <div style="top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;" class="task">
224 <strong><%= i.name %></strong>
225 </div>
226 <% end %>
215 <% top = top + 20
227 <% top = top + 20
216 end %>
228 end %>
217 </div>
229 </div>
218 </td>
230 </td>
219 </tr>
231 </tr>
220 </table>
232 </table>
221
233
222 <table width="100%">
234 <table width="100%">
223 <tr>
235 <tr>
224 <td align="left"><%= link_to ('&#171; ' + 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] %></td>
236 <td align="left"><%= link_to ('&#171; ' + 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] %></td>
225 <td align="right"><%= link_to (l(:label_next) + ' &#187;'), :year => (@date_from >> @months).year, :month => (@date_from >> @months).month, :zoom => @zoom, :months => @months, :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects] %></td>
237 <td align="right"><%= link_to (l(:label_next) + ' &#187;'), :year => (@date_from >> @months).year, :month => (@date_from >> @months).month, :zoom => @zoom, :months => @months, :tracker_ids => @selected_tracker_ids, :with_subprojects => params[:with_subprojects] %></td>
226 </tr>
238 </tr>
227 </table> No newline at end of file
239 </table>
@@ -1,632 +1,633
1 /* andreas08 - an open source xhtml/css website layout by Andreas Viklund - http://andreasviklund.com . Free to use in any way and for any purpose as long as the proper credits are given to the original designer. Version: 1.0, November 28, 2005 */
1 /* andreas08 - an open source xhtml/css website layout by Andreas Viklund - http://andreasviklund.com . Free to use in any way and for any purpose as long as the proper credits are given to the original designer. Version: 1.0, November 28, 2005 */
2 /* Edited by Jean-Philippe Lang *>
2 /* Edited by Jean-Philippe Lang *>
3 /**************** Body and tag styles ****************/
3 /**************** Body and tag styles ****************/
4
4
5 #header * {margin:0; padding:0;}
5 #header * {margin:0; padding:0;}
6 p, ul, ol, li {margin:0; padding:0;}
6 p, ul, ol, li {margin:0; padding:0;}
7
7
8 body{
8 body{
9 font:76% Verdana,Tahoma,Arial,sans-serif;
9 font:76% Verdana,Tahoma,Arial,sans-serif;
10 line-height:1.4em;
10 line-height:1.4em;
11 text-align:center;
11 text-align:center;
12 color:#303030;
12 color:#303030;
13 background:#e8eaec;
13 background:#e8eaec;
14 margin:0;
14 margin:0;
15 }
15 }
16
16
17 a{color:#467aa7;font-weight:bold;text-decoration:none;background-color:inherit;}
17 a{color:#467aa7;font-weight:bold;text-decoration:none;background-color:inherit;}
18 a:hover{color:#2a5a8a; text-decoration:none; background-color:inherit;}
18 a:hover{color:#2a5a8a; text-decoration:none; background-color:inherit;}
19 a img{border:none;}
19 a img{border:none;}
20
20
21 p{margin:0 0 1em 0;}
21 p{margin:0 0 1em 0;}
22 p form{margin-top:0; margin-bottom:20px;}
22 p form{margin-top:0; margin-bottom:20px;}
23
23
24 img.left,img.center,img.right{padding:4px; border:1px solid #a0a0a0;}
24 img.left,img.center,img.right{padding:4px; border:1px solid #a0a0a0;}
25 img.left{float:left; margin:0 12px 5px 0;}
25 img.left{float:left; margin:0 12px 5px 0;}
26 img.center{display:block; margin:0 auto 5px auto;}
26 img.center{display:block; margin:0 auto 5px auto;}
27 img.right{float:right; margin:0 0 5px 12px;}
27 img.right{float:right; margin:0 0 5px 12px;}
28
28
29 /**************** Header and navigation styles ****************/
29 /**************** Header and navigation styles ****************/
30
30
31 #container{
31 #container{
32 width:100%;
32 width:100%;
33 min-width: 800px;
33 min-width: 800px;
34 margin:0;
34 margin:0;
35 padding:0;
35 padding:0;
36 text-align:left;
36 text-align:left;
37 background:#ffffff;
37 background:#ffffff;
38 color:#303030;
38 color:#303030;
39 }
39 }
40
40
41 #header{
41 #header{
42 height:4.5em;
42 height:4.5em;
43 margin:0;
43 margin:0;
44 background:#467aa7;
44 background:#467aa7;
45 color:#ffffff;
45 color:#ffffff;
46 margin-bottom:1px;
46 margin-bottom:1px;
47 }
47 }
48
48
49 #header h1{
49 #header h1{
50 padding:10px 0 0 20px;
50 padding:10px 0 0 20px;
51 font-size:2em;
51 font-size:2em;
52 background-color:inherit;
52 background-color:inherit;
53 color:#fff;
53 color:#fff;
54 letter-spacing:-1px;
54 letter-spacing:-1px;
55 font-weight:bold;
55 font-weight:bold;
56 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
56 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
57 }
57 }
58
58
59 #header h2{
59 #header h2{
60 margin:3px 0 0 40px;
60 margin:3px 0 0 40px;
61 font-size:1.5em;
61 font-size:1.5em;
62 background-color:inherit;
62 background-color:inherit;
63 color:#f0f2f4;
63 color:#f0f2f4;
64 letter-spacing:-1px;
64 letter-spacing:-1px;
65 font-weight:normal;
65 font-weight:normal;
66 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
66 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
67 }
67 }
68
68
69 #navigation{
69 #navigation{
70 height:2.2em;
70 height:2.2em;
71 line-height:2.2em;
71 line-height:2.2em;
72 margin:0;
72 margin:0;
73 background:#578bb8;
73 background:#578bb8;
74 color:#ffffff;
74 color:#ffffff;
75 }
75 }
76
76
77 #navigation li{
77 #navigation li{
78 float:left;
78 float:left;
79 list-style-type:none;
79 list-style-type:none;
80 border-right:1px solid #ffffff;
80 border-right:1px solid #ffffff;
81 white-space:nowrap;
81 white-space:nowrap;
82 }
82 }
83
83
84 #navigation li.right {
84 #navigation li.right {
85 float:right;
85 float:right;
86 list-style-type:none;
86 list-style-type:none;
87 border-right:0;
87 border-right:0;
88 border-left:1px solid #ffffff;
88 border-left:1px solid #ffffff;
89 white-space:nowrap;
89 white-space:nowrap;
90 }
90 }
91
91
92 #navigation li a{
92 #navigation li a{
93 display:block;
93 display:block;
94 padding:0px 10px 0px 22px;
94 padding:0px 10px 0px 22px;
95 font-size:0.8em;
95 font-size:0.8em;
96 font-weight:normal;
96 font-weight:normal;
97 text-decoration:none;
97 text-decoration:none;
98 background-color:inherit;
98 background-color:inherit;
99 color: #ffffff;
99 color: #ffffff;
100 }
100 }
101
101
102 #navigation li.submenu {background:url(../images/arrow_down.png) 96% 80% no-repeat;}
102 #navigation li.submenu {background:url(../images/arrow_down.png) 96% 80% no-repeat;}
103 #navigation li.submenu a {padding:0px 16px 0px 22px;}
103 #navigation li.submenu a {padding:0px 16px 0px 22px;}
104 * html #navigation a {width:1%;}
104 * html #navigation a {width:1%;}
105
105
106 #navigation .selected,#navigation a:hover{
106 #navigation .selected,#navigation a:hover{
107 color:#ffffff;
107 color:#ffffff;
108 text-decoration:none;
108 text-decoration:none;
109 background-color: #80b0da;
109 background-color: #80b0da;
110 }
110 }
111
111
112 /**************** Icons *******************/
112 /**************** Icons *******************/
113 .icon {
113 .icon {
114 background-position: 0% 40%;
114 background-position: 0% 40%;
115 background-repeat: no-repeat;
115 background-repeat: no-repeat;
116 padding-left: 20px;
116 padding-left: 20px;
117 padding-top: 2px;
117 padding-top: 2px;
118 padding-bottom: 3px;
118 padding-bottom: 3px;
119 vertical-align: middle;
119 vertical-align: middle;
120 }
120 }
121
121
122 #navigation .icon {
122 #navigation .icon {
123 background-position: 4px 50%;
123 background-position: 4px 50%;
124 }
124 }
125
125
126 .icon22 {
126 .icon22 {
127 background-position: 0% 40%;
127 background-position: 0% 40%;
128 background-repeat: no-repeat;
128 background-repeat: no-repeat;
129 padding-left: 26px;
129 padding-left: 26px;
130 line-height: 22px;
130 line-height: 22px;
131 vertical-align: middle;
131 vertical-align: middle;
132 }
132 }
133
133
134 .icon-add { background-image: url(../images/add.png); }
134 .icon-add { background-image: url(../images/add.png); }
135 .icon-edit { background-image: url(../images/edit.png); }
135 .icon-edit { background-image: url(../images/edit.png); }
136 .icon-del { background-image: url(../images/delete.png); }
136 .icon-del { background-image: url(../images/delete.png); }
137 .icon-move { background-image: url(../images/move.png); }
137 .icon-move { background-image: url(../images/move.png); }
138 .icon-save { background-image: url(../images/save.png); }
138 .icon-save { background-image: url(../images/save.png); }
139 .icon-cancel { background-image: url(../images/cancel.png); }
139 .icon-cancel { background-image: url(../images/cancel.png); }
140 .icon-pdf { background-image: url(../images/pdf.png); }
140 .icon-pdf { background-image: url(../images/pdf.png); }
141 .icon-csv { background-image: url(../images/csv.png); }
141 .icon-csv { background-image: url(../images/csv.png); }
142 .icon-html { background-image: url(../images/html.png); }
142 .icon-html { background-image: url(../images/html.png); }
143 .icon-txt { background-image: url(../images/txt.png); }
143 .icon-txt { background-image: url(../images/txt.png); }
144 .icon-file { background-image: url(../images/file.png); }
144 .icon-file { background-image: url(../images/file.png); }
145 .icon-folder { background-image: url(../images/folder.png); }
145 .icon-folder { background-image: url(../images/folder.png); }
146 .icon-package { background-image: url(../images/package.png); }
146 .icon-package { background-image: url(../images/package.png); }
147 .icon-home { background-image: url(../images/home.png); }
147 .icon-home { background-image: url(../images/home.png); }
148 .icon-user { background-image: url(../images/user.png); }
148 .icon-user { background-image: url(../images/user.png); }
149 .icon-mypage { background-image: url(../images/user_page.png); }
149 .icon-mypage { background-image: url(../images/user_page.png); }
150 .icon-admin { background-image: url(../images/admin.png); }
150 .icon-admin { background-image: url(../images/admin.png); }
151 .icon-projects { background-image: url(../images/projects.png); }
151 .icon-projects { background-image: url(../images/projects.png); }
152 .icon-logout { background-image: url(../images/logout.png); }
152 .icon-logout { background-image: url(../images/logout.png); }
153 .icon-help { background-image: url(../images/help.png); }
153 .icon-help { background-image: url(../images/help.png); }
154 .icon-attachment { background-image: url(../images/attachment.png); }
154 .icon-attachment { background-image: url(../images/attachment.png); }
155 .icon-index { background-image: url(../images/index.png); }
155 .icon-index { background-image: url(../images/index.png); }
156 .icon-history { background-image: url(../images/history.png); }
156 .icon-history { background-image: url(../images/history.png); }
157 .icon-feed { background-image: url(../images/feed.png); }
157 .icon-feed { background-image: url(../images/feed.png); }
158 .icon-time { background-image: url(../images/time.png); }
158 .icon-time { background-image: url(../images/time.png); }
159 .icon-stats { background-image: url(../images/stats.png); }
159 .icon-stats { background-image: url(../images/stats.png); }
160
160
161 .icon22-projects { background-image: url(../images/22x22/projects.png); }
161 .icon22-projects { background-image: url(../images/22x22/projects.png); }
162 .icon22-users { background-image: url(../images/22x22/users.png); }
162 .icon22-users { background-image: url(../images/22x22/users.png); }
163 .icon22-tracker { background-image: url(../images/22x22/tracker.png); }
163 .icon22-tracker { background-image: url(../images/22x22/tracker.png); }
164 .icon22-role { background-image: url(../images/22x22/role.png); }
164 .icon22-role { background-image: url(../images/22x22/role.png); }
165 .icon22-workflow { background-image: url(../images/22x22/workflow.png); }
165 .icon22-workflow { background-image: url(../images/22x22/workflow.png); }
166 .icon22-options { background-image: url(../images/22x22/options.png); }
166 .icon22-options { background-image: url(../images/22x22/options.png); }
167 .icon22-notifications { background-image: url(../images/22x22/notifications.png); }
167 .icon22-notifications { background-image: url(../images/22x22/notifications.png); }
168 .icon22-authent { background-image: url(../images/22x22/authent.png); }
168 .icon22-authent { background-image: url(../images/22x22/authent.png); }
169 .icon22-info { background-image: url(../images/22x22/info.png); }
169 .icon22-info { background-image: url(../images/22x22/info.png); }
170 .icon22-comment { background-image: url(../images/22x22/comment.png); }
170 .icon22-comment { background-image: url(../images/22x22/comment.png); }
171 .icon22-package { background-image: url(../images/22x22/package.png); }
171 .icon22-package { background-image: url(../images/22x22/package.png); }
172 .icon22-settings { background-image: url(../images/22x22/settings.png); }
172 .icon22-settings { background-image: url(../images/22x22/settings.png); }
173
173
174 /**************** Content styles ****************/
174 /**************** Content styles ****************/
175
175
176 html>body #content {
176 html>body #content {
177 height: auto;
177 height: auto;
178 min-height: 500px;
178 min-height: 500px;
179 }
179 }
180
180
181 #content{
181 #content{
182 width: auto;
182 width: auto;
183 height:500px;
183 height:500px;
184 font-size:0.9em;
184 font-size:0.9em;
185 padding:20px 10px 10px 20px;
185 padding:20px 10px 10px 20px;
186 margin-left: 120px;
186 margin-left: 120px;
187 border-left: 1px dashed #c0c0c0;
187 border-left: 1px dashed #c0c0c0;
188
188
189 }
189 }
190
190
191 #content h2, #content div.wiki h1 {
191 #content h2, #content div.wiki h1 {
192 display:block;
192 display:block;
193 margin:0 0 16px 0;
193 margin:0 0 16px 0;
194 font-size:1.7em;
194 font-size:1.7em;
195 font-weight:normal;
195 font-weight:normal;
196 letter-spacing:-1px;
196 letter-spacing:-1px;
197 color:#606060;
197 color:#606060;
198 background-color:inherit;
198 background-color:inherit;
199 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
199 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
200 }
200 }
201
201
202 #content h2 a{font-weight:normal;}
202 #content h2 a{font-weight:normal;}
203 #content h3{margin:0 0 12px 0; font-size:1.4em;color:#707070;font-family: Trebuchet MS,Georgia,"Times New Roman",serif;}
203 #content h3{margin:0 0 12px 0; font-size:1.4em;color:#707070;font-family: Trebuchet MS,Georgia,"Times New Roman",serif;}
204 #content h4{font-size: 1em; margin-bottom: 12px; margin-top: 20px; font-weight: normal; border-bottom: dotted 1px #c0c0c0;}
204 #content h4{font-size: 1em; margin-bottom: 12px; margin-top: 20px; font-weight: normal; border-bottom: dotted 1px #c0c0c0;}
205 #content a:hover,#subcontent a:hover{text-decoration:underline;}
205 #content a:hover,#subcontent a:hover{text-decoration:underline;}
206 #content ul,#content ol{margin:0 5px 16px 35px;}
206 #content ul,#content ol{margin:0 5px 16px 35px;}
207 #content dl{margin:0 5px 10px 25px;}
207 #content dl{margin:0 5px 10px 25px;}
208 #content dt{font-weight:bold; margin-bottom:5px;}
208 #content dt{font-weight:bold; margin-bottom:5px;}
209 #content dd{margin:0 0 10px 15px;}
209 #content dd{margin:0 0 10px 15px;}
210
210
211 #content .tabs{height: 2.6em;}
211 #content .tabs{height: 2.6em;}
212 #content .tabs ul{margin:0;}
212 #content .tabs ul{margin:0;}
213 #content .tabs ul li{
213 #content .tabs ul li{
214 float:left;
214 float:left;
215 list-style-type:none;
215 list-style-type:none;
216 white-space:nowrap;
216 white-space:nowrap;
217 margin-right:8px;
217 margin-right:8px;
218 background:#fff;
218 background:#fff;
219 }
219 }
220 #content .tabs ul li a{
220 #content .tabs ul li a{
221 display:block;
221 display:block;
222 font-size: 0.9em;
222 font-size: 0.9em;
223 text-decoration:none;
223 text-decoration:none;
224 line-height:1em;
224 line-height:1em;
225 padding:4px;
225 padding:4px;
226 border: 1px solid #c0c0c0;
226 border: 1px solid #c0c0c0;
227 }
227 }
228
228
229 #content .tabs ul li a.selected, #content .tabs ul li a:hover{
229 #content .tabs ul li a.selected, #content .tabs ul li a:hover{
230 background-color: #80b0da;
230 background-color: #80b0da;
231 border: 1px solid #80b0da;
231 border: 1px solid #80b0da;
232 color: #fff;
232 color: #fff;
233 text-decoration:none;
233 text-decoration:none;
234 }
234 }
235
235
236 /***********************************************/
236 /***********************************************/
237
237
238 form {display: inline;}
238 form {display: inline;}
239 blockquote {padding-left: 6px; border-left: 2px solid #ccc;}
239 blockquote {padding-left: 6px; border-left: 2px solid #ccc;}
240 input, select {vertical-align: middle; margin-bottom: 4px;}
240 input, select {vertical-align: middle; margin-bottom: 4px;}
241
241
242 input.button-small {font-size: 0.8em;}
242 input.button-small {font-size: 0.8em;}
243 textarea.wiki-edit { width: 99.5%; }
243 textarea.wiki-edit { width: 99.5%; }
244 .select-small {font-size: 0.8em;}
244 .select-small {font-size: 0.8em;}
245 label {font-weight: bold; font-size: 1em; color: #505050;}
245 label {font-weight: bold; font-size: 1em; color: #505050;}
246 fieldset {border:1px solid #c0c0c0; padding: 6px;}
246 fieldset {border:1px solid #c0c0c0; padding: 6px;}
247 legend {color: #505050;}
247 legend {color: #505050;}
248 .required {color: #bb0000;}
248 .required {color: #bb0000;}
249 .odd {background-color:#f6f7f8;}
249 .odd {background-color:#f6f7f8;}
250 .even {background-color: #fff;}
250 .even {background-color: #fff;}
251 hr { border:0; border-top: dotted 1px #fff; border-bottom: dotted 1px #c0c0c0; }
251 hr { border:0; border-top: dotted 1px #fff; border-bottom: dotted 1px #c0c0c0; }
252 table p {margin:0; padding:0;}
252 table p {margin:0; padding:0;}
253
253
254 .highlight { background-color: #FCFD8D;}
254 .highlight { background-color: #FCFD8D;}
255
255
256 div.square {
256 div.square {
257 border: 1px solid #999;
257 border: 1px solid #999;
258 float: left;
258 float: left;
259 margin: .4em .5em 0 0;
259 margin: .4em .5em 0 0;
260 overflow: hidden;
260 overflow: hidden;
261 width: .6em; height: .6em;
261 width: .6em; height: .6em;
262 }
262 }
263
263
264 ul.documents {
264 ul.documents {
265 list-style-type: none;
265 list-style-type: none;
266 padding: 0;
266 padding: 0;
267 margin: 0;
267 margin: 0;
268 }
268 }
269
269
270 ul.documents li {
270 ul.documents li {
271 background-image: url(../images/32x32/file.png);
271 background-image: url(../images/32x32/file.png);
272 background-repeat: no-repeat;
272 background-repeat: no-repeat;
273 background-position: 0 1px;
273 background-position: 0 1px;
274 padding-left: 36px;
274 padding-left: 36px;
275 margin-bottom: 10px;
275 margin-bottom: 10px;
276 margin-left: -37px;
276 margin-left: -37px;
277 }
277 }
278
278
279 /********** Table used to display lists of things ***********/
279 /********** Table used to display lists of things ***********/
280
280
281 table.list {
281 table.list {
282 width:100%;
282 width:100%;
283 border-collapse: collapse;
283 border-collapse: collapse;
284 border: 1px dotted #d0d0d0;
284 border: 1px dotted #d0d0d0;
285 margin-bottom: 6px;
285 margin-bottom: 6px;
286 }
286 }
287
287
288 table.with-cells td {
288 table.with-cells td {
289 border: 1px solid #d7d7d7;
289 border: 1px solid #d7d7d7;
290 }
290 }
291
291
292 table.list td {
292 table.list td {
293 padding:2px;
293 padding:2px;
294 }
294 }
295
295
296 table.list thead th {
296 table.list thead th {
297 text-align: center;
297 text-align: center;
298 background: #eee;
298 background: #eee;
299 border: 1px solid #d7d7d7;
299 border: 1px solid #d7d7d7;
300 color: #777;
300 color: #777;
301 }
301 }
302
302
303 table.list tbody th {
303 table.list tbody th {
304 font-weight: normal;
304 font-weight: normal;
305 background: #eed;
305 background: #eed;
306 border: 1px solid #d7d7d7;
306 border: 1px solid #d7d7d7;
307 }
307 }
308
308
309 /********** Validation error messages *************/
309 /********** Validation error messages *************/
310 #errorExplanation {
310 #errorExplanation {
311 width: 400px;
311 width: 400px;
312 border: 0;
312 border: 0;
313 padding: 7px;
313 padding: 7px;
314 padding-bottom: 3px;
314 padding-bottom: 3px;
315 margin-bottom: 0px;
315 margin-bottom: 0px;
316 }
316 }
317
317
318 #errorExplanation h2 {
318 #errorExplanation h2 {
319 text-align: left;
319 text-align: left;
320 font-weight: bold;
320 font-weight: bold;
321 padding: 5px 5px 10px 26px;
321 padding: 5px 5px 10px 26px;
322 font-size: 1em;
322 font-size: 1em;
323 margin: -7px;
323 margin: -7px;
324 background: url(../images/alert.png) no-repeat 6px 6px;
324 background: url(../images/alert.png) no-repeat 6px 6px;
325 }
325 }
326
326
327 #errorExplanation p {
327 #errorExplanation p {
328 color: #333;
328 color: #333;
329 margin-bottom: 0;
329 margin-bottom: 0;
330 padding: 5px;
330 padding: 5px;
331 }
331 }
332
332
333 #errorExplanation ul li {
333 #errorExplanation ul li {
334 font-size: 1em;
334 font-size: 1em;
335 list-style: none;
335 list-style: none;
336 margin-left: -16px;
336 margin-left: -16px;
337 }
337 }
338
338
339 /*========== Drop down menu ==============*/
339 /*========== Drop down menu ==============*/
340 div.menu {
340 div.menu {
341 background-color: #FFFFFF;
341 background-color: #FFFFFF;
342 border-style: solid;
342 border-style: solid;
343 border-width: 1px;
343 border-width: 1px;
344 border-color: #7F9DB9;
344 border-color: #7F9DB9;
345 position: absolute;
345 position: absolute;
346 top: 0px;
346 top: 0px;
347 left: 0px;
347 left: 0px;
348 padding: 0;
348 padding: 0;
349 visibility: hidden;
349 visibility: hidden;
350 z-index: 101;
350 z-index: 101;
351 }
351 }
352
352
353 div.menu a.menuItem {
353 div.menu a.menuItem {
354 font-size: 10px;
354 font-size: 10px;
355 font-weight: normal;
355 font-weight: normal;
356 line-height: 2em;
356 line-height: 2em;
357 color: #000000;
357 color: #000000;
358 background-color: #FFFFFF;
358 background-color: #FFFFFF;
359 cursor: default;
359 cursor: default;
360 display: block;
360 display: block;
361 padding: 0 1em;
361 padding: 0 1em;
362 margin: 0;
362 margin: 0;
363 border: 0;
363 border: 0;
364 text-decoration: none;
364 text-decoration: none;
365 white-space: nowrap;
365 white-space: nowrap;
366 }
366 }
367
367
368 div.menu a.menuItem:hover, div.menu a.menuItemHighlight {
368 div.menu a.menuItem:hover, div.menu a.menuItemHighlight {
369 background-color: #80b0da;
369 background-color: #80b0da;
370 color: #ffffff;
370 color: #ffffff;
371 }
371 }
372
372
373 div.menu a.menuItem span.menuItemText {}
373 div.menu a.menuItem span.menuItemText {}
374
374
375 div.menu a.menuItem span.menuItemArrow {
375 div.menu a.menuItem span.menuItemArrow {
376 margin-right: -.75em;
376 margin-right: -.75em;
377 }
377 }
378
378
379 /**************** Sidebar styles ****************/
379 /**************** Sidebar styles ****************/
380
380
381 #subcontent{
381 #subcontent{
382 position: absolute;
382 position: absolute;
383 left: 0px;
383 left: 0px;
384 width:110px;
384 width:110px;
385 padding:20px 20px 10px 5px;
385 padding:20px 20px 10px 5px;
386 }
386 }
387
387
388 #subcontent h2{
388 #subcontent h2{
389 display:block;
389 display:block;
390 margin:0 0 5px 0;
390 margin:0 0 5px 0;
391 font-size:1.0em;
391 font-size:1.0em;
392 font-weight:bold;
392 font-weight:bold;
393 text-align:left;
393 text-align:left;
394 color:#606060;
394 color:#606060;
395 background-color:inherit;
395 background-color:inherit;
396 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
396 font-family: Trebuchet MS,Georgia,"Times New Roman",serif;
397 }
397 }
398
398
399 #subcontent p{margin:0 0 16px 0; font-size:0.9em;}
399 #subcontent p{margin:0 0 16px 0; font-size:0.9em;}
400
400
401 /**************** Menublock styles ****************/
401 /**************** Menublock styles ****************/
402
402
403 .menublock{margin:0 0 20px 8px; font-size:0.8em;}
403 .menublock{margin:0 0 20px 8px; font-size:0.8em;}
404 .menublock li{list-style:none; display:block; padding:1px; margin-bottom:0px;}
404 .menublock li{list-style:none; display:block; padding:1px; margin-bottom:0px;}
405 .menublock li a{font-weight:bold; text-decoration:none;}
405 .menublock li a{font-weight:bold; text-decoration:none;}
406 .menublock li a:hover{text-decoration:none;}
406 .menublock li a:hover{text-decoration:none;}
407 .menublock li ul{margin:0; font-size:1em; font-weight:normal;}
407 .menublock li ul{margin:0; font-size:1em; font-weight:normal;}
408 .menublock li ul li{margin-bottom:0;}
408 .menublock li ul li{margin-bottom:0;}
409 .menublock li ul a{font-weight:normal;}
409 .menublock li ul a{font-weight:normal;}
410
410
411 /**************** Footer styles ****************/
411 /**************** Footer styles ****************/
412
412
413 #footer{
413 #footer{
414 clear:both;
414 clear:both;
415 padding:5px 0;
415 padding:5px 0;
416 margin:0;
416 margin:0;
417 font-size:0.9em;
417 font-size:0.9em;
418 color:#f0f0f0;
418 color:#f0f0f0;
419 background:#467aa7;
419 background:#467aa7;
420 }
420 }
421
421
422 #footer p{padding:0; margin:0; text-align:center;}
422 #footer p{padding:0; margin:0; text-align:center;}
423 #footer a{color:#f0f0f0; background-color:inherit; font-weight:bold;}
423 #footer a{color:#f0f0f0; background-color:inherit; font-weight:bold;}
424 #footer a:hover{color:#ffffff; background-color:inherit; text-decoration: underline;}
424 #footer a:hover{color:#ffffff; background-color:inherit; text-decoration: underline;}
425
425
426 /**************** Misc classes and styles ****************/
426 /**************** Misc classes and styles ****************/
427
427
428 .splitcontentleft{float:left; width:49%;}
428 .splitcontentleft{float:left; width:49%;}
429 .splitcontentright{float:right; width:49%;}
429 .splitcontentright{float:right; width:49%;}
430 .clear{clear:both;}
430 .clear{clear:both;}
431 .small{font-size:0.8em;line-height:1.4em;padding:0 0 0 0;}
431 .small{font-size:0.8em;line-height:1.4em;padding:0 0 0 0;}
432 .hide{display:none;}
432 .hide{display:none;}
433 .textcenter{text-align:center;}
433 .textcenter{text-align:center;}
434 .textright{text-align:right;}
434 .textright{text-align:right;}
435 .important{color:#f02025; background-color:inherit; font-weight:bold;}
435 .important{color:#f02025; background-color:inherit; font-weight:bold;}
436
436
437 .box{
437 .box{
438 margin:0 0 20px 0;
438 margin:0 0 20px 0;
439 padding:10px;
439 padding:10px;
440 border:1px solid #c0c0c0;
440 border:1px solid #c0c0c0;
441 background-color:#fafbfc;
441 background-color:#fafbfc;
442 color:#505050;
442 color:#505050;
443 line-height:1.5em;
443 line-height:1.5em;
444 }
444 }
445
445
446 a.close-icon {
446 a.close-icon {
447 display:block;
447 display:block;
448 margin-top:3px;
448 margin-top:3px;
449 overflow:hidden;
449 overflow:hidden;
450 width:12px;
450 width:12px;
451 height:12px;
451 height:12px;
452 background-repeat: no-repeat;
452 background-repeat: no-repeat;
453 cursor:pointer;
453 cursor:pointer;
454 background-image:url('../images/close.png');
454 background-image:url('../images/close.png');
455 }
455 }
456
456
457 a.close-icon:hover {
457 a.close-icon:hover {
458 background-image:url('../images/close_hl.png');
458 background-image:url('../images/close_hl.png');
459 }
459 }
460
460
461 .rightbox{
461 .rightbox{
462 background: #fafbfc;
462 background: #fafbfc;
463 border: 1px solid #c0c0c0;
463 border: 1px solid #c0c0c0;
464 float: right;
464 float: right;
465 padding: 8px;
465 padding: 8px;
466 position: relative;
466 position: relative;
467 margin: 0 5px 5px;
467 margin: 0 5px 5px;
468 }
468 }
469
469
470 .overlay{
470 .overlay{
471 position: absolute;
471 position: absolute;
472 margin-left:0;
472 margin-left:0;
473 z-index: 50;
473 z-index: 50;
474 }
474 }
475
475
476 .layout-active {
476 .layout-active {
477 background: #ECF3E1;
477 background: #ECF3E1;
478 }
478 }
479
479
480 .block-receiver {
480 .block-receiver {
481 border:1px dashed #c0c0c0;
481 border:1px dashed #c0c0c0;
482 margin-bottom: 20px;
482 margin-bottom: 20px;
483 padding: 15px 0 15px 0;
483 padding: 15px 0 15px 0;
484 }
484 }
485
485
486 .mypage-box {
486 .mypage-box {
487 margin:0 0 20px 0;
487 margin:0 0 20px 0;
488 color:#505050;
488 color:#505050;
489 line-height:1.5em;
489 line-height:1.5em;
490 }
490 }
491
491
492 .handle {
492 .handle {
493 cursor: move;
493 cursor: move;
494 }
494 }
495
495
496 .login {
496 .login {
497 width: 50%;
497 width: 50%;
498 text-align: left;
498 text-align: left;
499 }
499 }
500
500
501 img.calendar-trigger {
501 img.calendar-trigger {
502 cursor: pointer;
502 cursor: pointer;
503 vertical-align: middle;
503 vertical-align: middle;
504 margin-left: 4px;
504 margin-left: 4px;
505 }
505 }
506
506
507 #history p {
507 #history p {
508 margin-left: 34px;
508 margin-left: 34px;
509 }
509 }
510
510
511 .progress {
511 .progress {
512 border: 1px solid #D7D7D7;
512 border: 1px solid #D7D7D7;
513 border-collapse: collapse;
513 border-collapse: collapse;
514 border-spacing: 0pt;
514 border-spacing: 0pt;
515 empty-cells: show;
515 empty-cells: show;
516 padding: 3px;
516 padding: 3px;
517 width: 40em;
517 width: 40em;
518 text-align: center;
518 text-align: center;
519 }
519 }
520
520
521 .progress td { height: 1em; }
521 .progress td { height: 1em; }
522 .progress .closed { background: #BAE0BA none repeat scroll 0%; }
522 .progress .closed { background: #BAE0BA none repeat scroll 0%; }
523 .progress .open { background: #FFF none repeat scroll 0%; }
523 .progress .open { background: #FFF none repeat scroll 0%; }
524
524
525 /***** Contextual links div *****/
525 /***** Contextual links div *****/
526 .contextual {
526 .contextual {
527 float: right;
527 float: right;
528 font-size: 0.8em;
528 font-size: 0.8em;
529 line-height: 16px;
529 line-height: 16px;
530 padding: 2px;
530 padding: 2px;
531 }
531 }
532
532
533 .contextual select, .contextual input {
533 .contextual select, .contextual input {
534 font-size: 1em;
534 font-size: 1em;
535 }
535 }
536
536
537 /***** Gantt chart *****/
537 /***** Gantt chart *****/
538 .gantt_hdr {
538 .gantt_hdr {
539 position:absolute;
539 position:absolute;
540 top:0;
540 top:0;
541 height:16px;
541 height:16px;
542 border-top: 1px solid #c0c0c0;
542 border-top: 1px solid #c0c0c0;
543 border-bottom: 1px solid #c0c0c0;
543 border-bottom: 1px solid #c0c0c0;
544 border-right: 1px solid #c0c0c0;
544 border-right: 1px solid #c0c0c0;
545 text-align: center;
545 text-align: center;
546 overflow: hidden;
546 overflow: hidden;
547 }
547 }
548
548
549 .task {
549 .task {
550 position: absolute;
550 position: absolute;
551 height:8px;
551 height:8px;
552 font-size:0.8em;
552 font-size:0.8em;
553 color:#888;
553 color:#888;
554 padding:0;
554 padding:0;
555 margin:0;
555 margin:0;
556 line-height:0.8em;
556 line-height:0.8em;
557 }
557 }
558
558
559 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
559 .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; }
560 .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
560 .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; }
561 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
561 .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; }
562 .milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; }
562
563
563 /***** Tooltips ******/
564 /***** Tooltips ******/
564 .tooltip{position:relative;z-index:24;}
565 .tooltip{position:relative;z-index:24;}
565 .tooltip:hover{z-index:25;color:#000;}
566 .tooltip:hover{z-index:25;color:#000;}
566 .tooltip span.tip{display: none; text-align:left;}
567 .tooltip span.tip{display: none; text-align:left;}
567
568
568 div.tooltip:hover span.tip{
569 div.tooltip:hover span.tip{
569 display:block;
570 display:block;
570 position:absolute;
571 position:absolute;
571 top:12px; left:24px; width:270px;
572 top:12px; left:24px; width:270px;
572 border:1px solid #555;
573 border:1px solid #555;
573 background-color:#fff;
574 background-color:#fff;
574 padding: 4px;
575 padding: 4px;
575 font-size: 0.8em;
576 font-size: 0.8em;
576 color:#505050;
577 color:#505050;
577 }
578 }
578
579
579 /***** CSS FORM ******/
580 /***** CSS FORM ******/
580 .tabular p{
581 .tabular p{
581 margin: 0;
582 margin: 0;
582 padding: 5px 0 8px 0;
583 padding: 5px 0 8px 0;
583 padding-left: 180px; /*width of left column containing the label elements*/
584 padding-left: 180px; /*width of left column containing the label elements*/
584 height: 1%;
585 height: 1%;
585 }
586 }
586
587
587 .tabular label{
588 .tabular label{
588 font-weight: bold;
589 font-weight: bold;
589 float: left;
590 float: left;
590 margin-left: -180px; /*width of left column*/
591 margin-left: -180px; /*width of left column*/
591 width: 175px; /*width of labels. Should be smaller than left column to create some right
592 width: 175px; /*width of labels. Should be smaller than left column to create some right
592 margin*/
593 margin*/
593 }
594 }
594
595
595 .error {
596 .error {
596 color: #cc0000;
597 color: #cc0000;
597 }
598 }
598
599
599 #settings .tabular p{ padding-left: 250px; }
600 #settings .tabular p{ padding-left: 250px; }
600 #settings .tabular label{ margin-left: -250px; width: 245px; }
601 #settings .tabular label{ margin-left: -250px; width: 245px; }
601
602
602 /*.threepxfix class below:
603 /*.threepxfix class below:
603 Targets IE6- ONLY. Adds 3 pixel indent for multi-line form contents.
604 Targets IE6- ONLY. Adds 3 pixel indent for multi-line form contents.
604 to account for 3 pixel bug: http://www.positioniseverything.net/explorer/threepxtest.html
605 to account for 3 pixel bug: http://www.positioniseverything.net/explorer/threepxtest.html
605 */
606 */
606
607
607 * html .threepxfix{
608 * html .threepxfix{
608 margin-left: 3px;
609 margin-left: 3px;
609 }
610 }
610
611
611 /***** Wiki sections ****/
612 /***** Wiki sections ****/
612 #content div.wiki { font-size: 110%}
613 #content div.wiki { font-size: 110%}
613
614
614 #content div.wiki h2, div.wiki h3 { font-family: Trebuchet MS,Georgia,"Times New Roman",serif; color:#606060; }
615 #content div.wiki h2, div.wiki h3 { font-family: Trebuchet MS,Georgia,"Times New Roman",serif; color:#606060; }
615 #content div.wiki h2 { font-size: 1.4em;}
616 #content div.wiki h2 { font-size: 1.4em;}
616 #content div.wiki h3 { font-size: 1.2em;}
617 #content div.wiki h3 { font-size: 1.2em;}
617
618
618 div.wiki table {
619 div.wiki table {
619 border: 1px solid #505050;
620 border: 1px solid #505050;
620 border-collapse: collapse;
621 border-collapse: collapse;
621 }
622 }
622
623
623 div.wiki table, div.wiki td {
624 div.wiki table, div.wiki td {
624 border: 1px solid #bbb;
625 border: 1px solid #bbb;
625 padding: 4px;
626 padding: 4px;
626 }
627 }
627
628
628 div.wiki code {
629 div.wiki code {
629 font-size: 1.2em;
630 font-size: 1.2em;
630 }
631 }
631
632
632 #preview .preview { background: #fafbfc url(../images/draft.png); }
633 #preview .preview { background: #fafbfc url(../images/draft.png); }
General Comments 0
You need to be logged in to leave comments. Login now