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:
265:
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:
272:
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:
295: needed_width = @width - set_width
296:
297:
298:
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
307:
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:
321:
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:
328:
329: aWidest.each { |name| cols0[name] = nWidest }
330: presentWidth -= (widest - nWidest) * aWidest.size
331: end
332: end
333: end
334:
335:
336:
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:
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:
389: pdf.fill_color @text_color
390: pdf.stroke_color @shade_color
391:
392: middle = (x0 + x1) / 2.0
393:
394:
395:
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
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:
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:
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:
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
440: low_y = y if low_y.nil? or y < low_y
441:
442:
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:
451:
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:
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:
482:
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:
491:
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
503:
504: ok = false
505: second_turn = false
506: loop do
507: break if abortTable or ok
508:
509: mx = 0
510: newRow = true
511:
512: loop do
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:
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:
541:
542:
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: hOID = __open_new_object__(pdf) if @shade_headings
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.close_object
570: pdf.fill_color! @shade_heading_color
571: pdf.rectangle(x0 - @gap / 2, y, x1 - x0, _height).fill
572: pdf.reopen_object(hOID)
573: pdf.close_object
574: pdf.restore_state
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:
594:
595:
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:
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:
660:
661: row = leftOvers
662:
663:
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:
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:
697: unless @split_rows
698: if (((pdf.pageset.size != pageStart) or (pdf.columns? and columnStart != pdf.column_number)) and not second_turn)
699:
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
718: end
719: end
720:
721: if abortTable
722:
723:
724: tg.rewind_transaction(:table)
725: pdf.start_new_page
726:
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:
748: unless :none == @shade_rows
749: pdf.close_object
750: pdf.restore_state
751: end
752:
753: pdf.y = low_y
754:
755:
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