Class: Writexlsx::Package::Styles

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

Constant Summary

Constants included from Utility

Utility::COL_MAX, 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, #convert_date_time, delete_files, #ptrue?, #put_deprecate_message, #row_col_notation, #store_col_max_min_values, #store_row_max_min_values, #substitute_cellref, #underline_attributes, #xl_cell_to_rowcol, #xl_col_to_name, #xl_range, #xl_range_formula, #xl_rowcol_to_cell, #xml_str

Constructor Details

#initializeStyles

Returns a new instance of Styles.



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

def initialize
  @writer = Package::XMLWriterSimple.new
  @xf_formats       = nil
  @palette          = []
  @font_count       = 0
  @num_format_count = 0
  @border_count     = 0
  @fill_count       = 0
  @custom_colors    = []
  @dxf_formats      = []
end

Instance Method Details

#assemble_xml_fileObject



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/write_xlsx/package/styles.rb', line 27

def assemble_xml_file
  write_xml_declaration
  write_style_sheet
  write_num_fmts
  write_fonts
  write_fills
  write_borders
  write_cell_style_xfs
  write_cell_xfs
  write_cell_styles
  write_dxfs
  write_table_styles
  write_colors
  @writer.end_tag('styleSheet')
  @writer.crlf
  @writer.close
end

#get_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.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/write_xlsx/package/styles.rb', line 63

def get_palette_color(index)
  palette = @palette

  # Handle colours in #XXXXXX RGB format.
  return "FF#{$1.upcase}" if index =~ /^#([0-9A-F]{6})$/i

  # Adjust the colour index.
  index -= 8

  # Palette is passed in from the Workbook class.
  rgb = @palette[index]

  sprintf("FF%02X%02X%02X", *rgb[0, 3])
end

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

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



48
49
50
51
52
53
54
55
56
57
# File 'lib/write_xlsx/package/styles.rb', line 48

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

#set_xml_writer(filename) ⇒ Object



23
24
25
# File 'lib/write_xlsx/package/styles.rb', line 23

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

#write_border(format, dxf_format = nil) ⇒ Object

Write the <border> element.



358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
# File 'lib/write_xlsx/package/styles.rb', line 358

def write_border(format, dxf_format = nil)
  attributes = []

  # Diagonal borders add attributes to the <border> element.
  if format.diag_type == 1
    attributes << 'diagonalUp'   << 1
  elsif format.diag_type == 2
    attributes << 'diagonalDown' << 1
  elsif format.diag_type == 3
    attributes << 'diagonalUp'   << 1
    attributes << 'diagonalDown' << 1
  end

  # 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 the start border tag.
  @writer.tag_elements('border', attributes) do
    # Write the <border> sub elements.
    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)

    # Condition DXF formats don't allow diagonal borders
    if !dxf_format
      write_sub_border('diagonal', format.diag_border, format.diag_color)
    end

    if dxf_format
      write_sub_border('vertical')
      write_sub_border('horizontal')
    end
  end
end

#write_bordersObject

Write the <borders> element.



338
339
340
341
342
343
344
# File 'lib/write_xlsx/package/styles.rb', line 338

def write_borders
  write_format_elements('borders', @border_count) do
    @xf_formats.each do |format|
      write_border(format) if format.has_border?
    end
  end
end

#write_cell_style_xfsObject

Write the <cellStyleXfs> element.



435
436
437
438
439
440
441
442
# File 'lib/write_xlsx/package/styles.rb', line 435

def write_cell_style_xfs
  attributes = ['count', 1]

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

#write_cell_xfsObject

Write the <cellXfs> element.



447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'lib/write_xlsx/package/styles.rb', line 447

def write_cell_xfs
  formats = @xf_formats

  # Workaround for when the last format is used for the comment font
  # and shouldn't be used for cellXfs.
  last_format =   formats[-1]

  formats.pop if last_format && last_format.font_only != 0

  attributes = ['count', formats.size]

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

#write_color(name, value) ⇒ Object

Write the <color> element.



239
240
241
242
243
# File 'lib/write_xlsx/package/styles.rb', line 239

def write_color(name, value)
  attributes = [name, value]

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

#write_default_fill(pattern_type) ⇒ Object

Write the <fill> element for the default fills.



268
269
270
271
272
# File 'lib/write_xlsx/package/styles.rb', line 268

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.



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/write_xlsx/package/styles.rb', line 277

def write_fill(format, dxf_format = nil)
  pattern    = format.pattern
  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

  patterns = %w(
    none
    solid
    mediumGray
    darkGray
    lightGray
    darkHorizontal
    darkVertical
    darkDown
    darkUp
    darkGrid
    darkTrellis
    lightHorizontal
    lightVertical
    lightDown
    lightUp
    lightGrid
    lightTrellis
    gray125
    gray0625
  )

  @writer.tag_elements('fill' ) do
    # The "none" pattern is handled differently for dxf formats.
    if dxf_format && format.pattern <= 1
      attributes = []
    else
      attributes = ['patternType', patterns[format.pattern]]
    end

    @writer.tag_elements('patternFill', attributes) do
      if fg_color && fg_color != 0
        fg_color = get_palette_color(fg_color)
        @writer.empty_tag('fgColor', ['rgb', fg_color])
      end

      if bg_color && bg_color != 0
        bg_color = get_palette_color(bg_color)
        @writer.empty_tag('bgColor', ['rgb', bg_color])
      else
        @writer.empty_tag('bgColor', ['indexed', 64]) if !dxf_format
      end
    end
  end
