8203796: Define API to support specifying ownership of print dialogs
Reviewed-by: serb, kcr
--- a/src/java.desktop/share/classes/javax/print/ServiceUI.java Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/share/classes/javax/print/ServiceUI.java Wed Jun 06 12:51:44 2018 -0700
@@ -25,8 +25,6 @@
package javax.print;
-import java.awt.Dialog;
-import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
@@ -35,11 +33,11 @@
import javax.print.attribute.Attribute;
import javax.print.attribute.AttributeSet;
+import javax.print.attribute.standard.DialogOwner;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.Destination;
import javax.print.attribute.standard.Fidelity;
-import sun.print.DialogOwner;
import sun.print.ServiceDialog;
import sun.print.SunAlternateMedia;
@@ -185,6 +183,7 @@
DialogOwner dlgOwner = (DialogOwner)attributes.get(DialogOwner.class);
Window owner = (dlgOwner != null) ? dlgOwner.getOwner() : null;
+ boolean setOnTop = (dlgOwner != null) && (owner == null);
Rectangle gcBounds = (gc == null) ? GraphicsEnvironment.
getLocalGraphicsEnvironment().getDefaultScreenDevice().
@@ -192,21 +191,17 @@
x += gcBounds.x;
y += gcBounds.y;
- ServiceDialog dialog;
- if (owner instanceof Frame) {
- dialog = new ServiceDialog(gc,
- x,
- y,
- services, defaultIndex,
- flavor, attributes,
- (Frame)owner);
- } else {
- dialog = new ServiceDialog(gc,
- x,
- y,
- services, defaultIndex,
- flavor, attributes,
- (Dialog)owner);
+ ServiceDialog dialog = new ServiceDialog(gc,
+ x,
+ y,
+ services, defaultIndex,
+ flavor, attributes,
+ owner);
+ if (setOnTop) {
+ try {
+ dialog.setAlwaysOnTop(true);
+ } catch (SecurityException e) {
+ }
}
Rectangle dlgBounds = dialog.getBounds();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/classes/javax/print/attribute/standard/DialogOwner.java Wed Jun 06 12:51:44 2018 -0700
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.print.attribute.standard;
+
+import java.awt.Window;
+import javax.print.attribute.Attribute;
+import javax.print.attribute.PrintRequestAttribute;
+import sun.print.DialogOwnerAccessor;
+
+/**
+ * An attribute class used to support requesting a print or page setup dialog
+ * be kept displayed on top of all windows or some specific window.
+ * <p>
+ * Constructed without any arguments it will request that a print or page
+ * setup dialog be configured as if the application directly was to specify
+ * {@code java.awt.Window.setAlwaysOnTop(true)}, subject to permission checks.
+ * <p>
+ * Constructed with a {@link java.awt.Window} parameter, it requests that
+ * the dialog be owned by the specified window.
+ *
+ * @since 11
+ */
+public final class DialogOwner implements PrintRequestAttribute {
+
+ private static class Accessor extends DialogOwnerAccessor {
+
+ public long getOwnerID(DialogOwner owner) {
+ return owner.getID();
+ }
+ }
+
+ static private Accessor accessor = new Accessor();
+ static {
+ DialogOwnerAccessor.setAccessor(accessor);
+ }
+
+ private static final long serialVersionUID = -1901909867156076547L;
+
+ private Window owner;
+ private transient long id;
+
+ /**
+ * Constructs an instance which can be used to request
+ * {@code java.awt.Window.setAlwaysOnTop(true)} behaviour.
+ * This should be used where there is no application preferred owner window.
+ * Whether this has any effect depends on if always on top is supported
+ * for this platform and the particular dialog to be displayed.
+ */
+ public DialogOwner() {
+ }
+
+ /**
+ * Constructs an instance which can be used to request that the
+ * specified {@link java.awt.Window} be the owner of the dialog.
+ * @param owner window.
+ */
+ public DialogOwner(Window owner) {
+ this.owner = owner;
+ }
+
+ /**
+ * Constructs an instance which requests that the dialog be displayed
+ * as if it were a child of a native platform window, specified
+ * using its opqaue platform identifier or handle.
+ * This is useful mainly for the case where the id represents a window
+ * which may not be an AWT {@code Window}, but instead was created by
+ * another UI toolkit, such as OpenJFX.
+ * Any effect is platform dependent.
+ * @param id a native window identifier or handle
+ */
+ DialogOwner(long id) {
+ this.id = id;
+ }
+
+ /**
+ * Returns a native platform id or handle, if one was specified,
+ * otherwise, zero.
+ * @return a native platform id.
+ */
+ long getID() {
+ return id;
+ }
+
+ /**
+ * Returns a {@code Window owner}, if one was specified,
+ * otherwise {@code null}.
+ * @return an owner window.
+ */
+ public Window getOwner() {
+ return owner;
+ }
+
+ /**
+ * Get the printing attribute class which is to be used as the "category"
+ * for this printing attribute value.
+ * <p>
+ * For class {@code DialogOwner}, the category is class
+ * {@code DialogOwner} itself.
+ *
+ * @return printing attribute class (category), an instance of class
+ * {@link Class java.lang.Class}
+ */
+ public final Class<? extends Attribute> getCategory() {
+ return DialogOwner.class;
+ }
+
+ /**
+ * Get the name of the category of which this attribute value is an
+ * instance.
+ * <p>
+ * For class {@code DialogOwner}, the category name is
+ * {@code "dialog-owner"}.
+ *
+ */
+ public final String getName() {
+ return "dialog-owner";
+
+ }
+}
--- a/src/java.desktop/share/classes/sun/print/DialogOnTop.java Wed Jun 06 12:35:44 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.print;
-
-import javax.print.attribute.Attribute;
-import javax.print.attribute.PrintRequestAttribute;
-
-/*
- * An implementation class used to request the dialog be set always-on-top.
- * It needs to be read and honoured by the dialog code which will use
- * java.awt.Window.setAlwaysOnTop(true) in cases where it is supported.
- */
-public class DialogOnTop implements PrintRequestAttribute {
-
- private static final long serialVersionUID = -1901909867156076547L;
-
- long id;
-
- public DialogOnTop() {
- }
-
- public DialogOnTop(long id) {
- this.id = id;
- }
-
- public final Class<? extends Attribute> getCategory() {
- return DialogOnTop.class;
- }
-
- public long getID() {
- return id;
- }
-
- public final String getName() {
- return "dialog-on-top";
- }
-
- public String toString() {
- return "dialog-on-top";
- }
-}
--- a/src/java.desktop/share/classes/sun/print/DialogOwner.java Wed Jun 06 12:35:44 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.print;
-
-import java.awt.Dialog;
-import javax.print.attribute.Attribute;
-import javax.print.attribute.PrintRequestAttribute;
-import java.awt.Frame;
-import java.awt.Window;
-
-/**
- * Class DialogOwner is a printing attribute class that identifies
- * the window that owns the print dialog.
- *
- * <P>
- * <B>IPP Compatibility:</B> This is not an IPP attribute.
- * <P>
- *
- */
-@SuppressWarnings("serial") // JDK-implementation class
-public final class DialogOwner
- implements PrintRequestAttribute {
-
- private Window dlgOwner;
-
- /**
- * Construct a new dialog owner attribute with the given frame.
- *
- * @param frame the frame that owns the print dialog
- */
- public DialogOwner(Frame frame) {
- dlgOwner = frame;
- }
-
- /**
- * Construct a new dialog owner attribute with the given dialog.
- *
- * @param dialog the dialog that owns the print dialog
- */
- public DialogOwner(Dialog dialog) {
- dlgOwner = dialog;
- }
-
- /**
- * Returns the string table for class DialogOwner.
- */
- public Window getOwner() {
- return dlgOwner;
- }
-
-
- /**
- * Get the printing attribute class which is to be used as the "category"
- * for this printing attribute value.
- * <P>
- * For class DialogOwner the category is class
- * DialogOwner itself.
- *
- * @return Printing attribute class (category), an instance of class
- * {@link java.lang.Class java.lang.Class}.
- */
- public Class<? extends Attribute> getCategory() {
- return DialogOwner.class;
- }
-
-
- /**
- * Get the name of the category of which this attribute value is an
- * instance.
- * <P>
- * For class DialogOwner the category name is
- * {@code "dialog-owner"}.
- *
- * @return Attribute category name.
- */
- public String getName() {
- return "dialog-owner";
- }
-
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/classes/sun/print/DialogOwnerAccessor.java Wed Jun 06 12:51:44 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.print;
+
+import javax.print.attribute.standard.DialogOwner;
+
+public abstract class DialogOwnerAccessor {
+
+ public abstract long getOwnerID(DialogOwner owner);
+
+ public static DialogOwnerAccessor accessor = null;
+
+ public static void setAccessor(DialogOwnerAccessor acc) {
+ accessor = acc;
+ }
+
+ public static long getID(DialogOwner owner) {
+ if (accessor == null || owner == null) {
+ return 0;
+ } else {
+ return accessor.getOwnerID(owner);
+ }
+ }
+}
--- a/src/java.desktop/share/classes/sun/print/PrintJob2D.java Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/share/classes/sun/print/PrintJob2D.java Wed Jun 06 12:51:44 2018 -0700
@@ -60,6 +60,7 @@
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.Destination;
import javax.print.attribute.standard.DialogTypeSelection;
+import javax.print.attribute.standard.DialogOwner;
import javax.print.attribute.standard.JobName;
import javax.print.attribute.standard.MediaSize;
import javax.print.attribute.standard.PrintQuality;
--- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java Wed Jun 06 12:51:44 2018 -0700
@@ -74,6 +74,7 @@
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.Destination;
import javax.print.attribute.standard.DialogTypeSelection;
+import javax.print.attribute.standard.DialogOwner;
import javax.print.attribute.standard.Fidelity;
import javax.print.attribute.standard.JobName;
import javax.print.attribute.standard.JobSheets;
@@ -830,17 +831,24 @@
int x = gcBounds.x+50;
int y = gcBounds.y+50;
ServiceDialog pageDialog;
+ boolean setOnTop = false;
if (onTop != null) {
attributes.add(onTop);
+ Window owner = onTop.getOwner();
+ if (owner != null) {
+ w = owner; // use the one specifed by the app
+ } else if (DialogOwnerAccessor.getID(onTop) == 0) {
+ setOnTop = true;
+ }
}
- if (w instanceof Frame) {
pageDialog = new ServiceDialog(gc, x, y, service,
DocFlavor.SERVICE_FORMATTED.PAGEABLE,
- attributes,(Frame)w);
- } else {
- pageDialog = new ServiceDialog(gc, x, y, service,
- DocFlavor.SERVICE_FORMATTED.PAGEABLE,
- attributes, (Dialog)w);
+ attributes, w);
+ if (setOnTop) {
+ try {
+ pageDialog.setAlwaysOnTop(true);
+ } catch (SecurityException e) {
+ }
}
Rectangle dlgBounds = pageDialog.getBounds();
@@ -988,8 +996,7 @@
* (it might be set in java.awt.PrintJob.printDialog)
*/
if (attributes.get(DialogOwner.class) == null) {
- attributes.add(w instanceof Frame ? new DialogOwner((Frame)w) :
- new DialogOwner((Dialog)w));
+ attributes.add(new DialogOwner(w));
}
} else {
grCfg = GraphicsEnvironment.getLocalGraphicsEnvironment().
@@ -2581,7 +2588,7 @@
}
}
- private DialogOnTop onTop = null;
+ private DialogOwner onTop = null;
private long parentWindowID = 0L;
@@ -2597,9 +2604,9 @@
private void setParentWindowID(PrintRequestAttributeSet attrs) {
parentWindowID = 0L;
- onTop = (DialogOnTop)attrs.get(DialogOnTop.class);
+ onTop = (DialogOwner)attrs.get(DialogOwner.class);
if (onTop != null) {
- parentWindowID = onTop.getID();
+ parentWindowID = DialogOwnerAccessor.getID(onTop);
}
}
}
--- a/src/java.desktop/share/classes/sun/print/ServiceDialog.java Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/share/classes/sun/print/ServiceDialog.java Wed Jun 06 12:51:44 2018 -0700
@@ -38,6 +38,7 @@
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Toolkit;
+import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
@@ -136,33 +137,13 @@
int defaultServiceIndex,
DocFlavor flavor,
PrintRequestAttributeSet attributes,
- Dialog dialog)
+ Window window)
{
- super(dialog, getMsg("dialog.printtitle"), true, gc);
+ super(window, getMsg("dialog.printtitle"), Dialog.DEFAULT_MODALITY_TYPE, gc);
initPrintDialog(x, y, services, defaultServiceIndex,
flavor, attributes);
}
-
-
- /**
- * Constructor for the "standard" print dialog (containing all relevant
- * tabs)
- */
- public ServiceDialog(GraphicsConfiguration gc,
- int x, int y,
- PrintService[] services,
- int defaultServiceIndex,
- DocFlavor flavor,
- PrintRequestAttributeSet attributes,
- Frame frame)
- {
- super(frame, getMsg("dialog.printtitle"), true, gc);
- initPrintDialog(x, y, services, defaultServiceIndex,
- flavor, attributes);
- }
-
-
/**
* Initialize print dialog.
*/
@@ -184,8 +165,22 @@
isAWT = true;
}
- if (attributes.get(DialogOnTop.class) != null) {
- setAlwaysOnTop(true);
+ if (attributes.get(DialogOwner.class) != null) {
+ DialogOwner owner = (DialogOwner)attributes.get(DialogOwner.class);
+ /* When the ServiceDialog is constructed the caller of the
+ * constructor checks for this attribute and if it specifies a
+ * window then it will use that in the constructor instead of
+ * inferring one from keyboard focus.
+ * In this case the owner of the dialog is the same as that
+ * specified in the attribute and we do not need to set the
+ * on top property
+ */
+ if ((getOwner() == null) || (owner.getOwner() != getOwner())) {
+ try {
+ setAlwaysOnTop(true);
+ } catch (SecurityException e) {
+ }
+ }
}
Container c = getContentPane();
c.setLayout(new BorderLayout());
@@ -244,28 +239,13 @@
PrintService ps,
DocFlavor flavor,
PrintRequestAttributeSet attributes,
- Dialog dialog)
+ Window window)
{
- super(dialog, getMsg("dialog.pstitle"), true, gc);
+ super(window, getMsg("dialog.pstitle"), Dialog.DEFAULT_MODALITY_TYPE, gc);
initPageDialog(x, y, ps, flavor, attributes);
}
/**
- * Constructor for the solitary "page setup" dialog
- */
- public ServiceDialog(GraphicsConfiguration gc,
- int x, int y,
- PrintService ps,
- DocFlavor flavor,
- PrintRequestAttributeSet attributes,
- Frame frame)
- {
- super(frame, getMsg("dialog.pstitle"), true, gc);
- initPageDialog(x, y, ps, flavor, attributes);
- }
-
-
- /**
* Initialize "page setup" dialog
*/
void initPageDialog(int x, int y,
@@ -278,8 +258,15 @@
this.asOriginal = attributes;
this.asCurrent = new HashPrintRequestAttributeSet(attributes);
- if (attributes.get(DialogOnTop.class) != null) {
- setAlwaysOnTop(true);
+ if (attributes.get(DialogOwner.class) != null) {
+ /* See comments in same block in initPrintDialog */
+ DialogOwner owner = (DialogOwner)attributes.get(DialogOwner.class);
+ if ((getOwner() == null) || (owner.getOwner() != getOwner())) {
+ try {
+ setAlwaysOnTop(true);
+ } catch (SecurityException e) {
+ }
+ }
}
Container c = getContentPane();
--- a/src/java.desktop/unix/classes/sun/print/IPPPrintService.java Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/unix/classes/sun/print/IPPPrintService.java Wed Jun 06 12:51:44 2018 -0700
@@ -25,6 +25,8 @@
package sun.print;
+import java.awt.GraphicsEnvironment;
+import java.awt.Toolkit;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;
import javax.print.DocFlavor;
@@ -1071,6 +1073,11 @@
catList.add(PrinterResolution.class);
}
+ if (GraphicsEnvironment.isHeadless() == false) {
+ catList.add(DialogOwner.class);
+ catList.add(DialogTypeSelection.class);
+ }
+
supportedCats = new Class<?>[catList.size()];
catList.toArray(supportedCats);
Class<?>[] copyCats = new Class<?>[supportedCats.length];
@@ -1392,10 +1399,38 @@
}
}
return false;
- } if (attr.getCategory() == PrinterResolution.class) {
+ } else if (attr.getCategory() == PrinterResolution.class) {
if (attr instanceof PrinterResolution) {
return isSupportedResolution((PrinterResolution)attr);
}
+ } else if (attr.getCategory() == DialogOwner.class) {
+ DialogOwner owner = (DialogOwner)attr;
+ // ID not supported on any dialog type on Unix platforms.
+ if (DialogOwnerAccessor.getID(owner) != 0) {
+ return false;
+ }
+ // On Mac we have no control over the native dialog.
+ DialogTypeSelection dst = (attributes == null) ? null :
+ (DialogTypeSelection)attributes.get(DialogTypeSelection.class);
+ if (PrintServiceLookupProvider.isMac() &&
+ dst == DialogTypeSelection.NATIVE) {
+ return false;
+ }
+ // The other case is always a Swing dialog on all Unix platforms.
+ // So we only need to check that the toolkit supports
+ // always on top.
+ if (owner.getOwner() != null) {
+ return true;
+ } else {
+ return Toolkit.getDefaultToolkit().isAlwaysOnTopSupported();
+ }
+ } else if (attr.getCategory() == DialogTypeSelection.class) {
+ if (PrintServiceLookupProvider.isMac()) {
+ return true;
+ } else {
+ DialogTypeSelection dst = (DialogTypeSelection)attr;
+ return attr == DialogTypeSelection.COMMON;
+ }
}
return true;
}
--- a/src/java.desktop/unix/classes/sun/print/UnixPrintService.java Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/unix/classes/sun/print/UnixPrintService.java Wed Jun 06 12:51:44 2018 -0700
@@ -31,6 +31,8 @@
import java.util.ArrayList;
import java.util.Locale;
+import java.awt.GraphicsEnvironment;
+import java.awt.Toolkit;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintService;
@@ -54,6 +56,8 @@
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.CopiesSupported;
import javax.print.attribute.standard.Destination;
+import javax.print.attribute.standard.DialogOwner;
+import javax.print.attribute.standard.DialogTypeSelection;
import javax.print.attribute.standard.Fidelity;
import javax.print.attribute.standard.Media;
import javax.print.attribute.standard.MediaPrintableArea;
@@ -619,10 +623,15 @@
}
public Class<?>[] getSupportedAttributeCategories() {
- int totalCats = otherAttrCats.length;
- Class<?>[] cats = new Class<?>[totalCats];
- System.arraycopy(otherAttrCats, 0, cats, 0, otherAttrCats.length);
- return cats;
+ ArrayList<Class<?>> categList = new ArrayList<>(otherAttrCats.length);
+ for (Class<?> c : otherAttrCats) {
+ categList.add(c);
+ }
+ if (GraphicsEnvironment.isHeadless() == false) {
+ categList.add(DialogOwner.class);
+ categList.add(DialogTypeSelection.class);
+ }
+ return categList.toArray(new Class<?>[categList.size()]);
}
public boolean
@@ -1023,6 +1032,24 @@
flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
return false;
}
+ } else if (attr.getCategory() == DialogOwner.class) {
+ DialogOwner owner = (DialogOwner)attr;
+ // ID not supported on any dialog type on Unix platforms.
+ if (DialogOwnerAccessor.getID(owner) != 0) {
+ return false;
+ }
+ // UnixPrintService is not used on Mac, so this is
+ // always some Unix system that does not have CUPS/IPP
+ // Which means we always use a Swing dialog and we need
+ // only check if alwaysOnTop is supported by the toolkit.
+ if (owner.getOwner() != null) {
+ return true;
+ } else {
+ return Toolkit.getDefaultToolkit().isAlwaysOnTopSupported();
+ }
+ } else if (attr.getCategory() == DialogTypeSelection.class) {
+ DialogTypeSelection dts = (DialogTypeSelection)attr;
+ return dts == DialogTypeSelection.COMMON;
}
return true;
}
--- a/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java Wed Jun 06 12:51:44 2018 -0700
@@ -79,6 +79,7 @@
import javax.print.attribute.standard.SheetCollate;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.Destination;
+import javax.print.attribute.standard.DialogOwner;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.Media;
import javax.print.attribute.standard.MediaSizeName;
@@ -95,7 +96,6 @@
import sun.print.Win32PrintService;
import sun.print.PrintServiceLookupProvider;
import sun.print.ServiceDialog;
-import sun.print.DialogOwner;
import java.awt.Frame;
import java.io.FilePermission;
--- a/src/java.desktop/windows/classes/sun/print/Win32PrintService.java Wed Jun 06 12:35:44 2018 -0700
+++ b/src/java.desktop/windows/classes/sun/print/Win32PrintService.java Wed Jun 06 12:51:44 2018 -0700
@@ -25,6 +25,8 @@
package sun.print;
+import java.awt.GraphicsEnvironment;
+import java.awt.Toolkit;
import java.awt.Window;
import java.awt.print.PrinterJob;
import java.io.File;
@@ -54,6 +56,8 @@
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.CopiesSupported;
import javax.print.attribute.standard.Destination;
+import javax.print.attribute.standard.DialogOwner;
+import javax.print.attribute.standard.DialogTypeSelection;
import javax.print.attribute.standard.Fidelity;
import javax.print.attribute.standard.Media;
import javax.print.attribute.standard.MediaSizeName;
@@ -1042,6 +1046,10 @@
categList.add(PrinterResolution.class);
}
+ if (GraphicsEnvironment.isHeadless() == false) {
+ categList.add(DialogOwner.class);
+ categList.add(DialogTypeSelection.class);
+ }
return categList.toArray(new Class<?>[categList.size()]);
}
@@ -1585,6 +1593,23 @@
(isColorSup && (attr == ColorSupported.NOT_SUPPORTED))) {
return false;
}
+ } else if (category == DialogTypeSelection.class) {
+ return true; // isHeadless was checked by category support
+ } else if (category == DialogOwner.class) {
+ DialogOwner owner = (DialogOwner)attr;
+ DialogTypeSelection dts = (attributes == null) ? null :
+ (DialogTypeSelection)attributes.get(DialogTypeSelection.class);
+ if (dts == DialogTypeSelection.NATIVE) {
+ return DialogOwnerAccessor.getID(owner) != 0;
+ } else {
+ if (DialogOwnerAccessor.getID(owner) != 0) {
+ return false;
+ } else if (owner.getOwner() != null) {
+ return true;
+ } else {
+ return Toolkit.getDefaultToolkit().isAlwaysOnTopSupported();
+ }
+ }
}
return true;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/awt/print/Dialog/DialogOwnerTest.java Wed Jun 06 12:51:44 2018 -0700
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ @bug 8203796
+ @run main/manual DialogOwnerTest
+ @summary Test DialogOwner API
+*/
+
+import java.util.ArrayList;
+import java.util.List;
+import java.awt.GraphicsConfiguration;
+import java.awt.GridLayout;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.print.PrinterJob;
+import javax.print.PrintService;
+import javax.print.PrintServiceLookup;
+import javax.print.ServiceUI;
+import javax.print.attribute.HashPrintRequestAttributeSet;
+import javax.print.attribute.PrintRequestAttributeSet;
+import javax.print.attribute.standard.DialogOwner;
+import javax.print.attribute.standard.DialogTypeSelection;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+
+public class DialogOwnerTest extends JPanel {
+
+ static final int NONE = 0x0;
+ static final int PRINT = 0x1;
+ static final int PAGE = 0x2;
+ static final int SWING2D = 0x4;
+ static final int NATIVE2D = 0x8;
+ static final int SERVICEUI = 0x10;
+
+ static final int ONTOP = 0x20;
+ static final int OWNED = 0x40;
+
+ static PrintService[] services =
+ PrintServiceLookup.lookupPrintServices(null, null);
+
+ public static void main(String[] args) {
+ if (services.length == 0) {
+ System.out.println("No printers, exiting");
+ return;
+ } else {
+ service = PrinterJob.getPrinterJob().getPrintService();
+ }
+ SwingUtilities.invokeLater(() -> {
+ createUI();
+ });
+ while (!testFinished) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e){
+ }
+ }
+ if (!testPassed) {
+ throw new RuntimeException("TEST FAILED.");
+ }
+ }
+
+
+ static final String otherText =
+ "This window is used to test on top behaviour\n" +
+ "For tests that are 'Owned' or 'On Top' the dialog\n" +
+ "must always stay above this window. Verify this\n " +
+ "by moving the dialog so that it partially obscures\n" +
+ "this window and then trying to raise this window.";
+
+ static final String instructions =
+ " Instructions\n" +
+ "This tests that a print dialog stays on top of either another\n" +
+ "window, or on top of all windows.\n" +
+ "For Owned tests the window titled 'Owner Window' should always \n" +
+ "stay behind the print dialog.\n" +
+ "For On Top tests all windows should stay behind the owner window.\n" +
+ "This test tracks if you have checked all the scenarios and will\n" +
+ "not allow the test to pass unless you have visited them all.\n";
+
+ static PrintService service;
+
+ public DialogOwnerTest() {
+ super();
+ //setLayout(new GridLayout(24, 1));
+ }
+
+ static boolean isNative(int flags) {
+ return (flags & NATIVE2D) != 0;
+ }
+
+ static boolean isCommon(int flags) {
+ return (flags & SWING2D) != 0;
+ }
+
+ static boolean is2D(int flags) {
+ return (flags & SWING2D|NATIVE2D) != 0;
+ }
+
+ static boolean isPage(int flags) {
+ return (flags & PAGE ) != 0;
+ }
+
+ static JFrame frame;
+ static JFrame other;
+ static JButton pass;
+ static ArrayList<JPanel> panelList = new ArrayList<JPanel>();
+ static volatile boolean testPassed, testFinished;
+
+ int testCount = 0;
+ List<String> testList = new ArrayList<String>();
+
+ static void createUI() {
+ other = new JFrame("Owner Window");
+ JTextArea otherTextArea = new JTextArea(otherText, 10, 40);
+ other.add(otherTextArea);
+ other.pack();
+ other.setVisible(true);
+ other.setLocation(800, 100);
+
+ frame = new JFrame("Test Dialog Owner");
+ frame.pack();
+ JTextArea instructionsPanel = new JTextArea(instructions, 10, 50);
+ instructionsPanel.setEditable(false);
+ frame.add("North", instructionsPanel);
+ DialogOwnerTest test = new DialogOwnerTest();
+
+ test.addTest("Owned Swing Print", OWNED, frame, PRINT|SWING2D);
+ test.addTest("On Top Swing Print", ONTOP, null, PRINT|SWING2D);
+
+ test.addTest("Owned Swing Page", OWNED, frame, PAGE|SWING2D);
+ test.addTest("On Top Swing Page", ONTOP, null, PAGE|SWING2D);
+
+ test.addTest("Owned javax.print", OWNED, frame, PRINT|SERVICEUI);
+ test.addTest("On Top javax.print", OWNED, null, PRINT|SERVICEUI);
+
+ test.addTest("Owned Native Print", OWNED, frame, PRINT|NATIVE2D);
+ test.addTest("On Top Native Print", OWNED, null, PRINT|NATIVE2D);
+
+ test.addTest("Owned Native Page", OWNED, frame, PAGE|NATIVE2D);
+ test.addTest("On Top Native Page", OWNED, null, PAGE|NATIVE2D);
+
+ test.setLayout(new GridLayout(panelList.size()+2, 1));
+
+ pass = new JButton("Pass");
+ pass.setEnabled(false);
+ pass.addActionListener((ActionEvent e) -> {
+ if (test.testList.size() > 0) {
+ return;
+ }
+ frame.dispose();
+ other.dispose();
+ System.out.println("User says test passed.");
+ testPassed = true;
+ testFinished = true;
+ });
+
+ JButton fail = new JButton("Fail");
+ fail.addActionListener((ActionEvent e) -> {
+ frame.dispose();
+ other.dispose();
+ System.out.println("User says test failed.");
+ testPassed = false;
+ testFinished = true;
+ });
+
+ JPanel p = new JPanel();
+ p.add(pass);
+ p.add(fail);
+ test.add(p);
+
+
+ for (JPanel panel : panelList) {
+ test.add(panel);
+ }
+
+ frame.add("Center", test);
+ frame.pack();
+ frame.setLocation(0,0);
+ frame.setVisible(true);
+ }
+
+ boolean isSupported(PrintRequestAttributeSet aset,
+ int ownerFlags, Window owner, int dlgFlags) {
+
+ boolean supported = true;
+ DialogOwner ownerAttr = null;
+ if (ownerFlags != NONE) {
+ if (ownerFlags == ONTOP) {
+ ownerAttr = new DialogOwner();
+ } else if (ownerFlags == OWNED) {
+ ownerAttr = new DialogOwner(owner);
+ }
+ aset.add(ownerAttr);
+ }
+ if (is2D(dlgFlags)) {
+ DialogTypeSelection dst = null;
+ if (isNative(dlgFlags)) {
+ dst = DialogTypeSelection.NATIVE;
+ } else if (isCommon(dlgFlags)) {
+ dst = DialogTypeSelection.COMMON;
+ }
+ if (dst != null &&
+ !service.isAttributeValueSupported(dst, null, aset)) {
+ //System.out.println("This DialogType not supported");
+ supported = false;
+ }
+ if (dst != null) {
+ aset.add(dst);
+ }
+ if (ownerAttr != null &&
+ !service.isAttributeValueSupported(ownerAttr, null, aset)) {
+ //System.out.println("This DialogOwner not supported");
+ supported = false;
+ }
+ }
+ return supported;
+ }
+
+ void addTest(String title, int ownerFlags, Window owner, int dlgFlags) {
+
+ PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
+ if (!isSupported(aset, ownerFlags, owner, dlgFlags)) {
+ return;
+ }
+
+ // if we are here then this is supportable and worth testing
+ // and the attribute set is configured.
+
+ String label = title + " Dialog";
+ JButton button = new JButton(label);
+ JCheckBox tested = new JCheckBox("Tested");
+ tested.setEnabled(false);
+ JPanel panel = new JPanel();
+ panel.add(tested);
+ panel.add(button);
+ panelList.add(panel);
+ //add(panel);
+ testList.add(title);
+ if (++testCount != testList.size()) {
+ throw new RuntimeException("Test titles must be unique");
+ }
+
+ button.addActionListener((ActionEvent e) -> {
+ tested.setSelected(true);
+ testList.remove(title);
+ if (testList.isEmpty()) {
+ pass.setEnabled(true);
+ }
+
+ if (is2D(dlgFlags)) {
+ PrinterJob job = PrinterJob.getPrinterJob();
+ if (isPage(dlgFlags)) {
+ job.pageDialog(aset);
+ } else {
+ job.printDialog(aset);
+ }
+ } else {
+ GraphicsConfiguration gc = null;
+ int x = 0, y = 0;
+ ServiceUI.printDialog(gc, x, y, services, services[0], null,aset);
+ }
+ });
+ }
+}