blob: e0f70f47d9082fa17bbbe9d6859d9ca5b67be214 [file] [log] [blame]
/*******************************************************************************
* 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 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.markers.internal;
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.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.TrayDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Font;
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.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;
/**
* Shows the properties of a new or existing marker
*/
class DialogMarkerProperties extends TrayDialog {
/**
* The marker being shown, or <code>null</code> for a new marker
*/
private IMarker marker = null;
/**
* The resource on which to create a new marker
*/
private IResource resource = null;
/**
* The type of marker to be created
*/
private String type = IMarker.MARKER;
/**
* The initial attributes to use when creating a new marker
*/
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 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;
private String title;
/**
* Creates the dialog. By default this dialog creates a new marker.
* To set the resource and initial attributes for the new marker,
* use <code>setResource</code> and <code>setInitialAttributes</code>.
* To show or modify an existing marker, use <code>setMarker</code>.
*
* @param shell the parent shell
*/
DialogMarkerProperties(Shell parentShell) {
super(parentShell);
}
/**
* Creates the dialog. By default this dialog creates a new marker.
* To set the resource and initial attributes for the new marker,
* use <code>setResource</code> and <code>setInitialAttributes</code>.
* To show or modify an existing marker, use <code>setMarker</code>.
*
* @param shell the parent shell
* @param title the title of the dialog
*/
DialogMarkerProperties(Shell parentShell, String title) {
super(parentShell);
this.title = title;
}
/**
* @see org.eclipse.jface.window.Window#create()
*/
public void create() {
super.create();
}
/**
* Sets the marker to show or modify.
*
* @param marker the marker, or <code>null</code> to create a new marker
*/
void setMarker(IMarker marker) {
this.marker = marker;
if (marker != null) {
try {
type = marker.getType();
} catch (CoreException e) {
}
}
}
/**
* 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.
*/
IMarker getMarker() {
return marker;
}
/**
* Sets the resource to use when creating a new marker.
* If not set, the new marker is created on the workspace root.
*/
public void setResource(IResource resource) {
this.resource = resource;
}
/**
* Returns the resource to use when creating a new marker,
* or <code>null</code> if none has been set.
* If not set, the new marker is created on the workspace root.
*/
IResource getResource() {
return resource;
}
/**
* Sets initial attributes to use when creating a new marker.
* If not set, the new marker is created with default attributes.
*/
void setInitialAttributes(Map initialAttributes) {
this.initialAttributes = initialAttributes;
}
/**
* Returns the initial attributes to use when creating a new marker,
* or <code>null</code> if not set.
* If not set, the new marker is created with default attributes.
*/
Map getInitialAttributes() {
if (initialAttributes == null) {
initialAttributes = new HashMap();
}
return initialAttributes;
}
/**
* Method declared on Window.
*/
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
if (title == null)
newShell.setText(MarkerMessages.propertiesDialog_title);
else
newShell.setText(title);
}
/**
* Method declared on Dialog.
*/
protected Control createDialogArea(Composite parent) {
//initialize resources/properties
if (marker != null) {
resource = marker.getResource();
try {
initialAttributes = marker.getAttributes();
} catch (CoreException e) {
}
} else if (resource == null) {
resource = ResourcesPlugin.getWorkspace().getRoot();
}
Composite composite = (Composite) super.createDialogArea(parent);
initializeDialogUnits(composite);
createDescriptionArea(composite);
if (marker != null) {
createCreationTimeArea(composite);
}
createAttributesArea(composite);
if (resource != null)
createResourceArea(composite);
updateDialogFromMarker();
updateEnablement();
return composite;
}
/**
* Method createCreationTimeArea.
* @param parent
*/
private void createCreationTimeArea(Composite parent) {
String creation = MarkerMessages
.propertiesDialog_creationTime_text;
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(creation);
label.setFont(font);
creationTime = new Label(composite, SWT.NONE);
creationTime.setFont(font);
}
/**
* Creates the OK and Cancel buttons.
*/
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
true);
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);
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
composite.setLayoutData(gridData);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
composite.setLayout(layout);
Label label = new Label(composite, SWT.NONE);
label.setText(MarkerMessages.propertiesDialog_description_text);
label.setFont(font);
int style = SWT.SINGLE | SWT.BORDER;
descriptionText = new Text(composite, style);
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.widthHint = convertHorizontalDLUsToPixels(400);
descriptionText.setLayoutData(gridData);
descriptionText.setFont(font);
descriptionText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
markDirty();
}
});
}
/**
* This method is intended to be overridden by subclasses. The attributes area is created between
* the creation time area and the resource area.
*
* @param parent the parent composite
*/
protected void createAttributesArea(Composite parent) {
}
/**
* Creates the area for the Resource field.
*/
private void createResourceArea(Composite parent) {
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(MarkerMessages.propertiesDialog_resource_text);
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(MarkerMessages.propertiesDialog_folder_text);
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(MarkerMessages.propertiesDialog_location_text);
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.
*/
protected void updateDialogFromMarker() {
if (marker == null) {
updateDialogForNewMarker();
return;
}
descriptionText.setText(Util.getProperty(IMarker.MESSAGE, marker));
if (creationTime != null)
creationTime.setText(Util.getCreationTime(marker));
if (resourceText != null)
resourceText.setText(Util.getResourceName(marker));
if (folderText != null)
folderText.setText(Util.getContainerName(marker));
if (locationText != null) {
String line = Util.getProperty(IMarker.LINE_NUMBER, marker);
if (line.equals("")) //$NON-NLS-1$
locationText.setText(""); //$NON-NLS-1$
else
locationText.setText(NLS.bind(MarkerMessages.label_lineNumber, line));
}
descriptionText.selectAll();
}
/**
* Updates the dialog from the predefined attributes.
*/
protected void updateDialogForNewMarker() {
if (resource != null && resourceText != null && folderText != null) {
resourceText.setText(resource.getName());
IPath path = resource.getFullPath();
int n = path.segmentCount() - 1; // n is the number of segments in container, not path
if (n > 0) {
int len = 0;
for (int i = 0; i < n; ++i)
len += path.segment(i).length();
// account for /'s
if (n > 1)
len += n - 1;
StringBuffer sb = new StringBuffer(len);
for (int i = 0; i < n; ++i) {
if (i != 0)
sb.append('/');
sb.append(path.segment(i));
}
folderText.setText(sb.toString());
}
}
if (initialAttributes != null) {
Object description = initialAttributes.get(IMarker.MESSAGE);
if (description != null && description instanceof String)
descriptionText.setText((String) description);
descriptionText.selectAll();
Object line = initialAttributes.get(IMarker.LINE_NUMBER);
if (line != null && line instanceof Integer && locationText != null)
locationText.setText(
NLS.bind(MarkerMessages.label_lineNumber, line));
}
}
/**
* Method declared on Dialog
*/
protected void okPressed() {
if (marker == null || Util.isEditable(marker)) {
saveChanges();
}
super.okPressed();
}
/**
* Sets the dialog's dirty flag to <code>true</code>
*/
protected void markDirty() {
dirty = true;
}
/**
* @return
* <ul>
* <li><code>true</code> if the dirty flag has been set to true.</li>
* <li><code>false</code> otherwise.</li>
* </ul>
*/
protected boolean isDirty() {
return dirty;
}
/**
* Saves the changes made in the dialog if needed.
* Creates a new marker if needed.
* Updates the existing marker only if there have been changes.
*/
private void saveChanges() {
final CoreException[] coreExceptions = new CoreException[1];
try {
final Map attrs = getMarkerAttributes();
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 {
monitor.beginTask("", 100);//$NON-NLS-1$
ResourcesPlugin.getWorkspace().run(
new IWorkspaceRunnable() {
public void run(
IProgressMonitor monitor)
throws CoreException {
if (marker == null)
createMarker(monitor);
if (isDirty())
updateMarker(monitor, attrs);
}
}, monitor);
monitor.done();
} catch (CoreException e) {
coreExceptions[0] = e;
}
}
});
} catch (InvocationTargetException e) {
IDEWorkbenchPlugin.log(e.getMessage(), StatusUtil.newStatus(
IStatus.ERROR, e.getMessage(), e));
return;
}
catch (InterruptedException e) {
}
if (coreExceptions[0] != null)
ErrorDialog
.openError(
getShell(),
MarkerMessages.Error, null, coreExceptions[0].getStatus());
}
/**
* Creates or updates the marker. Must be called within a workspace runnable.
* @param monitor the monitor we report to.
* @param attrs the attributes from the dialog
*/
private void updateMarker(IProgressMonitor monitor, Map attrs)
throws CoreException {
// 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.
int increment = 50 / attrs.size();
for (Iterator i = attrs.keySet().iterator(); i.hasNext();) {
monitor.worked(increment);
String key = (String) i.next();
Object val = attrs.get(key);
marker.setAttribute(key, val);
}
}
/**
* Returns the marker attributes to save back to the marker,
* based on the current dialog fields.
*/
protected Map getMarkerAttributes() {
Map attrs;
if (initialAttributes == null) {
attrs = initialAttributes;
} else {
attrs = new HashMap();
}
attrs.put(IMarker.MESSAGE, descriptionText.getText());
return attrs;
}
/**
* Create the marker and report progress
* to the monitor.
* @param monitor
* @throws CoreException
*/
private void createMarker(IProgressMonitor monitor) throws CoreException {
if (resource == null)
return;
monitor.worked(10);
marker = resource.createMarker(type);
monitor.worked(40);
}
/**
* Updates widget enablement for the dialog. Should be overridden by subclasses.
*/
protected void updateEnablement() {
descriptionText.setEditable(isEditable());
}
/**
* @return
* <ul>
* <li><code>true</code> if the marker is editable or the dialog is creating a new marker.</li>
* <li><code>false</code> if the marker is not editable.</li>
* </ul>
*/
protected boolean isEditable() {
if (marker == null) {
return true;
}
return Util.isEditable(marker);
}
/**
* Sets the marker type when creating a new marker.
*
* @param type the marker type
*/
void setType(String type) {
this.type = type;
}
}