class PDF::SimpleTable

This class will create tables with a relatively simple API and internal implementation.

Constants

VERSION
WIDTH_FACTOR

Attributes

bold_headings[RW]

Makes the heading text bold if true. Defaults to false.

column_gap[RW]

The space, in PDF user units, on the left and right sides of each cell. Default 5 units.

column_order[RW]

An array that defines the order of the columns in the table. The values in this array are the column names in data. The columns will be presented in the order defined here.

columns[RW]

An array that defines columns and column options for the table. The entries should be PDF::SimpleTable::Column objects.

data[RW]

An array of Hash entries. Each row is a Hash where the keys are the names of the columns as specified in column_order and the values are the values of the cell.

font_size[RW]

The font size of the data cells, in points. Defaults to 10 points.

header_gap[RW]

The number of PDF user units to leave open at the top of a page after a page break. This is typically used for a repeating page header, etc. Defaults to zero units.

heading_color[RW]

The text colour of the heading. Defaults to Color::RGB::Black.

heading_font_size[RW]

The font size of the heading cells, in points. Defaults to 12 points.

inner_line_style[RW]

Defines the inner line style. The default style is a solid line with a thickness of 1 unit.

line_color[RW]

The colour of the table lines. Defaults to Color::RGB::Black.

maximum_width[RW]

Specifies the maximum width of the table. The table will not grow larger than this width under any circumstances.

Defaults to zero, which indicates that there is no maximum width (aside from the margin size).

minimum_space[RW]

The minimum space between the bottom of each row and the bottom margin. If the amount of space is less than this, a new page will be started. Default is 100 PDF user units.

orientation[RW]

The orientation of the table relative to position.

:left

The table is to the left of position.

:right

The table is to the right of position.

:center

The table is centred at position.

offset

The left of the table is offset from position.

outer_line_style[RW]

Defines the outer line style. The default style is a solid line with a thickness of 1 unit.

position[RW]

The x position of the table. This will be one of:

:left

Aligned with the left margin.

:right

Aligned with the right margin.

:center

Centered between the margins. Default.

offset

The absolute position of the table, relative from the left margin.

protect_rows[RW]

The number of rows to hold with the heading on the page. If there are less than this number of rows on the page, then move the whole lot onto the next page. Default is one row.

row_gap[RW]

The space, in PDF user units, added to the top and bottom of each row between the text and the lines of the cell. Default 2 units.

shade_color[RW]

The main row shading colour. Defaults to Color::RGB::Grey80. Used with shade_rows of :shaded and :striped.

shade_color2[RW]

The alternate row shading colour, used with shade_rows of :striped. Defaults to Color::RGB::Grey70.

shade_heading_color[RW]

Defines the colour of the background shading for the heading if shade_headings is true. Default is Color::RGB::Grey90.

shade_headings[RW]

Places a background colour in the heading if true.

shade_rows[RW]

Controls row shading.

:none

No row shading; all rows are the standard background colour.

:shaded

Alternate lines will be shaded; half of the rows will be the standard background colour; the rest of the rows will be shaded with shade_color. Default

:striped

Alternate lines will be shaded; half of the rows will be shaded with shade_color; the rest of the rows will be shaded with shade_color2.

show_headings[RW]

Displays the headings for the table if true. The default is true.

show_lines[RW]

Whether to display the lines on the table or not. Valid values are:

:none

Displays no lines.

:outer

Displays outer lines only. Default

:inner

Displays inner lines only.

:all

Displays all lines, inner and outer.

split_rows[RW]

Allows a table’s rows to be split across page boundaries if true. This defaults to false.

text_color[RW]

The text colour of the body cells. Defaults to Color::RGB::Black.

title[RW]

The title to be put on the top of the table.

title_color[RW]

The text colour of the title. Defaults to Color::RGB::Black.

title_font_size[RW]

The font size of the title, in points. Defaults to 12 points.

title_gap[RW]

The gap, in PDF units, between the title and the table. Defaults to 5 units.

width[RW]

Specifies the width of the table. If the table is smaller than the provided width, columns are proportionally stretched to fit the width of the table. If the table is wider than the provided width, columns are proportionally shrunk to fit the width of the table. Content may need to wrap in this case.

