blob: dc333e036d928a9c66062e0d1d5de3a60d0e8691 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2016 EclipseSource Muenchen GmbH 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:
* Clemens Elflein - initial API and implementation
* Martin Fleck - bug 487101
******************************************************************************/
package org.eclipse.emfforms.internal.editor.ecore.referenceservices;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.ENamedElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecp.internal.edit.ECPControlHelper;
import org.eclipse.emf.ecp.spi.common.ui.SelectModelElementWizardFactory;
import org.eclipse.emf.ecp.ui.view.swt.DefaultReferenceService;
import org.eclipse.emf.ecp.view.spi.context.ViewModelContext;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emfforms.spi.editor.helpers.ResourceSetHelpers;
/**
* The ReferenceService provides all widgets with Ecore specific references.
*/
@SuppressWarnings("restriction")
public class EcoreReferenceService extends DefaultReferenceService {
private ViewModelContext context;
private EditingDomain editingDomain;
@Override
public void instantiate(ViewModelContext context) {
this.context = context;
editingDomain = AdapterFactoryEditingDomain.getEditingDomainFor(context.getDomainModel());
super.instantiate(context);
}
private EObject getExistingSuperTypeFor(EReference eReference) {
final EClass domainClass = EClass.class.cast(context.getDomainModel());
final List<EClass> classes = ResourceSetHelpers.findAllOfTypeInResourceSet(
domainClass, EClass.class, false);
// Subtract already present SuperTypes from the List
// The cast is fine, as we know that the eReference must be manyValued.
classes.removeAll((List<?>) domainClass.eGet(eReference));
// Subtract domain model from the List to avoid self-inheritance
classes.remove(domainClass);
// Subtract sub-types from List to avoid circular inheritance
final List<EClass> subTypes = new ArrayList<EClass>();
for (final EClass eClass : classes) {
if (domainClass.isSuperTypeOf(eClass)) {
subTypes.add(eClass);
}
}
classes.removeAll(subTypes);
return select(
classes,
"Select SuperType",
"Select a SuperType to add to "
+ ((ENamedElement) context.getDomainModel()).getName());
}
private EObject getExistingDataTypeFor(EReference eReference) {
final List<EDataType> dataTypes = ResourceSetHelpers
.findAllOfTypeInResourceSet(context.getDomainModel(),
EDataType.class, true);
return select(dataTypes, "Select Datatype", "Select the Datatype for "
+ ((ENamedElement) context.getDomainModel()).getName());
}
private EObject getExistingEAnnotationEReferencesFor(EReference eReference) {
final List<ENamedElement> namedElements = ResourceSetHelpers
.findAllOfTypeInResourceSet(context.getDomainModel(),
ENamedElement.class, true);
return select(namedElements, "Select Reference", "Select Reference to add");
}
// Let the user select an item from a List using a dialog
private EObject select(List<? extends EObject> elements, String title, String message) {
final Set<EObject> selectedEObjects = SelectModelElementWizardFactory
.openModelElementSelectionDialog(new LinkedHashSet<EObject>(elements), false);
if (selectedEObjects.isEmpty()) {
return null;
}
return selectedEObjects.iterator().next();
}
private EObject getExistingElementFor(EReference eReference) {
// Check, if the target is EDataType
if (context.getDomainModel() instanceof EAttribute
&& eReference.getEReferenceType() != null) {
return getExistingDataTypeFor(eReference);
}
if (eReference.equals(EcorePackage.eINSTANCE.getEClass_ESuperTypes())) {
return getExistingSuperTypeFor(eReference);
}
if (eReference.equals(EcorePackage.eINSTANCE.getEReference_EOpposite())) {
return getExistingOppositeFor(eReference);
}
if (eReference.equals(EcorePackage.eINSTANCE.getEAnnotation_References())) {
return getExistingEAnnotationEReferencesFor(eReference);
}
return getExistingGenericType(eReference);
}
private EObject getExistingOppositeFor(EReference eReference) {
final EReference editReference = (EReference) context.getDomainModel();
final List<EReference> allReferences = ResourceSetHelpers
.findAllOfTypeInResourceSet(context.getDomainModel(),
EReference.class, false);
// Remove the DomainModel from the List, as it can't be its own opposite
allReferences.remove(context.getDomainModel());
// Remove all references which do not reference our target type
// If the reference type is null, allow all references and set the type
// on selection later on.
if (editReference.getEReferenceType() != null) {
final Iterator<EReference> iterator = allReferences.iterator();
while (iterator.hasNext()) {
final EReference ref = iterator.next();
if (!editReference.getEReferenceType().equals(
ref.getEContainingClass())) {
iterator.remove();
}
}
}
return select(allReferences, "Select EOpposite",
"Select the opposite EReference");
}
@SuppressWarnings("unchecked")
private EObject getExistingGenericType(EReference eReference) {
final List<EObject> classes = (List<EObject>) ResourceSetHelpers
.findAllOfTypeInResourceSet(context.getDomainModel(),
eReference.getEReferenceType(), false);
return select(classes, "Select " + eReference.getName(), "Select a "
+ eReference.getEType().getName());
}
@Override
public void dispose() {
super.dispose();
}
@Override
public int getPriority() {
return 3;
}
private void addModelElement(EObject eObject, EReference eReference) {
final EditingDomain editingDomain = AdapterFactoryEditingDomain.getEditingDomainFor(context.getDomainModel());
// eObject.eSet(EcorePackage.eINSTANCE.getEAttribute_EAttributeType(),
// eReference);
// If we set the opposite and the current eReference does not have any
// type set,
// we can also set the type of the current eReference.
if (EcorePackage.eINSTANCE.getEReference_EOpposite().equals(eReference)) {
final EReference editReference = (EReference) context.getDomainModel();
final EReference selectedReference = (EReference) eObject;
// Set the opposite for the other reference as well
editingDomain.getCommandStack().execute(
SetCommand.create(AdapterFactoryEditingDomain.getEditingDomainFor(selectedReference),
selectedReference, EcorePackage.Literals.EREFERENCE__EOPPOSITE, editReference));
if (editReference.getEReferenceType() == null) {
editingDomain.getCommandStack().execute(
SetCommand.create(editingDomain, editReference, EcorePackage.Literals.ETYPED_ELEMENT__ETYPE,
selectedReference.getEContainingClass()));
}
editingDomain.getCommandStack().execute(
SetCommand.create(editingDomain, editReference, EcorePackage.Literals.EREFERENCE__EOPPOSITE, eObject));
return;
}
ECPControlHelper.addModelElementInReference(context.getDomainModel(), eObject, eReference, editingDomain);
}
@Override
public void openInNewContext(EObject eObject) {
// no op. stay inside editor
}
@Override
public void addExistingModelElements(EObject eObject, EReference eReference) {
final EObject selectedElement = getExistingElementFor(eReference);
if (selectedElement != null) {
addModelElement(selectedElement, eReference);
}
}
@Override
public void addNewModelElements(EObject eObject, EReference eReference) {
if (eReference == EcorePackage.eINSTANCE.getEReference_EOpposite()) {
handleEOpposite(eObject, eReference);
return;
}
super.addNewModelElements(eObject, eReference);
}
private void handleEOpposite(EObject eObject, EReference eReference) {
/* get the container for the existing reference. this will be the type for the newly created reference */
final EReference existingReference = EReference.class.cast(eObject);
final EClass existingType = (EClass) existingReference.eContainer();
/* create the new reference */
final EReference newReference = EcoreFactory.eINSTANCE.createEReference();
newReference.setName("");
newReference.setEType(existingType);
newReference.setEOpposite(existingReference);
/* the reference type will contain the new reference */
final EClass containerType = existingReference.getEReferenceType();
/* add new reference to model */
ECPControlHelper.addModelElementInReference(containerType, newReference,
EcorePackage.eINSTANCE.getEClass_EStructuralFeatures(), editingDomain);
/* set eopposite */
ECPControlHelper.addModelElementInReference(eObject, newReference,
eReference, editingDomain);
}
}