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 org.eclipse.jetty.util.log.Log;
20 import org.eclipse.jetty.util.log.Logger;
23 import javafx.print.*;
24 import javafx.scene.web.WebEngine;
25 import javafx.collections.ObservableSet;
26 import javafx.collections.SetChangeListener;
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;
36 import java.lang.IllegalArgumentException;
40 import java.util.List;
41 import java.util.ArrayList;
42 import java.util.HashMap;
43 import java.util.LinkedList;
45 import java.util.LinkedHashSet;
47 public class PrintManager {
49 static final Logger logger = Log.getLogger("PrintManager");
52 * Shows the print dialog, allowing the user to modify settings,
53 * but performs no print.
55 public Map<String,Object> configurePrinter(
56 Map<String,Object> params) throws IllegalArgumentException {
58 Map<String,Object> settings =
59 (Map<String,Object>) params.get("config");
61 PrinterJob job = buildPrinterJob(settings);
63 job.showPrintDialog(null);
68 // extract modifications to the settings applied within the dialog
69 return extractSettingsFromJob(job);
73 * Print the requested page using the provided settings
75 public void print(WebEngine engine, Map<String,Object>params) {
77 Long msgid = (Long) params.get("msgid");
78 Boolean showDialog = (Boolean) params.get("showDialog");
80 Map<String,Object> settings =
81 (Map<String,Object>) params.get("config");
83 HatchWebSocketHandler socket =
84 (HatchWebSocketHandler) params.get("socket");
86 PrinterJob job = null;
88 job = buildPrinterJob(settings);
89 } catch(IllegalArgumentException e) {
90 socket.reply(e.toString(), msgid, false);
93 if (showDialog != null && showDialog.booleanValue()) {
94 if (!job.showPrintDialog(null)) {
95 // job canceled by user
96 socket.reply("Print job canceled", msgid);
103 socket.reply("Print job succeeded", msgid);
107 * Constructs a PrinterJob based on the provided settings
109 public PrinterJob buildPrinterJob(
110 Map<String,Object> settings) throws IllegalArgumentException {
112 String name = (String) settings.get("printer");
113 Printer printer = getPrinterByName(name);
116 throw new IllegalArgumentException("No such printer: " + name);
118 PageLayout layout = buildPageLayout(settings, printer);
119 PrinterJob job = PrinterJob.createPrinterJob(printer);
121 if (layout != null) job.getJobSettings().setPageLayout(layout);
123 // apply any provided settings to the job
124 applySettingsToJob(settings, job);
130 * Builds a PageLayout for the requested printer, using the
133 protected PageLayout buildPageLayout(
134 Map<String,Object> settings, Printer printer) {
136 // modify the default page layout with our settings
137 Map<String,Object> layoutMap =
138 (Map<String,Object>) settings.get("pageLayout");
140 if (layoutMap == null) {
141 // Start with a sane default.
142 // The Java default is wonky
143 return printer.createPageLayout(
145 PageOrientation.PORTRAIT,
146 Printer.MarginType.DEFAULT
150 PrinterAttributes printerAttrs = printer.getPrinterAttributes();
152 // find the paper by name
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);
165 paper = printerAttrs.getDefaultPaper();
167 return printer.createPageLayout(
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()
178 * Applies the provided settings to the PrinterJob.
180 protected void applySettingsToJob(
181 Map<String,Object> settings, PrinterJob job) {
183 JobSettings jobSettings = job.getJobSettings();
185 PrinterAttributes printerAttrs =
186 job.getPrinter().getPrinterAttributes();
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");
196 if (collation != null)
197 jobSettings.setCollation(Collation.valueOf(collation));
200 jobSettings.setCopies(((Long) settings.get("copies")).intValue());
202 if (printColor != null)
203 jobSettings.setPrintColor(PrintColor.valueOf(printColor));
205 if (printQuality != null)
206 jobSettings.setPrintQuality(PrintQuality.valueOf(printQuality));
208 if (printSides != null)
209 jobSettings.setPrintSides(PrintSides.valueOf(printSides));
211 // find the paperSource by name
212 if (paperSource != null) {
213 Set<PaperSource> paperSources =
214 printerAttrs.getSupportedPaperSources();
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);
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;
233 if (i % 2 == 0 && i > 0)
234 builtRanges.add(new PageRange(start, end));
236 if (i == pageRanges.length) break;
238 int current = ((Long) pageRanges[i]).intValue();
239 if (i % 2 == 0) start = current; else end = current;
243 jobSettings.setPageRanges(builtRanges.toArray(new PageRange[0]));
248 * Extracts and flattens the various configuration values from a
249 * PrinterJob and its associated printer and stores the values in a Map.
251 protected Map<String,Object> extractSettingsFromJob(PrinterJob job) {
252 Map<String,Object> settings = new HashMap<String,Object>();
253 JobSettings jobSettings = job.getJobSettings();
256 jobSettings.collationProperty().getName(),
257 jobSettings.collationProperty().getValue()
260 jobSettings.copiesProperty().getName(),
261 jobSettings.copiesProperty().getValue()
265 jobSettings.getPaperSource().getName()
268 jobSettings.printColorProperty().getName(),
269 jobSettings.printColorProperty().getValue()
272 jobSettings.printQualityProperty().getName(),
273 jobSettings.printQualityProperty().getValue()
276 jobSettings.printSidesProperty().getName(),
277 jobSettings.printSidesProperty().getValue()
280 // nested properties...
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());
294 settings.put("pageLayout", layoutMap);
296 // page ranges --------------
297 PageRange[] ranges = jobSettings.getPageRanges();
298 if (ranges != null) {
299 List<Integer> pageRanges = new LinkedList<Integer>();
301 if (ranges.length == 1 &&
302 ranges[0].getStartPage() == 1 &&
303 ranges[0].getEndPage() == Integer.MAX_VALUE) {
304 // full range -- no need to store
307 for (PageRange range : ranges) {
308 pageRanges.add(range.getStartPage());
309 pageRanges.add(range.getEndPage());
311 settings.put("pageRanges", pageRanges);
315 logger.info("compiled printer properties: " + settings.toString());
320 * Returns a list of all known Printer's
322 protected Printer[] getPrinters() {
323 ObservableSet<Printer> printerObserver = Printer.getAllPrinters();
325 if (printerObserver == null) return new Printer[0];
327 return (Printer[]) printerObserver.toArray(new Printer[0]);
331 * Returns a list of all known printers, with their attributes
332 * encoded as a simple key/value Map.
334 protected List<Map<String,Object>> getPrintersAsMaps() {
335 Printer[] printers = getPrinters();
337 List<Map<String,Object>> printerMaps =
338 new LinkedList<Map<String,Object>>();
340 Printer defaultPrinter = Printer.getDefaultPrinter();
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));
349 logger.info("found printer " + printer.getName());
357 * Returns the Printer with the specified name.
359 protected Printer getPrinterByName(String name) {
360 Printer[] printers = getPrinters();
361 for (Printer printer : printers) {
362 if (printer.getName().equals(name))