xlsxwriter 0.2.1.pre → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +4 -3
  3. data/ext/xlsxwriter/chart.c +88 -80
  4. data/ext/xlsxwriter/chart.h +2 -2
  5. data/ext/xlsxwriter/chartsheet.c +307 -0
  6. data/ext/xlsxwriter/chartsheet.h +15 -0
  7. data/ext/xlsxwriter/common.h +104 -0
  8. data/ext/xlsxwriter/extconf.rb +8 -8
  9. data/ext/xlsxwriter/libxlsxwriter/License.txt +24 -2
  10. data/ext/xlsxwriter/libxlsxwriter/Makefile +46 -12
  11. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/app.h +1 -1
  12. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/chart.h +196 -30
  13. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/chartsheet.h +3 -3
  14. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/comment.h +76 -0
  15. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/common.h +24 -5
  16. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/content_types.h +5 -1
  17. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/core.h +1 -1
  18. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/custom.h +1 -1
  19. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/drawing.h +6 -17
  20. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/format.h +20 -6
  21. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
  22. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/packager.h +3 -1
  23. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/relationships.h +1 -1
  24. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/shared_strings.h +1 -1
  25. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/styles.h +11 -5
  26. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/theme.h +1 -1
  27. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/third_party/md5.h +43 -0
  28. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/utility.h +42 -3
  29. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/vml.h +55 -0
  30. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/workbook.h +83 -18
  31. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/worksheet.h +1519 -109
  32. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/xmlwriter.h +4 -2
  33. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter.h +3 -2
  34. data/ext/xlsxwriter/libxlsxwriter/src/Makefile +25 -7
  35. data/ext/xlsxwriter/libxlsxwriter/src/app.c +1 -1
  36. data/ext/xlsxwriter/libxlsxwriter/src/chart.c +332 -48
  37. data/ext/xlsxwriter/libxlsxwriter/src/chartsheet.c +20 -19
  38. data/ext/xlsxwriter/libxlsxwriter/src/comment.c +443 -0
  39. data/ext/xlsxwriter/libxlsxwriter/src/content_types.c +20 -1
  40. data/ext/xlsxwriter/libxlsxwriter/src/core.c +2 -2
  41. data/ext/xlsxwriter/libxlsxwriter/src/custom.c +1 -1
  42. data/ext/xlsxwriter/libxlsxwriter/src/drawing.c +58 -20
  43. data/ext/xlsxwriter/libxlsxwriter/src/format.c +98 -25
  44. data/ext/xlsxwriter/libxlsxwriter/src/hash_table.c +1 -1
  45. data/ext/xlsxwriter/libxlsxwriter/src/packager.c +269 -12
  46. data/ext/xlsxwriter/libxlsxwriter/src/relationships.c +1 -1
  47. data/ext/xlsxwriter/libxlsxwriter/src/shared_strings.c +2 -4
  48. data/ext/xlsxwriter/libxlsxwriter/src/styles.c +334 -48
  49. data/ext/xlsxwriter/libxlsxwriter/src/theme.c +1 -1
  50. data/ext/xlsxwriter/libxlsxwriter/src/utility.c +71 -8
  51. data/ext/xlsxwriter/libxlsxwriter/src/vml.c +1032 -0
  52. data/ext/xlsxwriter/libxlsxwriter/src/workbook.c +343 -27
  53. data/ext/xlsxwriter/libxlsxwriter/src/worksheet.c +3759 -478
  54. data/ext/xlsxwriter/libxlsxwriter/src/xmlwriter.c +81 -2
  55. data/ext/xlsxwriter/libxlsxwriter/third_party/md5/Makefile +42 -0
  56. data/ext/xlsxwriter/libxlsxwriter/third_party/md5/md5.c +291 -0
  57. data/ext/xlsxwriter/libxlsxwriter/third_party/md5/md5.h +43 -0
  58. data/ext/xlsxwriter/shared_strings.c +65 -0
  59. data/ext/xlsxwriter/shared_strings.h +15 -0
  60. data/ext/xlsxwriter/workbook.c +96 -20
  61. data/ext/xlsxwriter/worksheet.c +125 -235
  62. data/ext/xlsxwriter/worksheet.h +2 -1
  63. data/ext/xlsxwriter/xlsxwriter.c +4 -0
  64. data/lib/xlsxwriter/rich_string.rb +0 -2
  65. data/lib/xlsxwriter/version.rb +1 -1
  66. data/lib/xlsxwriter/worksheet.rb +2 -2
  67. data/test/{run-test.rb → run_test.rb} +3 -3
  68. data/test/support/chart_test.rb +3 -3
  69. data/test/support/with_xlsx_file.rb +4 -2
  70. data/test/support/xlsx_comparable.rb +40 -26
  71. data/test/test_array_formula.rb +42 -0
  72. data/test/test_autofilter.rb +72 -0
  73. data/test/{test-chart-area.rb → test_chart_area.rb} +2 -2
  74. data/test/{test-chart-axis.rb → test_chart_axis.rb} +16 -16
  75. data/test/test_chart_bar.rb +382 -0
  76. data/test/test_chart_blank.rb +27 -0
  77. data/test/{test-chart-column.rb → test_chart_column.rb} +2 -2
  78. data/test/{test-chart-doughnut.rb → test_chart_doughnut.rb} +2 -2
  79. data/test/{test-chart-legend.rb → test_chart_legend.rb} +2 -2
  80. data/test/{test-chart-pie.rb → test_chart_pie.rb} +2 -2
  81. data/test/{test-chart-scatter.rb → test_chart_scatter.rb} +3 -4
  82. data/test/{test-chart-size.rb → test_chart_size.rb} +2 -2
  83. data/test/{test-chart-title.rb → test_chart_title.rb} +3 -3
  84. data/test/test_chartsheet.rb +201 -0
  85. data/test/{test-data.rb → test_data.rb} +1 -1
  86. data/test/{test-data-validation.rb → test_data_validation.rb} +23 -24
  87. data/test/{test-default-row.rb → test_default_row.rb} +1 -1
  88. data/test/{test-defined-name.rb → test_defined_name.rb} +12 -12
  89. data/test/{test-escapes.rb → test_escapes.rb} +5 -2
  90. data/test/{test-fit-to-pages.rb → test_fit_to_pages.rb} +6 -6
  91. data/test/{test-formatting.rb → test_formatting.rb} +10 -10
  92. data/test/{test-gridlines.rb → test_gridlines.rb} +3 -3
  93. data/test/{test-hyperlink.rb → test_hyperlink.rb} +22 -11
  94. data/test/{test-image.rb → test_image.rb} +6 -4
  95. data/test/{test-macro.rb → test_macro.rb} +1 -1
  96. data/test/{test-merge-range.rb → test_merge_range.rb} +1 -1
  97. data/test/{test-misc.rb → test_misc.rb} +2 -2
  98. data/test/{test-optimize.rb → test_optimize.rb} +2 -4
  99. data/test/{test-outline.rb → test_outline.rb} +14 -14
  100. data/test/{test-page-breaks.rb → test_page_breaks.rb} +2 -2
  101. data/test/{test-page-setup.rb → test_page_setup.rb} +2 -2
  102. data/test/{test-panes.rb → test_panes.rb} +1 -1
  103. data/test/{test-print-area.rb → test_print_area.rb} +3 -3
  104. data/test/{test-print-options.rb → test_print_options.rb} +7 -7
  105. data/test/{test-print-scale.rb → test_print_scale.rb} +2 -2
  106. data/test/{test-properties.rb → test_properties.rb} +2 -2
  107. data/test/{test-protect.rb → test_protect.rb} +3 -3
  108. data/test/{test-repeat.rb → test_repeat.rb} +3 -3
  109. data/test/{test-rich-string.rb → test_rich_string.rb} +5 -9
  110. data/test/{test-row-col-format.rb → test_row_col_format.rb} +1 -1
  111. data/test/{test-ruby-worksheet.rb → test_ruby_worksheet.rb} +2 -2
  112. data/test/{test-set-selection.rb → test_set_selection.rb} +2 -2
  113. data/test/{test-set-start-page.rb → test_set_start_page.rb} +2 -2
  114. data/test/{test-simple.rb → test_simple.rb} +10 -10
  115. data/test/{test-types.rb → test_types.rb} +1 -1
  116. data/test/{xlsx-func-testcase.rb → xlsx_func_testcase.rb} +1 -0
  117. metadata +135 -104
  118. data/test/test-array-formula.rb +0 -35
  119. data/test/test-autofilter.rb +0 -72
  120. data/test/test-chart-bar.rb +0 -74
  121. /data/test/{test-errors.rb → test_errors.rb} +0 -0
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Used in conjunction with the libxlsxwriter library.
5
5
  *
