ricardoo27-writeexcel 0.6.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (245) hide show
  1. data/.document +5 -0
  2. data/.gitattributes +1 -0
  3. data/README.rdoc +136 -0
  4. data/Rakefile +52 -0
  5. data/VERSION +1 -0
  6. data/charts/chartex.rb +316 -0
  7. data/charts/demo1.rb +46 -0
  8. data/charts/demo101.bin +0 -0
  9. data/charts/demo2.rb +65 -0
  10. data/charts/demo201.bin +0 -0
  11. data/charts/demo3.rb +117 -0
  12. data/charts/demo301.bin +0 -0
  13. data/charts/demo4.rb +119 -0
  14. data/charts/demo401.bin +0 -0
  15. data/charts/demo5.rb +48 -0
  16. data/charts/demo501.bin +0 -0
  17. data/examples/a_simple.rb +43 -0
  18. data/examples/autofilter.rb +265 -0
  19. data/examples/bigfile.rb +30 -0
  20. data/examples/chart_area.rb +121 -0
  21. data/examples/chart_bar.rb +120 -0
  22. data/examples/chart_column.rb +120 -0
  23. data/examples/chart_line.rb +120 -0
  24. data/examples/chart_pie.rb +108 -0
  25. data/examples/chart_scatter.rb +121 -0
  26. data/examples/chart_stock.rb +148 -0
  27. data/examples/chess.rb +142 -0
  28. data/examples/colors.rb +129 -0
  29. data/examples/comments1.rb +27 -0
  30. data/examples/comments2.rb +352 -0
  31. data/examples/copyformat.rb +52 -0
  32. data/examples/data_validate.rb +279 -0
  33. data/examples/date_time.rb +87 -0
  34. data/examples/defined_name.rb +32 -0
  35. data/examples/demo.rb +124 -0
  36. data/examples/diag_border.rb +36 -0
  37. data/examples/formats.rb +490 -0
  38. data/examples/formula_result.rb +30 -0
  39. data/examples/header.rb +137 -0
  40. data/examples/hide_sheet.rb +29 -0
  41. data/examples/hyperlink.rb +43 -0
  42. data/examples/images.rb +63 -0
  43. data/examples/indent.rb +31 -0
  44. data/examples/merge1.rb +40 -0
  45. data/examples/merge2.rb +45 -0
  46. data/examples/merge3.rb +66 -0
  47. data/examples/merge4.rb +83 -0
  48. data/examples/merge5.rb +80 -0
  49. data/examples/merge6.rb +67 -0
  50. data/examples/outline.rb +255 -0
  51. data/examples/outline_collapsed.rb +209 -0
  52. data/examples/panes.rb +113 -0
  53. data/examples/password_protection.rb +33 -0
  54. data/examples/properties.rb +34 -0
  55. data/examples/properties_jp.rb +33 -0
  56. data/examples/protection.rb +47 -0
  57. data/examples/regions.rb +53 -0
  58. data/examples/repeat.rb +43 -0
  59. data/examples/republic.png +0 -0
  60. data/examples/right_to_left.rb +27 -0
  61. data/examples/row_wrap.rb +53 -0
  62. data/examples/set_first_sheet.rb +14 -0
  63. data/examples/stats.rb +74 -0
  64. data/examples/stocks.rb +81 -0
  65. data/examples/store_formula.rb +15 -0
  66. data/examples/tab_colors.rb +31 -0
  67. data/examples/utf8.rb +15 -0
  68. data/examples/write_arrays.rb +83 -0
  69. data/html/en/doc_en.html +5946 -0
  70. data/html/images/a_simple.jpg +0 -0
  71. data/html/images/area1.jpg +0 -0
  72. data/html/images/bar1.jpg +0 -0
  73. data/html/images/chart_area.xls +0 -0
  74. data/html/images/column1.jpg +0 -0
  75. data/html/images/data_validation.jpg +0 -0
  76. data/html/images/line1.jpg +0 -0
  77. data/html/images/pie1.jpg +0 -0
  78. data/html/images/regions.jpg +0 -0
  79. data/html/images/scatter1.jpg +0 -0
  80. data/html/images/stats.jpg +0 -0
  81. data/html/images/stock1.jpg +0 -0
  82. data/html/images/stocks.jpg +0 -0
  83. data/html/index.html +16 -0
  84. data/html/style.css +433 -0
  85. data/lib/writeexcel.rb +1159 -0
  86. data/lib/writeexcel/biffwriter.rb +223 -0
  87. data/lib/writeexcel/caller_info.rb +12 -0
  88. data/lib/writeexcel/cell_range.rb +332 -0
  89. data/lib/writeexcel/chart.rb +1968 -0
  90. data/lib/writeexcel/charts/area.rb +154 -0
  91. data/lib/writeexcel/charts/bar.rb +177 -0
  92. data/lib/writeexcel/charts/column.rb +156 -0
  93. data/lib/writeexcel/charts/external.rb +66 -0
  94. data/lib/writeexcel/charts/line.rb +154 -0
  95. data/lib/writeexcel/charts/pie.rb +169 -0
  96. data/lib/writeexcel/charts/scatter.rb +192 -0
  97. data/lib/writeexcel/charts/stock.rb +213 -0
  98. data/lib/writeexcel/col_info.rb +87 -0
  99. data/lib/writeexcel/colors.rb +68 -0
  100. data/lib/writeexcel/comments.rb +460 -0
  101. data/lib/writeexcel/compatibility.rb +65 -0
  102. data/lib/writeexcel/convert_date_time.rb +117 -0
  103. data/lib/writeexcel/data_validations.rb +370 -0
  104. data/lib/writeexcel/debug_info.rb +41 -0
  105. data/lib/writeexcel/embedded_chart.rb +35 -0
  106. data/lib/writeexcel/excelformula.y +139 -0
  107. data/lib/writeexcel/excelformulaparser.rb +587 -0
  108. data/lib/writeexcel/format.rb +1575 -0
  109. data/lib/writeexcel/formula.rb +987 -0
  110. data/lib/writeexcel/helper.rb +78 -0
  111. data/lib/writeexcel/image.rb +218 -0
  112. data/lib/writeexcel/olewriter.rb +305 -0
  113. data/lib/writeexcel/outline.rb +24 -0
  114. data/lib/writeexcel/properties.rb +242 -0
  115. data/lib/writeexcel/shared_string_table.rb +153 -0
  116. data/lib/writeexcel/storage_lite.rb +984 -0
  117. data/lib/writeexcel/workbook.rb +2478 -0
  118. data/lib/writeexcel/worksheet.rb +6925 -0
  119. data/lib/writeexcel/worksheets.rb +25 -0
  120. data/lib/writeexcel/write_file.rb +63 -0
  121. data/test/excelfile/Chart1.xls +0 -0
  122. data/test/excelfile/Chart2.xls +0 -0
  123. data/test/excelfile/Chart3.xls +0 -0
  124. data/test/excelfile/Chart4.xls +0 -0
  125. data/test/excelfile/Chart5.xls +0 -0
  126. data/test/helper.rb +31 -0
  127. data/test/perl_output/Chart1.xls.data +0 -0
  128. data/test/perl_output/Chart2.xls.data +0 -0
  129. data/test/perl_output/Chart3.xls.data +0 -0
  130. data/test/perl_output/Chart4.xls.data +0 -0
  131. data/test/perl_output/Chart5.xls.data +0 -0
  132. data/test/perl_output/README +31 -0
  133. data/test/perl_output/a_simple.xls +0 -0
  134. data/test/perl_output/autofilter.xls +0 -0
  135. data/test/perl_output/biff_add_continue_testdata +0 -0
  136. data/test/perl_output/chart_area.xls +0 -0
  137. data/test/perl_output/chart_bar.xls +0 -0
  138. data/test/perl_output/chart_column.xls +0 -0
  139. data/test/perl_output/chart_line.xls +0 -0
  140. data/test/perl_output/chess.xls +0 -0
  141. data/test/perl_output/colors.xls +0 -0
  142. data/test/perl_output/comments0.xls +0 -0
  143. data/test/perl_output/comments1.xls +0 -0
  144. data/test/perl_output/comments2.xls +0 -0
  145. data/test/perl_output/data_validate.xls +0 -0
  146. data/test/perl_output/date_time.xls +0 -0
  147. data/test/perl_output/defined_name.xls +0 -0
  148. data/test/perl_output/demo.xls +0 -0
  149. data/test/perl_output/demo101.bin +0 -0
  150. data/test/perl_output/demo201.bin +0 -0
  151. data/test/perl_output/demo301.bin +0 -0
  152. data/test/perl_output/demo401.bin +0 -0
  153. data/test/perl_output/demo501.bin +0 -0
  154. data/test/perl_output/diag_border.xls +0 -0
  155. data/test/perl_output/f_font_biff +0 -0
  156. data/test/perl_output/f_font_key +1 -0
  157. data/test/perl_output/f_xf_biff +0 -0
  158. data/test/perl_output/file_font_biff +0 -0
  159. data/test/perl_output/file_font_key +1 -0
  160. data/test/perl_output/file_xf_biff +0 -0
  161. data/test/perl_output/formula_result.xls +0 -0
  162. data/test/perl_output/headers.xls +0 -0
  163. data/test/perl_output/hidden.xls +0 -0
  164. data/test/perl_output/hide_zero.xls +0 -0
  165. data/test/perl_output/hyperlink.xls +0 -0
  166. data/test/perl_output/images.xls +0 -0
  167. data/test/perl_output/indent.xls +0 -0
  168. data/test/perl_output/merge1.xls +0 -0
  169. data/test/perl_output/merge2.xls +0 -0
  170. data/test/perl_output/merge3.xls +0 -0
  171. data/test/perl_output/merge4.xls +0 -0
  172. data/test/perl_output/merge5.xls +0 -0
  173. data/test/perl_output/merge6.xls +0 -0
  174. data/test/perl_output/ole_write_header +0 -0
  175. data/test/perl_output/outline.xls +0 -0
  176. data/test/perl_output/outline_collapsed.xls +0 -0
  177. data/test/perl_output/panes.xls +0 -0
  178. data/test/perl_output/password_protection.xls +0 -0
  179. data/test/perl_output/protection.xls +0 -0
  180. data/test/perl_output/regions.xls +0 -0
  181. data/test/perl_output/right_to_left.xls +0 -0
  182. data/test/perl_output/set_first_sheet.xls +0 -0
  183. data/test/perl_output/stats.xls +0 -0
  184. data/test/perl_output/stocks.xls +0 -0
  185. data/test/perl_output/store_formula.xls +0 -0
  186. data/test/perl_output/tab_colors.xls +0 -0
  187. data/test/perl_output/unicode_cyrillic.xls +0 -0
  188. data/test/perl_output/utf8.xls +0 -0
  189. data/test/perl_output/workbook1.xls +0 -0
  190. data/test/perl_output/workbook2.xls +0 -0
  191. data/test/perl_output/ws_colinfo +1 -0
  192. data/test/perl_output/ws_store_colinfo +0 -0
  193. data/test/perl_output/ws_store_dimensions +0 -0
  194. data/test/perl_output/ws_store_filtermode +0 -0
  195. data/test/perl_output/ws_store_filtermode_off +0 -0
  196. data/test/perl_output/ws_store_filtermode_on +0 -0
  197. data/test/perl_output/ws_store_selection +0 -0
  198. data/test/perl_output/ws_store_window2 +1 -0
  199. data/test/republic.png +0 -0
  200. data/test/test_00_IEEE_double.rb +13 -0
  201. data/test/test_01_add_worksheet.rb +10 -0
  202. data/test/test_02_merge_formats.rb +49 -0
  203. data/test/test_04_dimensions.rb +388 -0
  204. data/test/test_05_rows.rb +175 -0
  205. data/test/test_06_extsst.rb +74 -0
  206. data/test/test_11_date_time.rb +475 -0
  207. data/test/test_12_date_only.rb +525 -0
  208. data/test/test_13_date_seconds.rb +477 -0
  209. data/test/test_21_escher.rb +624 -0
  210. data/test/test_22_mso_drawing_group.rb +741 -0
  211. data/test/test_23_note.rb +57 -0
  212. data/test/test_24_txo.rb +74 -0
  213. data/test/test_25_position_object.rb +80 -0
  214. data/test/test_26_autofilter.rb +309 -0
  215. data/test/test_27_autofilter.rb +126 -0
  216. data/test/test_28_autofilter.rb +156 -0
  217. data/test/test_29_process_jpg.rb +670 -0
  218. data/test/test_30_validation_dval.rb +74 -0
  219. data/test/test_31_validation_dv_strings.rb +123 -0
  220. data/test/test_32_validation_dv_formula.rb +203 -0
  221. data/test/test_40_property_types.rb +188 -0
  222. data/test/test_41_properties.rb +235 -0
  223. data/test/test_42_set_properties.rb +434 -0
  224. data/test/test_50_name_stored.rb +295 -0
  225. data/test/test_51_name_print_area.rb +353 -0
  226. data/test/test_52_name_print_titles.rb +450 -0
  227. data/test/test_53_autofilter.rb +199 -0
  228. data/test/test_60_chart_generic.rb +574 -0
  229. data/test/test_61_chart_subclasses.rb +84 -0
  230. data/test/test_62_chart_formats.rb +268 -0
  231. data/test/test_63_chart_area_formats.rb +645 -0
  232. data/test/test_biff.rb +71 -0
  233. data/test/test_big_workbook.rb +17 -0
  234. data/test/test_compatibility.rb +12 -0
  235. data/test/test_example_match.rb +3246 -0
  236. data/test/test_format.rb +1189 -0
  237. data/test/test_formula.rb +61 -0
  238. data/test/test_ole.rb +102 -0
  239. data/test/test_storage_lite.rb +116 -0
  240. data/test/test_workbook.rb +146 -0
  241. data/test/test_worksheet.rb +106 -0
  242. data/utils/add_magic_comment.rb +80 -0
  243. data/writeexcel.gemspec +278 -0
  244. data/writeexcel.rdoc +1425 -0
  245. metadata +292 -0
