Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/pjsofts/eurobudget/gui/PrintableComponent.java


1   /*
2    * PrintableComponent.java
3    *
4    * Created on 29 janvier 2003, 16:16
5    */
6   
7   package com.pjsofts.eurobudget.gui;
8   
9   import com.pjsofts.eurobudget.EBConstants;
10  import com.pjsofts.eurobudget.EBPrefs;
11  import com.pjsofts.eurobudget.EBPrefsService;
12  import java.awt.*;
13  import java.awt.geom.AffineTransform;
14  import java.awt.image.BufferedImage;
15  import java.awt.print.PageFormat;
16  import java.awt.print.Pageable;
17  import java.awt.print.Printable;
18  import javax.swing.BorderFactory;
19  import javax.swing.JComponent;
20  import javax.swing.RepaintManager;
21  import javax.swing.border.BevelBorder;
22  
23  /**
24   *  Basic Component that is able to print or preview another component.
25   *  Receive an awt Component in parameters and prints it.
26   *  Could be useed as a Printable or as a JComponent (to preview the printing)
27   */
28  public class PrintableComponent extends JComponent implements Printable, Pageable {
29      
30      /** Initial awt component to render */
31      private Component component = null;
32      /** Page format to use */
33      private PageFormat pageFormat = null;
34      
35  //    too memory consuming depending of size of component :
36  //    /** cache of the raster of the component 
37  //     */
38  //    private  BufferedImage buffer = null;
39      
40      /** flag: make the component fit in page width if needed */
41      private boolean autoFit = true;
42      /** if component is resized; keep its ratio */
43      private boolean keepRatio = true;
44      /** current index of page to display (starting from 0 like Print API) */
45      private int currentPage = 0;
46      /** last computed value for this */
47      private int numberOfPages = 0;
48      
49      /** fit ratio */
50      private double fitRatio = 1.0d;
51      /** zoom value */
52      private double zoom = 1.0d;
53      
54      /** final width for buffer to be in page (same as buffer ) */
55      private int bufferW = 0;
56      /** same as */
57      private int bufferH = 0;
58      //    /** portion width, final width displayed in one portion (same as buffer ) */
59      //    private double width = 0;
60      /** portion height, same as imageableHeight in one portion */
61      private int portionH = 0;
62      
63      /** width of the page on screen in pixel (could be different as the one in page format) due of zoom */
64      private int pageWidth = 0;
65      private int pageHeight = 0;
66      
67      /**
68       * @param autoFit true means expand or collapse component view to page width
69       *
70       */
71      public PrintableComponent(Component component, PageFormat pf, boolean autoFit) {
72          super();
73          this.component = component;
74          this.pageFormat = pf;
75          this.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
76          // reuse static variables (otherwise the action print doesn't get same values as for preview)
77          autoFit = autoFit;
78          keepRatio = true;
79          currentPage = 0;
80          updateInternalData();
81      }
82   
83      /** convenient constructor that take autofit value from preferences */
84      public PrintableComponent(Component component, PageFormat pf) {
85          this(component, pf, EBPrefsService.getBoolean(EBPrefs.PRINT_AUTOFIT,true));
86      }
87      
88      /**
89       * throws PrinterExceptionPrints the page at the specified index into the specified Graphics context in the specified format. A PrinterJob calls the Printable interface to request that a page be rendered into the context specified by graphics. The format of the page to be drawn is specified by pageFormat. The zero based index of the requested page is specified by pageIndex. If the requested page does not exist then this method returns NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned. The Graphics class or subclass implements the PrinterGraphics interface to provide additional information. If the Printable object aborts the print job then it throws a PrinterException.
90       *
91       * Parameters:
92       * graphics - the context into which the page is drawn
93       * pageFormat - the size and orientation of the page being drawn
94       * pageIndex - the zero based index of the page to be drawn
95       * Returns:
96       * PAGE_EXISTS if the page is rendered successfully or NO_SUCH_PAGE if pageIndex specifies a non-existent page.
97       * Throws:
98       * PrinterException - thrown when the print job is terminated.         */
99      public int print(Graphics graphics, PageFormat pf, int pageIndex) {
100         if ( pf.equals(this.pageFormat) ) {
101             this.pageFormat = pf;
102             updateInternalData();
103         }
104         if ( pageIndex <0 || pageIndex >= getNumberOfPages() ) {
105             return Printable.NO_SUCH_PAGE;
106         }
107         double ix = pageFormat.getImageableX();
108         double iy = pageFormat.getImageableY();
109         // draw the good portion of component
110         int sx = 0;
111         int sy = (int)(portionH*currentPage);
112         int sw = (int)(bufferW*fitRatio);
113         int sh = (int)Math.min(portionH, bufferH - sy);
114         if ( EBConstants.DEBUG )
115             System.out.println("Portion: x="+sx+", y= "+sy+" width="+sw+" height="+sh);
116                        
117         BufferedImage tmpImage = new BufferedImage(sw,sh ,BufferedImage.TYPE_3BYTE_BGR);
118         Graphics2D og = tmpImage.createGraphics();
119         og.setBackground(Color.white);
120         og.clearRect(0,0, sw,sh);
121   og.translate(-sx,-sy);
122   og.setClip(sx,sy,sw,sh);
123 //  rm.setDoubleBufferingEnabled(false);
124   component.paint(og);
125 //  rm.setDoubleBufferingEnabled(isDBE);
126         
127         // Paint on screen :
128         Graphics2D g2 = (Graphics2D) graphics;
129         // draw the background: blank page with margin
130         g2.setBackground(Color.white);
131         g2.clearRect(0,0, pageWidth,pageHeight);
132         g2.translate(ix*zoom, iy*zoom);
133         // recopy this computed image on screen :
134         g2.drawRenderedImage(tmpImage, AffineTransform.getScaleInstance(zoom/fitRatio, zoom/fitRatio));
135         og.dispose();
136 
137         return Printable.PAGE_EXISTS;
138     }
139     
140     /** Invoked by Swing to draw components.
141      *
142      * @param g  the <code>Graphics</code> context in which to paint
143      * @see #paintComponent
144      * @see #paintBorder
145      * @see #paintChildren
146      * @see #getComponentGraphics
147      * @see #repaint
148      *
149      */
150     protected void paintComponent(Graphics graph) {
151         if ( EBConstants.DEBUG ) {
152             System.out.println("currentPage="+currentPage);
153             System.out.println("pageFormat="+pageFormat);
154         }
155         print(graph,pageFormat, currentPage);
156     }
157     
158     /**
159      * update current number of pages and cache of original component image.
160      * compute new size of component (width, height) to fit the page.
161      * To call each time pageFormat or component changed.
162      */
163     private void updateInternalData() {
164         // The area of the printable area.
165         double ix = pageFormat.getImageableX();
166         double iy = pageFormat.getImageableY();
167         double iw = pageFormat.getImageableWidth();
168         double ih = pageFormat.getImageableHeight();
169         int pw = (int)pageFormat.getWidth();
170         int ph = (int)pageFormat.getHeight();
171         // The component
172         int compW = component.getWidth();
173         int compH = component.getHeight();
174         if ( autoFit && keepRatio ) {
175             this.bufferW = (int)iw;
176             this.bufferH = (int)(compH * bufferW / compW );
177             this.fitRatio = compW / iw;
178             this.portionH = (int)(ih*fitRatio);
179         } else {
180             this.bufferW = (int)compW;
181             this.bufferH = (int)compH;
182             this.fitRatio = 1.0d;
183             this.portionH = (int)ih;
184         }
185 //        double scaleX = bufferW / compW;
186 //        double scaleY = scaleX;
187         
188         this.pageWidth = (int)(pw *zoom);        
189         this.pageHeight = (int)(ph *zoom);        
190         if ( EBConstants.DEBUG ) {
191             System.out.println("Page: ix="+ix+" iy="+iy+" iw="+iw+" ih="+ih+" pw="+pw+" ph="+ph);
192             System.out.println("Original component: compW="+compW+" compH="+compH);
193 //            System.out.println("scaleX="+scaleX+" scaleY="+scaleY);
194             System.out.println("Resized component: bufferW="+bufferW+" bufferH="+bufferH);
195             System.out.println("portionH="+portionH);
196             System.out.println("Zoom="+zoom+" FitRatio="+fitRatio);
197             System.out.println("Final component on screen: width="+pageWidth+" height="+pageHeight);
198         }
199         // try to avoid !
200         //java.lang.IllegalStateException: constrain(xywh) is not supported for complex transform.
201   //at sun.java2d.SunGraphics2D.constrain(SunGraphics2D.java:295)
202         // may cause an OutOfMemoryError also cause too memory consuming !!!
203 //        System.gc();
204 //        BufferedImage originalImage =  new BufferedImage((int)compW, (int) compH,BufferedImage.TYPE_3BYTE_BGR);
205 //        Graphics2D orig2D = originalImage.createGraphics();
206 //        component.paintAll(orig2D);
207 //        this.buffer = new BufferedImage((int)bufferW, (int) bufferH,BufferedImage.TYPE_3BYTE_BGR);
208 //        Graphics2D g2D = buffer.createGraphics();
209 //        g2D.scale(scaleX,scaleY);
210 //        component.paintAll(g2D);
211         // scall on the fly :
212 //        g2D.drawImage(originalImage,0,0,(int)bufferW, (int)bufferH, this);
213         // to try :
214 //  Graphics og = off.getGraphics();
215 //  og.translate(-clipX,-clipY);
216 //  og.setClip(clipX,clipY,clipW,clipH);
217 //  rm.setDoubleBufferingEnabled(false);
218 //  view.paint(og);
219 //  rm.setDoubleBufferingEnabled(isDBE);
220 //        og.dispose();
221         
222         this.numberOfPages = (int)(bufferH / portionH) + 1;
223         if ( currentPage >=  numberOfPages ) {
224             currentPage = 0;
225         }
226         this.setPreferredSize(new Dimension(pageWidth,pageHeight));
227         this.setSize(pageWidth, pageHeight);
228 //        originalImage = null;// gc flag
229 //        System.gc();
230     }
231     
232     /**
233      * Returns the number of pages in the set.
234      * To enable advanced printing features,
235      * it is recommended that <code>Pageable</code>
236      * implementations return the true number of pages
237      * rather than the
238      * UNKNOWN_NUMBER_OF_PAGES constant.
239      * @return the number of pages in this <code>Pageable</code>.
240      */
241     public int getNumberOfPages() {
242         // updateInternalData should have been called once
243         return this.numberOfPages;
244     }
245     
246 
247     /** If the <code>preferredSize</code> has been set to a
248      * non-<code>null</code> value just returns it.
249      * If the UI delegate's <code>getPreferredSize</code>
250      * method returns a non <code>null</code> value then return that;
251      * otherwise defer to the component's layout manager.
252      *
253      * @return the value of the <code>preferredSize</code> property
254      * @see #setPreferredSize
255      * @see ComponentUI
256      *
257      */
258 //    public Dimension getPreferredSize() {
259 //        Dimension retValue;
260 //        if ( pageFormat != null )
261 //            retValue = new Dimension((int)pageFormat.getWidth(), (int)pageFormat.getHeight());
262 //        else if ( this.component != null )
263 //            retValue = component.getPreferredSize();
264 //        else
265 //            retValue = new Dimension(50, 50);
266 //        //System.out.println("getPreferredSize="+retValue);
267 //        return retValue;
268 //    }
269 //    
270     /**
271      *
272      */
273 //    public Dimension getSize() {
274 //        Dimension retValue;
275 //        if ( pageFormat != null )
276 //            retValue = new Dimension((int)pageFormat.getWidth(), (int)pageFormat.getHeight());
277 //        else if ( this.component != null )
278 //            retValue =  component.getSize();
279 //        else
280 //            retValue = new Dimension(50, 50);
281 //        //System.out.println("getSize="+retValue);
282 //        return retValue;
283 //    }
284     
285     /** Returns true if this component is completely opaque.
286      * <p>
287      * An opaque component paints every pixel within its
288      * rectangular bounds. A non-opaque component paints only a subset of
289      * its pixels or none at all, allowing the pixels underneath it to
290      * "show through".  Therefore, a component that does not fully paint
291      * its pixels provides a degree of transparency.
292      * <p>
293      * Subclasses that guarantee to always completely paint their contents
294      * should override this method and return true.
295      *
296      * @return true if this component is completely opaque
297      * @see #setOpaque
298      *
299      */
300     public boolean isOpaque() {
301         return true;
302     }
303     
304     /** Returns the <code>PageFormat</code> of the page specified by
305      * <code>pageIndex</code>.
306      * @param pageIndex the zero based index of the page whose
307      *            <code>PageFormat</code> is being requested
308      * @return the <code>PageFormat</code> describing the size and
309      *     orientation.
310      * @throws IndexOutOfBoundsException if
311      *          the <code>Pageable</code> does not contain the requested
312      *     page.
313      *
314      */
315     public PageFormat getPageFormat(int pageIndex) throws IndexOutOfBoundsException {
316         return this.pageFormat;
317     }
318     
319     /** Returns the <code>Printable</code> instance responsible for
320      * rendering the page specified by <code>pageIndex</code>.
321      * @param pageIndex the zero based index of the page whose
322      *            <code>Printable</code> is being requested
323      * @return the <code>Printable</code> that renders the page.
324      * @throws IndexOutOfBoundsException if
325      *            the <code>Pageable</code> does not contain the requested
326      *       page.
327      *
328      */
329     public Printable getPrintable(int pageIndex) throws IndexOutOfBoundsException {
330         return this;
331     }
332     
333     /** Getter for property autoFit.
334      * @return Value of property autoFit.
335      *
336      */
337     public boolean isAutoFit() {
338         return autoFit;
339     }
340     
341     /** Setter for property autoFit.
342      * @param autoFit New value of property autoFit.
343      *
344      */
345     public void setAutoFit(boolean autoFit) {
346         this.autoFit = autoFit;
347         updateInternalData();
348         setCurrentPage(currentPage);
349     }
350     
351     /** Getter for property pageFormat.
352      * @return Value of property pageFormat.
353      *
354      */
355     public java.awt.print.PageFormat getPageFormat() {
356         return pageFormat;
357     }
358     
359     /** Setter for property pageFormat.
360      * @param pageFormat New value of property pageFormat.
361      *
362      */
363     public void setPageFormat(java.awt.print.PageFormat pageFormat) {
364         this.pageFormat = pageFormat;
365         updateInternalData();
366         setCurrentPage(currentPage);
367     }
368     
369     /** Getter for property component.
370      * @return Value of property component.
371      *
372      */
373     public java.awt.Component getComponent() {
374         return component;
375     }
376     
377     /** Setter for property component.
378      * @param component New value of property component.
379      *
380      */
381     public void setComponent(java.awt.Component component) {
382         this.component = component;
383         updateInternalData();
384         setCurrentPage(currentPage);
385     }
386     
387     /** Getter for property currentPage.
388      * @return Value of property currentPage.
389      *
390      */
391     public int getCurrentPage() {
392         return currentPage;
393     }
394     
395     /** Setter for property currentPage.
396      * @param currentPage New value of property currentPage.
397      * warning : valid indexes are from 0 to getNumberOfPages -1
398      */
399     public void setCurrentPage(int currentPage) {
400         if ( currentPage >= 0 && currentPage < this.numberOfPages ) {
401             this.currentPage = currentPage;
402             //        this.invalidate();
403             //        this.validate();
404             this.revalidate();
405             this.repaint();
406         }
407     }
408     
409     /** Getter for property zoom.
410      * @return Value of property zoom.
411      *
412      */
413     public double getZoom() {
414         return zoom;
415     }
416     
417     /** Setter for property zoom.
418      * @param zoom New value of property zoom.
419      *
420      */
421     public void setZoom(double zoom) {
422         this.zoom = zoom;
423         updateInternalData();
424         setCurrentPage(currentPage);
425     }
426     
427 }