6
- * Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
6
+ * Copyright 2014-2020, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7
7
  *
8
8
  */
9
9
 
@@ -14,7 +14,7 @@
14
14
  /*
15
15
  * Forward declarations.
16
16
  */
17
- STATIC void _write_font(lxw_styles *self, lxw_format *format,
17
+ STATIC void _write_font(lxw_styles *self, lxw_format *format, uint8_t is_dxf,
18
18
  uint8_t is_rich_string);
19
19
 
20
20
  /*****************************************************************************
@@ -34,9 +34,12 @@ lxw_styles_new(void)
34
34
 
35
35
  styles->xf_formats = calloc(1, sizeof(struct lxw_formats));
36
36
  GOTO_LABEL_ON_MEM_ERROR(styles->xf_formats, mem_error);
37
-
38
37
  STAILQ_INIT(styles->xf_formats);
39
38
 
39
+ styles->dxf_formats = calloc(1, sizeof(struct lxw_formats));
40
+ GOTO_LABEL_ON_MEM_ERROR(styles->dxf_formats, mem_error);
41
+ STAILQ_INIT(styles->dxf_formats);
42
+
40
43
  return styles;
41
44
 
42
45
  mem_error:
@@ -55,7 +58,7 @@ lxw_styles_free(lxw_styles *styles)
55
58
  if (!styles)
56
59
  return;
57
60
 
58
- /* Free the formats in the styles. */
61
+ /* Free the xf formats in the styles. */
59
62
  if (styles->xf_formats) {
60
63
  while (!STAILQ_EMPTY(styles->xf_formats)) {
61
64
  format = STAILQ_FIRST(styles->xf_formats);
@@ -65,6 +68,16 @@ lxw_styles_free(lxw_styles *styles)
65
68
  free(styles->xf_formats);
66
69
  }
67
70
 
71
+ /* Free the dxf formats in the styles. */
72
+ if (styles->dxf_formats) {
73
+ while (!STAILQ_EMPTY(styles->dxf_formats)) {
74
+ format = STAILQ_FIRST(styles->dxf_formats);
75
+ STAILQ_REMOVE_HEAD(styles->dxf_formats, list_pointers);
76
+ free(format);
77
+ }
78
+ free(styles->dxf_formats);
79
+ }
80
+
68
81
  free(styles);
69
82
  }
70
83
 
@@ -93,7 +106,7 @@ void
93
106
  lxw_styles_write_rich_font(lxw_styles *self, lxw_format *format)
94
107
  {
95
108
 
96
- _write_font(self, format, LXW_TRUE);
109
+ _write_font(self, format, LXW_FALSE, LXW_TRUE);
97
110
  }
98
111
 
99
112
  /*****************************************************************************
@@ -136,10 +149,68 @@ _write_num_fmt(lxw_styles *self, uint16_t num_fmt_id, char *format_code)
136
149
  {
137
150
  struct xml_attribute_list attributes;
138
151
  struct xml_attribute *attribute;
152
+ char *format_codes[] = {
153
+ "General",
154
+ "0",
155
+ "0.00",
156
+ "#,##0",
157
+ "#,##0.00",
158
+ "($#,##0_);($#,##0)",
159
+ "($#,##0_);[Red]($#,##0)",
160
+ "($#,##0.00_);($#,##0.00)",
161
+ "($#,##0.00_);[Red]($#,##0.00)",
162
+ "0%",
163
+ "0.00%",
164
+ "0.00E+00",
165
+ "# ?/?",
166
+ "# ?" "?/?" "?", /* Split string to avoid unintentional trigraph. */
167
+ "m/d/yy",
168
+ "d-mmm-yy",
169
+ "d-mmm",
170
+ "mmm-yy",
171
+ "h:mm AM/PM",
172
+ "h:mm:ss AM/PM",
173
+ "h:mm",
174
+ "h:mm:ss",
175
+ "m/d/yy h:mm",
176
+ "General",
177
+ "General",
178
+ "General",
179
+ "General",
180
+ "General",
181
+ "General",
182
+ "General",
183
+ "General",
184
+ "General",
185
+ "General",
186
+ "General",
187
+ "General",
188
+ "General",
189
+ "General",
190
+ "(#,##0_);(#,##0)",
191
+ "(#,##0_);[Red](#,##0)",
192
+ "(#,##0.00_);(#,##0.00)",
193
+ "(#,##0.00_);[Red](#,##0.00)",
194
+ "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
195
+ "_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)",
196
+ "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
197
+ "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)",
198
+ "mm:ss",
199
+ "[h]:mm:ss",
200
+ "mm:ss.0",
201
+ "##0.0E+0",
202
+ "@"
203
+ };
139
204
 
