| /******************************************************************************* |
| * Copyright (c) 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ui.internal.progress; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.dialogs.ErrorDialog; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.viewers.IContentProvider; |
| import org.eclipse.jface.viewers.ILabelProviderListener; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.IStructuredContentProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.ITableLabelProvider; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.TableViewer; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.jface.viewers.ViewerSorter; |
| 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.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.MouseAdapter; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.List; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swt.widgets.MenuItem; |
| import org.eclipse.swt.widgets.Shell; |
| /** |
| * The ErrorNotificationDialog is is the dialog that comes up when an error has |
| * occured. |
| */ |
| public class ErrorNotificationDialog extends Dialog { |
| TableViewer errorViewer; |
| Button clearButton; |
| List detailsList; |
| private Clipboard clipboard; |
| private ErrorInfo selectedError = null; |
| |
| /** |
| * Reserve room for this many details list items. |
| */ |
| private static final int DETAILS_LIST_ITEM_COUNT = 7; |
| |
| /** |
| * The nesting indent. |
| */ |
| private static final String NESTING_INDENT = " "; //$NON-NLS-1$ |
| |
| /** |
| * Create a new instance of the receiver. |
| * |
| * @param parentShell |
| */ |
| public ErrorNotificationDialog(Shell parentShell) { |
| super(parentShell == null |
| ? ProgressManagerUtil.getDefaultParent() |
| : parentShell); |
| setBlockOnOpen(false); |
| setShellStyle(SWT.CLOSE | SWT.MODELESS | SWT.BORDER | SWT.TITLE |
| | SWT.RESIZE); |
| } |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell) |
| */ |
| protected void configureShell(Shell newShell) { |
| super.configureShell(newShell); |
| newShell.setText(ProgressMessages |
| .getString("ErrorNotificationDialog.ErrorNotificationTitle")); //$NON-NLS-1$ |
| newShell.addDisposeListener(new DisposeListener() { |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent) |
| */ |
| public void widgetDisposed(DisposeEvent e) { |
| getManager().clearDialog(); |
| } |
| }); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.window.Window#getShellStyle() |
| */ |
| protected int getShellStyle() { |
| return super.getShellStyle() | SWT.MIN; |
| } |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite) |
| */ |
| protected Control createDialogArea(Composite parent) { |
| initializeDialogUnits(parent); |
| Composite topArea = (Composite) super.createDialogArea(parent); |
| errorViewer = new TableViewer(topArea, SWT.MULTI | SWT.H_SCROLL |
| | SWT.V_SCROLL | SWT.BORDER); |
| errorViewer.setSorter(getViewerSorter()); |
| errorViewer.getControl().addMouseListener(new MouseAdapter() { |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.swt.events.MouseAdapter#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) |
| */ |
| public void mouseDoubleClick(MouseEvent e) { |
| openErrorDialog(); |
| } |
| }); |
| errorViewer |
| .addSelectionChangedListener(new ISelectionChangedListener() { |
| public void selectionChanged(SelectionChangedEvent event) { |
| |
| clearButton.setEnabled(!errorViewer.getSelection() |
| .isEmpty()); |
| setDetailsContents(); |
| } |
| }); |
| Control control = errorViewer.getControl(); |
| GridData data = new GridData(GridData.FILL_BOTH |
| | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL); |
| data.widthHint = convertWidthInCharsToPixels(60); |
| data.heightHint = convertHeightInCharsToPixels(10); |
| control.setLayoutData(data); |
| initContentProvider(); |
| initLabelProvider(); |
| applyDialogFont(parent); |
| |
| createDetailsList(topArea); |
| return topArea; |
| } |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) |
| */ |
| protected void createButtonsForButtonBar(Composite parent) { |
| |
| clearButton = createButton( |
| parent, |
| IDialogConstants.CLIENT_ID + 2, |
| ProgressMessages |
| .getString("ErrorNotificationDialog.ClearButtonTitle"), false); //$NON-NLS-1$ |
| clearButton.setEnabled(false); |
| clearButton.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent e) { |
| ISelection rawSelection = errorViewer.getSelection(); |
| if (rawSelection != null |
| && rawSelection instanceof IStructuredSelection) { |
| IStructuredSelection selection = (IStructuredSelection) rawSelection; |
| getManager().removeErrors(selection.toList()); |
| } |
| refresh(); |
| } |
| }); |
| Button button = createButton(parent, IDialogConstants.CLOSE_ID, |
| IDialogConstants.CLOSE_LABEL, true); |
| button.addSelectionListener(new SelectionListener() { |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) |
| */ |
| public void widgetSelected(SelectionEvent e) { |
| close(); |
| } |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) |
| */ |
| public void widgetDefaultSelected(SelectionEvent e) { |
| close(); |
| } |
| }); |
| } |
| /** |
| * Return a viewer sorter for looking at the jobs. |
| * |
| * @return |
| */ |
| private ViewerSorter getViewerSorter() { |
| return new ViewerSorter() { |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.ViewerSorter#compare(org.eclipse.jface.viewers.Viewer, |
| * java.lang.Object, java.lang.Object) |
| */ |
| public int compare(Viewer testViewer, Object e1, Object e2) { |
| return ((Comparable) e1).compareTo(e2); |
| } |
| }; |
| } |
| /** |
| * Sets the content provider for the viewer. |
| */ |
| protected void initContentProvider() { |
| IContentProvider provider = new IStructuredContentProvider() { |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.IContentProvider#dispose() |
| */ |
| public void dispose() { |
| //Nothing of interest here |
| } |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) |
| */ |
| public Object[] getElements(Object inputElement) { |
| return getManager().getErrors().toArray(); |
| } |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, |
| * java.lang.Object, java.lang.Object) |
| */ |
| public void inputChanged(Viewer viewer, Object oldInput, |
| Object newInput) { |
| if (newInput != null) |
| refresh(); |
| } |
| }; |
| errorViewer.setContentProvider(provider); |
| errorViewer.setInput(getManager()); |
| } |
| /** |
| * Get the notificationManager that this is being created for. |
| * |
| * @return |
| */ |
| private ErrorNotificationManager getManager() { |
| return ProgressManager.getInstance().errorManager; |
| } |
| /** |
| * Refresh the contents of the viewer. |
| */ |
| void refresh() { |
| errorViewer.refresh(); |
| } |
| private void initLabelProvider() { |
| ITableLabelProvider provider = new ITableLabelProvider() { |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener) |
| */ |
| public void addListener(ILabelProviderListener listener) { |
| //Do nothing |
| } |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose() |
| */ |
| public void dispose() { |
| //Do nothing |
| } |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, |
| * int) |
| */ |
| public Image getColumnImage(Object element, int columnIndex) { |
| return JFaceResources.getImageRegistry().get( |
| ErrorNotificationManager.ERROR_JOB_KEY); |
| } |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, |
| * int) |
| */ |
| public String getColumnText(Object element, int columnIndex) { |
| return ((ErrorInfo) element).getDisplayString(); |
| } |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, |
| * java.lang.String) |
| */ |
| public boolean isLabelProperty(Object element, String property) { |
| return false; |
| } |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener) |
| */ |
| public void removeListener(ILabelProviderListener listener) { |
| //Do nothing |
| } |
| }; |
| errorViewer.setLabelProvider(provider); |
| } |
| /** |
| * Open the error dialog on the current selection. |
| */ |
| private void openErrorDialog() { |
| ErrorInfo element = getSingleSelection(); |
| if (element == null) |
| return; |
| ErrorDialog.openError(getShell(), element.getDisplayString(), null, |
| element.getErrorStatus()); |
| } |
| /** |
| * Get the single selection. Return null if the selection is not just one |
| * element. |
| * |
| * @return ErrorInfo or <code>null</code>. |
| */ |
| private ErrorInfo getSingleSelection() { |
| ISelection rawSelection = errorViewer.getSelection(); |
| if (rawSelection != null |
| && rawSelection instanceof IStructuredSelection) { |
| IStructuredSelection selection = (IStructuredSelection) rawSelection; |
| if (selection.size() == 1) |
| return (ErrorInfo) selection.getFirstElement(); |
| } |
| return null; |
| } |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.dialogs.Dialog#close() |
| */ |
| public boolean close() { |
| getManager().clearAllErrors(); |
| Rectangle shellPosition = getShell().getBounds(); |
| boolean result = super.close(); |
| ProgressManagerUtil.animateDown(shellPosition); |
| return result; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.dialogs.Dialog#initializeBounds() |
| */ |
| protected void initializeBounds() { |
| super.initializeBounds(); |
| Rectangle shellPosition = getShell().getBounds(); |
| ProgressManagerUtil.animateUp(shellPosition); |
| } |
| |
| /** |
| * Create this dialog's drop-down list component. |
| * |
| * @param detailsParent |
| * the parent composite |
| */ |
| private void createDetailsList(Composite detailsParent) { |
| // create the list |
| detailsList = new List(detailsParent, SWT.BORDER | SWT.H_SCROLL |
| | SWT.V_SCROLL | SWT.MULTI); |
| |
| GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL |
| | GridData.GRAB_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL |
| | GridData.GRAB_VERTICAL); |
| data.heightHint = detailsList.getItemHeight() * DETAILS_LIST_ITEM_COUNT; |
| data.horizontalSpan = 2; |
| detailsList.setLayoutData(data); |
| Menu copyMenu = new Menu(detailsList); |
| MenuItem copyItem = new MenuItem(copyMenu, SWT.NONE); |
| copyItem.addSelectionListener(new SelectionListener() { |
| /* |
| * @see SelectionListener.widgetSelected (SelectionEvent) |
| */ |
| public void widgetSelected(SelectionEvent e) { |
| copyToClipboard(); |
| } |
| /* |
| * @see SelectionListener.widgetDefaultSelected(SelectionEvent) |
| */ |
| public void widgetDefaultSelected(SelectionEvent e) { |
| copyToClipboard(); |
| } |
| }); |
| copyItem.setText(JFaceResources.getString("copy")); //$NON-NLS-1$ |
| detailsList.setMenu(copyMenu); |
| } |
| |
| /** |
| * Set the contents of the details list to be the status from the selected |
| * error. |
| */ |
| private void setDetailsContents() { |
| |
| Collection statusList = new ArrayList(); |
| |
| ErrorInfo info = getSingleSelection(); |
| |
| if (info != null) { |
| selectedError = info; |
| statusList.add(selectedError.getErrorStatus().getMessage()); |
| if (selectedError.getErrorStatus().getException() != null) { |
| Throwable exception = selectedError.getErrorStatus() |
| .getException(); |
| statusList.add(exception.toString()); |
| StackTraceElement[] elements = exception.getStackTrace(); |
| for (int i = 0; i < elements.length; i++) { |
| statusList.add(elements[i].toString()); |
| } |
| } |
| IStatus[] statuses = (selectedError.getErrorStatus().getChildren()); |
| for (int i = 0; i < statuses.length; i++) { |
| statusList.add(NESTING_INDENT + statuses[i].getMessage()); |
| } |
| } |
| |
| String[] items = new String[statusList.size()]; |
| statusList.toArray(items); |
| |
| detailsList.setItems(items); |
| |
| } |
| |
| /** |
| * Copy the contents of the statuses to the clipboard. |
| */ |
| private void copyToClipboard() { |
| |
| if (selectedError == null) |
| return; |
| |
| if (clipboard != null) |
| clipboard.dispose(); |
| |
| StringBuffer statusBuffer = new StringBuffer(); |
| populateCopyBuffer(selectedError.getErrorStatus(), statusBuffer, 0); |
| clipboard = new Clipboard(detailsList.getDisplay()); |
| clipboard.setContents(new Object[]{statusBuffer.toString()}, |
| new Transfer[]{TextTransfer.getInstance()}); |
| } |
| |
| /** |
| * Put the details of the status of the error onto the stream. |
| * |
| * @param buildingStatus |
| * @param buffer |
| * @param nesting |
| */ |
| private void populateCopyBuffer(IStatus buildingStatus, |
| StringBuffer buffer, int nesting) { |
| |
| for (int i = 0; i < nesting; i++) { |
| buffer.append(NESTING_INDENT); //$NON-NLS-1$ |
| } |
| buffer.append(buildingStatus.getMessage()); |
| |
| if (buildingStatus.getException() != null) { |
| Throwable exception = buildingStatus.getException(); |
| buffer.append("\n"); //$NON-NLS-1$ |
| buffer.append(exception.toString()); |
| StackTraceElement[] elements = exception.getStackTrace(); |
| for (int i = 0; i < elements.length; i++) { |
| buffer.append("\n"); //$NON-NLS-1$ |
| buffer.append(elements[i].toString()); |
| |
| } |
| } |
| |
| buffer.append("\n"); //$NON-NLS-1$ |
| IStatus[] children = buildingStatus.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| populateCopyBuffer(children[i], buffer, nesting + 1); |
| } |
| } |
| } |