Defaults to zero, which indicates that the size whould be determined automatically based on the content and the margins.

Public Class Methods

new() { |self| ... } click to toggle source
    # File lib/pdf/simpletable.rb
 70 def initialize
 71   @column_order = []
 72   @data         = []
 73   @columns      = {}
 74 
 75   @show_lines           = :outer
 76   @show_headings        = true
 77   @shade_rows           = :shaded
 78   @shade_color          = Color::RGB::Grey80
 79   @shade_color2         = Color::RGB::Grey70
 80   @shade_headings       = false
 81   @shade_heading_color  = Color::RGB::Grey90
 82   @font_size            = 10
 83   @heading_font_size    = 12
 84   @title_font_size      = 12
 85   @title_gap            = 5
 86   @title_color          = Color::RGB::Black
 87   @heading_color        = Color::RGB::Black
 88   @text_color           = Color::RGB::Black
 89   @line_color           = Color::RGB::Black
 90   @position             = :center
 91   @orientation          = :center
 92   @bold_headings        = false
 93 
 94   @cols                 = PDF::Writer::OHash.new
 95   @width                = 0
 96   @maximum_width        = 0
 97 
 98   @gap                  = 5
 99   @row_gap              = 2
100   @column_gap           = 5
101   @header_gap           = 0
102 
103   @minimum_space        = 0
104   @protect_rows         = 1
105   @split_rows           = false
106 
107   @inner_line_style     = PDF::Writer::StrokeStyle.new(1)
108   @outer_line_style     = PDF::Writer::StrokeStyle.new(1)
109 
110   yield self if block_given?
111 end

Public Instance Methods

render_on(pdf) click to toggle source

Render the table on the PDF::Writer document provided.

    # File lib/pdf/simpletable.rb