140
205
  LXW_INIT_ATTRIBUTES();
141
206
  LXW_PUSH_ATTRIBUTES_INT("numFmtId", num_fmt_id);
142
- LXW_PUSH_ATTRIBUTES_STR("formatCode", format_code);
207
+
208
+ if (num_fmt_id < 50)
209
+ LXW_PUSH_ATTRIBUTES_STR("formatCode", format_codes[num_fmt_id]);
210
+ else if (num_fmt_id < 164)
211
+ LXW_PUSH_ATTRIBUTES_STR("formatCode", "General");
212
+ else
213
+ LXW_PUSH_ATTRIBUTES_STR("formatCode", format_code);
143
214
 
144
215
  lxw_xml_empty_tag(self->file, "numFmt", &attributes);
145
216
 
@@ -240,6 +311,23 @@ _write_font_color_rgb(lxw_styles *self, int32_t rgb)
240
311
  LXW_FREE_ATTRIBUTES();
241
312
  }
242
313
 
314
+ /*
315
+ * Write the <color> element for indexed colors.
316
+ */
317
+ STATIC void
318
+ _write_font_color_indexed(lxw_styles *self, uint8_t index)
319
+ {
320
+ struct xml_attribute_list attributes;
321
+ struct xml_attribute *attribute;
322
+
323
+ LXW_INIT_ATTRIBUTES();
324
+ LXW_PUSH_ATTRIBUTES_INT("indexed", index);
325
+
326
+ lxw_xml_empty_tag(self->file, "color", &attributes);
327
+
328
+ LXW_FREE_ATTRIBUTES();
329
+ }
330
+
243
331
  /*
244
332
  * Write the <name> element.
245
333
  */
