lib/rubyXL/convenience_methods.rb in rubyXL-3.3.33 vs lib/rubyXL/convenience_methods.rb in rubyXL-3.4.0
- old
+ new
@@ -1,1301 +1,5 @@
-module RubyXL
-
- module WorkbookConvenienceMethods
- SHEET_NAME_TEMPLATE = 'Sheet%d'
-
- # Finds worksheet by its name or numerical index
- def [](ind)
- case ind
- when Integer then worksheets[ind]
- when String then worksheets.find { |ws| ws.sheet_name == ind }
- end
- end
-
- # Create new simple worksheet and add it to the workbook worksheets
- #
- # @param [String] The name for the new worksheet
- def add_worksheet(name = nil)
- if name.nil? then
- n = 0
-
- begin
- name = SHEET_NAME_TEMPLATE % (n += 1)
- end until self[name].nil?
- end
-
- new_worksheet = Worksheet.new(:workbook => self, :sheet_name => name)
- worksheets << new_worksheet
- new_worksheet
- end
-
- def each
- worksheets.each{ |i| yield i }
- end
-
- def date1904
- workbook_properties && workbook_properties.date1904
- end
-
- def date1904=(v)
- self.workbook_properties ||= RubyXL::WorkbookProperties.new
- workbook_properties.date1904 = v
- end
-
- def company
- root.document_properties.company && root.document_properties.company.value
- end
-
- def company=(v)
- root.document_properties.company ||= StringNode.new
- root.document_properties.company.value = v
- end
-
- def application
- root.document_properties.application && root.document_properties.application.value
- end
-
- def application=(v)
- root.document_properties.application ||= StringNode.new
- root.document_properties.application.value = v
- end
-
- def appversion
- root.document_properties.app_version && root.document_properties.app_version.value
- end
-
- def appversion=(v)
- root.document_properties.app_version ||= StringNode.new
- root.document_properties.app_version.value = v
- end
-
- def creator
- root.core_properties.creator
- end
-
- def creator=(v)
- root.core_properties.creator = v
- end
-
- def modifier
- root.core_properties.modifier
- end
-
- def modifier=(v)
- root.core_properties.modifier = v
- end
-
- def created_at
- root.core_properties.created_at
- end
-
- def created_at=(v)
- root.core_properties.created_at = v
- end
-
- def modified_at
- root.core_properties.modified_at
- end
-
- def modified_at=(v)
- root.core_properties.modified_at = v
- end
-
- def cell_xfs # Stylesheet should be pre-filled with defaults on initialize()
- stylesheet.cell_xfs
- end
-
- def fonts # Stylesheet should be pre-filled with defaults on initialize()
- stylesheet.fonts
- end
-
- def fills # Stylesheet should be pre-filled with defaults on initialize()
- stylesheet.fills
- end
-
- def borders # Stylesheet should be pre-filled with defaults on initialize()
- stylesheet.borders
- end
-
- def get_fill_color(xf)
- fill = fills[xf.fill_id]
- pattern = fill && fill.pattern_fill
- color = pattern && pattern.fg_color
- color = color && color.get_rgb(self)
- color && color.to_s || 'ffffff'
- end
-
- def register_new_fill(new_fill, old_xf)
- new_xf = old_xf.dup
- new_xf.apply_fill = true
- new_xf.fill_id = fills.find_index { |x| x == new_fill } # Reuse existing fill, if it exists
- new_xf.fill_id ||= fills.size # If this fill has never existed before, add it to collection.
- fills[new_xf.fill_id] = new_fill
- new_xf
- end
-
- def register_new_font(new_font, old_xf)
- new_xf = old_xf.dup
- new_xf.font_id = fonts.find_index { |x| x == new_font } # Reuse existing font, if it exists
- new_xf.font_id ||= fonts.size # If this font has never existed before, add it to collection.
- fonts[new_xf.font_id] = new_font
- new_xf.apply_font = true
- new_xf
- end
-
- def register_new_xf(new_xf)
- new_xf_id = cell_xfs.find_index { |xf| xf == new_xf } # Reuse existing XF, if it exists
- new_xf_id ||= cell_xfs.size # If this XF has never existed before, add it to collection.
- cell_xfs[new_xf_id] = new_xf
- new_xf_id
- end
-
- def modify_alignment(style_index, &block)
- xf = cell_xfs[style_index || 0].dup
- xf.alignment = xf.alignment.dup || RubyXL::Alignment.new
- yield(xf.alignment)
- xf.apply_alignment = true
-
- register_new_xf(xf)
- end
-
- def modify_fill(style_index, rgb)
- xf = cell_xfs[style_index || 0].dup
- new_fill = RubyXL::Fill.new(:pattern_fill =>
- RubyXL::PatternFill.new(:pattern_type => 'solid',
- :fg_color => RubyXL::Color.new(:rgb => rgb)))
- register_new_xf(register_new_fill(new_fill, xf))
- end
-
- def modify_border(style_index, direction, weight)
- xf = cell_xfs[style_index || 0].dup
- new_border = borders[xf.border_id || 0].dup
-
- edge = new_border.send(direction)
- new_border.send("#{direction}=", edge.dup) if edge
-
- new_border.set_edge_style(direction, weight)
-
- xf.border_id = borders.find_index { |x| x == new_border } # Reuse existing border, if it exists
- xf.border_id ||= borders.size # If this border has never existed before, add it to collection.
- borders[xf.border_id] = new_border
- xf.apply_border = true
-
- register_new_xf(xf)
- end
-
- def modify_border_color(style_index, direction, color)
- xf = cell_xfs[style_index || 0].dup
- new_border = borders[xf.border_id || 0].dup
- new_border.set_edge_color(direction, color)
-
- xf.border_id = borders.find_index { |x| x == new_border } # Reuse existing border, if it exists
- xf.border_id ||= borders.size # If this border has never existed before, add it to collection.
- borders[xf.border_id] = new_border
- xf.apply_border = true
-
- register_new_xf(xf)
- end
-
- # Calculate password hash from string for use in 'password' fields.
- # https://www.openoffice.org/sc/excelfileformat.pdf
- def password_hash(pwd)
- hsh = 0
- pwd.reverse.each_char { |c|
- hsh = hsh ^ c.ord
- hsh = hsh << 1
- hsh -= 0x7fff if hsh > 0x7fff
- }
-
- (hsh ^ pwd.length ^ 0xCE4B).to_s(16)
- end
- end
-
-
- module WorksheetConvenienceMethods
- NAME = 0
- SIZE = 1
- COLOR = 2
- ITALICS = 3
- BOLD = 4
- UNDERLINE = 5
- STRIKETHROUGH = 6
-
- def insert_cell(row = 0, col = 0, data = nil, formula = nil, shift = nil)
- validate_workbook
- ensure_cell_exists(row, col)
-
- case shift
- when nil then # No shifting at all
- when :right then
- sheet_data.rows[row].insert_cell_shift_right(nil, col)
- when :down then
- add_row(sheet_data.size, :cells => Array.new(sheet_data.rows[row].size))
- (sheet_data.size - 1).downto(row+1) { |index|
- sheet_data.rows[index].cells[col] = sheet_data.rows[index-1].cells[col]
- }
- else
- raise 'invalid shift option'
- end
-
- return add_cell(row, col, data, formula)
- end
-
- # by default, only sets cell to nil
- # if :left is specified, method will shift row contents to the right of the deleted cell to the left
- # if :up is specified, method will shift column contents below the deleted cell upward
- def delete_cell(row_index = 0, column_index=0, shift=nil)
- validate_workbook
- validate_nonnegative(row_index)
- validate_nonnegative(column_index)
-
- row = sheet_data[row_index]
- old_cell = row && row[column_index]
-
- case shift
- when nil then
- row.cells[column_index] = nil if row
- when :left then
- row.delete_cell_shift_left(column_index) if row
- when :up then
- (row_index...(sheet_data.size - 1)).each { |index|
- c = sheet_data.rows[index].cells[column_index] = sheet_data.rows[index + 1].cells[column_index]
- c.row -= 1 if c.is_a?(Cell)
- }
- else
- raise 'invalid shift option'
- end
-
- return old_cell
- end
-
- # Inserts row at row_index, pushes down, copies style from the row above (that's what Excel 2013 does!)
- # NOTE: use of this method will break formulas which reference cells which are being "pushed down"
- def insert_row(row_index = 0)
- validate_workbook
- ensure_cell_exists(row_index)
-
- old_row = new_cells = nil
-
- if row_index > 0 then
- old_row = sheet_data.rows[row_index - 1]
- if old_row then
- new_cells = old_row.cells.collect { |c|
- if c.nil? then nil
- else nc = RubyXL::Cell.new(:style_index => c.style_index)
- nc.worksheet = self
- nc
- end
- }
- end
- end
-
- row0 = sheet_data.rows[0]
- new_cells ||= Array.new((row0 && row0.cells.size) || 0)
-
- sheet_data.rows.insert(row_index, nil)
- new_row = add_row(row_index, :cells => new_cells, :style_index => old_row && old_row.style_index)
-
- # Update row values for all rows below
- row_index.upto(sheet_data.rows.size - 1) { |r|
- row = sheet_data.rows[r]
- next if row.nil?
- row.cells.each_with_index { |cell, c|
- next if cell.nil?
- cell.r = RubyXL::Reference.new(r, c)
- }
- }
-
- return new_row
- end
-
- def delete_row(row_index=0)
- validate_workbook
- validate_nonnegative(row_index)
-
- deleted = sheet_data.rows.delete_at(row_index)
-
- # Update row number of each cell
- row_index.upto(sheet_data.size - 1) { |index|
- row = sheet_data[index]
- row && row.cells.each{ |c| c.row -= 1 unless c.nil? }
- }
-
- return deleted
- end
-
- # Inserts column at +column_index+, pushes everything right, takes styles from column to left
- # NOTE: use of this method will break formulas which reference cells which are being "pushed right"
- def insert_column(column_index = 0)
- validate_workbook
- ensure_cell_exists(0, column_index)
-
- old_range = cols.get_range(column_index)
-
- #go through each cell in column
- sheet_data.rows.each_with_index { |row, row_index|
- old_cell = row[column_index]
- c = nil
-
- if old_cell && old_cell.style_index != 0 &&
- old_range && old_range.style_index != old_cell.style_index then
-
- c = RubyXL::Cell.new(:style_index => old_cell.style_index, :worksheet => self,
- :row => row_index, :column => column_index,
- :datatype => RubyXL::DataType::SHARED_STRING)
- end
-
- row.insert_cell_shift_right(c, column_index)
- }
-
- cols.insert_column(column_index)
-
- # TODO: update column numbers
- end
-
- def delete_column(column_index = 0)
- validate_workbook
- validate_nonnegative(column_index)
-
- # Delete column
- sheet_data.rows.each { |row| row.cells.delete_at(column_index) }
-
- # Update column numbers for cells to the right of the deleted column
- sheet_data.rows.each_with_index { |row, row_index|
- row.cells.each_with_index { |c, ci|
- c.column = ci if c.is_a?(Cell)
- }
- }
-
- cols.each { |range| range.delete_column(column_index) }
- end
-
- def get_row_style(row_index)
- row = sheet_data.rows[row_index]
- (row && row.style_index) || 0
- end
-
- def get_row_fill(row = 0)
- (row = sheet_data.rows[row]) && row.get_fill_color
- end
-
- def get_row_font_name(row = 0)
- (font = row_font(row)) && font.get_name
- end
-
- def get_row_font_size(row = 0)
- (font = row_font(row)) && font.get_size
- end
-
- def get_row_font_color(row = 0)
- font = row_font(row)
- color = font && font.color
- color && (color.rgb || '000000')
- end
-
- def is_row_italicized(row = 0)
- (font = row_font(row)) && font.is_italic
- end
-
- def is_row_bolded(row = 0)
- (font = row_font(row)) && font.is_bold
- end
-
- def is_row_underlined(row = 0)
- (font = row_font(row)) && font.is_underlined
- end
-
- def is_row_struckthrough(row = 0)
- (font = row_font(row)) && font.is_strikethrough
- end
-
- def get_row_height(row = 0)
- validate_workbook
- validate_nonnegative(row)
- row = sheet_data.rows[row]
- row && row.ht || RubyXL::Row::DEFAULT_HEIGHT
- end
-
- def get_row_border(row, border_direction)
- validate_workbook
-
- border = @workbook.borders[get_row_xf(row).border_id]
- border && border.get_edge_style(border_direction)
- end
-
- def get_row_border_color(row, border_direction)
- validate_workbook
-
- border = @workbook.borders[get_row_xf(row).border_id]
- border && border.get_edge_color(border_direction)
- end
-
- def row_font(row)
- (row = sheet_data.rows[row]) && row.get_font
- end
-
- def get_row_alignment(row, is_horizontal)
- validate_workbook
-
- xf_obj = get_row_xf(row)
- return nil if xf_obj.alignment.nil?
-
- if is_horizontal then return xf_obj.alignment.horizontal
- else return xf_obj.alignment.vertical
- end
- end
-
- def get_cols_style_index(column_index)
- validate_nonnegative(column_index)
- range = cols.locate_range(column_index)
- (range && range.style_index) || 0
- end
-
- def get_column_font_name(col = 0)
- font = column_font(col)
- font && font.get_name
- end
-
- def get_column_font_size(col = 0)
- font = column_font(col)
- font && font.get_size
- end
-
- def get_column_font_color(col = 0)
- font = column_font(col)
- font && (font.get_rgb_color || '000000')
- end
-
- def is_column_italicized(col = 0)
- font = column_font(col)
- font && font.is_italic
- end
-
- def is_column_bolded(col = 0)
- font = column_font(col)
- font && font.is_bold
- end
-
- def is_column_underlined(col = 0)
- font = column_font(col)
- font && font.is_underlined
- end
-
- def is_column_struckthrough(col = 0)
- font = column_font(col)
- font && font.is_strikethrough
- end
-
- # Get raw column width value as stored in the file
- def get_column_width_raw(column_index = 0)
- validate_workbook
- validate_nonnegative(column_index)
-
- range = cols.locate_range(column_index)
- range && range.width
- end
-
- # Get column width measured in number of digits, as per
- # http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.column%28v=office.14%29.aspx
- def get_column_width(column_index = 0)
- width = get_column_width_raw(column_index)
- return RubyXL::ColumnRange::DEFAULT_WIDTH if width.nil?
- (width - (5.0 / RubyXL::Font::MAX_DIGIT_WIDTH)).round
- end
-
- # Set raw column width value
- def change_column_width_raw(column_index, width)
- validate_workbook
- ensure_cell_exists(0, column_index)
- range = cols.get_range(column_index)
- range.width = width
- range.custom_width = true
- end
-
- # Get column width measured in number of digits, as per
- # http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.column%28v=office.14%29.aspx
- def change_column_width(column_index, width_in_chars = RubyXL::ColumnRange::DEFAULT_WIDTH)
- change_column_width_raw(column_index, ((width_in_chars + (5.0 / RubyXL::Font::MAX_DIGIT_WIDTH)) * 256).to_i / 256.0)
- end
-
- # Helper method to get the style index for a column
- def get_col_style(column_index)
- range = cols.locate_range(column_index)
- (range && range.style_index) || 0
- end
-
- def get_column_fill(col=0)
- validate_workbook
- validate_nonnegative(col)
-
- @workbook.get_fill_color(get_col_xf(col))
- end
-
- def change_column_fill(column_index, color_code = 'ffffff')
- validate_workbook
- RubyXL::Color.validate_color(color_code)
- ensure_cell_exists(0, column_index)
-
- cols.get_range(column_index).style_index = @workbook.modify_fill(get_col_style(column_index), color_code)
-
- sheet_data.rows.each { |row|
- c = row[column_index]
- c.change_fill(color_code) if c
- }
- end
-
- def get_column_border(col, border_direction)
- validate_workbook
-
- xf = @workbook.cell_xfs[get_cols_style_index(col)]
- border = @workbook.borders[xf.border_id]
- border && border.get_edge_style(border_direction)
- end
-
- def get_column_border_color(col, border_direction)
- validate_workbook
-
- xf = @workbook.cell_xfs[get_cols_style_index(col)]
- border = @workbook.borders[xf.border_id]
- border && border.get_edge_color(border_direction)
- end
-
- def column_font(col)
- validate_workbook
-
- @workbook.fonts[@workbook.cell_xfs[get_cols_style_index(col)].font_id]
- end
-
- def get_column_alignment(col, type)
- validate_workbook
-
- xf = @workbook.cell_xfs[get_cols_style_index(col)]
- xf.alignment && xf.alignment.send(type)
- end
-
- def change_row_horizontal_alignment(row = 0, alignment = 'center')
- validate_workbook
- validate_nonnegative(row)
- change_row_alignment(row) { |a| a.horizontal = alignment }
- end
-
- def change_row_vertical_alignment(row = 0, alignment = 'center')
- validate_workbook
- validate_nonnegative(row)
- change_row_alignment(row) { |a| a.vertical = alignment }
- end
-
- def change_row_border(row, direction, weight)
- validate_workbook
- ensure_cell_exists(row)
-
- sheet_data.rows[row].style_index = @workbook.modify_border(get_row_style(row), direction, weight)
-
- sheet_data[row].cells.each { |c|
- c.change_border(direction, weight) unless c.nil?
- }
- end
-
- def change_row_border_color(row, direction, color = '000000')
- validate_workbook
- ensure_cell_exists(row)
- Color.validate_color(color)
-
- sheet_data.rows[row].style_index = @workbook.modify_border_color(get_row_style(row), direction, color)
-
- sheet_data[row].cells.each { |c|
- c.change_border_color(direction, color) unless c.nil?
- }
- end
-
- def change_row_fill(row_index = 0, rgb = 'ffffff')
- validate_workbook
- ensure_cell_exists(row_index)
- Color.validate_color(rgb)
-
- sheet_data.rows[row_index].style_index = @workbook.modify_fill(get_row_style(row_index), rgb)
- sheet_data[row_index].cells.each { |c| c.change_fill(rgb) unless c.nil? }
- end
-
- # Helper method to update the row styles array
- # change_type - NAME or SIZE or COLOR etc
- # main method to change font, called from each separate font mutator method
- def change_row_font(row_index, change_type, arg, font)
- validate_workbook
- ensure_cell_exists(row_index)
-
- xf = workbook.register_new_font(font, get_row_xf(row_index))
- row = sheet_data[row_index]
- row.style_index = workbook.register_new_xf(xf)
- row.cells.each { |c| c.font_switch(change_type, arg) unless c.nil? }
- end
-
- def change_row_font_name(row = 0, font_name = 'Verdana')
- ensure_cell_exists(row)
- font = row_font(row).dup
- font.set_name(font_name)
- change_row_font(row, Worksheet::NAME, font_name, font)
- end
-
- def change_row_font_size(row = 0, font_size=10)
- ensure_cell_exists(row)
- font = row_font(row).dup
- font.set_size(font_size)
- change_row_font(row, Worksheet::SIZE, font_size, font)
- end
-
- def change_row_font_color(row = 0, font_color = '000000')
- ensure_cell_exists(row)
- Color.validate_color(font_color)
- font = row_font(row).dup
- font.set_rgb_color(font_color)
- change_row_font(row, Worksheet::COLOR, font_color, font)
- end
-
- def change_row_italics(row = 0, italicized = false)
- ensure_cell_exists(row)
- font = row_font(row).dup
- font.set_italic(italicized)
- change_row_font(row, Worksheet::ITALICS, italicized, font)
- end
-
- def change_row_bold(row = 0, bolded = false)
- ensure_cell_exists(row)
- font = row_font(row).dup
- font.set_bold(bolded)
- change_row_font(row, Worksheet::BOLD, bolded, font)
- end
-
- def change_row_underline(row = 0, underlined=false)
- ensure_cell_exists(row)
- font = row_font(row).dup
- font.set_underline(underlined)
- change_row_font(row, Worksheet::UNDERLINE, underlined, font)
- end
-
- def change_row_strikethrough(row = 0, struckthrough=false)
- ensure_cell_exists(row)
- font = row_font(row).dup
- font.set_strikethrough(struckthrough)
- change_row_font(row, Worksheet::STRIKETHROUGH, struckthrough, font)
- end
-
- def change_row_height(row = 0, height = 10)
- validate_workbook
- ensure_cell_exists(row)
-
- c = sheet_data.rows[row]
- c.ht = height
- c.custom_height = true
- end
-
- # Helper method to update the fonts and cell styles array
- # main method to change font, called from each separate font mutator method
- def change_column_font(column_index, change_type, arg, font, xf)
- validate_workbook
- ensure_cell_exists(0, column_index)
-
- xf = workbook.register_new_font(font, xf)
- cols.get_range(column_index).style_index = workbook.register_new_xf(xf)
-
- sheet_data.rows.each { |row|
- c = row && row[column_index]
- c.font_switch(change_type, arg) unless c.nil?
- }
- end
-
- def change_column_font_name(column_index = 0, font_name = 'Verdana')
- xf = get_col_xf(column_index)
- font = @workbook.fonts[xf.font_id].dup
- font.set_name(font_name)
- change_column_font(column_index, Worksheet::NAME, font_name, font, xf)
- end
-
- def change_column_font_size(column_index, font_size=10)
- xf = get_col_xf(column_index)
- font = @workbook.fonts[xf.font_id].dup
- font.set_size(font_size)
- change_column_font(column_index, Worksheet::SIZE, font_size, font, xf)
- end
-
- def change_column_font_color(column_index, font_color='000000')
- Color.validate_color(font_color)
-
- xf = get_col_xf(column_index)
- font = @workbook.fonts[xf.font_id].dup
- font.set_rgb_color(font_color)
- change_column_font(column_index, Worksheet::COLOR, font_color, font, xf)
- end
-
- def change_column_italics(column_index, italicized = false)
- xf = get_col_xf(column_index)
- font = @workbook.fonts[xf.font_id].dup
- font.set_italic(italicized)
- change_column_font(column_index, Worksheet::ITALICS, italicized, font, xf)
- end
-
- def change_column_bold(column_index, bolded = false)
- xf = get_col_xf(column_index)
- font = @workbook.fonts[xf.font_id].dup
- font.set_bold(bolded)
- change_column_font(column_index, Worksheet::BOLD, bolded, font, xf)
- end
-
- def change_column_underline(column_index, underlined = false)
- xf = get_col_xf(column_index)
- font = @workbook.fonts[xf.font_id].dup
- font.set_underline(underlined)
- change_column_font(column_index, Worksheet::UNDERLINE, underlined, font, xf)
- end
-
- def change_column_strikethrough(column_index, struckthrough=false)
- xf = get_col_xf(column_index)
- font = @workbook.fonts[xf.font_id].dup
- font.set_strikethrough(struckthrough)
- change_column_font(column_index, Worksheet::STRIKETHROUGH, struckthrough, font, xf)
- end
-
- def change_column_horizontal_alignment(column_index, alignment = 'center')
- change_column_alignment(column_index) { |a| a.horizontal = alignment }
- end
-
- def change_column_vertical_alignment(column_index, alignment = 'center')
- change_column_alignment(column_index) { |a| a.vertical = alignment }
- end
-
- def change_column_border(column_index, direction, weight)
- validate_workbook
- ensure_cell_exists(0, column_index)
-
- cols.get_range(column_index).style_index = @workbook.modify_border(get_col_style(column_index), direction, weight)
-
- sheet_data.rows.each { |row|
- c = row.cells[column_index]
- c.change_border(direction, weight) unless c.nil?
- }
- end
-
- def change_column_border_color(column_index, direction, color)
- validate_workbook
- ensure_cell_exists(0, column_index)
- Color.validate_color(color)
-
- cols.get_range(column_index).style_index = @workbook.modify_border_color(get_col_style(column_index), direction, color)
-
- sheet_data.rows.each { |row|
- c = row.cells[column_index]
- c.change_border_color(direction, color) unless c.nil?
- }
- end
-
- def change_row_alignment(row, &block)
- validate_workbook
- validate_nonnegative(row)
- ensure_cell_exists(row)
-
- sheet_data.rows[row].style_index = @workbook.modify_alignment(get_row_style(row), &block)
-
- sheet_data[row].cells.each { |c|
- next if c.nil?
- c.style_index = @workbook.modify_alignment(c.style_index, &block)
- }
- end
-
- def change_column_alignment(column_index, &block)
- validate_workbook
- ensure_cell_exists(0, column_index)
-
- cols.get_range(column_index).style_index = @workbook.modify_alignment(get_col_style(column_index), &block)
- # Excel gets confused if width is not explicitly set for a column that had alignment changes
- change_column_width(column_index) if get_column_width_raw(column_index).nil?
-
- sheet_data.rows.each { |row|
- c = row[column_index]
- next if c.nil?
- c.style_index = @workbook.modify_alignment(c.style_index, &block)
- }
- end
-
- # Merges cells within a rectangular area
- def merge_cells(start_row, start_col, end_row, end_col)
- validate_workbook
-
- self.merged_cells ||= RubyXL::MergedCells.new
- # TODO: add validation to make sure ranges are not intersecting with existing ones
- merged_cells << RubyXL::MergedCell.new(:ref => RubyXL::Reference.new(start_row, end_row, start_col, end_col))
- end
- end
-
- module CellConvenienceMethods
-
- def change_contents(data, formula_expression = nil)
- validate_worksheet
-
- if formula_expression then
- self.datatype = nil
- self.formula = RubyXL::Formula.new(:expression => formula_expression)
- else
- self.datatype = case data
- when Date, Numeric then nil
- else RubyXL::DataType::RAW_STRING
- end
- end
-
- data = workbook.date_to_num(data) if data.is_a?(Date)
-
- self.raw_value = data
- end
-
- def get_border(direction)
- validate_worksheet
- get_cell_border.get_edge_style(direction)
- end
-
- def get_border_color(direction)
- validate_worksheet
- get_cell_border.get_edge_color(direction)
- end
-
- def change_horizontal_alignment(alignment = 'center')
- validate_worksheet
- self.style_index = workbook.modify_alignment(self.style_index) { |a| a.horizontal = alignment }
- end
-
- def change_vertical_alignment(alignment = 'center')
- validate_worksheet
- self.style_index = workbook.modify_alignment(self.style_index) { |a| a.vertical = alignment }
- end
-
- def change_text_wrap(wrap = false)
- validate_worksheet
- self.style_index = workbook.modify_alignment(self.style_index) { |a| a.wrap_text = wrap }
- end
-
- def change_text_rotation(rot)
- validate_worksheet
- self.style_index = workbook.modify_alignment(self.style_index) { |a| a.text_rotation = rot }
- end
-
- def change_text_indent(indent)
- validate_worksheet
- self.style_index = workbook.modify_alignment(self.style_index) { |a| a.indent = indent }
- end
-
- def change_border(direction, weight)
- validate_worksheet
- self.style_index = workbook.modify_border(self.style_index, direction, weight)
- end
-
- def change_border_color(direction, color)
- validate_worksheet
- Color.validate_color(color)
- self.style_index = workbook.modify_border_color(self.style_index, direction, color)
- end
-
- def is_italicized()
- validate_worksheet
- get_cell_font.is_italic
- end
-
- def is_bolded()
- validate_worksheet
- get_cell_font.is_bold
- end
-
- def is_underlined()
- validate_worksheet
- get_cell_font.is_underlined
- end
-
- def is_struckthrough()
- validate_worksheet
- get_cell_font.is_strikethrough
- end
-
- def font_name()
- validate_worksheet
- get_cell_font.get_name
- end
-
- def font_size()
- validate_worksheet
- get_cell_font.get_size
- end
-
- def font_color()
- validate_worksheet
- get_cell_font.get_rgb_color || '000000'
- end
-
- def fill_color()
- validate_worksheet
- return workbook.get_fill_color(get_cell_xf)
- end
-
- def horizontal_alignment()
- validate_worksheet
- xf_obj = get_cell_xf
- return nil if xf_obj.alignment.nil?
- xf_obj.alignment.horizontal
- end
-
- def vertical_alignment()
- validate_worksheet
- xf_obj = get_cell_xf
- return nil if xf_obj.alignment.nil?
- xf_obj.alignment.vertical
- end
-
- def text_wrap()
- validate_worksheet
- xf_obj = get_cell_xf
- return nil if xf_obj.alignment.nil?
- xf_obj.alignment.wrap_text
- end
-
- def text_rotation
- validate_worksheet
- xf_obj = get_cell_xf
- return nil if xf_obj.alignment.nil?
- xf_obj.alignment.text_rotation
- end
-
- def text_indent()
- validate_worksheet
- xf_obj = get_cell_xf
- return nil if xf_obj.alignment.nil?
- xf_obj.alignment.indent
- end
-
- def set_number_format(format_code)
- new_xf = get_cell_xf.dup
- new_xf.num_fmt_id = workbook.stylesheet.register_number_format(format_code)
- new_xf.apply_number_format = true
- self.style_index = workbook.register_new_xf(new_xf)
- end
-
- # Changes fill color of cell
- def change_fill(rgb = 'ffffff')
- validate_worksheet
- Color.validate_color(rgb)
- self.style_index = workbook.modify_fill(self.style_index, rgb)
- end
-
- # Changes font name of cell
- def change_font_name(new_font_name = 'Verdana')
- validate_worksheet
-
- font = get_cell_font.dup
- font.set_name(new_font_name)
- update_font_references(font)
- end
-
- # Changes font size of cell
- def change_font_size(font_size = 10)
- validate_worksheet
- raise 'Argument must be a number' unless font_size.is_a?(Integer) || font_size.is_a?(Float)
-
- font = get_cell_font.dup
- font.set_size(font_size)
- update_font_references(font)
- end
-
- # Changes font color of cell
- def change_font_color(font_color = '000000')
- validate_worksheet
- Color.validate_color(font_color)
-
- font = get_cell_font.dup
- font.set_rgb_color(font_color)
- update_font_references(font)
- end
-
- # Changes font italics settings of cell
- def change_font_italics(italicized = false)
- validate_worksheet
-
- font = get_cell_font.dup
- font.set_italic(italicized)
- update_font_references(font)
- end
-
- # Changes font bold settings of cell
- def change_font_bold(bolded = false)
- validate_worksheet
-
- font = get_cell_font.dup
- font.set_bold(bolded)
- update_font_references(font)
- end
-
- # Changes font underline settings of cell
- def change_font_underline(underlined = false)
- validate_worksheet
-
- font = get_cell_font.dup
- font.set_underline(underlined)
- update_font_references(font)
- end
-
- def change_font_strikethrough(struckthrough = false)
- validate_worksheet
-
- font = get_cell_font.dup
- font.set_strikethrough(struckthrough)
- update_font_references(font)
- end
-
- # Helper method to update the font array and xf array
- def update_font_references(modified_font)
- xf = workbook.register_new_font(modified_font, get_cell_xf)
- self.style_index = workbook.register_new_xf(xf)
- end
- private :update_font_references
-
- # Performs correct modification based on what type of change_type is specified
- def font_switch(change_type, arg)
- case change_type
- when Worksheet::NAME then change_font_name(arg)
- when Worksheet::SIZE then change_font_size(arg)
- when Worksheet::COLOR then change_font_color(arg)
- when Worksheet::ITALICS then change_font_italics(arg)
- when Worksheet::BOLD then change_font_bold(arg)
- when Worksheet::UNDERLINE then change_font_underline(arg)
- when Worksheet::STRIKETHROUGH then change_font_strikethrough(arg)
- else raise 'Invalid change_type'
- end
- end
-
-=begin
- def add_hyperlink(l)
- worksheet.hyperlinks ||= RubyXL::Hyperlinks.new
- worksheet.hyperlinks << RubyXL::Hyperlink.new(:ref => self.r, :location => l)
-# define_attribute(:'r:id', :string)
-# define_attribute(:location, :string)
-# define_attribute(:tooltip, :string)
-# define_attribute(:display, :string)
-
- end
-
- def add_shared_string(str)
- self.datatype = RubyXL::DataType::SHARED_STRING
- self.raw_value = @workbook.shared_strings_container.add(str)
- end
-=end
-
- end
-
- module FontConvenienceMethods
- # Funny enough, but presence of <i> without value (equivalent to `val == nul`) means "italic = true"!
- # Same is true for bold, strikethrough, etc
- def is_italic
- i && (i.val != false)
- end
-
- def is_bold
- b && (b.val != false)
- end
-
- def is_underlined
- u && (u.val != false)
- end
-
- def is_strikethrough
- strike && (strike.val != false)
- end
-
- def get_name
- name && name.val
- end
-
- def get_size
- sz && sz.val
- end
-
- def get_rgb_color
- color && color.rgb
- end
-
- def set_italic(val)
- self.i = RubyXL::BooleanValue.new(:val => val)
- end
-
- def set_bold(val)
- self.b = RubyXL::BooleanValue.new(:val => val)
- end
-
- def set_underline(val)
- self.u = RubyXL::BooleanValue.new(:val => val)
- end
-
- def set_strikethrough(val)
- self.strike = RubyXL::BooleanValue.new(:val => val)
- end
-
- def set_name(val)
- self.name = RubyXL::StringValue.new(:val => val)
- end
-
- def set_size(val)
- self.sz = RubyXL::FloatValue.new(:val => val)
- end
-
- def set_rgb_color(font_color)
- self.color = RubyXL::Color.new(:rgb => font_color.to_s)
- end
- end
-
- module ColorConvenienceMethods
-
- def get_rgb(workbook)
- if rgb then
- return rgb
- elsif theme then
- theme_color = workbook.theme.get_theme_color(theme)
- rgb_color = theme_color && theme_color.a_srgb_clr
- color_value = rgb_color && rgb_color.val
- return nil if color_value.nil?
-
- RubyXL::RgbColor.parse(color_value).to_hls.apply_tint(tint).to_rgb.to_s
- end
- end
-
- end
-
- module ColorConvenienceClasses
- # https://ciintelligence.blogspot.com/2012/02/converting-excel-theme-color-and-tint.html
- class RgbColor
- attr_accessor :r, :g, :b, :a
-
- def to_hls
- hls_color = HlsColor.new
-
- # Note that we are overriding accessors with local vars here:
- r = self.r / 255.0
- g = self.g / 255.0
- b = self.b / 255.0
-
- hls_color.a = (self.a || 0) / 255.0
-
- min = [r, g, b].min
- max = [r, g, b].max
- delta = max - min
-
- if (max == min) then
- hls_color.h = hls_color.s = 0
- hls_color.l = max
- return hls_color
- end
-
- hls_color.l = (min + max) / 2
-
- if (hls_color.l < 0.5) then
- hls_color.s = delta / (max + min);
- else
- hls_color.s = delta / (2.0 - max - min);
- end
-
- hls_color.h = (g - b) / delta if (r == max)
- hls_color.h = 2.0 + (b - r) / delta if (g == max)
- hls_color.h = 4.0 + (r - g) / delta if (b == max)
-
- hls_color.h *= 60;
- hls_color.h += 360 if hls_color.h < 0
-
- hls_color
- end
-
- def self.parse(str)
- r, g, b, a = str.unpack("A2A2A2A2")
-
- rgb_color = RgbColor.new
- rgb_color.r = r && r.to_i(16)
- rgb_color.g = g && g.to_i(16)
- rgb_color.b = b && b.to_i(16)
- rgb_color.a = a && a.to_i(16)
-
- rgb_color
- end
-
- def to_s
- str = r.to_s(16) + g.to_s(16) + b.to_s(16)
- str += a.to_s(16) if a && a != 0
- str
- end
-
- end
-
- class HlsColor
- attr_accessor :h, :l, :s, :a
-
- def to_rgb
- rgb_color = RgbColor.new
-
- r = g = b = l
-
- if s != 0 then
- t1 = nil
-
- if l < 0.5 then
- t1 = l * (1.0 + s)
- else
- t1 = l + s - (l * s)
- end
-
- t2 = 2.0 * l - t1;
- h = self.h / 360.0
-
- t_r = h + (1.0 / 3.0)
- r = set_color(t1, t2, t_r)
-
- t_g = h;
- g = set_color(t1, t2, t_g)
-
- t_b = h - (1.0 / 3.0);
- b = set_color(t1, t2, t_b)
- end
-
- rgb_color.r = (r * 255).round(0).to_i
- rgb_color.g = (g * 255).round(0).to_i
- rgb_color.b = (b * 255).round(0).to_i
-
- rgb_color.a = (a * 255).round(0).to_i
-
- rgb_color
- end
-
- def set_color(t1, t2, t3)
- color = 0
-
- t3 += 1.0 if (t3 < 0)
- t3 -= 1.0 if (t3 > 1)
-
- if (6.0 * t3 < 1) then
- color = t2 + (t1 - t2) * 6.0 * t3;
- elsif (2.0 * t3 < 1) then
- color = t1;
- elsif (3.0 * t3 < 2) then
- color = t2 + (t1 - t2) * ((2.0 / 3.0) - t3) * 6.0;
- else
- color = t2;
- end
-
- color
- end
- private :set_color
-
- def apply_tint(tint)
- return self if tint.nil? || tint == 0
-
- if tint < 0 then
- self.l = l * (1.0 + tint);
- else
- self.l = l * (1.0 - tint) + tint;
- end
-
- self
- end
-
- end
- end
-
-end
+require 'rubyXL/convenience_methods/workbook'
+require 'rubyXL/convenience_methods/worksheet'
+require 'rubyXL/convenience_methods/cell'
+require 'rubyXL/convenience_methods/font'
+require 'rubyXL/convenience_methods/color'