Fix module namespaces

pull/6827/head
Michael Frister 11 years ago committed by Michael Frister
parent 2eaf168c26
commit fc112adc42
  1. 12
      lib/open_project/xls_export/filename_helper.rb
  2. 50
      lib/open_project/xls_export/filter_settings_helper.rb
  3. 117
      lib/open_project/xls_export/patches/issues_controller_patch.rb
  4. 263
      lib/open_project/xls_export/spreadsheet_builder.rb

@ -1,7 +1,9 @@
class FilenameHelper
# Remove characters that could cause problems on popular OSses
# => A string that does not start with a space or dot and does not contain any of \/:*?"<>|
def self.sane_filename(str)
str.gsub(/^[ \.]/,"").gsub(/[\\\/:\*\?"<>|"]/, "_")
module OpenProject::XlsExport
class FilenameHelper
# Remove characters that could cause problems on popular OSses
# => A string that does not start with a space or dot and does not contain any of \/:*?"<>|
def self.sane_filename(str)
str.gsub(/^[ \.]/,"").gsub(/[\\\/:\*\?"<>|"]/, "_")
end
end
end

@ -1,27 +1,29 @@
class FilterSettingsHelper
class << self
def group_by_setting(query)
I18n.t("field_#{query.group_by.to_s.gsub(/\_id$/, "")}") if query.group_by
end
def filter_settings(query)
filters = query.available_filters
filters.sort{|a,b| a[1][:order] <=> b[1][:order]}.collect do |field, options|
if query.has_filter? field
o = query.filters[field.to_s][:operator]
((options[:name] || I18n.t(("field_#{field.to_s.gsub(/\_id$/, "")}"))) + " " +
I18n.t(Query.operators[o], :default => o.to_s) + " " +
query.values_for(field).collect do |v|
if options[:values]
options[:values].detect do |o|
o[1] == v
module OpenProject::XlsExport
class FilterSettingsHelper
class << self
def group_by_setting(query)
I18n.t("field_#{query.group_by.to_s.gsub(/\_id$/, "")}") if query.group_by
end
def filter_settings(query)
filters = query.available_filters
filters.sort{|a,b| a[1][:order] <=> b[1][:order]}.collect do |field, options|
if query.has_filter? field
o = query.filters[field.to_s][:operator]
((options[:name] || I18n.t(("field_#{field.to_s.gsub(/\_id$/, "")}"))) + " " +
I18n.t(Query.operators[o], :default => o.to_s) + " " +
query.values_for(field).collect do |v|
if options[:values]
options[:values].detect do |o|
o[1] == v
end
else
[v]
end
else
[v]
end
end.compact.collect(&:first).join(" #{I18n.t(:sentence_separator_or)} "))
end
end.compact
end.compact.collect(&:first).join(" #{I18n.t(:sentence_separator_or)} "))
end
end.compact
end
end
end
end
end