@@ -0,0 +1,65 @@
1
+ # coding: utf-8
2
+ #
3
+ # Why would we ever use Ruby 1.8.7 when we can backport with something
4
+ # as simple as this?
5
+ #
6
+ # copied from prawn.
7
+ # modified by Hideo NAKAMURA
8
+ #
9
+ class String #:nodoc:
10
+ def first_line
11
+ self.each_line { |line| return line }
12
+ end
13
+ unless "".respond_to?(:lines)
14
+ alias_method :lines, :to_a
15
+ end
16
+ unless "".respond_to?(:each_char)
17
+ def each_char #:nodoc:
18
+ # copied from jcode
19
+ if block_given?
20
+ scan(/./m) { |x| yield x }
21
+ else
22
+ scan(/./m)
23
+ end
24
+ end
25
+ end
26
+
27
+ unless "".respond_to?(:bytesize)
28
+ def bytesize # :nodoc:
29
+ self.length
30
+ end
31
+ end
32
+
33
+ unless "".respond_to?(:ord)
34
+ def ord
35
+ self[0]
36
+ end
37
+ end
38
+ end
39
+
40
+ unless File.respond_to?(:binread)
41
+ def File.binread(file) #:nodoc:
42
+ File.open(file,"rb") { |f| f.read }
43
+ end
44
+ end
45
+
46
+ if RUBY_VERSION < "1.9"
47
+
48
+ def ruby_18 #:nodoc:
49
+ yield
50
+ end
51
+
52
+ def ruby_19 #:nodoc:
53
+ false
54
+ end
55
+
56
+ else
57
+
58
+ def ruby_18 #:nodoc:
59
+ false
60
+ end
61
+
62
+ def ruby_19 #:nodoc:
63
+ yield
64
+ end
65
+ end
@@ -0,0 +1,117 @@
1
+ module ConvertDateTime
2
+ #
3
+ # The function takes a date and time in ISO8601 "yyyy-mm-ddThh:mm:ss.ss" format
4
+ # and converts it to a decimal number representing a valid Excel date.
5
+ #
6
+ # Dates and times in Excel are represented by real numbers. The integer part of
7
+ # the number stores the number of days since the epoch and the fractional part
8
+ # stores the percentage of the day in seconds. The epoch can be either 1900 or
9
+ # 1904.
10
+ #
11
+ # Parameter: Date and time string in one of the following formats:
12
+ # yyyy-mm-ddThh:mm:ss.ss # Standard
13
+ # yyyy-mm-ddT # Date only
14
+ # Thh:mm:ss.ss # Time only
15
+ #
16
+ # Returns:
17
+ # A decimal number representing a valid Excel date, or
18
+ # undef if the date is invalid.
19
+ #
20
+ def convert_date_time(date_time_string, date_1904 = false) #:nodoc:
21
+ date_time = date_time_string
22
+
23
+ days = 0 # Number of days since epoch
24
+ seconds = 0 # Time expressed as fraction of 24h hours in seconds
25
+
26
+ # Strip leading and trailing whitespace.
27
+ date_time.sub!(/^\s+/, '')
28
+ date_time.sub!(/\s+$/, '')
29
+
30
+ # Check for invalid date char.
31
+ return nil if date_time =~ /[^0-9T:\-\.Z]/
32
+
33
+ # Check for "T" after date or before time.
34
+ return nil unless date_time =~ /\dT|T\d/
35
+
36
+ # Strip trailing Z in ISO8601 date.
37
+ date_time.sub!(/Z$/, '')
38
+
39
+ # Split into date and time.
40
+ date, time = date_time.split(/T/)
41
+
42
+ # We allow the time portion of the input DateTime to be optional.
43
+ if time
44
+ # Match hh:mm:ss.sss+ where the seconds are optional
45
+ if time =~ /^(\d\d):(\d\d)(:(\d\d(\.\d+)?))?/
46
+ hour = $1.to_i
47
+ min = $2.to_i
48
+ sec = $4.to_f || 0
49
+ else
50
+ return nil # Not a valid time format.
51
+ end
52
+
53
+ # Some boundary checks
54
+ return nil if hour >= 24
55
+ return nil if min >= 60
56
+ return nil if sec >= 60
57
+
58
+ # Excel expresses seconds as a fraction of the number in 24 hours.
59
+ seconds = (hour * 60* 60 + min * 60 + sec) / (24.0 * 60 * 60)
60
+ end
61
+
62
+ # We allow the date portion of the input DateTime to be optional.
63
+ return seconds if date == ''
64
+
65
+ # Match date as yyyy-mm-dd.
66
+ if date =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$/
67
+ year = $1.to_i
68
+ month = $2.to_i
69
+ day = $3.to_i
70
+ else
71
+ return nil # Not a valid date format.
72
+ end
73
+
74
+ # Set the epoch as 1900 or 1904. Defaults to 1900.
75
+ # Special cases for Excel.
76
+ unless date_1904
77
+ return seconds if date == '1899-12-31' # Excel 1900 epoch
78
+ return seconds if date == '1900-01-00' # Excel 1900 epoch
79
+ return 60 + seconds if date == '1900-02-29' # Excel false leapday
80
+ end
81
+
82
+
83
+ # We calculate the date by calculating the number of days since the epoch
84
+ # and adjust for the number of leap days. We calculate the number of leap
85
+ # days by normalising the year in relation to the epoch. Thus the year 2000
86
+ # becomes 100 for 4 and 100 year leapdays and 400 for 400 year leapdays.
87
+ #
88
+ epoch = date_1904 ? 1904 : 1900
89
+ offset = date_1904 ? 4 : 0
90
+ norm = 300
91
+ range = year -epoch
92
+
93
+ # Set month days and check for leap year.
94
+ mdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
95
+ leap = 0
96
+ leap = 1 if year % 4 == 0 && year % 100 != 0 || year % 400 == 0
97
+ mdays[1] = 29 if leap != 0
98
+
99
+ # Some boundary checks
100
+ return nil if year < epoch or year > 9999
101
+ return nil if month < 1 or month > 12
102
+ return nil if day < 1 or day > mdays[month -1]
103
+
104
+ # Accumulate the number of days since the epoch.
105
+ days = mdays[0, month - 1].inject(day) {|result, mday| result + mday} # days from 1, Jan
106
+ days += range *365 # Add days for past years
107
+ days += ((range) / 4) # Add leapdays
108
+ days -= ((range + offset) /100) # Subtract 100 year leapdays
109
+ days += ((range + offset + norm)/400) # Add 400 year leapdays
110
+ days -= leap # Already counted above
111
+
112
+ # Adjust for Excel erroneously treating 1900 as a leap year.
113
+ days += 1 if !date_1904 and days > 59
114
+
115
+ days + seconds
116
+ end
117
+ end
@@ -0,0 +1,370 @@
1
+ module Writeexcel
2
+
3
+ class Worksheet < BIFFWriter
4
+ require 'writeexcel/helper'
5
+
6
+ class DataValidations < Array
7
+ #
8
+ # the count of the DV records to follow.
9
+ #
10
+ # Note, this could be wrapped into store_dv() but we may require separate
11
+ # handling of the object id at a later stage.
12
+ #
13
+ def count_dv_record #:nodoc:
14
+ return if empty?
15
+
16
+ dval_record(-1, size) # obj_id = -1
17
+ end
18
+
19
+ private
20
+
21
+ #
22
+ # Store the DV record which contains the number of and information common to
23
+ # all DV structures.
24
+ # obj_id # Object ID number.
25
+ # dv_count # Count of DV structs to follow.
26
+ #
27
+ def dval_record(obj_id, dv_count) #:nodoc:
28
+ record = 0x01B2 # Record identifier
29
+ length = 0x0012 # Bytes to follow
30
+
31
+ flags = 0x0004 # Option flags.
32
+ x_coord = 0x00000000 # X coord of input box.
33
+ y_coord = 0x00000000 # Y coord of input box.
34
+
35
+ # Pack the record.
36
+ header = [record, length].pack('vv')
37
+ data = [flags, x_coord, y_coord, obj_id, dv_count].pack('vVVVV')
38
+
39
+ header + data
40
+ end
41
+ end
42
+
43
+ require 'writeexcel/convert_date_time'
44
+
45
+ class DataValidation
46
+ include ConvertDateTime
47
+
48
+ def initialize(parser = nil, param = {})
49
+ @parser = parser
50
+ @cells = param[:cells]
51
+ @validate = param[:validate]
52
+ @criteria = param[:criteria]
53
+ @value = param[:value]
54
+ @maximum = param[:maximum]
55
+ @input_title = param[:input_title]
56
+ @input_message = param[:input_message]
57
+ @error_title = param[:error_title]
58
+ @error_message = param[:error_message]
59
+ @error_type = param[:error_type]
60
+ @ignore_blank = param[:ignore_blank]
61
+ @dropdown = param[:dropdown]
62
+ @show_input = param[:show_input]
63
+ @show_error = param[:show_error]
64
+ end
65
+
66
+ #
67
+ # Calclate the DV record that specifies the data validation criteria and options
68
+ # for a range of cells..
69
+ # cells # Aref of cells to which DV applies.
70
+ # validate # Type of data validation.
71
+ # criteria # Validation criteria.
72
+ # value # Value/Source/Minimum formula.
73
+ # maximum # Maximum formula.
74
+ # input_title # Title of input message.
75
+ # input_message # Text of input message.
76
+ # error_title # Title of error message.
77
+ # error_message # Text of input message.
78
+ # error_type # Error dialog type.
79
+ # ignore_blank # Ignore blank cells.
80
+ # dropdown # Display dropdown with list.
81
+ # input_box # Display input box.
82
+ # error_box # Display error box.
83
+ #
84
+ def dv_record # :nodoc:
85
+ record = 0x01BE # Record identifier
86
+
87
+ flags = 0x00000000 # DV option flags.
88
+
89
+ ime_mode = 0 # IME input mode for far east fonts.
90
+ str_lookup = 0 # See below.
91
+
92
+ # Set the string lookup flag for 'list' validations with a string array.
93
+ str_lookup = @validate == 3 && @value.respond_to?(:to_ary) ? 1 : 0
94
+
95
+ # The dropdown flag is stored as a negated value.
96
+ no_dropdown = @dropdown ? 0 : 1
97
+
98
+ # Set the required flags.
99
+ flags |= @validate
100
+ flags |= @error_type << 4
101
+ flags |= str_lookup << 7
102
+ flags |= @ignore_blank << 8
103
+ flags |= no_dropdown << 9
104
+ flags |= ime_mode << 10
105
+ flags |= @show_input << 18
106
+ flags |= @show_error << 19
107
+ flags |= @criteria << 20
108
+
109
+ # Pack the DV cell data.
110
+ dv_data = @cells.inject([@cells.size].pack('v')) do |result, range|
111
+ result + [range[0], range[2], range[1], range[3]].pack('vvvv')
112
+ end
113
+
114
+ # Pack the record.
115
+ data = [flags].pack('V') +
116
+ pack_dv_string(@input_title, 32 ) +
117
+ pack_dv_string(@error_title, 32 ) +
118
+ pack_dv_string(@input_message, 255) +
119
+ pack_dv_string(@error_message, 255) +
120
+ pack_dv_formula(@value) +
121
+ pack_dv_formula(@maximum) +
122
+ dv_data
123
+
124
+ header = [record, data.bytesize].pack('vv')
125
+
126
+ header + data
127
+ end
128
+
129
+ def self.factory(parser, date_1904, *args)
130
+ # Check for a valid number of args.
131
+ return -1 if args.size != 5 && args.size != 3
132
+
133
+ # The final hashref contains the validation parameters.
134
+ param = args.pop
135
+
136
+ # 'validate' is a required parameter.
137
+ return -3 unless param.has_key?(:validate)
138
+
139
+ # Make the last row/col the same as the first if not defined.
140
+ row1, col1, row2, col2 = args
141
+ row2, col2 = row1, col1 unless row2
142
+
143
+ # List of valid input parameters.
144
+ obj = DataValidation.new
145
+ valid_parameter = obj.valid_parameter_of_data_validation
146
+
147
+ # Check for valid input parameters.
148
+ param.each_key { |param_key| return -3 unless valid_parameter.has_key?(param_key) }
149
+
150
+ # Map alternative parameter names 'source' or 'minimum' to 'value'.
151
+ param[:value] = param[:source] if param[:source]
152
+ param[:value] = param[:minimum] if param[:minimum]
153
+
154
+ # Check for valid validation types.
155
+ unless obj.valid_validation_type.has_key?(param[:validate].downcase)
156
+ return -3
157
+ else
158
+ param[:validate] = obj.valid_validation_type[param[:validate].downcase]
159
+ end
160
+
161
+ # No action is required for validation type 'any'.
162
+ # TODO: we should perhaps store 'any' for message only validations.
163
+ return 0 if param[:validate] == 0
164
+
165
+ # The list and custom validations don't have a criteria so we use a default
166
+ # of 'between'.
167
+ if param[:validate] == 3 || param[:validate] == 7
168
+ param[:criteria] = 'between'
169
+ param[:maximum] = nil
170
+ end
171
+
172
+ # 'criteria' is a required parameter.
173
+ unless param.has_key?(:criteria)
174
+ # carp "Parameter 'criteria' is required in data_validation()";
175
+ return -3
176
+ end
177
+
178
+ # Check for valid criteria types.
179
+ unless obj.valid_criteria_type.has_key?(param[:criteria].downcase)
180
+ return -3
181
+ else
182
+ param[:criteria] = obj.valid_criteria_type[param[:criteria].downcase]
183
+ end
184
+
185
+ # 'Between' and 'Not between' criteria require 2 values.
186
+ if param[:criteria] == 0 || param[:criteria] == 1
187
+ unless param.has_key?(:maximum)
188
+ return -3
189
+ end
190
+ else
191
+ param[:maximum] = nil
192
+ end
193
+
194
+ # Check for valid error dialog types.
195
+ if not param.has_key?(:error_type)
196
+ param[:error_type] = 0
197
+ elsif not obj.valid_error_type.has_key?(param[:error_type].downcase)
198
+ return -3
199
+ else
200
+ param[:error_type] = obj.valid_error_type[param[:error_type].downcase]
201
+ end
202
+
203
+ # Convert date/times value if required.
204
+ if param[:validate] == 4 || param[:validate] == 5
205
+ if param[:value] =~ /T/
206
+ param[:value] = obj.convert_date_time(param[:value], date_1904) || raise("invalid :value: #{param[:value]}")
207
+ end
208
+ if param[:maximum] && param[:maximum] =~ /T/
209
+ param[:maximum] = obj.convert_date_time(param[:maximum], date_1904) || raise("invalid :maximum: #{param[:maximum]}")
210
+ end
211
+ end
212
+
213
+ # Set some defaults if they haven't been defined by the user.
214
+ param[:ignore_blank] = 1 unless param[:ignore_blank]
215
+ param[:dropdown] = 1 unless param[:dropdown]
216
+ param[:show_input] = 1 unless param[:show_input]
217
+ param[:show_error] = 1 unless param[:show_error]
218
+
219
+ # These are the cells to which the validation is applied.
220
+ param[:cells] = [[row1, col1, row2, col2]]
221
+
222
+ # A (for now) undocumented parameter to pass additional cell ranges.
223
+ if param.has_key?(:other_cells)
224
+ param[:cells].push(param[:other_cells])
225
+ end
226
+
227
+ DataValidation.new(parser, param)
228
+ end
229
+
230
+ #
231
+ # Pack the strings used in the input and error dialog captions and messages.
232
+ # Captions are limited to 32 characters. Messages are limited to 255 chars.
233
+ #
234
+ def pack_dv_string(string, max_length) #:nodoc:
235
+ # The default empty string is "\0".
236
+ string = ruby_18 { "\0" } || ruby_19 { "\0".encode('BINARY') } unless string && string != ''
237
+
238
+ # Excel limits DV captions to 32 chars and messages to 255.
239
+ string = string[0 .. max_length-1] if string.bytesize > max_length
240
+
241
+ ruby_19 { string = convert_to_ascii_if_ascii(string) }
242
+
243
+ # Handle utf8 strings
244
+ if is_utf8?(string)
245
+ str_length = string.gsub(/[^\Wa-zA-Z_\d]/, ' ').bytesize # jlength
246
+ string = utf8_to_16le(string)
247
+ encoding = 1
248
+ else
249
+ str_length = string.bytesize
250
+ encoding = 0
251
+ end
252
+
253
+ ruby_18 { [str_length, encoding].pack('vC') + string } ||
254
+ ruby_19 { [str_length, encoding].pack('vC') + string.force_encoding('BINARY') }
255
+ end
256
+
257
+ #
258
+ # Pack the formula used in the DV record. This is the same as an cell formula
259
+ # with some additional header information. Note, DV formulas in Excel use
260
+ # relative addressing (R1C1 and ptgXxxN) however we use the Formula.pm's
261
+ # default absolute addressing (A1 and ptgXxx).
262
+ #
263
+ def pack_dv_formula(formula) #:nodoc:
264
+ unused = 0x0000
265
+
266
+ # Return a default structure for unused formulas.
267
+ return [0, unused].pack('vv') unless formula && formula != ''
268
+
269
+ # Pack a list array ref as a null separated string.
270
+ formula = %!"#{formula.join("\0")}"! if formula.respond_to?(:to_ary)
271
+
272
+ # Strip the = sign at the beginning of the formula string
273
+ formula = formula.to_s unless formula.respond_to?(:to_str)
274
+ formula.sub!(/^=/, '')
275
+
276
+ # In order to raise formula errors from the point of view of the calling
277
+ # program we use an eval block and re-raise the error from here.
278
+ #
279
+ tokens = @parser.parse_formula(formula) # ????
280
+
281
+ # if ($@) {
282
+ # $@ =~ s/\n$//; # Strip the \n used in the Formula.pm die()
283
+ # croak $@; # Re-raise the error
284
+ # }
285
+ # else {
286
+ # # TODO test for non valid ptgs such as Sheet2!A1
287
+ # }
288
+
289
+ # Force 2d ranges to be a reference class.
290
+ tokens.each do |t|
291
+ t.sub!(/_range2d/, "_range2dR")
292
+ t.sub!(/_name/, "_nameR")
293
+ end
294
+
295
+ # Parse the tokens into a formula string.
296
+ formula = @parser.parse_tokens(tokens)
297
+
298
+ [formula.length, unused].pack('vv') + formula
299
+ end
300
+
301
+ def valid_parameter_of_data_validation
302
+ {
303
+ :validate => 1,
304
+ :criteria => 1,
305
+ :value => 1,
306
+ :source => 1,
307
+ :minimum => 1,
308
+ :maximum => 1,
309
+ :ignore_blank => 1,
310
+ :dropdown => 1,
311
+ :show_input => 1,
312
+ :input_title => 1,
313
+ :input_message => 1,
314
+ :show_error => 1,
315
+ :error_title => 1,
316
+ :error_message => 1,
317
+ :error_type => 1,
318
+ :other_cells => 1
319
+ }
320
+ end
321
+
322
+ def valid_validation_type
323
+ {
324
+ 'any' => 0,
325
+ 'any value' => 0,
326
+ 'whole number' => 1,
327
+ 'whole' => 1,
328
+ 'integer' => 1,
329
+ 'decimal' => 2,
330
+ 'list' => 3,
331
+ 'date' => 4,
332
+ 'time' => 5,
333
+ 'text length' => 6,
334
+ 'length' => 6,
335
+ 'custom' => 7
336
+ }
337
+ end
338
+
339
+ def valid_criteria_type
340
+ {
341
+ 'between' => 0,
342
+ 'not between' => 1,
343
+ 'equal to' => 2,
344
+ '=' => 2,
345
+ '==' => 2,
346
+ 'not equal to' => 3,
347
+ '!=' => 3,
348
+ '<>' => 3,
349
+ 'greater than' => 4,
350
+ '>' => 4,
351
+ 'less than' => 5,
352
+ '<' => 5,
353
+ 'greater than or equal to' => 6,
354
+ '>=' => 6,
355
+ 'less than or equal to' => 7,
356
+ '<=' => 7
357
+ }
358
+ end
359
+
360
+ def valid_error_type
361
+ {
362
+ 'stop' => 0,
363
+ 'warning' => 1,
364
+ 'information' => 2
365
+ }
366
+ end
367
+ end
368
+ end
369
+
370
+ end