mack-pdf_writer 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/lib/gems/archive-tar-minitar-0.5.2/bin/minitar +27 -0
  2. data/lib/gems/archive-tar-minitar-0.5.2/lib/archive/tar/minitar/command.rb +814 -0
  3. data/lib/gems/archive-tar-minitar-0.5.2/lib/archive/tar/minitar.rb +979 -0
  4. data/lib/gems/color-1.4.0/lib/color/cmyk.rb +281 -0
  5. data/lib/gems/color-1.4.0/lib/color/css.rb +30 -0
  6. data/lib/gems/color-1.4.0/lib/color/grayscale.rb +214 -0
  7. data/lib/gems/color-1.4.0/lib/color/hsl.rb +223 -0
  8. data/lib/gems/color-1.4.0/lib/color/palette/adobecolor.rb +274 -0
  9. data/lib/gems/color-1.4.0/lib/color/palette/gimp.rb +118 -0
  10. data/lib/gems/color-1.4.0/lib/color/palette/monocontrast.rb +182 -0
  11. data/lib/gems/color-1.4.0/lib/color/palette.rb +18 -0
  12. data/lib/gems/color-1.4.0/lib/color/rgb/metallic.rb +45 -0
  13. data/lib/gems/color-1.4.0/lib/color/rgb-colors.rb +357 -0
  14. data/lib/gems/color-1.4.0/lib/color/rgb.rb +455 -0
  15. data/lib/gems/color-1.4.0/lib/color/yiq.rb +86 -0
  16. data/lib/gems/color-1.4.0/lib/color.rb +147 -0
  17. data/lib/gems/pdf-writer-1.1.8/bin/techbook +24 -0
  18. data/lib/gems/pdf-writer-1.1.8/lib/pdf/charts/stddev.rb +430 -0
  19. data/lib/gems/pdf-writer-1.1.8/lib/pdf/charts.rb +13 -0
  20. data/lib/gems/pdf-writer-1.1.8/lib/pdf/math.rb +108 -0
  21. data/lib/gems/pdf-writer-1.1.8/lib/pdf/quickref.rb +332 -0
  22. data/lib/gems/pdf-writer-1.1.8/lib/pdf/simpletable.rb +947 -0
  23. data/lib/gems/pdf-writer-1.1.8/lib/pdf/techbook.rb +901 -0
  24. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/arc4.rb +63 -0
  25. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fontmetrics.rb +203 -0
  26. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Courier-Bold.afm +342 -0
  27. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Courier-BoldOblique.afm +342 -0
  28. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Courier-Oblique.afm +342 -0
  29. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Courier.afm +342 -0
  30. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Helvetica-Bold.afm +2827 -0
  31. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Helvetica-BoldOblique.afm +2827 -0
  32. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Helvetica-Oblique.afm +3051 -0
  33. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Helvetica.afm +3051 -0
  34. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/MustRead.html +19 -0
  35. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Symbol.afm +213 -0
  36. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Times-Bold.afm +2588 -0
  37. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Times-BoldItalic.afm +2384 -0
  38. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Times-Italic.afm +2667 -0
  39. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/Times-Roman.afm +2419 -0
  40. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/fonts/ZapfDingbats.afm +225 -0
  41. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/graphics/imageinfo.rb +365 -0
  42. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/graphics.rb +813 -0
  43. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/lang/en.rb +99 -0
  44. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/lang.rb +43 -0
  45. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/action.rb +35 -0
  46. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/annotation.rb +42 -0
  47. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/catalog.rb +39 -0
  48. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/contents.rb +65 -0
  49. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/destination.rb +40 -0
  50. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/encryption.rb +53 -0
  51. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/font.rb +72 -0
  52. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/fontdescriptor.rb +34 -0
  53. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/fontencoding.rb +40 -0
  54. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/image.rb +304 -0
  55. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/info.rb +51 -0
  56. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/outline.rb +30 -0
  57. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/outlines.rb +30 -0
  58. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/page.rb +195 -0
  59. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/pages.rb +115 -0
  60. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/procset.rb +46 -0
  61. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object/viewerpreferences.rb +74 -0
  62. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/object.rb +23 -0
  63. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/ohash.rb +58 -0
  64. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/oreader.rb +25 -0
  65. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/state.rb +48 -0
  66. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer/strokestyle.rb +138 -0
  67. data/lib/gems/pdf-writer-1.1.8/lib/pdf/writer.rb +2729 -0
  68. data/lib/gems/transaction-simple-1.4.0/lib/transaction/simple/group.rb +146 -0
  69. data/lib/gems/transaction-simple-1.4.0/lib/transaction/simple/threadsafe/group.rb +36 -0
  70. data/lib/gems/transaction-simple-1.4.0/lib/transaction/simple/threadsafe.rb +68 -0
  71. data/lib/gems/transaction-simple-1.4.0/lib/transaction/simple.rb +486 -0
  72. data/lib/gems.rb +13 -0
  73. data/lib/mack-pdf_writer.rb +2 -0
  74. metadata +111 -16
