Class: Writexlsx::Package::Styles

Inherits:
Object
  • Object
show all
Includes:
Utility
Defined in:
lib/write_xlsx/package/styles.rb

Constant Summary collapse

FORMAT_CODES =
{
  0  => 'General',
  1  => '0',
  2  => '0.00',
  3  => '#,##0',
  4  => '#,##0.00',
  5  => '($#,##0_);($#,##0)',
  6  => '($#,##0_);[Red]($#,##0)',
  7  => '($#,##0.00_);($#,##0.00)',
  8  => '($#,##0.00_);[Red]($#,##0.00)',
  9  => '0%',
  10 => '0.00%',
  11 => '0.00E+00',
  12 => '# ?/?',
  13 => '# ??/??',
  14 => 'm/d/yy',
  15 => 'd-mmm-yy',
  16 => 'd-mmm',
  17 => 'mmm-yy',
  18 => 'h:mm AM/PM',
  19 => 'h:mm:ss AM/PM',
  20 => 'h:mm',
  21 => 'h:mm:ss',
  22 => 'm/d/yy h:mm',
  37 => '(#,##0_);(#,##0)',
  38 => '(#,##0_);[Red](#,##0)',
  39 => '(#,##0.00_);(#,##0.00)',
  40 => '(#,##0.00_);[Red](#,##0.00)',
  41 => '_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)',
  42 => '_($* #,##0_);_($* (#,##0);_($* "-"_);_(@_)',
  43 => '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)',
  44 => '_($* #,##0.00_);_($* (#,##0.00);_($* "-"??_);_(@_)',
  45 => 'mm:ss',
  46 => '[h]:mm:ss',
  47 => 'mm:ss.0',
  48 => '##0.0E+0',
  49 => '@'
}
PATTERNS =
%w[
  none
  solid
  mediumGray
  darkGray
  lightGray
  darkHorizontal
  darkVertical
  darkDown
  darkUp
  darkGrid
  darkTrellis
  lightHorizontal
  lightVertical
  lightDown
  lightUp
  lightGrid
  lightTrellis
  gray125
  gray0625
]
BORDER_STYLES =
%w[
  none
  thin
  medium
  dashed
  dotted
  thick
  double
  hair
  mediumDashed
  dashDot
  mediumDashDot
  dashDotDot
  mediumDashDotDot
  slantDashDot
]

Constants included from Utility

Utility::CHAR_WIDTHS, Utility::COL_MAX, Utility::PERL_TRUE_VALUES, Utility::ROW_MAX, Utility::SHEETNAME_MAX, Utility::STR_MAX

Instance Method Summary collapse

Methods included from Utility

#absolute_char, #check_dimensions, #check_dimensions_and_update_max_min_values, #check_parameter, #color, #convert_date_time, #convert_font_args, #dash_types, delete_files, #escape_url, #fill_properties, #float_to_str, #get_font_latin_attributes, #get_font_style_attributes, #get_image_properties, #layout_properties, #legend_properties, #line_fill_properties, #line_properties, #params_to_font, #pattern_properties, #pixels_to_points, #process_bmp, #process_gif, #process_jpg, #process_png, #process_workbook_options, #ptrue?, #put_deprecate_message, #quote_sheetname, #r_id_attributes, #row_col_notation, #shape_style_base, #store_col_max_min_values, #store_row_max_min_values, #substitute_cellref, #underline_attributes, #v_shape_attributes_base, #v_shape_style_base, #value_or_raise, #write_a_body_pr, #write_a_def_rpr, #write_a_end_para_rpr, #write_a_lst_style, #write_a_p_formula, #write_a_p_pr_formula, #write_a_solid_fill, #write_a_srgb_clr, #write_anchor, #write_auto_fill, #write_color, #write_comment_path, #write_def_rpr_r_pr_common, #write_div, #write_font, #write_stroke, #write_tx_pr, #write_xml_declaration, #xl_cell_to_rowcol, #xl_col_to_name, #xl_range, #xl_range_formula, #xl_rowcol_to_cell, #xl_string_pixel_width, #xml_str

Constructor Details

#initializeStyles

Returns a new instance of Styles.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/write_xlsx/package/styles.rb', line 12

