1 /* -----------------------------------------------------------------------
2 * Copyright 2014 Equinox Software, Inc.
3 * Bill Erickson <berick@esilibrary.com>
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.
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 * -----------------------------------------------------------------------
16 package org.evergreen_ils.hatch;
19 import javafx.print.*;
20 import javafx.scene.web.WebEngine;
21 import javafx.collections.ObservableSet;
22 import javafx.collections.SetChangeListener;
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;
32 import java.lang.IllegalArgumentException;
37 import java.util.List;
38 import java.util.HashMap;
39 import java.util.LinkedList;
41 import java.util.logging.Logger;
45 public class PrintManager {
47 /** Our logger instance */
48 static final Logger logger = Hatch.getLogger();
51 * Returns all known Printer's.
53 * @return Array of all printers
55 protected Printer[] getPrinters() {
56 ObservableSet<Printer> printerObserver = Printer.getAllPrinters();
58 if (printerObserver == null) return new Printer[0];
60 return (Printer[]) printerObserver.toArray(new Printer[0]);
64 * Returns a list of all known printers, with their attributes
65 * encoded as a simple key/value Map.
67 * @return Map of printer information.
69 protected List<Map<String,Object>> getPrintersAsMaps() {
70 Printer[] printers = getPrinters();
72 List<Map<String,Object>> printerMaps =
73 new LinkedList<Map<String,Object>>();
75 Printer defaultPrinter = Printer.getDefaultPrinter();
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));
92 * Returns the Printer with the specified name.
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.
98 protected Printer getPrinterByName(String name) {
99 Printer[] printers = getPrinters();
100 for (Printer printer : printers) {
101 if (printer.getName().equals(name))
109 * Print the requested page using the provided settings
111 * @param engine The WebEngine instance to print
112 * @param params Print request parameters
114 public void print(WebEngine engine, JSONObject request) {
116 JSONObject response = new JSONObject();
117 response.put("status", 200);
118 response.put("message", "OK");
122 response.put("clientid", request.getLong("clientid"));
123 response.put("msgid", request.getLong("msgid"));
125 boolean showDialog = request.optBoolean("showDialog");
127 // if no "settings" are applied, use defaults.
128 JSONObject settings = request.optJSONObject("settings");
129 if (settings == null) settings = new JSONObject();
131 PrinterJob job = buildPrinterJob(settings);
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);
145 response.put("message", "Print job queued");
146 // TODO: support watching the print job until it completes
148 } catch (JSONException je) {
150 String error = "JSON request protocol error: "
151 + je.toString() + " : " + request.toString();
153 logger.warning(error);
154 response.put("status", 400);
155 response.put("message", error);
157 } catch(IllegalArgumentException iae) {
159 String error = "Illegal argument in print request: "
160 + iae.toString() + " : " + request.toString();
162 logger.warning(error);
163 response.put("status", 400);
164 response.put("message", error);
167 RequestHandler.reply(response);
171 * Constructs a PrinterJob based on the provided settings.
173 * @param settings The printer configuration Map.
174 * @return The newly created printer job.
176 public PrinterJob buildPrinterJob(
177 JSONObject settings) throws IllegalArgumentException {
180 if (settings.has("printer")) {
181 String name = settings.getString("printer");
182 printer = getPrinterByName(name);
184 throw new IllegalArgumentException("No such printer: " + name);
187 printer = Printer.getDefaultPrinter();
189 throw new IllegalArgumentException(
190 "No printer specified; no default printer is set");
193 PageLayout layout = buildPageLayout(settings, printer);
194 PrinterJob job = PrinterJob.createPrinterJob(printer);
196 if (layout != null) job.getJobSettings().setPageLayout(layout);
198 // apply any provided settings to the job
199 applySettingsToJob(settings, job);
205 * Builds a PageLayout for the requested printer, using the
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.
212 protected PageLayout buildPageLayout(
213 JSONObject settings, Printer printer) {
215 JSONObject layoutMap = settings.optJSONObject("pageLayout");
217 if (layoutMap == null) {
218 // Start with a sane default. The Java default is wonky.
219 return printer.createPageLayout(
221 PageOrientation.PORTRAIT,
222 Printer.MarginType.DEFAULT
226 PrinterAttributes printerAttrs = printer.getPrinterAttributes();
228 // find the paper by name
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);
241 paper = printerAttrs.getDefaultPaper();
243 return printer.createPageLayout(
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()
254 * Applies the provided settings to the PrinterJob.
256 * @param settings The printer configuration settings map.
257 * @param job A PrinterJob, constructed from buildPrinterJob()
259 protected void applySettingsToJob(JSONObject settings, PrinterJob job) {
261 JobSettings jobSettings = job.getJobSettings();
263 PrinterAttributes printerAttrs =
264 job.getPrinter().getPrinterAttributes();
266 if (settings.has("collation")) {
267 jobSettings.setCollation(
268 Collation.valueOf(settings.getString("collation")));
271 if (settings.has("copies")) {
272 jobSettings.setCopies(settings.getInt("copies"));
275 if (settings.has("printColor")) {
276 jobSettings.setPrintColor(
277 PrintColor.valueOf(settings.getString("printColor")));
280 if (settings.has("printQuality")) {
281 jobSettings.setPrintQuality(
282 PrintQuality.valueOf(settings.getString("printQuality")));
285 if (settings.has("printSides")) {
286 jobSettings.setPrintSides(
287 PrintSides.valueOf(settings.getString("printSides")));
291 String paperSource = settings.optString("paperSource");
293 if (paperSource != null) {
294 // find the paperSource by name
296 Set<PaperSource> paperSources =
297 printerAttrs.getSupportedPaperSources();
299 for (PaperSource source : paperSources) {
300 if (source.getName().equals(paperSource)) {
301 logger.fine("Found paper source: " + paperSource);
302 jobSettings.setPaperSource(source);
308 JSONArray pageRanges = settings.optJSONArray("pageRanges");
310 if (pageRanges != null) {
311 List<PageRange> builtRanges = new LinkedList<PageRange>();
312 int i = 0, start = 0, end = 0;
314 if (i % 2 == 0 && i > 0)
315 builtRanges.add(new PageRange(start, end));
317 if (i == pageRanges.length()) break;
319 int current = pageRanges.getInt(i);
320 if (i % 2 == 0) start = current; else end = current;
324 jobSettings.setPageRanges(builtRanges.toArray(new PageRange[0]));