@@ -0,0 +1,947 @@
1
+ #--
2
+ # PDF::Writer for Ruby.
3
+ # http://rubyforge.org/projects/ruby-pdf/
4
+ # Copyright 2003 - 2005 Austin Ziegler.
5
+ #
6
+ # Licensed under a MIT-style licence. See LICENCE in the main distribution
7
+ # for full licensing information.
8
+ #
9
+ # $Id: simpletable.rb 186 2007-12-10 22:58:48Z sandal $
10
+ #++
11
+ require 'pdf/writer'
12
+ require 'transaction/simple/group'
13
+
14
+ # This class will create tables with a relatively simple API and internal
15
+ # implementation.
16
+ class PDF::SimpleTable
17
+
18
+ include Transaction::Simple
19
+
20
+ # Defines formatting options for a column.
21
+ class Column
22
+ def initialize(name)
23
+ @name = name
24
+
25
+ yield self if block_given?
26
+ end
27
+
28
+ # The heading of the column. This should be an instance of
29
+ # PDF::SimpleTable::Column::Heading. If it is not, it will be
30
+ # converted into one.
31
+ attr_accessor :heading
32
+ def heading=(hh) #:nodoc:
33
+ unless hh.kind_of?(Heading)
34
+ hh = Heading.new(hh)
35
+ end
36
+ @heading = hh
37
+ end
38
+ # The name of the column.
39
+ attr_reader :name
40
+ # The width of the column. If this value is set, the column will be
41
+ # exactly this number of units wide.
42
+ attr_accessor :width
43
+ # The data name that will be used to provide a hyperlink for values in
44
+ # this column.
45
+ attr_accessor :link_name
46
+ # The justification of the column. May be :left, :right, :center, or
47
+ # :full.
48
+ attr_accessor :justification
49
+
50
+ # Formatting options for heading rows. Each column can have a separate
51
+ # heading value.
52
+ class Heading
53
+ def initialize(title = nil)
54
+ @title = title
55
+ yield self if block_given?
56
+ end
57
+
58
+ # Indicates that the heading should be rendered bold.
59
+ attr_accessor :bold
60
+ # The justification of the heading of the column. May be :left,
61
+ # :center, :right, or :full.
62
+ attr_accessor :justification
63
+ # The title of the heading. If nothing is present, the name of the
64
+ # column will be used when headings are displayed.
65
+ attr_accessor :title
66
+ end
67
+ end
68
+
69
+ def initialize
70
+ @column_order = []
71
+ @data = []
72
+ @columns = {}
73
+
74
+ @show_lines = :outer
75
+ @show_headings = true
76
+ @shade_rows = :shaded
77
+ @shade_color = Color::RGB::Grey80
78
+ @shade_color2 = Color::RGB::Grey70
79
+ @shade_headings = false
80
+ @shade_heading_color = Color::RGB::Grey90
81
+ @font_size = 10
82
+ @heading_font_size = 12
83
+ @title_font_size = 12
84
+ @title_gap = 5
85
+ @title_color = Color::RGB::Black
86
+ @heading_color = Color::RGB::Black
87
+ @text_color = Color::RGB::Black
88
+ @line_color = Color::RGB::Black
89
+ @position = :center
90
+ @orientation = :center
91
+ @bold_headings = false
92
+
93
+ @cols = PDF::Writer::OHash.new
94
+ @width = 0
95
+ @maximum_width = 0
96
+
97
+ @gap = 5
98
+ @row_gap = 2
99
+ @column_gap = 5
100
+ @header_gap = 0
101
+
102
+ @minimum_space = 0
103
+ @protect_rows = 1
104
+ @split_rows = false
105
+
106
+ @inner_line_style = PDF::Writer::StrokeStyle.new(1)
107
+ @outer_line_style = PDF::Writer::StrokeStyle.new(1)
108
+
109
+ yield self if block_given?
110
+ end
111
+
112
+ # An array of Hash entries. Each row is a Hash where the keys are the
113
+ # names of the columns as specified in #column_order and the values are
114
+ # the values of the cell.
115
+ attr_accessor :data
116
+ # An array that defines the order of the columns in the table. The
117
+ # values in this array are the column names in #data. The columns will
118
+ # be presented in the order defined here.
119
+ attr_accessor :column_order
120
+ # An array that defines columns and column options for the table. The
121
+ # entries should be PDF::SimpleTable::Column objects.
122
+ attr_accessor :columns
123
+
124
+ # The title to be put on the top of the table.
125
+ attr_accessor :title
126
+
127
+ # Whether to display the lines on the table or not. Valid values are:
128
+ #
129
+ # <tt>:none</tt>:: Displays no lines.
130
+ # <tt>:outer</tt>:: Displays outer lines only. *Default*
131
+ # <tt>:inner</tt>:: Displays inner lines only.
132
+ # <tt>:all</tt>:: Displays all lines, inner and outer.
133
+ attr_accessor :show_lines
134
+ # Displays the headings for the table if +true+. The default is +true+.
135
+ attr_accessor :show_headings
136
+ # Controls row shading.
137
+ #
138
+ # <tt>:none</tt>:: No row shading; all rows are the standard
139
+ # background colour.
140
+ # <tt>:shaded</tt>:: Alternate lines will be shaded; half of the rows
141
+ # will be the standard background colour; the rest
142
+ # of the rows will be shaded with #shade_color.
143
+ # *Default*
144
+ # <tt>:striped</tt>:: Alternate lines will be shaded; half of the rows
145
+ # will be shaded with #shade_color; the rest of the
146
+ # rows will be shaded with #shade_color2.
147
+ attr_accessor :shade_rows
148
+ # The main row shading colour. Defaults to Color::RGB::Grey80. Used with
149
+ # #shade_rows of <tt>:shaded</tt> and <tt>:striped</tt>.
150
+ attr_accessor :shade_color
151
+ # The alternate row shading colour, used with #shade_rows of
152
+ # <tt>:striped</tt>. Defaults to Color::RGB::Grey70.
153
+ attr_accessor :shade_color2
154
+ # Places a background colour in the heading if +true+.
155
+ attr_accessor :shade_headings
156
+ # Defines the colour of the background shading for the heading if
157
+ # #shade_headings is +true+. Default is Color::RGB::Grey90.
158
+ attr_accessor :shade_heading_color
159
+ # The font size of the data cells, in points. Defaults to 10 points.
160
+ attr_accessor :font_size
161
+ # The font size of the heading cells, in points. Defaults to 12 points.
162
+ attr_accessor :heading_font_size
163
+ # The font size of the title, in points. Defaults to 12 points.
164
+ attr_accessor :title_font_size
165
+ # The gap, in PDF units, between the title and the table. Defaults to 5
166
+ # units.
167
+ attr_accessor :title_gap
168
+ # The text colour of the title. Defaults to Color::RGB::Black.
169
+ attr_accessor :title_color
170
+ # The text colour of the heading. Defaults to Color::RGB::Black.
171
+ attr_accessor :heading_color
172
+ # The text colour of the body cells. Defaults to Color::RGB::Black.
173
+ attr_accessor :text_color
174
+ # The colour of the table lines. Defaults to Color::RGB::Black.
175
+ attr_accessor :line_color
176
+ # The +x+ position of the table. This will be one of:
177
+ #
178
+ # <tt>:left</tt>:: Aligned with the left margin.
179
+ # <tt>:right</tt>:: Aligned with the right margin.
180
+ # <tt>:center</tt>:: Centered between the margins. *Default*.
181
+ # <em>offset</em>:: The absolute position of the table, relative from
182
+ # the left margin.
183
+ attr_accessor :position
184
+ # The orientation of the table relative to #position.
185
+ #
186
+ # <tt>:left</tt>:: The table is to the left of #position.
187
+ # <tt>:right</tt>:: The table is to the right of #position.
188
+ # <tt>:center</tt>:: The table is centred at #position.
189
+ # <em>offset</em>:: The left of the table is offset from #position.
190
+ attr_accessor :orientation
191
+ # Makes the heading text bold if +true+. Defaults to +false+.
192
+ attr_accessor :bold_headings
193
+ # Specifies the width of the table. If the table is smaller than the
194
+ # provided width, columns are proportionally stretched to fit the width
195
+ # of the table. If the table is wider than the provided width, columns
196
+ # are proportionally shrunk to fit the width of the table. Content may
197
+ # need to wrap in this case.
198
+ #
199
+ # Defaults to zero, which indicates that the size whould be determined
200
+ # automatically based on the content and the margins.
201
+ attr_accessor :width
202
+ # Specifies the maximum width of the table. The table will not grow
203
+ # larger than this width under any circumstances.
204
+ #
205
+ # Defaults to zero, which indicates that there is no maximum width
206
+ # (aside from the margin size).
207
+ attr_accessor :maximum_width
208
+ # The space, in PDF user units, added to the top and bottom of each row
209
+ # between the text and the lines of the cell. Default 2 units.
210
+ attr_accessor :row_gap
211
+ # The space, in PDF user units, on the left and right sides of each
212
+ # cell. Default 5 units.
213
+ attr_accessor :column_gap
214
+
215
+ # The minimum space between the bottom of each row and the bottom
216
+ # margin. If the amount of space is less than this, a new page will be
217
+ # started. Default is 100 PDF user units.
218
+ attr_accessor :minimum_space
219
+ # The number of rows to hold with the heading on the page. If there are
220
+ # less than this number of rows on the page, then move the whole lot
221
+ # onto the next page. Default is one row.
222
+ attr_accessor :protect_rows
223
+ # Allows a table's rows to be split across page boundaries if +true+.
224
+ # This defaults to +false+.
225
+ attr_accessor :split_rows
226
+ # The number of PDF user units to leave open at the top of a page after
227
+ # a page break. This is typically used for a repeating page header, etc.
228
+ # Defaults to zero units.
229
+ attr_accessor :header_gap
230
+ # Defines the inner line style. The default style is a solid line with a
231
+ # thickness of 1 unit.
232
+ attr_accessor :inner_line_style
233
+ # Defines the outer line style. The default style is a solid line with a
234
+ # thickness of 1 unit.
235
+ attr_accessor :outer_line_style
236
+
237
+ # Render the table on the PDF::Writer document provided.
238
+ def render_on(pdf)
239
+ if @column_order.empty?
240
+ raise TypeError, PDF::Writer::Lang[:simpletable_columns_undefined]
241
+ end
242
+ if @data.empty?
243
+ raise TypeError, PDF::Writer::Lang[:simpletable_data_empty]
244
+ end
245
+
246
+ low_y = descender = y0 = y1 = y = nil
247
+
248
+ @cols = PDF::Writer::OHash.new
249
+ @column_order.each do |name|
250
+ col = @columns[name]
251
+ if col
252
+ @cols[name] = col
253
+ else
254
+ @cols[name] = PDF::SimpleTable::Column.new(name)
255
+ end
256
+ end
257
+
258
+ @gap = 2 * @column_gap
259
+
260
+ max_width = __find_table_max_width__(pdf)
261
+ pos, t, x, adjustment_width, set_width = __find_table_positions__(pdf, max_width)
262
+
263
+ # if max_width is specified, and the table is too wide, and the width
264
+ # has not been set, then set the width.
265
+ if @width.zero? and @maximum_width.nonzero? and ((t - x) > @maximum_width)
266
+ @width = @maximum_width
267
+ end
268
+
269
+ if @width and (adjustment_width > 0) and (set_width < @width)
270
+ # First find the current widths of the columns involved in this
271
+ # mystery
272
+ cols0 = PDF::Writer::OHash.new
273
+ cols1 = PDF::Writer::OHash.new
274
+
275
+ xq = presentWidth = 0
276
+ last = nil
277
+
278
+ pos.each do |name, colpos|
279
+ if @cols[last].nil? or
280
+ @cols[last].width.nil? or
281
+ @cols[last].width <= 0
282
+ unless last.nil? or last.empty?
283
+ cols0[last] = colpos - xq - @gap
284
+ presentWidth += (colpos - xq - @gap)
285
+ end
286
+ else
287
+ cols1[last] = colpos - xq
288
+ end
289
+ last = name
290
+ xq = colpos
291
+ end
292
+
293
+ # cols0 contains the widths of all the columns which are not set
294
+ needed_width = @width - set_width
295
+
296
+ # If needed width is negative then add it equally to each column,
297
+ # else get more tricky.
298
+ if presentWidth < needed_width
299
+ diff = (needed_width - presentWidth) / cols0.size.to_f
300
+ cols0.each_key { |name| cols0[name] += diff }
301
+ else
302
+ cnt = 0
303
+ loop do
304
+ break if (presentWidth <= needed_width) or (cnt >= 100)
305
+ cnt += 1 # insurance policy
306
+ # Find the widest columns and the next to widest width
307
+ aWidest = []
308
+ nWidest = widest = 0
309
+ cols0.each do |name, w|
310
+ if w > widest
311
+ aWidest = [ name ]
312
+ nWidest = widest
313
+ widest = w
314
+ elsif w == widest
315
+ aWidest << name
316
+ end
317
+ end
318
+
319
+ # Then figure out what the width of the widest columns would
320
+ # have to be to take up all the slack.
321
+ newWidestWidth = widest - (presentWidth - needed_width) / aWidest.size.to_f
322
+ if newWidestWidth > nWidest
323
+ aWidest.each { |name| cols0[name] = newWidestWidth }
324
+ presentWidth = needed_width
325
+ else
326
+ # There is no space, reduce the size of the widest ones down
327
+ # to the next size down, and we will go round again
328
+ aWidest.each { |name| cols0[name] = nWidest }
329
+ presentWidth -= (widest - nWidest) * aWidest.size
330
+ end
331
+ end
332
+ end
333
+
334
+ # cols0 now contains the new widths of the constrained columns. now
335
+ # need to update the pos and max_width arrays
336
+ xq = 0
337
+ pos.each do |name, colpos|
338
+ pos[name] = xq
339
+
340
+ if @cols[name].nil? or
341
+ @cols[name].width.nil? or
342
+ @cols[name].width <= 0
343
+ if not cols0[name].nil?
344
+ xq += cols0[name] + @gap
345
+ max_width[name] = cols0[name]
346
+ end
347
+ else
348
+ xq += cols1[name] unless cols1[name].nil?
349
+ end
350
+ end
351
+
352
+ t = x + @width
353
+ pos[:__last_column__] = t
354
+ end
355
+
356
+ # now adjust the table to the correct location across the page
357
+ case @position
358
+ when :left
359
+ xref = pdf.absolute_left_margin
360
+ when :right
361
+ xref = pdf.absolute_right_margin
362
+ when :center
363
+ xref = pdf.margin_x_middle
364
+ else
365
+ xref = @position
366
+ end
367
+
368
+ case @orientation
369
+ when :left
370
+ dx = xref - t
371
+ when :right
372
+ dx = xref
373
+ when :center
374
+ dx = xref - (t / 2.0)
375
+ else
376
+ dx = xref + @orientation
377
+ end
378
+
379
+ pos.each { |k, v| pos[k] = v + dx }
380
+
381
+ base_x0 = x0 = x + dx
382
+ base_x1 = x1 = t + dx
383
+
384
+ base_left_margin = pdf.absolute_left_margin
385
+ base_pos = pos.dup
386
+
387
+ # Ok, just about ready to make me a table.
388
+ pdf.fill_color @text_color
389
+ pdf.stroke_color @shade_color
390
+
391
+ middle = (x0 + x1) / 2.0
392
+
393
+ # Start a transaction. This transaction will be used to regress the
394
+ # table if there are not enough rows protected.
395
+ tg = Transaction::Simple::Group.new(pdf, self)
396
+ tg.start_transaction(:table)
397
+ moved_once = false if @protect_rows.nonzero?
398
+
399
+ abortTable = true
400
+ loop do # while abortTable
401
+ break unless abortTable
402
+ abortTable = false
403
+
404
+ dm = pdf.absolute_left_margin - base_left_margin
405
+ base_pos.each { |k, v| pos[k] = v + dm }
406
+ x0 = base_x0 + dm
407
+ x1 = base_x1 + dm
408
+ middle = (x0 + x1) / 2.0
409
+
410
+ # If the title is set, then render it.
411
+ unless @title.nil? or @title.empty?
412
+ w = pdf.text_width(@title, @title_font_size)
413
+ _y = pdf.y - pdf.font_height(@title_font_size)
414
+ if _y < pdf.absolute_bottom_margin
415
+ pdf.start_new_page
416
+
417
+ # margins may have changed on the new page
418
+ dm = pdf.absolute_left_margin - base_left_margin
419
+ base_pos.each { |k, v| pos[k] = v + dm }
420
+ x0 = base_x0 + dm
421
+ x1 = base_x1 + dm
422
+ middle = (x0 + x1) / 2.0
423
+ end
424
+
425
+ pdf.y -= pdf.font_height(@title_font_size)
426
+ pdf.fill_color @title_color
427
+ pdf.add_text(middle - w / 2.0, pdf.y, title, @title_font_size)
428
+ pdf.y -= @title_gap
429
+ end
430
+
431
+ # Margins may have changed on the new_page.
432
+ dm = pdf.absolute_left_margin - base_left_margin
433
+ base_pos.each { |k, v| pos[k] = v + dm }
434
+ x0 = base_x0 + dm
435
+ x1 = base_x1 + dm
436
+ middle = (x0 + x1) / 2.0
437
+
438
+ y = pdf.y # simplifies the code a bit
439
+ low_y = y if low_y.nil? or y < low_y
440
+
441
+ # Make the table
442
+ height = pdf.font_height @font_size
443
+ descender = pdf.font_descender @font_size
444
+
445
+ y0 = y + descender
446
+ dy = 0
447
+
448
+ if @show_headings
449
+ # This function will move the start of the table to a new page if
450
+ # it does not fit on this one.
451
+ hOID = __open_new_object__(pdf) if @shade_headings
452
+ pdf.fill_color @heading_color
453
+ _height, y = __table_column_headings__(pdf, pos, max_width, height,
454
+ descender, @row_gap, @heading_font_size, y)
455
+ pdf.fill_color @text_color
456
+ y0 = y + _height
457
+ y1 = y
458
+
459
+ if @shade_headings
460
+ pdf.close_object
461
+ pdf.fill_color! @shade_heading_color
462
+ pdf.rectangle(x0 - @gap / 2.0, y, x1 - x0, _height).fill
463
+ pdf.reopen_object(hOID)
464
+ pdf.close_object
465
+ pdf.restore_state
466
+ end
467
+
468
+ # Margins may have changed on the new_page
469
+ dm = pdf.absolute_left_margin - base_left_margin
470
+ base_pos.each { |k, v| pos[k] = v + dm }
471
+ x0 = base_x0 + dm
472
+ x1 = base_x1 + dm
473
+ middle = (x0 + x1) / 2.0
474
+ else
475
+ y1 = y0
476
+ end
477
+
478
+ first_line = true
479
+
480
+ # open an object here so that the text can be put in over the
481
+ # shading
482
+ tOID = __open_new_object__(pdf) unless :none == @shade_rows
483
+
484
+ cnt = 0
485
+ cnt = 1 unless @shade_headings
486
+ newPage = false
487
+ @data.each do |row|
488
+ cnt += 1
489
+ # Start a transaction that will be used for this row to prevent it
490
+ # from being split.
491
+ unless @split_rows
492
+ pageStart = pdf.pageset.size
493
+
494
+ columnStart = pdf.column_number if pdf.columns?
495
+
496
+ tg.start_transaction(:row)
497
+ row_orig = row
498
+ y_orig = y
499
+ y0_orig = y0
500
+ y1_orig = y1
501
+ end # unless @split_rows
502
+
503
+ ok = false
504
+ second_turn = false
505
+ loop do # while !abortTable and !ok
506
+ break if abortTable or ok
507
+
508
+ mx = 0
509
+ newRow = true
510
+
511
+ loop do # while !abortTable and (newPage or newRow)
512
+ break if abortTable or not (newPage or newRow)
513
+
514
+ y -= height
515
+ low_y = y if low_y.nil? or y < low_y
516
+
517
+ if newPage or y < (pdf.absolute_bottom_margin + @minimum_space)
518
+ # check that enough rows are with the heading
519
+ moved_once = abortTable = true if @protect_rows.nonzero? and not moved_once and cnt <= @protect_rows
520
+
521
+ y2 = y - mx + (2 * height) + descender - (newRow ? 1 : 0) * height
522
+
523
+ unless :none == @show_lines
524
+ y0 = y1 unless @show_headings
525
+
526
+ __table_draw_lines__(pdf, pos, @gap, x0, x1, y0, y1, y2,
527
+ @line_color, @inner_line_style, @outer_line_style,
528
+ @show_lines)
529
+ end
530
+
531
+ unless :none == @shade_rows
532
+ pdf.close_object
533
+ pdf.restore_state
534
+ end
535
+
536
+ pdf.start_new_page
537
+ pdf.save_state
538
+
539
+ # and the margins may have changed, this is due to the
540
+ # possibility of the columns being turned on as the columns are
541
+ # managed by manipulating the margins
542
+ dm = pdf.absolute_left_margin - base_left_margin
543
+ base_pos.each { |k, v| pos[k] = v + dm }
544
+ x0 = base_x0 + dm
545
+ x1 = base_x1 + dm
546
+
547
+ tOID = __open_new_object__(pdf) unless :none == @shade_rows
548
+
549
+ pdf.fill_color! @text_color
550
+
551
+ y = pdf.absolute_top_margin - @header_gap
552
+ low_y = y
553
+ y0 = y + descender
554
+ mx = 0
555
+
556
+ if @show_headings
557
+ old_y = y
558
+
559
+ pdf.fill_color @heading_color
560
+ _height, y = __table_column_headings__(pdf, pos, max_width,
561
+ height, descender, @row_gap, @heading_font_size, y)
562
+ pdf.fill_color @text_color
563
+
564
+ y0 = y + _height
565
+ y1 = y
566
+
567
+ if @shade_headings
568
+ pdf.fill_color! @shade_heading_color
569
+ pdf.rectangle(x0 - @gap / 2, y, x1 - x0, _height).fill
570
+ pdf.fill_color @heading_color
571
+ __table_column_headings__(pdf, pos, max_width, height,
572
+ descender, @row_gap,
573
+ @heading_font_size, old_y)
574
+ pdf.fill_color @text_color
575
+ end
576
+
577
+ dm = pdf.absolute_left_margin - base_left_margin
578
+ base_pos.each { |k, v| pos[k] = v + dm }
579
+ x0 = base_x0 + dm
580
+ x1 = base_x1 + dm
581
+ middle = (x0 + x1) / 2.0
582
+ else
583
+ y1 = y0
584
+ end
585
+
586
+ first_line = true
587
+ y -= height
588
+ low_y = y if low_y.nil? or y < low_y
589
+ end
590
+
591
+ newRow = false
592
+
593
+ # Write the actual data. If these cells need to be split over
594
+ # a page, then newPage will be set, and the remaining text
595
+ # will be placed in leftOvers
596
+ newPage = false
597
+ leftOvers = PDF::Writer::OHash.new
598
+
599
+ @cols.each do |name, column|
600
+ pdf.pointer = y + height
601
+ colNewPage = false
602
+
603
+ unless row[name].nil?
604
+ lines = row[name].to_s.split(/\n/)
605
+ if column and column.link_name
606
+ lines.map! do |kk|
607
+ link = row[column.link_name]
608
+ if link
609
+ "<c:alink uri='#{link}'>#{kk}</c:alink>"
610
+ else
611
+ kk
612
+ end
613
+ end
614
+ end
615
+ else
616
+ lines = []
617
+ end
618
+
619
+ pdf.y -= @row_gap
620
+
621
+ lines.each do |line|
622
+ pdf.send(:preprocess_text, line)
623
+ start = true
624
+
625
+ loop do
626
+ break if (line.nil? or line.empty?) and not start
627
+ start = false
628
+
629
+ _y = pdf.y - height if not colNewPage
630
+
631
+ # a new page is required
632
+ newPage = colNewPage = true if _y < pdf.absolute_bottom_margin
633
+
634
+ if colNewPage
635
+ if leftOvers[name].nil?
636
+ leftOvers[name] = [line]
637
+ else
638
+ leftOvers[name] << "\n#{line}"
639
+ end
640
+ line = nil
641
+ else
642
+ if column and column.justification
643
+ just = column.justification
644
+ end
645
+ just ||= :left
646
+
647
+ pdf.y = _y
648
+ line = pdf.add_text_wrap(pos[name], pdf.y,
649
+ max_width[name], line,
650
+ @font_size, just)
651
+ end
652
+ end
653
+ end
654
+
655
+ dy = y + height - pdf.y + @row_gap
656
+ mx = dy - height * (newPage ? 1 : 0) if (dy - height * (newPage ? 1 : 0)) > mx
657
+ end
658
+
659
+ # Set row to leftOvers so that they will be processed onto the
660
+ # new page
661
+ row = leftOvers
662
+
663
+ # Now add the shading underneath
664
+ unless :none == @shade_rows
665
+ pdf.close_object
666
+
667
+ if (cnt % 2).zero?
668
+ pdf.fill_color!(@shade_color)
669
+ pdf.rectangle(x0 - @gap / 2.0, y + descender + height - mx, x1 - x0, mx).fill
670
+ elsif (cnt % 2).nonzero? and :striped == @shade_rows
671
+ pdf.fill_color!(@shade_color2)
672
+ pdf.rectangle(x0 - @gap / 2.0, y + descender + height - mx, x1 - x0, mx).fill
673
+ end
674
+ pdf.reopen_object(tOID)
675
+ end
676
+
677
+ if :inner == @show_lines or :all == @show_lines
678
+ # draw a line on the top of the block
679
+ pdf.save_state
680
+ pdf.stroke_color! @line_color
681
+ if first_line
682
+ pdf.stroke_style @outer_line_style
683
+ first_line = false
684
+ else
685
+ pdf.stroke_style @inner_line_style
686
+ end
687
+ pdf.line(x0 - @gap / 2.0, y + descender + height, x1 - @gap / 2.0, y + descender + height).stroke
688
+ pdf.restore_state
689
+ end
690
+ end
691
+
692
+ y = y - mx + height
693
+ pdf.y = y
694
+ low_y = y if low_y.nil? or y < low_y
695
+
696
+ # checking row split over pages
697
+ unless @split_rows
698
+ if (((pdf.pageset.size != pageStart) or (pdf.columns? and columnStart != pdf.column_number)) and not second_turn)
699
+ # then we need to go back and try that again!
700
+ newPage = second_turn = true
701
+ tg.rewind_transaction(:row)
702
+ row = row_orig
703
+ low_y = y = y_orig
704
+ y0 = y0_orig
705
+ y1 = y1_orig
706
+ ok = false
707
+
708
+ dm = pdf.absolute_left_margin - base_left_margin
709
+ base_pos.each { |k, v| pos[k] = v + dm }
710
+ x0 = base_x0 + dm
711
+ x1 = base_x1 + dm
712
+ else
713
+ tg.commit_transaction(:row)
714
+ ok = true
715
+ end
716
+ else
717
+ ok = true # don't go 'round the loop if splitting rows is allowed
718
+ end
719
+ end
720
+
721
+ if abortTable
722
+ # abort_transaction if not ok only the outer transaction should
723
+ # be operational.
724
+ tg.rewind_transaction(:table)
725
+ pdf.start_new_page
726
+ # fix a bug where a moved table will take up the whole page.
727
+ low_y = nil
728
+ pdf.save_state
729
+ break
730
+ end
731
+ end
732
+ end
733
+
734
+ if low_y <= y
735
+ y2 = low_y + descender
736
+ else
737
+ y2 = y + descender
738
+ end
739
+
740
+ unless :none == @show_lines
741
+ y0 = y1 unless @show_headings
742
+
743
+ __table_draw_lines__(pdf, pos, @gap, x0, x1, y0, y1, y2, @line_color,
744
+ @inner_line_style, @outer_line_style, @show_lines)
745
+ end
746
+
747
+ # close the object for drawing the text on top
748
+ unless :none == @shade_rows
749
+ pdf.close_object
750
+ pdf.restore_state
751
+ end
752
+
753
+ pdf.y = low_y
754
+
755
+ # Table has been put on the page, the rows guarded as required; commit.
756
+ tg.commit_transaction(:table)
757
+
758
+ y
759
+ rescue Exception => ex
760
+ begin
761
+ tg.abort_transaction(:table) if tg.transaction_open?
762
+ rescue
763
+ nil
764
+ end
765
+ raise ex
766
+ end
767
+
768
+ WIDTH_FACTOR = 1.01
769
+
770
+ # Find the maximum widths of the text within each column. Default to
771
+ # zero.
772
+ def __find_table_max_width__(pdf)
773
+ max_width = PDF::Writer::OHash.new(-1)
774
+
775
+ # Find the maximum cell widths based on the data and the headings.
776
+ # Passing through the data multiple times is unavoidable as we must
777
+ # do some analysis first.
778
+ @data.each do |row|
779
+ @cols.each do |name, column|
780
+ w = pdf.text_width(row[name].to_s, @font_size)
781
+ w *= PDF::SimpleTable::WIDTH_FACTOR
782
+
783
+ max_width[name] = w if w > max_width[name]
784
+ end
785
+ end
786
+
787
+ @cols.each do |name, column|
788
+ title = column.heading.title if column.heading
789
+ title ||= column.name
790
+ w = pdf.text_width(title, @heading_font_size)
791
+ w *= PDF::SimpleTable::WIDTH_FACTOR
792
+ max_width[name] = w if w > max_width[name]
793
+ end
794
+ max_width
795
+ end
796
+ private :__find_table_max_width__
797
+
798
+ # Calculate the start positions of each of the columns. This is based
799
+ # on max_width, but may be modified with column options.
800
+ def __find_table_positions__(pdf, max_width)
801
+ pos = PDF::Writer::OHash.new
802
+ x = t = adjustment_width = set_width = 0
803
+
804
+ max_width.each do |name, w|
805
+ pos[name] = t
806
+ # If the column width has been specified then set that here, also
807
+ # total the width avaliable for adjustment.
808
+ if not @cols[name].nil? and
809
+ not @cols[name].width.nil? and
810
+ @cols[name].width > 0
811
+ t += @cols[name].width
812
+ max_width[name] = @cols[name].width - @gap
813
+ set_width += @cols[name].width
814
+ else
815
+ t += w + @gap
816
+ adjustment_width += w
817
+ set_width += @gap
818
+ end
819
+ end
820
+ pos[:__last_column__] = t
821
+
822
+ [pos, t, x, adjustment_width, set_width]
823
+ end
824
+ private :__find_table_positions__
825
+
826
+ # Uses ezText to add the text, and returns the height taken by the
827
+ # largest heading. This page will move the headings to a new page if
828
+ # they will not fit completely on this one transaction support will be
829
+ # used to implement this.
830
+ def __table_column_headings__(pdf, pos, max_width, height, descender, gap, size, y)
831
+ mx = second_go = 0
832
+ start_page = pdf.pageset.size
833
+
834
+ # y is the position at which the top of the table should start, so the
835
+ # base of the first text, is y-height-gap-descender, but ezText starts
836
+ # by dropping height.
837
+
838
+ # The return from this function is the total cell height, including
839
+ # gaps, and y is adjusted to be the postion of the bottom line.
840
+ tg = Transaction::Simple::Group.new(pdf, self)
841
+ tg.start_transaction(:column_headings)
842
+
843
+ ok = false
844
+ y -= gap
845
+ loop do
846
+ break if ok
847
+ @cols.each do |name, column|
848
+ pdf.pointer = y
849
+
850
+ if column.heading
851
+ justification = column.heading.justification
852
+ bold = column.heading.bold
853
+ title = column.heading.title
854
+ end
855
+
856
+ justification ||= :left
857
+ bold ||= @bold_headings
858
+ title ||= column.name
859
+
860
+ title = "<b>#{title}</b>" if bold
861
+
862
+ pdf.text(title, :font_size => size, :absolute_left => pos[name],
863
+ :absolute_right => (max_width[name] + pos[name]),
864
+ :justification => justification)
865
+ dy = y - pdf.y
866
+ mx = dy if dy > mx
867
+ end
868
+
869
+ y -= (mx + gap) - descender # y = y - mx - gap + descender
870
+
871
+ # If this has been moved to a new page, then abort the transaction;
872
+ # move to a new page, and put it there. Do not check on the second
873
+ # time around to avoid an infinite loop.
874
+ if (pdf.pageset.size != start_page and not second_go)
875
+ tg.rewind_transaction(:column_headings)
876
+
877
+ pdf.start_new_page
878
+ save_state
879
+ y = @y - gap - descender
880
+ ok = false
881
+ second_go = true
882
+ mx = 0
883
+ else
884
+ tg.commit_transaction(:column_headings)
885
+ ok = true
886
+ end
887
+ end
888
+
889
+ return [mx + gap * 2 - descender, y]
890
+ rescue Exception => ex
891
+ begin
892
+ tg.abort_transaction(:column_headings) if tg.transaction_open?(:column_headings)
893
+ rescue
894
+ nil
895
+ end
896
+ raise ex
897
+ end
898
+ private :__table_column_headings__
899
+
900
+ def __table_draw_lines__(pdf, pos, gap, x0, x1, y0, y1, y2, col, inner, outer, opt = :outer)
901
+ x0 = 1000
902
+ x1 = 0
903
+
904
+ pdf.stroke_color(col)
905
+
906
+ cnt = 0
907
+ n = pos.size
908
+
909
+ pos.each do |name, x|
910
+ cnt += 1
911
+
912
+ if (cnt == 1 or cnt == n)
913
+ pdf.stroke_style outer
914
+ else
915
+ pdf.stroke_style inner
916
+ end
917
+
918
+ pdf.line(x - gap / 2.0, y0, x - gap / 2.0, y2).stroke
919
+ x1 = x if x > x1
920
+ x0 = x if x < x0
921
+ end
922
+
923
+ pdf.stroke_style outer
924
+
925
+ pdf.line(x0 - (gap / 2.0) - (outer.width / 2.0), y0,
926
+ x1 - (gap / 2.0) + (outer.width / 2.0), y0).stroke
927
+
928
+ # Only do the second line if it is different than the first AND each
929
+ # row does not have a line on it.
930
+ if y0 != y1 and @show_lines == :outer
931
+ pdf.line(x0 - gap / 2.0, y1, x1 - gap / 2.0, y1).stroke
932
+ end
933
+ pdf.line(x0 - (gap / 2.0) - (outer.width / 2.0), y2,
934
+ x1 - (gap / 2.0) + (outer.width / 2.0), y2).stroke
935
+ end
936
+ private :__table_draw_lines__
937
+
938
+ def __open_new_object__(pdf)
939
+ pdf.save_state
940
+ tOID = pdf.open_object
941
+ pdf.close_object
942
+ pdf.add_object(tOID)
943
+ pdf.reopen_object(tOID)
944
+ tOID
945
+ end
946
+ private :__open_new_object__
947
+ end