end

#write_fillsObject

Write the <fills> element.



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/write_xlsx/package/styles.rb', line 248

def write_fills
  count = @fill_count

  attributes = ['count', count]

  @writer.tag_elements('fills', attributes) do
    # 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
end

#write_font(format, dxf_format = nil) ⇒ Object

Write the <font> element.



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
219
220
221
222
223
224
# File 'lib/write_xlsx/package/styles.rb', line 183

def write_font(format, dxf_format = nil)
  @writer.tag_elements('font') do
    # The condense and extend elements are mainly used in dxf formats.
    write_condense unless format.font_condense == 0
    write_extend   unless format.font_extend   == 0

    @writer.empty_tag('b')       if format.bold?
    @writer.empty_tag('i')       if format.italic?
    @writer.empty_tag('strike')  if format.strikeout?
    @writer.empty_tag('outline') if format.outline?
    @writer.empty_tag('shadow')  if format.shadow?

    # Handle the underline variants.
    write_underline( format.underline ) if format.underline?

    write_vert_align('superscript') if format.font_script == 1
    write_vert_align('subscript')   if format.font_script == 2

    @writer.empty_tag('sz', ['val', format.size]) if !dxf_format

    theme = format.theme
    if theme != 0
      write_color('theme', theme)
    elsif format.color_indexed != 0
      write_color('indexed', format.color_indexed)
    elsif format.color != 0
      color = get_palette_color(format.color)
      write_color('rgb', color)
    elsif !dxf_format
      write_color('theme', 1)
    end

    if !dxf_format
      @writer.empty_tag('name',   ['val', format.font])
      @writer.empty_tag('family', ['val', format.font_family])

      if format.font == 'Calibri' && format.hyperlink == 0
        @writer.empty_tag('scheme', ['val', format.font_scheme])
      end
    end
  end
end

#write_fontsObject

Write the <fonts> element.



172
173
174
175
176
177
178
# File 'lib/write_xlsx/package/styles.rb', line 172

def write_fonts
  write_format_elements('fonts', @font_count) do
    @xf_formats.each do |format|
      write_font(format) if format.has_font?
    end
  end
end

#write_format_elements(elements, count) ⇒ Object



346
347
348
349
350
351
352
353
# File 'lib/write_xlsx/package/styles.rb', line 346

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

  @writer.tag_elements(elements, attributes) do
    # Write the border elements for format objects that have them.
    yield
  end
end

#write_num_fmt(num_fmt_id, format_code) ⇒ Object

Write the <numFmt> element.



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
# File 'lib/write_xlsx/package/styles.rb', line 112

def write_num_fmt(num_fmt_id, format_code)
  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 => '@'
  }

  # Set the format code for built-in number formats.
  if num_fmt_id < 164
    if format_codes[num_fmt_id]
      format_code = format_codes[num_fmt_id]
    else
      format_code = 'General'
    end
  end

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

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

#write_num_fmtsObject

Write the <numFmts> element.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/write_xlsx/package/styles.rb', line 92

def write_num_fmts
  count = @num_format_count

  return if count == 0

  attributes = ['count', count]

  @writer.tag_elements('numFmts', attributes) do
    # Write the numFmts elements.
    @xf_formats.each do |format|
      # Ignore built-in number formats, i.e., < 164.
      next unless format.num_format_index >= 164
      write_num_fmt(format.num_format_index, format.num_format)
    end
  end
end

#write_style_sheetObject

Write the <styleSheet> element.



81
82
83
84
85
86
87
# File 'lib/write_xlsx/package/styles.rb', line 81

def write_style_sheet
  xmlns = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'

  attributes = ['xmlns', xmlns]

  @writer.start_tag('styleSheet', attributes)
end

#write_style_xfObject

Write the style <xf> element.



467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
# File 'lib/write_xlsx/package/styles.rb', line 467

def write_style_xf
  num_fmt_id = 0
  font_id    = 0
  fill_id    = 0
  border_id  = 0

  attributes = [
    'numFmtId', num_fmt_id,
    'fontId',   font_id,
    'fillId',   fill_id,
    'borderId', border_id
  ]

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

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

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



397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
# File 'lib/write_xlsx/package/styles.rb', line 397

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

  border_styles = %w(
    none
    thin
    medium
    dashed
    dotted
    thick
    double
    hair
    mediumDashed
    dashDot
    mediumDashDot
    dashDotDot
    mediumDashDotDot
    slantDashDot
  )

  attributes = [:style, border_styles[style]]

  @writer.tag_elements(type, attributes) do
    if color != 0
      color = get_palette_color(color)
      @writer.empty_tag('color', ['rgb', color])
    else
      @writer.empty_tag('color', ['auto', 1])
    end
  end
end

#write_underline(underline) ⇒ Object

_write_underline()

Write the underline font element.



231
232
233
234
# File 'lib/write_xlsx/package/styles.rb', line 231

def write_underline(underline)
  attributes = underline_attributes(underline)
  @writer.empty_tag('u', attributes)
end