Java tutorial
/******************************************************************************* * Copyright (c) 2001, 2006 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * yyyymmdd bug Email and other contact information * -------- -------- ----------------------------------------------------------- * 20060504 128984 pmoogk@ca.ibm.com - Peter Moogk *******************************************************************************/ package org.eclipse.wst.command.internal.env.ui.dialog; import java.util.Arrays; import java.util.Iterator; import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.List; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.PlatformUI; import org.eclipse.wst.command.internal.env.common.StringUtils; import org.eclipse.wst.common.environment.Choice; /** * A dialog to display one or more errors to the user, as contained in an * <code>Status</code> object. If an error contains additional detailed * information then a Details button is automatically supplied, which shows or * hides an error details viewer when pressed by the user. * */ public class MessageDialog extends Dialog { protected Composite parent; /** * Reserve room for this many list items. */ protected static final int LIST_ITEM_COUNT = 7; /** * The Details button. */ protected Button detailsButton; /** * The title of the dialog. */ protected String title; /** * The message to display. */ protected String message; /** * The SWT list control that displays the error details. */ protected List list; protected Text details; /** * Indicates whether the error details viewer is currently created. */ protected boolean listCreated = false; protected boolean detailsCreated = false; /** * Filter mask for determining which status items to display. */ protected int displayMask = 0xFFFF; /** * The main status object. */ protected IStatus status; private Point savedSize = null; /** * List of the main error object's detailed errors (element type: <code>Status</code>). */ protected java.util.List statusList; /** * Creates an error dialog. Note that the dialog will have no visual * representation (no widgets) until it is told to open. * <p> * Normally one should use <code>openError</code> to create and open one of * these. This constructor is useful only if the error object being displayed * contains child items <it>and</it> you need to specify a mask which will * be used to filter the displaying of these children. * </p> * * @param parentShell * the shell under which to create this dialog * @param dialogTitle * the title to use for this dialog, or <code>null</code> to * indicate that the default title should be used * @param message * the message to show in this dialog, or <code>null</code> to * indicate that the error's message should be shown as the * primary message * @param status * the error to show to the user * @param displayMask * the mask to use to filter the displaying of child items, as per * <code>Status.matches</code> */ public MessageDialog(Shell parentShell, String dialogTitle, String message, IStatus status, int displayMask) { super(parentShell); this.title = dialogTitle == null ? JFaceResources.getString("Problem_Occurred") : //$NON-NLS-1$ dialogTitle; this.message = message == null ? status.getMessage() : JFaceResources.format("Reason", new Object[] { message, status.getMessage() }); //$NON-NLS-1$ this.status = status; statusList = Arrays.asList(status.getChildren()); this.displayMask = displayMask; setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL); } /* * (non-Javadoc) Method declared on Dialog. Handles the pressing of the Ok or * Details button in this dialog. If the Ok button was pressed then close * this dialog. If the Details button was pressed then toggle the displaying * of the error details area. Note that the Details button will only be * visible if the error being displayed specifies child details. */ protected void buttonPressed(int id) { if (id == StatusDialogConstants.DETAILS_ID) { // was the details button pressed? toggleDetailsArea(); } else { super.buttonPressed(id); } } /* * (non-Javadoc) Method declared in Window. */ protected void configureShell(Shell shell) { super.configureShell(shell); shell.setText(title); } /* * (non-Javadoc) This should also be overwritten Method declared on Dialog. */ protected void createButtonsForButtonBar(Composite parent) { // create OK and Details buttons createButton(parent, StatusDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); if (status.isMultiStatus() || status.getException() != null) { detailsButton = createButton(parent, StatusDialogConstants.DETAILS_ID, IDialogConstants.SHOW_DETAILS_LABEL, false); } parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); } /* * This is one of the few methods that needs to be overwritten by the * subclasses. The image names can be found in the Dialog class */ protected Image getDialogImage() { // create image return PlatformUI.getWorkbench().getDisplay().getSystemImage(SWT.ICON_INFORMATION); } /* * (non-Javadoc) Method declared on Dialog. Creates and returns the contents * of the upper part of the dialog (above the button bar). */ protected Control createDialogArea(Composite parent) { this.parent = parent; // create composite Composite composite = (Composite) super.createDialogArea(parent); Composite imageAndLabel = new Composite(composite, SWT.NONE); GridLayout gl = new GridLayout(); gl.numColumns = 2; imageAndLabel.setLayout(gl); imageAndLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); // create image Image image = getDialogImage(); if (image != null) { Label label = new Label(imageAndLabel, 0); image.setBackground(label.getBackground()); label.setImage(image); label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER | GridData.VERTICAL_ALIGN_BEGINNING)); } // create message if (message != null) { Text text = new Text(imageAndLabel, SWT.READ_ONLY | SWT.WRAP); text.setText(message); GridData data = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER); data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH); text.setLayoutData(data); text.setFont(parent.getFont()); } return composite; } protected List createDropDownList(Composite parent) { // create the list list = new List(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); // fill the list populateList(list); GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL); data.heightHint = list.getItemHeight() * LIST_ITEM_COUNT; list.setLayoutData(data); listCreated = true; return list; } protected Text createDropDownDetails(Composite parent) { details = new Text(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.READ_ONLY | SWT.WRAP); //details.setEditable(false); Color color = parent.getShell().getDisplay().getSystemColor(SWT.COLOR_WHITE); details.setBackground(color); populateDetails(details, status, 0); GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL); details.setLayoutData(data); details.setSelection(0); detailsCreated = true; return details; } /* * (non-Javadoc) Method declared on Window. */ /** * Extends <code>Window.open()</code>. Opens an error dialog to display * the error. If you specified a mask to filter the displaying of these * children, the error dialog will only be displayed if there is at least one * child status matching the mask. */ public int open() { if (shouldDisplay(status, displayMask)) { return super.open(); } return 0; } /** * This essentially does the work of a factory Opens an error dialog to * display the given error. Use this method if the error object being * displayed does not contain child items, or if you wish to display all such * items without filtering. * * @param parent * the parent shell of the dialog, or <code>null</code> if none * @param dialogTitle * the title to use for this dialog, or <code>null</code> to * indicate that the default title should be used * @param message * the message to show in this dialog, or <code>null</code> to * indicate that the error's message should be shown as the * primary message * @param status * the error to show to the user * @return the code of the button that was pressed that resulted in this * dialog closing. This will be <code>Dialog.OK</code> if the OK * button was pressed, or <code>Dialog.CANCEL</code> if this * dialog's close window decoration or the ESC key was used. */ public static int openMessage(Shell parent, String dialogTitle, String message, IStatus status) { switch (status.getSeverity()) { case IStatus.INFO: return openInfo(parent, dialogTitle, message, status, IStatus.OK | IStatus.INFO | IStatus.WARNING | IStatus.ERROR); case IStatus.WARNING: return openWarning(parent, dialogTitle, message, status, IStatus.OK | IStatus.INFO | IStatus.WARNING | IStatus.ERROR); default: return openError(parent, dialogTitle, message, status, IStatus.OK | IStatus.INFO | IStatus.WARNING | IStatus.ERROR); } } public static int openMessage(Shell parent, String dialogTitle, String message, IStatus status, Choice[] options) { return openOptions(parent, dialogTitle, message, status, IStatus.OK | IStatus.INFO | IStatus.WARNING | IStatus.ERROR, options); } /** * Opens an error dialog to display the given error. Use this method if the * error object being displayed contains child items <it>and</it> you wish * to specify a mask which will be used to filter the displaying of these * children. The error dialog will only be displayed if there is at least one * child status matching the mask. * * @param parentShell * the parent shell of the dialog, or <code>null</code> if none * @param dialogTitle * the title to use for this dialog, or <code>null</code> to * indicate that the default title should be used * @param message * the message to show in this dialog, or <code>null</code> to * indicate that the error's message should be shown as the * primary message * @param status * the error to show to the user * @param displayMask * the mask to use to filter the displaying of child items, as per * <code>Status.matches</code> * @return the code of the button that was pressed that resulted in this * dialog closing. This will be <code>Dialog.OK</code> if the OK * button was pressed, or <code>Dialog.CANCEL</code> if this * dialog's close window decoration or the ESC key was used. */ public static int openError(Shell parentShell, String title, String message, IStatus status, int displayMask) { ErrorDialog dialog = new ErrorDialog(parentShell, title, message, status, displayMask); return dialog.open(); } public static int openInfo(Shell parentShell, String title, String message, IStatus status, int displayMask) { InfoDialog dialog = new InfoDialog(parentShell, title, message, status, displayMask); return dialog.open(); } public static int openWarning(Shell parentShell, String title, String message, IStatus status, int displayMask) { WarningDialog dialog = new WarningDialog(parentShell, title, message, status, displayMask); return dialog.open(); } public static int openOptions(Shell parentShell, String title, String message, IStatus status, int displayMask, Choice[] options) { OptionsDialog dialog = new OptionsDialog(parentShell, title, message, status, displayMask, options); dialog.open(); return dialog.getReturnCode(); } /** * Populates the list using this error dialog's status object. This walks the * child stati of the status object and displays them in a list. The format * for each entry is status_path : status_message If the status's path was * null then it (and the colon) are omitted. */ private void populateList(List list) { Iterator enumeration = statusList.iterator(); while (enumeration.hasNext()) { IStatus childStatus = (IStatus) enumeration.next(); populateList(list, childStatus, 0); } } private void populateList(List list, IStatus status, int nesting) { if (!status.matches(displayMask)) { return; } StringBuffer sb = new StringBuffer(); for (int i = 0; i < nesting; i++) { sb.append(" "); } sb.append(status.getMessage()); list.add(sb.toString()); IStatus[] children = status.getChildren(); for (int i = 0; i < children.length; i++) { populateList(list, children[i], nesting + 1); } } private void populateDetails(Text text, IStatus status, int nesting) { if (!status.matches(displayMask)) { return; } String tabChars = StringUtils.repeat(' ', nesting * 2); String messageLine = tabChars + status.getMessage() + System.getProperty("line.separator"); Throwable except = status.getException(); text.append(messageLine); if (except != null) { String[] trace = StringUtils.getStackTrace(except); for (int index = 0; index < trace.length; index++) { text.append(tabChars + " " + trace[index] + System.getProperty("line.separator")); } } IStatus[] children = status.getChildren(); for (int i = 0; i < children.length; i++) { populateDetails(text, children[i], nesting + 1); } } /** * Returns whether the given status object should be displayed. * * @param status * a status object * @param mask * a mask as per <code>Status.matches</code> * @return <code>true</code> if the given status should be displayed, and * <code>false</code> otherwise */ protected static boolean shouldDisplay(IStatus status, int mask) { IStatus[] children = status.getChildren(); if (children == null || children.length == 0) { return status.matches(mask); } for (int i = 0; i < children.length; i++) { if (children[i].matches(mask)) return true; } return false; } /** * Toggles the unfolding of the details area. This is triggered by the user * pressing the details button. */ private void toggleDetailsArea() { Point windowSize = getShell().getSize(); int newHeight = -1; if (detailsCreated) { details.dispose(); detailsCreated = false; detailsButton.setText(IDialogConstants.SHOW_DETAILS_LABEL); // Without the following computeSize call the setSize call below throws an array out of bounds exception. // Very weird. getContents().computeSize(SWT.DEFAULT, SWT.DEFAULT); newHeight = savedSize.y; } else { if (savedSize == null) savedSize = windowSize; details = createDropDownDetails((Composite) getContents()); detailsButton.setText(IDialogConstants.HIDE_DETAILS_LABEL); newHeight = getContents().computeSize(SWT.DEFAULT, SWT.DEFAULT).y; newHeight = newHeight < 250 ? 250 : newHeight; } newHeight = newHeight > 400 ? 400 : newHeight; getShell().setSize(new Point(windowSize.x, newHeight)); parent.layout(); } }