blob: 716f46ff0858115fa46f68ab6218aff25dfdeea7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 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.views.tasklist;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
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.operation.IRunnableWithProgress;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
import org.eclipse.ui.internal.ide.StatusUtil;
import org.eclipse.ui.internal.views.tasklist.TaskListMessages;
/**
* Shows the properties of a new or existing task, or a problem.
*/
public class TaskPropertiesDialog extends Dialog {
/**
* The task or problem being shown, or <code>null</code> for a new task.
*/
private IMarker marker = null;
/**
* The resource on which to create a new task.
*/
private IResource resource = null;
/**
* The initial attributes to use when creating a new task.
*/
private Map initialAttributes = null;
/**
* The text control for the Description field.
*/
private Text descriptionText;
/**
* The control for the Creation Time field.
*/
private Label creationTime;
/**
* The combo box control for the Priority field.
*/
private Combo priorityCombo;
/**
* The checkbox button for the Completed field.
*/
private Button completedCheckbox;
/**
* The control for the Severity field.
*/
private Label severityLabel;
/**
* The text control for the Resource field.
*/
private Text resourceText;
/**
* The text control for the Folder field.
*/
private Text folderText;
/**
* The text control for the Location field.
*/
private Text locationText;
/**
* Dirty flag. True if any changes have been made.
*/
private boolean dirty;
/**
* Creates the dialog. By default this dialog creates a new task.
* To set the resource and initial attributes for the new task,
* use <code>setResource</code> and <code>setInitialAttributes</code>.
* To show or modify an existing task, use <code>setMarker</code>.
*
* @param parentShell the parent shell
*/
public TaskPropertiesDialog(Shell parentShell) {
super(parentShell);
}
/**
* Sets the marker to show or modify.
*
* @param marker the marker, or <code>null</code> to create a new marker
*/
public void setMarker(IMarker marker) {
this.marker = marker;
}
/**
* Returns the marker being created or modified.
* For a new marker, this returns <code>null</code> until
* the dialog returns, but is non-null after.
*
* @return the marker
*/
public IMarker getMarker() {
return marker;
}
/**
* Sets the resource to use when creating a new task.
* If not set, the new task is created on the workspace root.
*
* @param resource the resource
*/
public void setResource(IResource resource) {
this.resource = resource;
}
/**
* Returns the resource to use when creating a new task,
* or <code>null</code> if none has been set.
* If not set, the new task is created on the workspace root.
*
* @return the resource
*/
public IResource getResource() {
return resource;
}
/**
* Sets initial attributes to use when creating a new task.
* If not set, the new task is created with default attributes.
*
* @param initialAttributes the initial attributes
*/
public void setInitialAttributes(Map initialAttributes) {
this.initialAttributes = initialAttributes;
}
/**
* Returns the initial attributes to use when creating a new task,
* or <code>null</code> if not set.
* If not set, the new task is created with default attributes.
*
* @return the initial attributes
*/
public Map getInitialAttributes() {
return initialAttributes;
}
/* (non-Javadoc)
* Method declared on Window.
*/
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
if (marker == null) {
newShell.setText(TaskListMessages.TaskProp_newTaskTitle);
} else {
String kind = MarkerUtil.getKindText(marker);
newShell.setText(NLS.bind(TaskListMessages.TaskProp_propertiesTitle, kind));
}
PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell,
ITaskListHelpContextIds.PROPERTIES_DIALOG);
}
/* (non-Javadoc)
* Method declared on Dialog.
*/
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
initializeDialogUnits(composite);
createDescriptionArea(composite);
if (marker != null)
createCreationTimeArea(composite);
if (isTask()) {
createPriorityAndStatusArea(composite);
} else {
createSeverityArea(composite);
}
createResourceArea(composite);
updateDialogFromMarker();
return composite;
}
/**
* Method createCreationTimeArea.
*
* @param parent the parent
*/
private void createCreationTimeArea(Composite parent) {
Font font = parent.getFont();
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
composite.setLayout(layout);
Label label = new Label(composite, SWT.NONE);
label.setText(TaskListMessages.TaskProp_creationTime);
label.setFont(font);
creationTime = new Label(composite, SWT.NONE);
creationTime.setFont(font);
}
/**
* Creates only the OK button if showing problem properties, otherwise creates
* both OK and Cancel buttons.
*/
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
true);
if (isEditable()) {
createButton(parent, IDialogConstants.CANCEL_ID,
IDialogConstants.CANCEL_LABEL, false);
}
}
/**
* Creates the area for the Description field.
*/
private void createDescriptionArea(Composite parent) {
Font font = parent.getFont();
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
composite.setLayout(layout);
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
composite.setLayoutData(gridData);
Label label = new Label(composite, SWT.NONE);
label.setText(TaskListMessages.TaskProp_description);
label.setFont(font);
int style = SWT.SINGLE | SWT.BORDER;
if (!isEditable()) {
style |= SWT.READ_ONLY;
}
descriptionText = new Text(composite, style);
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.widthHint = convertHorizontalDLUsToPixels(400);
descriptionText.setLayoutData(gridData);
descriptionText.setFont(font);
}
/**
* Creates the area for the Priority and Status fields.
*/
private void createPriorityAndStatusArea(Composite parent) {
Font font = parent.getFont();
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 3;
composite.setLayout(layout);
Label label = new Label(composite, SWT.NONE);
label.setText(TaskListMessages.TaskProp_priority);
label.setFont(font);
priorityCombo = new Combo(composite, SWT.READ_ONLY);
priorityCombo.setItems(new String[] {
TaskListMessages.TaskList_high,
TaskListMessages.TaskList_normal,
TaskListMessages.TaskList_low
});
// Prevent Esc and Return from closing the dialog when the combo is active.
priorityCombo.addTraverseListener(new TraverseListener() {
public void keyTraversed(TraverseEvent e) {
if (e.detail == SWT.TRAVERSE_ESCAPE
|| e.detail == SWT.TRAVERSE_RETURN) {
e.doit = false;
}
}
});
priorityCombo.setFont(font);
completedCheckbox = new Button(composite, SWT.CHECK);
completedCheckbox.setText(TaskListMessages.TaskProp_completed);
GridData gridData = new GridData();
gridData.horizontalIndent = convertHorizontalDLUsToPixels(20);
completedCheckbox.setLayoutData(gridData);
completedCheckbox.setFont(font);
if (!isEditable()) {
priorityCombo.setEnabled(false);
completedCheckbox.setEnabled(false);
}
}
/**
* Creates the area for the Severity field.
*/
private void createSeverityArea(Composite parent) {
Font font = parent.getFont();
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
composite.setLayout(layout);
Label label = new Label(composite, SWT.NONE);
label.setText(TaskListMessages.TaskProp_severity);
label.setFont(font);
// workaround for bug 11078: Can't get a read-only combo box
severityLabel = new Label(composite, SWT.NONE);
severityLabel.setFont(font);
/*
severityCombo = new Combo(composite, SWT.READ_ONLY);
severityCombo.setItems(new String[] {
TaskListMessages.getString("TaskList.error"), //$NON-NLS-1$
TaskListMessages.getString("TaskList.warning"), //$NON-NLS-1$
TaskListMessages.getString("TaskList.info") //$NON-NLS-1$
});
*/
}
/**
* Creates the area for the Resource field.
*/
private void createResourceArea(Composite parent) {
IResource resource = getResource();
if (marker == null) {
if (resource == null)
return;
if ((resource.getType() & (IResource.FILE | IResource.FOLDER | IResource.PROJECT)) == 0)
return;
}
Font font = parent.getFont();
Composite composite = new Composite(parent, SWT.NONE);
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
composite.setLayoutData(gridData);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
composite.setLayout(layout);
Label resourceLabel = new Label(composite, SWT.NONE);
resourceLabel
.setText(TaskListMessages.TaskProp_onResource);
resourceLabel.setFont(font);
resourceText = new Text(composite, SWT.SINGLE | SWT.WRAP
| SWT.READ_ONLY | SWT.BORDER);
gridData = new GridData(GridData.FILL_HORIZONTAL);
resourceText.setLayoutData(gridData);
resourceText.setFont(font);
Label folderLabel = new Label(composite, SWT.NONE);
folderLabel.setText(TaskListMessages.TaskProp_inFolder);
folderLabel.setFont(font);
folderText = new Text(composite, SWT.SINGLE | SWT.WRAP | SWT.READ_ONLY
| SWT.BORDER);
gridData = new GridData(GridData.FILL_HORIZONTAL);
folderText.setLayoutData(gridData);
folderText.setFont(font);
Label locationLabel = new Label(composite, SWT.NONE);
locationLabel.setText(TaskListMessages.TaskProp_location);
locationLabel.setFont(font);
locationText = new Text(composite, SWT.SINGLE | SWT.WRAP
| SWT.READ_ONLY | SWT.BORDER);
gridData = new GridData(GridData.FILL_HORIZONTAL);
locationText.setLayoutData(gridData);
locationText.setFont(font);
}
/**
* Updates the dialog from the marker state.
*/
private void updateDialogFromMarker() {
if (marker == null) {
updateDialogForNewMarker();
return;
}
descriptionText.setText(MarkerUtil.getMessage(marker));
descriptionText.selectAll();
creationTime.setText(MarkerUtil.getCreationTime(marker));
if (isTask()) {
priorityCombo.clearSelection();
priorityCombo.select(IMarker.PRIORITY_HIGH
- MarkerUtil.getPriority(marker));
completedCheckbox.setSelection(MarkerUtil.isComplete(marker));
markDirty();
} else {
/* workaround for bug 11078: Can't get a read-only combo box
severityCombo.clearSelection();
severityCombo.select(IMarker.SEVERITY_ERROR - MarkerUtil.getSeverity(marker));
*/
String sev = ""; //$NON-NLS-1$
switch (MarkerUtil.getSeverity(marker)) {
case IMarker.SEVERITY_ERROR:
sev = TaskListMessages.TaskList_error;
break;
case IMarker.SEVERITY_WARNING:
sev = TaskListMessages.TaskList_warning;
break;
case IMarker.SEVERITY_INFO:
sev = TaskListMessages.TaskList_info;
break;
}
severityLabel.setText(sev);
}
resourceText.setText(MarkerUtil.getResourceName(marker));
folderText.setText(MarkerUtil.getContainerName(marker));
locationText.setText(MarkerUtil.getLineAndLocation(marker));
}
/**
* Updates the dialog to reflect the state for a new marker.
*/
private void updateDialogForNewMarker() {
Map attrs = getInitialAttributes();
String desc = ""; //$NON-NLS-1$
if (attrs != null) {
Object o = attrs.get(IMarker.MESSAGE);
if (o instanceof String) {
desc = (String) o;
}
}
descriptionText.setText(desc);
descriptionText.selectAll();
int pri = IMarker.PRIORITY_NORMAL;
if (attrs != null) {
Object o = attrs.get(IMarker.PRIORITY);
if (o instanceof Integer) {
int val = ((Integer) o).intValue();
if (val >= IMarker.PRIORITY_LOW && val <= IMarker.PRIORITY_HIGH) {
pri = val;
}
}
}
priorityCombo.deselectAll();
priorityCombo.select(IMarker.PRIORITY_HIGH - pri);
boolean completed = false;
if (attrs != null) {
Object o = attrs.get(IMarker.DONE);
if (o instanceof Boolean) {
completed = ((Boolean) o).booleanValue();
}
}
completedCheckbox.setSelection(completed);
IResource resource = getResource();
if (resource != null && resourceText != null) {
resourceText.setText(resource.getName());
IResource parent = resource.getParent();
folderText
.setText(parent == null ? "" : parent.getFullPath().toString().substring(1)); //$NON-NLS-1$
}
int line = -1;
String loc = ""; //$NON-NLS-1$
if (attrs != null) {
Object o = attrs.get(IMarker.LINE_NUMBER);
if (o instanceof Integer) {
line = ((Integer) o).intValue();
}
o = attrs.get(IMarker.LOCATION);
if (o instanceof String) {
loc = (String) o;
}
}
if (locationText != null)
locationText.setText(MarkerUtil.getLineAndLocation(line, loc));
markDirty();
return;
}
/* (non-Javadoc)
* Method declared on Dialog
*/
protected void okPressed() {
saveChanges();
super.okPressed();
}
private void markDirty() {
dirty = true;
}
private boolean isDirty() {
return dirty;
}
/**
* Returns whether the marker is editable.
*/
private boolean isEditable() {
return marker == null || MarkerUtil.isEditable(marker);
}
/**
* Returns <code>true</code> if a task is being created or modified.
* Returns <code>false</code> if a problem is being shown.
*/
private boolean isTask() {
return marker == null || MarkerUtil.isMarkerType(marker, IMarker.TASK);
}
/**
* Saves the changes made in the dialog if needed.
* Creates a new task if needed.
* Updates the existing task only if there have been changes.
* Does nothing for problems, since they cannot be modified.
*/
private void saveChanges() {
if (!isEditable() || !isDirty())
return;
final CoreException[] coreExceptions = new CoreException[1];
final Map attrs = getMarkerAttributesFromDialog();
try {
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(
new IRunnableWithProgress() {
/* (non-Javadoc)
* @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor)
*/
public void run(IProgressMonitor monitor)
throws InvocationTargetException,
InterruptedException {
try {
IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
/* (non-Javadoc)
* @see org.eclipse.core.resources.IWorkspaceRunnable#run(org.eclipse.core.runtime.IProgressMonitor)
*/
public void run(IProgressMonitor monitor)
throws CoreException {
createOrUpdateMarker(monitor, attrs);
}
};
ResourcesPlugin.getWorkspace().run(runnable,
monitor);
} catch (CoreException e) {
coreExceptions[0] = e;
}
}
});
} catch (InvocationTargetException e) {
IDEWorkbenchPlugin.log(e.getMessage(), StatusUtil.newStatus(
IStatus.ERROR, e.getMessage(), e));
return;
}
catch (InterruptedException e) {
IDEWorkbenchPlugin.log(e.getMessage(), StatusUtil.newStatus(
IStatus.ERROR, e.getMessage(), e));
return;
}
if (coreExceptions[0] != null)
ErrorDialog.openError(getShell(), TaskListMessages.TaskProp_errorMessage,
null, coreExceptions[0].getStatus());
}
/**
* Creates or updates the marker. Must be called within a workspace runnable.
* @param monitor The monitor to report to.
* @param attrs The atrributes entered from the dialog.
* @throws CoreException
*/
private void createOrUpdateMarker(IProgressMonitor monitor, Map attrs)
throws CoreException {
monitor.beginTask(TaskListMessages.TaskPropertiesDialog_WorkingOnMarker, 100);
if (marker == null) {
monitor.subTask(TaskListMessages.TaskPropertiesDialog_CreatingMarker);
IResource resource = getResource();
if (resource == null) {
resource = ResourcesPlugin.getWorkspace().getRoot();
}
monitor.worked(25);
marker = resource.createMarker(IMarker.TASK);
Map initialAttrs = getInitialAttributes();
if (initialAttrs != null) {
marker.setAttributes(initialAttrs);
}
monitor.worked(25);
} else
monitor.worked(50);
// Set the marker attributes from the current dialog field values.
// Do not use setAttributes(Map) as that overwrites any attributes
// not covered by the dialog.
monitor.subTask(TaskListMessages.TaskPropertiesDialog_UpdatingAttributes);
int increment = 50 / attrs.keySet().size();
for (Iterator i = attrs.keySet().iterator(); i.hasNext();) {
String key = (String) i.next();
Object val = attrs.get(key);
marker.setAttribute(key, val);
monitor.worked(increment);
}
monitor.done();
}
/**
* Returns the marker attributes to save back to the marker,
* based on the current dialog fields.
*/
private Map getMarkerAttributesFromDialog() {
Map attribs = new HashMap(11);
if (isTask()) {
attribs.put(IMarker.MESSAGE, descriptionText.getText());
int i = priorityCombo.getSelectionIndex();
if (i != -1) {
attribs.put(IMarker.PRIORITY, new Integer(IMarker.PRIORITY_HIGH
- i));
}
attribs.put(IMarker.DONE,
completedCheckbox.getSelection() ? Boolean.TRUE
: Boolean.FALSE);
}
return attribs;
}
}