diff --git a/src/qz/printer/PrintServiceMatcher.java b/src/qz/printer/PrintServiceMatcher.java index 619fba620..ebf4cc807 100644 --- a/src/qz/printer/PrintServiceMatcher.java +++ b/src/qz/printer/PrintServiceMatcher.java @@ -15,6 +15,7 @@ import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; +import qz.printer.info.MediaSizeHashSet; import qz.printer.info.NativePrinter; import qz.printer.info.NativePrinterMap; import qz.utils.SystemUtilities; @@ -23,9 +24,7 @@ import javax.print.PrintServiceLookup; import javax.print.attribute.ResolutionSyntax; import javax.print.attribute.standard.*; -import java.awt.geom.Rectangle2D; -import java.util.HashMap; -import java.util.Locale; +import java.util.*; public class PrintServiceMatcher { private static final Logger log = LogManager.getLogger(PrintServiceMatcher.class); @@ -174,35 +173,34 @@ public static JSONArray getPrintersJSON(boolean includeDetails) throws JSONExcep mediaTrayCrawled = true; } - HashMap sizes = new HashMap<>(); + MediaSizeHashSet sizes = new MediaSizeHashSet(); for(Media m : (Media[])ps.getSupportedAttributeValues(Media.class, null, null)) { if (m instanceof MediaTray) { jsonService.accumulate("trays", m.toString()); } if (m instanceof MediaSizeName) { - MediaSize mediaSize = MediaSize.getMediaSizeForName((MediaSizeName)m); - if(mediaSize != null) { - // Collect into a HashMap to avoid duplicates - float widthIn = mediaSize.getX(MediaPrintableArea.INCH); - float heightIn = mediaSize.getY(MediaPrintableArea.INCH); - String keyIn = String.format("%sx%s in",widthIn, heightIn); - Rectangle2D valueIn = new Rectangle2D.Float(0, 0, widthIn, heightIn); - sizes.put(keyIn, valueIn); - - float widthMm = mediaSize.getX(MediaPrintableArea.MM); - float heightMm = mediaSize.getY(MediaPrintableArea.MM); - String keyMm = String.format("%sx%s mm", widthMm, heightMm); - Rectangle2D valueMm = new Rectangle2D.Float(0, 0, widthMm, heightMm); - sizes.put(keyMm, valueMm); - } + sizes.add((MediaSizeName)m); } } - for(String key : sizes.keySet()) { - JSONObject sizeEntry = new JSONObject(); - sizeEntry.put("units", key.endsWith("in") ? "in" : "mm"); - sizeEntry.put("width", sizes.get(key).getWidth()); - sizeEntry.put("height", sizes.get(key).getHeight()); - jsonService.accumulate("sizes", sizeEntry); + List sortedList = new ArrayList<>(sizes); + Collections.sort(sortedList); + + for(MediaSizeHashSet.Pair pair : sortedList) { + // Inches + JSONObject inches = new JSONObject(); + inches.put("units", "in"); + inches.put("width", pair.getInches().getWidth()); + inches.put("height", pair.getInches().getHeight()); + jsonService.accumulate("sizes", inches); + } + + for(MediaSizeHashSet.Pair pair : sortedList) { + // Millimeters + JSONObject mm = new JSONObject(); + mm.put("units", "mm"); + mm.put("width", pair.getMm().getWidth()); + mm.put("height", pair.getMm().getHeight()); + jsonService.accumulate("sizes", mm); } PrinterResolution res = printer.getResolution().value(); diff --git a/src/qz/printer/info/MediaSizeHashSet.java b/src/qz/printer/info/MediaSizeHashSet.java new file mode 100644 index 000000000..c2fc9a533 --- /dev/null +++ b/src/qz/printer/info/MediaSizeHashSet.java @@ -0,0 +1,78 @@ +package qz.printer.info; + +import javax.print.attribute.standard.MediaPrintableArea; +import javax.print.attribute.standard.MediaSize; +import javax.print.attribute.standard.MediaSizeName; +import java.util.*; + +/** + * A sortable HashMap for storing printer page sizes for both imperial (inches) and metric (millimeters) + */ +public class MediaSizeHashSet extends HashSet { + public class Pair implements Comparable { + private DimensionFloat inches; + private DimensionFloat mm; + + public Pair(MediaSize mediaSize) { + inches = new DimensionFloat(mediaSize.getX(MediaPrintableArea.INCH), mediaSize.getY(MediaPrintableArea.INCH)); + mm = new DimensionFloat(mediaSize.getX(MediaPrintableArea.MM), mediaSize.getY(MediaPrintableArea.MM)); + } + + @Override + public boolean equals(Object o) { + if (this == o) {return true;} + if (o == null || getClass() != o.getClass()) {return false;} + Pair that = (Pair)o; + return inches.width == that.inches.width && inches.height == that.inches.height; + } + + @Override + public int compareTo(Object o) { + if (this == o) {return 0;} + if (o == null || getClass() != o.getClass()) {return -1;} + return Comparator.comparing((Pair p)-> p.inches.width) + .thenComparing((Pair p)-> p.inches.height) + .compare(this, (Pair)o); + } + + public DimensionFloat getInches() { + return inches; + } + + public DimensionFloat getMm() { + return mm; + } + } + + /** + * Simple dimension container using floats + */ + public class DimensionFloat { + private float width; + private float height; + + public DimensionFloat(float width, float height) { + this.width = width; + this.height = height; + } + + public float getWidth() { + return width; + } + + public float getHeight() { + return height; + } + } + + /** + * Adds an imperial (in) and metric (mm) entry of the specified MediaSizeName + */ + public boolean add(MediaSizeName mediaSizeName) { + MediaSize mediaSize = MediaSize.getMediaSizeForName(mediaSizeName); + if(mediaSize != null) { + return add(new Pair(mediaSize)); + } + return false; + } +}