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:
264:
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:
271:
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:
294: needed_width = @width - set_width
295:
296:
297:
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
306:
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:
320:
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:
327:
328: aWidest.each { |name| cols0[name] = nWidest }
329: presentWidth -= (widest - nWidest) * aWidest.size
330: end
331: end
332: end
333:
334:
335:
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:
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:
388: pdf.fill_color @text_color
389: pdf.stroke_color @shade_color
390:
391: middle = (x0 + x1) / 2.0
392:
393:
394:
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
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:
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:
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:
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
439: low_y = y if low_y.nil? or y < low_y
440:
441:
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:
450:
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:
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:
481:
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:
490:
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
502:
503: ok = false
504: second_turn = false
505: loop do
506: break if abortTable or ok
507:
508: mx = 0
509: newRow = true
510:
511: loop do
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:
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:
540:
541:
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:
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