blob: 067c23d0525443f933d6af496e01dc35b7ccbc8e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2012 Red Hat, Inc.
* All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
*
* @author Bob Brodt
******************************************************************************/
package org.eclipse.bpmn2.modeler.core.merrimac.dialogs;
import org.eclipse.bpmn2.modeler.core.ToolTipProvider;
import org.eclipse.bpmn2.modeler.core.adapters.ExtendedPropertiesAdapter;
import org.eclipse.bpmn2.modeler.core.merrimac.DefaultBusinessObjectDelegate;
import org.eclipse.bpmn2.modeler.core.merrimac.IBusinessObjectDelegate;
import org.eclipse.bpmn2.modeler.core.merrimac.IConstants;
import org.eclipse.bpmn2.modeler.core.merrimac.clad.AbstractDetailComposite;
import org.eclipse.bpmn2.modeler.core.utils.ErrorUtils;
import org.eclipse.bpmn2.modeler.core.utils.ModelUtil;
import org.eclipse.bpmn2.modeler.core.validation.ValidationStatusAdapter;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.provider.INotifyChangedListener;
import org.eclipse.emf.validation.model.ConstraintStatus;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.graphiti.ui.editor.DiagramEditor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.FormToolkit;
/**
* Base class for EObject feature editors. All subclasses must render the given object's feature,
* which may be either an attribute, a reference to an EObject, or a list of EObject references.
* Subclasses must also provide means to populate the display widgets from the feature and save
* modifications to the feature made in the display widget.
*
* @author Bob Brodt
*/
public abstract class ObjectEditor implements INotifyChangedListener {
public static int ID_CREATE_BUTTON = 1;
public static int ID_EDIT_BUTTON = 2;
public static int ID_DELETE_BUTTON = 3;
public static int ID_OTHER_BUTTONS = 4;
protected EObject object;
protected EStructuralFeature feature;
protected AbstractDetailComposite parent;
private Label label;
protected ControlDecoration decoration;
protected int style;
protected boolean isWidgetUpdating = false;
private IBusinessObjectDelegate boDelegate;
private boolean valueChanged = false;
public ObjectEditor(AbstractDetailComposite parent, EObject object, EStructuralFeature feature) {
this.parent = parent;
this.object = object;
this.feature = feature;
this.style = SWT.NONE;
}
/**
* This must be implemented by the ObjectEditor subclasses and should not be made public - clients
* should use one of the public createControl() methods instead so that the notifyChange listeners
* are hooked in to the change notification chain.
*
* @param composite - parent composite for this ObjectEditor control
* @param label - a text label displayed to the left of the control
* @param style - editor control SWT style flags
* @return the control created by the ObjectEditor subclasses (e.g. a Text, or Combo)
*/
protected abstract Control createControl(Composite composite, String label, int style);
public void setStyle(int style) {
this.style = style;
}
public Control createControl(Composite composite, String label) {
final Control c = createControl(composite,label,style);
c.setData(IConstants.NOTIFY_CHANGE_LISTENER_KEY, this);
c.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
valueChanged = false;
}
@Override
public void focusLost(FocusEvent e) {
if (valueChanged) {
IStatus status = parent.validate();
if (status.getSeverity() >= Status.ERROR) {
if (statusApplies(status)) {
MessageDialog.openError(parent.getShell(), Messages.ObjectEditor_Validation_Error_Title, status.getMessage());
if (!c.isDisposed())
c.setFocus();
}
}
}
ErrorUtils.showErrorMessage(null);
}
});
return c;
}
public Control createControl(String label) {
return createControl(parent,label);
}
public IBusinessObjectDelegate getBusinessObjectDelegate() {
if (boDelegate==null)
boDelegate = new DefaultBusinessObjectDelegate(getDiagramEditor().getEditingDomain());
return boDelegate;
}
protected Object getExtendedProperty(String property) {
Object result = null;
ExtendedPropertiesAdapter adapter = ExtendedPropertiesAdapter.adapt(object);
if (adapter!=null && feature!=null) {
result = adapter.getProperty(feature, property);
}
return result;
}
protected void setExtendedProperty(String property, Object value) {
ExtendedPropertiesAdapter adapter = ExtendedPropertiesAdapter.adapt(object);
if (adapter!=null && feature!=null) {
adapter.setProperty(feature, property, value);
}
}
public EStructuralFeature getFeature() {
return feature;
}
public EObject getObject() {
return object;
}
public void setObject(EObject object) {
this.object = object;
}
public void setObject(EObject object, EStructuralFeature feature) {
this.object = object;
this.feature = feature;
}
protected FormToolkit getToolkit() {
return parent.getToolkit();
}
protected DiagramEditor getDiagramEditor() {
return parent.getDiagramEditor();
}
protected Diagram getDiagram() {
return getDiagramEditor().getDiagramTypeProvider().getDiagram();
}
protected Label createLabel(Composite parent, String name) {
label = getToolkit().createLabel(parent, name);
label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
updateLabelDecorator();
return label;
}
public Label getLabel() {
return label;
}
private boolean statusApplies(IStatus status) {
if (status instanceof ConstraintStatus) {
ConstraintStatus cs = (ConstraintStatus)status;
for (EObject f : cs.getResultLocus()) {
if (f instanceof EStructuralFeature && f==this.feature) {
return true;
}
}
}
return false;
}
protected FeatureEditingDialog createFeatureEditingDialog(EObject value) {
FeatureEditingDialog dialog = new FeatureEditingDialog(getDiagramEditor(), object, feature, value) {
public void aboutToOpen() {
// Pass the container object along to the dialog so that
// it can be set in its detail composites. This is used
// if a detail composite needs to display additional information
// depending on what type of referencing object created the
// feature editing dialog.
dialogContent.setData("container", object);
super.aboutToOpen();
}
};
return dialog;
}
/**
* Returns a descriptive text string for use as a tooltip on the Label for this editor.
* The default implementation constructs a key from the object and feature name owned by this
* editor, and looks up the description text in the messages resource of the parent plugin.
*
* @return
*/
protected String getToolTipText() {
String text = (String) getExtendedProperty(ExtendedPropertiesAdapter.LONG_DESCRIPTION);
if (text==null || text.isEmpty())
text = ToolTipProvider.INSTANCE.getToolTip(parent, object, feature);
if (text==null || text.isEmpty())
text = NLS.bind(Messages.ObjectEditor_No_Description, label.getText());
setExtendedProperty(ExtendedPropertiesAdapter.LONG_DESCRIPTION, text);
return text;
}
/**
* Updates the error decorators and tooltips of this editor's Label widget.
*/
protected void updateLabelDecorator() {
if (label!=null && !label.isDisposed()) {
String tooltip = label.getToolTipText();
if (tooltip==null && object!=null && feature!=null) {
label.setToolTipText(getToolTipText());
}
boolean applies = false;
String text = null;
String image = null;
if (isVisible()) {
ValidationStatusAdapter statusAdapter = (ValidationStatusAdapter) EcoreUtil.getRegisteredAdapter(
object, ValidationStatusAdapter.class);
if (statusAdapter != null) {
final IStatus status = statusAdapter.getValidationStatus();
// System.out.println(status.getMessage());
if (status.isMultiStatus()) {
for (IStatus s : status.getChildren()) {
if (statusApplies(s)) {
applies = true;
break;
}
}
}
else if (statusApplies(status))
applies = true;
if (applies) {
text = status.getMessage();
switch (status.getSeverity()) {
case IStatus.INFO:
image = ISharedImages.IMG_OBJS_INFO_TSK;
break;
case IStatus.WARNING:
image = ISharedImages.IMG_DEC_FIELD_WARNING;
break;
case IStatus.ERROR:
image = ISharedImages.IMG_DEC_FIELD_ERROR;
break;
default:
break;
}
}
}
}
if (applies) {
if (decoration==null) {
decoration = new ControlDecoration(label, SWT.TOP | SWT.LEFT);
}
decoration.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(image));
decoration.show();
decoration.setDescriptionText(text);
}
else {
if (decoration!=null) {
decoration.hide();
decoration.dispose();
decoration = null;
}
}
}
}
public boolean setValue(final Object result) {
boolean success = getBusinessObjectDelegate().setValue(object, feature, result);
if (!success) {
showErrorMessage(
NLS.bind(
Messages.ObjectEditor_Set_Error_Message,
new Object[] {
getBusinessObjectDelegate().getTextValue(object),
getBusinessObjectDelegate().getLabel(object,feature),
ModelUtil.getTextValue(result)
}
)
);
return false;
}
valueChanged = true;
return true;
}
protected void showErrorMessage(String message) {
ErrorUtils.showErrorMessage(message);
}
public abstract Object getValue();
@Override
public void notifyChanged(Notification notification) {
updateLabelDecorator();
}
public void setVisible(boolean visible) {
label.setVisible(visible);
GridData data = (GridData)label.getLayoutData();
data.exclude = !visible;
updateLabelDecorator();
}
public boolean isVisible() {
return label.isVisible();
}
public void dispose() {
if (label!=null && !label.isDisposed()) {
label.dispose();
label = null;
}
if (decoration!=null) {
decoration.hide();
decoration.dispose();
decoration = null;
}
}
public Control getControl() {
return label;
}
protected boolean isMultiLineText() {
return getBusinessObjectDelegate().isMultiLineText(object,feature);
}
protected boolean canEdit() {
return getBusinessObjectDelegate().canEdit(object,feature);
}
protected boolean canCreateNew() {
return getBusinessObjectDelegate().canCreateNew(object,feature);
}
protected boolean canEditInline() {
return getBusinessObjectDelegate().canEditInline(object,feature);
}
protected boolean canSetNull() {
return getBusinessObjectDelegate().canSetNull(object,feature);
}
protected boolean canAdd() {
return false;
}
protected boolean canRemove() {
return false;
}
public void setEditable(boolean editable) {
Control control = getControl();
if (control instanceof Text) {
((Text)control).setEditable(editable);
control.setBackground(control.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
control.setForeground(control.getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND));
control.setData(AbstractObjectEditingDialog.DO_NOT_ADAPT, Boolean.TRUE);
}
}
}