/*******************************************************************************
* 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();
}
}
}