239 def render_on(pdf)
240   if @column_order.empty?
241     raise TypeError, PDF::Writer::Lang[:simpletable_columns_undefined]
242   end
243   if @data.empty?
244     raise TypeError, PDF::Writer::Lang[:simpletable_data_empty]
245   end
246 
247   low_y = descender = y0 = y1 = y = nil
248 
249   @cols = PDF::Writer::OHash.new
250   @column_order.each do |name|
251     col = @columns[name]
252     if col
253       @cols[name] = col
254     else
255       @cols[name] = PDF::SimpleTable::Column.new(name)
256     end
257   end
258 
259   @gap = 2 * @column_gap
260 
261   max_width = __find_table_max_width__(pdf)
262   pos, t, x, adjustment_width, set_width = __find_table_positions__(pdf, max_width)
263 
264   # if max_width is specified, and the table is too wide, and the width
265   # has not been set, then set the width.
266   if @width.zero? and @maximum_width.nonzero? and ((t - x) > @maximum_width)
267     @width = @maximum_width
268   end
269 
270   if @width and (adjustment_width > 0) and (set_width < @width)
271       # First find the current widths of the columns involved in this
272       # mystery
273     cols0 = PDF::Writer::OHash.new
274     cols1 = PDF::Writer::OHash.new
275 
276     xq = presentWidth = 0
277     last = nil
278 
279     pos.each do |name, colpos|
280       if @cols[last].nil? or
281         @cols[last].width.nil? or
282         @cols[last].width <= 0
283         unless last.nil? or last.empty?
284           cols0[last] = colpos - xq - @gap
285           presentWidth += (colpos - xq - @gap)
286         end
287       else
288         cols1[last] = colpos - xq
289       end
290       last = name
291       xq = colpos
292     end
293 
294     # cols0 contains the widths of all the columns which are not set
295     needed_width = @width - set_width
296 
297       # If needed width is negative then add it equally to each column,
298       # else get more tricky.
299     if presentWidth < needed_width
300       diff = (needed_width - presentWidth) / cols0.size.to_f
301       cols0.each_key { |name| cols0[name] += diff }
302     else
303       cnt = 0
304       loop do
305         break if (presentWidth <= needed_width) or (cnt >= 100)
306         cnt += 1 # insurance policy
307           # Find the widest columns and the next to widest width
308         aWidest = []
309         nWidest = widest = 0
310         cols0.each do |name, w|
311           if w > widest
312             aWidest = [ name ]
313             nWidest = widest
314             widest = w
315           elsif w == widest
316             aWidest << name
317           end
318         end
319 
320         # Then figure out what the width of the widest columns would
321         # have to be to take up all the slack.
322         newWidestWidth = widest - (presentWidth - needed_width) / aWidest.size.to_f
323         if newWidestWidth > nWidest
324           aWidest.each { |name| cols0[name] = newWidestWidth }
325           presentWidth = needed_width
326         else
327           # There is no space, reduce the size of the widest ones down
328           # to the next size down, and we will go round again
329           aWidest.each { |name| cols0[name] = nWidest }
330           presentWidth -= (widest - nWidest) * aWidest.size
331         end
332       end
333     end
334 
335       # cols0 now contains the new widths of the constrained columns. now
336       # need to update the pos and max_width arrays
337     xq = 0
338     pos.each do |name, colpos|
339       pos[name] = xq
340 
341       if @cols[name].nil? or
342         @cols[name].width.nil? or
343         @cols[name].width <= 0
344         if not cols0[name].nil?
345           xq += cols0[name] + @gap
346           max_width[name] = cols0[name]
347         end
348       else
349         xq += cols1[name] unless cols1[name].nil?
350       end
351     end
352 
353     t = x + @width
354     pos[:__last_column__] = t
355   end
356 
357   # now adjust the table to the correct location across the page
358   case @position
359   when :left
360     xref = pdf.absolute_left_margin
361   when :right
362     xref = pdf.absolute_right_margin
363   when :center
364     xref = pdf.margin_x_middle
365   else
366     xref = @position
367   end
368 
369   case @orientation
370   when :left
371     dx = xref - t
372   when :right
373     dx = xref
374   when :center
375     dx = xref - (t / 2.0)
376   else
377     dx = xref + @orientation
378   end
379 
380   pos.each { |k, v| pos[k] = v + dx }
381 
382   base_x0 = x0 = x + dx
383   base_x1 = x1 = t + dx
384 
385   base_left_margin = pdf.absolute_left_margin
386   base_pos = pos.dup
387 
388     # Ok, just about ready to make me a table.
389   pdf.fill_color @text_color
390   pdf.stroke_color @shade_color 
391 
392   middle = (x0 + x1) / 2.0
393 
394     # Start a transaction. This transaction will be used to regress the
395     # table if there are not enough rows protected.
396   tg = Transaction::Simple::Group.new(pdf, self)
397   tg.start_transaction(:table)
398   moved_once = false if @protect_rows.nonzero?
399 
400   abortTable = true
401   loop do # while abortTable
402     break unless abortTable
403     abortTable = false
404 
405     dm = pdf.absolute_left_margin - base_left_margin
406     base_pos.each { |k, v| pos[k] = v + dm }
407     x0 = base_x0 + dm
408     x1 = base_x1 + dm
409     middle = (x0 + x1) / 2.0
410 
411       # If the title is set, then render it.
412     unless @title.nil? or @title.empty?
413       w = pdf.text_width(@title, @title_font_size)
414       _y = pdf.y - pdf.font_height(@title_font_size)
415       if _y < pdf.absolute_bottom_margin
416         pdf.start_new_page
417 
418           # margins may have changed on the new page
419         dm = pdf.absolute_left_margin - base_left_margin
420         base_pos.each { |k, v| pos[k] = v + dm }
421         x0 = base_x0 + dm
422         x1 = base_x1 + dm
423         middle = (x0 + x1) / 2.0
424       end
425 
426       pdf.y -= pdf.font_height(@title_font_size)
427       pdf.fill_color @title_color
428       pdf.add_text(middle - w / 2.0, pdf.y, title, @title_font_size)
429       pdf.y -= @title_gap
430     end
431 
432       # Margins may have changed on the new_page.
433     dm = pdf.absolute_left_margin - base_left_margin
434     base_pos.each { |k, v| pos[k] = v + dm }
435     x0 = base_x0 + dm
436     x1 = base_x1 + dm
437     middle = (x0 + x1) / 2.0
438 
439     y = pdf.y  # simplifies the code a bit
440     low_y = y if low_y.nil? or y < low_y 
441 
442       # Make the table
443     height = pdf.font_height @font_size
444     descender = pdf.font_descender @font_size
445 
446     y0 = y + descender
447     dy = 0
448 
449     if @show_headings
450       # This function will move the start of the table to a new page if
451       # it does not fit on this one.
452       hOID = __open_new_object__(pdf) if @shade_headings
453       pdf.fill_color @heading_color
454       _height, y = __table_column_headings__(pdf, pos, max_width, height,
455         descender, @row_gap, @heading_font_size, y)
456       pdf.fill_color @text_color
457       y0 = y + _height
458       y1 = y
459 
460       if @shade_headings
461         pdf.close_object
462         pdf.fill_color! @shade_heading_color
463         pdf.rectangle(x0 - @gap / 2.0, y, x1 - x0, _height).fill
464         pdf.reopen_object(hOID)
465         pdf.close_object
466         pdf.restore_state
467       end
468 
469         # Margins may have changed on the new_page
470       dm = pdf.absolute_left_margin - base_left_margin
471       base_pos.each { |k, v| pos[k] = v + dm }
472       x0 = base_x0 + dm
473       x1 = base_x1 + dm
474       middle = (x0 + x1) / 2.0
475     else
476       y1 = y0
477     end
478 
479     first_line = true
480 
481     # open an object here so that the text can be put in over the
482     # shading
483     tOID = __open_new_object__(pdf) unless :none == @shade_rows
484 
485     cnt = 0
486     cnt = 1 unless @shade_headings
487     newPage = false
488     @data.each do |row|
489       cnt += 1
490         # Start a transaction that will be used for this row to prevent it
491         # from being split.
492       unless @split_rows
493         pageStart = pdf.pageset.size
494 
495         columnStart = pdf.column_number if pdf.columns?
496 
497         tg.start_transaction(:row)
498         row_orig = row
499         y_orig = y
500         y0_orig = y0
501         y1_orig = y1
502       end # unless @split_rows
503 
504       ok = false
505       second_turn = false
506       loop do # while !abortTable and !ok
507         break if abortTable or ok
508 
509         mx = 0
510         newRow = true
511 
512         loop do # while !abortTable and (newPage or newRow)
513           break if abortTable or not (newPage or newRow)
514 
515           y -= height
516           low_y = y if low_y.nil? or y < low_y 
517 
518           if newPage or y < (pdf.absolute_bottom_margin + @minimum_space)
519               # check that enough rows are with the heading
520             moved_once = abortTable = true if @protect_rows.nonzero? and not moved_once and cnt <= @protect_rows
521 
522             y2 = y - mx + (2 * height) + descender - (newRow ? 1 : 0) * height
523 
524             unless :none == @show_lines
525               y0 = y1 unless @show_headings
526 
527               __table_draw_lines__(pdf, pos, @gap, x0, x1, y0, y1, y2,
528                 @line_color, @inner_line_style, @outer_line_style,
529                 @show_lines)
530             end
531 
532             unless :none == @shade_rows
533               pdf.close_object
534               pdf.restore_state
535             end
536 
537             pdf.start_new_page
538             pdf.save_state
539 
540               # and the margins may have changed, this is due to the
541               # possibility of the columns being turned on as the columns are
542               # managed by manipulating the margins
543             dm = pdf.absolute_left_margin - base_left_margin
544             base_pos.each { |k, v| pos[k] = v + dm }
545             x0 = base_x0 + dm
546             x1 = base_x1 + dm
547 
548             tOID = __open_new_object__(pdf) unless :none == @shade_rows
549 
550             pdf.fill_color! @text_color
551 
552             y = pdf.absolute_top_margin - @header_gap
553             low_y = y
554             y0 = y + descender
555             mx = 0
556 
557             if @show_headings
558               old_y = y
559 
560               pdf.fill_color @heading_color
561               _height, y = __table_column_headings__(pdf, pos, max_width,
562                 height, descender, @row_gap, @heading_font_size, y)
563               pdf.fill_color @text_color
564 
565               y0 = y + _height
566               y1 = y
567 
568               if @shade_headings
569                 pdf.fill_color! @shade_heading_color
570                 pdf.rectangle(x0 - @gap / 2, y, x1 - x0, _height).fill
571                 pdf.fill_color @heading_color
572                 __table_column_headings__(pdf, pos, max_width, height,
573                                           descender, @row_gap,
574                                           @heading_font_size, old_y)
575                 pdf.fill_color @text_color
576               end
577 
578               dm = pdf.absolute_left_margin - base_left_margin
579               base_pos.each { |k, v| pos[k] = v + dm }
580               x0 = base_x0 + dm
581               x1 = base_x1 + dm
582               middle = (x0 + x1) / 2.0
583             else
584               y1 = y0
585             end
586 
587             first_line = true
588             y -= height
589             low_y = y if low_y.nil? or y < low_y 
590           end
591 
592           newRow = false
593 
594             # Write the actual data. If these cells need to be split over
595             # a page, then newPage will be set, and the remaining text
596             # will be placed in leftOvers
597           newPage = false
598           leftOvers = PDF::Writer::OHash.new
599 
600           @cols.each do |name, column|
601             pdf.pointer = y + height
602             colNewPage = false
603 
604             unless row[name].nil?
605               lines = row[name].to_s.split(/\n/)
606               if column and column.link_name
607                 lines.map! do |kk|
608                   link = row[column.link_name]
609                   if link
610                     "<c:alink uri='#{link}'>#{kk}</c:alink>"
611                   else
612                     kk
613                   end
614                 end
615               end
616             else
617               lines = []
618             end
619 
620             pdf.y -= @row_gap
621 
622             lines.each do |line|
623               pdf.send(:preprocess_text, line)
624               start = true
625 
626               loop do
627                 break if (line.nil? or line.empty?) and not start
628                 start = false
629 
630                 _y = pdf.y - height if not colNewPage
631 
632                   # a new page is required
633                 newPage = colNewPage = true if _y < pdf.absolute_bottom_margin
634 
635                 if colNewPage
636                   if leftOvers[name].nil?
637                     leftOvers[name] = [line]
638                   else
639                     leftOvers[name] << "\n#{line}"
640                   end
641                   line = nil
642                 else
643                   if column and column.justification
644                     just = column.justification
645                   end
646                   just ||= :left
647 
648                   pdf.y = _y
649                   line = pdf.add_text_wrap(pos[name], pdf.y,
650                                            max_width[name], line,
651                                            @font_size, just)
652                 end
653               end
654             end
655 
656             dy = y + height - pdf.y + @row_gap
657             mx = dy - height * (newPage ? 1 : 0) if (dy - height * (newPage ? 1 : 0)) > mx
658           end
659 
660             # Set row to leftOvers so that they will be processed onto the
661             # new page
662           row = leftOvers
663 
664           # Now add the shading underneath
665           unless :none == @shade_rows
666             pdf.close_object
667 
668             if (cnt % 2).zero?
669               pdf.fill_color!(@shade_color)
670               pdf.rectangle(x0 - @gap / 2.0, y + descender + height - mx, x1 - x0, mx).fill
671             elsif (cnt % 2).nonzero? and :striped == @shade_rows
672               pdf.fill_color!(@shade_color2)
673               pdf.rectangle(x0 - @gap / 2.0, y + descender + height - mx, x1 - x0, mx).fill
674             end
675             pdf.reopen_object(tOID)
676           end
677 
678           if :inner == @show_lines or :all == @show_lines
679             # draw a line on the top of the block
680             pdf.save_state
681             pdf.stroke_color! @line_color
682             if first_line
683               pdf.stroke_style @outer_line_style
684               first_line = false
685             else
686               pdf.stroke_style @inner_line_style
687             end
688             pdf.line(x0 - @gap / 2.0, y + descender + height, x1 - @gap / 2.0, y + descender + height).stroke
689             pdf.restore_state
690           end
691         end
692 
693         y = y - mx + height
694         pdf.y = y
695         low_y = y if low_y.nil? or y < low_y 
696 
697           # checking row split over pages
698         unless @split_rows
699           if (((pdf.pageset.size != pageStart) or (pdf.columns? and columnStart != pdf.column_number)) and not second_turn)
700             # then we need to go back and try that again!
701             newPage = second_turn = true
702             tg.rewind_transaction(:row)
703             row = row_orig
704             low_y = y = y_orig
705             y0 = y0_orig
706             y1 = y1_orig
707             ok = false
708 
709             dm = pdf.absolute_left_margin - base_left_margin
710             base_pos.each { |k, v| pos[k] = v + dm }
711             x0 = base_x0 + dm
712             x1 = base_x1 + dm
713           else
714             tg.commit_transaction(:row)
715             ok = true
716           end
717         else
718           ok = true # don't go 'round the loop if splitting rows is allowed
719         end
720       end
721 
722       if abortTable
723           # abort_transaction if not ok only the outer transaction should
724           # be operational.
725         tg.rewind_transaction(:table)
726         pdf.start_new_page
727           # fix a bug where a moved table will take up the whole page.
728         low_y = nil
729         pdf.save_state
730         break
731       end
732     end
733   end
734 
735   if low_y <= y
736     y2 = low_y + descender
737   else
738     y2 = y + descender
739   end
740 
741   unless :none == @show_lines
742     y0 = y1 unless @show_headings
743 
744     __table_draw_lines__(pdf, pos, @gap, x0, x1, y0, y1, y2, @line_color,
745       @inner_line_style, @outer_line_style, @show_lines)
746   end
747 
748   # close the object for drawing the text on top
749   unless :none == @shade_rows
750     pdf.close_object
751     pdf.restore_state
752   end
753 
754   pdf.y = low_y
755 
756     # Table has been put on the page, the rows guarded as required; commit.
757   tg.commit_transaction(:table)
758 
759   y
760 rescue Exception => ex
761   begin
762     tg.abort_transaction(:table) if tg.transaction_open?
763   rescue
764     nil
765   end
766   raise ex
767 end