def initialize
  @writer = Package::XMLWriterSimple.new
  @xf_formats        = nil
  @palette           = []
  @font_count        = 0
  @num_formats       = []
  @border_count      = 0
  @fill_count        = 0
  @custom_colors     = []
  @dxf_formats       = []
  @has_hyperlink     = 0
  @hyperlink_font_id = 0
  @has_comments      = false
end

Instance Method Details

#assemble_xml_fileObject



31
32
33
34
35
# File 'lib/write_xlsx/package/styles.rb', line 31

def assemble_xml_file
  write_xml_declaration do
    write_style_sheet { write_style_sheet_base }
  end
end

#bg_and_fg_color(format, dxf_format) ⇒ Object



293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/write_xlsx/package/styles.rb', line 293

def bg_and_fg_color(format, dxf_format)
  bg_color   = format.bg_color
  fg_color   = format.fg_color

  # Colors for dxf formats are handled differently from normal formats since
  # the normal format reverses the meaning of BG and FG for solid fills.
  if dxf_format && dxf_format != 0
    bg_color = format.dxf_bg_color
    fg_color = format.dxf_fg_color
  end

  [bg_color, fg_color]
end

#palette_color(index) ⇒ Object

Convert from an Excel internal colour index to a XML style #RRGGBB index based on the default or user defined values in the Workbook palette.



59
60
61
62
63
64
65
66
67
# File 'lib/write_xlsx/package/styles.rb', line 59

def palette_color(index)
  if index.to_s =~ /^#([0-9A-F]{6})$/i
    "FF#{::Regexp.last_match(1).upcase}"
  elsif index == 0x40
    "Automatic"
  else
    "FF#{super(index)}"
  end
end

#pattern_only_case?(format, dxf_format) ⇒ Boolean

Returns:

  • (Boolean)


258
259
260
261
262
# File 'lib/write_xlsx/package/styles.rb', line 258

def pattern_only_case?(format, dxf_format)
  bg_color, fg_color = bg_and_fg_color(format, dxf_format)

  !ptrue?(fg_color) && !ptrue?(bg_color) && ptrue?(format.pattern)
end

#set_style_properties(xf_formats, palette, font_count, num_formats, border_count, fill_count, custom_colors, dxf_formats, has_comments) ⇒ Object

Pass in the Format objects and other properties used to set the styles.



40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/write_xlsx/package/styles.rb', line 40

def set_style_properties(
      xf_formats, palette, font_count, num_formats, border_count,
      fill_count, custom_colors, dxf_formats, has_comments
    )
  @xf_formats    = xf_formats
  @palette       = palette
  @font_count    = font_count
  @num_formats   = num_formats
  @border_count  = border_count
  @fill_count    = fill_count
  @custom_colors = custom_colors
  @dxf_formats   = dxf_formats
  @has_comments  = has_comments
end

#set_xml_writer(filename) ⇒ Object



27
28
29
# File 'lib/write_xlsx/package/styles.rb', line 27

def set_xml_writer(filename)
  @writer.set_xml_writer(filename)
end

#write_border(format, dxf_format = nil) ⇒ Object

Write the <border> element.



331
332
333
334
335
336
# File 'lib/write_xlsx/package/styles.rb', line 331

def write_border(format, dxf_format = nil)
  # Write the start border tag.
  @writer.tag_elements('border', format.border_attributes) do
    write_border_base(format, dxf_format)
  end
end

#write_border_base(format, dxf_format) ⇒ Object



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/write_xlsx/package/styles.rb', line 338

def write_border_base(format, dxf_format)
  # Write the <border> sub elements.
  write_border_sub_elements(format)

  # Condition DXF formats don't allow diagonal borders
  if dxf_format
    write_sub_border('vertical')
    write_sub_border('horizontal')
  else
    # Ensure that a default diag border is set if the diag type is set.
    format.diag_border = 1 if format.diag_type != 0 && format.diag_border == 0

    write_sub_border('diagonal', format.diag_border, format.diag_color)
  end
end

#write_border_sub_elements(format) ⇒ Object



354
355
356
357
358
359
# File 'lib/write_xlsx/package/styles.rb', line 354

def write_border_sub_elements(format)
  write_sub_border('left',   format.left,   format.left_color)
  write_sub_border('right',  format.right,  format.right_color)
  write_sub_border('top',    format.top,    format.top_color)
  write_sub_border('bottom', format.bottom, format.bottom_color)
end

#write_bordersObject

