1 19 package org.openide.text; 20 21 22 import java.awt.*; 23 import java.awt.font.*; 24 import java.awt.geom.*; 25 import java.awt.print.*; 26 import java.text.*; 27 import java.util.*; 28 import java.util.List ; 29 import javax.swing.text.*; 30 import org.openide.*; 31 import org.openide.util.Exceptions; 32 import org.openide.util.NbBundle; 33 34 35 40 final class DefaultPrintable extends Object implements Printable { 41 42 private static final int ARG_SIZE = 3; 43 44 45 private static PrintSettings printSettings; 46 47 48 private static Font fontInstance; 49 50 53 private AttributedCharacterIterator[] styledTexts; 54 55 56 57 59 60 private int startPage = -1; 61 62 63 private List <TextLayout> textLayouts; 64 65 66 private int[] pageIndices; 67 68 69 private int pageIndicesSize; 70 71 72 private int currentLayout; 73 74 75 private int currentStyledText; 76 77 78 private LineBreakMeasurer lineBreakMeasurer; 79 80 81 private int maxPage; 82 83 84 private List <TextLayout> startLayouts; 85 86 87 private int[] lineIndices; 89 90 private Object [] pageArgs; 91 92 93 private MessageFormat header; 94 95 96 private boolean printHeader; 97 98 99 private MessageFormat footer; 100 101 102 private boolean printFooter; 103 104 105 private CancellationPanel cancellationPanel; 106 107 108 private Dialog cancellationDialog; 109 110 114 private DefaultPrintable(AttributedCharacterIterator[] iter, String filename) { 115 if ((iter == null) || (iter.length == 0)) { 116 throw new IllegalArgumentException (); 117 } 118 119 if (printSettings == null) { 120 printSettings = PrintSettings.findObject(PrintSettings.class, true); 121 } 122 123 replaceEmptyIterators(iter); 125 126 styledTexts = iter; 127 128 textLayouts = new ArrayList<TextLayout>(100); pageIndices = new int[50]; 131 pageIndicesSize = 0; 132 currentLayout = 0; 133 currentStyledText = 0; 134 lineBreakMeasurer = null; 135 maxPage = Integer.MAX_VALUE; 136 137 startLayouts = new ArrayList<TextLayout>(10); lineIndices = new int[pageIndices.length]; 139 140 pageArgs = new Object [ARG_SIZE]; 141 pageArgs[2] = filename; 142 pageArgs[1] = new Date(System.currentTimeMillis()); 143 144 header = new MessageFormat(getHeaderFormat()); 145 printHeader = !getHeaderFormat().equals(""); footer = new MessageFormat(getFooterFormat()); 147 printFooter = !getFooterFormat().equals(""); } 149 150 153 public DefaultPrintable(Document doc) { 154 this(getIterators(doc), getFilename(doc)); 155 } 156 157 164 public int print(Graphics g, PageFormat pf, int pageNo) 165 throws PrinterException { 166 boolean processDummy = false; 167 168 if (startPage == -1) { 169 processDummy = true; 170 startPage = pageNo; 171 } 172 173 if (processDummy) { 174 for (int i = 0; i < startPage; i++) { 175 printImpl(g, pf, i, false); 179 } 180 } 181 182 return printImpl(g, pf, pageNo, true); 183 } 184 185 private int printImpl(Graphics g, PageFormat pf, int pageNo, boolean print) 186 throws PrinterException { 187 if (pageNo > maxPage) { 188 closeDialog(); 189 190 return Printable.NO_SUCH_PAGE; 191 } else if (pageNo < 0) { 192 closeDialog(); 193 throw new IllegalArgumentException ("Illegal page number=" + pageNo); } 195 196 if ((g instanceof PrinterGraphics) && isCancelled(((PrinterGraphics) g).getPrinterJob())) { 198 closeDialog(); 199 throw new PrinterAbortException(); 200 } 201 202 if ((cancellationPanel == null) && (g instanceof PrinterGraphics)) { 203 PrinterJob pJob = ((PrinterGraphics) g).getPrinterJob(); 206 createCancellationPanel(pJob); 207 } 208 209 if (cancellationPanel != null) { 210 int pageNumber = (print ? pageNo : startPage); 211 cancellationPanel.setPageno(pageNumber); 212 packDialog(); 213 } 214 215 int startLine = 0; 217 int correction = 3; 219 221 231 232 g.setColor(Color.black); 234 235 final Graphics2D graphics = (Graphics2D) g; 236 final Point2D.Float pen = new Point2D.Float(getImageableXPatch(pf), getImageableYPatch(pf)); 237 238 246 pageArgs[0] = new Integer (pageNo + 1); 249 float pageBreakCorrection = 0.0F; 250 TextLayout headerString = null; 251 TextLayout footerString = null; 252 253 if (printHeader) { 254 headerString = new TextLayout(header.format(pageArgs), getHeaderFont(), graphics.getFontRenderContext()); 255 256 pageBreakCorrection += (headerString.getAscent() + 257 ((headerString.getDescent() + headerString.getLeading()) * 2)); 258 } 259 260 if (printFooter) { 261 footerString = new TextLayout(footer.format(pageArgs), getFooterFont(), graphics.getFontRenderContext()); 262 263 pageBreakCorrection += ((footerString.getAscent() * 2) + footerString.getDescent() + 264 footerString.getLeading()); 265 } 266 267 final float wrappingWidth = (wrap() ? ((float) pf.getImageableWidth() - correction) : Float.MAX_VALUE); 270 final float pageBreak = (((float) pf.getImageableHeight()) + ((float) pf.getImageableY())) - 271 pageBreakCorrection; 272 final FontRenderContext frCtx = graphics.getFontRenderContext(); 273 274 boolean pageExists = false; 275 276 for ( 278 TextLayout layout = layoutForPage(pageNo, wrappingWidth, frCtx); (pen.y < pageBreak); 279 layout = nextLayout(wrappingWidth, frCtx) 280 ) { 281 if (layout == null) { 282 maxPage = pageNo; 283 284 break; 285 } 286 287 if (!pageExists) { 288 if (printHeader && (headerString != null)) { 290 pen.y += headerString.getAscent(); 291 292 float center = computeStart( 293 headerString.getBounds(), (float) pf.getImageableWidth(), getHeaderAlignment() 294 ); 295 float dx = (headerString.isLeftToRight() ? center : (wrappingWidth - headerString.getAdvance() - 296 center)); 297 298 if (print) { 299 headerString.draw(graphics, pen.x + dx, pen.y); 300 } 301 302 pen.y += ((headerString.getDescent() + headerString.getLeading()) * 2); 303 } 304 305 pageExists = true; 306 } 307 308 pen.y += (layout.getAscent() * getLineAscentCorrection()); 309 310 313 326 327 float dx = (layout.isLeftToRight() ? 0 : (wrappingWidth - layout.getAdvance())); 329 330 if (print) { 331 layout.draw(graphics, correction + pen.x + dx, pen.y); 332 } 333 334 pen.y += ((layout.getDescent() + layout.getLeading()) * getLineAscentCorrection()); 335 } 336 337 if (printFooter && pageExists && (footerString != null)) { 339 pen.y = pageBreak; 340 pen.y += (footerString.getAscent() * 2); 341 342 float center = computeStart(footerString.getBounds(), (float) pf.getImageableWidth(), getFooterAlignment()); 343 float dx = (footerString.isLeftToRight() ? (0 + center) : (wrappingWidth - footerString.getAdvance() - 344 center)); 345 346 if (print) { 347 footerString.draw(graphics, pen.x + dx, pen.y); 348 } 349 } 350 351 if ((g instanceof PrinterGraphics) && isCancelled(((PrinterGraphics) g).getPrinterJob())) { 353 closeDialog(); 354 throw new PrinterAbortException(); 355 } 356 357 if (!pageExists) { 359 closeDialog(); 360 361 return Printable.NO_SUCH_PAGE; 362 } else { 363 return Printable.PAGE_EXISTS; 364 } 365 } 366 367 373 374 378 private float getImageableXPatch(PageFormat pf) { 379 if (pf.getOrientation() == PageFormat.LANDSCAPE) { 380 double ret = pf.getPaper().getHeight() - (pf.getImageableX() + pf.getImageableWidth()); 381 382 return (float) Math.round(ret); 383 } else { 384 return (float) pf.getImageableX(); 385 } 386 } 387 388 392 private float getImageableYPatch(PageFormat pf) { 393 if (pf.getOrientation() == PageFormat.LANDSCAPE) { 394 double ret = pf.getPaper().getWidth() - (pf.getImageableY() + pf.getImageableHeight()); 395 396 return (float) Math.round(ret); 397 } else { 398 return (float) pf.getImageableY(); 399 } 400 } 401 402 414 419 private boolean isNewline(TextLayout tl, int currentLine) { 420 if (currentLine >= startLayouts.size()) { 421 return false; } else { 423 return startLayouts.get(currentLine) == tl; 424 } 425 } 426 427 434 private static float computeStart(Rectangle2D rect, float width, int alignment) { 435 float x; 436 437 if (rect instanceof Rectangle2D.Float) { 438 x = ((Rectangle2D.Float) rect).width; 439 } else { 440 x = (float) ((Rectangle2D.Double) rect).width; 441 } 442 443 if (x >= width) { 444 return 0; 445 } 446 447 switch (alignment) { 448 case PrintSettings.LEFT: 449 return 0; 450 451 case PrintSettings.RIGHT: 452 return (width - x); 453 454 default: 455 return (width - x) / 2; 456 } 457 } 458 459 464 private TextLayout nextLayout(float wrappingWidth, FontRenderContext frc) { 465 TextLayout l; 466 467 if (currentLayout == textLayouts.size()) { 468 LineBreakMeasurer old = lineBreakMeasurer; 469 LineBreakMeasurer measurer = getMeasurer(frc); 470 471 if (measurer == null) { 472 return null; 473 } 474 475 l = measurer.nextLayout(wrappingWidth); 476 textLayouts.add(l); 477 478 if (old != measurer) { startLayouts.add(l); 480 } 481 } else { 482 l = textLayouts.get(currentLayout); 483 } 484 485 currentLayout++; 487 return l; 488 } 489 490 496 private TextLayout layoutForPage(int pageNo, float wrappingWidth, FontRenderContext frc) { 497 if (pageNo > (pageIndicesSize + 1)) { 498 throw new IllegalArgumentException ( 499 "Page number " + pageNo +" is bigger than array size " + (pageIndicesSize + 1) 501 ); } 503 504 if (pageNo == pageIndicesSize) { 506 if (pageIndicesSize >= pageIndices.length) { 508 pageIndices = increaseArray(pageIndices); 509 lineIndices = increaseArray(lineIndices); 510 } 511 512 pageIndices[pageIndicesSize] = Math.max(textLayouts.size() - 1, 0); 514 515 lineIndices[pageIndicesSize++] = Math.max(startLayouts.size() - 1, 0); 518 } 519 520 currentLayout = pageIndices[pageNo]; 522 return nextLayout(wrappingWidth, frc); } 524 525 529 private LineBreakMeasurer getMeasurer(FontRenderContext frc) { 530 if (lineBreakMeasurer == null) { lineBreakMeasurer = new LineBreakMeasurer(styledTexts[currentStyledText], frc); 532 533 } else if (lineBreakMeasurer.getPosition() >= styledTexts[currentStyledText].getEndIndex()) { 535 if (currentStyledText == (styledTexts.length - 1)) { 537 return null; } else { lineBreakMeasurer = new LineBreakMeasurer(styledTexts[++currentStyledText], frc); 540 } 541 } 542 543 return lineBreakMeasurer; 544 } 545 546 548 549 private static boolean wrap() { 550 return printSettings.getWrap(); 551 } 552 553 554 private static String getHeaderFormat() { 555 return printSettings.getHeaderFormat(); 556 } 557 558 559 private static String getFooterFormat() { 560 return printSettings.getFooterFormat(); 561 } 562 563 564 private static Font getHeaderFont() { 565 return printSettings.getHeaderFont(); 566 } 567 568 569 private static Font getFooterFont() { 570 return printSettings.getFooterFont(); 571 } 572 573 574 private static int getFooterAlignment() { 575 return printSettings.getFooterAlignment(); 576 } 577 578 579 private static int getHeaderAlignment() { 580 return printSettings.getHeaderAlignment(); 581 } 582 583 584 private static float getLineAscentCorrection() { 585 return printSettings.getLineAscentCorrection(); 586 } 587 588 589 private static boolean lineNumbers() { 590 return false; 591 } 592 593 private static Font lineNumbersFont() { 595 return new Font("Courier", java.awt.Font.PLAIN, 6); } 597 598 600 604 private static AttributedCharacterIterator[] getIterators(Document doc) { 605 if (doc instanceof NbDocument.Printable) { 606 return ((NbDocument.Printable) doc).createPrintIterators(); 607 } 608 609 java.awt.Font f = new java.awt.Font ("Courier", java.awt.Font.PLAIN, 8); 612 AttributedCharacters achs = null; 613 char[] chars = null; 614 List <AttributedCharacterIterator> iterators = new ArrayList<AttributedCharacterIterator>(300); 615 616 try { 617 String document = doc.getText(0, doc.getLength()); 618 619 int firstCharInDoc = 0; 621 622 for (int i = 0; i < document.length(); i++) { 624 if (document.charAt(i) == '\n') { 625 chars = new char[i - firstCharInDoc + 1]; 626 document.getChars(firstCharInDoc, chars.length + firstCharInDoc, chars, 0); 627 achs = new AttributedCharacters(); 628 achs.append(chars, f, Color.black); 629 iterators.add(achs.iterator()); firstCharInDoc = i + 1; 631 } 632 } 633 } catch (BadLocationException e) { 634 Exceptions.printStackTrace(e); 635 } 636 637 AttributedCharacterIterator[] iters = new AttributedCharacterIterator[iterators.size()]; 638 iterators.toArray(iters); 639 640 return iters; 641 } 642 643 647 private static String getFilename(Document doc) { 648 String ret = (String ) doc.getProperty(javax.swing.text.Document.TitleProperty); 649 650 return ((ret == null) ? "UNKNOWN" : ret); } 652 653 656 private static int[] increaseArray(int[] old) { 657 int[] ret = new int[2 * old.length]; 658 System.arraycopy(old, 0, ret, 0, old.length); 659 660 return ret; 661 } 662 663 665 668 private void createCancellationPanel(final PrinterJob job) { 669 cancellationPanel = new CancellationPanel(job); 670 671 DialogDescriptor ddesc = new DialogDescriptor( 672 cancellationPanel, NbBundle.getMessage(PrintSettings.class, "CTL_Print_cancellation"), false, 673 new Object [] { NbBundle.getMessage(PrintSettings.class, "CTL_Cancel") }, 674 NbBundle.getMessage(PrintSettings.class, "CTL_Cancel"), DialogDescriptor.BOTTOM_ALIGN, null, 675 new java.awt.event.ActionListener () { 676 public void actionPerformed(java.awt.event.ActionEvent ev) { 677 setCancelled(job); 678 closeDialog(); 679 } 680 } 681 ); 682 setDialog(DialogDisplayer.getDefault().createDialog(ddesc)); 683 } 684 685 686 void closeDialog() { 687 if (cancellationDialog != null) { 688 cancellationDialog.setVisible(false); 689 cancellationDialog.dispose(); 690 } 691 } 692 693 694 void setDialog(Dialog d) { 695 d.setVisible(true); 696 d.pack(); 697 cancellationDialog = d; 698 } 699 700 701 void packDialog() { 702 if (cancellationDialog != null) { 703 cancellationDialog.pack(); 704 } 705 } 706 707 710 void setCancelled(PrinterJob job) { 711 job.cancel(); 712 } 713 714 715 boolean isCancelled(PrinterJob job) { 716 return job.isCancelled(); 717 } 718 719 720 private static void replaceEmptyIterators(AttributedCharacterIterator[] iters) { 721 for (int i = 0; i < iters.length; i++) { 722 AttributedCharacterIterator achit = iters[i]; 723 724 if (achit.getBeginIndex() == achit.getEndIndex()) { 725 AttributedCharacters at = new AttributedCharacters(); 726 at.append(' ', getFontInstance(), Color.white); 727 iters[i] = at.iterator(); 728 } 729 } 730 } 731 732 733 static Font getFontInstance() { 734 if (fontInstance == null) { 735 fontInstance = new java.awt.Font ("Dialog", java.awt.Font.PLAIN, 14); } 737 738 return fontInstance; 739 } 740 741 742 static final class CancellationPanel extends javax.swing.JPanel { 743 static final long serialVersionUID = -6419253408585188541L; 744 745 746 private final javax.swing.JLabel printProgress; 747 748 749 private final MessageFormat format; 750 751 752 private final Object [] msgParams; 753 754 758 public CancellationPanel(PrinterJob job) { 759 if (job == null) { 760 throw new IllegalArgumentException (); 761 } 762 763 format = new MessageFormat(NbBundle.getMessage(PrintSettings.class, "CTL_Print_progress")); 764 msgParams = new Object [1]; 765 766 setLayout(new java.awt.BorderLayout ()); 767 setBorder(new javax.swing.border.EmptyBorder (12, 12, 0, 12)); 768 printProgress = new javax.swing.JLabel (); 769 printProgress.setHorizontalAlignment(javax.swing.JLabel.CENTER); 770 add(printProgress); 771 } 772 773 776 public void setPageno(int pageno) { 777 msgParams[0] = new Integer (pageno + 1); 778 printProgress.setText(format.format(msgParams)); 779 getAccessibleContext().setAccessibleDescription(printProgress.getText()); 780 } 781 } 782 } 783 | Popular Tags |