| /* | |
| * Copyright (c) 2005, 2024, 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 | |
| * <p> | |
| * Methods of these class are thread safe, although most Swing methods | |
| * are not. Please see | |
| * <A HREF="https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html">Concurrency | |
| * in Swing</A> 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 <code>Component</code> object to be used | |
| * as parent component for PrintingStatus dialog | |
| * @param job a <code>PrinterJob</code> object to be cancelled | |
| * using this <code>PrintingStatus</code> dialog | |
| * @return a <code>PrintingStatus</code> 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 <code>dispose()</code> was called otherwise returns immediately | |
| * | |
| * @param isModal <code>true</code> this dialog should be modal; | |
| * <code>false</code> 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 printing was aborted using this PrintingStatus | |
| * | |
| * @return whether the printing 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 <code>printable</code> is <code>null</code> | |
| */ | |
| 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[]{ | |
| 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; | |
| } | |
| } |