JComponentPrinter.java
001 /*
002  *  Copyright (c) 1995-2010, The University of Sheffield. See the file
003  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
004  *
005  *  This file is part of GATE (see http://gate.ac.uk/), and is free
006  *  software, licenced under the GNU Library General Public License,
007  *  Version 2, June 1991 (in the distribution as file licence.html,
008  *  and also available at http://gate.ac.uk/gate/licence.html).
009  *
010  *  Valentin Tablan 07/12/2001
011  *
012  *  $Id: JComponentPrinter.java 12950 2010-08-11 18:58:56Z bensonmargulies $
013  *
014  */
015 package gate.print;
016 
017 import java.awt.*;
018 import java.awt.print.*;
019 
020 import javax.swing.JComponent;
021 import javax.swing.text.BadLocationException;
022 import javax.swing.text.JTextComponent;
023 
024 import gate.Gate;
025 import gate.event.StatusListener;
026 import gate.util.Err;
027 
028 
029 /**
030  * Will scale the component so it fits on a page horizontally
031  */
032 public class JComponentPrinter implements Pageable{
033 
034   public JComponentPrinter(JComponent component, PageFormat format){
035     this.component = component;
036     this.pageFormat = format;
037     //find the scale factor; we will not enlarge as it would look ugly
038     Rectangle componentBounds = component.getBounds(null);
039     scaleFactor = Math.min(format.getImageableWidth() /componentBounds.width,
040                            1);
041 
042     //calculate the pages count
043     pageCount = (int)((componentBounds.height * scaleFactor +
044                        pageFormat.getImageableHeight() 1/
045                        pageFormat.getImageableHeight());
046   }
047 
048   /**
049    * Returns the number of pages over which the canvas
050    * will be drawn.
051    */
052   public int getNumberOfPages() {
053     return pageCount;
054   }
055 
056 
057   /**
058    * Returns the PageFormat of the page specified by
059    * pageIndex. The PageFormat is the same for all pages.
060    *
061    @param pageIndex the zero based index of the page whose
062    * PageFormat is being requested
063    @return the PageFormat describing the size and
064    * orientation.
065    @exception IndexOutOfBoundsException
066    * the Pageable  does not contain the requested
067    * page.
068    */
069   public PageFormat getPageFormat(int pageIndex)
070          throws IndexOutOfBoundsException {
071     if (pageIndex >= pageCountthrow new IndexOutOfBoundsException();
072     return pageFormat;
073   }
074 
075 
076   /**
077    * Returns the <code>Printable</code> instance responsible for
078    * rendering the page specified by <code>pageIndex</code>.
079    *
080    @param pageIndex the zero based index of the page whose
081    * Printable is being requested
082    @return the Printable that renders the page.
083    @exception IndexOutOfBoundsException
084    * the Pageable does not contain the requested
085    * page.
086    */
087   public Printable getPrintable(int pageIndex)
088          throws IndexOutOfBoundsException {
089     if (pageIndex >= pageCount)throw new IndexOutOfBoundsException();
090 
091     double originY = pageIndex * pageFormat.getImageableHeight() / scaleFactor;
092     if(component instanceof JTextComponent){
093       JTextComponent tComp = (JTextComponent)component;
094       //move the origin up towards the first inter-row space
095       int location = tComp.viewToModel(new Point(0(int)originY));
096       try{
097         Rectangle rect = tComp.modelToView(location);
098         originY = rect.y + rect.height - 1;
099       }catch(BadLocationException ble){
100         ble.printStackTrace(Err.getPrintWriter());
101       }
102     }
103 
104     return new TranslatedPrintable(originY);
105   }
106 
107 
108 /**
109    * This inner class's sole responsibility is to translate
110    * the coordinate system before invoking a canvas's
111    * painter. The coordinate system is translated in order
112    * to get the desired portion of a canvas to line up with
113    * the top of a page.
114    */
115   public class TranslatedPrintable implements Printable {
116     public TranslatedPrintable(double originY){
117       this.originY = originY;
118     }
119 
120     /**
121      * Prints the page at the specified index into the specified
122      {@link Graphics} context in the specified
123      * format. A PrinterJob calls the
124      * Printableinterface to request that a page be
125      * rendered into the context specified by
126      * graphics. The format of the page to be drawn is
127      * specified by pageFormat. The zero based index
128      * of the requested page is specified by pageIndex.
129      * If the requested page does not exist then this method returns
130      * NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned.
131      * The Graphics class or subclass implements the
132      {@link PrinterGraphics} interface to provide additional
133      * information. If the Printable object
134      * aborts the print job then it throws a {@link PrinterException}.
135      @param graphics the context into which the page is drawn
136      @param pageFormat the size and orientation of the page being drawn
137      @param pageIndex the zero based index of the page to be drawn
138      @return PAGE_EXISTS if the page is rendered successfully
139      * or NO_SUCH_PAGE if pageIndex specifies a
140      * non-existent page.
141      @exception java.awt.print.PrinterException
142      * thrown when the print job is terminated.
143      */
144     public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
145                throws PrinterException {
146 
147       Rectangle componentBounds = component.getBounds(null);
148       Graphics2D g2 = (Graphics2Dgraphics;
149       g2.translate(pageFormat.getImageableX() - componentBounds.x,
150                    pageFormat.getImageableY() - originY - componentBounds.y);
151       g2.scale(scaleFactor, scaleFactor);
152 
153       if(component instanceof JTextComponent){
154         JTextComponent tComp = (JTextComponent)component;
155         double nextOriginY = (pageIndex + 1* pageFormat.getImageableHeight() /
156                              scaleFactor;
157         int location = tComp.viewToModel(new Point(0(int)nextOriginY));
158         try{
159           Rectangle rect = tComp.modelToView(location);
160           nextOriginY = rect.y;
161         }catch(BadLocationException ble){
162           ble.printStackTrace(Err.getPrintWriter());
163         }
164         Rectangle clip = g2.getClip().getBounds();
165         clip.setSize((int)clip.getWidth()(int)(nextOriginY - originY1);
166         g2.setClip(clip);
167       }
168 
169       boolean wasBuffered = component.isDoubleBuffered();
170       component.paint(g2);
171       component.setDoubleBuffered(wasBuffered);
172 
173       //fire the events
174       StatusListener sListener = (StatusListener)Gate.getListeners().
175                                  get("gate.event.StatusListener");
176       if(sListener != null){
177         sListener.statusChanged("Printing page " (pageIndex + 1+
178                                 "/" + pageCount);
179       }
180 
181       return PAGE_EXISTS;
182     }
183 
184     double originY;
185   }
186 
187 
188   JComponent component;
189   PageFormat pageFormat;
190   int pageCount;
191   double scaleFactor;
192 }