<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">/*
 * @(#)JobAttributes.java	1.4 00/02/02
 *
 * Copyright 1999, 2000 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * This software is the proprietary information of Sun Microsystems, Inc.  
 * Use is subject to license terms.
 * 
 */

package java.awt;

/**
 * A set of attributes which control a print job.
 * &lt;p&gt;
 * Instances of this class control the number of copies, default selection,
 * destination, print dialog, file and printer names, page ranges, multiple
 * document handling (including collation), and multi-page imposition (such
 * as duplex) of every print job which uses the instance. Attribute names are
 * compliant with the Internet Printing Protocol (IPP) 1.1 where possible.
 * Attribute values are partially compliant where possible.
 * &lt;p&gt;
 * To use a method which takes an inner class type, pass a reference to
 * one of the constant fields of the inner class. Client code cannot create
 * new instances of the inner class types because none of those classes
 * has a public constructor. For example, to set the print dialog type to
 * the cross-platform, pure Java print dialog, use the following code:
 * &lt;pre&gt;
 * import java.awt.JobAttributes;
 *
 * public class PureJavaPrintDialogExample {
 *     public void setPureJavaPrintDialog(JobAttributes jobAttributes) {
 *         jobAttributes.setDialog(JobAttributes.DialogType.COMMON);
 *     }
 * }
 * &lt;/pre&gt;
 * &lt;p&gt;
 * Every IPP attribute which supports an &lt;i&gt;attributeName&lt;/i&gt;-default value
 * has a corresponding &lt;code&gt;set&lt;i&gt;attributeName&lt;/i&gt;ToDefault&lt;/code&gt; method.
 * Default value fields are not provided.
 *
 * @version	1.4, 02/02/00
 * @author	David Mendenhall
 */
public final class JobAttributes implements Cloneable {
    /**
     * A type-safe enumeration of possible default selection states.
     */
    public static final class DefaultSelectionType extends AttributeValue {
        private static final int I_ALL = 0;
        private static final int I_RANGE = 1;
        private static final int I_SELECTION = 2;

        private static final String NAMES[] = {
	    "all", "range", "selection"
	};

        /**
	 * The DefaultSelectionType instance to use for specifying that all
	 * pages of the job should be printed.
	 */
        public static final DefaultSelectionType ALL =
           new DefaultSelectionType(I_ALL);
        /**
	 * The DefaultSelectionType instance to use for specifying that a
	 * range of pages of the job should be printed.
	 */
        public static final DefaultSelectionType RANGE =
           new DefaultSelectionType(I_RANGE);
        /**
	 * The DefaultSelectionType instance to use for specifying that the
	 * current selection should be printed.
	 */
        public static final DefaultSelectionType SELECTION =
           new DefaultSelectionType(I_SELECTION);

        private DefaultSelectionType(int type) {
	    super(type, NAMES);
	}
    }

    /**
     * A type-safe enumeration of possible job destinations.
     */
    public static final class DestinationType extends AttributeValue {
        private static final int I_FILE = 0;
        private static final int I_PRINTER = 1;

        private static final String NAMES[] = {
	    "file", "printer"
	};

        /**
	 * The DestinationType instance to use for specifying print to file.
	 */
        public static final DestinationType FILE =
            new DestinationType(I_FILE);
        /**
	 * The DestinationType instance to use for specifying print to printer.
	 */
        public static final DestinationType PRINTER =
            new DestinationType(I_PRINTER);

        private DestinationType(int type) {
	    super(type, NAMES);
	}
    }

    /**
     * A type-safe enumeration of possible dialogs to display to the user.
     */
    public static final class DialogType extends AttributeValue {
        private static final int I_COMMON = 0;
        private static final int I_NATIVE = 1;
        private static final int I_NONE = 2;

        private static final String NAMES[] = {
	    "common", "native", "none"
	};

        /**
	 * The DialogType instance to use for specifying the cross-platform,
	 * pure Java print dialog.
	 */
        public static final DialogType COMMON = new DialogType(I_COMMON);
        /**
	 * The DialogType instance to use for specifying the platform's
	 * native print dialog.
	 */
        public static final DialogType NATIVE = new DialogType(I_NATIVE);
        /**
	 * The DialogType instance to use for specifying no print dialog.
	 */
        public static final DialogType NONE = new DialogType(I_NONE);

        private DialogType(int type) {
	    super(type, NAMES);
	}
    }

    /**
     * A type-safe enumeration of possible multiple document handling states.
     * These states are in partial compliance with IPP 1.1.
     */
    public static final class MultipleDocumentHandlingType extends
                                                               AttributeValue {
        private static final int I_SEPARATE_DOCUMENTS_COLLATED_COPIES = 0;
        private static final int I_SEPARATE_DOCUMENTS_UNCOLLATED_COPIES = 1;

        private static final String NAMES[] = {
	    "separate-documents-collated-copies",
	    "separate-documents-uncollated-copies"
	};

        /**
	 * The MultipleDocumentHandlingType instance to use for specifying
	 * that the job should be divided into separate, collated documents.
	 */
        public static final MultipleDocumentHandlingType
            SEPARATE_DOCUMENTS_COLLATED_COPIES =
                new MultipleDocumentHandlingType(
                    I_SEPARATE_DOCUMENTS_COLLATED_COPIES);
        /**
	 * The MultipleDocumentHandlingType instance to use for specifying
	 * that the job should be divided into separate, uncollated documents.
	 */
        public static final MultipleDocumentHandlingType
            SEPARATE_DOCUMENTS_UNCOLLATED_COPIES =
                new MultipleDocumentHandlingType(
                    I_SEPARATE_DOCUMENTS_UNCOLLATED_COPIES);

        private MultipleDocumentHandlingType(int type) {
	    super(type, NAMES);
	}
    }

    /**
     * A type-safe enumeration of possible multi-page impositions. These
     * impositions are in compliance with IPP 1.1.
     */
    public static final class SidesType extends AttributeValue {
        private static final int I_ONE_SIDED = 0;
        private static final int I_TWO_SIDED_LONG_EDGE = 1;
        private static final int I_TWO_SIDED_SHORT_EDGE = 2;

        private static final String NAMES[] = {
	    "one-sided", "two-sided-long-edge", "two-sided-short-edge"
	};

        /**
	 * The SidesType instance to use for specifying that consecutive job
	 * pages should be printed upon the same side of consecutive media
	 * sheets.
	 */
        public static final SidesType ONE_SIDED = new SidesType(I_ONE_SIDED);
        /**
	 * The SidesType instance to use for specifying that consecutive job
	 * pages should be printed upon front and back sides of consecutive
	 * media sheets, such that the orientation of each pair of pages on
	 * the medium would be correct for the reader as if for binding on
	 * the long edge.
	 */
        public static final SidesType TWO_SIDED_LONG_EDGE =
            new SidesType(I_TWO_SIDED_LONG_EDGE);
        /**
	 * The SidesType instance to use for specifying that consecutive job
	 * pages should be printed upon front and back sides of consecutive
	 * media sheets, such that the orientation of each pair of pages on
	 * the medium would be correct for the reader as if for binding on
	 * the short edge.
	 */
        public static final SidesType TWO_SIDED_SHORT_EDGE =
            new SidesType(I_TWO_SIDED_SHORT_EDGE);

        private SidesType(int type) {
	    super(type, NAMES);
	}
    }

    private int copies;
    private DefaultSelectionType defaultSelection;
    private DestinationType destination;
    private DialogType dialog;
    private String fileName;
    private int fromPage;
    private int maxPage;
    private int minPage;
    private MultipleDocumentHandlingType multipleDocumentHandling;
    private int[][] pageRanges;
    private int prFirst;
    private int prLast;
    private String printer;
    private SidesType sides;
    private int toPage;

    /**
     * Constructs a JobAttributes instance with default values for every
     * attribute.
     */
    public JobAttributes() {
        setCopiesToDefault();
	setDefaultSelection(DefaultSelectionType.ALL);
	setDestination(DestinationType.PRINTER);
	setDialog(DialogType.NATIVE);
	setMaxPage(Integer.MAX_VALUE);
	setMinPage(1);
	setMultipleDocumentHandlingToDefault();
	setSidesToDefault();
    }

    /**
     * Constructs a JobAttributes instance which is a copy of the supplied
     * JobAttributes.
     *
     * @param	obj the JobAttributes to copy.
     */
    public JobAttributes(JobAttributes obj) {
        set(obj);
    }

    /**
     * Constructs a JobAttributes instance with the specified values for
     * every attribute.
     *
     * @param	copies an integer greater than 0.
     * @param	defaultSelection DefaultSelectionType.ALL,
     *		DefaultSelectionType.RANGE, or DefaultSelectionType.SELECTION.
     * @param	destination DesintationType.FILE or DesintationType.PRINTER.
     * @param	dialog DialogType.COMMON, DialogType.NATIVE, or
     *		DialogType.NONE.
     * @param	fileName the possibly null file name.
     * @param	maxPage an integer greater than zero and greater than or equal
     *		to &lt;i&gt;minPage&lt;/i&gt;.
     * @param	minPage an integer greater than zero and less than or equal
     *		to &lt;i&gt;maxPage&lt;/i&gt;.
     * @param	multipleDocumentHandling
     *     MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES or
     *     MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES.
     * @param	pageRanges an array of integer arrays of 2 elements. An array
     *		is interpreted as a range spanning all pages including and
     *		between the specified pages. Ranges must be in ascending
     *		order and must not overlap. Specified page numbers cannot be
     *		less than &lt;i&gt;minPage&lt;/i&gt; nor greater than &lt;i&gt;maxPage&lt;/i&gt;.
     *		For example:
     *		(new int[][] { new int[] { 1, 3 }, new int[] { 5, 5 },
     *		               new int[] { 15, 19 } }),
     *		specifies pages 1, 2, 3, 5, 15, 16, 17, 18, and 19. Note that
     *		(new int[][] { new int[] { 1, 1 }, new int[] { 1, 2 } }),
     *		is an invalid set of page ranges because the two ranges
     *		overlap.
     * @param	printer the possibly null printer name.
     * @param	sides SidesType.ONE_SIDED, SidesType.TWO_SIDED_LONG_EDGE, or
     *		SidesType.TWO_SIDED_SHORT_EDGE.
     * @throws	IllegalArgumentException if one or more of the above
     *		conditions is violated.
     */
    public JobAttributes(int copies, DefaultSelectionType defaultSelection,
			 DestinationType destination, DialogType dialog,
			 String fileName, int maxPage, int minPage,
			 MultipleDocumentHandlingType multipleDocumentHandling,
			 int[][] pageRanges, String printer, SidesType sides) {
        setCopies(copies);
	setDefaultSelection(defaultSelection);
	setDestination(destination);
	setDialog(dialog);
	setFileName(fileName);
	setMaxPage(maxPage);
	setMinPage(minPage);
	setMultipleDocumentHandling(multipleDocumentHandling);
	setPageRanges(pageRanges);
	setPrinter(printer);
	setSides(sides);
    }

    /**
     * Creates and returns a copy of this JobAttributes.
     *
     * @return	the newly created copy. It is safe to cast this Object into
     *		a JobAttributes.
     */
    public Object clone() {
        try {
	    return super.clone();
	} catch (CloneNotSupportedException e) {
	    // Since we implement Cloneable, this should never happen
	    throw new InternalError();
	}
    }

    /**
     * Sets all of the attributes of this JobAttributes to the same values as
     * the attributes of obj.
     *
     * @param	obj the JobAttributes to copy.
     */
    public void set(JobAttributes obj) {
        copies = obj.copies;
	defaultSelection = obj.defaultSelection;
	destination = obj.destination;
	dialog = obj.dialog;
	fileName = obj.fileName;
	fromPage = obj.fromPage;
	maxPage = obj.maxPage;
	minPage = obj.minPage;
	multipleDocumentHandling = obj.multipleDocumentHandling;
	// okay because we never modify the contents of pageRanges
	pageRanges = obj.pageRanges;
	prFirst = obj.prFirst;
	prLast = obj.prLast;
	printer = obj.printer;
	sides = obj.sides;
	toPage = obj.toPage;
    }

    /**
     * Returns the number of copies the application should render for jobs
     * using these attributes. This attribute is updated to the value chosen
     * by the user.
     *
     * @return	an integer greater than 0.
     */
    public int getCopies() {
        return copies;
    }

    /**
     * Specifies the number of copies the application should render for jobs
     * using these attributes. Not specifying this attribute is equivalent to
     * specifying &lt;code&gt;1&lt;/code&gt;.
     *
     * @param	copies an integer greater than 0.
     * @throws	IllegalArgumentException if copies is less than or equal to 0.
     */
    public void setCopies(int copies) {
        if (copies &lt;= 0) {
	    throw new IllegalArgumentException("Invalid value for attribute "+
					       "copies");
	}
	this.copies = copies;
    }

    /**
     * Sets the number of copies the application should render for jobs using
     * these attributes to the default. The default number of copies is 1.
     */
    public void setCopiesToDefault() {
        setCopies(1);
    }

    /**
     * Specifies whether, for jobs using these attributes, the application
     * should print all pages, the range specified by the return value of
     * &lt;code&gt;getPageRanges&lt;/code&gt;, or the current selection. This attribute
     * is updated to the value chosen by the user.
     *
     * @return	DefaultSelectionType.ALL, DefaultSelectionType.RANGE, or
     *		DefaultSelectionType.SELECTION.
     */
    public DefaultSelectionType getDefaultSelection() {
        return defaultSelection;
    }

    /**
     * Specifies whether, for jobs using these attributes, the application
     * should print all pages, the range specified by the return value of
     * &lt;code&gt;getPageRanges&lt;/code&gt;, or the current selection. Not specifying
     * this attribute is equivalent to specifying DefaultSelectionType.ALL.
     *
     * @param	defaultSelection DefaultSelectionType.ALL,
     *		DefaultSelectionType.RANGE, or DefaultSelectionType.SELECTION.
     * @throws	IllegalArgumentException if defaultSelection is null.
     */
    public void setDefaultSelection(DefaultSelectionType defaultSelection) {
        if (defaultSelection == null) {
	    throw new IllegalArgumentException("Invalid value for attribute "+
					       "defaultSelection");
	}
        this.defaultSelection = defaultSelection;
    }

    /**
     * Specifies whether output will be to a printer or a file for jobs using
     * these attributes. This attribute is updated to the value chosen by the
     * user.
     *
     * @return	DesintationType.FILE or DesintationType.PRINTER.
     */
    public DestinationType getDestination() {
        return destination;
    }

    /**
     * Specifies whether output will be to a printer or a file for jobs using
     * these attributes. Not specifying this attribute is equivalent to
     * specifying DesintationType.PRINTER.
     *
     * @param	destination DesintationType.FILE or DesintationType.PRINTER.
     * @throws	IllegalArgumentException if destination is null.
     */
    public void setDestination(DestinationType destination) {
        if (destination == null) {
	    throw new IllegalArgumentException("Invalid value for attribute "+
					       "destination");
	}
        this.destination = destination;
    }

    /**
     * Returns whether, for jobs using these attributes, the user should see
     * a print dialog in which to modify the print settings, and which type of
     * print dialog should be displayed. DialogType.COMMON denotes a cross-
     * platform, pure Java print dialog. DialogType.NATIVE denotes the
     * platform's native print dialog. If a platform does not support a native
     * print dialog, the pure Java print dialog is displayed instead.
     * DialogType.NONE specifies no print dialog (i.e., background printing).
     * This attribute cannot be modified by, and is not subject to any
     * limitations of, the implementation or the target printer.
     *
     * @return	DialogType.COMMON, DialogType.NATIVE, or
     *		DialogType.NONE.
     */
    public DialogType getDialog() {
        return dialog;
    }

    /**
     * Specifies whether, for jobs using these attributes, the user should see
     * a print dialog in which to modify the print settings, and which type of
     * print dialog should be displayed. DialogType.COMMON denotes a cross-
     * platform, pure Java print dialog. DialogType.NATIVE denotes the
     * platform's native print dialog. If a platform does not support a native
     * print dialog, the pure Java print dialog is displayed instead.
     * DialogType.NONE specifies no print dialog (i.e., background printing).
     * Not specifying this attribute is equivalent to specifying
     * DialogType.NATIVE.
     *
     * @param	dialog DialogType.COMMON, DialogType.NATIVE, or
     *		DialogType.NONE.
     * @throws	IllegalArgumentException if dialog is null.
     */
    public void setDialog(DialogType dialog) {
        if (dialog == null) {
	    throw new IllegalArgumentException("Invalid value for attribute "+
					       "dialog");
	}
        this.dialog = dialog;
    }

    /**
     * Specifies the file name for the output file for jobs using these
     * attributes. This attribute is updated to the value chosen by the user.
     *
     * @return	the possibly null file name.
     */
    public String getFileName() {
        return fileName;
    }

    /**
     * Specifies the file name for the output file for jobs using these
     * attributes. Default is platform-dependent and implementation-defined.
     *
     * @param	fileName the possibly null file name.
     */
    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    /**
     * Returns, for jobs using these attributes, the first page to be
     * printed, if a range of pages is to be printed. This attribute is
     * updated to the value chosen by the user. An application should ignore
     * this attribute on output, unless the return value of the &lt;code&gt;
     * getDefaultSelection&lt;/code&gt; method is DefaultSelectionType.RANGE. An
     * application should honor the return value of &lt;code&gt;getPageRanges&lt;/code&gt;
     * over the return value of this method, if possible.
     *
     * @return	an integer greater than zero and less than or equal to
     *          &lt;i&gt;toPage&lt;/i&gt; and greater than or equal to &lt;i&gt;minPage&lt;/i&gt; and
     *		less than or equal to &lt;i&gt;maxPage&lt;/i&gt;.
     */
    public int getFromPage() {
        if (fromPage != 0) {
	    return fromPage;
	} else if (toPage != 0) {
	    return getMinPage();
	} else if (pageRanges != null) {
	    return prFirst;
	} else {
	    return getMinPage();
	}
    }

    /**
     * Specifies, for jobs using these attributes, the first page to be
     * printed, if a range of pages is to be printed. If this attribute is not
     * specified, then the values from the pageRanges attribute are used. If
     * pageRanges and either or both of fromPage and toPage are specified,
     * pageRanges takes precedence. Specifying none of pageRanges, fromPage,
     * or toPage is equivalent to calling
     * setPageRanges(new int[][] { new int[] { &lt;i&gt;minPage&lt;/i&gt; } });
     *
     * @param	fromPage an integer greater than zero and less than or equal to
     *          &lt;i&gt;toPage&lt;/i&gt; and greater than or equal to &lt;i&gt;minPage&lt;/i&gt; and
     *		less than or equal to &lt;i&gt;maxPage&lt;/i&gt;.
     * @throws	IllegalArgumentException if one or more of the above
     *		conditions is violated.
     */
    public void setFromPage(int fromPage) {
        if (fromPage &lt;= 0 ||
	    (toPage != 0 &amp;&amp; fromPage &gt; toPage) ||
	    fromPage &lt; minPage ||
	    fromPage &gt; maxPage) {
	    throw new IllegalArgumentException("Invalid value for attribute "+
					       "fromPage");
	}
	this.fromPage = fromPage;
    }

    /**
     * Specifies the maximum value the user can specify as the last page to
     * be printed for jobs using these attributes. This attribute cannot be
     * modified by, and is not subject to any limitations of, the
     * implementation or the target printer.
     *
     * @return	an integer greater than zero and greater than or equal
     *		to &lt;i&gt;minPage&lt;/i&gt;.
     */
    public int getMaxPage() {
        return maxPage;
    }

    /**
     * Specifies the maximum value the user can specify as the last page to
     * be printed for jobs using these attributes. Not specifying this
     * attribute is equivalent to specifying &lt;code&gt;Integer.MAX_VALUE&lt;/code&gt;.
     *
     * @param	maxPage an integer greater than zero and greater than or equal
     *		to &lt;i&gt;minPage&lt;/i&gt;.
     * @throws	IllegalArgumentException if one or more of the above
     *		conditions is violated.
     */
    public void setMaxPage(int maxPage) {
        if (maxPage &lt;= 0 || maxPage &lt; minPage) {
	    throw new IllegalArgumentException("Invalid value for attribute "+
					       "maxPage");
	}
	this.maxPage = maxPage;
    }

    /**
     * Specifies the minimum value the user can specify as the first page to
     * be printed for jobs using these attributes. This attribute cannot be
     * modified by, and is not subject to any limitations of, the
     * implementation or the target printer.
     *
     * @return	an integer greater than zero and less than or equal
     *		to &lt;i&gt;maxPage&lt;/i&gt;.
     */
    public int getMinPage() {
        return minPage;
    }

    /**
     * Specifies the minimum value the user can specify as the first page to
     * be printed for jobs using these attributes. Not specifying this
     * attribute is equivalent to specifying &lt;code&gt;1&lt;/code&gt;.
     *
     * @param	minPage an integer greater than zero and less than or equal
     *		to &lt;i&gt;maxPage&lt;/i&gt;.
     * @throws	IllegalArgumentException if one or more of the above
     *		conditions is violated.
     */
    public void setMinPage(int minPage) {
        if (minPage &lt;= 0 || minPage &gt; maxPage) {
	    throw new IllegalArgumentException("Invalid value for attribute "+
					       "minPage");
	}
	this.minPage = minPage;
    }

    /**
     * Specifies the handling of multiple documents, including collation, for
     * jobs using these attributes. This attribute is updated to the value
     * chosen by the user.
     *
     * @return
     *     MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES or
     *     MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES.
     */
    public MultipleDocumentHandlingType getMultipleDocumentHandling() {
        return multipleDocumentHandling;
    }

    /**
     * Specifies the handling of multiple documents, including collation, for
     * jobs using these attributes. Not specifying this attribute is equivalent
     * to specifying
     * MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES.
     *
     * @param	multipleDocumentHandling
     *     MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES or
     *     MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES.
     * @throws	IllegalArgumentException if multipleDocumentHandling is null.
     */
    public void setMultipleDocumentHandling(MultipleDocumentHandlingType
					    multipleDocumentHandling) {
        if (multipleDocumentHandling == null) {
	    throw new IllegalArgumentException("Invalid value for attribute "+
					       "multipleDocumentHandling");
	}
        this.multipleDocumentHandling = multipleDocumentHandling;
    }

    /**
     * Sets the handling of multiple documents, including collation, for jobs
     * using these attributes to the default. The default handling is
     * MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES.
     */
    public void setMultipleDocumentHandlingToDefault() {
        setMultipleDocumentHandling(
            MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES);
    }

    /**
     * Specifies, for jobs using these attributes, the ranges of pages to be
     * printed, if a range of pages is to be printed. All range numbers are
     * inclusive. This attribute is updated to the value chosen by the user.
     * An application should ignore this attribute on output, unless the
     * return value of the &lt;code&gt;getDefaultSelection&lt;/code&gt; method is
     * DefaultSelectionType.RANGE.
     *
     * @return	an array of integer arrays of 2 elements. An array
     *		is interpreted as a range spanning all pages including and
     *		between the specified pages. Ranges must be in ascending
     *		order and must not overlap. Specified page numbers cannot be
     *		less than &lt;i&gt;minPage&lt;/i&gt; nor greater than &lt;i&gt;maxPage&lt;/i&gt;.
     *		For example:
     *		(new int[][] { new int[] { 1, 3 }, new int[] { 5, 5 },
     *		               new int[] { 15, 19 } }),
     *		specifies pages 1, 2, 3, 5, 15, 16, 17, 18, and 19.
     */
    public int[][] getPageRanges() {
        if (pageRanges != null) {
	    // Return a copy because otherwise client code could circumvent the
	    // the checks made in setPageRanges by modifying the returned
	    // array.
	    int[][] copy = new int[pageRanges.length][2];
	    for (int i = 0; i &lt; pageRanges.length; i++) {
		copy[i][0] = pageRanges[i][0];
		copy[i][1] = pageRanges[i][1];
	    }
	    return copy;
	} else if (fromPage != 0 || toPage != 0) {
	    int fromPage = getFromPage();
	    int toPage = getToPage();
	    return new int[][] { new int[] { fromPage, toPage } };
	} else {
	    int minPage = getMinPage();
	    return new int[][] { new int[] { minPage, minPage } };
	}
    }

    /**
     * Specifies, for jobs using these attributes, the ranges of pages to be
     * printed, if a range of pages is to be printed. All range numbers are
     * inclusive. If this attribute is not specified, then the values from the
     * fromPage and toPages attributes are used. If pageRanges and either or
     * both of fromPage and toPage are specified, pageRanges takes precedence.
     * Specifying none of pageRanges, fromPage, or toPage is equivalent to
     * calling setPageRanges(new int[][] { new int[] { &lt;i&gt;minPage&lt;/i&gt;, 
     *                                                 &lt;i&gt;minPage&lt;/i&gt; } });
     *
     * @param	pageRanges an array of integer arrays of 2 elements. An array
     *		is interpreted as a range spanning all pages including and
     *		between the specified pages. Ranges must be in ascending
     *		order and must not overlap. Specified page numbers cannot be
     *		less than &lt;i&gt;minPage&lt;/i&gt; nor greater than &lt;i&gt;maxPage&lt;/i&gt;.
     *		For example:
     *		(new int[][] { new int[] { 1, 3 }, new int[] { 5, 5 },
     *		               new int[] { 15, 19 } }),
     *		specifies pages 1, 2, 3, 5, 15, 16, 17, 18, and 19. Note that
     *		(new int[][] { new int[] { 1, 1 }, new int[] { 1, 2 } }),
     *		is an invalid set of page ranges because the two ranges
     *		overlap.
     * @throws	IllegalArgumentException if one or more of the above
     *		conditions is violated.
     */
    public void setPageRanges(int[][] pageRanges) {
        String xcp = "Invalid value for attribute pageRanges";
	int first = 0;
        int last = 0;

	if (pageRanges == null) {
	    throw new IllegalArgumentException(xcp);
	}

        for (int i = 0; i &lt; pageRanges.length; i++) {
	    if (pageRanges[i] == null ||
		pageRanges[i].length != 2 ||
		pageRanges[i][0] &lt;= last ||
		pageRanges[i][1] &lt; pageRanges[i][0]) {
	            throw new IllegalArgumentException(xcp);
	    }
	    last = pageRanges[i][1];
	    if (first == 0) {
	        first = pageRanges[i][0];
	    }
	}

	if (first &lt; minPage || last &gt; maxPage) {
	    throw new IllegalArgumentException(xcp);
	}

        // Store a copy because otherwise client code could circumvent the
        // the checks made above by holding a reference to the array and
	// modifying it after calling setPageRanges.
        int[][] copy = new int[pageRanges.length][2];
	for (int i = 0; i &lt; pageRanges.length; i++) {
	    copy[i][0] = pageRanges[i][0];
	    copy[i][1] = pageRanges[i][1];
	}
	this.pageRanges = copy;
	this.prFirst = first;
	this.prLast = last;
    }

    /**
     * Returns the destination printer for jobs using these attributes. This
     * attribute is updated to the value chosen by the user.
     *
     * @return	the possibly null printer name.
     */
    public String getPrinter() {
        return printer;
    }

    /**
     * Specifies the destination printer for jobs using these attributes.
     * Default is platform-dependent and implementation-defined.
     *
     * @param	printer the possibly null printer name.
     */
    public void setPrinter(String printer) {
        this.printer = printer;
    }

    /**
     * Returns how consecutive pages should be imposed upon the sides of the
     * print medium for jobs using these attributes. SidesType.ONE_SIDED
     * imposes each consecutive page upon the same side of consecutive media
     * sheets. This imposition is sometimes called &lt;i&gt;simplex&lt;/i&gt;.
     * SidesType.TWO_SIDED_LONG_EDGE imposes each consecutive pair of pages
     * upon front and back sides of consecutive media sheets, such that the
     * orientation of each pair of pages on the medium would be correct for
     * the reader as if for binding on the long edge. This imposition is
     * sometimes called &lt;i&gt;duplex&lt;/i&gt;. SidesType.TWO_SIDED_SHORT_EDGE imposes
     * each consecutive pair of pages upon front and back sides of consecutive
     * media sheets, such that the orientation of each pair of pages on the
     * medium would be correct for the reader as if for binding on the short
     * edge. This imposition is sometimes called &lt;i&gt;tumble&lt;/i&gt;. This attribute
     * is updated to the value chosen by the user.
     *
     * @return	SidesType.ONE_SIDED, SidesType.TWO_SIDED_LONG_EDGE, or
     *		SidesType.TWO_SIDED_SHORT_EDGE.
     */
    public SidesType getSides() {
        return sides;
    }

    /**
     * Specifies how consecutive pages should be imposed upon the sides of the
     * print medium for jobs using these attributes. SidesType.ONE_SIDED
     * imposes each consecutive page upon the same side of consecutive media
     * sheets. This imposition is sometimes called &lt;i&gt;simplex&lt;/i&gt;.
     * SidesType.TWO_SIDED_LONG_EDGE imposes each consecutive pair of pages
     * upon front and back sides of consecutive media sheets, such that the
     * orientation of each pair of pages on the medium would be correct for
     * the reader as if for binding on the long edge. This imposition is
     * sometimes called &lt;i&gt;duplex&lt;/i&gt;. SidesType.TWO_SIDED_SHORT_EDGE imposes
     * each consecutive pair of pages upon front and back sides of consecutive
     * media sheets, such that the orientation of each pair of pages on the
     * medium would be correct for the reader as if for binding on the short
     * edge. This imposition is sometimes called &lt;i&gt;tumble&lt;/i&gt;. Not specifying
     * this attribute is equivalent to specifying SidesType.ONE_SIDED.
     *
     * @param	sides SidesType.ONE_SIDED, SidesType.TWO_SIDED_LONG_EDGE, or
     *		SidesType.TWO_SIDED_SHORT_EDGE.
     * @throws	IllegalArgumentException if sides is null.
     */
    public void setSides(SidesType sides) {
        if (sides == null) {
	    throw new IllegalArgumentException("Invalid value for attribute "+
					       "sides");
	}
        this.sides = sides;
    }

    /**
     * Sets how consecutive pages should be imposed upon the sides of the
     * print medium for jobs using these attributes to the default. The
     * default imposition is SidesType.ONE_SIDED.
     */
    public void setSidesToDefault() {
        setSides(SidesType.ONE_SIDED);
    }

    /**
     * Returns, for jobs using these attributes, the last page (inclusive)
     * to be printed, if a range of pages is to be printed. This attribute is
     * updated to the value chosen by the user. An application should ignore
     * this attribute on output, unless the return value of the &lt;code&gt;
     * getDefaultSelection&lt;/code&gt; method is DefaultSelectionType.RANGE. An
     * application should honor the return value of &lt;code&gt;getPageRanges&lt;/code&gt;
     * over the return value of this method, if possible.
     *
     * @return	an integer greater than zero and greater than or equal
     *		to &lt;i&gt;toPage&lt;/i&gt; and greater than or equal to &lt;i&gt;minPage&lt;/i&gt;
     *		and less than or equal to &lt;i&gt;maxPage&lt;/i&gt;.
     */
    public int getToPage() {
        if (toPage != 0) {
	    return toPage;
	} else if (fromPage != 0) {
	    return fromPage;
	} else if (pageRanges != null) {
	    return prLast;
	} else {
	    return getMinPage();
	}
    }

    /**
     * Specifies, for jobs using these attributes, the last page (inclusive)
     * to be printed, if a range of pages is to be printed.
     * If this attribute is not specified, then the values from the pageRanges
     * attribute are used. If pageRanges and either or both of fromPage and
     * toPage are specified, pageRanges takes precedence. Specifying none of
     * pageRanges, fromPage, or toPage is equivalent to calling
     * setPageRanges(new int[][] { new int[] { &lt;i&gt;minPage&lt;/i&gt; } });
     *
     * @param	toPage an integer greater than zero and greater than or equal
     *		to &lt;i&gt;fromPage&lt;/i&gt; and greater than or equal to &lt;i&gt;minPage&lt;/i&gt;
     *		and less than or equal to &lt;i&gt;maxPage&lt;/i&gt;.
     * @throws	IllegalArgumentException if one or more of the above
     *		conditions is violated.
     */
    public void setToPage(int toPage) {
        if (toPage &lt;= 0 ||
	    (fromPage != 0 &amp;&amp; toPage &lt; fromPage) ||
	    toPage &lt; minPage ||
	    toPage &gt; maxPage) {
	    throw new IllegalArgumentException("Invalid value for attribute "+
					       "toPage");
	}
	this.toPage = toPage;
    }

    /**
     * Determines whether two JobAttributes are equal to each other.
     * &lt;p&gt;
     * Two JobAttributes are equal if and only if each of their attributes are
     * equal. Attributes of enumeration type are equal if and only if the
     * fields refer to the same unique enumeration object. A set of page
     * ranges is equal if and only if the sets are of equal length, each range
     * enumerates the same pages, and the ranges are in the same order.
     *
     * @param	obj the object whose equality will be checked.
     * @return	whether obj is equal to this JobAttribute according to the
     *		above criteria.
     */
    public boolean equals(Object obj) {
        if (!(obj instanceof JobAttributes)) {
	    return false;
	}
	JobAttributes rhs = (JobAttributes)obj;

	if (fileName == null) {
	    if (rhs.fileName != null) {
	        return false;
	    }
	} else {
	    if (!fileName.equals(rhs.fileName)) {
	        return false;
	    }
	}

	if (pageRanges == null) {
	    if (rhs.pageRanges != null) {
	        return false;
	    }
	} else {
	    if (rhs.pageRanges == null ||
		    pageRanges.length != rhs.pageRanges.length) {
	        return false;
	    }
	    for (int i = 0; i &lt; pageRanges.length; i++) {
	        if (pageRanges[i][0] != rhs.pageRanges[i][0] ||
		    pageRanges[i][1] != rhs.pageRanges[i][1]) {
		    return false;
		}
	    }
	}

	if (printer == null) {
	    if (rhs.printer != null) {
	        return false;
	    }
	} else {
	    if (!printer.equals(rhs.printer)) {
	        return false;
	    }
	}

	return (copies == rhs.copies &amp;&amp;
		defaultSelection == rhs.defaultSelection &amp;&amp;
		destination == rhs.destination &amp;&amp;
		dialog == rhs.dialog &amp;&amp;
		fromPage == rhs.fromPage &amp;&amp;
		maxPage == rhs.maxPage &amp;&amp;
		minPage == rhs.minPage &amp;&amp;
		multipleDocumentHandling == rhs.multipleDocumentHandling &amp;&amp;
		prFirst == rhs.prFirst &amp;&amp;
		prLast == rhs.prLast &amp;&amp;
		sides == rhs.sides &amp;&amp;
		toPage == rhs.toPage);
    }

    /**
     * Returns a hash code value for this JobAttributes.
     *
     * @return	the hash code.
     */
    public int hashCode() {
	int rest = ((copies + fromPage + maxPage + minPage + prFirst + prLast +
		     toPage) * 31) &lt;&lt; 21;
	if (pageRanges != null) {
	    int sum = 0;
	    for (int i = 0; i &lt; pageRanges.length; i++) {
	        sum += pageRanges[i][0] + pageRanges[i][1];
	    }
	    rest ^= (sum * 31) &lt;&lt; 11;
	}
	if (fileName != null) {
	    rest ^= fileName.hashCode();
	}
	if (printer != null) {
	    rest ^= printer.hashCode();
	}
	return (defaultSelection.hashCode() &lt;&lt; 6 ^
		destination.hashCode() &lt;&lt; 5 ^
		dialog.hashCode() &lt;&lt; 3 ^
		multipleDocumentHandling.hashCode() &lt;&lt; 2 ^
		sides.hashCode() ^
		rest);
    }

    /**
     * Returns a string representation of this JobAttributes.
     *
     * @return	the string representation.
     */
    public String toString() {
        int[][] pageRanges = getPageRanges();
	String prStr = "[";
	boolean first = true;
	for (int i = 0; i &lt; pageRanges.length; i++) {
	    if (first) {
	        first = false;
	    } else {
	        prStr += ",";
	    }
	    prStr += pageRanges[i][0] + ":" + pageRanges[i][1];
	}
	prStr += "]";

        return "copies=" + getCopies() + ",defaultSelection=" + 
	    getDefaultSelection() + ",destination=" + getDestination() +
	    ",dialog=" + getDialog() + ",fileName=" + getFileName() +
	    ",fromPage=" + getFromPage() + ",maxPage=" + getMaxPage() +
	    ",minPage=" + getMinPage() + ",multiple-document-handling=" +
	    getMultipleDocumentHandling() + ",page-ranges=" + prStr +
	    ",printer=" + getPrinter() + ",sides=" + getSides() + ",toPage=" +
	    getToPage();
    }
}
</pre></body></html>