/******************************************************************************* * Copyright (c) 2016 Weasis Team and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Nicolas Roduit - initial API and implementation *******************************************************************************/ package org.weasis.dicom.sr; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.print.PageFormat; import java.awt.print.Pageable; import java.awt.print.Paper; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.util.ArrayList; import javax.swing.JEditorPane; import javax.swing.JPanel; import javax.swing.plaf.basic.BasicEditorPaneUI; import javax.swing.text.Position; import javax.swing.text.View; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; public class EditorPanePrinter extends JPanel implements Pageable, Printable { public static final int PAGE_SHIFT = 20; JEditorPane sourcePane; Insets margins; ArrayList<PagePanel> pages; int pageWidth; int pageHeight; View rootView; PageFormat pageFormat; public EditorPanePrinter(JEditorPane pane, PageFormat pageFormat, Insets margins) { JEditorPane tmpPane = new JEditorPane(); tmpPane.setUI(new BasicEditorPaneUI()); tmpPane.setContentType(pane.getContentType()); HTMLEditorKit kit = new HTMLEditorKit(); StyleSheet ss = kit.getStyleSheet(); ss.addRule( "body {font-family:sans-serif;font-size:12pt;background-color:white;color:black;margin:3;font-weight:normal;}"); //$NON-NLS-1$ tmpPane.setEditorKit(kit); tmpPane.setBorder(null); tmpPane.setText(pane.getText()); this.sourcePane = tmpPane; this.pageFormat = pageFormat; Paper paper = pageFormat.getPaper(); this.margins = margins; this.pageWidth = (int) paper.getWidth(); this.pageHeight = (int) paper.getHeight(); paper.setImageableArea(0, 0, paper.getWidth(), paper.getHeight()); pageFormat.setPaper(paper); doPagesLayout(); } public void doPagesLayout() { setLayout(null); removeAll(); this.rootView = sourcePane.getUI().getRootView(sourcePane); sourcePane.setSize(pageWidth - margins.top - margins.bottom, Integer.MAX_VALUE); Dimension d = sourcePane.getPreferredSize(); sourcePane.setSize(pageWidth - margins.top - margins.bottom, d.height); calculatePageInfo(); int count = pages.size(); this.setPreferredSize(new Dimension(pageWidth * 2 + 50, PAGE_SHIFT + count * (pageHeight + PAGE_SHIFT))); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); AffineTransform old = ((Graphics2D) g).getTransform(); ((Graphics2D) g).setTransform(old); } protected void calculatePageInfo() { pages = new ArrayList<>(); int startY = 0; int endPageY = getEndPageY(startY); while (startY + pageHeight - margins.top - margins.bottom < sourcePane.getHeight()) { Shape pageShape = getPageShape(startY, pageWidth - margins.left - margins.right, pageHeight - margins.top - margins.bottom, sourcePane); PagePanel p = new PagePanel(startY, endPageY, pageShape); updateUIToRemoveLF(p); pages.add(p); startY = endPageY; endPageY = getEndPageY(startY); } Shape pageShape = getPageShape(startY, pageWidth - margins.left - margins.right, pageHeight - margins.top - margins.bottom, sourcePane); PagePanel p = new PagePanel(startY, endPageY, pageShape); updateUIToRemoveLF(p); pages.add(p); int count = 0; for (PagePanel pi : pages) { add(pi); pi.setLocation(PAGE_SHIFT, PAGE_SHIFT + count * (pageHeight + PAGE_SHIFT)); count++; } } protected int getEndPageY(int startY) { int desiredY = startY + pageHeight - margins.top - margins.bottom; int realY = desiredY; for (int x = 1; x < pageWidth; x++) { View v = getLeafViewAtPoint(new Point(x, realY), rootView); if (v != null) { Rectangle alloc = getAllocation(v, sourcePane).getBounds(); if (alloc.height > pageHeight - margins.top - margins.bottom) { continue; } if (alloc.y + alloc.height > desiredY) { realY = Math.min(realY, alloc.y); } } } return realY; } private static void updateUIToRemoveLF(JPanel panel) { panel.setUI(new javax.swing.plaf.PanelUI() { }); panel.setBackground(Color.WHITE); panel.setForeground(Color.BLACK); panel.setBorder(null); panel.setOpaque(true); } protected View getLeafViewAtPoint(Point p, View root) { return getLeafViewAtPoint(p, root, sourcePane); } public static View getLeafViewAtPoint(Point p, View root, JEditorPane sourcePane) { int pos = sourcePane.viewToModel(p); View v = sourcePane.getUI().getRootView(sourcePane); while (v.getViewCount() > 0) { int i = v.getViewIndex(pos, Position.Bias.Forward); v = v.getView(i); } Shape alloc = getAllocation(root, sourcePane); if (alloc.contains(p)) { return v; } return null; } public static Shape getPageShape(int pageStartY, int pageWidth, int pageHeight, JEditorPane sourcePane) { Area result = new Area(new Rectangle(0, 0, pageWidth, pageHeight)); View rootView = sourcePane.getUI().getRootView(sourcePane); Rectangle last = new Rectangle(); for (int x = 1; x < pageWidth; x++) { View v = getLeafViewAtPoint(new Point(x, pageStartY), rootView, sourcePane); if (v != null) { Rectangle alloc = getAllocation(v, sourcePane).getBounds(); if (alloc.y < pageStartY && alloc.y + alloc.height > pageStartY) { if (!alloc.equals(last)) { Rectangle r = new Rectangle(alloc); r.y -= pageStartY; result.subtract(new Area(r)); } } last = alloc; } } last = new Rectangle(); for (int x = 1; x < pageWidth; x++) { View v = getLeafViewAtPoint(new Point(x, pageStartY + pageHeight), rootView, sourcePane); if (v != null) { Rectangle alloc = getAllocation(v, sourcePane).getBounds(); if (alloc.y < pageStartY + pageHeight && alloc.y + alloc.height > pageStartY + pageHeight) { if (!alloc.equals(last)) { Rectangle r = new Rectangle(alloc); r.y -= pageStartY; result.subtract(new Area(r)); } } last = alloc; } } return result; } // pageable methods @Override public int getNumberOfPages() { return pages.size(); } @Override public PageFormat getPageFormat(int pageIndex) { return pageFormat; } @Override public Printable getPrintable(int pageIndex) { return this; } @Override public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException { if (pageIndex < pages.size()) { pageFormat.getPaper().setImageableArea(0, 0, pageWidth, pageHeight); PagePanel p = pages.get(pageIndex); p.isPrinting = true; p.paint(g); p.isPrinting = false; return PAGE_EXISTS; } return NO_SUCH_PAGE; } class PagePanel extends JPanel { int pageStartY; int pageEndY; Shape pageShape; boolean isPrinting = false; JPanel innerPage = new JPanel() { @Override public void paintComponent(Graphics g) { super.paintComponent(g); AffineTransform old = ((Graphics2D) g).getTransform(); Shape oldClip = g.getClip(); Area newClip = new Area(oldClip); if (isPrinting) { newClip = new Area(pageShape); } else { newClip.intersect(new Area(pageShape)); } g.setClip(newClip); g.translate(0, -pageStartY); sourcePane.paint(g); for (Component c : sourcePane.getComponents()) { AffineTransform tmp = ((Graphics2D) g).getTransform(); g.translate(c.getX(), c.getY()); ((Container) c).getComponent(0).paint(g); ((Graphics2D) g).setTransform(tmp); } ((Graphics2D) g).setTransform(old); g.setClip(oldClip); } }; public PagePanel() { this(0, 0, null); } public PagePanel(int pageStartY, int pageEndY, Shape pageShape) { this.pageStartY = pageStartY; this.pageEndY = pageEndY; this.pageShape = pageShape; updateUIToRemoveLF(innerPage); setSize(pageWidth, pageHeight); setLayout(null); add(innerPage); innerPage.setBounds(margins.left, margins.top, pageWidth - margins.left - margins.right, pageHeight - margins.top - margins.bottom); } } protected static Shape getAllocation(View v, JEditorPane edit) { Insets ins = edit.getInsets(); View vParent = v.getParent(); int x = ins.left; int y = ins.top; while (vParent != null) { int i = vParent.getViewIndex(v.getStartOffset(), Position.Bias.Forward); Shape alloc = vParent.getChildAllocation(i, new Rectangle(0, 0, Short.MAX_VALUE, Short.MAX_VALUE)); x += alloc.getBounds().x; y += alloc.getBounds().y; vParent = vParent.getParent(); } return new Rectangle(x, y, (int) v.getPreferredSpan(View.X_AXIS), (int) v.getPreferredSpan(View.Y_AXIS)); } }