Private Instance Methods

__find_table_max_width__(pdf) click to toggle source

Find the maximum widths of the text within each column. Default to zero.

    # File lib/pdf/simpletable.rb
773 def __find_table_max_width__(pdf)     
774   max_width = PDF::Writer::OHash.new(-1)
775 
776   # Find the maximum cell widths based on the data and the headings.
777   # Passing through the data multiple times is unavoidable as we must
778   # do some analysis first.
779   @data.each do |row|
780    @cols.each do |name, column|
781      w = pdf.text_width(row[name].to_s, @font_size)
782      w *= PDF::SimpleTable::WIDTH_FACTOR
783 
784      max_width[name] = w if w > max_width[name]
785    end
786   end
787 
788   @cols.each do |name, column|
789    title = column.heading.title if column.heading
790    title ||= column.name
791    w = pdf.text_width(title, @heading_font_size)
792    w *= PDF::SimpleTable::WIDTH_FACTOR  
793    max_width[name] = w if w > max_width[name]
794   end
795   max_width  
796 end
__find_table_positions__(pdf, max_width) click to toggle source

Calculate the start positions of each of the columns. This is based on max_width, but may be modified with column options.

    # File lib/pdf/simpletable.rb
801 def __find_table_positions__(pdf, max_width)
802   pos = PDF::Writer::OHash.new
803   x = t = adjustment_width = set_width = 0
804 
805   max_width.each do |name, w|
806     pos[name] = t
807       # If the column width has been specified then set that here, also
808       # total the width avaliable for adjustment.
809     if not @cols[name].nil? and
810        not @cols[name].width.nil? and
811        @cols[name].width > 0
812       t += @cols[name].width
813       max_width[name] = @cols[name].width - @gap
814       set_width += @cols[name].width
815     else
816       t += w + @gap
817       adjustment_width += w
818       set_width += @gap
819     end
820   end
821   pos[:__last_column__] = t
822 
823   [pos, t, x, adjustment_width, set_width]
824 end
__open_new_object__(pdf) click to toggle source
    # File lib/pdf/simpletable.rb
