/* * Copyright (c) 2005-2016 Vincent Vandenschrick. All rights reserved. * * This file is part of the Jspresso framework. * * Jspresso is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Jspresso 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Jspresso. If not, see <http://www.gnu.org/licenses/>. */ package org.jspresso.framework.gui.swing.components; import java.awt.Component; import java.awt.Dialog; import java.awt.Dimension; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Window; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Locale; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JEditorPane; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.TransferHandler; import javax.swing.plaf.basic.BasicHTML; import org.jspresso.framework.util.i18n.ITranslationProvider; import org.jspresso.framework.util.swing.SwingUtil; /** * Dialog used for reporting detailed messages (and errors). * * @author Vincent Vandenschrick */ public final class JErrorDialog extends JDialog { private static final long serialVersionUID = -3122747783739141527L; private int collapsedHeight = 0; private JButton detailsButton; private JEditorPane detailsPane; private JPanel detailsPanel; private int expandedHeight = 0; private JLabel iconLabel; private Locale locale; private JEditorPane messagePane; private ITranslationProvider translationProvider; private JErrorDialog(Dialog owner) { super(owner, true); } private JErrorDialog(Frame owner) { super(owner, true); } /** * Factory method for error dialog. * * @param sourceComponent * one of the components inside the owning window. * @param translationProvider * the translationProvider for labels. * @param locale * the locale used. * @return the created error dialog instance. */ public static JErrorDialog createInstance(Component sourceComponent, ITranslationProvider translationProvider, Locale locale) { JErrorDialog errorDialog; Window window = SwingUtil.getVisibleWindow(sourceComponent); if (window instanceof Dialog) { errorDialog = new JErrorDialog((Dialog) window); } else { errorDialog = new JErrorDialog((Frame) window); } errorDialog.translationProvider = translationProvider; errorDialog.locale = locale; errorDialog.initGui(); return errorDialog; } /** * Set the details section of the error dialog. If the details are either null * or an empty string, then hide the detailsPane button and hide the detail * scroll pane. Otherwise, just set the detailsPane section. * * @param details * Details to be shown in the detail section of the dialog. This can * be null if you do not want to display the details section of the * dialog. */ public void setDetails(String details) { if (details == null || details.equals("")) { setDetailsVisible(false); detailsButton.setVisible(false); } else { this.detailsPane.setText(details); setDetailsVisible(false); detailsButton.setVisible(true); } } /** * Set the details section of the error dialog. If the details are either null * or an empty string, then hide the detailsPane button and hide the detail * scroll pane. Otherwise, just set the detailsPane section. * * @param details * Details to be shown in the detail section of the dialog. This can * be null if you do not want to display the details section of the * dialog. */ public void setDetails(Throwable details) { String exceptionAsDetails = null; if (details != null) { StringBuilder html = new StringBuilder("<html>"); html.append("<b>").append(translationProvider.getTranslation("details", locale)).append(" :</b>"); html.append("<pre>"); html.append(" ").append(details.getMessage()); html.append("</pre>"); html.append("<div></div>"); html.append("<b>").append(translationProvider.getTranslation("stacktrace", locale)).append(" :</b>"); html.append("<pre>"); for (StackTraceElement el : details.getStackTrace()) { html.append(" ").append(el.toString()).append("\n"); } html.append("</pre></html>"); exceptionAsDetails = html.toString(); } setDetails(exceptionAsDetails); } /** * Set the error message for the dialog box. * * @param message * Message for the error dialog */ public void setMessage(String message) { if (BasicHTML.isHTMLString(message)) { this.messagePane.setContentType("text/html"); } else { this.messagePane.setContentType("text/plain"); } this.messagePane.setText(message); } /** * Specifies the icon to use. * * @param messageIcon * the Icon to use. If null, the default error icon will be used */ public void setMessageIcon(Icon messageIcon) { iconLabel.setIcon(messageIcon); } /** * initialize the gui. */ private void initGui() { // initialize the gui GridBagLayout layout = new GridBagLayout(); this.getContentPane().setLayout(layout); GridBagConstraints gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.NORTH; gbc.fill = GridBagConstraints.NONE; gbc.gridheight = 1; gbc.insets = new Insets(22, 12, 11, 17); iconLabel = new JLabel(); this.getContentPane().add(iconLabel, gbc); messagePane = new JEditorPane(); messagePane.setEditable(false); messagePane.setContentType("text/html"); messagePane.setOpaque(false); messagePane.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE); gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.LINE_START; gbc.fill = GridBagConstraints.BOTH; gbc.gridheight = 1; gbc.gridwidth = 2; gbc.gridx = 1; gbc.gridy = 0; gbc.weightx = 0.0; gbc.weighty = 0.00001; gbc.insets = new Insets(24, 0, 0, 11); this.getContentPane().add(messagePane, gbc); gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.NONE; gbc.gridx = 1; gbc.gridy = 1; gbc.gridwidth = 1; gbc.weightx = 1.0; gbc.weighty = 0.0; gbc.anchor = GridBagConstraints.LINE_END; gbc.insets = new Insets(12, 0, 11, 5); JButton okButton = new JButton(translationProvider.getTranslation("ok", locale)); this.getContentPane().add(okButton, gbc); detailsButton = new JButton(translationProvider.getTranslation("details", locale)); gbc = new GridBagConstraints(); gbc.gridx = 2; gbc.weightx = 0.0; gbc.insets = new Insets(12, 0, 11, 11); this.getContentPane().add(detailsButton, gbc); detailsPane = new JEditorPane(); detailsPane.setContentType("text/html"); detailsPane.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE); detailsPane.setTransferHandler(new DetailsTransferHandler()); JScrollPane detailsScrollPane = new JScrollPane(detailsPane); detailsScrollPane.setPreferredSize(new Dimension(10, 250)); detailsPane.setEditable(false); detailsPanel = new JPanel(new GridBagLayout()); detailsPanel.add(detailsScrollPane, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(6, 11, 11, 11), 0, 0)); gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.BOTH; gbc.gridwidth = 3; gbc.gridx = 0; gbc.gridy = 2; gbc.weightx = 1.0; gbc.weighty = 1.0; this.getContentPane().add(detailsPanel, gbc); JButton button = new JButton(translationProvider.getTranslation( "copy.name", locale)); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { detailsPane.copy(); } }); gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.LINE_END; gbc.fill = GridBagConstraints.NONE; gbc.gridwidth = 1; gbc.gridx = 0; gbc.gridy = 1; gbc.weighty = 0.0; gbc.weightx = 1.0; gbc.insets = new Insets(6, 11, 11, 11); detailsPanel.add(button, gbc); okButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setVisible(false); dispose(); } }); detailsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setDetailsVisible(!detailsPanel.isVisible()); } }); } /** * Set the detailsPane section to be either visible or invisible. Set the text * of the Details button accordingly. * * @param b * if true detailsPane section will be visible */ private void setDetailsVisible(boolean b) { if (b) { collapsedHeight = getHeight(); int height; if (expandedHeight == 0) { height = collapsedHeight + 300; } else { height = expandedHeight; } detailsPanel.setVisible(true); detailsButton.setText(translationProvider.getTranslation("details", locale) + "<<"); detailsPanel.applyComponentOrientation(detailsButton .getComponentOrientation()); detailsPane.setCaretPosition(0); setSize(getWidth(), height); } else { expandedHeight = getHeight(); detailsPanel.setVisible(false); detailsButton.setText(translationProvider.getTranslation("details", locale) + ">>"); messagePane.setSize(0, 0); messagePane.setSize(messagePane.getPreferredSize()); setSize(getWidth(), collapsedHeight); } invalidate(); repaint(); } private final class DetailsTransferHandler extends TransferHandler { private static final long serialVersionUID = -5398570598349570102L; /** * {@inheritDoc} */ @Override public int getSourceActions(JComponent c) { return TransferHandler.COPY; } /** * {@inheritDoc} */ @Override protected Transferable createTransferable(JComponent c) { String text = detailsPane.getSelectedText(); if (text == null || text.equals("")) { detailsPane.selectAll(); text = detailsPane.getSelectedText(); detailsPane.select(-1, -1); } return new StringSelection(text); } } }