# encoding: UTF-8
module Axlsx
# Table
# @note Worksheet#add_pivot_table is the recommended way to create tables for your worksheets.
# @see README for examples
class PivotTable
include Axlsx::OptionsParser
# Creates a new PivotTable object
# @param [String] ref The reference to where the pivot table lives like 'G4:L17'.
# @param [String] range The reference to the pivot table data like 'A1:D31'.
# @param [Worksheet] sheet The sheet containing the table data.
# @option options [Cell, String] name
# @option options [TableStyle] style
def initialize(ref, range, sheet, options={})
@ref = ref
self.range = range
@sheet = sheet
@sheet.workbook.pivot_tables << self
@name = "PivotTable#{index+1}"
@rows = []
@columns = []
@data = []
@pages = []
parse_options options
yield self if block_given?
end
# The reference to the table data
# @return [String]
attr_reader :ref
# The name of the table.
# @return [String]
attr_reader :name
# The name of the sheet.
# @return [String]
attr_reader :sheet
# The range where the data for this pivot table lives.
# @return [String]
attr_reader :range
# (see #range)
def range=(v)
DataTypeValidator.validate "#{self.class}.range", [String], v
if v.is_a?(String)
@range = v
end
end
# The rows
# @return [Array]
attr_reader :rows
# (see #rows)
def rows=(v)
DataTypeValidator.validate "#{self.class}.rows", [Array], v
v.each do |ref|
DataTypeValidator.validate "#{self.class}.rows[]", [String], ref
end
@rows = v
end
# The columns
# @return [Array]
attr_reader :columns
# (see #columns)
def columns=(v)
DataTypeValidator.validate "#{self.class}.columns", [Array], v
v.each do |ref|
DataTypeValidator.validate "#{self.class}.columns[]", [String], ref
end
@columns = v
end
# The data
# @return [Array]
attr_reader :data
# (see #data)
def data=(v)
DataTypeValidator.validate "#{self.class}.data", [Array], v
v.each do |ref|
DataTypeValidator.validate "#{self.class}.data[]", [String], ref
end
@data = v
end
# The pages
# @return [String]
attr_reader :pages
# (see #pages)
def pages=(v)
DataTypeValidator.validate "#{self.class}.pages", [Array], v
v.each do |ref|
DataTypeValidator.validate "#{self.class}.pages[]", [String], ref
end
@pages = v
end
# The index of this chart in the workbooks charts collection
# @return [Integer]
def index
@sheet.workbook.pivot_tables.index(self)
end
# The part name for this table
# @return [String]
def pn
"#{PIVOT_TABLE_PN % (index+1)}"
end
# The relationship part name of this pivot table
# @return [String]
def rels_pn
"#{PIVOT_TABLE_RELS_PN % (index+1)}"
end
# The cache_definition for this pivot table
# @return [PivotTableCacheDefinition]
def cache_definition
@cache_definition ||= PivotTableCacheDefinition.new(self)
end
# The worksheet relationships. This is managed automatically by the worksheet
# @return [Relationships]
def relationships
r = Relationships.new
r << Relationship.new(PIVOT_TABLE_CACHE_DEFINITION_R, "../#{cache_definition.pn}")
r
end
# The relation reference id for this table
# @return [String]
def rId
"rId#{index+1}"
end
# Serializes the object
# @param [String] str
# @return [String]
def to_xml_string(str = '')
str << ''
str << ''
str << ''
str << ''
header_cell_values.each do |cell_value|
str << pivot_field_for(cell_value)
end
str << ''
if rows.empty?
str << ''
str << ' '
else
str << ''
rows.each do |row_value|
str << ''
end
str << ''
str << ''
rows.size.times do |i|
str << ''
end
str << ''
end
if columns.empty?
str << ''
else
str << ''
columns.each do |column_value|
str << ''
end
str << ''
end
unless pages.empty?
str << ''
pages.each do |page_value|
str << ''
end
str << ''
end
unless data.empty?
str << ''
data.each do |datum_value|
str << ''
end
str << ''
end
str << ''
end
# References for header cells
# @return [Array]
def header_cell_refs
Axlsx::range_to_a(header_range).first
end
# The header cells for the pivot table
# @return [Array]
def header_cells
@sheet[header_range]
end
# The values in the header cells collection
# @return [Array]
def header_cell_values
header_cells.map(&:value)
end
# The number of cells in the header_cells collection
# @return [Integer]
def header_cells_count
header_cells.count
end
# The index of a given value in the header cells
# @return [Integer]
def header_index_of(value)
header_cell_values.index(value)
end
private
def pivot_field_for(cell_ref)
if rows.include? cell_ref
'' <<
' ' <<
''
elsif columns.include? cell_ref
'' <<
' ' <<
''
elsif pages.include? cell_ref
'' <<
' ' <<
''
elsif data.include? cell_ref
'' <<
''
else
'' <<
''
end
end
def header_range
range.gsub(/^(\w+?)(\d+)\:(\w+?)\d+$/, '\1\2:\3\2')
end
end
end