939 def __open_new_object__(pdf)
940   pdf.save_state
941   tOID = pdf.open_object
942   pdf.close_object
943   pdf.add_object(tOID)
944   pdf.reopen_object(tOID)
945   tOID
946 end
__table_column_headings__(pdf, pos, max_width, height, descender, gap, size, y) click to toggle source

Uses ezText to add the text, and returns the height taken by the largest heading. This page will move the headings to a new page if they will not fit completely on this one transaction support will be used to implement this.

    # File lib/pdf/simpletable.rb
831 def __table_column_headings__(pdf, pos, max_width, height, descender, gap, size, y)
832   mx = second_go = 0
833   start_page = pdf.pageset.size
834 
835     # y is the position at which the top of the table should start, so the
836     # base of the first text, is y-height-gap-descender, but ezText starts
837     # by dropping height.
838 
839     # The return from this function is the total cell height, including
840     # gaps, and y is adjusted to be the postion of the bottom line.
841   tg = Transaction::Simple::Group.new(pdf, self)
842   tg.start_transaction(:column_headings)
843 
844   ok = false
845   y -= gap
846   loop do
847     break if ok
848     @cols.each do |name, column|
849       pdf.pointer = y
850 
851       if column.heading
852         justification = column.heading.justification
853         bold          = column.heading.bold
854         title         = column.heading.title
855       end
856 
857       justification ||= :left
858       bold ||= @bold_headings
859       title ||= column.name
860 
861       title = "<b>#{title}</b>" if bold
862 
863       pdf.text(title, :font_size => size, :absolute_left => pos[name],
864               :absolute_right => (max_width[name] + pos[name]),
865               :justification => justification)
866       dy = y - pdf.y
867       mx = dy if dy > mx
868     end
869 
870     y -= (mx + gap) - descender # y = y - mx - gap + descender
871 
872       # If this has been moved to a new page, then abort the transaction;
873       # move to a new page, and put it there. Do not check on the second
874       # time around to avoid an infinite loop.
875     if (pdf.pageset.size != start_page and not second_go)
876       tg.rewind_transaction(:column_headings)
877 
878       pdf.start_new_page
879       save_state
880       y = @y - gap - descender
881       ok = false
882       second_go = true
883       mx = 0
884     else
885       tg.commit_transaction(:column_headings)
886       ok = true
887     end
888   end
889 
890   return [mx + gap * 2 - descender, y]
891 rescue Exception => ex
892   begin
893     tg.abort_transaction(:column_headings) if tg.transaction_open?(:column_headings)
894   rescue
895     nil
896   end
897   raise ex
898 end
__table_draw_lines__(pdf, pos, gap, x0, x1, y0, y1, y2, col, inner, outer, opt = :outer) click to toggle source
    # File lib/pdf/simpletable.rb
