diff --git a/src/main/java/com/itextpdf/rups/model/ErrorDialogPane.java b/src/main/java/com/itextpdf/rups/model/ErrorDialogPane.java index 16b82522..1e65e4b4 100644 --- a/src/main/java/com/itextpdf/rups/model/ErrorDialogPane.java +++ b/src/main/java/com/itextpdf/rups/model/ErrorDialogPane.java @@ -42,6 +42,13 @@ This file is part of the iText (R) project. */ package com.itextpdf.rups.model; +import java.awt.Dialog; +import java.awt.GraphicsConfiguration; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.HierarchyEvent; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextArea; @@ -49,12 +56,14 @@ This file is part of the iText (R) project. import java.awt.Dimension; import java.io.PrintWriter; import java.io.StringWriter; +import javax.swing.SwingUtilities; /** * A utility to display a dialog showing Throwable object */ public final class ErrorDialogPane { - private static final Dimension DIALOG_PREFERRED_SIZE = new Dimension(300, 200); + private static final int DEFAULT_DOUBLED_MARGIN = 100; + private static final int FALLBACK_MAX_SIZE_DIM = 200; private ErrorDialogPane() { // do not instantiate @@ -64,10 +73,73 @@ public static void showErrorDialog(Component parent, Throwable th) { final String msg = getTraceString(th); final JTextArea textArea = new JTextArea(msg); final JScrollPane scrollPane = new JScrollPane(textArea); - scrollPane.setPreferredSize(DIALOG_PREFERRED_SIZE); + /* + * Update the dialog, created by JOptionPane, using the HierarchyListener. + * Taken from https://stackoverflow.com/a/7989417/6564861 and the linked blog post + * (which was cached in Wayback Machine). + */ + scrollPane.addHierarchyListener(ErrorDialogPane::tweakDialogSize); JOptionPane.showMessageDialog(parent, scrollPane); } + private static void tweakDialogSize(HierarchyEvent e) { + final Window window = SwingUtilities.getWindowAncestor(e.getComponent()); + // We are fishing for JOptionPane dialog... + if (!(window instanceof Dialog)) { + return; + } + Dialog dialog = (Dialog) window; + /* + * If dialog was set to resizeable, then this handler was already + * called for the dialog. So no reason to change sizes again. + */ + if (dialog.isResizable()) { + return; + } + dialog.setResizable(true); + limitDialogSize(dialog); + } + + /** + * Limits the preferred size of the window based on the linked graphics + * configuration. + * + * @param window Window to update. + */ + private static void limitDialogSize(Window window) { + final GraphicsConfiguration gc = window.getGraphicsConfiguration(); + if (gc == null) { + return; + } + final Rectangle bounds = gc.getBounds(); + final Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc); + final int gcMaxWidth = Math.max( + FALLBACK_MAX_SIZE_DIM, + bounds.width - insets.left - insets.right - DEFAULT_DOUBLED_MARGIN + ); + final int gcMaxHeight = Math.max( + FALLBACK_MAX_SIZE_DIM, + bounds.height - insets.top - insets.bottom - DEFAULT_DOUBLED_MARGIN + ); + final Dimension currentSize = window.getPreferredSize(); + boolean sizeModified = false; + if (currentSize.width > gcMaxWidth) { + currentSize.width = gcMaxWidth; + sizeModified = true; + } + if (currentSize.height > gcMaxHeight) { + currentSize.height = gcMaxHeight; + sizeModified = true; + } + /* + * We should call setPreferredSize only when we actually change the + * size. As it might be calculated dynamically, if not set explicitly. + */ + if (sizeModified) { + window.setPreferredSize(currentSize); + } + } + private static String getTraceString(Throwable th) { final StringWriter sw = new StringWriter(); final PrintWriter pw = new PrintWriter(sw); diff --git a/src/main/java/com/itextpdf/rups/model/IProgressDialog.java b/src/main/java/com/itextpdf/rups/model/IProgressDialog.java index 1a558bef..b7b2df38 100644 --- a/src/main/java/com/itextpdf/rups/model/IProgressDialog.java +++ b/src/main/java/com/itextpdf/rups/model/IProgressDialog.java @@ -69,11 +69,11 @@ public interface IProgressDialog { void setTotal(int n); /** - * Displays an error dialog for the given exception. + * Displays an error dialog for the given throwable. * - * @param ex exception to display information about + * @param th throwable to display information about */ - void showErrorDialog(Exception ex); + void showErrorDialog(Throwable th); /** * Control the visibility of the progress dialog. diff --git a/src/main/java/com/itextpdf/rups/model/LoggerHelper.java b/src/main/java/com/itextpdf/rups/model/LoggerHelper.java index 2f8f3da1..034d9cf8 100644 --- a/src/main/java/com/itextpdf/rups/model/LoggerHelper.java +++ b/src/main/java/com/itextpdf/rups/model/LoggerHelper.java @@ -52,10 +52,10 @@ private LoggerHelper() { // static class } - public static void warn(String message, Exception e, String className) { + public static void warn(String message, Throwable th, String className) { final Logger logger = LoggerFactory.getLogger(className); logger.warn(message); - logger.debug(message, e); + logger.debug(message, th); } public static void warn(String message, String className) { @@ -64,8 +64,8 @@ public static void warn(String message, String className) { logger.debug(message); } - public static void warn(String message, Exception e, Class c) { - warn(message, e, c.getName()); + public static void warn(String message, Throwable th, Class c) { + warn(message, th, c.getName()); } public static void warn(String message, Class c) { @@ -80,10 +80,10 @@ public static void warnf(Language format, Class c, Object... args) { warnf(format.getString(), c, args); } - public static void error(String message, Exception e, String className) { + public static void error(String message, Throwable th, String className) { final Logger logger = LoggerFactory.getLogger(className); logger.error(message); - logger.debug(message, e); + logger.debug(message, th); } public static void error(String message, String className) { @@ -92,8 +92,8 @@ public static void error(String message, String className) { logger.debug(message); } - public static void error(String message, Exception e, Class c) { - error(message, e, c.getName()); + public static void error(String message, Throwable th, Class c) { + error(message, th, c.getName()); } public static void error(String message, Class c) { @@ -110,12 +110,12 @@ public static void info(String message, Class c) { info(message, c.getName()); } - public static void debug(String message, Exception e, String className) { - LoggerFactory.getLogger(className).debug(message, e); + public static void debug(String message, Throwable th, String className) { + LoggerFactory.getLogger(className).debug(message, th); } - public static void debug(String message, Exception e, Class c) { - debug(message, e, c.getName()); + public static void debug(String message, Throwable th, Class c) { + debug(message, th, c.getName()); } public static void debug(String message, String className) { diff --git a/src/main/java/com/itextpdf/rups/model/ObjectLoader.java b/src/main/java/com/itextpdf/rups/model/ObjectLoader.java index 1eb41208..8f496bfe 100644 --- a/src/main/java/com/itextpdf/rups/model/ObjectLoader.java +++ b/src/main/java/com/itextpdf/rups/model/ObjectLoader.java @@ -44,29 +44,32 @@ This file is part of the iText (R) project. import com.itextpdf.rups.view.Language; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; /** * Loads the necessary iText PDF objects in Background. */ -public class ObjectLoader extends SwingWorker { +public final class ObjectLoader extends SwingWorker { /** * This is the object that wait for task to complete. */ - protected IRupsEventListener eventListener; + private final IRupsEventListener eventListener; /** * RUPS's PdfFile object. */ - protected IPdfFile file; + private final IPdfFile file; /** * The factory that can provide PDF objects. */ - protected IndirectObjectFactory objects; + private IndirectObjectFactory objects; /** * The factory that can provide tree nodes. */ - protected TreeNodeFactory nodes; + private TreeNodeFactory nodes; /** * a human readable name for this loaded */ @@ -145,12 +148,47 @@ protected Void doInBackground() { @Override protected void done() { + if (handleTaskException()) { + return; + } try { eventListener.handleOpenDocument(this); + SwingUtilities.invokeLater(() -> progress.setVisible(false)); } catch (RuntimeException ex) { - progress.showErrorDialog(ex); - LoggerHelper.error(ex.getLocalizedMessage(), ex, getClass()); + displayThrowable(ex); + } + } + + private boolean handleTaskException() { + try { + // This will throw an ExecutionException, if doInBackground + // threw an exception + get(0L, TimeUnit.NANOSECONDS); + return false; + } catch (ExecutionException e) { + displayThrowable(e.getCause()); + clearResult(); + } catch (TimeoutException | RuntimeException e) { + // This should not happen in practice + displayThrowable(e); + clearResult(); + } catch (InterruptedException e) { + // This should not happen in practice + displayThrowable(e); + clearResult(); + Thread.currentThread().interrupt(); } - progress.setVisible(false); + return true; + } + + private void clearResult() { + objects = null; + nodes = null; + } + + private void displayThrowable(Throwable th) { + LoggerHelper.error(th.getLocalizedMessage(), th, getClass()); + progress.showErrorDialog(th); + SwingUtilities.invokeLater(() -> progress.setVisible(false)); } } diff --git a/src/main/java/com/itextpdf/rups/model/ProgressDialog.java b/src/main/java/com/itextpdf/rups/model/ProgressDialog.java index 1f1120a1..4d4c137c 100644 --- a/src/main/java/com/itextpdf/rups/model/ProgressDialog.java +++ b/src/main/java/com/itextpdf/rups/model/ProgressDialog.java @@ -158,12 +158,12 @@ public void setTotal(int n) { } /** - * Displays an error dialog for the given exception. + * Displays an error dialog for the given throwable. * - * @param ex exception to display information about + * @param th throwable to display information about */ @Override - public void showErrorDialog(Exception ex) { - ErrorDialogPane.showErrorDialog(this, ex); + public void showErrorDialog(Throwable th) { + ErrorDialogPane.showErrorDialog(this, th); } } diff --git a/src/test/java/com/itextpdf/rups/mock/NoopProgressDialog.java b/src/test/java/com/itextpdf/rups/mock/NoopProgressDialog.java index 2f554dd5..3e85262e 100644 --- a/src/test/java/com/itextpdf/rups/mock/NoopProgressDialog.java +++ b/src/test/java/com/itextpdf/rups/mock/NoopProgressDialog.java @@ -64,7 +64,7 @@ public void setTotal(int n) { } @Override - public void showErrorDialog(Exception ex) { + public void showErrorDialog(Throwable th) { // noop }