blob: 44b05486971d16d8634ea333270dfe9d63f241a2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2011 Chair for Applied Software Engineering,
* Technische Universitaet Muenchen.
* 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:
******************************************************************************/
package org.eclipse.emf.ecp.editor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecp.common.commands.DeleteModelElementCommand;
import org.eclipse.emf.ecp.common.model.ECPModelelementContext;
import org.eclipse.emf.ecp.common.utilities.ShortLabelProvider;
import org.eclipse.emf.ecp.editor.mecontrols.AbstractMEControl;
import org.eclipse.emf.ecp.editor.mecontrols.FeatureHintTooltipSupport;
import org.eclipse.emf.ecp.editor.mecontrols.IValidatableControl;
import org.eclipse.emf.ecp.editor.mecontrols.METextControl;
import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ContributionManager;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.SashForm;
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.ui.AbstractSourceProvider;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.ISourceProvider;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.editor.FormPage;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.menus.IMenuService;
import org.eclipse.ui.services.IEvaluationService;
/**
* The editor page for the {@link MEEditor}.
*
* @author helming
* @author shterev
* @author naughton
*/
public class MEEditorPage extends FormPage {
private EObject modelElement;
private FormToolkit toolkit;
private Map<EStructuralFeature, AbstractMEControl> meControls = new HashMap<EStructuralFeature, AbstractMEControl>();
private Map<AbstractMEControl, Diagnostic> valdiatedControls = new HashMap<AbstractMEControl, Diagnostic>();
private static String activeModelelement = "activeModelelement";
private ScrolledForm form;
private List<IItemPropertyDescriptor> leftColumnAttributes = new ArrayList<IItemPropertyDescriptor>();
private List<IItemPropertyDescriptor> rightColumnAttributes = new ArrayList<IItemPropertyDescriptor>();
private List<IItemPropertyDescriptor> bottomAttributes = new ArrayList<IItemPropertyDescriptor>();
private Composite leftColumnComposite;
private Composite rightColumnComposite;
private Composite bottomComposite;
private EStructuralFeature problemFeature;
private final ECPModelelementContext modelElementContext;
private final ComposedAdapterFactory adapterFactory;
/**
* Default constructor.
*
* @param editor
* the {@link MEEditor}
* @param id
* the {@link FormPage#id}
* @param title
* the title
* @param modelElement
* the modelElement
* @param modelElementContext
* the {@link ModelElementContext}
*/
public MEEditorPage(MEEditor editor, String id, String title, ECPModelelementContext modelElementContext,
EObject modelElement) {
super(editor, id, title);
this.modelElementContext = modelElementContext;
this.modelElement = modelElement;
this.adapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
}
/**
* Default constructor.
*
* @param editor
* the {@link MEEditor}
* @param id
* the {@link FormPage#id}
* @param title
* the title
* @param modelElement
* the modelElement
* @param problemFeature
* the problemFeature
* @param modelElementContext
* the {@link ModelElementContext}
*/
public MEEditorPage(MEEditor editor, String id, String title, ECPModelelementContext modelElementContext,
EObject modelElement, EStructuralFeature problemFeature) {
this(editor, id, title, modelElementContext, modelElement);
this.problemFeature = problemFeature;
}
/**
* {@inheritDoc}
*/
@Override
protected void createFormContent(IManagedForm managedForm) {
super.createFormContent(managedForm);
toolkit = this.getEditor().getToolkit();
form = managedForm.getForm();
toolkit.decorateFormHeading(form.getForm());
Composite body = form.getBody();
body.setLayout(new GridLayout());
Composite topComposite = toolkit.createComposite(body);
topComposite.setLayout(new GridLayout());
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(topComposite);
sortAndOrderAttributes();
if (!rightColumnAttributes.isEmpty()) {
SashForm topSash = new SashForm(topComposite, SWT.HORIZONTAL);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(topSash);
toolkit.adapt(topSash, true, true);
topSash.setSashWidth(4);
leftColumnComposite = toolkit.createComposite(topSash, SWT.NONE);
rightColumnComposite = toolkit.createComposite(topSash, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(1).equalWidth(false).extendedMargins(5, 2, 5, 5)
.applyTo(rightColumnComposite);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).applyTo(rightColumnComposite);
int[] topWeights = { 50, 50 };
topSash.setWeights(topWeights);
} else {
leftColumnComposite = toolkit.createComposite(topComposite, SWT.NONE);
}
GridLayoutFactory.fillDefaults().numColumns(1).equalWidth(false).extendedMargins(2, 5, 5, 5)
.applyTo(leftColumnComposite);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).applyTo(leftColumnComposite);
bottomComposite = toolkit.createComposite(topComposite);
GridLayoutFactory.fillDefaults().numColumns(1).equalWidth(false).extendedMargins(0, 0, 0, 0)
.applyTo(bottomComposite);
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(bottomComposite);
// updateSectionTitle();
form.setImage(new AdapterFactoryLabelProvider(adapterFactory).getImage(modelElement));
// Sort and order attributes
// Create attributes
createAttributes(leftColumnComposite, leftColumnAttributes);
if (!rightColumnAttributes.isEmpty()) {
createAttributes(rightColumnComposite, rightColumnAttributes);
}
createAttributes(bottomComposite, bottomAttributes);
createToolbar();
form.pack();
updateSectionTitle();
updateLiveValidation();
}
/**
* Updates the name of the section.
*/
public void updateSectionTitle() {
// Layout form
ShortLabelProvider shortLabelProvider = new ShortLabelProvider();
String name = shortLabelProvider.getText(modelElement);
name += " [" + modelElement.eClass().getName() + "]";
try {
form.setText(name);
} catch (SWTException e) {
// Catch in case editor is closed directly after change
}
}
private void createToolbar() {
IMenuService menuService = (IMenuService) PlatformUI.getWorkbench().getService(IMenuService.class);
ISourceProvider sourceProvider = new AbstractSourceProvider() {
public void dispose() {
}
@SuppressWarnings("rawtypes")
public Map getCurrentState() {
HashMap<Object, Object> map = new HashMap<Object, Object>();
map.put(activeModelelement, modelElement);
return map;
}
public String[] getProvidedSourceNames() {
String[] namens = new String[1];
namens[0] = activeModelelement;
return namens;
}
};
IEvaluationService service = (IEvaluationService) PlatformUI.getWorkbench()
.getService(IEvaluationService.class);
service.addSourceProvider(sourceProvider);
form.getToolBarManager().add(new Action("", Activator.getImageDescriptor("icons/delete.gif")) {
@Override
public void run() {
new DeleteModelElementCommand(modelElement, modelElementContext).run();
}
});
menuService.populateContributionManager((ContributionManager) form.getToolBarManager(),
"toolbar:org.eclipse.emf.ecp.editor.MEEditorPage");
form.getToolBarManager().update(true);
}
/**
* Filters attributes marked with "hidden=true" annotation.
*
* @param propertyDescriptors property descriptors to filter
*/
private void filterHiddenAttributes(Collection<IItemPropertyDescriptor> propertyDescriptors) {
Iterator<IItemPropertyDescriptor> iterator = propertyDescriptors.iterator();
AnnotationHiddenDescriptor visibilityDescriptor = new AnnotationHiddenDescriptor();
while (iterator.hasNext()) {
IItemPropertyDescriptor descriptor = iterator.next();
if (visibilityDescriptor.getValue(descriptor, modelElement)) {
iterator.remove();
}
}
}
private void sortAndOrderAttributes() {
AdapterFactoryItemDelegator adapterFactoryItemDelegator = new AdapterFactoryItemDelegator(adapterFactory);
Collection<IItemPropertyDescriptor> propertyDescriptors = adapterFactoryItemDelegator
.getPropertyDescriptors(modelElement);
if (propertyDescriptors != null) {
filterHiddenAttributes(propertyDescriptors);
AnnotationPositionDescriptor positionDescriptor = new AnnotationPositionDescriptor();
for (IItemPropertyDescriptor itemPropertyDescriptor : propertyDescriptors) {
String value = positionDescriptor.getValue(itemPropertyDescriptor, modelElement);
if (value.equals("left")) {
leftColumnAttributes.add(itemPropertyDescriptor);
} else if (value.equals("right")) {
rightColumnAttributes.add(itemPropertyDescriptor);
} else if (value.equals("bottom")) {
bottomAttributes.add(itemPropertyDescriptor);
} else {
leftColumnAttributes.add(itemPropertyDescriptor);
}
}
final HashMap<IItemPropertyDescriptor, Double> priorityMap = new HashMap<IItemPropertyDescriptor, Double>();
AnnotationPriorityDescriptor priorityDescriptor = new AnnotationPriorityDescriptor();
for (IItemPropertyDescriptor itemPropertyDescriptor : propertyDescriptors) {
priorityMap.put(itemPropertyDescriptor,
priorityDescriptor.getValue(itemPropertyDescriptor, modelElement));
}
Comparator<IItemPropertyDescriptor> comparator = new Comparator<IItemPropertyDescriptor>() {
public int compare(IItemPropertyDescriptor o1, IItemPropertyDescriptor o2) {
return Double.compare(priorityMap.get(o1), priorityMap.get(o2));
}
};
Collections.sort(leftColumnAttributes, comparator);
Collections.sort(rightColumnAttributes, comparator);
Collections.sort(bottomAttributes, comparator);
}
}
private void createAttributes(Composite column, List<IItemPropertyDescriptor> attributes) {
Composite attributeComposite = toolkit.createComposite(column);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(attributeComposite);
GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.BEGINNING).indent(10, 0)
.applyTo(attributeComposite);
ControlFactory controlFactory = new ControlFactory();
for (IItemPropertyDescriptor itemPropertyDescriptor : attributes) {
AbstractMEControl meControl = controlFactory.createControl(itemPropertyDescriptor, modelElement,
modelElementContext);
if (meControl == null) {
continue;
}
meControls.put((EStructuralFeature) itemPropertyDescriptor.getFeature(modelElement), meControl);
Control control;
if (meControl.getShowLabel()) {
Label label = toolkit.createLabel(attributeComposite,
itemPropertyDescriptor.getDisplayName(modelElement));
label.setData(modelElement);
FeatureHintTooltipSupport.enableFor(label, itemPropertyDescriptor);
control = meControl.createControl(attributeComposite, SWT.WRAP, itemPropertyDescriptor, modelElement,
modelElementContext, toolkit);
GridDataFactory.fillDefaults().align(SWT.LEFT, SWT.CENTER).applyTo(label);
GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.BEGINNING).indent(10, 0)
.applyTo(control);
meControl.applyCustomLayoutData();
} else {
control = meControl.createControl(attributeComposite, SWT.WRAP, itemPropertyDescriptor, modelElement,
modelElementContext, toolkit);
control.setData(modelElement);
FeatureHintTooltipSupport.enableFor(control, itemPropertyDescriptor);
GridDataFactory.fillDefaults().span(2, 1).grab(true, true).align(SWT.FILL, SWT.BEGINNING).indent(10, 0)
.applyTo(control);
}
if (itemPropertyDescriptor.getFeature(modelElement) == problemFeature) {
ControlDecoration dec = new ControlDecoration(control, SWT.TOP | SWT.LEFT);
dec.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK));
dec.setDescriptionText("Problem detected.");
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void dispose() {
for (AbstractMEControl control : meControls.values()) {
control.dispose();
}
if (adapterFactory != null) {
adapterFactory.dispose();
}
super.dispose();
}
/**
* {@inheritDoc} This method is added to solve the focus bug of navigator.
* Every time that a ME is opened in editor, navigator has to lose focus so
* that its action contributions are set correctly for next time.
*/
@Override
public void setFocus() {
super.setFocus();
// set keyboard focus on the first Text control
for (AbstractMEControl meControl : this.meControls.values()) {
if (meControl instanceof METextControl) {
((METextControl) meControl).setFocus();
return;
}
}
leftColumnComposite.setFocus();
}
/**
* Triggers live validation of the model attributes.
* **/
public void updateLiveValidation() {
Diagnostic diagnostic = Diagnostician.INSTANCE.validate(modelElement);
List<AbstractMEControl> affectedControls = new ArrayList<AbstractMEControl>();
for (Iterator<Diagnostic> i = diagnostic.getChildren().iterator(); i.hasNext();) {
Diagnostic childDiagnostic = i.next();
Object object = childDiagnostic.getData().get(0);
if (object instanceof EObject) {
EObject eObject = (EObject) object;
if (eObject != modelElement) {
continue;
}
}
if (childDiagnostic.getData().size() < 2) {
continue;
}
AbstractMEControl meControl = this.meControls.get(childDiagnostic.getData().get(1));
affectedControls.add(meControl);
if (meControl instanceof IValidatableControl) {
if (this.valdiatedControls.containsKey(meControl)) {
if (childDiagnostic.getSeverity() != this.valdiatedControls.get(meControl).getSeverity()) {
((IValidatableControl) meControl).handleValidation(childDiagnostic);
this.valdiatedControls.put(meControl, childDiagnostic);
}
} else {
((IValidatableControl) meControl).handleValidation(childDiagnostic);
this.valdiatedControls.put(meControl, childDiagnostic);
}
}
}
Map<AbstractMEControl, Diagnostic> temp = new HashMap<AbstractMEControl, Diagnostic>();
temp.putAll(this.valdiatedControls);
for (Map.Entry<AbstractMEControl, Diagnostic> entry : temp.entrySet()) {
AbstractMEControl meControl = entry.getKey();
if (!affectedControls.contains(meControl)) {
this.valdiatedControls.remove(meControl);
((IValidatableControl) meControl).resetValidation();
}
}
}
}