3232import javax .print .PrintService ;
3333import javax .print .PrintServiceLookup ;
3434import java .util .Comparator ;
35+ import java .util .HashMap ;
3536import java .util .Set ;
3637import java .util .TreeSet ;
3738import java .awt .Graphics ;
@@ -62,8 +63,6 @@ public PrinterJobImpl createPrinterJob(PrinterJob job) {
6263
6364 private static Printer defaultPrinter = null ;
6465 public synchronized Printer getDefaultPrinter () {
65- // Eventually this needs to be updated to reflect when
66- // the default has changed.
6766 if (defaultPrinter == null ) {
6867 PrintService defPrt =
6968 PrintServiceLookup .lookupDefaultPrintService ();
@@ -96,13 +95,16 @@ public int compare(Printer p1, Printer p2) {
9695
9796 private static final NameComparator nameComparator = new NameComparator ();
9897
99- // This is static. Eventually I want it to be dynamic, but first
100- // it needs to be enhanced to only create new instances where
101- // there really has been a change, which will be rare.
98+ // The map is useful when updating
99+ private static HashMap <PrintService , Printer > pMap = new HashMap <>();
100+
101+ private static long lastTime = 0L ;
102102 private static ObservableSet <Printer > printerSet = null ;
103+ private static ObservableSet <Printer > returnedPrinterSet = null ;
104+
103105 public synchronized ObservableSet <Printer > getAllPrinters () {
104- if (printerSet == null ) {
105- Set printers = new TreeSet <Printer >(nameComparator );
106+ if (returnedPrinterSet == null ) {
107+ TreeSet < Printer > printers = new TreeSet <Printer >(nameComparator );
106108 // Trigger getting default first, so we don't recreate that.
107109 Printer defPrinter = getDefaultPrinter ();
108110 PrintService defService = null ;
@@ -116,17 +118,94 @@ public synchronized ObservableSet<Printer> getAllPrinters() {
116118 for (int i =0 ; i <allServices .length ;i ++) {
117119 if (defService != null && defService .equals (allServices [i ])) {
118120 printers .add (defPrinter );
121+ pMap .put (defService , defPrinter );
119122 } else {
120- PrinterImpl impl = new J2DPrinter (allServices [i ]);
121- Printer printer = PrintHelper .createPrinter (impl );
122- impl .setPrinter (printer );
123- printers .add (printer );
123+ addNew (allServices [i ], printers );
124+ }
125+ }
126+ printerSet = FXCollections .observableSet (printers );
127+ returnedPrinterSet =
128+ FXCollections .unmodifiableObservableSet (printerSet );
129+ lastTime = System .currentTimeMillis ();
130+ } else {
131+ PrintService [] newServices =
132+ PrintServiceLookup .lookupPrintServices (null , null );
133+ if ((newServices .length != printerSet .size ()) ||
134+ (lastTime + 120000 ) < System .currentTimeMillis ()) {
135+ updatePrinters (newServices );
136+ lastTime = System .currentTimeMillis ();
137+ }
138+ }
139+ return returnedPrinterSet ;
140+ }
141+
142+ private void addNew (PrintService s , Set <Printer > printers ) {
143+ PrinterImpl impl = new J2DPrinter (s );
144+ Printer printer = PrintHelper .createPrinter (impl );
145+ impl .setPrinter (printer );
146+ printers .add (printer );
147+ pMap .put (s , printer );
148+ }
149+
150+ /* Only change a Printer instance if Java 2D changed it.
151+ * Otherwise re-map back to the existing Printer instance.
152+ * This relies on Java 2D not re-creating a printer too.
153+ * Update the existing set so that an app that has cached the printer list
154+ * automatically gets the updates. They can also observe changes .. but
155+ * if doing so they could see the work in progress, but that's probably
156+ * a good thing for an app that is interested.
157+ * Two passes -
158+ * First pass remove any printers that no longer exist.
159+ * Second pass add any new printers.
160+ * Finally update the default printer - if needed.
161+ */
162+ private void updatePrinters (PrintService [] newServices ) {
163+
164+ Set <PrintService > oldServiceSet = pMap .keySet ();
165+ PrintService [] oldServices = oldServiceSet .toArray (new PrintService [0 ]);
166+
167+ for (PrintService os : oldServices ) {
168+ boolean present = false ;
169+ for (PrintService ns : newServices ) {
170+ if (os .equals (ns )) {
171+ present = true ;
172+ break ;
124173 }
125174 }
126- printerSet =
127- FXCollections .unmodifiableObservableSet
128- (FXCollections .observableSet (printers ));
175+ if (!present ) {
176+ Printer printer = pMap .get (os );
177+ pMap .remove (os );
178+ printerSet .remove (printer );
179+ }
180+ }
181+ for (PrintService s : newServices ) {
182+ if (!pMap .containsKey (s )) {
183+ addNew (s , printerSet );
184+ }
185+ }
186+ PrintService oldDefaultService =
187+ (defaultPrinter == null ) ? null :
188+ ((J2DPrinter )PrintHelper .getPrinterImpl (defaultPrinter )).getService ();
189+ PrintService newDefaultService = PrintServiceLookup .lookupDefaultPrintService ();
190+ if (newDefaultService != null ) {
191+ if (oldDefaultService == null ||
192+ (!oldDefaultService .equals (newDefaultService )))
193+ {
194+ defaultPrinter = findDefaultPrinter (printerSet , newDefaultService );
195+ }
196+ } else {
197+ defaultPrinter = null ;
198+ }
199+ }
200+
201+ private static Printer findDefaultPrinter (Set <Printer > printers ,
202+ PrintService defaultService ) {
203+ for (Printer p : printers ) {
204+ PrintService s = ((J2DPrinter )PrintHelper .getPrinterImpl (p )).getService ();
205+ if (s .getName ().equals (defaultService .getName ())) {
206+ return p ;
207+ }
129208 }
130- return printerSet ;
209+ return null ;
131210 }
132211}
0 commit comments