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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
|
# encoding: utf-8
require 'spreadsheet/datatypes'
require 'spreadsheet/encodings'
require 'spreadsheet/font'
module Spreadsheet
##
# Formatting data
class Format
include Spreadsheet::Datatypes
include Spreadsheet::Encodings
##
# You can set the following boolean attributes:
# #cross_down:: Draws a Line from the top-left to the bottom-right
# corner of a cell.
# #cross_up:: Draws a Line from the bottom-left to the top-right
# corner of a cell.
# #hidden:: The cell is hidden.
# #locked:: The cell is locked.
# #merge_range:: The cell is in a merged range.
# #shrink:: Shrink the contents to fit the cell.
# #text_justlast:: Force the last line of a cell to be justified. This
# probably makes sense if horizontal_align = :justify
# #left:: Apply a border style to the left of the cell.
# #right:: Apply a border style to the right of the cell.
# #top:: Apply a border style at the top of the cell.
# #bottom:: Apply a border style at the bottom of the cell.
# #rotation_stacked:: Characters in the cell are stacked on top of each
# other. Excel will ignore other rotation values if
# this is set.
boolean :cross_down, :cross_up, :hidden, :locked,
:merge_range, :shrink, :text_justlast, :text_wrap,
:rotation_stacked
##
# Border line styles
# Valid values: :none, :thin, :medium, :dashed, :dotted, :thick,
# :double, :hair, :medium_dashed, :thin_dash_dotted,
# :medium_dash_dotted, :thin_dash_dot_dotted,
# :medium_dash_dot_dotted, :slanted_medium_dash_dotted
# Default: :none
styles = [ :thin, :medium, :dashed, :dotted, :thick,
:double, :hair, :medium_dashed, :thin_dash_dotted,
:medium_dash_dotted, :thin_dash_dot_dotted,
:medium_dash_dot_dotted, :slanted_medium_dash_dotted ]
enum :left, :none, *styles
enum :right, :none, *styles
enum :top, :none, *styles
enum :bottom, :none, *styles
##
# Color attributes
colors :bottom_color, :top_color, :left_color, :right_color,
:pattern_fg_color, :pattern_bg_color,
:diagonal_color
##
# Text direction
# Valid values: :context, :left_to_right, :right_to_left
# Default: :context
enum :text_direction, :context, :left_to_right, :right_to_left,
:left_to_right => [:ltr, :l2r],
:right_to_left => [:rtl, :r2l]
alias :reading_order :text_direction
alias :reading_order= :text_direction=
##
# Indentation level
enum :indent_level, 0, Integer
alias :indent :indent_level
alias :indent= :indent_level=
##
# Horizontal alignment
# Valid values: :default, :left, :center, :right, :fill, :justify, :merge,
# :distributed
# Default: :default
enum :horizontal_align, :default, :left, :center, :right, :fill, :justify,
:merge, :distributed,
:center => :centre,
:merge => [ :center_across, :centre_across ],
:distributed => :equal_space
##
# Vertical alignment
# Valid values: :bottom, :top, :middle, :justify, :distributed
# Default: :bottom
enum :vertical_align, :bottom, :top, :middle, :justify, :distributed,
:distributed => [:vdistributed, :vequal_space, :equal_space],
:justify => :vjustify,
:middle => [:vcenter, :vcentre, :center, :centre]
attr_accessor :font, :number_format, :name, :pattern, :used_merge
##
# Text rotation
attr_reader :rotation
def initialize opts={}
@font = Font.new client("Arial", 'UTF-8'), :family => :swiss
@number_format = client 'GENERAL', 'UTF-8'
@rotation = 0
@pattern = 0
@bottom_color = :black
@top_color = :black
@left_color = :black
@right_color = :black
@diagonal_color = :black
@pattern_fg_color = :border
@pattern_bg_color = :pattern_bg
@regexes = {
:date => Regexp.new(client("[YMD]|d{2}|m{3}|y{2}", 'UTF-8')),
:date_or_time => Regexp.new(client("[hmsYMD]", 'UTF-8')),
:datetime => Regexp.new(client("([YMD].*[HS])|([HS].*[YMD])", 'UTF-8')),
:time => Regexp.new(client("[hms]", 'UTF-8')),
:number => Regexp.new(client("([\#]|0+)", 'UTF-8')),
:locale => Regexp.new(client(/\A\[\$\-\S+\]/.to_s, 'UTF-8')),
}
# Temp code to prevent merged formats in non-merged cells.
@used_merge = 0
update_format(opts)
yield self if block_given?
end
def update_format(opts = {})
opts.each do |attribute, value|
writer = "#{attribute}="
@font.respond_to?(writer) ? @font.send(writer,value) : self.send(writer, value)
end
self
end
##
# Combined method for both horizontal and vertical alignment. Sets the
# first valid value (e.g. Format#align = :justify only sets the horizontal
# alignment. Use one of the aliases prefixed with :v if you need to
# disambiguate.)
#
# This is essentially a backward-compatibility method and may be removed at
# some point in the future.
def align= location
self.horizontal_align = location
rescue ArgumentError
self.vertical_align = location rescue ArgumentError
end
##
# Returns an Array containing the line styles of the four borders:
# bottom, top, right, left
def border
[bottom, top, right, left]
end
##
# Set same line style on all four borders at once (left, right, top, bottom)
def border=(style)
[:bottom=, :top=, :right=, :left=].each do |writer| send writer, style end
end
##
# Returns an Array containing the colors of the four borders:
# bottom, top, right, left
def border_color
[@bottom_color,@top_color,@right_color,@left_color]
end
##
# Set all four border colors to _color_ (left, right, top, bottom)
def border_color=(color)
[:bottom_color=, :top_color=, :right_color=, :left_color=].each do |writer|
send writer, color end
end
##
# Set the Text rotation
# Valid values: Integers from -90 to 90,
# or :stacked (sets #rotation_stacked to true)
def rotation=(rot)
if rot.to_s.downcase == 'stacked'
@rotation_stacked = true
@rotation = 0
elsif rot.kind_of?(Integer)
@rotation_stacked = false
@rotation = rot % 360
else
raise TypeError, "rotation value must be an Integer or the String 'stacked'"
end
end
##
# Backward compatibility method. May disappear at some point in the future.
def center_across!
self.horizontal_align = :merge
end
alias :merge! :center_across!
##
# Is the cell formatted as a Date?
def date?
!number? && matches_format?(:date)
end
##
# Is the cell formatted as a Date or Time?
def date_or_time?
!number? && matches_format?(:date_or_time)
end
##
# Is the cell formatted as a DateTime?
def datetime?
!number? && matches_format?(:datetime)
end
##
# Is the cell formatted as a Time?
def time?
!number? && matches_format?(:time)
end
##
# Is the cell formatted as a number?
def number?
matches_format?(:number)
end
##
# Does the cell match a particular preset format?
def matches_format?(name)
# Excel number formats may optionally include a locale identifier like this:
# [$-409]
format = @number_format.to_s.sub(@regexes[:locale], '')
!!@regexes[name].match(format)
end
end
end
|