1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
require "spreadsheet/excel/offset"
require "spreadsheet/excel/row"
require "spreadsheet/worksheet"
module Spreadsheet
module Excel
##
# Excel-specific Worksheet methods. These are mostly pertinent to the Excel
# reader, and to recording changes to the Worksheet. You should have no reason
# to use any of these.
class Worksheet < Spreadsheet::Worksheet
include Spreadsheet::Excel::Offset
offset :dimensions
attr_reader :offset, :ole, :links, :guts, :notes
def initialize opts = {}
@row_addresses = nil
super
@offset, @ole, @reader = opts[:offset], opts[:ole], opts[:reader]
@dimensions = nil
@links = {}
@guts = {}
@notes = {}
end
def add_link row, column, link
@links.store [row, column], link
end
def add_note row, column, note
@notes.store [row, column], note
end
def column idx
ensure_rows_read
super
end
def date_base
@workbook.date_base
end
def margins
ensure_rows_read
super
end
def pagesetup
ensure_rows_read
super
end
def each *args
ensure_rows_read
super
end
def ensure_rows_read
return if @row_addresses
@dimensions = nil
@row_addresses = []
@reader&.read_worksheet self, @offset
end
def row idx
@rows[idx] or begin
ensure_rows_read
if (addr = @row_addresses[idx])
row = @reader.read_row self, addr
[:default_format, :height, :outline_level, :hidden].each do |key|
row.send :"unupdated_#{key}=", addr[key]
end
row.worksheet = self
row
else
Row.new self, idx
end
end
end
def rows
to_a
end
def row_updated idx, row
res = super
@workbook.changes.store self, true
@workbook.changes.store :boundsheets, true
@changes.store idx, true
@changes.store :dimensions, true
res
end
def set_row_address idx, opts
@offsets.store idx, opts[:row_block]
@row_addresses[idx] = opts
end
def shared_string idx
@workbook.shared_string idx
end
private
## premature optimization?
def have_set_dimensions value, pos, len
if @row_addresses.size < row_count
@row_addresses.concat Array.new(row_count - @row_addresses.size)
end
end
def recalculate_dimensions
ensure_rows_read
shorten @rows
@dimensions = []
@dimensions[0] = [index_of_first(@rows),
index_of_first(@row_addresses)].compact.min || 0
@dimensions[1] = [@rows.size, @row_addresses.size].compact.max || 0
compact = @rows.compact
first_rows = compact.collect { |row| row.first_used }.compact.min
first_addrs = @row_addresses.compact.collect do |addr|
addr[:first_used]
end.compact.min
@dimensions[2] = [first_rows, first_addrs].compact.min || 0
last_rows = compact.collect { |row| row.first_unused }.max
last_addrs = @row_addresses.compact.collect do |addr|
addr[:first_unused]
end.compact.max
@dimensions[3] = [last_rows, last_addrs].compact.max || 0
@dimensions
end
end
end
end
|