@@ -329,11 +417,45 @@ _write_font_underline(lxw_styles *self, uint8_t underline)
329
417
 
330
418
  }
331
419
 
420
+ /*
421
+ * Write the font <condense> element.
422
+ */
423
+ STATIC void
424
+ _write_font_condense(lxw_styles *self)
425
+ {
426
+ struct xml_attribute_list attributes;
427
+ struct xml_attribute *attribute;
428
+
429
+ LXW_INIT_ATTRIBUTES();
430
+ LXW_PUSH_ATTRIBUTES_STR("val", "0");
431
+
432
+ lxw_xml_empty_tag(self->file, "condense", &attributes);
433
+
434
+ LXW_FREE_ATTRIBUTES();
435
+ }
436
+
437
+ /*
438
+ * Write the font <extend> element.
439
+ */
440
+ STATIC void
441
+ _write_font_extend(lxw_styles *self)
442
+ {
443
+ struct xml_attribute_list attributes;
444
+ struct xml_attribute *attribute;
445
+
446
+ LXW_INIT_ATTRIBUTES();
447
+ LXW_PUSH_ATTRIBUTES_STR("val", "0");
448
+
449
+ lxw_xml_empty_tag(self->file, "extend", &attributes);
450
+
451
+ LXW_FREE_ATTRIBUTES();
452
+ }
453
+
332
454
  /*
333
455
  * Write the <vertAlign> font sub-element.
334
456
  */
335
457
  STATIC void
