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