]> git.evergreen-ils.org Git - working/Hatch.git/blob - src/org/evergreen_ils/hatch/PrintManager.java
hatch : comments, cleanup
[working/Hatch.git] / src / org / evergreen_ils / hatch / PrintManager.java
1 /* -----------------------------------------------------------------------
2  * Copyright 2014 Equinox Software, Inc.
3  * Bill Erickson <berick@esilibrary.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * -----------------------------------------------------------------------
15  */
16 package org.evergreen_ils.hatch;
17
18 // logging
19 import org.eclipse.jetty.util.log.Log;
20 import org.eclipse.jetty.util.log.Logger;
21
22 // printing
23 import javafx.print.*;
24 import javafx.scene.web.WebEngine;
25 import javafx.collections.ObservableSet;
26 import javafx.collections.SetChangeListener;
27
28 import javax.print.PrintService;
29 import javax.print.PrintServiceLookup;
30 import javax.print.attribute.Attribute;
31 import javax.print.attribute.AttributeSet;
32 import javax.print.attribute.PrintRequestAttributeSet;
33 import javax.print.attribute.standard.Media;
34 import javax.print.attribute.standard.OrientationRequested;
35
36 import java.lang.IllegalArgumentException;
37
38 // data structures
39 import java.util.Map;
40 import java.util.List;
41 import java.util.ArrayList;
42 import java.util.HashMap;
43 import java.util.LinkedList;
44 import java.util.Set;
45 import java.util.LinkedHashSet;
46
47 public class PrintManager {
48
49     static final Logger logger = Log.getLogger("PrintManager");
50
51     /**
52      * Shows the print dialog, allowing the user to modify settings,
53      * but performs no print.
54      */
55     public Map<String,Object> configurePrinter(
56         Map<String,Object> params) throws IllegalArgumentException {
57
58         Map<String,Object> settings = 
59             (Map<String,Object>) params.get("config");
60
61         PrinterJob job = buildPrinterJob(settings);
62         
63         job.showPrintDialog(null);
64
65         // no printing needed
66         job.endJob(); 
67
68         // extract modifications to the settings applied within the dialog
69         return extractSettingsFromJob(job);
70     }
71
72     /**
73      * Print the requested page using the provided settings
74      */
75     public void print(WebEngine engine, Map<String,Object>params) {
76
77         Long msgid = (Long) params.get("msgid");
78         Boolean showDialog = (Boolean) params.get("showDialog");
79
80         Map<String,Object> settings = 
81             (Map<String,Object>) params.get("config");
82
83         HatchWebSocketHandler socket = 
84             (HatchWebSocketHandler) params.get("socket");
85
86         PrinterJob job = null;
87         try {
88             job = buildPrinterJob(settings);
89         } catch(IllegalArgumentException e) {
90             socket.reply(e.toString(), msgid, false);
91         }
92
93         if (showDialog != null && showDialog.booleanValue()) {
94             if (!job.showPrintDialog(null)) {
95                 // job canceled by user
96                 socket.reply("Print job canceled", msgid);
97             }
98         }
99
100         engine.print(job);
101         job.endJob();
102
103         socket.reply("Print job succeeded", msgid);
104     }
105
106     /**
107      * Constructs a PrinterJob based on the provided settings
108      */
109     public PrinterJob buildPrinterJob(
110         Map<String,Object> settings) throws IllegalArgumentException {
111
112         String name = (String) settings.get("printer");
113         Printer printer = getPrinterByName(name);
114
115         if (printer == null) 
116             throw new IllegalArgumentException("No such printer: " + name);
117
118         PageLayout layout = buildPageLayout(settings, printer);
119         PrinterJob job = PrinterJob.createPrinterJob(printer);
120
121         if (layout != null) job.getJobSettings().setPageLayout(layout);
122
123         // apply any provided settings to the job
124         applySettingsToJob(settings, job);
125
126         return job;
127     }
128
129     /**
130      * Builds a PageLayout for the requested printer, using the
131      * provided settings.
132      */
133     protected PageLayout buildPageLayout(
134             Map<String,Object> settings, Printer printer) {
135
136         // modify the default page layout with our settings
137         Map<String,Object> layoutMap = 
138             (Map<String,Object>) settings.get("pageLayout");
139
140         if (layoutMap == null) {
141             // Start with a sane default.
142             // The Java default is wonky
143             return printer.createPageLayout(
144                 Paper.NA_LETTER,
145                 PageOrientation.PORTRAIT,
146                 Printer.MarginType.DEFAULT
147             );
148         }
149
150         PrinterAttributes printerAttrs = printer.getPrinterAttributes();
151
152         // find the paper by name
153         Paper paper = null;
154         String paperName = (String) layoutMap.get("paper");
155         Set<Paper> papers = printerAttrs.getSupportedPapers();
156         for (Paper source : papers) {
157             if (source.getName().equals(paperName)) {
158                 logger.info("Found matching paper for " + paperName);
159                 paper = source;
160                 break;
161             }
162         }
163
164         if (paper == null) 
165             paper = printerAttrs.getDefaultPaper();
166
167         return printer.createPageLayout(
168             paper,
169             PageOrientation.valueOf((String) layoutMap.get("pageOrientation")),
170             ((Number) layoutMap.get("leftMargin")).doubleValue(),
171             ((Number) layoutMap.get("rightMargin")).doubleValue(),
172             ((Number) layoutMap.get("topMargin")).doubleValue(),
173             ((Number) layoutMap.get("bottomMargin")).doubleValue()
174         );
175     }
176
177     /**
178      * Applies the provided settings to the PrinterJob.
179      */
180     protected void applySettingsToJob(
181             Map<String,Object> settings, PrinterJob job) {
182
183         JobSettings jobSettings = job.getJobSettings();
184
185         PrinterAttributes printerAttrs = 
186             job.getPrinter().getPrinterAttributes();
187
188         String collation = (String) settings.get("collation");
189         Long copies = (Long) settings.get("copies");
190         String printColor = (String) settings.get("printColor");
191         String printQuality = (String) settings.get("printQuality");
192         String printSides = (String) settings.get("printSides");
193         String paperSource = (String) settings.get("paperSource");
194         Object[] pageRanges = (Object[]) settings.get("pageRanges");
195
196         if (collation != null) 
197             jobSettings.setCollation(Collation.valueOf(collation));
198
199         if (copies != null) 
200             jobSettings.setCopies(((Long) settings.get("copies")).intValue());
201
202         if (printColor != null) 
203             jobSettings.setPrintColor(PrintColor.valueOf(printColor));
204
205         if (printQuality != null) 
206             jobSettings.setPrintQuality(PrintQuality.valueOf(printQuality));
207
208         if (printSides != null) 
209             jobSettings.setPrintSides(PrintSides.valueOf(printSides));
210
211         // find the paperSource by name
212         if (paperSource != null) {
213             Set<PaperSource> paperSources = 
214                 printerAttrs.getSupportedPaperSources();
215
216             // note: "Automatic" appears to be a virtual source,
217             // meaning no source.. meaning let the printer decide.
218             for (PaperSource source : paperSources) {
219                 if (source.getName().equals(paperSource)) {
220                     logger.info("matched paper source for " + paperSource);
221                     jobSettings.setPaperSource(source);
222                     break;
223                 }
224             }
225         }
226
227
228         if (pageRanges != null) {
229             logger.info("pageRanges = " + pageRanges.toString());
230             List<PageRange> builtRanges = new LinkedList<PageRange>();
231             int i = 0, start = 0, end = 0;
232             do {
233                 if (i % 2 == 0 && i > 0)
234                     builtRanges.add(new PageRange(start, end));
235
236                 if (i == pageRanges.length) break;
237
238                 int current = ((Long) pageRanges[i]).intValue();
239                 if (i % 2 == 0) start = current; else end = current;
240
241             } while (++i > 0);
242
243             jobSettings.setPageRanges(builtRanges.toArray(new PageRange[0]));
244         }
245     }
246
247     /**
248      * Extracts and flattens the various configuration values from a 
249      * PrinterJob and its associated printer and stores the values in a Map.
250      */
251     protected Map<String,Object> extractSettingsFromJob(PrinterJob job) {
252         Map<String,Object> settings = new HashMap<String,Object>();
253         JobSettings jobSettings = job.getJobSettings();
254
255         settings.put(
256             jobSettings.collationProperty().getName(),
257             jobSettings.collationProperty().getValue()
258         );
259         settings.put(
260             jobSettings.copiesProperty().getName(),
261             jobSettings.copiesProperty().getValue()
262         );
263         settings.put(
264             "paperSource", 
265             jobSettings.getPaperSource().getName()
266         );
267         settings.put(
268             jobSettings.printColorProperty().getName(),
269             jobSettings.printColorProperty().getValue()
270         );
271         settings.put(
272             jobSettings.printQualityProperty().getName(),
273             jobSettings.printQualityProperty().getValue()
274         );
275         settings.put(
276             jobSettings.printSidesProperty().getName(),
277             jobSettings.printSidesProperty().getValue()
278         );
279
280         // nested properties...
281         
282         // page layout --------------
283         PageLayout layout = jobSettings.getPageLayout();
284         Map<String,Object> layoutMap = new HashMap<String,Object>();
285         layoutMap.put("bottomMargin", layout.getBottomMargin());
286         layoutMap.put("leftMargin", layout.getLeftMargin());
287         layoutMap.put("topMargin", layout.getTopMargin());
288         layoutMap.put("rightMargin", layout.getRightMargin());
289         layoutMap.put("pageOrientation", layout.getPageOrientation().toString());
290         layoutMap.put("printableHeight", layout.getPrintableHeight());
291         layoutMap.put("printableWidth", layout.getPrintableWidth());
292         layoutMap.put("paper", layout.getPaper().getName());
293
294         settings.put("pageLayout", layoutMap);
295
296         // page ranges --------------
297         PageRange[] ranges = jobSettings.getPageRanges();
298         if (ranges != null) {
299             List<Integer> pageRanges = new LinkedList<Integer>();
300
301             if (ranges.length == 1 &&
302                 ranges[0].getStartPage() == 1 && 
303                 ranges[0].getEndPage() == Integer.MAX_VALUE) {
304                 // full range -- no need to store
305
306             } else {
307                 for (PageRange range : ranges) {
308                     pageRanges.add(range.getStartPage());
309                     pageRanges.add(range.getEndPage());
310                 }
311                 settings.put("pageRanges", pageRanges);
312             }
313         }
314
315         logger.info("compiled printer properties: " + settings.toString());
316         return settings;
317     }
318
319     /**
320      * Returns a list of all known Printer's
321      */
322     protected Printer[] getPrinters() {
323         ObservableSet<Printer> printerObserver = Printer.getAllPrinters();
324
325         if (printerObserver == null) return new Printer[0];
326
327         return (Printer[]) printerObserver.toArray(new Printer[0]);
328     }
329
330     /**
331      * Returns a list of all known printers, with their attributes 
332      * encoded as a simple key/value Map.
333      */
334     protected List<Map<String,Object>> getPrintersAsMaps() {
335         Printer[] printers = getPrinters();
336
337         List<Map<String,Object>> printerMaps = 
338             new LinkedList<Map<String,Object>>();
339
340         Printer defaultPrinter = Printer.getDefaultPrinter();
341
342         for (Printer printer : printers) {
343             HashMap<String, Object> printerMap = new HashMap<String, Object>();
344             printerMaps.add(printerMap);
345             printerMap.put("name", printer.getName());
346             if (printer.getName().equals(defaultPrinter.getName())) {
347                 printerMap.put("is-default", new Boolean(true));
348             }
349             logger.info("found printer " + printer.getName());            
350         }
351
352         return printerMaps;
353     }
354
355
356     /**
357      * Returns the Printer with the specified name.
358      */
359     protected Printer getPrinterByName(String name) {
360         Printer[] printers = getPrinters();
361         for (Printer printer : printers) {
362             if (printer.getName().equals(name))
363                 return printer;
364         }
365         return null;
366     }
367 }
368