write_xlsx 1.02.0 → 1.08.1
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 +72 -0
- data/README.md +1 -1
- data/examples/chart_data_labels.rb +320 -0
- data/examples/chart_line.rb +85 -10
- data/examples/tables.rb +77 -42
- data/lib/write_xlsx/chart/line.rb +15 -1
- 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/format.rb +5 -5
- data/lib/write_xlsx/package/app.rb +3 -3
- data/lib/write_xlsx/package/comments.rb +4 -4
- data/lib/write_xlsx/package/conditional_format.rb +2 -8
- data/lib/write_xlsx/package/packager.rb +1 -0
- data/lib/write_xlsx/package/relationships.rb +2 -2
- data/lib/write_xlsx/package/styles.rb +42 -11
- data/lib/write_xlsx/package/table.rb +16 -7
- data/lib/write_xlsx/package/vml.rb +20 -19
- data/lib/write_xlsx/sheets.rb +12 -20
- data/lib/write_xlsx/utility.rb +9 -3
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +76 -35
- data/lib/write_xlsx/worksheet/data_validation.rb +1 -6
- data/lib/write_xlsx/worksheet.rb +197 -57
- 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/chart_line.xlsx +0 -0
- data/test/perl_output/comments2.xlsx +0 -0
- data/test/perl_output/tables.xlsx +0 -0
- data/test/regression/images/red2.png +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_chart_line05.rb +43 -0
- data/test/regression/test_chart_line06.rb +43 -0
- data/test/regression/test_comment15.rb +28 -0
- data/test/regression/test_comment16.rb +34 -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_header_image15.rb +36 -0
- data/test/regression/test_header_image16.rb +42 -0
- data/test/regression/test_header_image17.rb +46 -0
- data/test/regression/test_header_image18.rb +48 -0
- data/test/regression/test_header_image19.rb +36 -0
- data/test/regression/test_hyperlink48.rb +31 -0
- data/test/regression/test_hyperlink49.rb +29 -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_image45.rb +2 -1
- data/test/regression/test_image46.rb +1 -1
- data/test/regression/test_image48.rb +32 -0
- data/test/regression/test_image49.rb +38 -0
- data/test/regression/test_image50.rb +24 -0
- data/test/regression/test_image51.rb +30 -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_object_position12.rb +25 -0
- data/test/regression/test_object_position13.rb +25 -0
- data/test/regression/test_object_position14.rb +25 -0
- data/test/regression/test_object_position15.rb +29 -0
- data/test/regression/test_object_position16.rb +29 -0
- data/test/regression/test_object_position17.rb +29 -0
- data/test/regression/test_object_position18.rb +29 -0
- data/test/regression/test_object_position19.rb +29 -0
- data/test/regression/test_object_position20.rb +29 -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_table24.rb +27 -0
- data/test/regression/test_table25.rb +27 -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/chart_line05.xlsx +0 -0
- data/test/regression/xlsx_files/chart_line06.xlsx +0 -0
- data/test/regression/xlsx_files/comment15.xlsx +0 -0
- data/test/regression/xlsx_files/comment16.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/header_image15.xlsx +0 -0
- data/test/regression/xlsx_files/header_image16.xlsx +0 -0
- data/test/regression/xlsx_files/header_image17.xlsx +0 -0
- data/test/regression/xlsx_files/header_image18.xlsx +0 -0
- data/test/regression/xlsx_files/header_image19.xlsx +0 -0
- data/test/regression/xlsx_files/hyperlink46.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/image45.xlsx +0 -0
- data/test/regression/xlsx_files/image46.xlsx +0 -0
- data/test/regression/xlsx_files/image48.xlsx +0 -0
- data/test/regression/xlsx_files/image49.xlsx +0 -0
- data/test/regression/xlsx_files/image50.xlsx +0 -0
- data/test/regression/xlsx_files/image51.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/object_position12.xlsx +0 -0
- data/test/regression/xlsx_files/object_position13.xlsx +0 -0
- data/test/regression/xlsx_files/object_position14.xlsx +0 -0
- data/test/regression/xlsx_files/object_position15.xlsx +0 -0
- data/test/regression/xlsx_files/object_position16.xlsx +0 -0
- data/test/regression/xlsx_files/object_position17.xlsx +0 -0
- data/test/regression/xlsx_files/object_position18.xlsx +0 -0
- data/test/regression/xlsx_files/object_position19.xlsx +0 -0
- data/test/regression/xlsx_files/object_position20.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/table24.xlsx +0 -0
- data/test/regression/xlsx_files/table25.xlsx +0 -0
- data/test/regression/xlsx_files/table26.xlsx +0 -0
- data/test/test_example_match.rb +433 -10
- data/test/utility/test_range.rb +20 -0
- data/test/workbook/test_check_sheetname.rb +0 -10
- data/write_xlsx.gemspec +1 -0
- metadata +323 -8
data/lib/write_xlsx/worksheet.rb
CHANGED
|
@@ -359,6 +359,8 @@ module Writexlsx
|
|
|
359
359
|
@shape_hash = {}
|
|
360
360
|
@drawing_rels = {}
|
|
361
361
|
@drawing_rels_id = 0
|
|
362
|
+
@vml_drawing_rels = {}
|
|
363
|
+
@vml_drawing_rels_id = 0
|
|
362
364
|
@header_images = []
|
|
363
365
|
@footer_images = []
|
|
364
366
|
|
|
@@ -379,6 +381,7 @@ module Writexlsx
|
|
|
379
381
|
@comments = Package::Comments.new(self)
|
|
380
382
|
@buttons_array = []
|
|
381
383
|
@header_images_array = []
|
|
384
|
+
@ignore_errors = nil
|
|
382
385
|
|
|
383
386
|
@validations = []
|
|
384
387
|
|
|
@@ -386,6 +389,9 @@ module Writexlsx
|
|
|
386
389
|
@data_bars_2010 = []
|
|
387
390
|
@dxf_priority = 1
|
|
388
391
|
|
|
392
|
+
@protected_ranges = []
|
|
393
|
+
@num_protected_ranges = 0
|
|
394
|
+
|
|
389
395
|
if excel2003_style?
|
|
390
396
|
@original_row_height = 12.75
|
|
391
397
|
@default_row_height = 12.75
|
|
@@ -412,6 +418,7 @@ module Writexlsx
|
|
|
412
418
|
write_cols
|
|
413
419
|
write_sheet_data
|
|
414
420
|
write_sheet_protection
|
|
421
|
+
write_protected_ranges
|
|
415
422
|
# write_sheet_calc_pr
|
|
416
423
|
write_phonetic_pr if excel2003_style?
|
|
417
424
|
write_auto_filter
|
|
@@ -425,6 +432,7 @@ module Writexlsx
|
|
|
425
432
|
write_header_footer
|
|
426
433
|
write_row_breaks
|
|
427
434
|
write_col_breaks
|
|
435
|
+
write_ignored_errors
|
|
428
436
|
write_drawings
|
|
429
437
|
write_legacy_drawing
|
|
430
438
|
write_legacy_drawing_hf
|
|
@@ -614,7 +622,25 @@ module Writexlsx
|
|
|
614
622
|
|
|
615
623
|
# Set the password after the user defined values.
|
|
616
624
|
@protect[:password] =
|
|
617
|
-
|
|
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]
|
|
618
644
|
end
|
|
619
645
|
|
|
620
646
|
def protect_default_settings # :nodoc:
|
|
@@ -816,12 +842,7 @@ module Writexlsx
|
|
|
816
842
|
row_first, row_last = row_last, row_first if row_first > row_last
|
|
817
843
|
col_first, col_last = col_last, col_first if col_first > col_last
|
|
818
844
|
|
|
819
|
-
|
|
820
|
-
if row_first == row_last && col_first == col_last
|
|
821
|
-
sqref = active_cell
|
|
822
|
-
else
|
|
823
|
-
sqref = xl_range(row_first, row_last, col_first, col_last)
|
|
824
|
-
end
|
|
845
|
+
sqref = xl_range(row_first, row_last, col_first, col_last)
|
|
825
846
|
else # Single cell selection.
|
|
826
847
|
sqref = active_cell
|
|
827
848
|
end
|
|
@@ -1205,14 +1226,10 @@ module Writexlsx
|
|
|
1205
1226
|
# distribution.
|
|
1206
1227
|
#
|
|
1207
1228
|
def set_header(string = '', margin = 0.3, options = {})
|
|
1208
|
-
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
|
|
1209
1230
|
# Replace the Excel placeholder &[Picture] with the internal &G.
|
|
1210
1231
|
@page_setup.header = string.gsub(/&\[Picture\]/, '&G')
|
|
1211
1232
|
|
|
1212
|
-
if string.size >= 255
|
|
1213
|
-
raise 'Header string must be less than 255 characters'
|
|
1214
|
-
end
|
|
1215
|
-
|
|
1216
1233
|
if options[:align_with_margins]
|
|
1217
1234
|
@page_setup.header_footer_aligns = options[:align_with_margins]
|
|
1218
1235
|
end
|
|
@@ -1253,17 +1270,13 @@ module Writexlsx
|
|
|
1253
1270
|
# The syntax of the set_footer() method is the same as set_header()
|
|
1254
1271
|
#
|
|
1255
1272
|
def set_footer(string = '', margin = 0.3, options = {})
|
|
1256
|
-
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
|
|
1257
1274
|
|
|
1258
1275
|
@page_setup.footer = string.dup
|
|
1259
1276
|
|
|
1260
1277
|
# Replace the Excel placeholder &[Picture] with the internal &G.
|
|
1261
1278
|
@page_setup.footer = string.gsub(/&\[Picture\]/, '&G')
|
|
1262
1279
|
|
|
1263
|
-
if string.size >= 255
|
|
1264
|
-
raise 'Header string must be less than 255 characters'
|
|
1265
|
-
end
|
|
1266
|
-
|
|
1267
1280
|
if options[:align_with_margins]
|
|
1268
1281
|
@page_setup.header_footer_aligns = options[:align_with_margins]
|
|
1269
1282
|
end
|
|
@@ -2512,7 +2525,9 @@ module Writexlsx
|
|
|
2512
2525
|
col1, col2 = col2, col1 if col1 > col2
|
|
2513
2526
|
|
|
2514
2527
|
# Check that row and col are valid and store max and min values
|
|
2528
|
+
check_dimensions(row1, col1)
|
|
2515
2529
|
check_dimensions(row2, col2)
|
|
2530
|
+
store_row_col_max_min_values(row1, col1)
|
|
2516
2531
|
store_row_col_max_min_values(row2, col2)
|
|
2517
2532
|
|
|
2518
2533
|
# Define array range
|
|
@@ -3044,14 +3059,16 @@ module Writexlsx
|
|
|
3044
3059
|
|
|
3045
3060
|
if options.first.class == Hash
|
|
3046
3061
|
# Newer hash bashed options
|
|
3047
|
-
params
|
|
3048
|
-
x_offset
|
|
3049
|
-
y_offset
|
|
3050
|
-
x_scale
|
|
3051
|
-
y_scale
|
|
3052
|
-
anchor
|
|
3053
|
-
url
|
|
3054
|
-
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]
|
|
3055
3072
|
else
|
|
3056
3073
|
x_offset, y_offset, x_scale, y_scale, anchor = options
|
|
3057
3074
|
end
|
|
@@ -3063,7 +3080,7 @@ module Writexlsx
|
|
|
3063
3080
|
|
|
3064
3081
|
@images << [
|
|
3065
3082
|
row, col, image, x_offset, y_offset,
|
|
3066
|
-
x_scale, y_scale, url, tip, anchor
|
|
3083
|
+
x_scale, y_scale, url, tip, anchor, description, decorative
|
|
3067
3084
|
]
|
|
3068
3085
|
end
|
|
3069
3086
|
|
|
@@ -3361,9 +3378,11 @@ module Writexlsx
|
|
|
3361
3378
|
row_first, row_last = row_last, row_first if row_first > row_last
|
|
3362
3379
|
col_first, col_last = col_last, col_first if col_first > col_last
|
|
3363
3380
|
|
|
3364
|
-
# Check that
|
|
3365
|
-
check_dimensions(
|
|
3366
|
-
|
|
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)
|
|
3367
3386
|
|
|
3368
3387
|
# Store the merge range.
|
|
3369
3388
|
@merge << [row_first, col_first, row_last, col_last]
|
|
@@ -3426,9 +3445,11 @@ module Writexlsx
|
|
|
3426
3445
|
row_first, row_last = row_last, row_first if row_first > row_last
|
|
3427
3446
|
col_first, col_last = col_last, col_first if col_first > col_last
|
|
3428
3447
|
|
|
3429
|
-
# Check that
|
|
3430
|
-
check_dimensions(
|
|
3431
|
-
|
|
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)
|
|
3432
3453
|
|
|
3433
3454
|
# Store the merge range.
|
|
3434
3455
|
@merge << [row_first, col_first, row_last, col_last]
|
|
@@ -5736,7 +5757,7 @@ module Writexlsx
|
|
|
5736
5757
|
name = chart.name
|
|
5737
5758
|
|
|
5738
5759
|
# Create a Drawing object to use with worksheet unless one already exists.
|
|
5739
|
-
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)
|
|
5740
5761
|
if !drawings?
|
|
5741
5762
|
@drawings = Drawings.new
|
|
5742
5763
|
@drawings.add_drawing_object(drawing)
|
|
@@ -5868,27 +5889,24 @@ module Writexlsx
|
|
|
5868
5889
|
y_abs += y1
|
|
5869
5890
|
|
|
5870
5891
|
# Adjust start column for offsets that are greater than the col width.
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
col_start += 1
|
|
5875
|
-
end
|
|
5892
|
+
while x1 >= size_col(col_start, anchor)
|
|
5893
|
+
x1 -= size_col(col_start)
|
|
5894
|
+
col_start += 1
|
|
5876
5895
|
end
|
|
5877
5896
|
|
|
5878
5897
|
# Adjust start row for offsets that are greater than the row height.
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
row_start += 1
|
|
5883
|
-
end
|
|
5898
|
+
while y1 >= size_row(row_start, anchor)
|
|
5899
|
+
y1 -= size_row(row_start)
|
|
5900
|
+
row_start += 1
|
|
5884
5901
|
end
|
|
5885
5902
|
|
|
5886
5903
|
# Initialise end cell to the same as the start cell.
|
|
5887
5904
|
col_end = col_start
|
|
5888
5905
|
row_end = row_start
|
|
5889
5906
|
|
|
5890
|
-
|
|
5891
|
-
|
|
5907
|
+
# Only offset the image in the cell if the row/col isn't hidden.
|
|
5908
|
+
width += x1 if size_col(col_start, anchor) > 0
|
|
5909
|
+
height += y1 if size_row(row_start, anchor) > 0
|
|
5892
5910
|
|
|
5893
5911
|
# Subtract the underlying cell widths to find the end cell of the object.
|
|
5894
5912
|
while width >= size_col(col_end, anchor)
|
|
@@ -6063,6 +6081,30 @@ module Writexlsx
|
|
|
6063
6081
|
end
|
|
6064
6082
|
end
|
|
6065
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
|
+
|
|
6066
6108
|
def write_ext(url)
|
|
6067
6109
|
attributes = [
|
|
6068
6110
|
['xmlns:x14', "#{OFFICE_URL}spreadsheetml/2009/9/main"],
|
|
@@ -6100,6 +6142,18 @@ module Writexlsx
|
|
|
6100
6142
|
end
|
|
6101
6143
|
end
|
|
6102
6144
|
|
|
6145
|
+
#
|
|
6146
|
+
# Get the index used to address a vml_drawing rel link.
|
|
6147
|
+
#
|
|
6148
|
+
def get_vml_drawing_rel_index(target)
|
|
6149
|
+
if @vml_drawing_rels[target]
|
|
6150
|
+
@vml_drawing_rels[target]
|
|
6151
|
+
else
|
|
6152
|
+
@vml_drawing_rels_id += 1
|
|
6153
|
+
@vml_drawing_rels[target] = @vml_drawing_rels_id
|
|
6154
|
+
end
|
|
6155
|
+
end
|
|
6156
|
+
|
|
6103
6157
|
def hyperlinks_count
|
|
6104
6158
|
@hyperlinks.keys.inject(0) { |s, n| s += @hyperlinks[n].keys.size }
|
|
6105
6159
|
end
|
|
@@ -6447,13 +6501,13 @@ module Writexlsx
|
|
|
6447
6501
|
#
|
|
6448
6502
|
# Set up image/drawings.
|
|
6449
6503
|
#
|
|
6450
|
-
def prepare_image(index, image_id, drawing_id, width, height, name, image_type, x_dpi = 96, y_dpi = 96) #:nodoc:
|
|
6504
|
+
def prepare_image(index, image_id, drawing_id, width, height, name, image_type, x_dpi = 96, y_dpi = 96, md5 = nil) #:nodoc:
|
|
6451
6505
|
x_dpi ||= 96
|
|
6452
6506
|
y_dpi ||= 96
|
|
6453
6507
|
drawing_type = 2
|
|
6454
6508
|
|
|
6455
6509
|
row, col, image, x_offset, y_offset,
|
|
6456
|
-
x_scale, y_scale, url, tip, anchor = @images[index]
|
|
6510
|
+
x_scale, y_scale, url, tip, anchor, description, decorative = @images[index]
|
|
6457
6511
|
|
|
6458
6512
|
width *= x_scale
|
|
6459
6513
|
height *= y_scale
|
|
@@ -6468,7 +6522,7 @@ module Writexlsx
|
|
|
6468
6522
|
height = (0.5 + (height * 9_525)).to_i
|
|
6469
6523
|
|
|
6470
6524
|
# Create a Drawing object to use with worksheet unless one already exists.
|
|
6471
|
-
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)
|
|
6472
6526
|
if !drawings?
|
|
6473
6527
|
drawings = Drawings.new
|
|
6474
6528
|
drawings.embedded = 1
|
|
@@ -6481,6 +6535,10 @@ module Writexlsx
|
|
|
6481
6535
|
end
|
|
6482
6536
|
drawings.add_drawing_object(drawing)
|
|
6483
6537
|
|
|
6538
|
+
if description
|
|
6539
|
+
drawing.description = description
|
|
6540
|
+
end
|
|
6541
|
+
|
|
6484
6542
|
if url
|
|
6485
6543
|
rel_type = '/hyperlink'
|
|
6486
6544
|
target_mode = 'External'
|
|
@@ -6488,10 +6546,19 @@ module Writexlsx
|
|
|
6488
6546
|
target = escape_url(url)
|
|
6489
6547
|
end
|
|
6490
6548
|
if url =~ /^external:/
|
|
6491
|
-
target = escape_url(url.sub(/^external:/, '
|
|
6549
|
+
target = escape_url(url.sub(/^external:/, ''))
|
|
6550
|
+
|
|
6492
6551
|
# Additional escape not required in worksheet hyperlinks
|
|
6493
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
|
|
6494
6560
|
end
|
|
6561
|
+
|
|
6495
6562
|
if url =~ /^internal:/
|
|
6496
6563
|
target = url.sub(/^internal:/, '#')
|
|
6497
6564
|
target_mode = nil
|
|
@@ -6503,24 +6570,30 @@ Ignoring URL #{target} where link or anchor > 255 characters since it exceeds Ex
|
|
|
6503
6570
|
EOS
|
|
6504
6571
|
end
|
|
6505
6572
|
|
|
6506
|
-
if target
|
|
6573
|
+
if target && !@drawing_rels[url]
|
|
6507
6574
|
@drawing_links << [rel_type, target, target_mode]
|
|
6508
6575
|
end
|
|
6509
|
-
drawing.url_rel_index = drawing_rel_index
|
|
6576
|
+
drawing.url_rel_index = drawing_rel_index(url)
|
|
6510
6577
|
end
|
|
6511
6578
|
|
|
6512
|
-
|
|
6513
|
-
|
|
6579
|
+
if !@drawing_rels[md5]
|
|
6580
|
+
@drawing_links << ['/image', "../media/image#{image_id}.#{image_type}"]
|
|
6581
|
+
end
|
|
6582
|
+
drawing.rel_index = drawing_rel_index(md5)
|
|
6514
6583
|
end
|
|
6515
6584
|
public :prepare_image
|
|
6516
6585
|
|
|
6517
|
-
def prepare_header_image(image_id, width, height, name, image_type, position, x_dpi, y_dpi)
|
|
6586
|
+
def prepare_header_image(image_id, width, height, name, image_type, position, x_dpi, y_dpi, md5)
|
|
6518
6587
|
# Strip the extension from the filename.
|
|
6519
6588
|
body = name.dup
|
|
6520
6589
|
body[/\.[^\.]+$/, 0] = ''
|
|
6521
6590
|
|
|
6522
|
-
|
|
6523
|
-
|
|
6591
|
+
if !@vml_drawing_rels[md5]
|
|
6592
|
+
@vml_drawing_links << ['/image', "../media/image#{image_id}.#{image_type}" ]
|
|
6593
|
+
end
|
|
6594
|
+
|
|
6595
|
+
ref_id = get_vml_drawing_rel_index(md5)
|
|
6596
|
+
@header_images_array << [width, height, body, position, x_dpi, y_dpi, ref_id]
|
|
6524
6597
|
end
|
|
6525
6598
|
public :prepare_header_image
|
|
6526
6599
|
|
|
@@ -6628,7 +6701,7 @@ EOS
|
|
|
6628
6701
|
shape.calc_position_emus(self)
|
|
6629
6702
|
|
|
6630
6703
|
drawing_type = 3
|
|
6631
|
-
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)
|
|
6632
6705
|
drawings.add_drawing_object(drawing)
|
|
6633
6706
|
end
|
|
6634
6707
|
public :prepare_shape
|
|
@@ -6718,6 +6791,8 @@ EOS
|
|
|
6718
6791
|
chars.each { |c| encoded_password ^= c }
|
|
6719
6792
|
encoded_password ^= count
|
|
6720
6793
|
encoded_password ^= 0xCE4B
|
|
6794
|
+
|
|
6795
|
+
sprintf("%X", encoded_password)
|
|
6721
6796
|
end
|
|
6722
6797
|
|
|
6723
6798
|
#
|
|
@@ -7533,6 +7608,32 @@ EOS
|
|
|
7533
7608
|
@writer.empty_tag('sheetProtection', attributes)
|
|
7534
7609
|
end
|
|
7535
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
|
+
|
|
7536
7637
|
#
|
|
7537
7638
|
# Write the <drawing> elements.
|
|
7538
7639
|
#
|
|
@@ -8065,5 +8166,44 @@ EOS
|
|
|
8065
8166
|
end
|
|
8066
8167
|
col
|
|
8067
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
|
|
8068
8208
|
end
|
|
8069
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
|
|
Binary file
|
|
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
|