Write the <borders> element.



310
311
312
313
314
# File 'lib/write_xlsx/package/styles.rb', line 310

def write_borders
  write_format_elements('borders', @border_count) do
    write_borders_base
  end
end

#write_borders_baseObject



316
317
318
319
320
# File 'lib/write_xlsx/package/styles.rb', line 316

def write_borders_base
  @xf_formats.each do |format|
    write_border(format) if format.has_border?
  end
end

#write_cell_style_xfsObject

Write the <cellStyleXfs> element.



403
404
405
406
407
408
409
410
411
412
413
414
# File 'lib/write_xlsx/package/styles.rb', line 403

def write_cell_style_xfs
  count = ptrue?(@has_hyperlink) ? 2 : 1

  attributes = [['count', count]]

  @writer.tag_elements('cellStyleXfs', attributes) do
    # Write the style_xf element.
    write_style_xf(0, 0)

    write_style_xf(1, @hyperlink_font_id) if ptrue?(@has_hyperlink)
  end
end

#write_cell_xfsObject

Write the <cellXfs> element.



419
420
421
422
423
424
425
426
427
428
# File 'lib/write_xlsx/package/styles.rb', line 419

def write_cell_xfs
  formats = @xf_formats

  attributes = [['count', formats.size]]

  @writer.tag_elements('cellXfs', attributes) do
    # Write the xf elements.
    formats.each { |format| write_xf(format) }
  end
end

#write_comment_fontObject

Write the <font> element used for comments.



182
183
184
185
186
187
188
189
# File 'lib/write_xlsx/package/styles.rb', line 182

def write_comment_font
  @writer.tag_elements('font') do
    @writer.empty_tag('sz', [['val', 8]])
    write_color('indexed', 81)
    @writer.empty_tag('name',   [%w[val Tahoma]])
    @writer.empty_tag('family', [['val', 2]])
  end
end

#write_default_fill(pattern_type) ⇒ Object

Write the <fill> element for the default fills.



216
217
218
219
220
# File 'lib/write_xlsx/package/styles.rb', line 216

def write_default_fill(pattern_type)
  @writer.tag_elements('fill') do
    @writer.empty_tag('patternFill', [['patternType', pattern_type]])
  end
end

#write_fill(format, dxf_format = nil) ⇒ Object

Write the <fill> element.



247
248
249
250
251
252
253
254
255
256
# File 'lib/write_xlsx/package/styles.rb', line 247

def write_fill(format, dxf_format = nil)
  # Special handling for pattern only case.
  if pattern_only_case?(format, dxf_format)
    write_default_fill(PATTERNS[format.pattern])
  else
    @writer.tag_elements('fill') do
      write_fill_base(format, dxf_format)
    end
  end
end

#write_fill_base(format, dxf_format) ⇒ Object



264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/write_xlsx/package/styles.rb', line 264

def write_fill_base(format, dxf_format)
  # The "none" pattern is handled differently for dxf formats.
  attributes = if dxf_format && format.pattern <= 1
                 []
               else
                 [['patternType', PATTERNS[format.pattern]]]
               end

  @writer.tag_elements('patternFill', attributes) do
    write_pattern_fill(format, dxf_format)
  end
end

#write_fillsObject

Write the <fills> element.



194
195
196
197
198
199
200
# File 'lib/write_xlsx/package/styles.rb', line 194

def write_fills
  attributes = [['count', @fill_count]]

  @writer.tag_elements('fills', attributes) do
    write_fills_base
  end
end

#write_fills_baseObject



202
203
204
205
206
207
208
209
210
211
# File 'lib/write_xlsx/package/styles.rb', line 202

def write_fills_base
  # Write the default fill element.
  write_default_fill('none')
  write_default_fill('gray125')

  # Write the fill elements for format objects that have them.
  @xf_formats.each do |format|
    write_fill(format) if format.has_fill?
  end
end

#write_font_baseObject



168
169
170
171
172
173
174
175
176
177
# File 'lib/write_xlsx/package/styles.rb', line 168

def write_font_base
  @xf_formats.each do |format|
    next unless format.has_font?

    format.write_font(@writer, self)
    @has_hyperlink     = 1 if ptrue?(format.hyperlink)
    @hyperlink_font_id = format.font_index unless ptrue?(@hyperlink_font_id)
  end
  write_comment_font if @has_comments