336
- _write_vert_align(lxw_styles *self, const char *align)
458
+ _write_font_vert_align(lxw_styles *self, const char *align)
337
459
  {
338
460
  struct xml_attribute_list attributes;
339
461
  struct xml_attribute *attribute;
@@ -350,13 +472,20 @@ _write_vert_align(lxw_styles *self, const char *align)
350
472
  * Write the <font> element.
351
473
  */
352
474
  STATIC void
353
- _write_font(lxw_styles *self, lxw_format *format, uint8_t is_rich_string)
475
+ _write_font(lxw_styles *self, lxw_format *format, uint8_t is_dxf,
476
+ uint8_t is_rich_string)
354
477
  {
355
478
  if (is_rich_string)
356
479
  lxw_xml_start_tag(self->file, "rPr", NULL);
357
480
  else
358
481
  lxw_xml_start_tag(self->file, "font", NULL);
359
482
 
483
+ if (format->font_condense)
484
+ _write_font_condense(self);
485
+
486
+ if (format->font_extend)
487
+ _write_font_extend(self);
488
+
360
489
  if (format->bold)
361
490
  lxw_xml_empty_tag(self->file, "b", NULL);
362
491
 
@@ -376,30 +505,41 @@ _write_font(lxw_styles *self, lxw_format *format, uint8_t is_rich_string)
376
505
  _write_font_underline(self, format->underline);
377
506
 
378
507
  if (format->font_script == LXW_FONT_SUPERSCRIPT)
379
- _write_vert_align(self, "superscript");
508
+ _write_font_vert_align(self, "superscript");
380
509
 
381
510
  if (format->font_script == LXW_FONT_SUBSCRIPT)
382
- _write_vert_align(self, "subscript");
511
+ _write_font_vert_align(self, "subscript");
383
512
 
384
- if (format->font_size > 0.0)
513
+ if (!is_dxf && format->font_size > 0.0)
385
514
  _write_font_size(self, format->font_size);
386
515
 
387
516
  if (format->theme)
388
517
  _write_font_color_theme(self, format->theme);
518
+ else if (format->color_indexed)
519
+ _write_font_color_indexed(self, format->color_indexed);
389
520
  else if (format->font_color != LXW_COLOR_UNSET)
390
521
  _write_font_color_rgb(self, format->font_color);
391
- else
522
+ else if (!is_dxf)
392
523
  _write_font_color_theme(self, LXW_DEFAULT_FONT_THEME);
393
524
 
394
- _write_font_name(self, format->font_name, is_rich_string);
395
- _write_font_family(self, format->font_family);
525
+ if (!is_dxf) {
526
+ _write_font_name(self, format->font_name, is_rich_string);
527
+ _write_font_family(self, format->font_family);
528
+
529
+ /* Only write the scheme element for the default font type if it
530
+ * is a hyperlink. */
531
+ if ((!*format->font_name
532
+ || strcmp(LXW_DEFAULT_FONT_NAME, format->font_name) == 0)
533
+ && !format->hyperlink) {
534
+ _write_font_scheme(self, format->font_scheme);
535
+ }
536
+ }
537
+
538
+ if (format->hyperlink) {
539
+ self->has_hyperlink = LXW_TRUE;
396
540
 
397
- /* Only write the scheme element for the default font type if it
398
- * is a hyperlink. */
399
- if ((!*format->font_name
400
- || strcmp(LXW_DEFAULT_FONT_NAME, format->font_name) == 0)
401
- && !format->hyperlink) {
402
- _write_font_scheme(self, format->font_scheme);
541
+ if (self->hyperlink_font_id == 0)
542
+ self->hyperlink_font_id = format->font_index;
403
543
  }
404
544
 
405
545
  if (is_rich_string)
@@ -408,6 +548,22 @@ _write_font(lxw_styles *self, lxw_format *format, uint8_t is_rich_string)
408
548
  lxw_xml_end_tag(self->file, "font");
409
549
  }
410
550
 
551
+ /*
552
+ * Write the <font> element for comments.
553
+ */
554
+ STATIC void
555
+ _write_comment_font(lxw_styles *self)
556
+ {
557
+ lxw_xml_start_tag(self->file, "font", NULL);
558
+
559
+ _write_font_size(self, 8);
560
+ _write_font_color_indexed(self, 81);
561
+ _write_font_name(self, "Tahoma", LXW_FALSE);
562
+ _write_font_family(self, 2);
563
+
564
+ lxw_xml_end_tag(self->file, "font");
565
+ }
566
+
411
567
  /*
412
568
  * Write the <fonts> element.
413
569
  */
@@ -417,17 +573,26 @@ _write_fonts(lxw_styles *self)
417
573
  struct xml_attribute_list attributes;
418
574
  struct xml_attribute *attribute;
419
575
  lxw_format *format;
576
+ uint32_t count;
420
577
 
421
578
  LXW_INIT_ATTRIBUTES();
422
- LXW_PUSH_ATTRIBUTES_INT("count", self->font_count);
579
+
580
+ count = self->font_count;
581
+ if (self->has_comments)
582
+ count++;
583
+
584
+ LXW_PUSH_ATTRIBUTES_INT("count", count);
423
585
 
424
586
  lxw_xml_start_tag(self->file, "fonts", &attributes);
425
587
 
426
588
  STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
427
589
  if (format->has_font)
428
- _write_font(self, format, LXW_FALSE);
590
+ _write_font(self, format, LXW_FALSE, LXW_FALSE);
429
591
  }
430
592
 
593
+ if (self->has_comments)
594
+ _write_comment_font(self);
595
+
431
596
  lxw_xml_end_tag(self->file, "fonts");
432
597
 
433
598
  LXW_FREE_ATTRIBUTES();
@@ -501,7 +666,7 @@ _write_bg_color(lxw_styles *self, lxw_color_t color)
501
666
  * Write the <fill> element.
502
667
  */
503
668
  STATIC void
504
- _write_fill(lxw_styles *self, lxw_format *format)
669
+ _write_fill(lxw_styles *self, lxw_format *format, uint8_t is_dxf)
505
670
  {
506
671
  struct xml_attribute_list attributes;
507
672
  struct xml_attribute *attribute;
@@ -532,11 +697,17 @@ _write_fill(lxw_styles *self, lxw_format *format)
532
697
  "gray0625",
533
698
  };
534
699
 
700
+ if (is_dxf) {
701
+ bg_color = format->dxf_bg_color;
702
+ fg_color = format->dxf_fg_color;
703
+ }
704
+
535
705
  LXW_INIT_ATTRIBUTES();
536
706
 
537
707
  lxw_xml_start_tag(self->file, "fill", NULL);
538
708
 
539
- if (pattern)
709
+ /* None/Solid patterns are handled differently for dxf formats. */
710
+ if (pattern && !(is_dxf && pattern <= LXW_PATTERN_SOLID))
540
711
  LXW_PUSH_ATTRIBUTES_STR("patternType", patterns[pattern]);
541
712
 
542
713
  lxw_xml_start_tag(self->file, "patternFill", &attributes);
@@ -573,7 +744,7 @@ _write_fills(lxw_styles *self)
573
744
 
574
745
  STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
575
746
  if (format->has_fill)
576
- _write_fill(self, format);
747
+ _write_fill(self, format, LXW_FALSE);
577
748
  }
