Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 15407 Details for
Bug 76726
[Jobs][Progress] Redesign job error dialog
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read
this important communication.
[patch]
Patch to Workbench which improves concurreny error dialog usability
org.eclipse.ui.workbench.txt (text/plain), 68.01 KB, created by
Michael Valenta
on 2004-10-26 16:06:57 EDT
(
hide
)
Description:
Patch to Workbench which improves concurreny error dialog usability
Filename:
MIME Type:
Creator:
Michael Valenta
Created:
2004-10-26 16:06:57 EDT
Size:
68.01 KB
patch
obsolete
>Index: Eclipse UI/org/eclipse/ui/internal/progress/ErrorInfo.java >=================================================================== >RCS file: /home/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/ErrorInfo.java,v >retrieving revision 1.5 >diff -u -r1.5 ErrorInfo.java >--- Eclipse UI/org/eclipse/ui/internal/progress/ErrorInfo.java 8 Jul 2004 20:07:37 -0000 1.5 >+++ Eclipse UI/org/eclipse/ui/internal/progress/ErrorInfo.java 26 Oct 2004 19:50:40 -0000 >@@ -10,7 +10,10 @@ > *******************************************************************************/ > package org.eclipse.ui.internal.progress; > >+import java.util.Date; >+ > import org.eclipse.core.runtime.IStatus; >+import org.eclipse.core.runtime.jobs.Job; > import org.eclipse.jface.resource.JFaceResources; > import org.eclipse.swt.graphics.Image; > >@@ -19,17 +22,18 @@ > */ > public class ErrorInfo extends JobTreeElement { > >- private IStatus errorStatus; >- >- private String jobName; >+ private final IStatus errorStatus; >+ private final Job job; >+ private final long timestamp; > > /** > * Create a new instance of the receiver. > * @param status > */ >- public ErrorInfo(IStatus status, String name) { >+ public ErrorInfo(IStatus status, Job job) { > errorStatus = status; >- jobName = name; >+ this.job = job; >+ timestamp = System.currentTimeMillis(); > } > > /* (non-Javadoc) >@@ -58,7 +62,7 @@ > */ > String getDisplayString() { > return ProgressMessages.format("JobInfo.Error", //$NON-NLS-1$ >- new Object[] { jobName, errorStatus.getMessage() }); >+ new Object[] { job.getName(), new Date(timestamp) }); > } > > /** >@@ -89,5 +93,35 @@ > */ > boolean isActive() { > return true; >+ } >+ >+ /** >+ * Return the job that generated the error. >+ * @return the job that generated the error >+ */ >+ public Job getJob() { >+ return job; >+ } >+ >+ public long getTimestamp() { >+ return timestamp; >+ } >+ >+ /* (non-Javadoc) >+ * @see org.eclipse.ui.internal.progress.JobTreeElement#compareTo(java.lang.Object) >+ */ >+ public int compareTo(Object arg0) { >+ if (arg0 instanceof ErrorInfo) { >+ // Order ErrorInfo by time received >+ long otherTimestamp = ((ErrorInfo)arg0).timestamp; >+ if (timestamp < otherTimestamp) { >+ return -1; >+ } else if (timestamp > otherTimestamp) { >+ return 1; >+ } else { >+ return 0; >+ } >+ } >+ return super.compareTo(arg0); > } > } >Index: Eclipse UI/org/eclipse/ui/internal/progress/ErrorNotificationDialog.java >=================================================================== >RCS file: Eclipse UI/org/eclipse/ui/internal/progress/ErrorNotificationDialog.java >diff -N Eclipse UI/org/eclipse/ui/internal/progress/ErrorNotificationDialog.java >--- Eclipse UI/org/eclipse/ui/internal/progress/ErrorNotificationDialog.java 20 Oct 2004 16:24:50 -0000 1.12 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,526 +0,0 @@ >-/******************************************************************************* >- * 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 | getDefaultOrientation()); >- } >- >- /* >- * (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); >- } >- } >-} >\ No newline at end of file >Index: Eclipse UI/org/eclipse/ui/internal/progress/ErrorNotificationManager.java >=================================================================== >RCS file: /home/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/ErrorNotificationManager.java,v >retrieving revision 1.5 >diff -u -r1.5 ErrorNotificationManager.java >--- Eclipse UI/org/eclipse/ui/internal/progress/ErrorNotificationManager.java 14 Jul 2004 13:03:07 -0000 1.5 >+++ Eclipse UI/org/eclipse/ui/internal/progress/ErrorNotificationManager.java 26 Oct 2004 19:50:40 -0000 >@@ -12,24 +12,16 @@ > > import java.net.MalformedURLException; > import java.net.URL; >-import java.util.Collection; >-import java.util.Collections; >-import java.util.HashSet; >-import java.util.Iterator; >-import java.util.Set; >- >-import org.eclipse.core.runtime.IProgressMonitor; >-import org.eclipse.core.runtime.IStatus; >-import org.eclipse.core.runtime.Status; >+import java.util.*; >+ >+import org.eclipse.core.runtime.*; >+import org.eclipse.core.runtime.jobs.Job; > import org.eclipse.jface.resource.ImageDescriptor; > import org.eclipse.jface.resource.JFaceResources; >-import org.eclipse.ui.IWorkbench; >-import org.eclipse.ui.IWorkbenchWindow; >-import org.eclipse.ui.PlatformUI; >-import org.eclipse.ui.internal.ExceptionHandler; >-import org.eclipse.ui.internal.Workbench; >-import org.eclipse.ui.internal.WorkbenchPlugin; >-import org.eclipse.ui.progress.UIJob; >+import org.eclipse.swt.widgets.Shell; >+import org.eclipse.ui.*; >+import org.eclipse.ui.internal.*; >+import org.eclipse.ui.progress.IProgressConstants; > import org.eclipse.ui.progress.WorkbenchJob; > > /** >@@ -44,9 +36,7 @@ > > private Collection errors = Collections.synchronizedSet(new HashSet()); > >- private ErrorNotificationDialog dialog; >- >- private boolean dialogActive = false; >+ private JobErrorDialog dialog; > > /** > * Create a new instance of the receiver. >@@ -70,7 +60,7 @@ > * @param status > * @param jobName > */ >- void addError(IStatus status, String jobName) { >+ void addError(IStatus status, Job job) { > > //Handle out of memory errors via the workbench > final Throwable exception = status.getException(); >@@ -86,33 +76,50 @@ > > return; > } >- errors.add(new ErrorInfo(status, jobName)); >- if (dialogActive) { >- if (dialog != null) >- refreshDialog(); >- } else >- openErrorDialog(jobName, status); >+ ErrorInfo errorInfo = new ErrorInfo(status, job); >+ showError(errorInfo); > } > > /** >- * >+ * Show the error in the error dialog. This is done from the UI thread to >+ * ensure that no errors are dropped. >+ * @param errorInfo the error to be displayed > */ >- private void refreshDialog() { >+ private void showError(final ErrorInfo errorInfo) { >+ >+ if (!PlatformUI.isWorkbenchRunning()) { >+ //We are shutdown so just log >+ WorkbenchPlugin.log(errorInfo.getJob().getName(), errorInfo.getErrorStatus()); >+ return; >+ } > >- UIJob refreshJob = new UIJob(ProgressMessages >- .getString("ErrorNotificationManager.RefreshErrorDialogJob")) { //$NON-NLS-1$ >- /* (non-Javadoc) >- * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) >- */ >+ // We must open or update the error dialog in the UI thread to ensure that >+ // errors are not dropped >+ WorkbenchJob job = new WorkbenchJob(ProgressMessages >+ .getString("ErrorNotificationManager.OpenErrorDialogJob")) { //$NON-NLS-1$ > public IStatus runInUIThread(IProgressMonitor monitor) { >- dialog.refresh(); >+ // Add the error in the UI thread to ensure thread safety in the dialog >+ errors.add(errorInfo); >+ if (dialog != null) { >+ dialog.refresh(); >+ } else if (Platform.isRunning()) { >+ // Delay prompting if the job property is set >+ Object noPromptProperty = errorInfo.getJob().getProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY); >+ boolean prompt; >+ if (noPromptProperty instanceof Boolean) { >+ prompt = !((Boolean)noPromptProperty).booleanValue(); >+ } else { >+ prompt = true; >+ } >+ if (prompt) { >+ return openErrorDialog(null /* use default title */, null /* use default message */, errorInfo); >+ } >+ } > return Status.OK_STATUS; > } > }; >- >- refreshJob.setSystem(true); >- refreshJob.schedule(); >- >+ job.setSystem(true); >+ job.schedule(); > } > > /** >@@ -126,43 +133,31 @@ > /** > * The job caleed jobName has just failed with status status. > * Open the error dialog if possible - otherwise log the error. >+ * @param title the title of the dialog or <code>null</code> >+ * @param msg the message for the dialog oe <code>null</code> > * @param jobName String. The name of the Job > * @param status IStatus The status of the failure. > */ >- private void openErrorDialog(String jobName, IStatus status) { >+ private IStatus openErrorDialog(String title, String msg, final ErrorInfo errorInfo) { >+ IWorkbench workbench = PlatformUI.getWorkbench(); > >- if (!PlatformUI.isWorkbenchRunning()) { >- //We are shutdown so just log >- WorkbenchPlugin.log(jobName, status); >- return; >+ //Abort on shutdown >+ if (workbench instanceof Workbench >+ && ((Workbench) workbench).isClosing()) >+ return Status.CANCEL_STATUS; >+ IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); >+ >+ if (window == null) >+ return Status.CANCEL_STATUS; >+ dialog = new JobErrorDialog(window.getShell(), title, msg, errorInfo, IStatus.OK >+ | IStatus.INFO | IStatus.WARNING | IStatus.ERROR); >+ try { >+ dialog.open(); >+ } finally { >+ dialog = null; >+ clearAllErrors(); > } >- >- dialogActive = true; >- WorkbenchJob job = new WorkbenchJob(ProgressMessages >- .getString("ErrorNotificationManager.OpenErrorDialogJob")) { //$NON-NLS-1$ >- /* >- * (non-Javadoc) >- * >- * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) >- */ >- public IStatus runInUIThread(IProgressMonitor monitor) { >- IWorkbench workbench = PlatformUI.getWorkbench(); >- >- //Abort on shutdown >- if (workbench instanceof Workbench >- && ((Workbench) workbench).isClosing()) >- return Status.CANCEL_STATUS; >- IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); >- >- if (window == null) >- return Status.CANCEL_STATUS; >- dialog = new ErrorNotificationDialog(window.getShell()); >- dialog.open(); >- return Status.OK_STATUS; >- } >- }; >- job.setSystem(true); >- job.schedule(); >+ return Status.OK_STATUS; > } > > /** >@@ -200,16 +195,70 @@ > /** > * Clear all of the errors held onto by the receiver. > */ >- void clearAllErrors() { >+ private void clearAllErrors() { > removeFromFinishedJobs(errors); > errors.clear(); > } > > /** >- * Remove the reference to the errors dialog. >+ * Display the error for the given job and any other errors >+ * that have been accumulated. This method must be invoked >+ * from the UI thread. >+ * @param shell the shell used to parent the dialog >+ * @param job the job whose error should be displayed >+ * @return <code>true</code> if the info for the job was found and the error >+ * displayed and <code>false</code> otherwise. >+ */ >+ public boolean showErrorFor(Shell shell, Job job, String title, String msg) { >+ if (dialog != null) { >+ // The dialog is already open so the error is being displayed >+ return true; >+ } >+ ErrorInfo info = getErrorInfo(job); >+ if (job == null) { >+ info = getMostRecentError(); >+ } else { >+ info = getErrorInfo(job); >+ } >+ if (info != null) { >+ openErrorDialog(title, msg, info); >+ return true; >+ } >+ return false; >+ } >+ >+ /* >+ * Return the most recent error. >+ */ >+ private ErrorInfo getMostRecentError() { >+ ErrorInfo mostRecentInfo = null; >+ for (Iterator iter = errors.iterator(); iter.hasNext();) { >+ ErrorInfo info = (ErrorInfo) iter.next(); >+ if (mostRecentInfo == null || info.getTimestamp() > mostRecentInfo.getTimestamp()) { >+ mostRecentInfo = info; >+ } >+ } >+ return mostRecentInfo; >+ } >+ >+ /* >+ * Return the error info for the given job >+ */ >+ private ErrorInfo getErrorInfo(Job job) { >+ for (Iterator iter = errors.iterator(); iter.hasNext();) { >+ ErrorInfo info = (ErrorInfo) iter.next(); >+ if (info.getJob() == job) { >+ return info; >+ } >+ } >+ return null; >+ } >+ >+ /** >+ * Return whether the manager has errors to report. >+ * @return whether the manager has errors to report > */ >- void clearDialog() { >- dialog = null; >- dialogActive = false; >+ public boolean hasErrors() { >+ return !errors.isEmpty(); > } > } >Index: Eclipse UI/org/eclipse/ui/internal/progress/FinishedJobs.java >=================================================================== >RCS file: /home/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/FinishedJobs.java,v >retrieving revision 1.20 >diff -u -r1.20 FinishedJobs.java >--- Eclipse UI/org/eclipse/ui/internal/progress/FinishedJobs.java 8 Jul 2004 20:07:37 -0000 1.20 >+++ Eclipse UI/org/eclipse/ui/internal/progress/FinishedJobs.java 26 Oct 2004 19:50:40 -0000 >@@ -288,11 +288,13 @@ > } > } > >- void remove(JobTreeElement jte) { >+ boolean remove(JobTreeElement jte) { > boolean fire = false; >+ boolean removed = false; > > synchronized (keptjobinfos) { > if (keptjobinfos.remove(jte)) { >+ removed = true; > finishedTime.remove(jte); > disposeAction(jte); > if (NewProgressViewer.DEBUG) >@@ -324,6 +326,7 @@ > jv.removed(jte); > } > } >+ return removed; > } > > /** >Index: Eclipse UI/org/eclipse/ui/internal/progress/NewProgressViewer.java >=================================================================== >RCS file: /home/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/NewProgressViewer.java,v >retrieving revision 1.57 >diff -u -r1.57 NewProgressViewer.java >--- Eclipse UI/org/eclipse/ui/internal/progress/NewProgressViewer.java 15 Sep 2004 14:48:38 -0000 1.57 >+++ Eclipse UI/org/eclipse/ui/internal/progress/NewProgressViewer.java 26 Oct 2004 19:50:40 -0000 >@@ -12,10 +12,7 @@ > > import java.net.URL; > import java.text.DateFormat; >-import java.util.ArrayList; >-import java.util.Date; >-import java.util.HashMap; >-import java.util.HashSet; >+import java.util.*; > import java.util.List; > > import org.eclipse.core.runtime.IStatus; >@@ -24,47 +21,15 @@ > import org.eclipse.jface.action.Action; > import org.eclipse.jface.action.IAction; > import org.eclipse.jface.dialogs.ErrorDialog; >-import org.eclipse.jface.resource.ImageDescriptor; >-import org.eclipse.jface.resource.JFaceColors; >-import org.eclipse.jface.resource.JFaceResources; >+import org.eclipse.jface.resource.*; > import org.eclipse.jface.util.IPropertyChangeListener; > import org.eclipse.jface.util.PropertyChangeEvent; >-import org.eclipse.jface.viewers.IContentProvider; >-import org.eclipse.jface.viewers.ISelection; >-import org.eclipse.jface.viewers.ITreeContentProvider; >-import org.eclipse.jface.viewers.StructuredSelection; >-import org.eclipse.jface.viewers.TreeViewer; >-import org.eclipse.jface.viewers.ViewerSorter; >+import org.eclipse.jface.viewers.*; > import org.eclipse.swt.SWT; > import org.eclipse.swt.custom.ScrolledComposite; >-import org.eclipse.swt.events.ControlAdapter; >-import org.eclipse.swt.events.ControlEvent; >-import org.eclipse.swt.events.SelectionAdapter; >-import org.eclipse.swt.events.SelectionEvent; >-import org.eclipse.swt.events.TreeListener; >-import org.eclipse.swt.graphics.Color; >-import org.eclipse.swt.graphics.Cursor; >-import org.eclipse.swt.graphics.Font; >-import org.eclipse.swt.graphics.FontData; >-import org.eclipse.swt.graphics.FontMetrics; >-import org.eclipse.swt.graphics.GC; >-import org.eclipse.swt.graphics.Image; >-import org.eclipse.swt.graphics.Point; >-import org.eclipse.swt.graphics.Rectangle; >-import org.eclipse.swt.widgets.Canvas; >-import org.eclipse.swt.widgets.Composite; >-import org.eclipse.swt.widgets.Control; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Event; >-import org.eclipse.swt.widgets.Item; >-import org.eclipse.swt.widgets.Label; >-import org.eclipse.swt.widgets.Layout; >-import org.eclipse.swt.widgets.Listener; >-import org.eclipse.swt.widgets.ProgressBar; >-import org.eclipse.swt.widgets.ToolBar; >-import org.eclipse.swt.widgets.ToolItem; >-import org.eclipse.swt.widgets.Tree; >-import org.eclipse.swt.widgets.Widget; >+import org.eclipse.swt.events.*; >+import org.eclipse.swt.graphics.*; >+import org.eclipse.swt.widgets.*; > import org.eclipse.ui.internal.misc.Assert; > import org.eclipse.ui.internal.util.ImageSupport; > import org.eclipse.ui.progress.IProgressConstants; >@@ -234,7 +199,7 @@ > return null; > } > >- public boolean kill(boolean refresh, boolean broadcast) { >+ public boolean kill() { > return true; > } > >@@ -509,7 +474,7 @@ > jobitem.locked = true; > gotoAction.run(); > if (jobitem.jobTerminated) >- jobitem.kill(true, true); >+ jobitem.kill(); > return true; > } > return false; >@@ -520,7 +485,7 @@ > if (jobTreeElement == null) // shouldn't happen > return false; > >- Job job = getJob(); >+ final Job job = getJob(); > if (job != null) { > // check for icon property and propagate to parent > if (jobitem.image == null) >@@ -542,11 +507,24 @@ > setAction(new Action() { > public void run() { > String title = ProgressMessages >- .getString("NewProgressView.errorDialogTitle"); //$NON-NLS-1$ >- String msg = ProgressMessages >- .getString("NewProgressView.errorDialogMessage"); //$NON-NLS-1$ >- ErrorDialog.openError(getShell(), title, msg, >- result); >+ .getString("NewProgressView.errorDialogTitle"); //$NON-NLS-1$ >+ String msg = ProgressMessages >+ .getString("NewProgressView.errorDialogMessage"); //$NON-NLS-1$ >+ if (!getManager().showErrorFor(getShell(), job, title, msg)) { >+ // The error is missing from the error manager. >+ // This should only occur if what the progress view is showing is >+ // out-of-sync with the ErrorNotificationManager and/or FinishedJobs >+ // manager. In other words, it shouldn't happen but may so it is >+ // better to show the user something than fail silently >+ ErrorDialog.openError(getShell(), title, msg, >+ result); >+ } >+ } >+ /* >+ * Get the notificationManager that this is being created for. >+ */ >+ private ErrorNotificationManager getManager() { >+ return ProgressManager.getInstance().errorManager; > } > }); > } >@@ -786,7 +764,7 @@ > > boolean cancelOrRemove() { > if (jobTerminated) >- return kill(true, true); >+ return kill(); > jobTreeElement.cancel(); > return false; > } >@@ -879,14 +857,17 @@ > return changed; > } > >- public boolean kill(boolean refresh, boolean broadcast) { >+ public boolean kill() { > if (jobTerminated) { >- >- if (broadcast) >- finishedJobs.remove(jobTreeElement); >- else { >+ // Removing the job from the list of jobs will >+ // remove the job from the view using a callback >+ if (!finishedJobs.remove(jobTreeElement)) { >+ // The terminated job has already been removed >+ // from the list of finished jobs but was somehow >+ // left in the view. Dispose of the item and refresh >+ // the view > dispose(); >- relayout(refresh, refresh); >+ relayout(true, true); > return true; > } > } >Index: Eclipse UI/org/eclipse/ui/internal/progress/ProgressAnimationItem.java >=================================================================== >RCS file: /home/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/ProgressAnimationItem.java,v >retrieving revision 1.35 >diff -u -r1.35 ProgressAnimationItem.java >--- Eclipse UI/org/eclipse/ui/internal/progress/ProgressAnimationItem.java 8 Jul 2004 20:07:37 -0000 1.35 >+++ Eclipse UI/org/eclipse/ui/internal/progress/ProgressAnimationItem.java 26 Oct 2004 19:50:40 -0000 >@@ -10,28 +10,19 @@ > *******************************************************************************/ > package org.eclipse.ui.internal.progress; > >+import java.util.Collection; >+import java.util.Iterator; >+ > import org.eclipse.core.runtime.IStatus; > import org.eclipse.core.runtime.jobs.Job; > import org.eclipse.jface.action.IAction; > import org.eclipse.jface.dialogs.ErrorDialog; > import org.eclipse.swt.SWT; >-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.MouseListener; >-import org.eclipse.swt.events.SelectionAdapter; >-import org.eclipse.swt.events.SelectionEvent; >+import org.eclipse.swt.events.*; > import org.eclipse.swt.graphics.Image; > import org.eclipse.swt.layout.GridData; > import org.eclipse.swt.layout.GridLayout; >-import org.eclipse.swt.widgets.Composite; >-import org.eclipse.swt.widgets.Control; >-import org.eclipse.swt.widgets.Display; >-import org.eclipse.swt.widgets.Label; >-import org.eclipse.swt.widgets.ProgressBar; >-import org.eclipse.swt.widgets.ToolBar; >-import org.eclipse.swt.widgets.ToolItem; >+import org.eclipse.swt.widgets.*; > import org.eclipse.ui.PlatformUI; > import org.eclipse.ui.internal.util.ImageSupport; > import org.eclipse.ui.progress.IProgressConstants; >@@ -92,17 +83,27 @@ > > IStatus status = job.getResult(); > if (status != null && status.getSeverity() == IStatus.ERROR) { >+ // The showErrorFor method will show the user all the accumulated errors >+ // and clear then when done > String title = ProgressMessages >- .getString("NewProgressView.errorDialogTitle"); //$NON-NLS-1$ >- String msg = ProgressMessages >- .getString("NewProgressView.errorDialogMessage"); //$NON-NLS-1$ >- ErrorDialog.openError(toolbar.getShell(), title, msg, >- status); >- JobTreeElement topElement = (JobTreeElement) ji >- .getParent(); >- if (topElement == null) >- topElement = ji; >- FinishedJobs.getInstance().remove(topElement); >+ .getString("NewProgressView.errorDialogTitle"); //$NON-NLS-1$ >+ String msg = ProgressMessages >+ .getString("NewProgressView.errorDialogMessage"); //$NON-NLS-1$ >+ if (!getManager().showErrorFor(toolbar.getShell(), job, title, msg)) { >+ // The error is missing from the error manager. >+ // This should only occur if what the progress view is showing is >+ // out-of-sync with the ErrorNotificationManager >+ // In other words, it shouldn't happen but may so it is >+ // better to show the user something and clean up >+ // than fail silently. >+ ErrorDialog.openError(toolbar.getShell(), title, msg, >+ status); >+ JobTreeElement topElement = (JobTreeElement) ji >+ .getParent(); >+ if (topElement == null) >+ topElement = ji; >+ FinishedJobs.getInstance().remove(topElement); >+ } > return; > } > >@@ -124,6 +125,10 @@ > } > } > >+ if (getManager().hasErrors()) { >+ getManager().showErrorFor(toolbar.getShell(), null, null, null); >+ } >+ > progressRegion.processDoubleClick(); > refresh(); > } >@@ -183,6 +188,22 @@ > } > } > } >+ >+ // If the error manager has errors, display the error indication >+ // just in case a previous job ended in error but wasn't kept >+ ErrorNotificationManager errorNotificationManager = ProgressManager.getInstance().errorManager; >+ if (errorNotificationManager.hasErrors()) { >+ Collection errors = errorNotificationManager.getErrors(); >+ for (Iterator iter = errors.iterator(); iter.hasNext();) { >+ ErrorInfo info = (ErrorInfo) iter.next(); >+ initButton( >+ errorImage, >+ ProgressMessages >+ .format( >+ "ProgressAnimationItem.error", new Object[] { info.getJob().getName() })); //$NON-NLS-1$ >+ return; >+ } >+ } > > if (animationRunning) { > initButton(noneImage, ProgressMessages >@@ -317,5 +338,12 @@ > refresh(); > } > }); >+ } >+ >+ /* >+ * Get the notificationManager that this is being created for. >+ */ >+ private ErrorNotificationManager getManager() { >+ return ProgressManager.getInstance().errorManager; > } > } >Index: Eclipse UI/org/eclipse/ui/internal/progress/ProgressManager.java >=================================================================== >RCS file: /home/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/ProgressManager.java,v >retrieving revision 1.97 >diff -u -r1.97 ProgressManager.java >--- Eclipse UI/org/eclipse/ui/internal/progress/ProgressManager.java 30 Aug 2004 20:11:08 -0000 1.97 >+++ Eclipse UI/org/eclipse/ui/internal/progress/ProgressManager.java 26 Oct 2004 19:50:40 -0000 >@@ -389,8 +389,7 @@ > JobInfo info = getJobInfo(event.getJob()); > if (event.getResult() != null > && event.getResult().getSeverity() == IStatus.ERROR) { >- errorManager.addError(event.getResult(), event.getJob() >- .getName()); >+ errorManager.addError(event.getResult(), event.getJob()); > } > jobs.remove(event.getJob()); > //Only refresh if we are showing it >Index: Eclipse UI/org/eclipse/ui/internal/progress/messages.properties >=================================================================== >RCS file: /home/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/messages.properties,v >retrieving revision 1.72 >diff -u -r1.72 messages.properties >--- Eclipse UI/org/eclipse/ui/internal/progress/messages.properties 23 Jun 2004 17:14:37 -0000 1.72 >+++ Eclipse UI/org/eclipse/ui/internal/progress/messages.properties 26 Oct 2004 19:50:40 -0000 >@@ -19,7 +19,7 @@ > JobInfo.Sleeping = {0} (Sleeping) > JobInfo.System = System: {0} > JobInfo.Cancelled = {0} (Cancelled) >-JobInfo.Error = {0} (Error: {1}) >+JobInfo.Error = {0} (Time of error: {1}) > JobInfo.Blocked = {0} (Blocked: {1}) > JobInfo.Finished = {0} (Finished) > JobInfo.FinishedAt = {0} (Finished at {1}) >Index: Eclipse UI/org/eclipse/ui/progress/IProgressConstants.java >=================================================================== >RCS file: /home/eclipse/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/progress/IProgressConstants.java,v >retrieving revision 1.7 >diff -u -r1.7 IProgressConstants.java >--- Eclipse UI/org/eclipse/ui/progress/IProgressConstants.java 8 Jul 2004 20:07:40 -0000 1.7 >+++ Eclipse UI/org/eclipse/ui/progress/IProgressConstants.java 26 Oct 2004 19:50:41 -0000 >@@ -48,8 +48,12 @@ > * set of kept Jobs. That is, whenever a Job that has the KEEPONE_PROPERTY starts or finishes, > * all other kept Jobs of the same family are removed first. > * <p> >- * Membership to family is established by implementing a Job's <code>belongsTo</code> >- * method and returning <code>true</code>. >+ * Membership to family is determined using a Job's <code>belongsTo</code> >+ * method. The progress service will pass each job that currently exists in the >+ * view to the <code>belongsTo</code> method of a newly added job. Clients who >+ * set the <code>KEEPONE_PROPERTY</code> must implement a <code>belongsTo</code> >+ * method that determines if the passed job is of the same family as their job >+ * and return <code>true</code> if it is. > * </p> > * <p> > * Please note that other Jobs of the same family are only removed if they have finished. >@@ -108,4 +112,16 @@ > */ > public static final QualifiedName PROPERTY_IN_DIALOG = new QualifiedName( > IProgressConstants.PROPERTY_PREFIX, "inDialog"); //$NON-NLS-1$ >+ >+ /** >+ * This property provides a hint to the progress UI to not prompt on errors >+ * immediatlybut instead make the errors available through the progress UI. >+ * <p> >+ * The property must be of type <code>Boolean</code> and the hint is used >+ * if its value is <code>true</code>. >+ * </p> >+ * @since 3.1 >+ */ >+ public static final QualifiedName NO_IMMEDIATE_ERROR_PROMPT_PROPERTY = new QualifiedName( >+ PROPERTY_PREFIX, "delayErrorPrompt"); //$NON-NLS-1$ > } >Index: Eclipse UI/org/eclipse/ui/internal/progress/JobErrorDialog.java >=================================================================== >RCS file: Eclipse UI/org/eclipse/ui/internal/progress/JobErrorDialog.java >diff -N Eclipse UI/org/eclipse/ui/internal/progress/JobErrorDialog.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ Eclipse UI/org/eclipse/ui/internal/progress/JobErrorDialog.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,471 @@ >+/******************************************************************************* >+ * Copyright (c) 2000, 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.net.URL; >+import java.util.*; >+ >+import org.eclipse.core.runtime.jobs.Job; >+import org.eclipse.jface.action.IAction; >+import org.eclipse.jface.dialogs.*; >+import org.eclipse.jface.dialogs.ErrorDialog; >+import org.eclipse.jface.dialogs.IDialogConstants; >+import org.eclipse.jface.preference.IPreferenceStore; >+import org.eclipse.jface.resource.ImageDescriptor; >+import org.eclipse.jface.viewers.*; >+import org.eclipse.swt.SWT; >+import org.eclipse.swt.graphics.*; >+import org.eclipse.swt.layout.GridData; >+import org.eclipse.swt.layout.GridLayout; >+import org.eclipse.swt.widgets.*; >+import org.eclipse.ui.internal.WorkbenchPlugin; >+import org.eclipse.ui.progress.IProgressConstants; >+ >+/** >+ * A dialog that can display the errors from multiple jobs at once >+ * but is visually optimal for the case of one job (which is the >+ * case 99% of the time). >+ */ >+public class JobErrorDialog extends ErrorDialog { >+ >+ /* >+ * Preference used to indicate whether the user should be prompted >+ * to confirm the execution of the job's goto action >+ */ >+ private static final String PREF_SKIP_GOTO_ACTION_PROMPT = "pref_skip_goto_action_prompt"; //$NON-NLS-1$ >+ >+ /* >+ * The id of the goto action button >+ */ >+ private static final int GOTO_ACTION_ID = IDialogConstants.CLIENT_ID + 1; >+ >+ private TableViewer jobListViewer; >+ private ErrorInfo selectedError; >+ >+ public JobErrorDialog(Shell parentShell, String title, String msg, ErrorInfo errorInfo, int displayMask) { >+ super(parentShell, title == null ? errorInfo.getJob().getName() : title, msg, errorInfo.getErrorStatus(), displayMask); >+ this.selectedError = errorInfo; >+ } >+ >+ private Composite createComposite(Composite parent, int numColumns) { >+ Composite composite = new Composite(parent, SWT.NONE); >+ 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 = numColumns; >+ composite.setLayout(layout); >+ GridData childData = new GridData(GridData.FILL_BOTH); >+ composite.setLayoutData(childData); >+ return composite; >+ } >+ >+ /** >+ * Method which should be invoked when new errors become available for display >+ */ >+ void refresh() { >+ if (isMultipleJobErrors()) { >+ if (jobListViewer == null && !dialogArea.isDisposed()) { >+ // The job list doesn't exist so create it. >+ setMessage("Multiple background operations have reported errors. Select an operation to view its errors."); >+ getShell().setText("Multiple Errors have Occurred"); >+ createJobListArea((Composite)dialogArea); >+ showDetailsArea(); >+ } >+ refreshJobList(); >+ } >+ updateEnablements(); >+ } >+ >+ /* (non-Javadoc) >+ * @see org.eclipse.jface.dialogs.ErrorDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) >+ */ >+ protected void createButtonsForButtonBar(Composite parent) { >+ IAction gotoAction = getGotoAction(); >+ String text = null; >+ if (gotoAction != null) { >+ text = gotoAction.getText(); >+ } >+ if (text == null) { >+ // Text is set to this initiallybut will be changed for active job >+ text = "Custom Job Action"; >+ } >+ createButton(parent, GOTO_ACTION_ID, text, false); >+ super.createButtonsForButtonBar(parent); >+ } >+ >+ /* >+ * Update the button enablements >+ */ >+ private void updateEnablements() { >+ Button details = getButton(IDialogConstants.DETAILS_ID); >+ if (details != null) { >+ details.setEnabled(selectedError.getErrorStatus().isMultiStatus() || isMultipleJobErrors()); >+ } >+ Button gotoButton = getButton(GOTO_ACTION_ID); >+ if (gotoButton != null) { >+ IAction gotoAction = getGotoAction(); >+ boolean hasValidGotoAction = gotoAction != null; >+ String text = gotoButton.getText(); >+ String newText = null; >+ if (hasValidGotoAction) { >+ newText = gotoAction.getText(); >+ } >+ if (newText == null) { >+ hasValidGotoAction = false; >+ newText = "Custom Job Action"; >+ } >+ if (!newText.equals(text)) { >+ gotoButton.setText(newText); >+ } >+ gotoButton.setEnabled(hasValidGotoAction); >+ gotoButton.setVisible(hasValidGotoAction); >+ } >+ } >+ >+ /* (non-Javadoc) >+ * @see org.eclipse.jface.dialogs.ErrorDialog#buttonPressed(int) >+ */ >+ protected void buttonPressed(int id) { >+ if (id == GOTO_ACTION_ID) { >+ IAction gotoAction = getGotoAction(); >+ if (gotoAction != null) { >+ if (!isMultipleJobErrors() || isPromptToClose()) { >+ okPressed(); // close the dialog >+ gotoAction.run(); // run the goto action >+ } >+ } >+ } >+ super.buttonPressed(id); >+ } >+ >+ >+ /* >+ * Prompt to inform the user that the dialog will close and the errors >+ * cleared. >+ */ >+ private boolean isPromptToClose() { >+ IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); >+ if (!store.contains(PREF_SKIP_GOTO_ACTION_PROMPT) || !store.getString(PREF_SKIP_GOTO_ACTION_PROMPT).equals(MessageDialogWithToggle.ALWAYS)) { >+ MessageDialogWithToggle dialog = MessageDialogWithToggle.openOkCancelConfirm(getShell(), "OK to Close?", >+ "Performing this action will close the error dialog and clear the errors being displayed.", >+ "Don't show this again", false, store, PREF_SKIP_GOTO_ACTION_PROMPT); >+ return dialog.getReturnCode() == OK; >+ } >+ return true; >+ } >+ >+ private IAction getGotoAction() { >+ Object property = selectedError.getJob().getProperty(IProgressConstants.ACTION_PROPERTY); >+ if (property instanceof IAction) >+ return (IAction)property; >+ return null; >+ } >+ >+ /** >+ * This method sets the message in the message label. >+ * >+ * @param messageString - >+ * the String for the message area >+ */ >+ private void setMessage(String messageString) { >+ //must not set null text in a label >+ message = messageString == null ? "" : messageString; //$NON-NLS-1$ >+ if (messageLabel == null || messageLabel.isDisposed()) >+ return; >+ messageLabel.setText(message); >+ } >+ >+ /* >+ * Create an area that allow the user to select one of multiple >+ * jobs that have reported errors >+ */ >+ private Control createJobListArea(Composite parent) { >+ Composite composite = createComposite(parent, 1); >+ >+ // Display a list of jobs that have reported errors >+ jobListViewer = new TableViewer(composite, SWT.SINGLE | SWT.H_SCROLL >+ | SWT.V_SCROLL | SWT.BORDER); >+ jobListViewer.setSorter(getViewerSorter()); >+ Control control = jobListViewer.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(); >+ jobListViewer.addSelectionChangedListener(new ISelectionChangedListener() { >+ public void selectionChanged(SelectionChangedEvent event) { >+ handleSelectionChange(); >+ } >+ }); >+ applyDialogFont(parent); >+ return composite; >+ } >+ >+ /* >+ * Return whether there are multiple errors to be displayed >+ */ >+ private boolean isMultipleJobErrors() { >+ return getManager().getErrors().size() > 1; >+ } >+ >+ /* >+ * Get the notificationManager that this is being created for. >+ */ >+ private ErrorNotificationManager getManager() { >+ return ProgressManager.getInstance().errorManager; >+ } >+ >+ public ErrorInfo getSelectedError() { >+ return selectedError; >+ } >+ >+ /** >+ * 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) >+ refreshJobList(); >+ } >+ }; >+ jobListViewer.setContentProvider(provider); >+ jobListViewer.setInput(getManager()); >+ jobListViewer.setSelection(new StructuredSelection(selectedError)); >+ } >+ >+ /** >+ * Refresh the contents of the viewer. >+ */ >+ void refreshJobList() { >+ if (jobListViewer != null && !jobListViewer.getControl().isDisposed()) { >+ jobListViewer.refresh(); >+ Point newSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT); >+ getShell().setSize(newSize); >+ } >+ setStatus(selectedError.getErrorStatus()); >+ } >+ >+ private void initLabelProvider() { >+ ITableLabelProvider provider = new ITableLabelProvider() { >+ Map imageTable = new HashMap(); >+ /* >+ * (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() { >+ if (!imageTable.isEmpty()) { >+ for (Iterator iter = imageTable.values().iterator(); iter.hasNext();) { >+ Image image = (Image) iter.next(); >+ image.dispose(); >+ } >+ } >+ } >+ >+ /* >+ * (non-Javadoc) >+ * >+ * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, >+ * int) >+ */ >+ public Image getColumnImage(Object element, int columnIndex) { >+ return getIcon(((ErrorInfo)element).getJob()); >+ } >+ >+ /* >+ * Get the icon for the job. Code copied from NewProgressViewer >+ */ >+ private Image getIcon(Job job) { >+ if (job != null) { >+ >+ Object property = job.getProperty(IProgressConstants.ICON_PROPERTY); >+ >+ // If we already have an image cached, return it >+ Image im = (Image)imageTable.get(property); >+ if (im != null) { >+ return im; >+ } >+ >+ // Create an image from the job's icon property or family >+ Display display = getShell().getDisplay(); >+ if (property instanceof ImageDescriptor) { >+ im = ((ImageDescriptor) property).createImage(display); >+ imageTable.put(property, im); // Cache for disposal >+ } else if (property instanceof URL) { >+ im = ImageDescriptor.createFromURL((URL) property) >+ .createImage(display); >+ imageTable.put(property, im); // Cache for disposal >+ } else { >+ im = ProgressManager.getInstance().getIconFor(job); >+ // No need to cache since the progress manager will >+ } >+ return im; >+ } >+ return null; >+ } >+ >+ /* >+ * (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 >+ } >+ }; >+ jobListViewer.setLabelProvider(provider); >+ } >+ >+ /** >+ * 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 = jobListViewer.getSelection(); >+ if (rawSelection != null >+ && rawSelection instanceof IStructuredSelection) { >+ IStructuredSelection selection = (IStructuredSelection) rawSelection; >+ if (selection.size() == 1) >+ return (ErrorInfo) selection.getFirstElement(); >+ } >+ return null; >+ } >+ >+ public boolean close() { >+ 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() { >+ // We need to refesh here instead of in createContents >+ // because the showDetailsArea requires that the content >+ // composite be set >+ refresh(); >+ super.initializeBounds(); >+ Rectangle shellPosition = getShell().getBounds(); >+ ProgressManagerUtil.animateUp(shellPosition); >+ } >+ >+ /** >+ * The selection in the multiple job list has changed. >+ * Update widget enablements and repopulate the list. >+ */ >+ void handleSelectionChange() { >+ ErrorInfo newSelection = getSingleSelection(); >+ if (newSelection != null && newSelection != selectedError) { >+ selectedError = newSelection; >+ setStatus(selectedError.getErrorStatus()); >+ updateEnablements(); >+ showDetailsArea(); >+ } >+ } >+ >+ /* (non-Javadoc) >+ * @see org.eclipse.jface.dialogs.ErrorDialog#isIncludeTopLevelErrorInDetails() >+ */ >+ protected boolean isIncludeTopLevelErrorInDetails() { >+ return isMultipleJobErrors(); >+ } >+ >+ /* (non-Javadoc) >+ * @see org.eclipse.jface.dialogs.ErrorDialog#isIncludeDetailsButton() >+ */ >+ protected boolean isIncludeDetailsButton() { >+ // Always include the deatils button since we may have errors added that have details >+ return true; >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 76726
:
15406
| 15407 |
15408