]> git.evergreen-ils.org Git - working/Hatch.git/blob - src/org/evergreen_ils/hatch/PrintManager.java
Native Messaging WIP - docs, tweaks
[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 // printing
19 import javafx.print.*;
20 import javafx.scene.web.WebEngine;
21 import javafx.collections.ObservableSet;
22 import javafx.collections.SetChangeListener;
23
24 import javax.print.PrintService;
25 import javax.print.PrintServiceLookup;
26 import javax.print.attribute.Attribute;
27 import javax.print.attribute.AttributeSet;
28 import javax.print.attribute.PrintRequestAttributeSet;
29 import javax.print.attribute.standard.Media;
30 import javax.print.attribute.standard.OrientationRequested;
31
32 import java.lang.IllegalArgumentException;
33
34 // data structures
35 import java.util.Set;
36 import java.util.Map;
37 import java.util.List;
38 import java.util.HashMap;
39 import java.util.LinkedList;
40
41 import java.util.logging.Logger;
42
43 import org.json.*;
44
45 public class PrintManager {
46
47     /** Our logger instance */
48     static final Logger logger = Hatch.getLogger();
49
50     /**
51      * Returns all known Printer's.
52      *
53      * @return Array of all printers
54      */
55     protected Printer[] getPrinters() {
56         ObservableSet<Printer> printerObserver = Printer.getAllPrinters();
57
58         if (printerObserver == null) return new Printer[0];
59
60         return (Printer[]) printerObserver.toArray(new Printer[0]);
61     }
62
63     /**
64      * Returns a list of all known printers, with their attributes 
65      * encoded as a simple key/value Map.
66      *
67      * @return Map of printer information.
68      */
69     protected List<Map<String,Object>> getPrintersAsMaps() {
70         Printer[] printers = getPrinters();
71
72         List<Map<String,Object>> printerMaps = 
73             new LinkedList<Map<String,Object>>();
74
75         Printer defaultPrinter = Printer.getDefaultPrinter();
76
77         for (Printer printer : printers) {
78             HashMap<String, Object> printerMap = new HashMap<String, Object>();
79             printerMaps.add(printerMap);
80             printerMap.put("name", printer.getName());
81             if (defaultPrinter != null && 
82                 printer.getName().equals(defaultPrinter.getName())) {
83                 printerMap.put("is-default", new Boolean(true));
84             }
85         }
86
87         return printerMaps;
88     }
89
90
91     /**
92      * Returns the Printer with the specified name.
93      *
94      * @param name The printer name
95      * @return The printer whose name matches the provided name, or null
96      * if no such printer is found.
97      */
98     protected Printer getPrinterByName(String name) {
99         Printer[] printers = getPrinters();
100         for (Printer printer : printers) {
101             if (printer.getName().equals(name))
102                 return printer;
103         }
104         return null;
105     }
106
107
108     /**
109      * Print the requested page using the provided settings
110      *
111      * @param engine The WebEngine instance to print
112      * @param params Print request parameters
113      */
114     public void print(WebEngine engine, JSONObject request) {
115
116         JSONObject response = new JSONObject();
117         response.put("status", 200);
118         response.put("message", "OK");
119
120         try {
121
122             response.put("clientid", request.getLong("clientid"));
123             response.put("msgid", request.getLong("msgid"));
124
125             boolean showDialog = request.optBoolean("showDialog");
126
127             // if no "settings" are applied, use defaults.
128             JSONObject settings = request.optJSONObject("settings");
129             if (settings == null) settings = new JSONObject();
130
131             PrinterJob job = buildPrinterJob(settings);
132
133             if (showDialog) {
134                 if (!job.showPrintDialog(null)) {
135                     job.endJob(); // canceled by user
136                     response.put("status", 200);
137                     response.put("message", "Print job canceled by user");
138                     RequestHandler.reply(response);
139                     return;
140                 }
141             }
142
143             engine.print(job);
144             job.endJob();
145             response.put("message", "Print job queued");
146             // TODO: support watching the print job until it completes
147
148         } catch (JSONException je) {
149
150             String error = "JSON request protocol error: " 
151                 + je.toString() + " : " + request.toString();
152
153             logger.warning(error);
154             response.put("status", 400);
155             response.put("message", error);
156
157         } catch(IllegalArgumentException iae) {
158
159             String error = "Illegal argument in print request: "
160                 + iae.toString() + " : " + request.toString();
161
162             logger.warning(error);
163             response.put("status", 400);
164             response.put("message", error);
165         }
166
167         RequestHandler.reply(response);
168     }
169
170     /**
171      * Constructs a PrinterJob based on the provided settings.
172      *
173      * @param settings The printer configuration Map.
174      * @return The newly created printer job.
175      */
176     public PrinterJob buildPrinterJob(
177         JSONObject settings) throws IllegalArgumentException {
178
179         Printer printer;
180         if (settings.has("printer")) {
181             String name = settings.getString("printer");
182             printer = getPrinterByName(name);
183             if (printer == null) 
184                 throw new IllegalArgumentException("No such printer: " + name);
185
186         } else {
187             printer = Printer.getDefaultPrinter();
188             if (printer == null) 
189                 throw new IllegalArgumentException(
190                     "No printer specified; no default printer is set");
191         }
192
193         PageLayout layout = buildPageLayout(settings, printer);
194         PrinterJob job = PrinterJob.createPrinterJob(printer);
195
196         if (layout != null) job.getJobSettings().setPageLayout(layout);
197
198         // apply any provided settings to the job
199         applySettingsToJob(settings, job);
200
201         return job;
202     }
203
204     /**
205      * Builds a PageLayout for the requested printer, using the
206      * provided settings.
207      *
208      * @param settings The printer configuration settings
209      * @param printer The printer from which to spawn the PageLayout
210      * @return The newly constructed PageLayout object.
211      */
212     protected PageLayout buildPageLayout(
213         JSONObject settings, Printer printer) {
214
215         JSONObject layoutMap = settings.optJSONObject("pageLayout");
216
217         if (layoutMap == null) {
218             // Start with a sane default. The Java default is wonky.
219             return printer.createPageLayout(
220                 Paper.NA_LETTER,
221                 PageOrientation.PORTRAIT,
222                 Printer.MarginType.DEFAULT
223             );
224         }
225
226         PrinterAttributes printerAttrs = printer.getPrinterAttributes();
227
228         // find the paper by name
229         Paper paper = null;
230         String paperName = (String) layoutMap.get("paper");
231         Set<Paper> papers = printerAttrs.getSupportedPapers();
232         for (Paper source : papers) {
233             if (source.getName().equals(paperName)) {
234                 //logger.info("Found matching paper for " + paperName);
235                 paper = source;
236                 break;
237             }
238         }
239
240         if (paper == null) 
241             paper = printerAttrs.getDefaultPaper();
242
243         return printer.createPageLayout(
244             paper,
245             PageOrientation.valueOf((String) layoutMap.get("pageOrientation")),
246             ((Number) layoutMap.get("leftMargin")).doubleValue(),
247             ((Number) layoutMap.get("rightMargin")).doubleValue(),
248             ((Number) layoutMap.get("topMargin")).doubleValue(),
249             ((Number) layoutMap.get("bottomMargin")).doubleValue()
250         );
251     }
252
253     /**
254      * Applies the provided settings to the PrinterJob.
255      *
256      * @param settings The printer configuration settings map.
257      * @param job A PrinterJob, constructed from buildPrinterJob()
258      */
259     protected void applySettingsToJob(JSONObject settings, PrinterJob job) {
260
261         JobSettings jobSettings = job.getJobSettings();
262
263         PrinterAttributes printerAttrs = 
264             job.getPrinter().getPrinterAttributes();
265
266         if (settings.has("collation")) {
267             jobSettings.setCollation(
268                 Collation.valueOf(settings.getString("collation")));
269         }
270
271         if (settings.has("copies")) {
272             jobSettings.setCopies(settings.getInt("copies"));
273         }
274
275         if (settings.has("printColor")) {
276             jobSettings.setPrintColor(
277                 PrintColor.valueOf(settings.getString("printColor")));
278         }
279
280         if (settings.has("printQuality")) {
281             jobSettings.setPrintQuality(
282                 PrintQuality.valueOf(settings.getString("printQuality")));
283         }
284
285         if (settings.has("printSides")) {
286             jobSettings.setPrintSides(
287                 PrintSides.valueOf(settings.getString("printSides")));
288
289         }
290
291         String paperSource = settings.optString("paperSource");
292
293         if (paperSource != null) {
294             // find the paperSource by name
295
296             Set<PaperSource> paperSources = 
297                 printerAttrs.getSupportedPaperSources();
298
299             for (PaperSource source : paperSources) {
300                 if (source.getName().equals(paperSource)) {
301                     logger.fine("Found paper source: " + paperSource);
302                     jobSettings.setPaperSource(source);
303                     break;
304                 }
305             }
306         }
307
308         JSONArray pageRanges = settings.optJSONArray("pageRanges");
309
310         if (pageRanges != null) {
311             List<PageRange> builtRanges = new LinkedList<PageRange>();
312             int i = 0, start = 0, end = 0;
313             do {
314                 if (i % 2 == 0 && i > 0)
315                     builtRanges.add(new PageRange(start, end));
316
317                 if (i == pageRanges.length()) break;
318
319                 int current = pageRanges.getInt(i);
320                 if (i % 2 == 0) start = current; else end = current;
321
322             } while (++i > 0);
323
324             jobSettings.setPageRanges(builtRanges.toArray(new PageRange[0]));
325         }
326     }
327
328 }
329