578
749
 
579
750
  lxw_xml_end_tag(self->file, "fills");
@@ -654,7 +825,7 @@ _write_sub_border(lxw_styles *self, const char *type, uint8_t style,
654
825
  * Write the <border> element.
655
826
  */
656
827
  STATIC void
657
- _write_border(lxw_styles *self, lxw_format *format)
828
+ _write_border(lxw_styles *self, lxw_format *format, uint8_t is_dxf)
658
829
  {
659
830
  struct xml_attribute_list attributes;
660
831
  struct xml_attribute *attribute;
@@ -686,8 +857,16 @@ _write_border(lxw_styles *self, lxw_format *format)
686
857
  _write_sub_border(self, "right", format->right, format->right_color);
687
858
  _write_sub_border(self, "top", format->top, format->top_color);
688
859
  _write_sub_border(self, "bottom", format->bottom, format->bottom_color);
689
- _write_sub_border(self,
690
- "diagonal", format->diag_border, format->diag_color);
860
+
861
+ if (is_dxf) {
862
+ _write_sub_border(self, "vertical", 0, LXW_COLOR_UNSET);
863
+ _write_sub_border(self, "horizontal", 0, LXW_COLOR_UNSET);
864
+ }
865
+
866
+ /* Conditional DXF formats don't allow diagonal borders. */
867
+ if (!is_dxf)
868
+ _write_sub_border(self, "diagonal",
869
+ format->diag_border, format->diag_color);
691
870
 
692
871
  lxw_xml_end_tag(self->file, "border");
693
872
 
@@ -711,7 +890,7 @@ _write_borders(lxw_styles *self)
711
890
 
712
891
  STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
713
892
  if (format->has_border)
714
- _write_border(self, format);
893
+ _write_border(self, format, LXW_FALSE);
715
894
  }
716
895
 
717
896
  lxw_xml_end_tag(self->file, "borders");
@@ -719,22 +898,70 @@ _write_borders(lxw_styles *self)
719
898
  LXW_FREE_ATTRIBUTES();
720
899
  }
721
900
 
901
+ /*
902
+ * Write the <alignment> element for hyperlinks.
903
+ */
904
+ STATIC void
905
+ _write_hyperlink_alignment(lxw_styles *self)
906
+ {
907
+ struct xml_attribute_list attributes;
908
+ struct xml_attribute *attribute;
909
+
910
+ LXW_INIT_ATTRIBUTES();
911
+ LXW_PUSH_ATTRIBUTES_STR("vertical", "top");
912
+
913
+ lxw_xml_empty_tag(self->file, "alignment", &attributes);
914
+
915
+ LXW_FREE_ATTRIBUTES();
916
+ }
917
+
918
+ /*
919
+ * Write the <protection> element for hyperlinks.
920
+ */
921
+ STATIC void
922
+ _write_hyperlink_protection(lxw_styles *self)
923
+ {
924
+ struct xml_attribute_list attributes;
925
+ struct xml_attribute *attribute;
926
+
927
+ LXW_INIT_ATTRIBUTES();
928
+ LXW_PUSH_ATTRIBUTES_STR("locked", "0");
929
+
930
+ lxw_xml_empty_tag(self->file, "protection", &attributes);
931
+
932
+ LXW_FREE_ATTRIBUTES();
933
+ }
934
+
722
935
  /*
723
936
  * Write the <xf> element for styles.
724
937
  */
725
938
  STATIC void
726
- _write_style_xf(lxw_styles *self)
939
+ _write_style_xf(lxw_styles *self, uint8_t has_hyperlink, uint16_t font_id)
727
940
  {
728
941
  struct xml_attribute_list attributes;
729
942
  struct xml_attribute *attribute;
730
943
 
731
944
  LXW_INIT_ATTRIBUTES();
732
945
  LXW_PUSH_ATTRIBUTES_STR("numFmtId", "0");
733
- LXW_PUSH_ATTRIBUTES_STR("fontId", "0");
946
+ LXW_PUSH_ATTRIBUTES_INT("fontId", font_id);
734
947
  LXW_PUSH_ATTRIBUTES_STR("fillId", "0");
735
948
  LXW_PUSH_ATTRIBUTES_STR("borderId", "0");
736
949
 
737
- lxw_xml_empty_tag(self->file, "xf", &attributes);
950
+ if (has_hyperlink) {
951
+ LXW_PUSH_ATTRIBUTES_STR("applyNumberFormat", "0");
952
+ LXW_PUSH_ATTRIBUTES_STR("applyFill", "0");
953
+ LXW_PUSH_ATTRIBUTES_STR("applyBorder", "0");
954
+ LXW_PUSH_ATTRIBUTES_STR("applyAlignment", "0");
955
+ LXW_PUSH_ATTRIBUTES_STR("applyProtection", "0");
956
+
957
+ lxw_xml_start_tag(self->file, "xf", &attributes);
958
+ _write_hyperlink_alignment(self);
959
+ _write_hyperlink_protection(self);
960
+ lxw_xml_end_tag(self->file, "xf");
961
+ }
962
+ else {
963
+ lxw_xml_empty_tag(self->file, "xf", &attributes);
964
+ }
738
965
 
739
966
  LXW_FREE_ATTRIBUTES();
740
967
  }
