Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.print;
027
028import com.sun.javafx.print.PrintHelper;
029import javafx.beans.property.ReadOnlyObjectProperty;
030import javafx.beans.property.ReadOnlyObjectWrapper;
031import javafx.collections.ObservableSet;
032import javafx.geometry.Rectangle2D;
033
034import static javafx.print.PageOrientation.*;
035
036import com.sun.javafx.tk.PrintPipeline;
037import com.sun.javafx.print.PrinterImpl;
038
039/**
040 * A Printer instance represents the destination for a print job.
041 * <p>
042 * Printers may be enumerated and selected for use with a print job.
043 * <p>
044 * The configuration of the printer default settings are then used to
045 * populate the initial settings for a job.
046 * <p>
047 * Since the availability of printers may change during the
048 * execution of a program, due to administrative actions,
049 * a long running program which has cached a printer which
050 * has since been taken off-line, may create a job using that
051 * instance, but printing will fail.
052 *
053 * @since JavaFX 8
054 */
055public final class Printer {
056
057    /**
058     * Retrieve the installed printers.
059     * The set of printers may be dynamic.
060     * Consequently there is no guarantee that the result will be
061     * the same from call to call, but should change only as
062     * a result of the default changing in the environment of the
063     * application.
064     * <p>Note: since printers may be installed, but offline, then
065     * the application may want to query the status of a printer
066     * before using it.
067     * @return may be null if there are no printers.
068     * @throws SecurityException if the application does not
069     * have permission to browse printers.
070     */
071    public static ObservableSet<Printer> getAllPrinters() {
072        SecurityManager security = System.getSecurityManager();
073        if (security != null) {
074            security.checkPrintJobAccess();
075        }
076        return PrintPipeline.getPrintPipeline().getAllPrinters();
077    }
078
079    private static ReadOnlyObjectWrapper<Printer> defaultPrinter;
080
081    private static ReadOnlyObjectWrapper<Printer> defaultPrinterImpl() {
082        SecurityManager security = System.getSecurityManager();
083        if (security != null) {
084            security.checkPrintJobAccess();
085        }
086        if (defaultPrinter == null) {
087            Printer p = PrintPipeline.getPrintPipeline().getDefaultPrinter();
088            defaultPrinter =
089                new ReadOnlyObjectWrapper<Printer>(null, "defaultPrinter", p);
090        }
091        return defaultPrinter;
092    }
093
094    /**
095     * A read only object property representing the current default printer.
096     * If there are no installed printers, the wrapped value will be null.
097     * @throws SecurityException if the application does not
098     * have permission to browse printers.
099     */
100    public static ReadOnlyObjectProperty<Printer> defaultPrinterProperty() {
101        return defaultPrinterImpl().getReadOnlyProperty();
102    }
103
104    /**
105     * Retrieve the default printer.
106     * May return null if no printers are installed.
107     * <p>
108     * The configuration of available printers may be dynamic.
109     * Consequently there is no guarantee that the result will be
110     * the same from call to call, but should change only as
111     * a result of the default changing in the environment of the
112     * application.
113     * @return default printer or null.
114     * @throws SecurityException if the application does not
115     * have permission to browse printers.
116     */
117    public static Printer getDefaultPrinter() {
118        return defaultPrinterProperty().get();
119    }
120
121    private PrinterImpl impl;
122
123    Printer(PrinterImpl impl) {
124        this.impl = impl;
125        impl.setPrinter(this);
126    }
127
128    PrinterImpl getPrinterImpl() {
129        return impl;
130    }
131
132    /**
133     * Return the name used by the underlying system to identify
134     * the printer to users and/or applications.
135     * @return printer name.
136     */
137    public String getName() {
138        return impl.getName();
139    }
140
141    private PrinterAttributes attributes;
142    /**
143     * Retrieves the delegate object encapsulating the printer
144     * attributes and capabilities.
145     * @return printer attributes.
146     */
147    public PrinterAttributes getPrinterAttributes() {
148        if (attributes == null) {
149            attributes = new PrinterAttributes(impl);
150        }
151        return attributes;
152    }
153
154    /**
155     * Returns the default settings for this printer as would be
156     * used in setting up a job for this printer.
157     * <p>
158     * When a job is first created and associated with a printer,
159     * (typically the default printer), it acquires these default
160     * settings for that printer.
161     * This method always returns a new instance.
162     */
163    JobSettings getDefaultJobSettings() {
164        return impl.getDefaultJobSettings();
165    }
166
167    /**
168     * The MarginType is used to determine the printable area of a PageLayout.
169     * @since JavaFX 8
170     */
171    public static enum MarginType {
172        /**
173         * This requests a default 0.75 inch margin on all sides.
174         * This is considered to be a common default and is supported
175         * by all known printers. However this may be adjusted if the paper is
176         * too small, to ensure that the margins are not more than 50% of
177         * the smaller dimension. Applications that do expect to deal with
178         * such small media should likely be specifying the required margins
179         * explicitly.
180         * In the unlikely event the hardware margin is larger than 0.75"
181         * it will be adjusted to that same hardware minimum on all sides.
182         */
183        DEFAULT,
184        /**
185         * Request margins are set to be the smallest on each side that
186         * the hardware allows. This creates the greatest printable area
187         * but the margins may not be aesthetic if they are too small, or
188         * there is significant variation on the different sides of the
189         * paper.
190         * <p>
191         * This is is also useful for an application that wants to know
192         * this so it can construct a new PageLayout that fits within
193         * these margins.
194         */
195        HARDWARE_MINIMUM,
196        /**
197         * Choose the largest of the four hardware margins, and use that for
198         * all for margins, so that the margins are equal on all sides.
199         */
200        EQUAL,
201        /**
202         * Similar to <code>EQUAL</code>, but it chooses the larger of
203         * the left/right hardware margins and top/bottom hardware margins
204         * separately, so that the top and bottom margins are equal, and
205         * the left and right margins are equal.
206         */
207        EQUAL_OPPOSITES,
208
209    };
210
211    private PageLayout defPageLayout;
212    /**
213     * Return the default page layout for this printer.
214     * @return default page layout.
215     */
216    public PageLayout getDefaultPageLayout() {
217        if (defPageLayout == null) {
218            PrinterAttributes printerCaps = getPrinterAttributes();
219            defPageLayout =
220                createPageLayout(printerCaps.getDefaultPaper(),
221                                 printerCaps.getDefaultPageOrientation(),
222                                 MarginType.DEFAULT);
223        }
224        return defPageLayout;
225    }
226
227    /**
228     * Obtain a new PageLayout instance for this printer using the specified
229     * parameters.
230     * The paper should be one of the supported papers and
231     * the orientation should be a supported orientation.
232     * If the printer cannot support the layout as specified, it
233     * will adjust the returned layout to a supported configuration
234     * @param paper The paper to use
235     * @param orient The orientation to use
236     * @param mType the margin type to use
237     * @return PageLayout based on the specified parameters.
238     * @throws NullPointerException if any of the parameters are null.
239     */
240    public PageLayout createPageLayout(Paper paper, PageOrientation orient,
241                        MarginType mType) {
242
243        if (paper == null || orient == null || mType == null) {
244            throw new NullPointerException("Parameters cannot be null");
245        }
246
247        // TBD: Adjust paper to a supported one first.
248        Rectangle2D imgArea = impl.printableArea(paper);
249        double width = paper.getWidth() / 72.0;
250        double height = paper.getHeight() / 72.0;
251        double plm = imgArea.getMinX();
252        double ptm = imgArea.getMinY();
253        double prm = width - imgArea.getMaxX();
254        double pbm = height - imgArea.getMaxY();
255
256        switch (mType) {
257        case DEFAULT:
258            plm = (plm <= 0.75) ? 0.75 : plm;
259            prm = (prm <= 0.75) ? 0.75 : prm;
260            ptm = (ptm <= 0.75) ? 0.75 : ptm;
261            pbm = (pbm <= 0.75) ? 0.75 : pbm;
262            break;
263        case EQUAL: {
264            double maxH = (double)Math.max(plm, prm);
265            double maxV = (double)Math.max(ptm, pbm);
266            double maxM = (double)Math.max(maxH, maxV);
267            plm = prm = ptm = pbm = maxM;
268            break;
269        }
270        case EQUAL_OPPOSITES: {
271            double maxH = (double)Math.max(plm, prm);
272            double maxV = (double)Math.max(ptm, pbm);
273            plm = prm = maxH;
274            ptm = pbm = maxV;
275            break;
276        }
277        case HARDWARE_MINIMUM:
278        default: // Use hardware margins as is.
279            break;
280        }
281
282        double lm, rm, tm, bm;
283        // Now we gave the margins, they need to be adjusted into
284        // the orientation of the paper. If the orientation is not
285        // supported by the printer, then that needs to adjusted first.
286
287        // TBD: Adjust orient to a supported one first.
288        switch (orient) {
289        case LANDSCAPE: lm = pbm; rm = ptm; tm = plm; bm = prm;
290            break;
291        case REVERSE_LANDSCAPE: lm = ptm; rm = pbm; tm = prm; bm = plm;
292            break;
293        case REVERSE_PORTRAIT: lm = prm; rm = plm; tm = pbm; bm = ptm;
294            break;
295        default: lm = plm; rm = prm; tm = ptm; bm = pbm;
296        }
297        lm *= 72;
298        rm *= 72;
299        tm *= 72;
300        bm *= 72;
301        return new PageLayout(paper, orient, lm, rm, tm, bm);
302    }
303
304    /**
305     * Obtain a new PageLayout for this printer using the specified
306     * parameters.
307     * The paper should be one of the supported papers and
308     * the orientation should be a supported orientation.
309     * <p>
310     * Margin values are specified in 1/72 of an inch points.
311     * Margins will be validated against the printer supported margins,
312     * and adjusted if necessary. This method is generally useful to
313     * a client that wants margins that are different (eg wider)
314     * than the default margins, such as 1" at top and bottom and
315     * 0.5" to the left and right.
316     * <p>A client that needs to know what margin values are legal should first
317     * obtain a PageLayout using the <code>HARDWARE_MINIMUM</code> margins.
318     * <p>
319     * If the printer cannot support the layout as specified, it
320     * will adjust the returned layout to a supported configuration
321     * @param paper The paper to use
322     * @param orient The orientation to use
323     * @param lMargin the left margin to use in pts.
324     * @param rMargin the right margin to use in pts.
325     * @param tMargin the top margin to use in pts.
326     * @param bMargin the bottom margin to use in pts.
327     * @return PageLayout based on the specified parameters.
328     * @throws NullPointerException if paper or orient are null.
329     * @throws IllegalArgumentException if any of the margins values are
330     * less than zero.
331     */
332    public PageLayout createPageLayout(Paper paper, PageOrientation orient,
333                                       double lMargin, double rMargin,
334                                       double tMargin, double bMargin) {
335
336        if (paper == null || orient == null) {
337            throw new NullPointerException("Parameters cannot be null");
338        }
339        if (lMargin < 0 || rMargin < 0 || tMargin < 0 || bMargin < 0) {
340            throw new IllegalArgumentException("Margins must be >= 0");
341        }
342        // TBD: Adjust paper to a supported one first.
343        Rectangle2D imgArea = impl.printableArea(paper);
344        double width = paper.getWidth() / 72.0;
345        double height = paper.getHeight() / 72.0;
346        double plm = imgArea.getMinX();
347        double ptm = imgArea.getMinY();
348        double prm = width - imgArea.getMaxX();
349        double pbm = height - imgArea.getMaxY();
350
351        // Check if the requested margins exceed the paper and
352        // if they do, ignore them.
353        boolean useDefault = false;
354        if (orient == PORTRAIT || orient == REVERSE_PORTRAIT) {
355            if ((lMargin + rMargin > width) ||
356                (tMargin + bMargin > height)) {
357                useDefault = true;
358            }
359        } else {
360            if ((lMargin + rMargin > height) ||
361                (tMargin + bMargin > width)) {
362                useDefault = true;
363            }
364        }
365        if (useDefault) {
366            return createPageLayout(paper, orient, MarginType.DEFAULT);
367        }
368
369        double lm, rm, tm, bm;
370        // TBD: Adjust orient to a supported one first.
371        switch (orient) {
372        case LANDSCAPE: lm = pbm; rm = ptm; tm = plm; bm = prm;
373            break;
374        case REVERSE_LANDSCAPE: lm = ptm; rm = pbm; tm = prm; bm = plm;
375            break;
376        case REVERSE_PORTRAIT: lm = prm; rm = plm; tm = pbm; bm = ptm;
377            break;
378        default: lm = plm; rm = prm; tm = ptm; bm = pbm;
379        }
380
381        lm = (lMargin <= lm) ? lMargin : lm;
382        rm = (rMargin <= rm) ? rMargin : rm;
383        tm = (tMargin <= tm) ? tMargin : tm;
384        bm = (bMargin <= bm) ? bMargin : bm;
385
386        return new PageLayout(paper, orient, lm, rm, tm, bm);
387    }
388
389    @Override public String toString() {
390        return "Printer " + getName();
391    }
392
393    static {
394        // This is used by classes in different packages to get access to
395        // private and package private methods.
396        PrintHelper.setPrintAccessor(new PrintHelper.PrintAccessor() {
397
398            @Override
399            public PrintResolution createPrintResolution(int fr, int cfr) {
400                return new PrintResolution(fr, cfr);
401            }
402
403            @Override
404            public Paper createPaper(String paperName,
405                                     double paperWidth,
406                                     double paperHeight,
407                                     Paper.Units units) {
408                return new Paper(paperName, paperWidth, paperHeight, units);
409            }
410
411            @Override
412            public PaperSource createPaperSource(String name) {
413                return new PaperSource(name);
414            }
415
416            @Override
417            public JobSettings createJobSettings(Printer printer) {
418                return new JobSettings(printer);
419            }
420
421            /**
422             * PrintAccess is used so that implementation code outside this package
423             * package can construct printer instances using a non-visible API.
424             * We need this since its not valid for applications to create
425             * Printer instances, and we also need to pass in the delegate
426             * impl object which is not intended to be public.
427             */
428            @Override
429            public Printer createPrinter(PrinterImpl impl) {
430                return new Printer(impl);
431            }
432
433            @Override
434            public PrinterImpl getPrinterImpl(Printer printer) {
435                return printer.getPrinterImpl();
436            }
437        });
438    }
439}