write_xlsx 1.04.0 → 1.08.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|