@@ -749,10 +976,18 @@ _write_cell_style_xfs(lxw_styles *self)
749
976
  struct xml_attribute *attribute;
750
977
 
751
978
  LXW_INIT_ATTRIBUTES();
752
- LXW_PUSH_ATTRIBUTES_STR("count", "1");
979
+
980
+ if (self->has_hyperlink)
981
+ LXW_PUSH_ATTRIBUTES_STR("count", "2");
982
+ else
983
+ LXW_PUSH_ATTRIBUTES_STR("count", "1");
753
984
 
754
985
  lxw_xml_start_tag(self->file, "cellStyleXfs", &attributes);
755
- _write_style_xf(self);
986
+ _write_style_xf(self, LXW_FALSE, 0);
987
+
988
+ if (self->has_hyperlink)
989
+ _write_style_xf(self, self->has_hyperlink, self->hyperlink_font_id);
990
+
756
991
  lxw_xml_end_tag(self->file, "cellStyleXfs");
757
992
 
758
993
  LXW_FREE_ATTRIBUTES();
@@ -936,13 +1171,13 @@ _write_xf(lxw_styles *self, lxw_format *format)
936
1171
  LXW_PUSH_ATTRIBUTES_INT("fontId", format->font_index);
937
1172
  LXW_PUSH_ATTRIBUTES_INT("fillId", format->fill_index);
938
1173
  LXW_PUSH_ATTRIBUTES_INT("borderId", format->border_index);
939
- LXW_PUSH_ATTRIBUTES_STR("xfId", "0");
1174
+ LXW_PUSH_ATTRIBUTES_INT("xfId", format->xf_id);
940
1175
 
941
1176
  if (format->num_format_index > 0)
942
1177
  LXW_PUSH_ATTRIBUTES_STR("applyNumberFormat", "1");
943
1178
 
944
1179
  /* Add applyFont attribute if XF format uses a font element. */
945
- if (format->font_index > 0)
1180
+ if (format->font_index > 0 && !format->hyperlink)
946
1181
  LXW_PUSH_ATTRIBUTES_STR("applyFont", "1");
947
1182
 
948
1183
  /* Add applyFill attribute if XF format uses a fill element. */
@@ -954,10 +1189,10 @@ _write_xf(lxw_styles *self, lxw_format *format)
954
1189
  LXW_PUSH_ATTRIBUTES_STR("applyBorder", "1");
955
1190
 
956
1191
  /* We can also have applyAlignment without a sub-element. */
957
- if (apply_alignment)
1192
+ if (apply_alignment || format->hyperlink)
958
1193
  LXW_PUSH_ATTRIBUTES_STR("applyAlignment", "1");
959
1194
 
960
- if (has_protection)
1195
+ if (has_protection || format->hyperlink)
961
1196
  LXW_PUSH_ATTRIBUTES_STR("applyProtection", "1");
962
1197
 
963
1198
  /* Write XF with sub-elements if required. */
@@ -988,14 +1223,27 @@ _write_cell_xfs(lxw_styles *self)
988
1223
  struct xml_attribute_list attributes;
989
1224
  struct xml_attribute *attribute;
990
1225
  lxw_format *format;
1226
+ uint32_t count = self->xf_count;
1227
+ uint32_t i = 0;
1228
+
1229
+ /* If the last format is "font_only" it is for the comment font and
1230
+ * shouldn't be counted. This is a workaround to get the last object
1231
+ * in the list since STAILQ_LAST() requires __containerof and isn't
1232
+ * ANSI compatible. */
1233
+ STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
1234
+ i++;
1235
+ if (i == self->xf_count && format->font_only)
1236
+ count--;
1237
+ }
991
1238
 
992
1239
  LXW_INIT_ATTRIBUTES();
993
- LXW_PUSH_ATTRIBUTES_INT("count", self->xf_count);
1240
+ LXW_PUSH_ATTRIBUTES_INT("count", count);
994
1241
 
995
1242
  lxw_xml_start_tag(self->file, "cellXfs", &attributes);
996
1243
 
997
1244
  STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
998
- _write_xf(self, format);
1245
+ if (!format->font_only)
1246
+ _write_xf(self, format);
999
1247
  }
1000
1248
 
