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