Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extGraph / src / org / gvsig / graph / core / DocumentRenderer.java @ 39203

History | View | Annotate | Download (16.4 KB)

1
/*  Copyright 2002
2
    Kei G. Gauthier
3
    Suite 301
4
    77 Winsor Street
5
    Ludlow, MA  01056
6
 */
7

    
8
package org.gvsig.graph.core;
9

    
10
import java.awt.Component;
11
import java.awt.Graphics;
12
import java.awt.Graphics2D;
13
import java.awt.Rectangle;
14
import java.awt.Shape;
15
import java.awt.print.PageFormat;
16
import java.awt.print.Paper;
17
import java.awt.print.Printable;
18
import java.awt.print.PrinterJob;
19

    
20
import javax.print.Doc;
21
import javax.print.DocFlavor;
22
import javax.print.DocPrintJob;
23
import javax.print.PrintException;
24
import javax.print.PrintService;
25
import javax.print.PrintServiceLookup;
26
import javax.print.ServiceUI;
27
import javax.print.SimpleDoc;
28
import javax.print.attribute.PrintRequestAttributeSet;
29
import javax.print.event.PrintJobAdapter;
30
import javax.print.event.PrintJobEvent;
31
import javax.print.event.PrintJobListener;
32
import javax.swing.JEditorPane;
33
import javax.swing.JOptionPane;
34
import javax.swing.text.Document;
35
import javax.swing.text.PlainDocument;
36
import javax.swing.text.View;
37
import javax.swing.text.html.HTMLDocument;
38

    
39
import org.apache.log4j.Logger;
40

    
41
import com.iver.andami.PluginServices;
42
import com.iver.cit.gvsig.project.documents.layout.Attributes;
43

    
44
public class DocumentRenderer implements Printable {
45
        /*
46
         * DocumentRenderer prints objects of type Document. Text attributes,
47
         * including fonts, color, and small icons, will be rendered to a printed
48
         * page. DocumentRenderer computes line breaks, paginates, and performs
49
         * other formatting.
50
         * 
51
         * An HTMLDocument is printed by sending it as an argument to the
52
         * print(HTMLDocument) method. A PlainDocument is printed the same way.
53
         * Other types of documents must be sent in a JEditorPane as an argument to
54
         * the print(JEditorPane) method. Printing Documents in this way will
55
         * automatically display a print dialog.
56
         * 
57
         * As objects which implement the Printable Interface, instances of the
58
         * DocumentRenderer class can also be used as the argument in the
59
         * setPrintable method of the PrinterJob class. Instead of using the print()
60
         * methods detailed above, a programmer may gain access to the formatting
61
         * capabilities of this class without using its print dialog by creating an
62
         * instance of DocumentRenderer and setting the document to be printed with
63
         * the setDocument() or setJEditorPane(). The Document may then be printed
64
         * by setting the instance of DocumentRenderer in any PrinterJob.
65
         */
66

    
67
        private static boolean useDefaultJavaPrinting = true;
68
        
69
        protected int currentPage = -1; // Used to keep track of when
70
        // the page to print changes.
71

    
72
        protected JEditorPane jeditorPane; // Container to hold the
73
        // Document. This object will
74
        // be used to lay out the
75
        // Document for printing.
76

    
77
        protected double pageEndY = 0; // Location of the current page
78
        // end.
79

    
80
        protected double pageStartY = 0; // Location of the current page
81
        // start.
82

    
83
        protected boolean scaleWidthToFit = false; // boolean to allow control over
84
        // whether pages too wide to fit
85
        // on a page will be scaled.
86

    
87
        private PrintService[] m_cachePrintServices = null;
88
        private PrintService m_cachePrintService = null;
89

    
90
        /*
91
         * The DocumentRenderer class uses pFormat and pJob in its methods. Note
92
         * that pFormat is not the variable name used by the print method of the
93
         * DocumentRenderer. Although it would always be expected to reference the
94
         * pFormat object, the print method gets its PageFormat as an argument.
95
         */
96
        protected PageFormat pFormat;
97
        protected PrinterJob pJob;
98

    
99
        /*
100
         * The constructor initializes the pFormat and PJob variables.
101
         */
102
        public DocumentRenderer() {
103
                pFormat = new PageFormat();
104
                pJob = PrinterJob.getPrinterJob();
105
        }
106

    
107
        /*
108
         * Method to get the current Document
109
         */
110
        public Document getDocument() {
111
                if (jeditorPane != null)
112
                        return jeditorPane.getDocument();
113
                else
114
                        return null;
115
        }
116

    
117
        /*
118
         * Method to get the current choice the width scaling option.
119
         */
120
        public boolean getScaleWidthToFit() {
121
                return scaleWidthToFit;
122
        }
123

    
124
        /*
125
         * pageDialog() displays a page setup dialog.
126
         */
127
        public void pageDialog() {
128
                pFormat = pJob.pageDialog(pFormat);
129
        }
130

    
131
        /*
132
         * The print method implements the Printable interface. Although Printables
133
         * may be called to render a page more than once, each page is painted in
134
         * order. We may, therefore, keep track of changes in the page being
135
         * rendered by setting the currentPage variable to equal the pageIndex, and
136
         * then comparing these variables on subsequent calls to this method. When
137
         * the two variables match, it means that the page is being rendered for the
138
         * second or third time. When the currentPage differs from the pageIndex, a
139
         * new page is being requested.
140
         * 
141
         * The highlights of the process used print a page are as follows:
142
         * 
143
         * I. The Graphics object is cast to a Graphics2D object to allow for
144
         * scaling. II. The JEditorPane is laid out using the width of a printable
145
         * page. This will handle line breaks. If the JEditorPane cannot be sized at
146
         * the width of the graphics clip, scaling will be allowed. III. The root
147
         * view of the JEditorPane is obtained. By examining this root view and all
148
         * of its children, printView will be able to determine the location of each
149
         * printable element of the document. IV. If the scaleWidthToFit option is
150
         * chosen, a scaling ratio is determined, and the graphics2D object is
151
         * scaled. V. The Graphics2D object is clipped to the size of the printable
152
         * page. VI. currentPage is checked to see if this is a new page to render.
153
         * If so, pageStartY and pageEndY are reset. VII. To match the coordinates
154
         * of the printable clip of graphics2D and the allocation rectangle which
155
         * will be used to lay out the views, graphics2D is translated to begin at
156
         * the printable X and Y coordinates of the graphics clip. VIII. An
157
         * allocation Rectangle is created to represent the layout of the Views.
158
         * 
159
         * The Printable Interface always prints the area indexed by reference to
160
         * the Graphics object. For instance, with a standard 8.5 x 11 inch page
161
         * with 1 inch margins the rectangle X = 72, Y = 72, Width = 468, and Height
162
         * = 648, the area 72, 72, 468, 648 will be painted regardless of which page
163
         * is actually being printed.
164
         * 
165
         * To align the allocation Rectangle with the graphics2D object two things
166
         * are done. The first step is to translate the X and Y coordinates of the
167
         * graphics2D object to begin at the X and Y coordinates of the printable
168
         * clip, see step VII. Next, when printing other than the first page, the
169
         * allocation rectangle must start laying out in coordinates represented by
170
         * negative numbers. After page one, the beginning of the allocation is
171
         * started at minus the page end of the prior page. This moves the part
172
         * which has already been rendered to before the printable clip of the
173
         * graphics2D object.
174
         * 
175
         * X. The printView method is called to paint the page. Its return value
176
         * will indicate if a page has been rendered.
177
         * 
178
         * Although public, print should not ordinarily be called by programs other
179
         * than PrinterJob.
180
         */
181
        public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) {
182
                double scale = 1.0;
183
                Graphics2D graphics2D;
184
                View rootView;
185
                // I
186
                graphics2D = (Graphics2D) graphics;
187
                // II
188
                jeditorPane.setSize((int) pageFormat.getImageableWidth(),
189
                                Integer.MAX_VALUE);
190
                jeditorPane.validate();
191
                // III
192
                rootView = jeditorPane.getUI().getRootView(jeditorPane);
193
                // IV
194
                graphics2D.translate(70, 0);
195
                if ((scaleWidthToFit)
196
                                && (jeditorPane.getMinimumSize().getWidth() > pageFormat
197
                                                .getImageableWidth())) {
198
                        scale = pageFormat.getImageableWidth()
199
                                        / jeditorPane.getMinimumSize().getWidth();
200
                        graphics2D.scale(scale, scale);
201
                }
202
                // V
203
                graphics2D.setClip((int) (pageFormat.getImageableX() / scale),
204
                                (int) (pageFormat.getImageableY() / scale), (int) (pageFormat
205
                                                .getImageableWidth() / scale), (int) (pageFormat
206
                                                .getImageableHeight() / scale));
207
                // VI
208
                if (pageIndex > currentPage) {
209
                        currentPage = pageIndex;
210
                        pageStartY += pageEndY;
211
                        pageEndY = graphics2D.getClipBounds().getHeight();
212
                }
213
                // VII
214
                graphics2D.translate(graphics2D.getClipBounds().getX(), graphics2D
215
                                .getClipBounds().getY());
216
                // VIII
217
                Rectangle allocation = new Rectangle(0, (int) -pageStartY,
218
                                (int) (jeditorPane.getMinimumSize().getWidth()),
219
                                (int) (jeditorPane.getPreferredSize().getHeight()));
220
                // X
221
                if (printView(graphics2D, allocation, rootView)) {
222
                        return Printable.PAGE_EXISTS;
223
                } else {
224
                        pageStartY = 0;
225
                        pageEndY = 0;
226
                        currentPage = -1;
227
                        return Printable.NO_SUCH_PAGE;
228
                }
229
        }
