/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 *******************************************************************************/ package org.ebayopensource.turmeric.eclipse.utils.ui; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IconAndMessageDialog; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; 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.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; /** * code to show error message for soa plug-ins. */ public class SOAErrorDialog extends IconAndMessageDialog { private static final int RESERVE_LIST_ITEM_COUNT = 9; private static final String NESTING_INDENT = " "; private Button detailsButton; private String errorDialogTitle; private List messageList; private boolean isListCreated = false; private int filterMask = 0xFFFF; private IStatus status; private Clipboard clipboard; private boolean hasLineBreak = false; private boolean hasLineTitle = false; private boolean hasCancelButton = false; private boolean buttonLabelChange = false; /** * create an error dialog instance. * * @param parent the parent * @param title the title * @param message the message * @param status the status * @param mask the mask */ public SOAErrorDialog(Shell parent, String title, String message, IStatus status, int mask) { this(parent, title, message, status, mask, false, false, false, false); } /** * Instantiates a new sOA error dialog. * * @param parent the parent * @param title the title * @param message the message * @param status the status * @param mask the mask * @param needLineBreak the need line break * @param needLineTitle the need line title * @param needCancelButton the need cancel button * @param changeButtonLabel the change button label */ public SOAErrorDialog(Shell parent, String title, String message, IStatus status, int mask, boolean needLineBreak, boolean needLineTitle, boolean needCancelButton, boolean changeButtonLabel) { super(parent); errorDialogTitle = title; if (errorDialogTitle == null) { errorDialogTitle = JFaceResources.getString("Problem_Occurred"); } this.message = message == null ? status.getMessage() : JFaceResources .format( "Reason", new Object[] { message, status.getMessage() }); //$NON-NLS-1$ this.status = status; this.filterMask = mask; setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX);// #added by wecai this.hasLineBreak = needLineBreak; this.hasLineTitle = needLineTitle; this.hasCancelButton = needCancelButton; this.buttonLabelChange = changeButtonLabel; } /** * Handle "Details" button action.show details if it is hidden. Hide details * if it is shown. * * @param id the id */ @Override protected void buttonPressed(int id) { if (id == IDialogConstants.DETAILS_ID) { showDetialsArea(); } else { super.buttonPressed(id); } } /** * {@inheritDoc} */ @Override protected void configureShell(Shell shell) { super.configureShell(shell); shell.setText(errorDialogTitle); } /** * {@inheritDoc} */ @Override protected void createButtonsForButtonBar(Composite parent) { // create OK and Details buttons String okLabel = IDialogConstants.OK_LABEL; String cancelLabel = IDialogConstants.CANCEL_LABEL; if (buttonLabelChange == true) { okLabel = "Ignore and Continue"; cancelLabel = "Abort"; } createButton(parent, IDialogConstants.OK_ID, okLabel, true); if (hasCancelButton == true) { createButton(parent, IDialogConstants.CANCEL_ID, cancelLabel, true); } if (shouldShowDetailsButton()) { detailsButton = createButton(parent, IDialogConstants.DETAILS_ID, IDialogConstants.SHOW_DETAILS_LABEL, false); } } /** * create the main part of the dialog. * * @param parent the parent * @return the control */ @Override protected Control createDialogArea(Composite parent) { createMessageArea(parent); // create content area Composite composite = new Composite(parent, SWT.NONE); GridData childData = new GridData(GridData.FILL_BOTH); childData.horizontalSpan = 2; composite.setLayoutData(childData); composite.setFont(parent.getFont()); GridLayout layout = new GridLayout(); layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); layout.numColumns = 2; composite.setLayout(layout); return composite; } /** * {@inheritDoc} */ @Override protected void createDialogAndButtonArea(Composite parent) { super.createDialogAndButtonArea(parent); if (this.dialogArea instanceof Composite) { Composite dialogComposite = (Composite) dialogArea; if (dialogComposite.getChildren().length == 0) { new Label(dialogComposite, SWT.NULL); } } } /** * get dialog icon. * * @return the image */ @Override protected Image getImage() { if (status != null) { if (status.getSeverity() == IStatus.WARNING || hasCancelButton == true) { // if the cancel button is needed, then we should use warning // icon return getWarningImage(); } if (status.getSeverity() == IStatus.INFO) { return getInfoImage(); } } // If it was not a warning or an error then return the error image return getErrorImage(); } /** * create the details list. * * @param parent the parent * @return the list */ protected List createDetailsList(Composite parent) { // create the list messageList = new List(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI); // fill the list fillList(messageList, status, 0); GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL); data.heightHint = messageList.getItemHeight() * RESERVE_LIST_ITEM_COUNT; data.horizontalSpan = 2; messageList.setLayoutData(data); messageList.setFont(parent.getFont()); Menu copyMenu = new Menu(messageList); MenuItem copyItem = new MenuItem(copyMenu, SWT.NONE); copyItem.addSelectionListener(new SelectionListener() { /* * @see SelectionListener.widgetSelected (SelectionEvent) */ @Override public void widgetSelected(SelectionEvent e) { copyDetailsToClipboard(); } /* * @see SelectionListener.widgetDefaultSelected(SelectionEvent) */ @Override public void widgetDefaultSelected(SelectionEvent e) { copyDetailsToClipboard(); } }); copyItem.setText(JFaceResources.getString("copy")); //$NON-NLS-1$ messageList.setMenu(copyMenu); isListCreated = true; return messageList; } /** * open error dialog.only show desired status based on status mask. * * @return the int */ @Override public int open() { if (shouldShow(status, filterMask)) { return super.open(); } setReturnCode(OK); return OK; } /** * Open error. * * @param parent the parent * @param dialogTitle the dialog title * @param message the message * @param status the status * @return the int */ public static int openError(Shell parent, String dialogTitle, String message, IStatus status) { return openError(parent, dialogTitle, message, status, IStatus.OK | IStatus.INFO | IStatus.WARNING | IStatus.ERROR); } /** * Open error. * * @param parentShell the parent shell * @param title the title * @param message the message * @param status the status * @param displayMask the display mask * @return the int */ public static int openError(Shell parentShell, String title, String message, IStatus status, int displayMask) { return openError(parentShell, title, message, status, displayMask, false, false, false, false); } /** * Open error. * * @param parentShell the parent shell * @param title the title * @param message the message * @param status the status * @param displayMask the display mask * @param needLineBreak the need line break * @param needLineTitle the need line title * @param needCancelButton the need cancel button * @param changeButtonLabel the change button label * @return the int */ public static int openError(Shell parentShell, String title, String message, IStatus status, int displayMask, boolean needLineBreak, boolean needLineTitle, boolean needCancelButton, boolean changeButtonLabel) { SOAErrorDialog dialog = new SOAErrorDialog(parentShell, title, message, status, displayMask, needLineBreak, needLineTitle, needCancelButton, changeButtonLabel); return dialog.open(); } private void fillList(List listToPopulate, IStatus status, int nesting) { if (!status.matches(filterMask)) { return; } java.util.List<String> msg = new ArrayList<String>(); createDetailContent(status, msg, 0); for (String str : msg) { listToPopulate.add(str); } } /** * Should show. * * @param status the status * @param mask the mask * @return true, if successful */ protected static boolean shouldShow(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 showDetialsArea() { Point windowSize = getShell().getSize(); Point oldSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT); // if list showed, hide list. Otherwise, show list. if (isListCreated) { messageList.dispose(); isListCreated = false; detailsButton.setText(IDialogConstants.SHOW_DETAILS_LABEL); // #added by wecai ((GridData) this.dialogArea.getLayoutData()).grabExcessVerticalSpace = true; } else { messageList = createDetailsList((Composite) getContents()); detailsButton.setText(IDialogConstants.HIDE_DETAILS_LABEL); // #added by wecai ((GridData) this.dialogArea.getLayoutData()).grabExcessVerticalSpace = false; } // resize dialog. Point newSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT); getShell() .setSize( new Point(windowSize.x, windowSize.y + (newSize.y - oldSize.y))); } /** * generate content to show. * * @param buildingStatus * @param msg * @param nesting */ private void createDetailContent(IStatus buildingStatus, java.util.List<String> msg, int nesting) { StringBuffer buffer = new StringBuffer(); // not to be showed, just return. if (!buildingStatus.matches(filterMask)) { return; } if (hasLineBreak == true && buffer.length() > 0) { msg.add("\r\n"); } for (int i = 0; i < nesting; i++) { buffer.append(NESTING_INDENT); } Class<?> statusClazz = buildingStatus.getClass(); if (hasLineTitle == true && buildingStatus.isOK() == false) { if (buildingStatus.getSeverity() == IStatus.WARNING && (buildingStatus instanceof MultiStatus) == false && statusClazz.equals(Status.class) == false && buildingStatus.getCode() != IStatus.OK) { // this is the case that we are dealing with customized status buffer.append(buildingStatus.toString()); } else { buffer .append(buildingStatus.getSeverity() == IStatus.ERROR ? "Must Fix Error: " : "Should Fix Warning: "); buffer.append(buildingStatus.getMessage()); } } else { buffer.append(buildingStatus.getMessage()); } msg.add(buffer.toString()); buffer.delete(0, buffer.length()); // Look for a nested core exception Throwable t = buildingStatus.getException(); if (t instanceof CoreException) { CoreException ce = (CoreException) t; createDetailContent(ce.getStatus(), msg, nesting + 1); } else if (t != null) { // Include low-level exception message for (int i = 0; i < nesting; i++) { buffer.append(NESTING_INDENT); } String message = t.getLocalizedMessage(); if (message == null) { message = t.toString(); } buffer.append(message); msg.add(buffer.toString()); buffer.delete(0, buffer.length()); } IStatus[] children = buildingStatus.getChildren(); Arrays.sort(children, StatusComparator.INSTANCE); for (int i = 0; i < children.length; i++) { createDetailContent(children[i], msg, nesting + 1); } } /** * Copy the contents of the statuses to the clipboard. */ private void copyDetailsToClipboard() { if (clipboard != null) { clipboard.dispose(); } StringBuffer statusBuffer = new StringBuffer(); java.util.List<String> msg = new ArrayList<String>(); createDetailContent(status, msg, 0); for (String str : msg) { statusBuffer.append(str + "\r\n"); } clipboard = new Clipboard(messageList.getDisplay()); clipboard.setContents(new Object[] { statusBuffer.toString() }, new Transfer[] { TextTransfer.getInstance() }); } /** * {@inheritDoc} */ @Override public boolean close() { if (clipboard != null) { clipboard.dispose(); } return super.close(); } /** * Should show details button. * * @return true, if successful */ protected boolean shouldShowDetailsButton() { return status.isMultiStatus() || status.getException() != null; } private static class StatusComparator implements Comparator<IStatus>{ public static StatusComparator INSTANCE = new StatusComparator(); @Override public int compare(IStatus status1, IStatus status2) { return status2.getSeverity() - status1.getSeverity(); } } }