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