230

    
231
        /*
232
         * print(HTMLDocument) is called to set an HTMLDocument for printing.
233
         */
234
        public void print(HTMLDocument htmlDocument) {
235
                setDocument(htmlDocument);
236
                printDialog();
237
        }
238

    
239
        /*
240
         * print(JEditorPane) prints a Document contained within a JEDitorPane.
241
         */
242
        public void print(JEditorPane jedPane) {
243
                setDocument(jedPane);
244
                printDialog();
245
        }
246

    
247
        /*
248
         * print(PlainDocument) is called to set a PlainDocument for printing.
249
         */
250
        public void print(PlainDocument plainDocument) {
251
                setDocument(plainDocument);
252
                printDialog();
253
        }
254

    
255
        /*
256
         * A protected method, printDialog(), displays the print dialog and
257
         * initiates printing in response to user input.
258
         */
259
        protected void printDialog() {
260
                Attributes m_attributes = new Attributes();
261
                m_attributes.setIsLandScape(false);
262
                PageFormat pf = m_attributes.getPageFormat();
263
                pf.setOrientation(PageFormat.PORTRAIT);
264
                double w = pf.getImageableWidth();
265
                double h = pf.getImageableHeight();
266
                Paper paper = pf.getPaper();
267
                paper.setImageableArea(pf.getImageableX() + 110, pf.getImageableY(), w -110, h-50);
268
                pf.setPaper(paper);
269
                PrintRequestAttributeSet att = m_attributes.toPrintAttributes();
270
//                att = new HashPrintRequestAttributeSet();
271
                DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
272
                try {
273
                        if (m_cachePrintServices == null) {
274
                                m_cachePrintServices = PrintServiceLookup.lookupPrintServices(
275
                                                flavor, null);
276
                        }
277

    
278
                        PrintService defaultService = null;
279

    
280
                        if (m_cachePrintService == null) {
281
                                defaultService = PrintServiceLookup.lookupDefaultPrintService();
282
                        }
283

    
284
                        if(m_cachePrintService == null && defaultService == null && m_cachePrintServices.length > 0)
285
                    defaultService = m_cachePrintServices[0];
286
                        
287
            if ((defaultService == null) && (m_cachePrintService == null)) {
288
                JOptionPane.showMessageDialog((Component) PluginServices
289
                        .getMainFrame(),PluginServices.getText(this,"ninguna_impresora_configurada"));
290

    
291
                return;
292
            }
293
            if (useDefaultJavaPrinting) {
294
                    try {
295
                            m_cachePrintService = ServiceUI.printDialog(null, 200, 200,
296
                                            m_cachePrintServices, defaultService, flavor, att);
297
                    }
298
                    catch (RuntimeException ex) {
299
                            useDefaultJavaPrinting=false;
300
                            Logger logger = PluginServices.getLogger();
301
                            logger.error("Error showing print dialog", ex); 
302
                            
303
                            // workaround a problem with Java 1.5 with moder CUPS versions
304
                            // this try-catch block may be safely removed when we move to Java 1.6
305
                            logger.debug("Opening gvSIG's internal Java 1.7 CUPS printing dialog");
306
                            m_cachePrintService = backport1_7.javax.print.ServiceUI.printDialog(null, 200, 200,
307
                                            m_cachePrintServices, defaultService, flavor, att);
308
                    }
309
            }
310
            else {
311
                    PluginServices.getLogger().debug("Opening gvSIG's internal Java 1.7 CUPS printing dialog");
312
                    m_cachePrintService = backport1_7.javax.print.ServiceUI.printDialog(null, 200, 200,
313
                                    m_cachePrintServices, defaultService, flavor, att);
314
            }
315

    
316
                        if (m_cachePrintService != null) {
317
                                DocPrintJob jobNuevo = m_cachePrintService.createPrintJob();
318
                                PrintJobListener pjlistener = new PrintJobAdapter() {
319
                                        public void printDataTransferCompleted(PrintJobEvent e) {
320
                                                System.out.println("Fin de impresi?n");
321
                                        }
322
                                };
323

    
324
                                jobNuevo.addPrintJobListener(pjlistener);
325

    
326
                                Doc doc = new SimpleDoc(this, flavor, null);
327
                                jobNuevo.print(doc, att);
328
                        }
329
                }
330
                catch (PrintException printerException) {
331
                        pageStartY = 0;
332
                        pageEndY = 0;
333
                        currentPage = -1;
334
                        System.out.println("Error Printing Document");
335
                }
336

    
337

    
338
                // if (pJob.printDialog(att)) {
339
                // pJob.setPrintable(this,pFormat);
340
                // try {
341
                // pJob.print(att);
342
                // }
343
                // }
344
        }
