| JComponentPrinter.java |
1 /*
2 * Copyright (c) 1998-2004, The University of Sheffield.
3 *
4 * This file is part of GATE (see http://gate.ac.uk/), and is free
5 * software, licenced under the GNU Library General Public License,
6 * Version 2, June 1991 (in the distribution as file licence.html,
7 * and also available at http://gate.ac.uk/gate/licence.html).
8 *
9 * Valentin Tablan 07/12/2001
10 *
11 * $Id: JComponentPrinter.java,v 1.5 2004/07/21 17:10:08 akshay Exp $
12 *
13 */
14 package gate.print;
15
16 import java.awt.*;
17 import java.awt.print.*;
18
19 import javax.swing.JComponent;
20 import javax.swing.text.BadLocationException;
21 import javax.swing.text.JTextComponent;
22
23 import gate.event.StatusListener;
24 import gate.gui.MainFrame;
25 import gate.util.Err;
26
27
28 /**
29 * Will scale the component so it fits on a page horizontally
30 */
31 public class JComponentPrinter implements Pageable{
32
33 public JComponentPrinter(JComponent component, PageFormat format){
34 this.component = component;
35 this.pageFormat = format;
36 //find the scale factor; we will not enlarge as it would look ugly
37 Rectangle componentBounds = component.getBounds(null);
38 scaleFactor = Math.min(format.getImageableWidth() /componentBounds.width,
39 1);
40
41 //calculate the pages count
42 pageCount = (int)((componentBounds.height * scaleFactor +
43 pageFormat.getImageableHeight() - 1) /
44 pageFormat.getImageableHeight());
45 }
46
47 /**
48 * Returns the number of pages over which the canvas
49 * will be drawn.
50 */
51 public int getNumberOfPages() {
52 return pageCount;
53 }
54
55
56 /**
57 * Returns the PageFormat of the page specified by
58 * pageIndex. The PageFormat is the same for all pages.
59 *
60 * @param pageIndex the zero based index of the page whose
61 * PageFormat is being requested
62 * @return the PageFormat describing the size and
63 * orientation.
64 * @exception IndexOutOfBoundsException
65 * the Pageable does not contain the requested
66 * page.
67 */
68 public PageFormat getPageFormat(int pageIndex)
69 throws IndexOutOfBoundsException {
70 if (pageIndex >= pageCount) throw new IndexOutOfBoundsException();
71 return pageFormat;
72 }
73
74
75 /**
76 * Returns the <code>Printable</code> instance responsible for
77 * rendering the page specified by <code>pageIndex</code>.
78 *
79 * @param pageIndex the zero based index of the page whose
80 * Printable is being requested
81 * @return the Printable that renders the page.
82 * @exception IndexOutOfBoundsException
83 * the Pageable does not contain the requested
84 * page.
85 */
86 public Printable getPrintable(int pageIndex)
87 throws IndexOutOfBoundsException {
88 if (pageIndex >= pageCount)throw new IndexOutOfBoundsException();
89
90 double originY = pageIndex * pageFormat.getImageableHeight() / scaleFactor;
91 if(component instanceof JTextComponent){
92 JTextComponent tComp = (JTextComponent)component;
93 //move the origin up towards the first inter-row space
94 int location = tComp.viewToModel(new Point(0, (int)originY));
95 try{
96 Rectangle rect = tComp.modelToView(location);
97 originY = rect.y + rect.height - 1;
98 }catch(BadLocationException ble){
99 ble.printStackTrace(Err.getPrintWriter());
100 }
101 }
102
103 return new TranslatedPrintable(originY);
104 }
105
106
107 /**
108 * This inner class's sole responsibility is to translate
109 * the coordinate system before invoking a canvas's
110 * painter. The coordinate system is translated in order
111 * to get the desired portion of a canvas to line up with
112 * the top of a page.
113 */
114 public class TranslatedPrintable implements Printable {
115 public TranslatedPrintable(double originY){
116 this.originY = originY;
117 }
118
119 /**
120 * Prints the page at the specified index into the specified
121 * {@link Graphics} context in the specified
122 * format. A PrinterJob calls the
123 * Printableinterface to request that a page be
124 * rendered into the context specified by
125 * graphics. The format of the page to be drawn is
126 * specified by pageFormat. The zero based index
127 * of the requested page is specified by pageIndex.
128 * If the requested page does not exist then this method returns
129 * NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned.
130 * The Graphics class or subclass implements the
131 * {@link PrinterGraphics} interface to provide additional
132 * information. If the Printable object
133 * aborts the print job then it throws a {@link PrinterException}.
134 * @param graphics the context into which the page is drawn
135 * @param pageFormat the size and orientation of the page being drawn
136 * @param pageIndex the zero based index of the page to be drawn
137 * @return PAGE_EXISTS if the page is rendered successfully
138 * or NO_SUCH_PAGE if pageIndex specifies a
139 * non-existent page.
140 * @exception java.awt.print.PrinterException
141 * thrown when the print job is terminated.
142 */
143 public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
144 throws PrinterException {
145
146 Rectangle componentBounds = component.getBounds(null);
147 Graphics2D g2 = (Graphics2D) graphics;
148 g2.translate(pageFormat.getImageableX() - componentBounds.x,
149 pageFormat.getImageableY() - originY - componentBounds.y);
150 g2.scale(scaleFactor, scaleFactor);
151
152 if(component instanceof JTextComponent){
153 JTextComponent tComp = (JTextComponent)component;
154 double nextOriginY = (pageIndex + 1) * pageFormat.getImageableHeight() /
155 scaleFactor;
156 int location = tComp.viewToModel(new Point(0, (int)nextOriginY));
157 try{
158 Rectangle rect = tComp.modelToView(location);
159 nextOriginY = rect.y;
160 }catch(BadLocationException ble){
161 ble.printStackTrace(Err.getPrintWriter());
162 }
163 Rectangle clip = g2.getClip().getBounds();
164 clip.setSize((int)clip.getWidth(), (int)(nextOriginY - originY) - 1);
165 g2.setClip(clip);
166 }
167
168 boolean wasBuffered = component.isDoubleBuffered();
169 component.paint(g2);
170 component.setDoubleBuffered(wasBuffered);
171
172 //fire the events
173 StatusListener sListener = (StatusListener)MainFrame.getListeners().
174 get("gate.event.StatusListener");
175 if(sListener != null){
176 sListener.statusChanged("Printing page " + (pageIndex + 1) +
177 "/" + pageCount);
178 }
179
180 return PAGE_EXISTS;
181 }
182
183 double originY;
184 }
185
186
187 JComponent component;
188 PageFormat pageFormat;
189 int pageCount;
190 double scaleFactor;
191 }