write_xlsx 0.58.0 → 0.59.0
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.
- data/README.rdoc +7 -1
- data/bin/extract_vba.rb +29 -0
- data/examples/add_vba_project.rb +36 -0
- data/examples/vbaProject.bin +0 -0
- data/lib/write_xlsx/chart.rb +22 -37
- data/lib/write_xlsx/package/conditional_format.rb +593 -0
- data/lib/write_xlsx/package/content_types.rb +17 -0
- data/lib/write_xlsx/package/packager.rb +26 -6
- data/lib/write_xlsx/package/relationships.rb +11 -1
- data/lib/write_xlsx/package/table.rb +284 -62
- data/lib/write_xlsx/utility.rb +179 -0
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +14 -1
- data/lib/write_xlsx/worksheet.rb +667 -875
- data/test/package/table/test_table01.rb +1 -2
- data/test/package/table/test_table02.rb +1 -2
- data/test/package/table/test_table03.rb +1 -2
- data/test/package/table/test_table04.rb +1 -2
- data/test/package/table/test_table05.rb +1 -2
- data/test/package/table/test_table06.rb +1 -2
- data/test/package/table/test_table07.rb +1 -2
- data/test/package/table/test_table08.rb +1 -2
- data/test/package/table/test_table09.rb +1 -2
- data/test/package/table/test_table10.rb +1 -2
- data/test/package/table/test_table11.rb +1 -2
- data/test/package/table/test_table12.rb +1 -2
- data/test/package/table/test_write_auto_filter.rb +10 -3
- data/test/package/table/test_write_table_column.rb +9 -2
- data/test/package/table/test_write_table_style_info.rb +12 -11
- data/test/package/table/test_write_xml_declaration.rb +6 -1
- data/test/perl_output/add_vba_project.xlsm +0 -0
- data/test/regression/test_macro01.rb +29 -0
- data/test/regression/xlsx_files/macro01.xlsm +0 -0
- data/test/regression/xlsx_files/vbaProject01.bin +0 -0
- data/test/test_example_match.rb +22 -0
- data/test/vbaProject.bin +0 -0
- metadata +18 -3
data/lib/write_xlsx/worksheet.rb
CHANGED
@@ -5,6 +5,7 @@ require 'write_xlsx/format'
|
|
5
5
|
require 'write_xlsx/drawing'
|
6
6
|
require 'write_xlsx/compatibility'
|
7
7
|
require 'write_xlsx/utility'
|
8
|
+
require 'write_xlsx/package/conditional_format'
|
8
9
|
require 'tempfile'
|
9
10
|
|
10
11
|
module Writexlsx
|
@@ -354,6 +355,7 @@ module Writexlsx
|
|
354
355
|
attr_reader :writer, :set_rows, :col_formats # :nodoc:
|
355
356
|
attr_accessor :vml_shape_id, :rel_count, :hlink_refs # :nodoc:
|
356
357
|
attr_reader :comments_author # :nodoc:
|
358
|
+
attr_accessor :dxf_priority # :nodoc:
|
357
359
|
|
358
360
|
def initialize(workbook, index, name) #:nodoc:
|
359
361
|
@writer = Package::XMLWriterSimple.new
|
@@ -2901,133 +2903,6 @@ module Writexlsx
|
|
2901
2903
|
write_formula(row, col, formula, format, value)
|
2902
2904
|
end
|
2903
2905
|
|
2904
|
-
#
|
2905
|
-
# convert_date_time(date_time_string)
|
2906
|
-
#
|
2907
|
-
# The function takes a date and time in ISO8601 "yyyy-mm-ddThh:mm:ss.ss" format
|
2908
|
-
# and converts it to a decimal number representing a valid Excel date.
|
2909
|
-
#
|
2910
|
-
# Dates and times in Excel are represented by real numbers. The integer part of
|
2911
|
-
# the number stores the number of days since the epoch and the fractional part
|
2912
|
-
# stores the percentage of the day in seconds. The epoch can be either 1900 or
|
2913
|
-
# 1904.
|
2914
|
-
#
|
2915
|
-
# Parameter: Date and time string in one of the following formats:
|
2916
|
-
# yyyy-mm-ddThh:mm:ss.ss # Standard
|
2917
|
-
# yyyy-mm-ddT # Date only
|
2918
|
-
# Thh:mm:ss.ss # Time only
|
2919
|
-
#
|
2920
|
-
# Returns:
|
2921
|
-
# A decimal number representing a valid Excel date, or
|
2922
|
-
# nil if the date is invalid.
|
2923
|
-
#
|
2924
|
-
def convert_date_time(date_time_string) #:nodoc:
|
2925
|
-
date_time = date_time_string
|
2926
|
-
|
2927
|
-
days = 0 # Number of days since epoch
|
2928
|
-
seconds = 0 # Time expressed as fraction of 24h hours in seconds
|
2929
|
-
|
2930
|
-
# Strip leading and trailing whitespace.
|
2931
|
-
date_time.sub!(/^\s+/, '')
|
2932
|
-
date_time.sub!(/\s+$/, '')
|
2933
|
-
|
2934
|
-
# Check for invalid date char.
|
2935
|
-
return nil if date_time =~ /[^0-9T:\-\.Z]/
|
2936
|
-
|
2937
|
-
# Check for "T" after date or before time.
|
2938
|
-
return nil unless date_time =~ /\dT|T\d/
|
2939
|
-
|
2940
|
-
# Strip trailing Z in ISO8601 date.
|
2941
|
-
date_time.sub!(/Z$/, '')
|
2942
|
-
|
2943
|
-
# Split into date and time.
|
2944
|
-
date, time = date_time.split(/T/)
|
2945
|
-
|
2946
|
-
# We allow the time portion of the input DateTime to be optional.
|
2947
|
-
if time
|
2948
|
-
# Match hh:mm:ss.sss+ where the seconds are optional
|
2949
|
-
if time =~ /^(\d\d):(\d\d)(:(\d\d(\.\d+)?))?/
|
2950
|
-
hour = $1.to_i
|
2951
|
-
min = $2.to_i
|
2952
|
-
sec = $4.to_f || 0
|
2953
|
-
else
|
2954
|
-
return nil # Not a valid time format.
|
2955
|
-
end
|
2956
|
-
|
2957
|
-
# Some boundary checks
|
2958
|
-
return nil if hour >= 24
|
2959
|
-
return nil if min >= 60
|
2960
|
-
return nil if sec >= 60
|
2961
|
-
|
2962
|
-
# Excel expresses seconds as a fraction of the number in 24 hours.
|
2963
|
-
seconds = (hour * 60* 60 + min * 60 + sec) / (24.0 * 60 * 60)
|
2964
|
-
end
|
2965
|
-
|
2966
|
-
# We allow the date portion of the input DateTime to be optional.
|
2967
|
-
return seconds if date == ''
|
2968
|
-
|
2969
|
-
# Match date as yyyy-mm-dd.
|
2970
|
-
if date =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$/
|
2971
|
-
year = $1.to_i
|
2972
|
-
month = $2.to_i
|
2973
|
-
day = $3.to_i
|
2974
|
-
else
|
2975
|
-
return nil # Not a valid date format.
|
2976
|
-
end
|
2977
|
-
|
2978
|
-
# Set the epoch as 1900 or 1904. Defaults to 1900.
|
2979
|
-
# Special cases for Excel.
|
2980
|
-
unless date_1904?
|
2981
|
-
return seconds if date == '1899-12-31' # Excel 1900 epoch
|
2982
|
-
return seconds if date == '1900-01-00' # Excel 1900 epoch
|
2983
|
-
return 60 + seconds if date == '1900-02-29' # Excel false leapday
|
2984
|
-
end
|
2985
|
-
|
2986
|
-
|
2987
|
-
# We calculate the date by calculating the number of days since the epoch
|
2988
|
-
# and adjust for the number of leap days. We calculate the number of leap
|
2989
|
-
# days by normalising the year in relation to the epoch. Thus the year 2000
|
2990
|
-
# becomes 100 for 4 and 100 year leapdays and 400 for 400 year leapdays.
|
2991
|
-
#
|
2992
|
-
epoch = date_1904? ? 1904 : 1900
|
2993
|
-
offset = date_1904? ? 4 : 0
|
2994
|
-
norm = 300
|
2995
|
-
range = year - epoch
|
2996
|
-
|
2997
|
-
# Set month days and check for leap year.
|
2998
|
-
mdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
2999
|
-
leap = 0
|
3000
|
-
leap = 1 if year % 4 == 0 && year % 100 != 0 || year % 400 == 0
|
3001
|
-
mdays[1] = 29 if leap != 0
|
3002
|
-
|
3003
|
-
# Some boundary checks
|
3004
|
-
return nil if year < epoch or year > 9999
|
3005
|
-
return nil if month < 1 or month > 12
|
3006
|
-
return nil if day < 1 or day > mdays[month - 1]
|
3007
|
-
|
3008
|
-
# Accumulate the number of days since the epoch.
|
3009
|
-
days = day # Add days for current month
|
3010
|
-
(0 .. month-2).each do |m|
|
3011
|
-
days += mdays[m] # Add days for past months
|
3012
|
-
end
|
3013
|
-
days += range * 365 # Add days for past years
|
3014
|
-
days += ((range) / 4) # Add leapdays
|
3015
|
-
days -= ((range + offset) /100) # Subtract 100 year leapdays
|
3016
|
-
days += ((range + offset + norm)/400) # Add 400 year leapdays
|
3017
|
-
days -= leap # Already counted above
|
3018
|
-
|
3019
|
-
# Adjust for Excel erroneously treating 1900 as a leap year.
|
3020
|
-
days += 1 if !date_1904? and days > 59
|
3021
|
-
|
3022
|
-
date_time = sprintf("%0.10f", days + seconds)
|
3023
|
-
date_time = date_time.sub(/\.?0+$/, '') if date_time =~ /\./
|
3024
|
-
if date_time =~ /\./
|
3025
|
-
date_time.to_f
|
3026
|
-
else
|
3027
|
-
date_time.to_i
|
3028
|
-
end
|
3029
|
-
end
|
3030
|
-
|
3031
2906
|
#
|
3032
2907
|
# :call-seq:
|
3033
2908
|
# set_row(row [ , height, format, hidden, level, collapsed ] )
|
@@ -3222,6 +3097,9 @@ module Writexlsx
|
|
3222
3097
|
#
|
3223
3098
|
# This method handles the interface to Excel conditional formatting.
|
3224
3099
|
#
|
3100
|
+
# This method contains a lot of parameters and is described in detail in
|
3101
|
+
# the section below.
|
3102
|
+
#
|
3225
3103
|
# We allow the format to be called on one cell or a range of cells. The
|
3226
3104
|
# hashref contains the formatting parameters and must be the last param:
|
3227
3105
|
#
|
@@ -3240,170 +3118,604 @@ module Writexlsx
|
|
3240
3118
|
# }
|
3241
3119
|
# )
|
3242
3120
|
#
|
3243
|
-
#
|
3244
|
-
#
|
3121
|
+
# See also the conditional_format.rb program in the examples directory of
|
3122
|
+
# the distro.
|
3123
|
+
#
|
3124
|
+
# The conditional_formatting method is used to apply formatting based
|
3125
|
+
# on user defined criteria to an write_xlsx file.
|
3126
|
+
#
|
3127
|
+
# It can be applied to a single cell or a range of cells.
|
3128
|
+
# You can pass 3 parameters such as (row, col, {...})
|
3129
|
+
# or 5 parameters such as (first_row, first_col, last_row, last_col, {...}).
|
3130
|
+
# You can also use A1 style notation. For example:
|
3131
|
+
#
|
3132
|
+
# worksheet.conditional_formatting( 0, 0, {...} )
|
3133
|
+
# worksheet.conditional_formatting( 0, 0, 4, 1, {...} )
|
3134
|
+
#
|
3135
|
+
# # Which are the same as:
|
3136
|
+
#
|
3137
|
+
# worksheet.conditional_formatting( 'A1', {...} )
|
3138
|
+
# worksheet.conditional_formatting( 'A1:B5', {...} )
|
3139
|
+
#
|
3140
|
+
# Using A1 style notation is is also possible to specify
|
3141
|
+
# non-contiguous ranges, separated by a comma. For example:
|
3142
|
+
#
|
3143
|
+
# worksheet.conditional_formatting( 'A1:D5,A8:D12', {...} )
|
3144
|
+
# The last parameter in conditional_formatting must be a hash containing
|
3145
|
+
# the parameters that describe the type and style of the data validation.
|
3146
|
+
#
|
3147
|
+
# The main parameters are:
|
3148
|
+
#
|
3149
|
+
# :type
|
3150
|
+
# :format
|
3151
|
+
# :criteria
|
3152
|
+
# :value
|
3153
|
+
# :minimum
|
3154
|
+
# :maximum
|
3155
|
+
# Other, less commonly used parameters are:
|
3156
|
+
#
|
3157
|
+
# :min_type
|
3158
|
+
# :mid_type
|
3159
|
+
# :max_type
|
3160
|
+
# :min_value
|
3161
|
+
# :mid_value
|
3162
|
+
# :max_value
|
3163
|
+
# :min_color
|
3164
|
+
# :mid_color
|
3165
|
+
# :max_color
|
3166
|
+
# :bar_color
|
3167
|
+
# Additional parameters which are used for specific conditional format types
|
3168
|
+
# are shown in the relevant sections below.
|
3169
|
+
#
|
3170
|
+
# == :type
|
3171
|
+
#
|
3172
|
+
# This parameter is passed in a hash to conditional_formatting.
|
3173
|
+
#
|
3174
|
+
# The type parameter is used to set the type of conditional formatting
|
3175
|
+
# that you wish to apply. It is always required and it has no default value.
|
3176
|
+
# Allowable type values and their associated parameters are:
|
3177
|
+
#
|
3178
|
+
# Type Parameters
|
3179
|
+
# ====== ==========
|
3180
|
+
# 'cell' :criteria
|
3181
|
+
# :value
|
3182
|
+
# :minimum
|
3183
|
+
# :maximum
|
3184
|
+
#
|
3185
|
+
# 'date' :criteria
|
3186
|
+
# :value
|
3187
|
+
# :minimum
|
3188
|
+
# :maximum
|
3189
|
+
#
|
3190
|
+
# 'time_period' :criteria
|
3191
|
+
#
|
3192
|
+
# 'text' :criteria
|
3193
|
+
# :value
|
3194
|
+
#
|
3195
|
+
# 'average' :criteria
|
3196
|
+
#
|
3197
|
+
# 'duplicate' (none)
|
3198
|
+
#
|
3199
|
+
# 'unique' (none)
|
3200
|
+
#
|
3201
|
+
# 'top' :criteria
|
3202
|
+
# :value
|
3203
|
+
#
|
3204
|
+
# 'bottom' :criteria
|
3205
|
+
# :value
|
3206
|
+
#
|
3207
|
+
# 'blanks' (none)
|
3208
|
+
#
|
3209
|
+
# 'no_blanks' (none)
|
3210
|
+
#
|
3211
|
+
# 'errors' (none)
|
3212
|
+
#
|
3213
|
+
# 'no_errors' (none)
|
3214
|
+
#
|
3215
|
+
# '2_color_scale' (none)
|
3216
|
+
#
|
3217
|
+
# '3_color_scale' (none)
|
3218
|
+
#
|
3219
|
+
# 'data_bar' (none)
|
3220
|
+
#
|
3221
|
+
# 'formula' :criteria
|
3222
|
+
# All conditional formatting types have a format parameter, see below.
|
3223
|
+
# Other types and parameters such as icon sets will be added in time.
|
3224
|
+
#
|
3225
|
+
# == :type => 'cell'
|
3226
|
+
#
|
3227
|
+
# This is the most common conditional formatting type. It is used when
|
3228
|
+
# a format is applied to a cell based on a simple criterion. For example:
|
3229
|
+
#
|
3230
|
+
# worksheet.conditional_formatting( 'A1',
|
3231
|
+
# {
|
3232
|
+
# :type => 'cell',
|
3233
|
+
# :criteria => 'greater than',
|
3234
|
+
# :value => 5,
|
3235
|
+
# :format => red_format
|
3236
|
+
# }
|
3237
|
+
# )
|
3238
|
+
# Or, using the between criteria:
|
3239
|
+
#
|
3240
|
+
# worksheet.conditional_formatting( 'C1:C4',
|
3241
|
+
# {
|
3242
|
+
# :type => 'cell',
|
3243
|
+
# :criteria => 'between',
|
3244
|
+
# :minimum => 20,
|
3245
|
+
# :maximum => 30,
|
3246
|
+
# :format => green_format
|
3247
|
+
# }
|
3248
|
+
# )
|
3249
|
+
# == :criteria
|
3250
|
+
#
|
3251
|
+
# The criteria parameter is used to set the criteria by which the cell data
|
3252
|
+
# will be evaluated. It has no default value. The most common criteria
|
3253
|
+
# as applied to { type => 'cell' } are:
|
3254
|
+
#
|
3255
|
+
# 'between'
|
3256
|
+
# 'not between'
|
3257
|
+
# 'equal to' | '==' | '='
|
3258
|
+
# 'not equal to' | '!=' | '<>'
|
3259
|
+
# 'greater than' | '>'
|
3260
|
+
# 'less than' | '<'
|
3261
|
+
# 'greater than or equal to' | '>='
|
3262
|
+
# 'less than or equal to' | '<='
|
3263
|
+
# You can either use Excel's textual description strings,
|
3264
|
+
# in the first column above, or the more common symbolic alternatives.
|
3265
|
+
#
|
3266
|
+
# Additional criteria which are specific to other conditional format types
|
3267
|
+
# are shown in the relevant sections below.
|
3268
|
+
#
|
3269
|
+
# == :value
|
3270
|
+
#
|
3271
|
+
# The value is generally used along with the criteria parameter to set the
|
3272
|
+
# rule by which the cell data will be evaluated.
|
3273
|
+
#
|
3274
|
+
# :type => 'cell',
|
3275
|
+
# :criteria => '>',
|
3276
|
+
# :value => 5
|
3277
|
+
# :format => format
|
3278
|
+
# The value property can also be an cell reference.
|
3279
|
+
#
|
3280
|
+
# :type => 'cell',
|
3281
|
+
# :criteria => '>',
|
3282
|
+
# :value => '$C$1',
|
3283
|
+
# :format => format
|
3284
|
+
# == :format
|
3285
|
+
#
|
3286
|
+
# The format parameter is used to specify the format that will be applied
|
3287
|
+
# to the cell when the conditional formatting criterion is met.
|
3288
|
+
# The format is created using the add_format method in the same way as cell
|
3289
|
+
# formats:
|
3290
|
+
#
|
3291
|
+
# format = workbook.add_format( :bold => 1, :italic => 1 )
|
3292
|
+
#
|
3293
|
+
# worksheet.conditional_formatting( 'A1',
|
3294
|
+
# {
|
3295
|
+
# :type => 'cell',
|
3296
|
+
# :criteria => '>',
|
3297
|
+
# :value => 5
|
3298
|
+
# :format => format
|
3299
|
+
# }
|
3300
|
+
# )
|
3301
|
+
# The conditional format follows the same rules as in Excel:
|
3302
|
+
# it is superimposed over the existing cell format and not all font and
|
3303
|
+
# border properties can be modified. Font properties that can't be modified
|
3304
|
+
# are font name, font size, superscript and subscript.
|
3305
|
+
# The border property that cannot be modified is diagonal borders.
|
3306
|
+
#
|
3307
|
+
# Excel specifies some default formats to be used with conditional
|
3308
|
+
# formatting. You can replicate them using the following write_xlsx formats:
|
3309
|
+
#
|
3310
|
+
# # Light red fill with dark red text.
|
3311
|
+
#
|
3312
|
+
# format1 = workbook.add_format(
|
3313
|
+
# :bg_color => '#FFC7CE',
|
3314
|
+
# :color => '#9C0006'
|
3315
|
+
# )
|
3316
|
+
#
|
3317
|
+
# # Light yellow fill with dark yellow text.
|
3318
|
+
#
|
3319
|
+
# format2 = workbook.add_format(
|
3320
|
+
# :bg_color => '#FFEB9C',
|
3321
|
+
# :color => '#9C6500'
|
3322
|
+
# )
|
3323
|
+
#
|
3324
|
+
# # Green fill with dark green text.
|
3325
|
+
#
|
3326
|
+
# format3 = workbook.add_format(
|
3327
|
+
# :bg_color => '#C6EFCE',
|
3328
|
+
# :color => '#006100'
|
3329
|
+
# )
|
3330
|
+
# == :minimum
|
3331
|
+
#
|
3332
|
+
# The minimum parameter is used to set the lower limiting value when the
|
3333
|
+
# criteria is either 'between' or 'not between':
|
3334
|
+
#
|
3335
|
+
# :validate => 'integer',
|
3336
|
+
# :criteria => 'between',
|
3337
|
+
# :minimum => 1,
|
3338
|
+
# :maximum => 100
|
3339
|
+
# == :maximum
|
3340
|
+
#
|
3341
|
+
# The maximum parameter is used to set the upper limiting value when the
|
3342
|
+
# criteria is either 'between' or 'not between'. See the previous example.
|
3343
|
+
#
|
3344
|
+
# == :type => 'date'
|
3345
|
+
#
|
3346
|
+
# The date type is the same as the cell type and uses the same criteria
|
3347
|
+
# and values. However it allows the value, minimum and maximum properties
|
3348
|
+
# to be specified in the ISO8601 yyyy-mm-ddThh:mm:ss.sss date format which
|
3349
|
+
# is detailed in the write_date_time() method.
|
3350
|
+
#
|
3351
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3352
|
+
# {
|
3353
|
+
# :type => 'date',
|
3354
|
+
# :criteria => 'greater than',
|
3355
|
+
# :value => '2011-01-01T',
|
3356
|
+
# :format => format
|
3357
|
+
# }
|
3358
|
+
# )
|
3359
|
+
# == :type => 'time_period'
|
3360
|
+
#
|
3361
|
+
# The time_period type is used to specify Excel's "Dates Occurring" style
|
3362
|
+
# conditional format.
|
3363
|
+
#
|
3364
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3365
|
+
# {
|
3366
|
+
# :type => 'time_period',
|
3367
|
+
# :criteria => 'yesterday',
|
3368
|
+
# :format => format
|
3369
|
+
# }
|
3370
|
+
# )
|
3371
|
+
# The period is set in the criteria and can have one of the following
|
3372
|
+
# values:
|
3373
|
+
#
|
3374
|
+
# :criteria => 'yesterday',
|
3375
|
+
# :criteria => 'today',
|
3376
|
+
# :criteria => 'last 7 days',
|
3377
|
+
# :criteria => 'last week',
|
3378
|
+
# :criteria => 'this week',
|
3379
|
+
# :criteria => 'next week',
|
3380
|
+
# :criteria => 'last month',
|
3381
|
+
# :criteria => 'this month',
|
3382
|
+
# :criteria => 'next month'
|
3383
|
+
# == :type => 'text'
|
3384
|
+
#
|
3385
|
+
# The text type is used to specify Excel's "Specific Text" style conditional
|
3386
|
+
# format. It is used to do simple string matching using the criteria and
|
3387
|
+
# value parameters:
|
3388
|
+
#
|
3389
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3390
|
+
# {
|
3391
|
+
# :type => 'text',
|
3392
|
+
# :criteria => 'containing',
|
3393
|
+
# :value => 'foo',
|
3394
|
+
# :format => format
|
3395
|
+
# }
|
3396
|
+
# )
|
3397
|
+
# The criteria can have one of the following values:
|
3398
|
+
#
|
3399
|
+
# :criteria => 'containing',
|
3400
|
+
# :criteria => 'not containing',
|
3401
|
+
# :criteria => 'begins with',
|
3402
|
+
# :criteria => 'ends with'
|
3403
|
+
# The value parameter should be a string or single character.
|
3404
|
+
#
|
3405
|
+
# == :type => 'average'
|
3406
|
+
#
|
3407
|
+
# The average type is used to specify Excel's "Average" style conditional
|
3408
|
+
# format.
|
3409
|
+
#
|
3410
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3411
|
+
# {
|
3412
|
+
# :type => 'average',
|
3413
|
+
# :criteria => 'above',
|
3414
|
+
# :format => format
|
3415
|
+
# }
|
3416
|
+
# )
|
3417
|
+
# The type of average for the conditional format range is specified by the
|
3418
|
+
# criteria:
|
3419
|
+
#
|
3420
|
+
# :criteria => 'above',
|
3421
|
+
# :criteria => 'below',
|
3422
|
+
# :criteria => 'equal or above',
|
3423
|
+
# :criteria => 'equal or below',
|
3424
|
+
# :criteria => '1 std dev above',
|
3425
|
+
# :criteria => '1 std dev below',
|
3426
|
+
# :criteria => '2 std dev above',
|
3427
|
+
# :criteria => '2 std dev below',
|
3428
|
+
# :criteria => '3 std dev above',
|
3429
|
+
# :criteria => '3 std dev below'
|
3430
|
+
# == :type => 'duplicate'
|
3431
|
+
#
|
3432
|
+
# The duplicate type is used to highlight duplicate cells in a range:
|
3433
|
+
#
|
3434
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3435
|
+
# {
|
3436
|
+
# :type => 'duplicate',
|
3437
|
+
# :format => format
|
3438
|
+
# }
|
3439
|
+
# )
|
3440
|
+
# == :type => 'unique'
|
3441
|
+
#
|
3442
|
+
# The unique type is used to highlight unique cells in a range:
|
3443
|
+
#
|
3444
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3445
|
+
# {
|
3446
|
+
# :type => 'unique',
|
3447
|
+
# :format => format
|
3448
|
+
# }
|
3449
|
+
# )
|
3450
|
+
# == :type => 'top'
|
3451
|
+
#
|
3452
|
+
# The top type is used to specify the top n values by number or percentage
|
3453
|
+
# in a range:
|
3454
|
+
#
|
3455
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3456
|
+
# {
|
3457
|
+
# :type => 'top',
|
3458
|
+
# :value => 10,
|
3459
|
+
# :format => format
|
3460
|
+
# }
|
3461
|
+
# )
|
3462
|
+
# The criteria can be used to indicate that a percentage condition is
|
3463
|
+
# required:
|
3464
|
+
#
|
3465
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3466
|
+
# {
|
3467
|
+
# :type => 'top',
|
3468
|
+
# :value => 10,
|
3469
|
+
# :criteria => '%',
|
3470
|
+
# :format => format
|
3471
|
+
# }
|
3472
|
+
# )
|
3473
|
+
# == :type => 'bottom'
|
3474
|
+
#
|
3475
|
+
# The bottom type is used to specify the bottom n values by number or
|
3476
|
+
# percentage in a range.
|
3477
|
+
#
|
3478
|
+
# It takes the same parameters as top, see above.
|
3479
|
+
#
|
3480
|
+
# == :type => 'blanks'
|
3481
|
+
#
|
3482
|
+
# The blanks type is used to highlight blank cells in a range:
|
3483
|
+
#
|
3484
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3485
|
+
# {
|
3486
|
+
# :type => 'blanks',
|
3487
|
+
# :format => format
|
3488
|
+
# }
|
3489
|
+
# )
|
3490
|
+
# == :type => 'no_blanks'
|
3491
|
+
#
|
3492
|
+
# The no_blanks type is used to highlight non blank cells in a range:
|
3493
|
+
#
|
3494
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3495
|
+
# {
|
3496
|
+
# :type => 'no_blanks',
|
3497
|
+
# :format => format
|
3498
|
+
# }
|
3499
|
+
# )
|
3500
|
+
# == :type => 'errors'
|
3501
|
+
#
|
3502
|
+
# The errors type is used to highlight error cells in a range:
|
3503
|
+
#
|
3504
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3505
|
+
# {
|
3506
|
+
# :type => 'errors',
|
3507
|
+
# :format => format
|
3508
|
+
# }
|
3509
|
+
# )
|
3510
|
+
# == :type => 'no_errors'
|
3511
|
+
#
|
3512
|
+
# The no_errors type is used to highlight non error cells in a range:
|
3513
|
+
#
|
3514
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3515
|
+
# {
|
3516
|
+
# :type => 'no_errors',
|
3517
|
+
# :format => format
|
3518
|
+
# }
|
3519
|
+
# )
|
3520
|
+
# == :type => '2_color_scale'
|
3521
|
+
#
|
3522
|
+
# The 2_color_scale type is used to specify Excel's "2 Color Scale" style
|
3523
|
+
# conditional format.
|
3524
|
+
#
|
3525
|
+
# worksheet.conditional_formatting( 'A1:A12',
|
3526
|
+
# {
|
3527
|
+
# :type => '2_color_scale'
|
3528
|
+
# }
|
3529
|
+
# )
|
3530
|
+
# At the moment only the default colors and properties can be used. These
|
3531
|
+
# will be extended in time.
|
3532
|
+
#
|
3533
|
+
# == :type => '3_color_scale'
|
3534
|
+
#
|
3535
|
+
# The 3_color_scale type is used to specify Excel's "3 Color Scale" style
|
3536
|
+
# conditional format.
|
3537
|
+
#
|
3538
|
+
# worksheet.conditional_formatting( 'A1:A12',
|
3539
|
+
# {
|
3540
|
+
# :type => '3_color_scale'
|
3541
|
+
# }
|
3542
|
+
# )
|
3543
|
+
# At the moment only the default colors and properties can be used.
|
3544
|
+
# These will be extended in time.
|
3545
|
+
#
|
3546
|
+
# == :type => 'data_bar'
|
3547
|
+
#
|
3548
|
+
# The data_bar type is used to specify Excel's "Data Bar" style conditional
|
3549
|
+
# format.
|
3550
|
+
#
|
3551
|
+
# worksheet.conditional_formatting( 'A1:A12',
|
3552
|
+
# {
|
3553
|
+
# :type => 'data_bar',
|
3554
|
+
# }
|
3555
|
+
# )
|
3556
|
+
# At the moment only the default colors and properties can be used. These
|
3557
|
+
# will be extended in time.
|
3558
|
+
#
|
3559
|
+
# == :type => 'formula'
|
3560
|
+
#
|
3561
|
+
# The formula type is used to specify a conditional format based on
|
3562
|
+
# a user defined formula:
|
3563
|
+
#
|
3564
|
+
# worksheet.conditional_formatting( 'A1:A4',
|
3565
|
+
# {
|
3566
|
+
# :type => 'formula',
|
3567
|
+
# :criteria => '=$A$1 > 5',
|
3568
|
+
# :format => format
|
3569
|
+
# }
|
3570
|
+
# )
|
3571
|
+
# The formula is specified in the criteria.
|
3572
|
+
#
|
3573
|
+
# == :min_type, :mid_type, :max_type
|
3574
|
+
#
|
3575
|
+
# The min_type and max_type properties are available when the conditional
|
3576
|
+
# formatting type is 2_color_scale, 3_color_scale or data_bar. The mid_type
|
3577
|
+
# is available for 3_color_scale. The properties are used as follows:
|
3578
|
+
#
|
3579
|
+
# worksheet.conditional_formatting( 'A1:A12',
|
3580
|
+
# {
|
3581
|
+
# :type => '2_color_scale',
|
3582
|
+
# :min_type => 'percent',
|
3583
|
+
# :max_type => 'percent'
|
3584
|
+
# }
|
3585
|
+
# )
|
3586
|
+
# The available min/mid/max types are:
|
3587
|
+
#
|
3588
|
+
# 'num'
|
3589
|
+
# 'percent'
|
3590
|
+
# 'percentile'
|
3591
|
+
# 'formula'
|
3592
|
+
# == :min_value, :mid_value, :max_value
|
3593
|
+
#
|
3594
|
+
# The min_value and max_value properties are available when the conditional
|
3595
|
+
# formatting type is 2_color_scale, 3_color_scale or data_bar. The mid_value
|
3596
|
+
# is available for 3_color_scale. The properties are used as follows:
|
3597
|
+
#
|
3598
|
+
# worksheet.conditional_formatting( 'A1:A12',
|
3599
|
+
# {
|
3600
|
+
# :type => '2_color_scale',
|
3601
|
+
# :min_value => 10,
|
3602
|
+
# :max_value => 90
|
3603
|
+
# }
|
3604
|
+
# )
|
3605
|
+
# == :min_color, :mid_color, :max_color, :bar_color
|
3606
|
+
#
|
3607
|
+
# The min_color and max_color properties are available when the conditional
|
3608
|
+
# formatting type is 2_color_scale, 3_color_scale or data_bar. The mid_color
|
3609
|
+
# is available for 3_color_scale. The properties are used as follows:
|
3610
|
+
#
|
3611
|
+
# worksheet.conditional_formatting( 'A1:A12',
|
3612
|
+
# {
|
3613
|
+
# ;type => '2_color_scale',
|
3614
|
+
# :min_color => "#C5D9F1",
|
3615
|
+
# :max_color => "#538ED5"
|
3616
|
+
# }
|
3617
|
+
# )
|
3618
|
+
# The color can be specifies as an Excel::Writer::XLSX color index or,
|
3619
|
+
# more usefully, as a HTML style RGB hex number, as shown above.
|
3620
|
+
#
|
3621
|
+
# == Conditional Formatting Examples
|
3622
|
+
#
|
3623
|
+
# === Example 1. Highlight cells greater than an integer value.
|
3624
|
+
#
|
3625
|
+
# worksheet.conditional_formatting( 'A1:F10',
|
3626
|
+
# {
|
3627
|
+
# :type => 'cell',
|
3628
|
+
# :criteria => 'greater than',
|
3629
|
+
# :value => 5,
|
3630
|
+
# :format => format
|
3631
|
+
# }
|
3632
|
+
# )
|
3633
|
+
# === Example 2. Highlight cells greater than a value in a reference cell.
|
3634
|
+
#
|
3635
|
+
# worksheet.conditional_formatting( 'A1:F10',
|
3636
|
+
# {
|
3637
|
+
# :type => 'cell',
|
3638
|
+
# :criteria => 'greater than',
|
3639
|
+
# :value => '$H$1',
|
3640
|
+
# :format => format
|
3641
|
+
# }
|
3642
|
+
# )
|
3643
|
+
# === Example 3. Highlight cells greater than a certain date:
|
3644
|
+
#
|
3645
|
+
# worksheet.conditional_formatting( 'A1:F10',
|
3646
|
+
# {
|
3647
|
+
# :type => 'date',
|
3648
|
+
# :criteria => 'greater than',
|
3649
|
+
# :value => '2011-01-01T',
|
3650
|
+
# :format => format
|
3651
|
+
# }
|
3652
|
+
# )
|
3653
|
+
# === Example 4. Highlight cells with a date in the last seven days:
|
3654
|
+
#
|
3655
|
+
# worksheet.conditional_formatting( 'A1:F10',
|
3656
|
+
# {
|
3657
|
+
# :type => 'time_period',
|
3658
|
+
# :criteria => 'last 7 days',
|
3659
|
+
# :format => format
|
3660
|
+
# }
|
3661
|
+
# )
|
3662
|
+
# === Example 5. Highlight cells with strings starting with the letter b:
|
3663
|
+
#
|
3664
|
+
# worksheet.conditional_formatting( 'A1:F10',
|
3665
|
+
# {
|
3666
|
+
# :type => 'text',
|
3667
|
+
# :criteria => 'begins with',
|
3668
|
+
# :value => 'b',
|
3669
|
+
# :format => format
|
3670
|
+
# }
|
3671
|
+
# )
|
3672
|
+
# === Example 6. Highlight cells that are 1 std deviation above the average for the range:
|
3673
|
+
#
|
3674
|
+
# worksheet.conditional_formatting( 'A1:F10',
|
3675
|
+
# {
|
3676
|
+
# :type => 'average',
|
3677
|
+
# :format => format
|
3678
|
+
# }
|
3679
|
+
# )
|
3680
|
+
# === Example 7. Highlight duplicate cells in a range:
|
3681
|
+
#
|
3682
|
+
# worksheet.conditional_formatting( 'A1:F10',
|
3683
|
+
# {
|
3684
|
+
# :type => 'duplicate',
|
3685
|
+
# :format => format
|
3686
|
+
# }
|
3687
|
+
# )
|
3688
|
+
# === Example 8. Highlight unique cells in a range.
|
3689
|
+
#
|
3690
|
+
# worksheet.conditional_formatting( 'A1:F10',
|
3691
|
+
# {
|
3692
|
+
# :type => 'unique',
|
3693
|
+
# :format => format
|
3694
|
+
# }
|
3695
|
+
# )
|
3696
|
+
# === Example 9. Highlight the top 10 cells.
|
3245
3697
|
#
|
3246
|
-
#
|
3698
|
+
# worksheet.conditional_formatting( 'A1:F10',
|
3699
|
+
# {
|
3700
|
+
# :type => 'top',
|
3701
|
+
# :value => 10,
|
3702
|
+
# :format => format
|
3703
|
+
# }
|
3704
|
+
# )
|
3705
|
+
# === Example 10. Highlight blank cells.
|
3706
|
+
#
|
3707
|
+
# worksheet.conditional_formatting( 'A1:F10',
|
3708
|
+
# {
|
3709
|
+
# :type => 'blanks',
|
3710
|
+
# :format => format
|
3711
|
+
# }
|
3712
|
+
# )
|
3713
|
+
# See also the conditional_format.rb example program in EXAMPLES.
|
3247
3714
|
#
|
3248
3715
|
def conditional_formatting(*args)
|
3249
|
-
|
3250
|
-
|
3251
|
-
|
3252
|
-
user_range = args[0].gsub(/\s*,\s*/, ' ').gsub(/\$/, '') if args[0] =~ /,/
|
3253
|
-
end
|
3254
|
-
row1, col1, row2, col2, param = row_col_notation(args)
|
3255
|
-
if row2.respond_to?(:keys)
|
3256
|
-
param = row2
|
3257
|
-
row2, col2 = row1, col1
|
3258
|
-
end
|
3259
|
-
raise WriteXLSXInsufficientArgumentError if [row1, col1, row2, col2, param].include?(nil)
|
3260
|
-
|
3261
|
-
# Check that row and col are valid without storing the values.
|
3262
|
-
check_dimensions(row1, col1)
|
3263
|
-
check_dimensions(row2, col2)
|
3264
|
-
check_conditional_formatting_parameters(param)
|
3265
|
-
|
3266
|
-
# Swap last row/col for first row/col as necessary
|
3267
|
-
row1, row2 = row2, row1 if row1 > row2
|
3268
|
-
col1, col2 = col2, col1 if col1 > col2
|
3269
|
-
|
3270
|
-
# If the first and last cell are the same write a single cell.
|
3271
|
-
if row1 == row2 && col1 == col2
|
3272
|
-
range = xl_rowcol_to_cell(row1, col1)
|
3273
|
-
start_cell = range
|
3274
|
-
else
|
3275
|
-
range = xl_range(row1, row2, col1, col2)
|
3276
|
-
start_cell = xl_rowcol_to_cell(row1, col1)
|
3277
|
-
end
|
3278
|
-
|
3279
|
-
# Override with user defined multiple range if provided.
|
3280
|
-
range = user_range if user_range
|
3281
|
-
|
3282
|
-
param[:format] = param[:format].get_dxf_index if param[:format]
|
3283
|
-
param[:priority] = @dxf_priority
|
3284
|
-
@dxf_priority += 1
|
3285
|
-
|
3286
|
-
# Special handling of text criteria.
|
3287
|
-
if param[:type] == 'text'
|
3288
|
-
case param[:criteria]
|
3289
|
-
when 'containsText'
|
3290
|
-
param[:type] = 'containsText';
|
3291
|
-
param[:formula] = %Q!NOT(ISERROR(SEARCH("#{param[:value]}",#{start_cell})))!
|
3292
|
-
when 'notContains'
|
3293
|
-
param[:type] = 'notContainsText';
|
3294
|
-
param[:formula] = %Q!ISERROR(SEARCH("#{param[:value]}",#{start_cell}))!
|
3295
|
-
when 'beginsWith'
|
3296
|
-
param[:type] = 'beginsWith'
|
3297
|
-
param[:formula] =
|
3298
|
-
%Q!LEFT(#{start_cell},#{param[:value].size})="#{param[:value]}"!
|
3299
|
-
when 'endsWith'
|
3300
|
-
param[:type] = 'endsWith'
|
3301
|
-
param[:formula] =
|
3302
|
-
%Q!RIGHT(#{start_cell},#{param[:value].size})="#{param[:value]}"!
|
3303
|
-
else
|
3304
|
-
raise "Invalid text criteria '#{param[:criteria]} in conditional_formatting()"
|
3305
|
-
end
|
3306
|
-
end
|
3307
|
-
|
3308
|
-
# Special handling of time time_period criteria.
|
3309
|
-
if param[:type] == 'timePeriod'
|
3310
|
-
case param[:criteria]
|
3311
|
-
when 'yesterday'
|
3312
|
-
param[:formula] = "FLOOR(#{start_cell},1)=TODAY()-1"
|
3313
|
-
when 'today'
|
3314
|
-
param[:formula] = "FLOOR(#{start_cell},1)=TODAY()"
|
3315
|
-
when 'tomorrow'
|
3316
|
-
param[:formula] = "FLOOR(#{start_cell},1)=TODAY()+1"
|
3317
|
-
when 'last7Days'
|
3318
|
-
param[:formula] =
|
3319
|
-
"AND(TODAY()-FLOOR(#{start_cell},1)<=6,FLOOR(#{start_cell},1)<=TODAY())"
|
3320
|
-
when 'lastWeek'
|
3321
|
-
param[:formula] =
|
3322
|
-
"AND(TODAY()-ROUNDDOWN(#{start_cell},0)>=(WEEKDAY(TODAY())),TODAY()-ROUNDDOWN(#{start_cell},0)<(WEEKDAY(TODAY())+7))"
|
3323
|
-
when 'thisWeek'
|
3324
|
-
param[:formula] =
|
3325
|
-
"AND(TODAY()-ROUNDDOWN(#{start_cell},0)<=WEEKDAY(TODAY())-1,ROUNDDOWN(#{start_cell},0)-TODAY()<=7-WEEKDAY(TODAY()))"
|
3326
|
-
when 'nextWeek'
|
3327
|
-
param[:formula] =
|
3328
|
-
"AND(ROUNDDOWN(#{start_cell},0)-TODAY()>(7-WEEKDAY(TODAY())),ROUNDDOWN(#{start_cell},0)-TODAY()<(15-WEEKDAY(TODAY())))"
|
3329
|
-
when 'lastMonth'
|
3330
|
-
param[:formula] =
|
3331
|
-
"AND(MONTH(#{start_cell})=MONTH(TODAY())-1,OR(YEAR(#{start_cell})=YEAR(TODAY()),AND(MONTH(#{start_cell})=1,YEAR(A1)=YEAR(TODAY())-1)))"
|
3332
|
-
when 'thisMonth'
|
3333
|
-
param[:formula] =
|
3334
|
-
"AND(MONTH(#{start_cell})=MONTH(TODAY()),YEAR(#{start_cell})=YEAR(TODAY()))"
|
3335
|
-
when 'nextMonth'
|
3336
|
-
param[:formula] =
|
3337
|
-
"AND(MONTH(#{start_cell})=MONTH(TODAY())+1,OR(YEAR(#{start_cell})=YEAR(TODAY()),AND(MONTH(#{start_cell})=12,YEAR(#{start_cell})=YEAR(TODAY())+1)))"
|
3338
|
-
else
|
3339
|
-
raise "Invalid time_period criteria '#{param[:criteria]}' in conditional_formatting()"
|
3340
|
-
end
|
3341
|
-
end
|
3342
|
-
|
3343
|
-
# Special handling of blanks/error types.
|
3344
|
-
case param[:type]
|
3345
|
-
when 'containsBlanks'
|
3346
|
-
param[:formula] = "LEN(TRIM(#{start_cell}))=0"
|
3347
|
-
when 'notContainsBlanks'
|
3348
|
-
param[:formula] = "LEN(TRIM(#{start_cell}))>0"
|
3349
|
-
when 'containsErrors'
|
3350
|
-
param[:formula] = "ISERROR(#{start_cell})"
|
3351
|
-
when 'notContainsErrors'
|
3352
|
-
param[:formula] = "NOT(ISERROR(#{start_cell}))"
|
3353
|
-
when '2_color_scale'
|
3354
|
-
param[:type] = 'colorScale'
|
3355
|
-
|
3356
|
-
# Color scales don't use any additional formatting.
|
3357
|
-
param[:format] = nil
|
3358
|
-
|
3359
|
-
# Turn off 3 color parameters.
|
3360
|
-
param[:mid_type] = nil
|
3361
|
-
param[:mid_color] = nil
|
3362
|
-
|
3363
|
-
param[:min_type] ||= 'min'
|
3364
|
-
param[:max_type] ||= 'max'
|
3365
|
-
param[:min_value] ||= 0
|
3366
|
-
param[:max_value] ||= 0
|
3367
|
-
param[:min_color] ||= '#FF7128'
|
3368
|
-
param[:max_color] ||= '#FFEF9C'
|
3369
|
-
|
3370
|
-
param[:max_color] = get_palette_color( param[:max_color] )
|
3371
|
-
param[:min_color] = get_palette_color( param[:min_color] )
|
3372
|
-
when '3_color_scale'
|
3373
|
-
param[:type] = 'colorScale'
|
3374
|
-
|
3375
|
-
# Color scales don't use any additional formatting.
|
3376
|
-
param[:format] = nil
|
3377
|
-
|
3378
|
-
param[:min_type] ||= 'min'
|
3379
|
-
param[:mid_type] ||= 'percentile'
|
3380
|
-
param[:max_type] ||= 'max'
|
3381
|
-
param[:min_value] ||= 0
|
3382
|
-
param[:mid_value] ||= 50
|
3383
|
-
param[:max_value] ||= 0
|
3384
|
-
param[:min_color] ||= '#F8696B'
|
3385
|
-
param[:mid_color] ||= '#FFEB84'
|
3386
|
-
param[:max_color] ||= '#63BE7B'
|
3387
|
-
|
3388
|
-
param[:max_color] = get_palette_color(param[:max_color])
|
3389
|
-
param[:mid_color] = get_palette_color(param[:mid_color])
|
3390
|
-
param[:min_color] = get_palette_color(param[:min_color])
|
3391
|
-
when 'dataBar'
|
3392
|
-
# Color scales don't use any additional formatting.
|
3393
|
-
param[:format] = nil
|
3394
|
-
|
3395
|
-
param[:min_type] ||= 'min'
|
3396
|
-
param[:max_type] ||= 'max'
|
3397
|
-
param[:min_value] ||= 0
|
3398
|
-
param[:max_value] ||= 0
|
3399
|
-
param[:bar_color] ||= '#638EC6'
|
3400
|
-
|
3401
|
-
param[:bar_color] = get_palette_color(param[:bar_color])
|
3402
|
-
end
|
3403
|
-
|
3404
|
-
# Store the validation information until we close the worksheet.
|
3405
|
-
@cond_formats[range] ||= []
|
3406
|
-
@cond_formats[range] << param
|
3716
|
+
cond_format = Package::ConditionalFormat.factory(self, *args)
|
3717
|
+
@cond_formats[cond_format.range] ||= []
|
3718
|
+
@cond_formats[cond_format.range] << cond_format
|
3407
3719
|
end
|
3408
3720
|
|
3409
3721
|
#
|
@@ -3420,218 +3732,37 @@ module Writexlsx
|
|
3420
3732
|
# See also the tables.rb program in the examples directory of the distro
|
3421
3733
|
#
|
3422
3734
|
def add_table(*args)
|
3423
|
-
col_formats = []
|
3424
|
-
=begin
|
3425
|
-
# We would need to order the write statements very carefully within this
|
3426
|
-
# function to support optimisation mode. Disable add_table() when it is
|
3427
|
-
# on for now.
|
3428
|
-
if @optimization
|
3429
|
-
carp "add_table() isn't supported when set_optimization() is on"
|
3430
|
-
return -1
|
3431
|
-
end
|
3432
|
-
=end
|
3433
|
-
# Check for a cell reference in A1 notation and substitute row and column
|
3434
|
-
row1, col1, row2, col2, param = row_col_notation(args)
|
3435
|
-
|
3436
|
-
# Check for a valid number of args.
|
3437
|
-
raise "Not enough parameters to add_table()" if [row1, col1, row2, col2].include?(nil)
|
3438
|
-
|
3439
|
-
# Check that row and col are valid without storing the values.
|
3440
|
-
check_dimensions_and_update_max_min_values(row1, col1, 1, 1)
|
3441
|
-
check_dimensions_and_update_max_min_values(row2, col2, 1, 1)
|
3442
|
-
|
3443
|
-
# The final hashref contains the validation parameters.
|
3444
|
-
param ||= {}
|
3445
|
-
|
3446
|
-
check_parameter(param, valid_table_parameter, 'add_table')
|
3447
|
-
|
3448
3735
|
# Table count is a member of Workbook, global to all Worksheet.
|
3449
3736
|
@workbook.table_count += 1
|
3450
|
-
table =
|
3451
|
-
table[:_columns] = []
|
3452
|
-
table[:id] = @workbook.table_count
|
3453
|
-
|
3454
|
-
# Turn on Excel's defaults.
|
3455
|
-
param[:banded_rows] ||= 1
|
3456
|
-
param[:header_row] ||= 1
|
3457
|
-
param[:autofilter] ||= 1
|
3458
|
-
|
3459
|
-
# Set the table options.
|
3460
|
-
table[:_show_first_col] = ptrue?(param[:first_column]) ? 1 : 0
|
3461
|
-
table[:_show_last_col] = ptrue?(param[:last_column]) ? 1 : 0
|
3462
|
-
table[:_show_row_stripes] = ptrue?(param[:banded_rows]) ? 1 : 0
|
3463
|
-
table[:_show_col_stripes] = ptrue?(param[:banded_columns]) ? 1 : 0
|
3464
|
-
table[:_header_row_count] = ptrue?(param[:header_row]) ? 1 : 0
|
3465
|
-
table[:_totals_row_shown] = ptrue?(param[:total_row]) ? 1 : 0
|
3466
|
-
|
3467
|
-
# Set the table name.
|
3468
|
-
if param[:name]
|
3469
|
-
table[:_name] = param[:name]
|
3470
|
-
else
|
3471
|
-
# Set a default name.
|
3472
|
-
table[:_name] = "Table#{table[:id]}"
|
3473
|
-
end
|
3474
|
-
|
3475
|
-
# Set the table style.
|
3476
|
-
if param[:style]
|
3477
|
-
table[:_style] = param[:style]
|
3478
|
-
# Remove whitespace from style name.
|
3479
|
-
table[:_style].gsub!(/\s/, '')
|
3480
|
-
else
|
3481
|
-
table[:_style] = "TableStyleMedium9"
|
3482
|
-
end
|
3483
|
-
|
3484
|
-
# Swap last row/col for first row/col as necessary.
|
3485
|
-
row1, row2 = row2, row1 if row1 > row2
|
3486
|
-
col1, col2 = col2, col1 if col1 > col2
|
3737
|
+
table = Package::Table.new(self, @workbook.table_count, *args)
|
3487
3738
|
|
3488
|
-
|
3489
|
-
first_data_row = row1
|
3490
|
-
last_data_row = row2
|
3491
|
-
first_data_row += 1 if param[:header_row] != 0
|
3492
|
-
last_data_row -= 1 if param[:total_row]
|
3493
|
-
|
3494
|
-
# Set the table and autofilter ranges.
|
3495
|
-
table[:_range] = xl_range(row1, row2, col1, col2)
|
3496
|
-
table[:_a_range] = xl_range(row1, last_data_row, col1, col2)
|
3497
|
-
|
3498
|
-
# If the header row if off the default is to turn autofilter off.
|
3499
|
-
param[:autofilter] = 0 if param[:header_row] == 0
|
3500
|
-
|
3501
|
-
# Set the autofilter range.
|
3502
|
-
if param[:autofilter] && param[:autofilter] != 0
|
3503
|
-
table[:_autofilter] = table[:_a_range]
|
3504
|
-
end
|
3505
|
-
|
3506
|
-
# Add the table columns.
|
3507
|
-
col_id = 1
|
3508
|
-
(col1..col2).each do |col_num|
|
3509
|
-
# Set up the default column data.
|
3510
|
-
col_data = {
|
3511
|
-
:_id => col_id,
|
3512
|
-
:_name => "Column#{col_id}",
|
3513
|
-
:_total_string => '',
|
3514
|
-
:_total_function => '',
|
3515
|
-
:_formula => '',
|
3516
|
-
:_format => nil
|
3517
|
-
}
|
3518
|
-
|
3519
|
-
# Overwrite the defaults with any use defined values.
|
3520
|
-
if param[:columns]
|
3521
|
-
# Check if there are user defined values for this column.
|
3522
|
-
if user_data = param[:columns][col_id - 1]
|
3523
|
-
# Map user defined values to internal values.
|
3524
|
-
if user_data[:header] && !user_data[:header].empty?
|
3525
|
-
col_data[:_name] = user_data[:header]
|
3526
|
-
end
|
3527
|
-
# Handle the column formula.
|
3528
|
-
if user_data[:formula]
|
3529
|
-
formula = user_data[:formula]
|
3530
|
-
# Remove the leading = from formula.
|
3531
|
-
formula.sub!(/^=/, '')
|
3532
|
-
# Covert Excel 2010 "@" ref to 2007 "#This Row".
|
3533
|
-
formula.gsub!(/@/,'[#This Row],')
|
3534
|
-
|
3535
|
-
col_data[:_formula] = formula
|
3536
|
-
|
3537
|
-
(first_data_row..last_data_row).each do |row|
|
3538
|
-
write_formula(row, col_num, formula, user_data[:format])
|
3539
|
-
end
|
3540
|
-
end
|
3541
|
-
|
3542
|
-
# Handle the function for the total row.
|
3543
|
-
if user_data[:total_function]
|
3544
|
-
function = user_data[:total_function]
|
3545
|
-
|
3546
|
-
# Massage the function name.
|
3547
|
-
function = function.downcase
|
3548
|
-
function.gsub!(/_/, '')
|
3549
|
-
function.gsub!(/\s/,'')
|
3550
|
-
|
3551
|
-
function = 'countNums' if function == 'countnums'
|
3552
|
-
function = 'stdDev' if function == 'stddev'
|
3553
|
-
|
3554
|
-
col_data[:_total_function] = function
|
3555
|
-
|
3556
|
-
formula = table_function_to_formula(function, col_data[:_name])
|
3557
|
-
write_formula(row2, col_num, formula, user_data[:format])
|
3558
|
-
elsif user_data[:total_string]
|
3559
|
-
# Total label only (not a function).
|
3560
|
-
total_string = user_data[:total_string]
|
3561
|
-
col_data[:_total_string] = total_string
|
3562
|
-
|
3563
|
-
write_string(row2, col_num, total_string, user_data[:format])
|
3564
|
-
end
|
3565
|
-
|
3566
|
-
# Get the dxf format index.
|
3567
|
-
if user_data[:format]
|
3568
|
-
col_data[:_format] = user_data[:format].get_dxf_index
|
3569
|
-
end
|
3570
|
-
|
3571
|
-
# Store the column format for writing the cell data.
|
3572
|
-
# It doesn't matter if it is undefined.
|
3573
|
-
col_formats[col_id - 1] = user_data[:format]
|
3574
|
-
end
|
3575
|
-
end
|
3576
|
-
|
3577
|
-
# Store the column data.
|
3578
|
-
table[:_columns] << col_data
|
3579
|
-
|
3580
|
-
# Write the column headers to the worksheet.
|
3581
|
-
if param[:header_row] != 0
|
3582
|
-
write_string(row1, col_num, col_data[:_name])
|
3583
|
-
end
|
3584
|
-
|
3585
|
-
col_id += 1
|
3586
|
-
end # Table columns.
|
3587
|
-
|
3588
|
-
# Write the cell data if supplied.
|
3589
|
-
if data = param[:data]
|
3590
|
-
|
3591
|
-
i = 0 # For indexing the row data.
|
3592
|
-
(first_data_row..last_data_row).each do |row|
|
3593
|
-
next unless data[i]
|
3594
|
-
|
3595
|
-
j = 0 # For indexing the col data.
|
3596
|
-
(col1..col2).each do |col|
|
3597
|
-
token = data[i][j]
|
3598
|
-
write(row, col, token, col_formats[j]) if token
|
3599
|
-
j += 1
|
3600
|
-
end
|
3601
|
-
i += 1
|
3602
|
-
end
|
3603
|
-
end
|
3604
|
-
|
3605
|
-
# Store the table data.
|
3739
|
+
@external_table_links << ['/table', "../tables/table#{table.id}.xml"]
|
3606
3740
|
@tables << table
|
3607
|
-
|
3608
|
-
# Store the link used for the rels file.
|
3609
|
-
@external_table_links << ['/table', "../tables/table#{table[:id]}.xml"]
|
3610
|
-
|
3611
|
-
return table
|
3741
|
+
table
|
3612
3742
|
end
|
3613
3743
|
|
3614
|
-
# List of valid input parameters.
|
3615
|
-
def valid_table_parameter
|
3616
|
-
[
|
3617
|
-
:autofilter,
|
3618
|
-
:banded_columns,
|
3619
|
-
:banded_rows,
|
3620
|
-
:columns,
|
3621
|
-
:data,
|
3622
|
-
:first_column,
|
3623
|
-
:header_row,
|
3624
|
-
:last_column,
|
3625
|
-
:name,
|
3626
|
-
:style,
|
3627
|
-
:total_row
|
3628
|
-
]
|
3629
|
-
end
|
3630
|
-
private :valid_table_parameter
|
3631
|
-
|
3632
3744
|
#
|
3633
3745
|
# Add sparklines to the worksheet.
|
3634
3746
|
#
|
3747
|
+
# The add_sparkline worksheet method is used to add sparklines to a cell or a range of cells.
|
3748
|
+
#
|
3749
|
+
# worksheet.add_sparkline(
|
3750
|
+
# {
|
3751
|
+
# :location => 'F2',
|
3752
|
+
# :range => 'Sheet1!A2:E2',
|
3753
|
+
# :type => 'column',
|
3754
|
+
# :style => 12
|
3755
|
+
# }
|
3756
|
+
# )
|
3757
|
+
#
|
3758
|
+
# See also the sparklines1.rb and sparklines2.rb example programs in the examples directory of the distro.
|
3759
|
+
#
|
3760
|
+
# Note: Sparklines are a feature of Excel 2010+ only.
|
3761
|
+
# You can write them to an XLSX file that can be read by Excel 2007 but they won't be displayed.
|
3762
|
+
#
|
3763
|
+
# Sparklines are a feature of Excel 2010+ which allows you to add small charts to worksheet cells.
|
3764
|
+
# These are useful for showing visual trends in data in a compact format.
|
3765
|
+
#
|
3635
3766
|
def add_sparkline(param)
|
3636
3767
|
sparkline = {}
|
3637
3768
|
|
@@ -4840,29 +4971,31 @@ module Writexlsx
|
|
4840
4971
|
@writer.data_element('f', formula, attributes)
|
4841
4972
|
end
|
4842
4973
|
|
4843
|
-
|
4974
|
+
def date_1904? #:nodoc:
|
4975
|
+
@workbook.date_1904?
|
4976
|
+
end
|
4844
4977
|
|
4845
4978
|
#
|
4846
|
-
# Convert
|
4979
|
+
# Convert from an Excel internal colour index to a XML style #RRGGBB index
|
4980
|
+
# based on the default or user defined values in the Workbook palette.
|
4847
4981
|
#
|
4848
|
-
def
|
4849
|
-
|
4850
|
-
|
4851
|
-
:countNums => 102,
|
4852
|
-
:count => 103,
|
4853
|
-
:max => 104,
|
4854
|
-
:min => 105,
|
4855
|
-
:stdDev => 107,
|
4856
|
-
:sum => 109,
|
4857
|
-
:var => 110
|
4858
|
-
}
|
4859
|
-
|
4860
|
-
unless func_num = subtotals[function.to_sym]
|
4861
|
-
raise "Unsupported function '#{function}' in add_table()"
|
4982
|
+
def get_palette_color(index) #:nodoc:
|
4983
|
+
if index =~ /^#([0-9A-F]{6})$/i
|
4984
|
+
return "FF#{$~[1]}"
|
4862
4985
|
end
|
4863
|
-
|
4986
|
+
|
4987
|
+
# Adjust the colour index.
|
4988
|
+
index -= 8
|
4989
|
+
|
4990
|
+
# Palette is passed in from the Workbook class.
|
4991
|
+
rgb = @workbook.palette[index]
|
4992
|
+
|
4993
|
+
# TODO Add the alpha part to the RGB.
|
4994
|
+
sprintf("FF%02X%02X%02X", *rgb[0, 3])
|
4864
4995
|
end
|
4865
4996
|
|
4997
|
+
private
|
4998
|
+
|
4866
4999
|
def check_for_valid_input_params(param)
|
4867
5000
|
check_parameter(param, valid_validation_parameter, 'data_validation')
|
4868
5001
|
|
@@ -4999,139 +5132,6 @@ module Writexlsx
|
|
4999
5132
|
[fragments, length]
|
5000
5133
|
end
|
5001
5134
|
|
5002
|
-
def check_conditional_formatting_parameters(param) # :nodoc:
|
5003
|
-
# Check for valid input parameters.
|
5004
|
-
unless (param.keys.uniq - valid_parameter_for_conditional_formatting).empty? &&
|
5005
|
-
param.has_key?(:type) &&
|
5006
|
-
valid_type_for_conditional_formatting.has_key?(param[:type].downcase)
|
5007
|
-
raise WriteXLSXOptionParameterError, "Invalid type : #{param[:type]}"
|
5008
|
-
end
|
5009
|
-
|
5010
|
-
param[:direction] = 'bottom' if param[:type] == 'bottom'
|
5011
|
-
param[:type] = valid_type_for_conditional_formatting[param[:type].downcase]
|
5012
|
-
|
5013
|
-
# Check for valid criteria types.
|
5014
|
-
if param.has_key?(:criteria) && valid_criteria_type_for_conditional_formatting.has_key?(param[:criteria].downcase)
|
5015
|
-
param[:criteria] = valid_criteria_type_for_conditional_formatting[param[:criteria].downcase]
|
5016
|
-
end
|
5017
|
-
|
5018
|
-
# Convert date/times value if required.
|
5019
|
-
if %w[date time cellIs].include?(param[:type])
|
5020
|
-
param[:type] = 'cellIs'
|
5021
|
-
|
5022
|
-
param[:value] = convert_date_time_if_required(param[:value])
|
5023
|
-
param[:minimum] = convert_date_time_if_required(param[:minimum])
|
5024
|
-
param[:maximum] = convert_date_time_if_required(param[:maximum])
|
5025
|
-
end
|
5026
|
-
|
5027
|
-
# 'Between' and 'Not between' criteria require 2 values.
|
5028
|
-
if param[:criteria] == 'between' || param[:criteria] == 'notBetween'
|
5029
|
-
unless param.has_key?(:minimum) || param.has_key?(:maximum)
|
5030
|
-
raise WriteXLSXOptionParameterError, "Invalid criteria : #{param[:criteria]}"
|
5031
|
-
end
|
5032
|
-
else
|
5033
|
-
param[:minimum] = nil
|
5034
|
-
param[:maximum] = nil
|
5035
|
-
end
|
5036
|
-
|
5037
|
-
# Convert date/times value if required.
|
5038
|
-
if param[:type] == 'date' || param[:type] == 'time'
|
5039
|
-
unless convert_date_time_value(param, :value) || convert_date_time_value(param, :maximum)
|
5040
|
-
raise WriteXLSXOptionParameterError
|
5041
|
-
end
|
5042
|
-
end
|
5043
|
-
end
|
5044
|
-
|
5045
|
-
def convert_date_time_if_required(val)
|
5046
|
-
if val =~ /T/
|
5047
|
-
date_time = convert_date_time(val)
|
5048
|
-
raise "Invalid date/time value '#{val}' in conditional_formatting()" unless date_time
|
5049
|
-
date_time
|
5050
|
-
else
|
5051
|
-
val
|
5052
|
-
end
|
5053
|
-
end
|
5054
|
-
|
5055
|
-
# List of valid input parameters for conditional_formatting.
|
5056
|
-
def valid_parameter_for_conditional_formatting
|
5057
|
-
[
|
5058
|
-
:type,
|
5059
|
-
:format,
|
5060
|
-
:criteria,
|
5061
|
-
:value,
|
5062
|
-
:minimum,
|
5063
|
-
:maximum,
|
5064
|
-
:min_type,
|
5065
|
-
:mid_type,
|
5066
|
-
:max_type,
|
5067
|
-
:min_value,
|
5068
|
-
:mid_value,
|
5069
|
-
:max_value,
|
5070
|
-
:min_color,
|
5071
|
-
:mid_color,
|
5072
|
-
:max_color,
|
5073
|
-
:bar_color
|
5074
|
-
]
|
5075
|
-
end
|
5076
|
-
|
5077
|
-
# List of valid validation types for conditional_formatting.
|
5078
|
-
def valid_type_for_conditional_formatting
|
5079
|
-
{
|
5080
|
-
'cell' => 'cellIs',
|
5081
|
-
'date' => 'date',
|
5082
|
-
'time' => 'time',
|
5083
|
-
'average' => 'aboveAverage',
|
5084
|
-
'duplicate' => 'duplicateValues',
|
5085
|
-
'unique' => 'uniqueValues',
|
5086
|
-
'top' => 'top10',
|
5087
|
-
'bottom' => 'top10',
|
5088
|
-
'text' => 'text',
|
5089
|
-
'time_period' => 'timePeriod',
|
5090
|
-
'blanks' => 'containsBlanks',
|
5091
|
-
'no_blanks' => 'notContainsBlanks',
|
5092
|
-
'errors' => 'containsErrors',
|
5093
|
-
'no_errors' => 'notContainsErrors',
|
5094
|
-
'2_color_scale' => '2_color_scale',
|
5095
|
-
'3_color_scale' => '3_color_scale',
|
5096
|
-
'data_bar' => 'dataBar',
|
5097
|
-
'formula' => 'expression'
|
5098
|
-
}
|
5099
|
-
end
|
5100
|
-
|
5101
|
-
# List of valid criteria types for conditional_formatting.
|
5102
|
-
def valid_criteria_type_for_conditional_formatting
|
5103
|
-
{
|
5104
|
-
'between' => 'between',
|
5105
|
-
'not between' => 'notBetween',
|
5106
|
-
'equal to' => 'equal',
|
5107
|
-
'=' => 'equal',
|
5108
|
-
'==' => 'equal',
|
5109
|
-
'not equal to' => 'notEqual',
|
5110
|
-
'!=' => 'notEqual',
|
5111
|
-
'<>' => 'notEqual',
|
5112
|
-
'greater than' => 'greaterThan',
|
5113
|
-
'>' => 'greaterThan',
|
5114
|
-
'less than' => 'lessThan',
|
5115
|
-
'<' => 'lessThan',
|
5116
|
-
'greater than or equal to' => 'greaterThanOrEqual',
|
5117
|
-
'>=' => 'greaterThanOrEqual',
|
5118
|
-
'less than or equal to' => 'lessThanOrEqual',
|
5119
|
-
'<=' => 'lessThanOrEqual',
|
5120
|
-
'containing' => 'containsText',
|
5121
|
-
'not containing' => 'notContains',
|
5122
|
-
'begins with' => 'beginsWith',
|
5123
|
-
'ends with' => 'endsWith',
|
5124
|
-
'yesterday' => 'yesterday',
|
5125
|
-
'today' => 'today',
|
5126
|
-
'last 7 days' => 'last7Days',
|
5127
|
-
'last week' => 'lastWeek',
|
5128
|
-
'this week' => 'thisWeek',
|
5129
|
-
'next week' => 'nextWeek',
|
5130
|
-
'last month' => 'lastMonth',
|
5131
|
-
'this month' => 'thisMonth',
|
5132
|
-
'next month' => 'nextMonth'
|
5133
|
-
}
|
5134
|
-
end
|
5135
5135
|
# Pad out the rest of the area with formatted blank cells.
|
5136
5136
|
def write_formatted_blank_to_area(row_first, row_last, col_first, col_last, format)
|
5137
5137
|
(row_first .. row_last).each do |row|
|
@@ -5301,25 +5301,6 @@ module Writexlsx
|
|
5301
5301
|
[operator, token]
|
5302
5302
|
end
|
5303
5303
|
|
5304
|
-
#
|
5305
|
-
# Convert from an Excel internal colour index to a XML style #RRGGBB index
|
5306
|
-
# based on the default or user defined values in the Workbook palette.
|
5307
|
-
#
|
5308
|
-
def get_palette_color(index) #:nodoc:
|
5309
|
-
if index =~ /^#([0-9A-F]{6})$/i
|
5310
|
-
return "FF#{$~[1]}"
|
5311
|
-
end
|
5312
|
-
|
5313
|
-
# Adjust the colour index.
|
5314
|
-
index -= 8
|
5315
|
-
|
5316
|
-
# Palette is passed in from the Workbook class.
|
5317
|
-
rgb = @workbook.palette[index]
|
5318
|
-
|
5319
|
-
# TODO Add the alpha part to the RGB.
|
5320
|
-
sprintf("FF%02X%02X%02X", *rgb[0, 3])
|
5321
|
-
end
|
5322
|
-
|
5323
5304
|
#
|
5324
5305
|
# This is an internal method that is used to filter elements of the array of
|
5325
5306
|
# pagebreaks used in the _store_hbreak() and _store_vbreak() methods. It:
|
@@ -6764,15 +6745,6 @@ module Writexlsx
|
|
6764
6745
|
writer.empty_tag('vertAlign', attributes)
|
6765
6746
|
end
|
6766
6747
|
|
6767
|
-
#
|
6768
|
-
# Write the <color> element.
|
6769
|
-
#
|
6770
|
-
def write_color(writer, name, value) #:nodoc:
|
6771
|
-
attributes = [name, value]
|
6772
|
-
|
6773
|
-
writer.empty_tag('color', attributes)
|
6774
|
-
end
|
6775
|
-
|
6776
6748
|
#
|
6777
6749
|
# Write the <tableParts> element.
|
6778
6750
|
#
|
@@ -7313,36 +7285,30 @@ module Writexlsx
|
|
7313
7285
|
# maxAxisType="custom"
|
7314
7286
|
# rightToLeft="1">
|
7315
7287
|
#
|
7316
|
-
def write_sparkline_group(
|
7317
|
-
|
7318
|
-
|
7319
|
-
|
7320
|
-
|
7288
|
+
def write_sparkline_group(sparkline) # :nodoc:
|
7289
|
+
@writer.start_tag(
|
7290
|
+
'x14:sparklineGroup',
|
7291
|
+
attributes_from_sparkline(sparkline)
|
7292
|
+
)
|
7293
|
+
end
|
7321
7294
|
|
7322
|
-
|
7323
|
-
|
7324
|
-
|
7325
|
-
else
|
7326
|
-
a << 'manualMax' << opts[:_max]
|
7327
|
-
opts[:_cust_max] = 'custom'
|
7328
|
-
end
|
7329
|
-
end
|
7295
|
+
def attributes_from_sparkline(opts) # :nodoc:
|
7296
|
+
opts[:_cust_max] = cust_max_min(opts[:_max]) if opts[:_max]
|
7297
|
+
opts[:_cust_min] = cust_max_min(opts[:_min]) if opts[:_min]
|
7330
7298
|
|
7331
|
-
if opts[:
|
7332
|
-
|
7333
|
-
|
7334
|
-
|
7335
|
-
|
7336
|
-
|
7337
|
-
end
|
7338
|
-
end
|
7299
|
+
opts[:_cust_max] = cust_max_min(opts[:_max]) if opts[:_max]
|
7300
|
+
opts[:_cust_min] = cust_max_min(opts[:_min]) if opts[:_min]
|
7301
|
+
|
7302
|
+
a = []
|
7303
|
+
a << 'manualMax' << opts[:_max] if opts[:_max] && opts[:_max] != 'group'
|
7304
|
+
a << 'manualMin' << opts[:_min] if opts[:_min] && opts[:_min] != 'group'
|
7339
7305
|
|
7340
7306
|
# Ignore the default type attribute (line).
|
7341
7307
|
a << 'type' << opts[:_type] if opts[:_type] != 'line'
|
7342
7308
|
|
7343
7309
|
a << 'lineWeight' << opts[:_weight] if opts[:_weight]
|
7344
7310
|
a << 'dateAxis' << 1 if opts[:_date_axis]
|
7345
|
-
a << 'displayEmptyCellsAs' <<
|
7311
|
+
a << 'displayEmptyCellsAs' << opts[:_empty] if ptrue?(opts[:_empty])
|
7346
7312
|
|
7347
7313
|
a << 'markers' << 1 if opts[:_markers]
|
7348
7314
|
a << 'high' << 1 if opts[:_high]
|
@@ -7355,8 +7321,11 @@ module Writexlsx
|
|
7355
7321
|
a << 'minAxisType' << opts[:_cust_min] if opts[:_cust_min]
|
7356
7322
|
a << 'maxAxisType' << opts[:_cust_max] if opts[:_cust_max]
|
7357
7323
|
a << 'rightToLeft' << 1 if opts[:_reverse]
|
7324
|
+
a
|
7325
|
+
end
|
7358
7326
|
|
7359
|
-
|
7327
|
+
def cust_max_min(max_min) # :nodoc:
|
7328
|
+
max_min == 'group' ? 'group' : 'custom'
|
7360
7329
|
end
|
7361
7330
|
|
7362
7331
|
#
|
@@ -7514,153 +7483,23 @@ module Writexlsx
|
|
7514
7483
|
@writer.data_element('formula2', formula)
|
7515
7484
|
end
|
7516
7485
|
|
7517
|
-
# in Perl module : _write_formula()
|
7518
|
-
#
|
7519
|
-
def write_formula_tag(data) #:nodoc:
|
7520
|
-
data = data.sub(/^=/, '') if data.respond_to?(:sub)
|
7521
|
-
@writer.data_element('formula', data)
|
7522
|
-
end
|
7523
|
-
|
7524
|
-
#
|
7525
|
-
# Write the <colorScale> element.
|
7526
|
-
#
|
7527
|
-
def write_color_scale(param)
|
7528
|
-
@writer.tag_elements('colorScale') do
|
7529
|
-
write_cfvo(param[:min_type], param[:min_value])
|
7530
|
-
write_cfvo(param[:mid_type], param[:mid_value]) if param[:mid_type]
|
7531
|
-
write_cfvo(param[:max_type], param[:max_value])
|
7532
|
-
write_color(@writer, 'rgb', param[:min_color])
|
7533
|
-
write_color(@writer, 'rgb', param[:mid_color]) if param[:mid_color]
|
7534
|
-
write_color(@writer, 'rgb', param[:max_color])
|
7535
|
-
end
|
7536
|
-
end
|
7537
|
-
|
7538
|
-
#
|
7539
|
-
# Write the <dataBar> element.
|
7540
|
-
#
|
7541
|
-
def write_data_bar(param)
|
7542
|
-
@writer.tag_elements('dataBar') do
|
7543
|
-
write_cfvo(param[:min_type], param[:min_value])
|
7544
|
-
write_cfvo(param[:max_type], param[:max_value])
|
7545
|
-
|
7546
|
-
write_color(@writer, 'rgb', param[:bar_color])
|
7547
|
-
end
|
7548
|
-
end
|
7549
|
-
|
7550
|
-
#
|
7551
|
-
# Write the <cfvo> element.
|
7552
|
-
#
|
7553
|
-
def write_cfvo(type, val)
|
7554
|
-
attributes = [
|
7555
|
-
'type', type,
|
7556
|
-
'val', val
|
7557
|
-
]
|
7558
|
-
|
7559
|
-
@writer.empty_tag('cfvo', attributes)
|
7560
|
-
end
|
7561
|
-
|
7562
7486
|
#
|
7563
7487
|
# Write the Worksheet conditional formats.
|
7564
7488
|
#
|
7565
|
-
def write_conditional_formats
|
7566
|
-
|
7567
|
-
|
7568
|
-
|
7569
|
-
ranges.each { |range| write_conditional_formatting(range, @cond_formats[range]) }
|
7489
|
+
def write_conditional_formats #:nodoc:
|
7490
|
+
@cond_formats.keys.sort.each do |range|
|
7491
|
+
write_conditional_formatting(range, @cond_formats[range])
|
7492
|
+
end
|
7570
7493
|
end
|
7571
7494
|
|
7572
7495
|
#
|
7573
7496
|
# Write the <conditionalFormatting> element.
|
7574
7497
|
#
|
7575
|
-
|
7576
|
-
# to a cell or range of cells based on user defined criteria.
|
7577
|
-
#
|
7578
|
-
# worksheet.conditional_formatting('A1:J10',
|
7579
|
-
# {
|
7580
|
-
# :type => 'cell',
|
7581
|
-
# :criteria => '>=',
|
7582
|
-
# :value => 50,
|
7583
|
-
# :format => format1
|
7584
|
-
# }
|
7585
|
-
# )
|
7586
|
-
# This method contains a lot of parameters and is described
|
7587
|
-
# in detail in a separate section "CONDITIONAL FORMATTING IN EXCEL".
|
7588
|
-
#
|
7589
|
-
# See also the conditional_format.rb program in the examples directory
|
7590
|
-
# of the distro
|
7591
|
-
#
|
7592
|
-
def write_conditional_formatting(range, params) #:nodoc:
|
7498
|
+
def write_conditional_formatting(range, cond_formats) #:nodoc:
|
7593
7499
|
attributes = ['sqref', range]
|
7594
7500
|
|
7595
7501
|
@writer.tag_elements('conditionalFormatting', attributes) do
|
7596
|
-
|
7597
|
-
end
|
7598
|
-
end
|
7599
|
-
|
7600
|
-
#
|
7601
|
-
# Write the <cfRule> element.
|
7602
|
-
#
|
7603
|
-
def write_cf_rule(param) #:nodoc:
|
7604
|
-
attributes = ['type' , param[:type]]
|
7605
|
-
|
7606
|
-
if param[:format]
|
7607
|
-
attributes << 'dxfId' << param[:format]
|
7608
|
-
end
|
7609
|
-
attributes << 'priority' << param[:priority]
|
7610
|
-
|
7611
|
-
case param[:type]
|
7612
|
-
when 'cellIs'
|
7613
|
-
attributes << 'operator' << param[:criteria]
|
7614
|
-
@writer.tag_elements('cfRule', attributes) do
|
7615
|
-
if param[:minimum] && param[:maximum]
|
7616
|
-
write_formula_tag(param[:minimum])
|
7617
|
-
write_formula_tag(param[:maximum])
|
7618
|
-
else
|
7619
|
-
write_formula_tag(param[:value])
|
7620
|
-
end
|
7621
|
-
end
|
7622
|
-
when 'aboveAverage'
|
7623
|
-
attributes << 'aboveAverage' << 0 if param[:criteria] =~ /below/
|
7624
|
-
attributes << 'equalAverage' << 1 if param[:criteria] =~ /equal/
|
7625
|
-
if param[:criteria] =~ /([123]) std dev/
|
7626
|
-
attributes << 'stdDev' << $~[1]
|
7627
|
-
end
|
7628
|
-
@writer.empty_tag('cfRule', attributes)
|
7629
|
-
when 'top10'
|
7630
|
-
attributes << 'percent' << 1 if param[:criteria] == '%'
|
7631
|
-
attributes << 'bottom' << 1 if param[:direction]
|
7632
|
-
rank = param[:value] || 10
|
7633
|
-
attributes << 'rank' << rank
|
7634
|
-
@writer.empty_tag('cfRule', attributes)
|
7635
|
-
when 'duplicateValues', 'uniqueValues'
|
7636
|
-
@writer.empty_tag('cfRule', attributes)
|
7637
|
-
when 'containsText', 'notContainsText', 'beginsWith', 'endsWith'
|
7638
|
-
attributes << 'operator' << param[:criteria]
|
7639
|
-
attributes << 'text' << param[:value]
|
7640
|
-
@writer.tag_elements('cfRule', attributes) do
|
7641
|
-
write_formula_tag(param[:formula])
|
7642
|
-
end
|
7643
|
-
when 'timePeriod'
|
7644
|
-
attributes << 'timePeriod' << param[:criteria]
|
7645
|
-
@writer.tag_elements('cfRule', attributes) do
|
7646
|
-
write_formula_tag(param[:formula])
|
7647
|
-
end
|
7648
|
-
when 'containsBlanks', 'notContainsBlanks', 'containsErrors', 'notContainsErrors'
|
7649
|
-
@writer.tag_elements('cfRule', attributes) do
|
7650
|
-
write_formula_tag(param[:formula])
|
7651
|
-
end
|
7652
|
-
when 'colorScale'
|
7653
|
-
@writer.tag_elements('cfRule', attributes) do
|
7654
|
-
write_color_scale(param)
|
7655
|
-
end
|
7656
|
-
when 'dataBar'
|
7657
|
-
@writer.tag_elements('cfRule', attributes) do
|
7658
|
-
write_data_bar(param)
|
7659
|
-
end
|
7660
|
-
when 'expression'
|
7661
|
-
@writer.tag_elements('cfRule', attributes) do
|
7662
|
-
write_formula_tag(param[:criteria])
|
7663
|
-
end
|
7502
|
+
cond_formats.each { |cond_format| cond_format.write_cf_rule }
|
7664
7503
|
end
|
7665
7504
|
end
|
7666
7505
|
|
@@ -7674,54 +7513,11 @@ module Writexlsx
|
|
7674
7513
|
end
|
7675
7514
|
end
|
7676
7515
|
|
7677
|
-
# Check for a cell reference in A1 notation and substitute row and column
|
7678
|
-
def row_col_notation(args) # :nodoc:
|
7679
|
-
if args[0] =~ /^\D/
|
7680
|
-
substitute_cellref(*args)
|
7681
|
-
else
|
7682
|
-
args
|
7683
|
-
end
|
7684
|
-
end
|
7685
|
-
|
7686
|
-
#
|
7687
|
-
# Check that row and col are valid and store max and min values for use in
|
7688
|
-
# other methods/elements.
|
7689
|
-
#
|
7690
|
-
# The ignore_row/ignore_col flags is used to indicate that we wish to
|
7691
|
-
# perform the dimension check without storing the value.
|
7692
|
-
#
|
7693
|
-
# The ignore flags are use by set_row() and data_validate.
|
7694
|
-
#
|
7695
|
-
def check_dimensions_and_update_max_min_values(row, col, ignore_row = 0, ignore_col = 0) #:nodoc:
|
7696
|
-
check_dimensions(row, col)
|
7697
|
-
store_row_max_min_values(row) if ignore_row == 0
|
7698
|
-
store_col_max_min_values(col) if ignore_col == 0
|
7699
|
-
|
7700
|
-
0
|
7701
|
-
end
|
7702
|
-
|
7703
|
-
def check_dimensions(row, col)
|
7704
|
-
if !row || row >= ROW_MAX || !col || col >= COL_MAX
|
7705
|
-
raise WriteXLSXDimensionError
|
7706
|
-
end
|
7707
|
-
0
|
7708
|
-
end
|
7709
|
-
|
7710
7516
|
def store_row_col_max_min_values(row, col)
|
7711
7517
|
store_row_max_min_values(row)
|
7712
7518
|
store_col_max_min_values(col)
|
7713
7519
|
end
|
7714
7520
|
|
7715
|
-
def store_row_max_min_values(row)
|
7716
|
-
@dim_rowmin = row if !@dim_rowmin || (row < @dim_rowmin)
|
7717
|
-
@dim_rowmax = row if !@dim_rowmax || (row > @dim_rowmax)
|
7718
|
-
end
|
7719
|
-
|
7720
|
-
def store_col_max_min_values(col)
|
7721
|
-
@dim_colmin = col if !@dim_colmin || (col < @dim_colmin)
|
7722
|
-
@dim_colmax = col if !@dim_colmax || (col > @dim_colmax)
|
7723
|
-
end
|
7724
|
-
|
7725
7521
|
#
|
7726
7522
|
# Calculate the "spans" attribute of the <row> tag. This is an XLSX
|
7727
7523
|
# optimisation and isn't strictly required. However, it makes comparing
|
@@ -7885,10 +7681,6 @@ module Writexlsx
|
|
7885
7681
|
!!@autofilter_ref
|
7886
7682
|
end
|
7887
7683
|
|
7888
|
-
def date_1904? #:nodoc:
|
7889
|
-
@workbook.date_1904?
|
7890
|
-
end
|
7891
|
-
|
7892
7684
|
def print_options_changed? #:nodoc:
|
7893
7685
|
!!@print_options_changed
|
7894
7686
|
end
|