345

    
346
        /*
347
         * printView is a recursive method which iterates through the tree structure
348
         * of the view sent to it. If the view sent to printView is a branch view,
349
         * that is one with children, the method calls itself on each of these
350
         * children. If the view is a leaf view, that is a view without children
351
         * which represents an actual piece of text to be painted, printView
352
         * attempts to render the view to the Graphics2D object.
353
         * 
354
         * I. When any view starts after the beginning of the current printable
355
         * page, this means that there are pages to print and the method sets
356
         * pageExists to true. II. When a leaf view is taller than the printable
357
         * area of a page, it cannot, of course, be broken down to fit a single
358
         * page. Such a View will be printed whenever it intersects with the
359
         * Graphics2D clip. III. If a leaf view intersects the printable area of the
360
         * graphics clip and fits vertically within the printable area, it will be
361
         * rendered. IV. If a leaf view does not exceed the printable area of a page
362
         * but does not fit vertically within the Graphics2D clip of the current
363
         * page, the method records that this page should end at the start of the
364
         * view. This information is stored in pageEndY.
365
         */
366
        protected boolean printView(Graphics2D graphics2D, Shape allocation,
367
                        View view) {
368
                boolean pageExists = false;
369
                Rectangle clipRectangle = graphics2D.getClipBounds();
370
                Shape childAllocation;
371
                View childView;
372

    
373
                if (view.getViewCount() > 0) {
374
                        for (int i = 0; i < view.getViewCount(); i++) {
375
                                childAllocation = view.getChildAllocation(i, allocation);
376
                                if (childAllocation != null) {
377
                                        childView = view.getView(i);
378
                                        if (printView(graphics2D, childAllocation, childView)) {
379
                                                pageExists = true;
380
                                        }
381
                                }
382
                        }
383
                } else {
384
                        // I
385
                        if (allocation.getBounds().getMaxY() >= clipRectangle.getY()) {
386
                                pageExists = true;
387
                                // II
388
                                if ((allocation.getBounds().getHeight() > clipRectangle
389
                                                .getHeight())
390
                                                && (allocation.intersects(clipRectangle))) {
391
                                        view.paint(graphics2D, allocation);
392
                                } else {
393
                                        // III
394
                                        if (allocation.getBounds().getY() >= clipRectangle.getY()) {
395
                                                if (allocation.getBounds().getMaxY() <= clipRectangle
396
                                                                .getMaxY()) {
397
                                                        view.paint(graphics2D, allocation);
398
                                                } else {
399
                                                        // IV
400
                                                        if (allocation.getBounds().getY() < pageEndY) {
401
                                                                pageEndY = allocation.getBounds().getY();
402
                                                        }
403
                                                }
404
                                        }
405
                                }
406
                        }
407
                }
408
                return pageExists;
409
        }
