write_xlsx 1.04.0 → 1.08.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/Changes +50 -0
- data/README.md +1 -1
- data/examples/chart_data_labels.rb +320 -0
- data/examples/ignore_errors.rb +39 -0
- data/ignore_errors.xlsx +0 -0
- data/lib/write_xlsx/chart/series.rb +100 -0
- data/lib/write_xlsx/chart.rb +155 -33
- data/lib/write_xlsx/drawing.rb +80 -17
- data/lib/write_xlsx/package/app.rb +3 -3
- data/lib/write_xlsx/package/conditional_format.rb +2 -8
- data/lib/write_xlsx/package/packager.rb +1 -0
- data/lib/write_xlsx/package/styles.rb +16 -3
- data/lib/write_xlsx/package/table.rb +8 -0
- data/lib/write_xlsx/utility.rb +9 -3
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +23 -0
- data/lib/write_xlsx/worksheet/data_validation.rb +1 -6
- data/lib/write_xlsx/worksheet.rb +160 -37
- data/test/drawing/{test_write_ext.rb → test_write_xdr_ext.rb} +2 -2
- data/test/perl_output/chart_data_labels.xlsx +0 -0
- data/test/perl_output/ignore_errors.xlsx +0 -0
- data/test/regression/test_array_formula04.rb +31 -0
- data/test/regression/test_chart_crossing01.rb +1 -1
- data/test/regression/test_chart_crossing05.rb +46 -0
- data/test/regression/test_chart_crossing06.rb +46 -0
- data/test/regression/test_chart_data_labels26.rb +44 -0
- data/test/regression/test_chart_data_labels27.rb +44 -0
- data/test/regression/test_chart_data_labels28.rb +52 -0
- data/test/regression/test_chart_data_labels29.rb +43 -0
- data/test/regression/test_chart_data_labels30.rb +46 -0
- data/test/regression/test_chart_data_labels31.rb +49 -0
- data/test/regression/test_chart_data_labels32.rb +54 -0
- data/test/regression/test_chart_data_labels33.rb +52 -0
- data/test/regression/test_chart_data_labels34.rb +54 -0
- data/test/regression/test_chart_data_labels35.rb +46 -0
- data/test/regression/test_chart_data_labels36.rb +54 -0
- data/test/regression/test_chart_data_labels37.rb +51 -0
- data/test/regression/test_chart_data_labels38.rb +54 -0
- data/test/regression/test_chart_data_labels39.rb +53 -0
- data/test/regression/test_chart_data_labels40.rb +53 -0
- data/test/regression/test_chart_data_labels41.rb +54 -0
- data/test/regression/test_chart_data_labels42.rb +58 -0
- data/test/regression/test_chart_data_labels43.rb +58 -0
- data/test/regression/test_chart_data_labels44.rb +56 -0
- data/test/regression/test_chart_data_labels45.rb +57 -0
- data/test/regression/test_chart_data_labels46.rb +61 -0
- data/test/regression/test_chart_data_labels47.rb +61 -0
- data/test/regression/test_chart_data_labels48.rb +55 -0
- data/test/regression/test_chart_data_labels49.rb +55 -0
- data/test/regression/test_chart_data_labels50.rb +57 -0
- data/test/regression/test_format16.rb +24 -0
- data/test/regression/test_format17.rb +24 -0
- data/test/regression/test_header04.rb +30 -0
- data/test/regression/test_hyperlink50.rb +27 -0
- data/test/regression/test_hyperlink51.rb +27 -0
- data/test/regression/test_ignore_error01.rb +23 -0
- data/test/regression/test_ignore_error02.rb +24 -0
- data/test/regression/test_ignore_error03.rb +26 -0
- data/test/regression/test_ignore_error04.rb +26 -0
- data/test/regression/test_ignore_error05.rb +32 -0
- data/test/regression/test_ignore_error06.rb +32 -0
- data/test/regression/test_image52.rb +26 -0
- data/test/regression/test_image53.rb +26 -0
- data/test/regression/test_image54.rb +26 -0
- data/test/regression/test_image55.rb +27 -0
- data/test/regression/test_protect04.rb +32 -0
- data/test/regression/test_protect05.rb +35 -0
- data/test/regression/test_protect06.rb +35 -0
- data/test/regression/test_protect07.rb +23 -0
- data/test/regression/test_table26.rb +38 -0
- data/test/regression/xlsx_files/array_formula04.xlsx +0 -0
- data/test/regression/xlsx_files/chart_crossing05.xlsx +0 -0
- data/test/regression/xlsx_files/chart_crossing06.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels26.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels27.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels28.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels29.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels30.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels31.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels32.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels33.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels34.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels35.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels36.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels37.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels38.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels39.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels40.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels41.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels42.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels43.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels44.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels45.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels46.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels47.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels48.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels49.xlsx +0 -0
- data/test/regression/xlsx_files/chart_data_labels50.xlsx +0 -0
- data/test/regression/xlsx_files/format16.xlsx +0 -0
- data/test/regression/xlsx_files/format17.xlsx +0 -0
- data/test/regression/xlsx_files/header04.xlsx +0 -0
- data/test/regression/xlsx_files/hyperlink50.xlsx +0 -0
- data/test/regression/xlsx_files/hyperlink51.xlsx +0 -0
- data/test/regression/xlsx_files/ignore_error01.xlsx +0 -0
- data/test/regression/xlsx_files/ignore_error02.xlsx +0 -0
- data/test/regression/xlsx_files/ignore_error03.xlsx +0 -0
- data/test/regression/xlsx_files/ignore_error04.xlsx +0 -0
- data/test/regression/xlsx_files/ignore_error05.xlsx +0 -0
- data/test/regression/xlsx_files/ignore_error06.xlsx +0 -0
- data/test/regression/xlsx_files/image52.xlsx +0 -0
- data/test/regression/xlsx_files/image53.xlsx +0 -0
- data/test/regression/xlsx_files/image54.xlsx +0 -0
- data/test/regression/xlsx_files/image55.xlsx +0 -0
- data/test/regression/xlsx_files/protect04.xlsx +0 -0
- data/test/regression/xlsx_files/protect05.xlsx +0 -0
- data/test/regression/xlsx_files/protect06.xlsx +0 -0
- data/test/regression/xlsx_files/protect07.xlsx +0 -0
- data/test/regression/xlsx_files/table26.xlsx +0 -0
- data/test/test_example_match.rb +345 -1
- data/test/utility/test_range.rb +20 -0
- metadata +209 -8
data/lib/write_xlsx/workbook.rb
CHANGED
|
@@ -52,6 +52,7 @@ module Writexlsx
|
|
|
52
52
|
attr_reader :max_url_length # :nodoc:
|
|
53
53
|
attr_reader :strings_to_urls # :nodoc:
|
|
54
54
|
attr_reader :default_url_format # :nodoc:
|
|
55
|
+
attr_reader :read_only # :nodoc:
|
|
55
56
|
|
|
56
57
|
#
|
|
57
58
|
# A new Excel workbook is created using the +new+ constructor
|
|
@@ -133,6 +134,7 @@ module Writexlsx
|
|
|
133
134
|
|
|
134
135
|
@max_url_length = 2079
|
|
135
136
|
@has_comments = false
|
|
137
|
+
@read_only = 0
|
|
136
138
|
if options[:max_url_length]
|
|
137
139
|
@max_url_length = options[:max_url_length]
|
|
138
140
|
|
|
@@ -292,6 +294,9 @@ module Writexlsx
|
|
|
292
294
|
# Write the XLSX file version.
|
|
293
295
|
write_file_version
|
|
294
296
|
|
|
297
|
+
# Write the fileSharing element.
|
|
298
|
+
write_file_sharing
|
|
299
|
+
|
|
295
300
|
# Write the workbook properties.
|
|
296
301
|
write_workbook_pr
|
|
297
302
|
|
|
@@ -954,6 +959,13 @@ module Writexlsx
|
|
|
954
959
|
end
|
|
955
960
|
end
|
|
956
961
|
|
|
962
|
+
#
|
|
963
|
+
# Set the Excel "Read-only recommended" save option.
|
|
964
|
+
#
|
|
965
|
+
def read_only_recommended
|
|
966
|
+
@read_only = 2
|
|
967
|
+
end
|
|
968
|
+
|
|
957
969
|
#
|
|
958
970
|
# set_calc_mode()
|
|
959
971
|
#
|
|
@@ -1311,6 +1323,17 @@ module Writexlsx
|
|
|
1311
1323
|
@writer.empty_tag('fileVersion', attributes)
|
|
1312
1324
|
end
|
|
1313
1325
|
|
|
1326
|
+
#
|
|
1327
|
+
# Write the <fileSharing> element.
|
|
1328
|
+
#
|
|
1329
|
+
def write_file_sharing
|
|
1330
|
+
return if !ptrue?(@read_only)
|
|
1331
|
+
|
|
1332
|
+
attributes = []
|
|
1333
|
+
attributes << ['readOnlyRecommended', 1]
|
|
1334
|
+
@writer.empty_tag('fileSharing', attributes)
|
|
1335
|
+
end
|
|
1336
|
+
|
|
1314
1337
|
def write_workbook_pr #:nodoc:
|
|
1315
1338
|
attributes = []
|
|
1316
1339
|
attributes << ['codeName', @vba_codename] if ptrue?(@vba_codename)
|
|
@@ -138,12 +138,7 @@ module Writexlsx
|
|
|
138
138
|
row_first, row_last = row_last, row_first if row_first > row_last
|
|
139
139
|
col_first, col_last = col_last, col_first if col_first > col_last
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
if row_first == row_last && col_first == col_last
|
|
143
|
-
sqref += xl_rowcol_to_cell(row_first, col_first)
|
|
144
|
-
else
|
|
145
|
-
sqref += xl_range(row_first, row_last, col_first, col_last)
|
|
146
|
-
end
|
|
141
|
+
sqref += xl_range(row_first, row_last, col_first, col_last)
|
|
147
142
|
end
|
|
148
143
|
|
|
149
144
|
if @validate != 'none'
|
data/lib/write_xlsx/worksheet.rb
CHANGED
|
@@ -381,6 +381,7 @@ module Writexlsx
|
|
|
381
381
|
@comments = Package::Comments.new(self)
|
|
382
382
|
@buttons_array = []
|
|
383
383
|
@header_images_array = []
|
|
384
|
+
@ignore_errors = nil
|
|
384
385
|
|
|
385
386
|
@validations = []
|
|
386
387
|
|
|
@@ -388,6 +389,9 @@ module Writexlsx
|
|
|
388
389
|
@data_bars_2010 = []
|
|
389
390
|
@dxf_priority = 1
|
|
390
391
|
|
|
392
|
+
@protected_ranges = []
|
|
393
|
+
@num_protected_ranges = 0
|
|
394
|
+
|
|
391
395
|
if excel2003_style?
|
|
392
396
|
@original_row_height = 12.75
|
|
393
397
|
@default_row_height = 12.75
|
|
@@ -414,6 +418,7 @@ module Writexlsx
|
|
|
414
418
|
write_cols
|
|
415
419
|
write_sheet_data
|
|
416
420
|
write_sheet_protection
|
|
421
|
+
write_protected_ranges
|
|
417
422
|
# write_sheet_calc_pr
|
|
418
423
|
write_phonetic_pr if excel2003_style?
|
|
419
424
|
write_auto_filter
|
|
@@ -427,6 +432,7 @@ module Writexlsx
|
|
|
427
432
|
write_header_footer
|
|
428
433
|
write_row_breaks
|
|
429
434
|
write_col_breaks
|
|
435
|
+
write_ignored_errors
|
|
430
436
|
write_drawings
|
|
431
437
|
write_legacy_drawing
|
|
432
438
|
write_legacy_drawing_hf
|
|
@@ -616,7 +622,25 @@ module Writexlsx
|
|
|
616
622
|
|
|
617
623
|
# Set the password after the user defined values.
|
|
618
624
|
@protect[:password] =
|
|
619
|
-
|
|
625
|
+
encode_password(password) if password && password != ''
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
#
|
|
629
|
+
# Unprotect ranges within a protected worksheet.
|
|
630
|
+
#
|
|
631
|
+
def unprotect_range(range, range_name = nil, password = nil)
|
|
632
|
+
if range.nil?
|
|
633
|
+
raise "The range must be defined in unprotect_range())\n"
|
|
634
|
+
else
|
|
635
|
+
range.gsub!(/\$/, "")
|
|
636
|
+
range.sub!(/^=/, "")
|
|
637
|
+
@num_protected_ranges += 1
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
range_name ||= "Range#{@num_protected_ranges}"
|
|
641
|
+
password &&= encode_password(password)
|
|
642
|
+
|
|
643
|
+
@protected_ranges << [range, range_name, password]
|
|
620
644
|
end
|
|
621
645
|
|
|
622
646
|
def protect_default_settings # :nodoc:
|
|
@@ -818,12 +842,7 @@ module Writexlsx
|
|
|
818
842
|
row_first, row_last = row_last, row_first if row_first > row_last
|
|
819
843
|
col_first, col_last = col_last, col_first if col_first > col_last
|
|
820
844
|
|
|
821
|
-
|
|
822
|
-
if row_first == row_last && col_first == col_last
|
|
823
|
-
sqref = active_cell
|
|
824
|
-
else
|
|
825
|
-
sqref = xl_range(row_first, row_last, col_first, col_last)
|
|
826
|
-
end
|
|
845
|
+
sqref = xl_range(row_first, row_last, col_first, col_last)
|
|
827
846
|
else # Single cell selection.
|
|
828
847
|
sqref = active_cell
|
|
829
848
|
end
|
|
@@ -1207,14 +1226,10 @@ module Writexlsx
|
|
|
1207
1226
|
# distribution.
|
|
1208
1227
|
#
|
|
1209
1228
|
def set_header(string = '', margin = 0.3, options = {})
|
|
1210
|
-
raise 'Header string must be less than 255 characters' if string.length
|
|
1229
|
+
raise 'Header string must be less than 255 characters' if string.length > 255
|
|
1211
1230
|
# Replace the Excel placeholder &[Picture] with the internal &G.
|
|
1212
1231
|
@page_setup.header = string.gsub(/&\[Picture\]/, '&G')
|
|
1213
1232
|
|
|
1214
|
-
if string.size >= 255
|
|
1215
|
-
raise 'Header string must be less than 255 characters'
|
|
1216
|
-
end
|
|
1217
|
-
|
|
1218
1233
|
if options[:align_with_margins]
|
|
1219
1234
|
@page_setup.header_footer_aligns = options[:align_with_margins]
|
|
1220
1235
|
end
|
|
@@ -1255,17 +1270,13 @@ module Writexlsx
|
|
|
1255
1270
|
# The syntax of the set_footer() method is the same as set_header()
|
|
1256
1271
|
#
|
|
1257
1272
|
def set_footer(string = '', margin = 0.3, options = {})
|
|
1258
|
-
raise 'Footer string must be less than 255 characters' if string.length
|
|
1273
|
+
raise 'Footer string must be less than 255 characters' if string.length > 255
|
|
1259
1274
|
|
|
1260
1275
|
@page_setup.footer = string.dup
|
|
1261
1276
|
|
|
1262
1277
|
# Replace the Excel placeholder &[Picture] with the internal &G.
|
|
1263
1278
|
@page_setup.footer = string.gsub(/&\[Picture\]/, '&G')
|
|
1264
1279
|
|
|
1265
|
-
if string.size >= 255
|
|
1266
|
-
raise 'Header string must be less than 255 characters'
|
|
1267
|
-
end
|
|
1268
|
-
|
|
1269
1280
|
if options[:align_with_margins]
|
|
1270
1281
|
@page_setup.header_footer_aligns = options[:align_with_margins]
|
|
1271
1282
|
end
|
|
@@ -2514,7 +2525,9 @@ module Writexlsx
|
|
|
2514
2525
|
col1, col2 = col2, col1 if col1 > col2
|
|
2515
2526
|
|
|
2516
2527
|
# Check that row and col are valid and store max and min values
|
|
2528
|
+
check_dimensions(row1, col1)
|
|
2517
2529
|
check_dimensions(row2, col2)
|
|
2530
|
+
store_row_col_max_min_values(row1, col1)
|
|
2518
2531
|
store_row_col_max_min_values(row2, col2)
|
|
2519
2532
|
|
|
2520
2533
|
# Define array range
|
|
@@ -3046,14 +3059,16 @@ module Writexlsx
|
|
|
3046
3059
|
|
|
3047
3060
|
if options.first.class == Hash
|
|
3048
3061
|
# Newer hash bashed options
|
|
3049
|
-
params
|
|
3050
|
-
x_offset
|
|
3051
|
-
y_offset
|
|
3052
|
-
x_scale
|
|
3053
|
-
y_scale
|
|
3054
|
-
anchor
|
|
3055
|
-
url
|
|
3056
|
-
tip
|
|
3062
|
+
params = options.first
|
|
3063
|
+
x_offset = params[:x_offset]
|
|
3064
|
+
y_offset = params[:y_offset]
|
|
3065
|
+
x_scale = params[:x_scale]
|
|
3066
|
+
y_scale = params[:y_scale]
|
|
3067
|
+
anchor = params[:object_position]
|
|
3068
|
+
url = params[:url]
|
|
3069
|
+
tip = params[:tip]
|
|
3070
|
+
description = params[:description]
|
|
3071
|
+
decorative = params[:decorative]
|
|
3057
3072
|
else
|
|
3058
3073
|
x_offset, y_offset, x_scale, y_scale, anchor = options
|
|
3059
3074
|
end
|
|
@@ -3065,7 +3080,7 @@ module Writexlsx
|
|
|
3065
3080
|
|
|
3066
3081
|
@images << [
|
|
3067
3082
|
row, col, image, x_offset, y_offset,
|
|
3068
|
-
x_scale, y_scale, url, tip, anchor
|
|
3083
|
+
x_scale, y_scale, url, tip, anchor, description, decorative
|
|
3069
3084
|
]
|
|
3070
3085
|
end
|
|
3071
3086
|
|
|
@@ -3363,9 +3378,11 @@ module Writexlsx
|
|
|
3363
3378
|
row_first, row_last = row_last, row_first if row_first > row_last
|
|
3364
3379
|
col_first, col_last = col_last, col_first if col_first > col_last
|
|
3365
3380
|
|
|
3366
|
-
# Check that
|
|
3367
|
-
check_dimensions(
|
|
3368
|
-
|
|
3381
|
+
# Check that the data range is valid and store the max and min values.
|
|
3382
|
+
check_dimensions(row_first, col_first)
|
|
3383
|
+
check_dimensions(row_last, col_last)
|
|
3384
|
+
store_row_col_max_min_values(row_first, col_first)
|
|
3385
|
+
store_row_col_max_min_values(row_last, col_last)
|
|
3369
3386
|
|
|
3370
3387
|
# Store the merge range.
|
|
3371
3388
|
@merge << [row_first, col_first, row_last, col_last]
|
|
@@ -3428,9 +3445,11 @@ module Writexlsx
|
|
|
3428
3445
|
row_first, row_last = row_last, row_first if row_first > row_last
|
|
3429
3446
|
col_first, col_last = col_last, col_first if col_first > col_last
|
|
3430
3447
|
|
|
3431
|
-
# Check that
|
|
3432
|
-
check_dimensions(
|
|
3433
|
-
|
|
3448
|
+
# Check that the data range is valid and store the max and min values.
|
|
3449
|
+
check_dimensions(row_first, col_first)
|
|
3450
|
+
check_dimensions(row_last, col_last)
|
|
3451
|
+
store_row_col_max_min_values(row_first, col_first)
|
|
3452
|
+
store_row_col_max_min_values(row_last, col_last)
|
|
3434
3453
|
|
|
3435
3454
|
# Store the merge range.
|
|
3436
3455
|
@merge << [row_first, col_first, row_last, col_last]
|
|
@@ -5738,7 +5757,7 @@ module Writexlsx
|
|
|
5738
5757
|
name = chart.name
|
|
5739
5758
|
|
|
5740
5759
|
# Create a Drawing object to use with worksheet unless one already exists.
|
|
5741
|
-
drawing = Drawing.new(drawing_type, dimensions, 0, 0, name, nil, anchor, drawing_rel_index, 0, nil)
|
|
5760
|
+
drawing = Drawing.new(drawing_type, dimensions, 0, 0, name, nil, anchor, drawing_rel_index, 0, nil, 0)
|
|
5742
5761
|
if !drawings?
|
|
5743
5762
|
@drawings = Drawings.new
|
|
5744
5763
|
@drawings.add_drawing_object(drawing)
|
|
@@ -6062,6 +6081,30 @@ module Writexlsx
|
|
|
6062
6081
|
end
|
|
6063
6082
|
end
|
|
6064
6083
|
|
|
6084
|
+
#
|
|
6085
|
+
# Ignore worksheet errors/warnings in user defined ranges.
|
|
6086
|
+
#
|
|
6087
|
+
def ignore_errors(ignores)
|
|
6088
|
+
# List of valid input parameters.
|
|
6089
|
+
valid_parameter_keys = [
|
|
6090
|
+
:number_stored_as_text,
|
|
6091
|
+
:eval_error,
|
|
6092
|
+
:formula_differs,
|
|
6093
|
+
:formula_range,
|
|
6094
|
+
:formula_unlocked,
|
|
6095
|
+
:empty_cell_reference,
|
|
6096
|
+
:list_data_validation,
|
|
6097
|
+
:calculated_column,
|
|
6098
|
+
:two_digit_text_year
|
|
6099
|
+
]
|
|
6100
|
+
|
|
6101
|
+
unless (ignores.keys - valid_parameter_keys).empty?
|
|
6102
|
+
raise "Unknown parameter '#{ignores.key - valid_parameter_keys}' in ignore_errors()."
|
|
6103
|
+
end
|
|
6104
|
+
|
|
6105
|
+
@ignore_errors = ignores
|
|
6106
|
+
end
|
|
6107
|
+
|
|
6065
6108
|
def write_ext(url)
|
|
6066
6109
|
attributes = [
|
|
6067
6110
|
['xmlns:x14', "#{OFFICE_URL}spreadsheetml/2009/9/main"],
|
|
@@ -6464,7 +6507,7 @@ module Writexlsx
|
|
|
6464
6507
|
drawing_type = 2
|
|
6465
6508
|
|
|
6466
6509
|
row, col, image, x_offset, y_offset,
|
|
6467
|
-
x_scale, y_scale, url, tip, anchor = @images[index]
|
|
6510
|
+
x_scale, y_scale, url, tip, anchor, description, decorative = @images[index]
|
|
6468
6511
|
|
|
6469
6512
|
width *= x_scale
|
|
6470
6513
|
height *= y_scale
|
|
@@ -6479,7 +6522,7 @@ module Writexlsx
|
|
|
6479
6522
|
height = (0.5 + (height * 9_525)).to_i
|
|
6480
6523
|
|
|
6481
6524
|
# Create a Drawing object to use with worksheet unless one already exists.
|
|
6482
|
-
drawing = Drawing.new(drawing_type, dimensions, width, height, name, nil, anchor, 0, 0, tip)
|
|
6525
|
+
drawing = Drawing.new(drawing_type, dimensions, width, height, name, nil, anchor, 0, 0, tip, decorative)
|
|
6483
6526
|
if !drawings?
|
|
6484
6527
|
drawings = Drawings.new
|
|
6485
6528
|
drawings.embedded = 1
|
|
@@ -6492,6 +6535,10 @@ module Writexlsx
|
|
|
6492
6535
|
end
|
|
6493
6536
|
drawings.add_drawing_object(drawing)
|
|
6494
6537
|
|
|
6538
|
+
if description
|
|
6539
|
+
drawing.description = description
|
|
6540
|
+
end
|
|
6541
|
+
|
|
6495
6542
|
if url
|
|
6496
6543
|
rel_type = '/hyperlink'
|
|
6497
6544
|
target_mode = 'External'
|
|
@@ -6499,10 +6546,19 @@ module Writexlsx
|
|
|
6499
6546
|
target = escape_url(url)
|
|
6500
6547
|
end
|
|
6501
6548
|
if url =~ /^external:/
|
|
6502
|
-
target = escape_url(url.sub(/^external:/, '
|
|
6549
|
+
target = escape_url(url.sub(/^external:/, ''))
|
|
6550
|
+
|
|
6503
6551
|
# Additional escape not required in worksheet hyperlinks
|
|
6504
6552
|
target = target.gsub(/#/, '%23')
|
|
6553
|
+
|
|
6554
|
+
# Prefix absolute paths (not relative) with file:///
|
|
6555
|
+
if target =~ /^\w:/ || target =~ /^\\\\/
|
|
6556
|
+
target = "file:///#{target}"
|
|
6557
|
+
else
|
|
6558
|
+
target = target.gsub(/\\/, '/')
|
|
6559
|
+
end
|
|
6505
6560
|
end
|
|
6561
|
+
|
|
6506
6562
|
if url =~ /^internal:/
|
|
6507
6563
|
target = url.sub(/^internal:/, '#')
|
|
6508
6564
|
target_mode = nil
|
|
@@ -6645,7 +6701,7 @@ EOS
|
|
|
6645
6701
|
shape.calc_position_emus(self)
|
|
6646
6702
|
|
|
6647
6703
|
drawing_type = 3
|
|
6648
|
-
drawing = Drawing.new(drawing_type, shape.dimensions, shape.width_emu, shape.height_emu, shape.name, shape, shape.anchor, drawing_rel_index, 0, nil)
|
|
6704
|
+
drawing = Drawing.new(drawing_type, shape.dimensions, shape.width_emu, shape.height_emu, shape.name, shape, shape.anchor, drawing_rel_index, 0, nil, 0)
|
|
6649
6705
|
drawings.add_drawing_object(drawing)
|
|
6650
6706
|
end
|
|
6651
6707
|
public :prepare_shape
|
|
@@ -6735,6 +6791,8 @@ EOS
|
|
|
6735
6791
|
chars.each { |c| encoded_password ^= c }
|
|
6736
6792
|
encoded_password ^= count
|
|
6737
6793
|
encoded_password ^= 0xCE4B
|
|
6794
|
+
|
|
6795
|
+
sprintf("%X", encoded_password)
|
|
6738
6796
|
end
|
|
6739
6797
|
|
|
6740
6798
|
#
|
|
@@ -7550,6 +7608,32 @@ EOS
|
|
|
7550
7608
|
@writer.empty_tag('sheetProtection', attributes)
|
|
7551
7609
|
end
|
|
7552
7610
|
|
|
7611
|
+
#
|
|
7612
|
+
# Write the <protectedRanges> element.
|
|
7613
|
+
#
|
|
7614
|
+
def write_protected_ranges
|
|
7615
|
+
return if @num_protected_ranges == 0
|
|
7616
|
+
|
|
7617
|
+
@writer.tag_elements('protectedRanges') do
|
|
7618
|
+
@protected_ranges.each do |protected_range|
|
|
7619
|
+
write_protected_range(*protected_range)
|
|
7620
|
+
end
|
|
7621
|
+
end
|
|
7622
|
+
end
|
|
7623
|
+
|
|
7624
|
+
#
|
|
7625
|
+
# Write the <protectedRange> element.
|
|
7626
|
+
#
|
|
7627
|
+
def write_protected_range(sqref, name, password)
|
|
7628
|
+
attributes = []
|
|
7629
|
+
|
|
7630
|
+
attributes << ['password', password] if password
|
|
7631
|
+
attributes << ['sqref', sqref]
|
|
7632
|
+
attributes << ['name', name]
|
|
7633
|
+
|
|
7634
|
+
@writer.empty_tag('protectedRange', attributes)
|
|
7635
|
+
end
|
|
7636
|
+
|
|
7553
7637
|
#
|
|
7554
7638
|
# Write the <drawing> elements.
|
|
7555
7639
|
#
|
|
@@ -8082,5 +8166,44 @@ EOS
|
|
|
8082
8166
|
end
|
|
8083
8167
|
col
|
|
8084
8168
|
end
|
|
8169
|
+
|
|
8170
|
+
#
|
|
8171
|
+
# Write the <ignoredErrors> element.
|
|
8172
|
+
#
|
|
8173
|
+
def write_ignored_errors
|
|
8174
|
+
return unless @ignore_errors
|
|
8175
|
+
|
|
8176
|
+
ignore = @ignore_errors
|
|
8177
|
+
|
|
8178
|
+
@writer.tag_elements('ignoredErrors' ) do
|
|
8179
|
+
{
|
|
8180
|
+
:number_stored_as_text => 'numberStoredAsText',
|
|
8181
|
+
:eval_error => 'evalError',
|
|
8182
|
+
:formula_differs => 'formula',
|
|
8183
|
+
:formula_range => 'formulaRange',
|
|
8184
|
+
:formula_unlocked => 'unlockedFormula',
|
|
8185
|
+
:empty_cell_reference => 'emptyCellReference',
|
|
8186
|
+
:list_data_validation => 'listDataValidation',
|
|
8187
|
+
:calculated_column => 'calculatedColumn',
|
|
8188
|
+
:two_digit_text_year => 'twoDigitTextYear'
|
|
8189
|
+
}.each do |key, value|
|
|
8190
|
+
if ignore[key]
|
|
8191
|
+
write_ignored_error(value, ignore[key])
|
|
8192
|
+
end
|
|
8193
|
+
end
|
|
8194
|
+
end
|
|
8195
|
+
end
|
|
8196
|
+
|
|
8197
|
+
#
|
|
8198
|
+
# Write the <ignoredError> element.
|
|
8199
|
+
#
|
|
8200
|
+
def write_ignored_error(type, sqref)
|
|
8201
|
+
attributes = {
|
|
8202
|
+
'sqref' => sqref,
|
|
8203
|
+
type => 1
|
|
8204
|
+
}
|
|
8205
|
+
|
|
8206
|
+
@writer.empty_tag('ignoredError', attributes)
|
|
8207
|
+
end
|
|
8085
8208
|
end
|
|
8086
8209
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
require 'helper'
|
|
3
3
|
require 'write_xlsx/drawing'
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class TestWriteXdrExt < Minitest::Test
|
|
6
6
|
def setup
|
|
7
7
|
@drawing = Writexlsx::Drawings.new
|
|
8
8
|
end
|
|
@@ -10,7 +10,7 @@ class TestWriteExt < Minitest::Test
|
|
|
10
10
|
def test_write_ext
|
|
11
11
|
expected = '<xdr:ext cx="9308969" cy="6078325"/>'
|
|
12
12
|
|
|
13
|
-
@drawing.__send__(:
|
|
13
|
+
@drawing.__send__(:write_xdr_ext, 9308969, 6078325)
|
|
14
14
|
result = @drawing.instance_variable_get(:@writer).string
|
|
15
15
|
|
|
16
16
|
assert_equal(expected, result)
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'helper'
|
|
3
|
+
|
|
4
|
+
class TestRegressionArrayFormula04 < Minitest::Test
|
|
5
|
+
def setup
|
|
6
|
+
setup_dir_var
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def teardown
|
|
10
|
+
@tempfile.close(true)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_array_formula04
|
|
14
|
+
@xlsx = 'array_formula04.xlsx'
|
|
15
|
+
workbook = WriteXLSX.new(@io)
|
|
16
|
+
worksheet = workbook.add_worksheet
|
|
17
|
+
|
|
18
|
+
worksheet.write_array_formula(
|
|
19
|
+
'A1:A3',
|
|
20
|
+
'{=SUM(B1:C1*B2:C2)}',
|
|
21
|
+
nil,
|
|
22
|
+
0
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
workbook.close
|
|
26
|
+
compare_for_regression(
|
|
27
|
+
[ 'xl/calcChain.xml', '[Content_Types].xml', 'xl/_rels/workbook.xml.rels' ],
|
|
28
|
+
{'xl/workbook.xml' => ['<workbookView']}
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -33,7 +33,7 @@ class TestRegressionChartCrossing01 < Minitest::Test
|
|
|
33
33
|
|
|
34
34
|
chart.set_y_axis(:crossing => 'max')
|
|
35
35
|
|
|
36
|
-
# Not
|
|
36
|
+
# Not strictly required. Just to match reference file.
|
|
37
37
|
chart.set_x_axis(:position => 't')
|
|
38
38
|
|
|
39
39
|
worksheet.insert_chart('E9', chart)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'helper'
|
|
3
|
+
|
|
4
|
+
class TestRegressionChartCrossing05 < Minitest::Test
|
|
5
|
+
def setup
|
|
6
|
+
setup_dir_var
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def teardown
|
|
10
|
+
@tempfile.close(true)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_chart_crossing05
|
|
14
|
+
@xlsx = 'chart_crossing05.xlsx'
|
|
15
|
+
workbook = WriteXLSX.new(@io)
|
|
16
|
+
worksheet = workbook.add_worksheet
|
|
17
|
+
chart = workbook.add_chart(:type => 'column', :embedded => 1)
|
|
18
|
+
|
|
19
|
+
# For testing, copy the randomly generated axis ids in the target xlsx file.
|
|
20
|
+
chart.instance_variable_set(:@axis_ids, [55948032, 55950336])
|
|
21
|
+
|
|
22
|
+
data = [
|
|
23
|
+
[1, 2, 3, 4, 5],
|
|
24
|
+
[2, 4, 6, 8, 10],
|
|
25
|
+
[3, 6, 9, 12, 15]
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
worksheet.write('A1', data)
|
|
29
|
+
|
|
30
|
+
chart.add_series(:values => '=Sheet1!$A$1:$A$5')
|
|
31
|
+
chart.add_series(:values => '=Sheet1!$B$1:$B$5')
|
|
32
|
+
chart.add_series(:values => '=Sheet1!$C$1:$C$5')
|
|
33
|
+
|
|
34
|
+
chart.set_x_axis(:crossing => 'min')
|
|
35
|
+
|
|
36
|
+
worksheet.insert_chart('E9', chart)
|
|
37
|
+
|
|
38
|
+
workbook.close
|
|
39
|
+
compare_for_regression(
|
|
40
|
+
nil,
|
|
41
|
+
{
|
|
42
|
+
'xl/charts/chart1.xml' => [ '<c:pageMargins' ]
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'helper'
|
|
3
|
+
|
|
4
|
+
class TestRegressionChartCrossing06 < Minitest::Test
|
|
5
|
+
def setup
|
|
6
|
+
setup_dir_var
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def teardown
|
|
10
|
+
@tempfile.close(true)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_chart_crossing06
|
|
14
|
+
@xlsx = 'chart_crossing06.xlsx'
|
|
15
|
+
workbook = WriteXLSX.new(@io)
|
|
16
|
+
worksheet = workbook.add_worksheet
|
|
17
|
+
chart = workbook.add_chart(:type => 'column', :embedded => 1)
|
|
18
|
+
|
|
19
|
+
# For testing, copy the randomly generated axis ids in the target xlsx file.
|
|
20
|
+
chart.instance_variable_set(:@axis_ids, [72794880, 72796416])
|
|
21
|
+
|
|
22
|
+
data = [
|
|
23
|
+
[1, 2, 3, 4, 5],
|
|
24
|
+
[2, 4, 6, 8, 10],
|
|
25
|
+
[3, 6, 9, 12, 15]
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
worksheet.write('A1', data)
|
|
29
|
+
|
|
30
|
+
chart.add_series(:values => '=Sheet1!$A$1:$A$5')
|
|
31
|
+
chart.add_series(:values => '=Sheet1!$B$1:$B$5')
|
|
32
|
+
chart.add_series(:values => '=Sheet1!$C$1:$C$5')
|
|
33
|
+
|
|
34
|
+
chart.set_y_axis(:crossing => 'min')
|
|
35
|
+
|
|
36
|
+
worksheet.insert_chart('E9', chart)
|
|
37
|
+
|
|
38
|
+
workbook.close
|
|
39
|
+
compare_for_regression(
|
|
40
|
+
nil,
|
|
41
|
+
{
|
|
42
|
+
'xl/charts/chart1.xml' => [ '<c:pageMargins' ]
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'helper'
|
|
3
|
+
|
|
4
|
+
class TestRegressionChartDataLabels26 < Minitest::Test
|
|
5
|
+
def setup
|
|
6
|
+
setup_dir_var
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def teardown
|
|
10
|
+
@tempfile.close(true)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_chart_data_labels26
|
|
14
|
+
@xlsx = 'chart_data_labels26.xlsx'
|
|
15
|
+
workbook = WriteXLSX.new(@io)
|
|
16
|
+
worksheet = workbook.add_worksheet
|
|
17
|
+
chart = workbook.add_chart(:type => 'column', :embedded => 1)
|
|
18
|
+
|
|
19
|
+
# For testing, copy the randomly generated axis ids in the target xlsx file.
|
|
20
|
+
chart.instance_variable_set(:@axis_ids, [48514944, 48516480])
|
|
21
|
+
|
|
22
|
+
data = [
|
|
23
|
+
[ 1, 2, 3, 4, 5],
|
|
24
|
+
[ 2, 4, 6, 8, 10],
|
|
25
|
+
[ 3, 6, 9, 12, 15],
|
|
26
|
+
[10, 20, 30, 40, 50]
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
worksheet.write('A1', data)
|
|
30
|
+
|
|
31
|
+
chart.add_series(
|
|
32
|
+
:values => '=Sheet1!$A$1:$A$5',
|
|
33
|
+
:data_labels => {:value => 1, :custom => [{:value => 33}]}
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
chart.add_series(:values => '=Sheet1!$B$1:$B$5')
|
|
37
|
+
chart.add_series(:values => '=Sheet1!$C$1:$C$5')
|
|
38
|
+
|
|
39
|
+
worksheet.insert_chart('E9', chart)
|
|
40
|
+
|
|
41
|
+
workbook.close
|
|
42
|
+
compare_for_regression
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
require 'helper'
|
|
3
|
+
|
|
4
|
+
class TestRegressionChartDataLabels27 < Minitest::Test
|
|
5
|
+
def setup
|
|
6
|
+
setup_dir_var
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def teardown
|
|
10
|
+
@tempfile.close(true)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_chart_data_labels27
|
|
14
|
+
@xlsx = 'chart_data_labels27.xlsx'
|
|
15
|
+
workbook = WriteXLSX.new(@io)
|
|
16
|
+
worksheet = workbook.add_worksheet
|
|
17
|
+
chart = workbook.add_chart(:type => 'column', :embedded => 1)
|
|
18
|
+
|
|
19
|
+
# For testing, copy the randomly generated axis ids in the target xlsx file.
|
|
20
|
+
chart.instance_variable_set(:@axis_ids, [48514944, 48516480])
|
|
21
|
+
|
|
22
|
+
data = [
|
|
23
|
+
[ 1, 2, 3, 4, 5],
|
|
24
|
+
[ 2, 4, 6, 8, 10],
|
|
25
|
+
[ 3, 6, 9, 12, 15],
|
|
26
|
+
[10, 20, 30, 40, 50]
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
worksheet.write('A1', data)
|
|
30
|
+
|
|
31
|
+
chart.add_series(
|
|
32
|
+
:values => '=Sheet1!$A$1:$A$5',
|
|
33
|
+
:data_labels => {:value => 1, :custom => [{:value => '=Sheet1!$D$1'}]}
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
chart.add_series(:values => '=Sheet1!$B$1:$B$5')
|
|
37
|
+
chart.add_series(:values => '=Sheet1!$C$1:$C$5')
|
|
38
|
+
|
|
39
|
+
worksheet.insert_chart('E9', chart)
|
|
40
|
+
|
|
41
|
+
workbook.close
|
|
42
|
+
compare_for_regression
|
|
43
|
+
end
|
|
44
|
+
end
|