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

Quick Search    Search Deep

Source code: com/virtuosotechnologies/asaph/standardgui/PrintHandler.java


1   /*
2   ================================================================================
3   
4     FILE:  PrintHandler.java
5     
6     PROJECT:
7     
8       Asaph
9     
10    CONTENTS:
11    
12      An object that manages printing
13    
14    PROGRAMMERS:
15    
16      Daniel Azuma (DA)  <dazuma@kagi.com>
17    
18    COPYRIGHT:
19    
20      Copyright (C) 2003  Daniel Azuma  (dazuma@kagi.com)
21      
22      This program is free software; you can redistribute it and/or
23      modify it under the terms of the GNU General Public License as
24      published by the Free Software Foundation; either version 2
25      of the License, or (at your option) any later version.
26      
27      This program is distributed in the hope that it will be useful,
28      but WITHOUT ANY WARRANTY; without even the implied warranty of
29      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30      GNU General Public License for more details.
31      
32      You should have received a copy of the GNU General Public
33      License along with this program; if not, write to
34        Free Software Foundation, Inc.
35        59 Temple Place, Suite 330
36        Boston, MA 02111-1307 USA
37  
38  ================================================================================
39  */
40  
41  
42  package com.virtuosotechnologies.asaph.standardgui;
43  
44  
45  import java.awt.Font;
46  import java.awt.Color;
47  import java.awt.FlowLayout;
48  import java.awt.GridBagLayout;
49  import java.awt.GridBagConstraints;
50  import java.awt.Frame;
51  import java.awt.Insets;
52  import java.awt.Graphics;
53  import java.awt.Graphics2D;
54  import java.awt.event.ActionListener;
55  import java.awt.event.ActionEvent;
56  import java.awt.print.Printable;
57  import java.awt.print.Pageable;
58  import java.awt.print.PrinterJob;
59  import java.awt.print.PageFormat;
60  import java.awt.print.PrinterException;
61  import java.util.Hashtable;
62  import javax.swing.JComponent;
63  import javax.swing.JDialog;
64  import javax.swing.JPanel;
65  import javax.swing.JLabel;
66  import javax.swing.JRadioButton;
67  import javax.swing.JComboBox;
68  import javax.swing.JSlider;
69  import javax.swing.JButton;
70  import javax.swing.ButtonGroup;
71  import javax.swing.event.ChangeListener;
72  import javax.swing.event.ChangeEvent;
73  import javax.print.attribute.PrintRequestAttributeSet;
74  
75  import com.virtuosotechnologies.lib.asyncjob.AsyncJobRunner;
76  import com.virtuosotechnologies.lib.asyncjob.AbstractAsyncJob;
77  import com.virtuosotechnologies.lib.asyncjob.AsyncJob;
78  import com.virtuosotechnologies.lib.asyncjob.AsyncJobProgressReporter;
79  import com.virtuosotechnologies.lib.asyncjob.AsyncJobException;
80  
81  
82  /**
83   * An object that manages printing.
84   */
85  /*package*/ class PrintHandler
86  implements Printable, Pageable
87  {
88    private static final String STR_PrintHandler_FormatDialog_Title =
89      ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_Title");
90    private static final String STR_PrintHandler_FormatDialog_PromptLabel =
91      ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_PromptLabel");
92    private static final String STR_PrintHandler_FormatDialog_ScaleRadio =
93      ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_ScaleRadio");
94    private static final String STR_PrintHandler_FormatDialog_FlowRadio =
95      ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_FlowRadio");
96    private static final String STR_PrintHandler_FormatDialog_ColumnsLabel =
97      ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_ColumnsLabel");
98    private static final String STR_PrintHandler_FormatDialog_GutterLabel =
99      ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_GutterLabel");
100   private static final String STR_PrintHandler_FormatDialog_0InchLabel =
101     ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_0InchLabel");
102   private static final String STR_PrintHandler_FormatDialog_HalfInchLabel =
103     ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_HalfInchLabel");
104   private static final String STR_PrintHandler_FormatDialog_1InchLabel =
105     ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_1InchLabel");
106   private static final String STR_PrintHandler_FormatDialog_PrintButton =
107     ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_PrintButton");
108   private static final String STR_PrintHandler_FormatDialog_CancelButton =
109     ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_CancelButton");
110   private static final String STR_PrintHandler_FormatDialog_PrintJobName =
111     ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_PrintJobName");
112   
113   private static final Font SMALL_FONT = new Font("Dialog", Font.PLAIN, 9);
114   
115   private RenderHelper helper_;
116   
117   private JComponent dialogParent_;
118   private AsyncJobRunner jobRunner_;
119   
120   private PrinterJob printJob_;
121   private PageFormat pageFormat_;
122   private PrintRequestAttributeSet attrs_;
123   
124   // Settings for formatting
125   private boolean fitOnOnePage_;
126   private boolean okayed_;
127   private PrintRenderHelper flowingRender_;
128   private float scaleRequired_;
129   
130   // Page format analysis
131   private float pageWidth_;
132   private float pageHeight_;
133   private float imageableLeft_;
134   private float imageableTop_;
135   private float imageableRight_;
136   private float imageableBottom_;
137   private float imageableWidth_;
138   private float imageableHeight_;
139   private float imageableHCenter_;
140   private float imageableVCenter_;
141   
142   
143   /**
144    * Pseudo-Constructor
145    */
146   /*package*/ static PrintHandler create(
147     PrinterJob job,
148     PrintRequestAttributeSet attrs,
149     RenderHelper renderHelper,
150     JComponent dialogParent,
151     AsyncJobRunner jobRunner)
152   {
153     PrintHandler handler = new PrintHandler(job, attrs, renderHelper, dialogParent, jobRunner);
154     if (handler.displayPrintDialogs())
155     {
156       if (handler.validateFormat())
157       {
158         return handler;
159       }
160     }
161     return null;
162   }
163   
164   
165   /**
166    * Constructor
167    */
168   private PrintHandler(
169     PrinterJob job,
170     PrintRequestAttributeSet attrs,
171     RenderHelper renderHelper,
172     JComponent dialogParent,
173     AsyncJobRunner jobRunner)
174   {
175     printJob_ = job;
176     attrs_ = attrs;
177     helper_ = renderHelper;
178     dialogParent_ = dialogParent;
179     scaleRequired_ = 1;
180     fitOnOnePage_ = true;
181     jobRunner_ = jobRunner;
182   }
183   
184   
185   /**
186    * Display print dialogs
187    */
188   private boolean displayPrintDialogs()
189   {
190     if (printJob_.printDialog(attrs_))
191     {
192       PageFormat format = printJob_.pageDialog(attrs_);
193       if (format != null)
194       {
195         setPageFormat(format);
196         return true;
197       }
198     }
199     return false;
200   }
201   
202   
203   /**
204    * Check formatting
205    */
206   private boolean validateFormat()
207   {
208     if (helper_.getWidth() <= imageableWidth_ && helper_.getHeight() <= imageableHeight_)
209     {
210       // It all fits in one page
211       return true;
212     }
213     
214     scaleRequired_ = Math.min(imageableWidth_/helper_.getWidth(),
215       imageableHeight_/helper_.getHeight());
216     
217     // Start building dialog
218     final JDialog dialog = new JDialog((Frame)dialogParent_.getTopLevelAncestor(),
219       STR_PrintHandler_FormatDialog_Title, true);
220     JPanel content = new JPanel(new GridBagLayout());
221     dialog.setContentPane(content);
222     GridBagConstraints gbc = new GridBagConstraints();
223     gbc.gridx = 0;
224     gbc.anchor = GridBagConstraints.WEST;
225     gbc.gridwidth = 2;
226     
227     JLabel label = new JLabel(STR_PrintHandler_FormatDialog_PromptLabel);
228     gbc.insets = new Insets(10, 10, 10, 10);
229     content.add(label, gbc);
230     
231     ButtonGroup radioGroup = new ButtonGroup();
232     
233     // Scale-style radio button
234     JRadioButton scaleRadio = new JRadioButton(STR_PrintHandler_FormatDialog_ScaleRadio, true);
235     gbc.insets = new Insets(0, 10, 3, 10);
236     content.add(scaleRadio, gbc);
237     radioGroup.add(scaleRadio);
238     
239     // Scale-style requirements
240     JLabel scaleReqLabel = new JLabel(
241       ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_ScaleRequires",
242         Integer.toString((int)(scaleRequired_*100))));
243     gbc.insets = new Insets(0, 40, 10, 10);
244     content.add(scaleReqLabel, gbc);
245     
246     // Flow-style radio button
247     JRadioButton flowRadio = new JRadioButton(STR_PrintHandler_FormatDialog_FlowRadio);
248     gbc.insets = new Insets(0, 10, 3, 10);
249     content.add(flowRadio, gbc);
250     radioGroup.add(flowRadio);
251     
252     // Columns combo and label
253     label = new JLabel(STR_PrintHandler_FormatDialog_ColumnsLabel);
254     gbc.insets = new Insets(0, 40, 5, 5);
255     gbc.gridwidth = 1;
256     content.add(label, gbc);
257     
258     final JComboBox columnsCombo = new JComboBox(new Integer[]{
259       new Integer(1), new Integer(2), new Integer(3), new Integer(4)});
260     gbc.insets = new Insets(0, 0, 5, 10);
261     gbc.gridx = 1;
262     gbc.weightx = 1;
263     content.add(columnsCombo, gbc);
264     
265     // Gutter slider and label
266     label = new JLabel(STR_PrintHandler_FormatDialog_GutterLabel);
267     gbc.insets = new Insets(0, 40, 0, 5);
268     gbc.gridx = 0;
269     gbc.weightx = 0;
270     gbc.anchor = GridBagConstraints.SOUTHWEST;
271     content.add(label, gbc);
272     
273     final JLabel gutterWidthLabel = new JLabel(
274       ResourceAccess.Strings.buildString("PrintHandler_FormatDialog_GutterPoints", "24"));
275     gbc.insets = new Insets(0, 40, 5, 5);
276     gbc.anchor = GridBagConstraints.NORTHWEST;
277     content.add(gutterWidthLabel, gbc);
278     
279     final JSlider gutterWidthSlider = new JSlider(0, 72, 24);
280     Hashtable labelTable = new Hashtable();
281     label = new JLabel(STR_PrintHandler_FormatDialog_0InchLabel);
282     label.setFont(SMALL_FONT);
283     labelTable.put(new Integer(0), label);
284     label = new JLabel(STR_PrintHandler_FormatDialog_HalfInchLabel);
285     label.setFont(SMALL_FONT);
286     labelTable.put(new Integer(36), label);
287     label = new JLabel(STR_PrintHandler_FormatDialog_1InchLabel);
288     label.setFont(SMALL_FONT);
289     labelTable.put(new Integer(72), label);
290     gutterWidthSlider.setLabelTable(labelTable);
291     gutterWidthSlider.setPaintLabels(true);
292     gutterWidthSlider.setPaintTicks(true);
293     gutterWidthSlider.setMajorTickSpacing(36);
294     gutterWidthSlider.setMinorTickSpacing(12);
295     gbc.insets = new Insets(0, 0, 5, 10);
296     gbc.gridx = 1;
297     gbc.gridheight = 2;
298     gbc.weightx = 1;
299     gbc.anchor = GridBagConstraints.WEST;
300     content.add(gutterWidthSlider, gbc);
301     
302     // Flowed-style requirements
303     final JLabel flowReqLabel = new JLabel();
304     gbc.insets = new Insets(0, 40, 5, 10);
305     gbc.gridx = 0;
306     gbc.gridheight = 1;
307     gbc.gridwidth = 2;
308     gbc.weightx = 0;
309     content.add(flowReqLabel, gbc);
310     
311     // Updaters
312     columnsCombo.addActionListener(
313       new ActionListener()
314       {
315         public void actionPerformed(
316           ActionEvent ev)
317         {
318           recalcPrintHelper(((Integer)columnsCombo.getSelectedItem()).intValue(),
319             gutterWidthSlider.getValue(), gutterWidthLabel, flowReqLabel);
320         }
321       });
322     gutterWidthSlider.addChangeListener(
323       new ChangeListener()
324       {
325         public void stateChanged(
326           ChangeEvent ev)
327         {
328           gutterWidthLabel.setText(ResourceAccess.Strings.buildString(
329             "PrintHandler_FormatDialog_GutterPoints",
330             Integer.toString(gutterWidthSlider.getValue())));
331           if (!gutterWidthSlider.getValueIsAdjusting())
332           {
333             recalcPrintHelper(((Integer)columnsCombo.getSelectedItem()).intValue(),
334               gutterWidthSlider.getValue(), gutterWidthLabel, flowReqLabel);
335           }
336         }
337       });
338     recalcPrintHelper(1, 24, gutterWidthLabel, flowReqLabel);
339     
340     // Build buttons
341     JPanel buttonPanel = new JPanel(new FlowLayout());
342     JButton okButton = new JButton(STR_PrintHandler_FormatDialog_PrintButton);
343     buttonPanel.add(okButton);
344     JButton cancelButton = new JButton(STR_PrintHandler_FormatDialog_CancelButton);
345     buttonPanel.add(cancelButton);
346     gbc.insets = new Insets(5, 10, 5, 10);
347     gbc.fill = GridBagConstraints.HORIZONTAL;
348     content.add(buttonPanel, gbc);
349     
350     okButton.addActionListener(
351       new ActionListener()
352       {
353         public void actionPerformed(
354           ActionEvent ev)
355         {
356           okayed_ = true;
357           dialog.dispose();
358         }
359       });
360     cancelButton.addActionListener(
361       new ActionListener()
362       {
363         public void actionPerformed(
364           ActionEvent ev)
365         {
366           okayed_ = false;
367           dialog.dispose();
368         }
369       });
370     okayed_ = false;
371     
372     // Show dialog
373     dialog.pack();
374     dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
375     dialog.setResizable(false);
376     dialog.setLocationRelativeTo(dialogParent_);
377     dialog.show();
378     fitOnOnePage_ = scaleRadio.isSelected();
379     
380     return okayed_;
381   }
382   
383   
384   private void recalcPrintHelper(
385     int columns,
386     int gutterWidth,
387     JLabel gutterWidthLabel,
388     JLabel flowReqLabel)
389   {
390     flowingRender_ = new PrintRenderHelper(helper_,
391       imageableWidth_, imageableHeight_, columns, gutterWidth);
392     flowReqLabel.setText(ResourceAccess.Strings.buildString(
393       "PrintHandler_FormatDialog_FlowRequires",
394       Integer.toString((int)(flowingRender_.getRequiredScale()*100))));
395   }
396   
397   
398   /**
399    * Do the actual printing
400    */
401   /*package*/ void doPrint()
402   {
403     // Do the print
404     printJob_.setPageable(this);
405     jobRunner_.startJob(
406       new AbstractAsyncJob(STR_PrintHandler_FormatDialog_PrintJobName,
407         false, AsyncJob.INDETERMINATE_PROGRESS, null)
408       {
409         public Object run(
410           AsyncJobProgressReporter reporter)
411         throws
412           AsyncJobException
413         {
414           try
415           {
416             printJob_.print(attrs_);
417           }
418           catch (PrinterException ex)
419           {
420             throw new AsyncJobException(ex);
421           }
422           return null;
423         }
424       });
425   }
426   
427   
428   /**
429    * Implementation of Pageable
430    */
431   public int getNumberOfPages()
432   {
433     if (fitOnOnePage_)
434     {
435       return 1;
436     }
437     return flowingRender_.getNumPages();
438   }
439   
440   
441   /**
442    * Implementation of Pageable
443    */
444   public PageFormat getPageFormat(
445     int pageIndex)
446   {
447     return pageFormat_;
448   }
449   
450   
451   /**
452    * Implementation of Pageable
453    */
454   public Printable getPrintable(
455     int pageIndex)
456   {
457     return this;
458   }
459   
460   
461   /**
462    * Implementation of Printable
463    */
464   public int print(
465     Graphics g,
466     PageFormat pageFormat,
467     int pageIndex)
468   {
469     if (pageIndex >= getNumberOfPages())
470     {
471       return NO_SUCH_PAGE;
472     }
473     Graphics2D g2d = (Graphics2D)g;
474     
475     RenderHelper.mungeGraphics2D(g2d);
476     
477     g2d.setColor(Color.white);
478     g2d.fillRect(0, 0, (int)pageWidth_, (int)pageHeight_);
479     g2d.setColor(Color.black);
480     
481     if (fitOnOnePage_)
482     {
483       g2d.scale(scaleRequired_, scaleRequired_);
484       float scaledHCenter = imageableHCenter_/scaleRequired_;
485       float scaledVCenter = imageableVCenter_/scaleRequired_;
486       RenderHelper helper = helper_.createUsingGraphics(g2d);
487       helper.paint(g2d, scaledHCenter-(helper.getWidth()*0.5f),
488         scaledVCenter-(helper.getHeight()*0.5f));
489     }
490     else
491     {
492       PrintRenderHelper printHelper = flowingRender_.createUsingGraphics(g2d);
493       float scaleRequired = printHelper.getRequiredScale();
494       g2d.scale(scaleRequired, scaleRequired);
495       float scaledHCenter = imageableHCenter_/scaleRequired;
496       float scaledVCenter = imageableVCenter_/scaleRequired;
497       printHelper.paintPage(pageIndex, g2d,
498         scaledHCenter-(printHelper.getWidth()*0.5f),
499         scaledVCenter-(printHelper.getHeightForPage(pageIndex)*0.5f));
500     }
501     
502     return PAGE_EXISTS;
503   }
504   
505   
506   private void setPageFormat(
507     PageFormat pageFormat)
508   {
509     pageFormat_ = pageFormat;
510     pageWidth_ = (float)pageFormat_.getWidth();
511     pageHeight_ = (float)pageFormat_.getHeight();
512     imageableLeft_ = (float)pageFormat_.getImageableX();
513     imageableTop_ = (float)pageFormat_.getImageableY();
514     imageableRight_ = imageableLeft_+(float)pageFormat_.getImageableWidth();
515     imageableBottom_ = imageableTop_+(float)pageFormat_.getImageableHeight();
516     if (imageableLeft_ < 36) imageableLeft_ = 36;
517     if (imageableTop_ < 36) imageableTop_ = 36;
518     if (imageableRight_ > pageWidth_-36) imageableRight_ = pageWidth_-36;
519     if (imageableBottom_ > pageHeight_-36) imageableBottom_ = pageHeight_-36;
520     imageableWidth_ = imageableRight_-imageableLeft_;
521     imageableHeight_ = imageableBottom_-imageableTop_;
522     imageableHCenter_ = (imageableRight_+imageableLeft_)*0.5f;
523     imageableVCenter_ = (imageableBottom_+imageableTop_)*0.5f;
524   }
525 }