/******************************************************************************* | |
* Copyright (c) 2011 Formal Mind GmbH and University of Dusseldorf. | |
* 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: | |
* Michael Jastram - initial API and implementation | |
* Lukas Ladenberger - ProR GUI | |
******************************************************************************/ | |
package org.eclipse.rmf.reqif10.pror.editor.propertiesview; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.Collection; | |
import java.util.List; | |
import org.agilemore.agilegrid.AgileGrid; | |
import org.agilemore.agilegrid.CellEditor; | |
import org.agilemore.agilegrid.ICellEditorValidator; | |
import org.eclipse.emf.common.notify.AdapterFactory; | |
import org.eclipse.emf.common.util.Diagnostic; | |
import org.eclipse.emf.ecore.EClassifier; | |
import org.eclipse.emf.ecore.EDataType; | |
import org.eclipse.emf.ecore.EReference; | |
import org.eclipse.emf.ecore.EStructuralFeature; | |
import org.eclipse.emf.ecore.util.Diagnostician; | |
import org.eclipse.emf.ecore.util.EcoreUtil; | |
import org.eclipse.emf.edit.domain.EditingDomain; | |
import org.eclipse.emf.edit.provider.IItemLabelProvider; | |
import org.eclipse.emf.edit.provider.IItemPropertyDescriptor; | |
import org.eclipse.emf.edit.provider.ItemPropertyDescriptor.PropertyValueWrapper; | |
import org.eclipse.emf.edit.provider.ItemProviderAdapter; | |
import org.eclipse.emf.edit.ui.EMFEditUIPlugin; | |
import org.eclipse.emf.edit.ui.celleditor.FeatureEditorDialog; | |
import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry; | |
import org.eclipse.jface.dialogs.IInputValidator; | |
import org.eclipse.jface.dialogs.InputDialog; | |
import org.eclipse.jface.viewers.ILabelProvider; | |
import org.eclipse.jface.viewers.LabelProvider; | |
import org.eclipse.jface.window.Window; | |
import org.eclipse.rmf.reqif10.AttributeValue; | |
import org.eclipse.rmf.reqif10.SpecElementWithAttributes; | |
import org.eclipse.rmf.reqif10.SpecHierarchy; | |
import org.eclipse.rmf.reqif10.pror.configuration.ProrPresentationConfiguration; | |
import org.eclipse.rmf.reqif10.pror.editor.agilegrid.AbstractProrCellEditorProvider; | |
import org.eclipse.rmf.reqif10.pror.editor.presentation.service.PresentationEditorInterface; | |
import org.eclipse.rmf.reqif10.pror.editor.presentation.service.PresentationServiceManager; | |
import org.eclipse.rmf.reqif10.pror.editor.propertiesview.ProrPropertyContentProvider.Descriptor; | |
import org.eclipse.rmf.reqif10.pror.editor.propertiesview.ProrPropertyContentProvider.PropertyRow; | |
import org.eclipse.rmf.reqif10.pror.util.ConfigurationUtil; | |
import org.eclipse.rmf.reqif10.pror.util.PresentationEditInterface; | |
import org.eclipse.rmf.reqif10.pror.util.ProrUtil; | |
import org.eclipse.swt.SWT; | |
import org.eclipse.swt.graphics.Image; | |
import org.eclipse.swt.widgets.Control; | |
import org.eclipse.swt.widgets.Shell; | |
/** | |
* The cell editor provider for the properties view. | |
* | |
* @author Lukas Ladenberger | |
* @author Michael Jastram | |
*/ | |
public class ProrPropertyCellEditorProvider extends AbstractProrCellEditorProvider { | |
private final ProrPropertyContentProvider contentProvider; | |
public ProrPropertyCellEditorProvider(AgileGrid agileGrid, | |
AdapterFactory adapterFactory, EditingDomain editingDomain, | |
ProrPropertyContentProvider contentProvider) { | |
super(agileGrid, adapterFactory, editingDomain); | |
this.contentProvider = contentProvider; | |
} | |
@Override | |
public Object getValue(int row, int col) { | |
PropertyRow propertyRow = contentProvider.getRowContent(row); | |
if (propertyRow instanceof Descriptor) { | |
Descriptor descriptor = ((Descriptor) propertyRow); | |
if (descriptor.isRMFSpecific()) { | |
return descriptor.getAttributeValue(); | |
} else { | |
Object target = contentProvider.getElement(); | |
PropertyValueWrapper wrapper = (PropertyValueWrapper) descriptor | |
.getItemPropertyDescriptor().getPropertyValue(target); | |
Object content = descriptor.getContent(col); | |
return wrapper == null ? null : wrapper | |
.getEditableValue(content); | |
} | |
} else { | |
return propertyRow.getContent(col); | |
} | |
} | |
@Override | |
protected AttributeValue getAttributeValue(int row, int col) { | |
PropertyRow propertyRow = contentProvider.getRowContent(row); | |
if (propertyRow instanceof Descriptor) { | |
return ((Descriptor) propertyRow).getAttributeValue(); | |
} | |
return null; | |
} | |
@Override | |
public boolean canEdit(int row, int col) { | |
AttributeValue av = getAttributeValue(row, col); | |
// If we have an attribute value, use default method in extended class | |
if (av != null) { | |
// Consult the presentation | |
ProrPresentationConfiguration config = ConfigurationUtil | |
.getPresentationConfiguration(av); | |
if (config != null) { | |
ItemProviderAdapter ip = ProrUtil.getItemProvider( | |
adapterFactory, config); | |
if (ip instanceof PresentationEditInterface) { | |
return ((PresentationEditInterface) ip).canEdit(); | |
} | |
} | |
} else { | |
// Else we have an EMF specific attribute use the corresponding | |
// method of the item property descriptor | |
PropertyRow propertyRow = contentProvider.getRowContent(row); | |
if (propertyRow instanceof Descriptor) { | |
return ((Descriptor) propertyRow).getItemPropertyDescriptor() | |
.canSetProperty(contentProvider.getElement()); | |
} | |
} | |
return true; | |
} | |
@Override | |
public CellEditor getCellEditor(int row, int col, Object hint) { | |
// Get the correct celleditor | |
PropertyRow propertyRow = contentProvider.getRowContent(row); | |
SpecElementWithAttributes specElement; | |
if (contentProvider.getElement() instanceof SpecHierarchy) { | |
specElement = ((SpecHierarchy) contentProvider.getElement()) | |
.getObject(); | |
} else if (contentProvider.getElement() instanceof SpecElementWithAttributes) { | |
specElement = (SpecElementWithAttributes) contentProvider | |
.getElement(); | |
} else { | |
specElement = null; | |
} | |
AttributeValue attrValue = getAttributeValue(row, col); | |
CellEditor cellEditor = null; | |
// If the attribute is a reqif attribute (an attribute value exists), | |
// when try to get the presentation service | |
if (attrValue != null) { | |
// Ask Presentation | |
ProrPresentationConfiguration config = ConfigurationUtil | |
.getPresentationConfiguration(attrValue); | |
if (config != null) { | |
ItemProviderAdapter ip = ProrUtil.getItemProvider( | |
adapterFactory, config); | |
if (ip instanceof PresentationEditorInterface) { | |
cellEditor = ((PresentationEditorInterface) ip) | |
.getCellEditor(agileGrid, editingDomain, attrValue, | |
specElement, getAffectedElement(row, col)); | |
} | |
} | |
// See whether there is a default editor | |
if (cellEditor == null) { | |
cellEditor = PresentationServiceManager.getDefaultCellEditor( | |
agileGrid, editingDomain, adapterFactory, attrValue, | |
specElement, getAffectedElement(row, col)); | |
} | |
if (cellEditor == null) | |
cellEditor = getDefaultCellEditor(attrValue, | |
contentProvider.getElement(), | |
getAffectedElement(row, col)); | |
} else { // If the attribute is an EMF attribute (no attribute value | |
// exists) return a default celleditor | |
if (propertyRow instanceof Descriptor) { | |
Descriptor rowDescriptor = (Descriptor) propertyRow; | |
final IItemPropertyDescriptor descriptor = rowDescriptor | |
.getItemPropertyDescriptor(); | |
String categoryName = descriptor.getCategory(contentProvider | |
.getElement()); | |
Object selectedElement = contentProvider.getElement(); | |
if (categoryName != null | |
&& categoryName | |
.equals(ProrPropertyContentProvider.SPEC_OBJECT_NAME)) { | |
if (this.contentProvider.getElement() instanceof SpecHierarchy) | |
selectedElement = ((SpecHierarchy) this.contentProvider.getElement()) | |
.getObject(); | |
} | |
cellEditor = getNonAttributeCellEditor(selectedElement, descriptor); | |
} | |
} | |
return cellEditor; | |
} | |
/** | |
* | |
* This returns the cell editor that will be used to edit the value of this | |
* property. This default implementation determines the type of cell editor | |
* from the nature of the structural feature. | |
* | |
*/ | |
CellEditor getNonAttributeCellEditor(final Object object, | |
final IItemPropertyDescriptor itemPropertyDescriptor) { | |
if (!itemPropertyDescriptor.canSetProperty(object)) { | |
return null; | |
} | |
CellEditor result = null; | |
Object genericFeature = itemPropertyDescriptor.getFeature(object); | |
if (genericFeature instanceof EReference[]) { | |
result = null; | |
result = new ExtendedAgileComboBoxCellEditor(agileGrid, | |
editingDomain, new ArrayList<Object>( | |
itemPropertyDescriptor.getChoiceOfValues(object)), | |
itemPropertyDescriptor, object, | |
itemPropertyDescriptor.isSortChoices(object)); | |
} else if (genericFeature instanceof EStructuralFeature) { | |
final EStructuralFeature feature = (EStructuralFeature) genericFeature; | |
final EClassifier eType = feature.getEType(); | |
final Collection<?> choiceOfValues = itemPropertyDescriptor | |
.getChoiceOfValues(object); | |
if (choiceOfValues != null) { | |
if (itemPropertyDescriptor.isMany(object)) { | |
boolean valid = true; | |
for (Object choice : choiceOfValues) { | |
if (!eType.isInstance(choice)) { | |
valid = false; | |
break; | |
} | |
} | |
if (valid) { | |
final ILabelProvider editLabelProvider = getLabelProvider( | |
itemPropertyDescriptor, object); | |
result = new ExtendedAgileDialogCellEditor(agileGrid, | |
editingDomain, itemPropertyDescriptor, object) { | |
@Override | |
protected Object openDialogBox( | |
Control cellEditorWindow) { | |
FeatureEditorDialog dialog = new FeatureEditorDialog( | |
cellEditorWindow.getShell(), | |
editLabelProvider, | |
object, | |
feature.getEType(), | |
(List<?>) doGetValue(), | |
getDisplayName(itemPropertyDescriptor, | |
object), new ArrayList<Object>( | |
choiceOfValues), false, | |
itemPropertyDescriptor | |
.isSortChoices(object), feature | |
.isUnique()); | |
super.openDialogBox(cellEditorWindow); | |
dialog.open(); | |
return dialog.getResult(); | |
} | |
}; | |
} | |
} | |
if (result == null) { | |
result = new ExtendedAgileComboBoxCellEditor(agileGrid, | |
editingDomain, new ArrayList<Object>( | |
itemPropertyDescriptor | |
.getChoiceOfValues(object)), | |
itemPropertyDescriptor, object, | |
itemPropertyDescriptor.isSortChoices(object)); | |
} | |
} | |
else if (eType instanceof EDataType) { | |
final EDataType eDataType = (EDataType) eType; | |
if (eDataType.isSerializable()) { | |
if (itemPropertyDescriptor.isMany(object)) { | |
final ILabelProvider editLabelProvider = getLabelProvider( | |
itemPropertyDescriptor, object); | |
result = new ExtendedAgileDialogCellEditor(agileGrid, | |
editingDomain, itemPropertyDescriptor, object) { | |
@Override | |
protected Object openDialogBox( | |
Control cellEditorWindow) { | |
FeatureEditorDialog dialog = new FeatureEditorDialog( | |
cellEditorWindow.getShell(), | |
editLabelProvider, object, | |
feature.getEType(), | |
(List<?>) doGetValue(), | |
getDisplayName(itemPropertyDescriptor, | |
object), null, | |
itemPropertyDescriptor | |
.isMultiLine(object), false, | |
feature.isUnique()); | |
super.openDialogBox(cellEditorWindow); | |
dialog.open(); | |
return dialog.getResult(); | |
} | |
}; | |
} else if (eDataType.getInstanceClass() == Boolean.class | |
|| eDataType.getInstanceClass() == Boolean.TYPE) { | |
result = new ExtendedAgileComboBoxCellEditor(agileGrid, | |
editingDomain, Arrays.asList(new Object[] { | |
Boolean.FALSE, Boolean.TRUE }), | |
itemPropertyDescriptor, object, | |
itemPropertyDescriptor.isSortChoices(object)); | |
} else { | |
if (itemPropertyDescriptor.isMultiLine(object)) { | |
result = new ExtendedAgileDialogCellEditor( | |
agileGrid, editingDomain, | |
itemPropertyDescriptor, object) { | |
// TODO: not working yet ... | |
protected EDataTypeValueHandler valueHandler = new EDataTypeValueHandler( | |
eDataType); | |
@Override | |
protected Object openDialogBox( | |
Control cellEditorWindow) { | |
InputDialog dialog = new MultiLineInputDialog( | |
cellEditorWindow.getShell(), | |
EMFEditUIPlugin.INSTANCE | |
.getString( | |
"_UI_FeatureEditorDialog_title", | |
new Object[] { | |
getDisplayName( | |
itemPropertyDescriptor, | |
object), | |
getLabelProvider( | |
itemPropertyDescriptor, | |
object) | |
.getText( | |
object) }), | |
EMFEditUIPlugin.INSTANCE | |
.getString("_UI_MultiLineInputDialog_message"), | |
valueHandler.toString(getValue()), | |
valueHandler); | |
return dialog.open() == Window.OK ? valueHandler | |
.toValue(dialog.getValue()) : null; | |
} | |
}; | |
} else { | |
result = new EDataTypeAgileCellEditor(agileGrid, | |
editingDomain, itemPropertyDescriptor, | |
object, eDataType); | |
} | |
} | |
} | |
} | |
} | |
return result; | |
} | |
// /** | |
// * This method undos the last command, wrapps it to change the affected | |
// * objects, and executes it again. | |
// * <p> | |
// * This is a workaround, as we modify properties via | |
// * {@link IItemPropertyDescriptor#setPropertyValue(Object, Object)}. That | |
// * method builds the appropriate command and executes it. However, the | |
// * affected objects are incorrect, as this is typically the | |
// * {@link SpecElementWithAttributes} (or {@link SpecHierarchy}), but the | |
// * property belongs to {@link AttributeValue}, which is therefore reported | |
// * as the affected element. | |
// */ | |
// private void fixAffectedObjectsOfLastcommand() { | |
// Command lastCmd = editingDomain.getCommandStack().getMostRecentCommand(); | |
// if (lastCmd == null) return; | |
// editingDomain.getCommandStack().undo(); | |
// CommandWrapper wrappedCmd = new CommandWrapper(lastCmd) { | |
// public java.util.Collection<?> getAffectedObjects() { | |
// List<Object> list = new ArrayList<Object>(); | |
// list.add(contentProvider.getIdentifiable()); | |
// return list; | |
// } | |
// }; | |
// editingDomain.getCommandStack().execute(wrappedCmd); | |
// } | |
@Override | |
public Object getAffectedElement(int row, int col) { | |
if (this.contentProvider != null) | |
return this.contentProvider.getElement(); | |
return null; | |
} | |
public static ILabelProvider getLabelProvider( | |
IItemPropertyDescriptor itemPropertyDescriptor, Object object) { | |
final IItemLabelProvider itemLabelProvider = itemPropertyDescriptor | |
.getLabelProvider(object); | |
return new LabelProvider() { | |
@Override | |
public String getText(Object object) { | |
return itemLabelProvider.getText(object); | |
} | |
@Override | |
public Image getImage(Object object) { | |
return ExtendedImageRegistry.getInstance().getImage( | |
itemLabelProvider.getImage(object)); | |
} | |
}; | |
} | |
public static String getDisplayName( | |
IItemPropertyDescriptor itemPropertyDescriptor, Object object) { | |
return itemPropertyDescriptor.getDisplayName(object); | |
} | |
/** | |
* A delegate for handling validation and conversion for data type values. | |
*/ | |
protected static class EDataTypeValueHandler implements | |
ICellEditorValidator, IInputValidator { | |
protected EDataType eDataType; | |
public EDataTypeValueHandler(EDataType eDataType) { | |
this.eDataType = eDataType; | |
} | |
public String isValid(Object object) { | |
Object value; | |
try { | |
value = eDataType.getEPackage().getEFactoryInstance() | |
.createFromString(eDataType, (String) object); | |
} catch (Exception exception) { | |
String message = exception.getClass().getName(); | |
int index = message.lastIndexOf('.'); | |
if (index >= 0) { | |
message = message.substring(index + 1); | |
} | |
if (exception.getLocalizedMessage() != null) { | |
message = message + ": " + exception.getLocalizedMessage(); | |
} | |
return message; | |
} | |
Diagnostic diagnostic = Diagnostician.INSTANCE.validate(eDataType, | |
value); | |
if (diagnostic.getSeverity() == Diagnostic.OK) { | |
return null; | |
} else { | |
return (diagnostic.getChildren().get(0)).getMessage() | |
.replaceAll("'", "''").replaceAll("\\{", "'{'"); // }} | |
} | |
} | |
public String isValid(String text) { | |
return isValid((Object) text); | |
} | |
public Object toValue(String string) { | |
return EcoreUtil.createFromString(eDataType, string); | |
} | |
public String toString(Object value) { | |
String result = EcoreUtil.convertToString(eDataType, value); | |
return result == null ? "" : result; | |
} | |
} | |
private static class MultiLineInputDialog extends InputDialog { | |
public MultiLineInputDialog(Shell parentShell, String title, | |
String message, String initialValue, IInputValidator validator) { | |
super(parentShell, title, message, initialValue, validator); | |
setShellStyle(getShellStyle() | SWT.RESIZE); | |
} | |
} | |
} |