end

#write_fontsObject

Write the <fonts> element.



155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/write_xlsx/package/styles.rb', line 155

def write_fonts
  count = @font_count

  if @has_comments
    # Add an extra font for comments.
    count += 1
  end

  write_format_elements('fonts', count) do
    write_font_base
  end
end

#write_format_elements(elements, count, &block) ⇒ Object



322
323
324
325
326
# File 'lib/write_xlsx/package/styles.rb', line 322

def write_format_elements(elements, count, &block)
  attributes = [['count', count]]

  @writer.tag_elements(elements, attributes, &block)
end

#write_num_fmt(num_fmt_id, format_code) ⇒ Object

Write the <numFmt> element.



140
141
142
143
144
145
146
147
148
149
150
# File 'lib/write_xlsx/package/styles.rb', line 140

def write_num_fmt(num_fmt_id, format_code)
  # Set the format code for built-in number formats.
  format_code = FORMAT_CODES[num_fmt_id] || 'General' if num_fmt_id < 164

  attributes = [
    ['numFmtId',   num_fmt_id],
    ['formatCode', format_code]
  ]

  @writer.empty_tag('numFmt', attributes)
end

#write_num_fmtsObject

Write the <numFmts> element.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/write_xlsx/package/styles.rb', line 81

def write_num_fmts
  count = @num_formats.size

  return if count == 0

  attributes = [['count', count]]

  @writer.tag_elements('numFmts', attributes) do
    # Write the numFmts elements.
    index = 164
    @num_formats.each do |num_format|
      write_num_fmt(index, num_format)
      index += 1
    end
  end
end

#write_pattern_fill(format, dxf_format) ⇒ Object



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/write_xlsx/package/styles.rb', line 277

def write_pattern_fill(format, dxf_format)
  bg_color, fg_color = bg_and_fg_color(format, dxf_format)

  if fg_color && fg_color != 0 && fg_color != 0x40  # 'Automatic'
    @writer.empty_tag('fgColor', [['rgb', palette_color(fg_color)]])
  end

  if bg_color && bg_color != 0
    if bg_color != 0x40 # 'Automatic'
      @writer.empty_tag('bgColor', [['rgb', palette_color(bg_color)]])
    end
  elsif !dxf_format && format.pattern <= 1
    @writer.empty_tag('bgColor', [['indexed', 64]])
  end
end

#write_style_sheet(&block) ⇒ Object

Write the <styleSheet> element.



72
73
74
75
76
# File 'lib/write_xlsx/package/styles.rb', line 72

def write_style_sheet(&block)
  attributes = [['xmlns', XMLWriterSimple::XMLNS]]

  @writer.tag_elements('styleSheet', attributes, &block)
end

#write_style_xf(has_hyperlink, font_id) ⇒ Object

Write the style <xf> element.



433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
# File 'lib/write_xlsx/package/styles.rb', line 433

def write_style_xf(has_hyperlink, font_id)
  attributes = [
    ['numFmtId', 0],
    ['fontId',   font_id],
    ['fillId',   0],
    ['borderId', 0]
  ]

  if ptrue?(has_hyperlink)
    attributes << ['applyNumberFormat', 0]
    attributes << ['applyFill',         0]
    attributes << ['applyBorder',       0]
    attributes << ['applyAlignment',    0]
    attributes << ['applyProtection',   0]
    @writer.tag_elements('xf', attributes) do
      @writer.empty_tag('alignment',  [%w[vertical top]])
      @writer.empty_tag('protection', [['locked',   0]])
    end
  else
    @writer.empty_tag('xf', attributes)
  end
end

#write_sub_border(type, style = 0, color = nil) ⇒ Object

Write the <border> sub elements such as <right>, <top>, etc.



381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
# File 'lib/write_xlsx/package/styles.rb', line 381

def write_sub_border(type, style = 0, color = nil)
  if style == 0
    @writer.empty_tag(type)
    return
  end

  attributes = [[:style, BORDER_STYLES[style]]]

  @writer.tag_elements(type, attributes) do
    if [0, 0x40].include?(color) # 'Automatic'
      @writer.empty_tag('color', [['auto', 1]])
    elsif color != 0 && color != 0x40 # 'Automatic'
      color = palette_color(color)

      @writer.empty_tag('color', [['rgb', color]])
    end
  end
end