901 def __table_draw_lines__(pdf, pos, gap, x0, x1, y0, y1, y2, col, inner, outer, opt = :outer)
902   x0 = 1000
903   x1 = 0
904 
905   pdf.stroke_color(col)
906 
907   cnt = 0
908   n = pos.size
909 
910   pos.each do |name, x|
911     cnt += 1
912 
913     if (cnt == 1 or cnt == n)
914       pdf.stroke_style outer
915     else
916       pdf.stroke_style inner
917     end
918 
919     pdf.line(x - gap / 2.0, y0, x - gap / 2.0, y2).stroke
920     x1 = x if x > x1
921     x0 = x if x < x0
922   end
923 
924   pdf.stroke_style outer
925 
926   pdf.line(x0 - (gap / 2.0) - (outer.width / 2.0), y0,
927            x1 - (gap / 2.0) + (outer.width / 2.0), y0).stroke
928 
929     # Only do the second line if it is different than the first AND each
930     # row does not have a line on it.
931   if y0 != y1 and @show_lines == :outer
932     pdf.line(x0 - gap / 2.0, y1, x1 - gap / 2.0, y1).stroke
933   end
934   pdf.line(x0 - (gap / 2.0) - (outer.width / 2.0), y2,
935            x1 - (gap / 2.0) + (outer.width / 2.0), y2).stroke
936 end