@ -2,79 +2,82 @@
#require_dependency 'xls_report/spreadsheet_builder'
#require_dependency 'additional_formats/filter_settings_helper'
module OpenProject::XlsExport::Patches
module IssuesControllerPatch
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
module OpenProject::XlsExport
module Patches
module IssuesControllerPatch
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
base.class_eval do
unloadable
end
end
end
module InstanceMethods
module InstanceMethods
# If the index action is called, hook the xls format into the issues controller
def respond_to(&block)
if ((params["action"].to_sym == :index or params[:action] == "all") && params["format"].to_s.downcase == "xls")
super do |format|
yield format
format.xls do
@issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
:order => sort_clause)
unless @issues.empty?
send_data(issues_to_xls, :type => "application/vnd.ms-excel",
:filename => FilenameHelper.sane_filename("(#{I18n.l(DateTime.now)}) Issue Report#{" " + @project.name if @project}.xls"))
# If the index action is called, hook the xls format into the issues controller
def respond_to(&block)
if ((params["action"].to_sym == :index or params[:action] == "all") && params["format"].to_s.downcase == "xls")
super do |format|
yield format
format.xls do
@issues = @query.issues(:include => [:assigned_to, :type, :priority, :category, :fixed_version],
:order => sort_clause)
unless @issues.empty?
send_data(issues_to_xls, :type => "application/vnd.ms-excel",
:filename => FilenameHelper.sane_filename("(#{I18n.l(DateTime.now)}) Issue Report#{" " + @project.name if @project}.xls"))
end
end
end
else
super(&block)
end
else
super(&block)
end
end
# Convert an issues query with associated issues to xls using the queries columns as headers
def build_spreadsheet(project, issues, query)
columns = query.columns
sb = SpreadsheetBuilder.new
project_name = (project.name if project) || "All Projects"
sb.add_title("#{project_name} >> #{l(:label_issue_plural)} (#{format_date(Date.today)})")
# Convert an issues query with associated issues to xls using the queries columns as headers
def build_spreadsheet(project, issues, query)
columns = query.columns
filters = FilterSettingsHelper.filter_settings(query)
sb.add_headers l(:label_filter_plural)
sb.add_row(filters)
group_by_settings = FilterSettingsHelper.group_by_setting(query)
if group_by_settings
sb.add_headers l(:field_group_by)
sb.add_row group_by_settings
end
sb.add_empty_row
sb = SpreadsheetBuilder.new
project_name = (project.name if project) || "All Projects"
sb.add_title("#{project_name} >> #{l(:label_issue_plural)} (#{format_date(Date.today)})")
headers = (columns.collect(&:caption) << l(:field_description)).unshift("#")
sb.add_headers headers
filters = FilterSettingsHelper.filter_settings(query)
sb.add_headers l(:label_filter_plural)
sb.add_row(filters)
group_by_settings = FilterSettingsHelper.group_by_setting(query)
if group_by_settings
sb.add_headers l(:field_group_by)
sb.add_row group_by_settings
end
sb.add_empty_row
issues.each do |issue|
sb.add_row((columns.collect do |column|
cv = column.value(issue)
(cv.respond_to? :name) ? cv.name : cv
end << issue.description).unshift(issue.id))
end
headers = (columns.collect(&:caption) << l(:field_description)).unshift("#")
sb.add_headers headers
headers.each_with_index do |h,idx|
h = h.to_s.downcase
if (h =~ /.*hours.*/ or h == "spent_time")
sb.add_format_option_to_column idx, :number_format => "0.0 h"
elsif (h =~ /.*cost.*/)
sb.add_format_option_to_column idx, :number_format => number_to_currency(0.00)
issues.each do |issue|
sb.add_row((columns.collect do |column|
cv = column.value(issue)
(cv.respond_to? :name) ? cv.name : cv
end << issue.description).unshift(issue.id))
end
end
sb
end
headers.each_with_index do |h,idx|
h = h.to_s.downcase
if (h =~ /.*hours.*/ or h == "spent_time")
sb.add_format_option_to_column idx, :number_format => "0.0 h"
elsif (h =~ /.*cost.*/)
sb.add_format_option_to_column idx, :number_format => number_to_currency(0.00)
end
end
# Return an xls file from a spreadsheet builder
def issues_to_xls
build_spreadsheet(@project, @issues, @query).xls
sb
end
# Return an xls file from a spreadsheet builder
def issues_to_xls
build_spreadsheet(@project, @issues, @query).xls
end
end
end
end

