blob: bfffc43f15a598632b28e25b62e73258b0974b39 [file] [log] [blame]
/*******************************************************************************
* 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();
}
});
}
}