410

    
411
        /*
412
         * Method to set the content type the JEditorPane.
413
         */
414
        protected void setContentType(String type) {
415
                jeditorPane.setContentType(type);
416
        }
417

    
418
        /*
419
         * Method to set an HTMLDocument as the Document to print.
420
         */
421
        public void setDocument(HTMLDocument htmlDocument) {
422
                jeditorPane = new JEditorPane();
423
                setDocument("text/html", htmlDocument);
424
        }
425

    
426
        /*
427
         * Method to set the Document to print as the one contained in a
428
         * JEditorPane. This method is useful when Java does not provide direct
429
         * access to a particular Document type, such as a Rich Text Format
430
         * document. With this method such a document can be sent to the
431
         * DocumentRenderer class enclosed in a JEditorPane.
432
         */
433
        public void setDocument(JEditorPane jedPane) {
434
                jeditorPane = jedPane; // new JEditorPane();
435
                // setDocument(jedPane.getContentType(),jedPane.getDocument());
436
        }
437

    
438
        /*
439
         * Method to set a PlainDocument as the Document to print.
440
         */
441
        public void setDocument(PlainDocument plainDocument) {
442
                jeditorPane = new JEditorPane();
443
                setDocument("text/plain", plainDocument);
444
        }
445

    
446
        /*
447
         * Method to set the content type and document of the JEditorPane.
448
         */
449
        protected void setDocument(String type, Document document) {
450
                setContentType(type);
451
                jeditorPane.setDocument(document);
452
        }
453

    
454
        /*
455
         * Method to set the current choice of the width scaling option.
456
         */
457
        public void setScaleWidthToFit(boolean scaleWidth) {
458
                scaleWidthToFit = scaleWidth;
459
        }
460
}