/* * Copyright (c) 2005, 2013, 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.swing; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.text.MessageFormat; import java.util.concurrent.atomic.AtomicBoolean; import java.lang.reflect.InvocationTargetException; /** * The {@code PrintingStatus} provides a dialog that displays progress * of the printing job and provides a way to abort it *

* Methods of these class are thread safe, although most Swing methods * are not. Please see * Concurrency * in Swing for more information. * * @author Alexander Potochkin * @since 1.6 */ public class PrintingStatus { private final PrinterJob job; private final Component parent; private JDialog abortDialog; private JButton abortButton; private JLabel statusLabel; private MessageFormat statusFormat; private final AtomicBoolean isAborted = new AtomicBoolean(false); // the action that will abort printing private final Action abortAction = new AbstractAction() { public void actionPerformed(ActionEvent ae) { if (!isAborted.get()) { isAborted.set(true); // update the status abortDialog to indicate aborting abortButton.setEnabled(false); abortDialog.setTitle( UIManager.getString("PrintingDialog.titleAbortingText")); statusLabel.setText( UIManager.getString("PrintingDialog.contentAbortingText")); // cancel the PrinterJob job.cancel(); } } }; private final WindowAdapter closeListener = new WindowAdapter() { public void windowClosing(WindowEvent we) { abortAction.actionPerformed(null); } }; /** * Creates PrintingStatus instance * * @param parent a Component object to be used * as parent component for PrintingStatus dialog * @param job a PrinterJob object to be cancelled * using this PrintingStatus dialog * @return a PrintingStatus object */ public static PrintingStatus createPrintingStatus(Component parent, PrinterJob job) { return new PrintingStatus(parent, job); } protected PrintingStatus(Component parent, PrinterJob job) { this.job = job; this.parent = parent; } private void init() { // prepare the status JOptionPane String progressTitle = UIManager.getString("PrintingDialog.titleProgressText"); String dialogInitialContent = UIManager.getString("PrintingDialog.contentInitialText"); // this one's a MessageFormat since it must include the page // number in its text statusFormat = new MessageFormat( UIManager.getString("PrintingDialog.contentProgressText")); String abortText = UIManager.getString("PrintingDialog.abortButtonText"); String abortTooltip = UIManager.getString("PrintingDialog.abortButtonToolTipText"); int abortMnemonic = getInt("PrintingDialog.abortButtonMnemonic", -1); int abortMnemonicIndex = getInt("PrintingDialog.abortButtonDisplayedMnemonicIndex", -1); abortButton = new JButton(abortText); abortButton.addActionListener(abortAction); abortButton.setToolTipText(abortTooltip); if (abortMnemonic != -1) { abortButton.setMnemonic(abortMnemonic); } if (abortMnemonicIndex != -1) { abortButton.setDisplayedMnemonicIndex(abortMnemonicIndex); } statusLabel = new JLabel(dialogInitialContent); JOptionPane abortPane = new JOptionPane(statusLabel, JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION, null, new Object[]{abortButton}, abortButton); abortPane.getActionMap().put("close", abortAction); // The dialog should be centered over the viewport if the table is in one if (parent != null && parent.getParent() instanceof JViewport) { abortDialog = abortPane.createDialog(parent.getParent(), progressTitle); } else { abortDialog = abortPane.createDialog(parent, progressTitle); } // clicking the X button should not hide the dialog abortDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); abortDialog.addWindowListener(closeListener); } /** * Shows PrintingStatus dialog. * if dialog is modal this method returns only * after dispose() was called otherwise returns immediately * * @param isModal true this dialog should be modal; * false otherwise. * @see #dispose */ public void showModal(final boolean isModal) { if (SwingUtilities.isEventDispatchThread()) { showModalOnEDT(isModal); } else { try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { showModalOnEDT(isModal); } }); } catch(InterruptedException e) { throw new RuntimeException(e); } catch(InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } else { throw new RuntimeException(cause); } } } } /** * The EDT part of the showModal method. * * This method is to be called on the EDT only. */ private void showModalOnEDT(boolean isModal) { assert SwingUtilities.isEventDispatchThread(); init(); abortDialog.setModal(isModal); abortDialog.setVisible(true); } /** * Disposes modal PrintingStatus dialog * * @see #showModal(boolean) */ public void dispose() { if (SwingUtilities.isEventDispatchThread()) { disposeOnEDT(); } else { SwingUtilities.invokeLater(new Runnable() { public void run() { disposeOnEDT(); } }); } } /** * The EDT part of the dispose method. * * This method is to be called on the EDT only. */ private void disposeOnEDT() { assert SwingUtilities.isEventDispatchThread(); if (abortDialog != null) { abortDialog.removeWindowListener(closeListener); abortDialog.dispose(); abortDialog = null; } } /** * Returns whether the printng was aborted using this PrintingStatus * * @return whether the printng was aborted using this PrintingStatus */ public boolean isAborted() { return isAborted.get(); } /** * Returns printable which is used to track the current page being * printed in this PrintingStatus * * @param printable to be used to create notification printable * @return printable which is used to track the current page being * printed in this PrintingStatus * @throws NullPointerException if printable is null */ public Printable createNotificationPrintable(Printable printable) { return new NotificationPrintable(printable); } private class NotificationPrintable implements Printable { private final Printable printDelegatee; public NotificationPrintable(Printable delegatee) { if (delegatee == null) { throw new NullPointerException("Printable is null"); } this.printDelegatee = delegatee; } public int print(final Graphics graphics, final PageFormat pageFormat, final int pageIndex) throws PrinterException { final int retVal = printDelegatee.print(graphics, pageFormat, pageIndex); if (retVal != NO_SUCH_PAGE && !isAborted()) { if (SwingUtilities.isEventDispatchThread()) { updateStatusOnEDT(pageIndex); } else { SwingUtilities.invokeLater(new Runnable() { public void run() { updateStatusOnEDT(pageIndex); } }); } } return retVal; } /** * The EDT part of the print method. * * This method is to be called on the EDT only. */ private void updateStatusOnEDT(int pageIndex) { assert SwingUtilities.isEventDispatchThread(); Object[] pageNumber = new Object[]{ new Integer(pageIndex + 1)}; statusLabel.setText(statusFormat.format(pageNumber)); } } /** * Duplicated from UIManager to make it visible */ static int getInt(Object key, int defaultValue) { Object value = UIManager.get(key); if (value instanceof Integer) { return ((Integer) value).intValue(); } if (value instanceof String) { try { return Integer.parseInt((String) value); } catch(NumberFormatException nfe) { } } return defaultValue; } }