| /******************************************************************************* |
| * Copyright (c) 2000, 2006 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ui.internal.progress; |
| |
| import java.net.URL; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.dialogs.ErrorDialog; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.MessageDialogWithToggle; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| 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.StructuredSelection; |
| import org.eclipse.jface.viewers.TableViewer; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.jface.viewers.ViewerComparator; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.Point; |
| 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.Display; |
| import org.eclipse.swt.widgets.Shell; |
| 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; |
| |
| /** |
| * Create a new instance of the receiver. |
| * |
| * @param parentShell |
| * @param title |
| * @param msg |
| * @param errorInfo |
| * @param displayMask |
| */ |
| public JobErrorDialog(Shell parentShell, String title, String msg, |
| ErrorInfo errorInfo, int displayMask) { |
| super(parentShell, |
| title == null ? errorInfo.getJob().getName() : title, msg, |
| errorInfo.getErrorStatus(), displayMask); |
| setShellStyle(SWT.DIALOG_TRIM | SWT.MODELESS | SWT.RESIZE | SWT.MIN |
| | getDefaultOrientation()); // Do not want this one to be modal |
| this.selectedError = errorInfo; |
| setBlockOnOpen(false); |
| } |
| |
| /** |
| * Method which should be invoked when new errors become available for |
| * display |
| */ |
| void refresh() { |
| |
| if (AUTOMATED_MODE) { |
| return; |
| } |
| |
| // Do not refresh if we are in the process of |
| // opening or shutting down |
| if (dialogArea == null || dialogArea.isDisposed()) { |
| return; |
| } |
| |
| if (isMultipleJobErrors()) { |
| if (jobListViewer == null) { |
| // The job list doesn't exist so create it. |
| setMessage(ProgressMessages.JobErrorDialog_MultipleErrorsMessage); |
| getShell().setText( |
| ProgressMessages.JobErrorDialog_MultipleErrorsTitle); |
| 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 = ProgressMessages.JobErrorDialog_CustomJobText; |
| } |
| 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 = ProgressMessages.JobErrorDialog_CustomJobText; |
| } |
| 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(), |
| ProgressMessages.JobErrorDialog_CloseDialogTitle, |
| ProgressMessages.JobErrorDialog_CloseDialogMessage, |
| ProgressMessages.JobErrorDialog_DoNotShowAgainMessage, |
| 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 |
| * |
| * @param parent - |
| * the parent of the area |
| */ |
| private void createJobListArea(Composite parent) { |
| // Display a list of jobs that have reported errors |
| jobListViewer = new TableViewer(parent, SWT.SINGLE | SWT.H_SCROLL |
| | SWT.V_SCROLL | SWT.BORDER); |
| jobListViewer.setComparator(getViewerComparator()); |
| Control control = jobListViewer.getControl(); |
| GridData data = new GridData(GridData.FILL_BOTH |
| | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL); |
| data.heightHint = convertHeightInCharsToPixels(10); |
| control.setLayoutData(data); |
| initContentProvider(); |
| initLabelProvider(); |
| jobListViewer |
| .addSelectionChangedListener(new ISelectionChangedListener() { |
| public void selectionChanged(SelectionChangedEvent event) { |
| handleSelectionChange(); |
| } |
| }); |
| applyDialogFont(parent); |
| } |
| |
| /* |
| * 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; |
| } |
| |
| /** |
| * Return the selected error info. |
| * |
| * @return ErrorInfo |
| */ |
| public ErrorInfo getSelectedError() { |
| return selectedError; |
| } |
| |
| /** |
| * Return a viewer sorter for looking at the jobs. |
| * |
| * @return ViewerSorter |
| */ |
| private ViewerComparator getViewerComparator() { |
| return new ViewerComparator() { |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.viewers.ViewerComparator#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#shouldShowDetailsButton() |
| */ |
| protected boolean shouldShowDetailsButton() { |
| return true; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.dialogs.ErrorDialog#configureShell(org.eclipse.swt.widgets.Shell) |
| */ |
| protected void configureShell(Shell shell) { |
| super.configureShell(shell); |
| shell.addDisposeListener(new DisposeListener() { |
| /* (non-Javadoc) |
| * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent) |
| */ |
| public void widgetDisposed(org.eclipse.swt.events.DisposeEvent e) { |
| ProgressManager.getInstance().errorManager.dialogClosed(); |
| } |
| |
| }); |
| } |
| } |