001: /**
002: * ===========================================
003: * JFreeReport : a free Java reporting library
004: * ===========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * ExceptionDialog.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.modules.gui.commonswing;
030:
031: import java.awt.Color;
032: import java.awt.Dimension;
033: import java.awt.FlowLayout;
034: import java.awt.GridBagConstraints;
035: import java.awt.GridBagLayout;
036: import java.awt.event.ActionEvent;
037: import java.io.PrintWriter;
038: import javax.swing.AbstractAction;
039: import javax.swing.BorderFactory;
040: import javax.swing.JButton;
041: import javax.swing.JDialog;
042: import javax.swing.JLabel;
043: import javax.swing.JPanel;
044: import javax.swing.JScrollPane;
045: import javax.swing.JTextArea;
046: import javax.swing.UIManager;
047:
048: import org.jfree.report.util.MemoryStringWriter;
049: import org.jfree.report.util.i18n.Messages;
050: import org.jfree.ui.FloatingButtonEnabler;
051: import org.jfree.ui.action.ActionButton;
052: import org.jfree.util.Log;
053:
054: /**
055: * The exception dialog is used to display an exception and the exceptions stacktrace to
056: * the user.
057: *
058: * @author Thomas Morgner
059: */
060: public class ExceptionDialog extends JDialog {
061: /**
062: * OK action.
063: */
064: private final class OKAction extends AbstractAction {
065: /**
066: * Default constructor.
067: */
068: private OKAction() {
069: putValue(NAME, UIManager.getDefaults().getString(
070: "OptionPane.okButtonText")); //$NON-NLS-1$
071: }
072:
073: /**
074: * Receives notification that an action event has occurred.
075: *
076: * @param event the action event.
077: */
078: public void actionPerformed(final ActionEvent event) {
079: setVisible(false);
080: }
081: }
082:
083: /**
084: * Details action.
085: */
086: private final class DetailsAction extends AbstractAction {
087: /**
088: * Default constructor.
089: */
090: private DetailsAction() {
091: putValue(NAME, ">>"); //$NON-NLS-1$
092: }
093:
094: /**
095: * Receives notification that an action event has occurred.
096: *
097: * @param event the action event.
098: */
099: public void actionPerformed(final ActionEvent event) {
100: setScrollerVisible(!(isScrollerVisible()));
101: if (isScrollerVisible()) {
102: putValue(NAME, "<<"); //$NON-NLS-1$
103: } else {
104: putValue(NAME, ">>"); //$NON-NLS-1$
105: }
106: adjustSize();
107: }
108: }
109:
110: /**
111: * A UI component for displaying the stack trace.
112: */
113: private final JTextArea backtraceArea;
114:
115: /**
116: * A UI component for displaying the message.
117: */
118: private final JLabel messageLabel;
119:
120: /**
121: * The exception.
122: */
123: private Exception currentEx;
124:
125: /**
126: * An action associated with the 'Details' button.
127: */
128: private DetailsAction detailsAction;
129:
130: /**
131: * A scroll pane.
132: */
133: private final JScrollPane scroller;
134:
135: /**
136: * A filler panel.
137: */
138: private final JPanel filler;
139:
140: /**
141: * The default dialog.
142: */
143: private static ExceptionDialog defaultDialog;
144:
145: /**
146: * Localized message class
147: */
148: private Messages messages;
149:
150: /**
151: * Creates a new ExceptionDialog.
152: */
153: public ExceptionDialog() {
154: messages = new Messages(getLocale(),
155: SwingCommonModule.BUNDLE_NAME);
156: setModal(true);
157: detailsAction = new DetailsAction();
158:
159: messageLabel = new JLabel();
160: backtraceArea = new JTextArea();
161:
162: scroller = new JScrollPane(backtraceArea);
163: scroller.setVisible(false);
164:
165: final JPanel detailPane = new JPanel();
166: detailPane.setLayout(new GridBagLayout());
167: GridBagConstraints gbc = new GridBagConstraints();
168: gbc.anchor = GridBagConstraints.CENTER;
169: gbc.fill = GridBagConstraints.NONE;
170: gbc.weightx = 0;
171: gbc.weighty = 0;
172: gbc.gridx = 0;
173: gbc.gridy = 0;
174: final JLabel icon = new JLabel(UIManager.getDefaults().getIcon(
175: "OptionPane.errorIcon")); //$NON-NLS-1$
176: icon.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
177: detailPane.add(icon, gbc);
178:
179: gbc = new GridBagConstraints();
180: gbc.anchor = GridBagConstraints.WEST;
181: gbc.fill = GridBagConstraints.NONE;
182: gbc.weightx = 1;
183: gbc.weighty = 1;
184: gbc.gridx = 1;
185: gbc.gridy = 0;
186: detailPane.add(messageLabel);
187:
188: gbc = new GridBagConstraints();
189: gbc.anchor = GridBagConstraints.SOUTH;
190: gbc.fill = GridBagConstraints.HORIZONTAL;
191: gbc.weightx = 0;
192: gbc.weighty = 0;
193: gbc.gridx = 0;
194: gbc.gridy = 2;
195: gbc.gridwidth = 2;
196: detailPane.add(createButtonPane(), gbc);
197:
198: filler = new JPanel();
199: filler.setPreferredSize(new Dimension(0, 0));
200: filler.setBackground(Color.green);
201: gbc = new GridBagConstraints();
202: gbc.anchor = GridBagConstraints.NORTH;
203: gbc.fill = GridBagConstraints.HORIZONTAL;
204: gbc.weightx = 1;
205: gbc.weighty = 5;
206: gbc.gridx = 0;
207: gbc.gridy = 3;
208: gbc.gridwidth = 2;
209: detailPane.add(filler, gbc);
210:
211: gbc = new GridBagConstraints();
212: gbc.anchor = GridBagConstraints.SOUTHWEST;
213: gbc.fill = GridBagConstraints.BOTH;
214: gbc.weightx = 1;
215: gbc.weighty = 5;
216: gbc.gridx = 0;
217: gbc.gridy = 4;
218: gbc.gridwidth = 2;
219: detailPane.add(scroller, gbc);
220:
221: setContentPane(detailPane);
222: }
223:
224: /**
225: * Adjusts the size of the dialog to fit the with of the contained message and
226: * stacktrace.
227: */
228: public void adjustSize() {
229: final Dimension scSize = scroller.getPreferredSize();
230: final Dimension cbase = filler.getPreferredSize();
231: cbase.width = Math.max(scSize.width, cbase.width);
232: cbase.height = 0;
233: filler.setMinimumSize(cbase);
234: pack();
235:
236: }
237:
238: /**
239: * Defines, whether the scroll pane of the exception stack trace area is visible.
240: *
241: * @param b true, if the scroller should be visible, false otherwise.
242: */
243: protected void setScrollerVisible(final boolean b) {
244: scroller.setVisible(b);
245: }
246:
247: /**
248: * Checks, whether the scroll pane of the exception stack trace area is visible.
249: *
250: * @return true, if the scroller is visible, false otherwise.
251: */
252: protected boolean isScrollerVisible() {
253: return scroller.isVisible();
254: }
255:
256: /**
257: * Initializes the buttonpane.
258: *
259: * @return a panel containing the 'OK' and 'Details' buttons.
260: */
261: private JPanel createButtonPane() {
262: final JPanel buttonPane = new JPanel();
263: buttonPane.setLayout(new FlowLayout(2));
264: buttonPane.setBorder(BorderFactory
265: .createEmptyBorder(2, 2, 2, 2));
266: final OKAction okAction = new OKAction();
267:
268: final JButton ok = new ActionButton(okAction);
269: final JButton details = new ActionButton(detailsAction);
270:
271: FloatingButtonEnabler.getInstance().addButton(ok);
272: FloatingButtonEnabler.getInstance().addButton(details);
273:
274: buttonPane.add(ok);
275: buttonPane.add(details);
276: return buttonPane;
277: }
278:
279: /**
280: * Sets the message for this exception dialog. The message is displayed on the main
281: * page.
282: *
283: * @param mesg the message.
284: */
285: public void setMessage(final String mesg) {
286: messageLabel.setText(mesg);
287: }
288:
289: /**
290: * Returns the message for this exception dialog. The message is displayed on the main
291: * page.
292: *
293: * @return the message.
294: */
295: public String getMessage() {
296: return messageLabel.getText();
297: }
298:
299: /**
300: * Sets the exception for this dialog. If no exception is set, the "Detail" button is
301: * disabled and the stacktrace text cleared. Else the stacktraces text is read into the
302: * detail message area.
303: *
304: * @param e the exception.
305: */
306: public void setException(final Exception e) {
307: currentEx = e;
308: if (e == null) {
309: detailsAction.setEnabled(false);
310: backtraceArea.setText(""); //$NON-NLS-1$
311: } else {
312: backtraceArea.setText(readFromException(e));
313: }
314: }
315:
316: /**
317: * Reads the stacktrace text from the exception.
318: *
319: * @param e the exception.
320: * @return the stack trace.
321: * @noinspection IOResourceOpenedButNotSafelyClosed
322: */
323: private String readFromException(final Exception e) {
324: String text = messages
325: .getString("ExceptionDialog.USER_NO_BACKTRACE");//$NON-NLS-1$
326: try {
327: final MemoryStringWriter writer = new MemoryStringWriter();
328: final PrintWriter pwriter = new PrintWriter(writer);
329: e.printStackTrace(pwriter);
330: text = writer.toString();
331: pwriter.close();
332: } catch (Exception ex) {
333: Log
334: .info(messages
335: .getString("ExceptionDialog.INFO_EXCEPTION_SUPRESSED")); //$NON-NLS-1$
336: }
337: return text;
338: }
339:
340: /**
341: * Returns the exception that was the reason for this dialog to show up.
342: *
343: * @return the exception.
344: */
345: public Exception getException() {
346: return currentEx;
347: }
348:
349: /**
350: * Shows an default dialog with the given message and title and the exceptions
351: * stacktrace in the detail area.
352: *
353: * @param title the title.
354: * @param message the message.
355: * @param e the exception.
356: */
357: public static void showExceptionDialog(final String title,
358: final String message, final Exception e) {
359: if (defaultDialog == null) {
360: defaultDialog = new ExceptionDialog();
361: }
362: if (e != null) {
363: final Messages messages = new Messages(
364: SwingCommonModule.BUNDLE_NAME);
365: Log
366: .error(
367: messages
368: .getErrorString("ExceptionDialog.ERROR_0001_USER_ERROR"), e); //$NON-NLS-1$
369: }
370: defaultDialog.setTitle(title);
371: defaultDialog.setMessage(message);
372: defaultDialog.setException(e);
373: defaultDialog.adjustSize();
374: defaultDialog.setVisible(true);
375: }
376:
377: }
|