@ -11,165 +11,168 @@ require 'spreadsheet'
# If a worksheet with an index larger than the number of worksheets is requested,
# a new worksheet is created.
#
class SpreadsheetBuilder
Worksheet = Struct.new(:sheet, :column_widths) unless defined? Worksheet
module OpenProject::XlsExport
class SpreadsheetBuilder
def initialize(name = nil)
Spreadsheet.client_encoding = 'UTF-8'
@xls = Spreadsheet::Workbook.new
@worksheets = []
worksheet(0, name)
end
Worksheet = Struct.new(:sheet, :column_widths) unless defined? Worksheet
# Retrieve or create the worksheet at index x
def worksheet(idx, name = nil)
name ||= "Worksheet #{@worksheets.length + 1}"
if @worksheets[idx].nil?
@worksheets[idx] = Worksheet.new.tap do |wb|
wb.sheet = @xls.create_worksheet(:name => name)
wb.column_widths = []
end
def initialize(name = nil)
Spreadsheet.client_encoding = 'UTF-8'
@xls = Spreadsheet::Workbook.new
@worksheets = []
worksheet(0, name)
end
@sheet = @worksheets[idx].sheet
@column_widths = @worksheets[idx].column_widths
end
# Retrieve or create the worksheet at index x
def worksheet(idx, name = nil)
name ||= "Worksheet #{@worksheets.length + 1}"
if @worksheets[idx].nil?
@worksheets[idx] = Worksheet.new.tap do |wb|
wb.sheet = @xls.create_worksheet(:name => name)
wb.column_widths = []
end
end
# Update column widths and wrap text if neccessary
def update_sheet_widths
@column_widths.count.times do |idx|
if @column_widths[idx] > 60
@sheet.column(idx).width = 60
@sheet.rows.each do |row|
fmt = row.formats[idx] || @sheet.column(idx).default_format
fmt.text_wrap = true
row.set_format(idx, fmt)
@sheet = @worksheets[idx].sheet
@column_widths = @worksheets[idx].column_widths
end
# Update column widths and wrap text if neccessary
def update_sheet_widths
@column_widths.count.times do |idx|
if @column_widths[idx] > 60
@sheet.column(idx).width = 60
@sheet.rows.each do |row|
fmt = row.formats[idx] || @sheet.column(idx).default_format
fmt.text_wrap = true
row.set_format(idx, fmt)
end
else
@sheet.column(idx).width = @column_widths[idx]
end
else
@sheet.column(idx).width = @column_widths[idx]
end
end
end
# Get the approximate width of a value as seen in the excel sheet
def get_value_width(value)
if ['Time', 'Date'].include?(value.class.name)
return 18 unless value.to_s.length < 18
# Get the approximate width of a value as seen in the excel sheet
def get_value_width(value)
if ['Time', 'Date'].include?(value.class.name)
return 18 unless value.to_s.length < 18
end
tot_w = [Float(0)]
idx=0
value.to_s.each_char do |c|
case c
when '0'..'9'
tot_w[idx] += 1.2
when '.', ';', ':', ',', ' ', 'i', 'I', 'j', 'J', '(', ')', '[', ']', '!', '-', 't', 'l'
tot_w[idx] += 0.7
when 'W', 'M', 'D'
tot_w[idx] += 1.2
when "\n"
idx = idx + 1
tot_w << Float(0)
else
tot_w[idx] += 1.05
end
end
wdth=0
tot_w.each do |w|
wdth = w unless w<wdth
end
return wdth+1.5
end
tot_w = [Float(0)]
idx=0
value.to_s.each_char do |c|
case c
when '0'..'9'
tot_w[idx] += 1.2
when '.', ';', ':', ',', ' ', 'i', 'I', 'j', 'J', '(', ')', '[', ']', '!', '-', 't', 'l'
tot_w[idx] += 0.7
when 'W', 'M', 'D'
tot_w[idx] += 1.2
when "\n"
idx = idx + 1
tot_w << Float(0)
# Add a "Title". This basically just set the first column to
# the passed text and makes it bold and larger (font-size 18)
def add_title(arr_or_str)
if arr_or_str.respond_to? :to_str
@sheet[0, 0] = arr_or_str
else
tot_w[idx] += 1.05
@sheet.row(0).concat arr_or_str
value_width = get_value_width(arr_or_str[0] * 2)
@column_widths[0] = value_width if (@column_widths[0] || 0) < value_width
end
title_format = Spreadsheet::Format.new(:weight => :bold, :size => 18)
@sheet.row(0).set_format(0, title_format)
end
wdth=0
tot_w.each do |w|
wdth = w unless w<wdth
# Add an empty row in the next sequential position. Convenience method
# for calling add_row([""])
def add_empty_row
add_row([""])
end
return wdth+1.5
end
# Add a "Title". This basically just set the first column to
# the passed text and makes it bold and larger (font-size 18)
def add_title(arr_or_str)
if arr_or_str.respond_to? :to_str
@sheet[0, 0] = arr_or_str
else
@sheet.row(0).concat arr_or_str
value_width = get_value_width(arr_or_str[0] * 2)
@column_widths[0] = value_width if (@column_widths[0] || 0) < value_width
# Add headers. This is usually used for adding a table header to the
# second row in the document, but the row can be set using the second
# optional parameter. The format is automatically set to bold font
def add_headers(arr, idx = nil)
header_format = Spreadsheet::Format.new(:weight => :bold)
add_row(arr, idx)
idx ||= @sheet.last_row_index
(arr.size + 1).times { |i| @sheet.row(idx).set_format(i, header_format) }
end
title_format = Spreadsheet::Format.new(:weight => :bold, :size => 18)
@sheet.row(0).set_format(0, title_format)
end
# Add an empty row in the next sequential position. Convenience method
# for calling add_row([""])
def add_empty_row
add_row([""])
end
# Add headers. This is usually used for adding a table header to the
# second row in the document, but the row can be set using the second
# optional parameter. The format is automatically set to bold font
def add_headers(arr, idx = nil)
header_format = Spreadsheet::Format.new(:weight => :bold)
add_row(arr, idx)
idx ||= @sheet.last_row_index
(arr.size + 1).times { |i| @sheet.row(idx).set_format(i, header_format) }
end
# Add a simple row. This will default to the next row in the sequence.
# Fixnums, Dates and Times are preserved, all other types are converted
# to String as the spreadsheet gem cannot do more formats
def add_row(arr, idx = nil)
idx ||= [@sheet.last_row_index + 1, 1].max
column_array = []
arr.each_with_index do |c,i|
value = if ['Time', 'Date', 'Fixnum', 'Float', 'Integer'].include?(c.class.name)
c
elsif c.class == BigDecimal
c.to_f
else
c.to_s.gsub('_', ' ').gsub("\r\n", "\n").gsub("\r", "\n")
# Add a simple row. This will default to the next row in the sequence.
# Fixnums, Dates and Times are preserved, all other types are converted
# to String as the spreadsheet gem cannot do more formats
def add_row(arr, idx = nil)
idx ||= [@sheet.last_row_index + 1, 1].max
column_array = []
arr.each_with_index do |c,i|
value = if ['Time', 'Date', 'Fixnum', 'Float', 'Integer'].include?(c.class.name)
c
elsif c.class == BigDecimal
c.to_f
else
c.to_s.gsub('_', ' ').gsub("\r\n", "\n").gsub("\r", "\n")
end
column_array << value
@column_widths[i] = 0 if @column_widths[i].nil?
value_width = get_value_width(value)
@column_widths[i] = value_width if @column_widths[i] < value_width
end
column_array << value
@column_widths[i] = 0 if @column_widths[i].nil?
value_width = get_value_width(value)
@column_widths[i] = value_width if @column_widths[i] < value_width
@sheet.row(idx).concat column_array
end
@sheet.row(idx).concat column_array
end
# Add a default format to the column at index
def add_format_option_to_column(index, opt)
unless opt.empty?
fmt = @sheet.column(index).default_format
opt.each do |k,v|
fmt.send(:"#{k.to_sym}=", v) if fmt.respond_to? :"#{k.to_sym}="
# Add a default format to the column at index
def add_format_option_to_column(index, opt)
unless opt.empty?
fmt = @sheet.column(index).default_format
opt.each do |k,v|
fmt.send(:"#{k.to_sym}=", v) if fmt.respond_to? :"#{k.to_sym}="
end
@sheet.column(index).default_format = fmt
end
@sheet.column(index).default_format = fmt
end
end
# Return the next free row we would write to in natural indexing (Starting at 1)
def current_row
@sheet.row_count
end
# Return the next free row we would write to in natural indexing (Starting at 1)
def current_row
@sheet.row_count
end
# Return the xls file as a string
def xls
@worksheets.length.times do |i|
worksheet(i)
update_sheet_widths
# Return the xls file as a string
def xls
@worksheets.length.times do |i|
worksheet(i)
update_sheet_widths
end
io = StringIO.new
@xls.write(io)
io.rewind
io.read
end
io = StringIO.new
@xls.write(io)
io.rewind
io.read
end
private
def raw_xls
@xls
end
private
def raw_xls
@xls
end
def raw_sheet
@sheet
def raw_sheet
@sheet
end
end
end

Loading…
Cancel
Save