1001
1249
  lxw_xml_end_tag(self->file, "cellXfs");
@@ -1007,15 +1255,16 @@ _write_cell_xfs(lxw_styles *self)
1007
1255
  * Write the <cellStyle> element.
1008
1256
  */
1009
1257
  STATIC void
1010
- _write_cell_style(lxw_styles *self)
1258
+ _write_cell_style(lxw_styles *self, char *name, uint8_t xf_id,
1259
+ uint8_t builtin_id)
1011
1260
  {
1012
1261
  struct xml_attribute_list attributes;
1013
1262
  struct xml_attribute *attribute;
1014
1263
 
1015
1264
  LXW_INIT_ATTRIBUTES();
1016
- LXW_PUSH_ATTRIBUTES_STR("name", "Normal");
1017
- LXW_PUSH_ATTRIBUTES_STR("xfId", "0");
1018
- LXW_PUSH_ATTRIBUTES_STR("builtinId", "0");
1265
+ LXW_PUSH_ATTRIBUTES_STR("name", name);
1266
+ LXW_PUSH_ATTRIBUTES_INT("xfId", xf_id);
1267
+ LXW_PUSH_ATTRIBUTES_INT("builtinId", builtin_id);
1019
1268
 
1020
1269
  lxw_xml_empty_tag(self->file, "cellStyle", &attributes);
1021
1270
 
@@ -1031,10 +1280,19 @@ _write_cell_styles(lxw_styles *self)
1031
1280
  struct xml_attribute_list attributes;
1032
1281
  struct xml_attribute *attribute;
1033
1282
  LXW_INIT_ATTRIBUTES();
1034
- LXW_PUSH_ATTRIBUTES_STR("count", "1");
1283
+
1284
+ if (self->has_hyperlink)
1285
+ LXW_PUSH_ATTRIBUTES_STR("count", "2");
1286
+ else
1287
+ LXW_PUSH_ATTRIBUTES_STR("count", "1");
1035
1288
 
1036
1289
  lxw_xml_start_tag(self->file, "cellStyles", &attributes);
1037
- _write_cell_style(self);
1290
+
1291
+ if (self->has_hyperlink)
1292
+ _write_cell_style(self, "Hyperlink", 1, 8);
1293
+
1294
+ _write_cell_style(self, "Normal", 0, 0);
1295
+
1038
1296
  lxw_xml_end_tag(self->file, "cellStyles");
1039
1297
 
1040
1298
  LXW_FREE_ATTRIBUTES();
@@ -1042,18 +1300,46 @@ _write_cell_styles(lxw_styles *self)
1042
1300
 
1043
1301
  /*
1044
1302
  * Write the <dxfs> element.
1303
+ *
1045
1304
  */
1046
1305
  STATIC void
1047
1306
  _write_dxfs(lxw_styles *self)
1048
1307
  {
1049
1308
  struct xml_attribute_list attributes;
1050
1309
  struct xml_attribute *attribute;
1310
+ lxw_format *format;
1311
+ uint32_t count = self->dxf_count;
1051
1312
 
1052
1313
  LXW_INIT_ATTRIBUTES();
1053
- LXW_PUSH_ATTRIBUTES_STR("count", "0");
1314
+ LXW_PUSH_ATTRIBUTES_INT("count", count);
1315
+
1316
+ if (count) {
1317
+ lxw_xml_start_tag(self->file, "dxfs", &attributes);
1318
+
1319
+ STAILQ_FOREACH(format, self->dxf_formats, list_pointers) {
1320
+ lxw_xml_start_tag(self->file, "dxf", NULL);
1054
1321
 
1055
- lxw_xml_empty_tag(self->file, "dxfs", &attributes);
1322
+ if (format->has_dxf_font)
1323
+ _write_font(self, format, LXW_TRUE, LXW_FALSE);
1056
1324
 
1325
+ if (format->num_format_index)
1326
+ _write_num_fmt(self, format->num_format_index,
1327
+ format->num_format);
1328
+
1329
+ if (format->has_dxf_fill)
1330
+ _write_fill(self, format, LXW_TRUE);
1331
+
1332
+ if (format->has_dxf_border)
1333
+ _write_border(self, format, LXW_TRUE);
1334
+
1335
+ lxw_xml_end_tag(self->file, "dxf");
1336
+ }
1337
+
1338
+ lxw_xml_end_tag(self->file, "dxfs");
1339
+ }
1340
+ else {
1341
+ lxw_xml_empty_tag(self->file, "dxfs", &attributes);
1342
+ }
1057
1343
  LXW_FREE_ATTRIBUTES();
1058
1344
  }
1059
1345
 
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Used in conjunction with the libxlsxwriter library.
5
5
  *
6
- * Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
6
+ * Copyright 2014-2020, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7
7
  *
8
8
  */
9
9