blob: 8f0348d6b6cc5601c5d5fb4f1e07e74b3ec2e5af [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012-2014 SAP SE.
* 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:
* SAP SE - initial API and implementation and/or initial documentation
*
*******************************************************************************/
package org.eclipse.ogee.designer.features;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.graphiti.dt.IDiagramTypeProvider;
import org.eclipse.graphiti.features.IDeleteFeature;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.context.ICustomContext;
import org.eclipse.graphiti.features.context.impl.CreateConnectionContext;
import org.eclipse.graphiti.features.custom.AbstractCustomFeature;
import org.eclipse.graphiti.mm.pictograms.Anchor;
import org.eclipse.graphiti.mm.pictograms.AnchorContainer;
import org.eclipse.graphiti.mm.pictograms.Connection;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.mm.pictograms.Shape;
import org.eclipse.graphiti.platform.IDiagramContainer;
import org.eclipse.graphiti.services.Graphiti;
import org.eclipse.ogee.designer.ODataEditor;
import org.eclipse.ogee.designer.actions.ODataShowUsageAction;
import org.eclipse.ogee.designer.contexts.LinkUsageContext;
import org.eclipse.ogee.designer.factories.ArtifactFactory;
import org.eclipse.ogee.designer.factories.ShapesFactory;
import org.eclipse.ogee.designer.messages.Messages;
import org.eclipse.ogee.designer.providers.ODataImageProvider;
import org.eclipse.ogee.designer.utils.ArtifactUtil;
import org.eclipse.ogee.designer.utils.IODataEditorConstants;
import org.eclipse.ogee.designer.utils.PropertyUtil;
import org.eclipse.ogee.model.odata.ComplexType;
import org.eclipse.ogee.model.odata.ComplexTypeUsage;
import org.eclipse.ogee.model.odata.EntityType;
import org.eclipse.ogee.model.odata.EntityTypeUsage;
import org.eclipse.ogee.model.odata.EnumType;
import org.eclipse.ogee.model.odata.EnumTypeUsage;
import org.eclipse.ogee.model.odata.FunctionImport;
import org.eclipse.ogee.model.odata.IFunctionReturnTypeUsage;
import org.eclipse.ogee.model.odata.IParameterTypeUsage;
import org.eclipse.ogee.model.odata.IPropertyTypeUsage;
import org.eclipse.ogee.model.odata.Parameter;
import org.eclipse.ogee.model.odata.Property;
import org.eclipse.ogee.model.odata.ReturnEntityTypeUsage;
import org.eclipse.ogee.model.odata.impl.ComplexTypeUsageImpl;
import org.eclipse.ogee.model.odata.impl.EntityTypeUsageImpl;
import org.eclipse.ogee.model.odata.impl.EnumTypeUsageImpl;
import org.eclipse.ogee.model.odata.impl.ReturnEntityTypeUsageImpl;
/**
* This pattern class is created for 'LinkUsage' feature of the artifacts. This
* contains all the methods required to create the Show/Hide usage links Shape.
* This is used to make the feature work from the context menu.
*
*/
public class ODataLinkUsageFeature extends AbstractCustomFeature {
/**
* artifact factory
*/
private ArtifactFactory artifactFactory;
/**
* shapes factory
*/
private ShapesFactory shapesFactory;
/**
* Feature Provider
*/
private IFeatureProvider featureProvider;
private boolean isToolBarReq = false;
private boolean isShown = false;
private boolean isHidden = false;
private boolean isUpdate = false;
/**
* @param fp
* @param artifactFactory
* @param shapesFactory
*/
public ODataLinkUsageFeature(IFeatureProvider fp,
ArtifactFactory artifactFactory, ShapesFactory shapesFactory) {
super(fp);
this.artifactFactory = artifactFactory;
this.shapesFactory = shapesFactory;
this.featureProvider = fp;
}
/**
* @param fp
* @param artifactFactory
* @param shapesFactory
* @param isUpdate
* - if it called from the update method or delete method
*/
public ODataLinkUsageFeature(IFeatureProvider fp,
ArtifactFactory artifactFactory, ShapesFactory shapesFactory,
boolean isUpdate) {
super(fp);
this.artifactFactory = artifactFactory;
this.shapesFactory = shapesFactory;
this.featureProvider = fp;
this.isUpdate = isUpdate;
}
/**
* @param fp
* @param artifactFactory
* @param shapesFactory
* @param show
* @param isToolBarReq
* boolean - to check if the show/hide usage request is from
* eclipse tool bar.
*/
public ODataLinkUsageFeature(IFeatureProvider fp,
ArtifactFactory artifactFactory, ShapesFactory shapesFactory,
boolean show, boolean isToolBarReq) {
this(fp, artifactFactory, shapesFactory);
this.isToolBarReq = isToolBarReq;
this.isShown = false;
this.isHidden = false;
}
/**
* Enabled for Enum Type and Complex Type.
*/
@Override
public boolean canExecute(ICustomContext context) {
boolean ret = false;
PictogramElement[] pes = context.getPictogramElements();
if (pes != null && pes.length == 1) {
Object bo = getBusinessObjectForPictogramElement(pes[0]);
if (bo instanceof EnumType || bo instanceof ComplexType
|| bo instanceof EntityType) {
ret = true;
}
}
return ret;
}
@Override
public String getName() {
return Messages.ODATAEDITOR_LINK_USAGE;
}
@Override
public String getImageId() {
return ODataImageProvider.IMG_DISPLAY_RELATION;
}
@Override
public void execute(ICustomContext context) {
// The following logic will un-check the Hide/Show All Usages button in
// case
// Hide/Show Usage is invoked from context menu of OData artifacts.
if (!this.isToolBarReq && this.featureProvider != null
&& !this.isUpdate) {
final IDiagramTypeProvider dtp = this.featureProvider
.getDiagramTypeProvider();
if (dtp != null) {
final IDiagramContainer editor = dtp.getDiagramBehavior().getDiagramContainer();
if (editor != null && editor instanceof ODataEditor) {
final ODataEditor odataEditor = (ODataEditor) editor;
if (odataEditor != null
&& odataEditor.getActionRegistry() != null) {
final ODataShowUsageAction action = (ODataShowUsageAction) odataEditor
.getActionRegistry()
.getAction(
IODataEditorConstants.ACTION_ID_SHOW_HIDE_USAGES);
if (action != null) {
action.setChecked(false);
}
}
}
if (PropertyUtil.isShowAllUsage(dtp.getDiagram())) {
PropertyUtil.setShowAllUsage(dtp.getDiagram(), false);
}
}
}
// Get all the artifacts which use complex type and entity type
List<EntityType> etypes = this.artifactFactory
.getAllEntitiesIncludingReferenced();
List<ComplexType> ctypes = this.artifactFactory
.getAllComplexTypesIncludingReferenced();
List<FunctionImport> functionImports = this.artifactFactory
.getAllFunctionImports();
// Create the list to populate the related usages
HashMap<EObject, Set<EObject>> linkMap = new HashMap<EObject, Set<EObject>>();
PictogramElement[] pet = context.getPictogramElements();
List<Connection> tempList = new ArrayList<Connection>();
// If isShowUsage returns true means the links are already shown
if (PropertyUtil.isShowUsage(pet[0])) {
// Set it as hide as the links will be hidden
PropertyUtil.setHideUsage(pet[0]);
// Get all the link usages
tempList.addAll(getLinkConnections(pet[0]));
// Delete all the link usages
deleteLinkUsage(tempList);
this.isHidden = true;
if (this.isUpdate) {
showUsageLinks(etypes, ctypes, functionImports, linkMap, pet);
}
} else {
showUsageLinks(etypes, ctypes, functionImports, linkMap, pet);
}
}
/**
* Method is used to rebuild the linkages
*
* @param etypes
* @param ctypes
* @param functionImports
* @param linkMap
* @param pet
*/
public void showUsageLinks(List<EntityType> etypes,
List<ComplexType> ctypes, List<FunctionImport> functionImports,
HashMap<EObject, Set<EObject>> linkMap, PictogramElement[] pet) {
Object businessObject = getBusinessObjectForPictogramElement(pet[0]);
if (businessObject instanceof ComplexType
|| businessObject instanceof EnumType
|| businessObject instanceof EntityType) {
PropertyUtil.setShowUsage(pet[0]);
// Get all the complex types attached with the selected complex
// type
getLinkedComplexTypes(ctypes, linkMap, (EObject) businessObject);
// Get all the entity types attached with the selected complex
// type
getLinkedEntityTypes(etypes, linkMap, (EObject) businessObject);
// Get all the function imports attached with the selected
// complex type
getLinkedFunctionImports(functionImports, linkMap,
(EObject) businessObject);
Set<EObject> keySet = linkMap.keySet();
for (EObject currnetKey : keySet) {
Set<EObject> valueSet = linkMap.get(currnetKey);
createLinkShape(valueSet, currnetKey);
this.isShown = true;
}
}
}
/**
* @return boolean - if usage link is shown on canvas.
*/
public boolean isShown() {
return this.isShown;
}
/**
* @return boolean - if usage link is hidden on canvas.
*/
public boolean isHidden() {
return this.isHidden;
}
/**
* @param connectionContext
* @param complexType
* @param valueSet
*/
private void createLinkShape(Set<EObject> valueSet, EObject sourceObj) {
CreateConnectionContext connectionContext = new CreateConnectionContext();
if (valueSet != null) {
for (EObject currentArtifact : valueSet) {
connectionContext = new CreateConnectionContext();
connectionContext.setSourceAnchor(Graphiti.getPeService()
.getChopboxAnchor(getTopContainerShape(sourceObj)));
connectionContext
.setTargetAnchor(Graphiti.getPeService()
.getChopboxAnchor(
getTopContainerShape(currentArtifact)));
this.shapesFactory.createLinkUsageShape(getFeatureProvider(),
connectionContext);
}
}
}
/**
* @param complexType
* @return
*/
private Shape getTopContainerShape(EObject currentObject) {
Shape topContainer = null;
PictogramElement[] pes = getFeatureProvider()
.getAllPictogramElementsForBusinessObject(currentObject);
for (PictogramElement pe : pes) {
if (PropertyUtil.isTopContainer(pe)) {
topContainer = (Shape) pe;
break;
}
}
return topContainer;
}
/**
* Get all the links which are going to be deleted
*
* @param pe
* @return
*/
private List<Connection> getLinkConnections(PictogramElement pe) {
EList<Connection> connections = getFeatureProvider()
.getDiagramTypeProvider().getDiagram().getConnections();
List<Connection> tempList = new ArrayList<Connection>();
// Populate all the dependent usages
Anchor anchor;
AnchorContainer anchorContainer;
Object targetObject;
Object businessObject;
for (Connection connection : connections) {
if (PropertyUtil.isLinkConnection(connection)) {
anchor = connection.getStart();
anchorContainer = anchor.getParent();
targetObject = getBusinessObjectForPictogramElement(anchorContainer);
businessObject = getBusinessObjectForPictogramElement(pe);
if (businessObject instanceof ComplexType
|| businessObject instanceof EnumType
|| businessObject instanceof EntityType) {
if (targetObject == businessObject) {
tempList.add(connection);
}
}
}
}
return tempList;
}
/**
* To delete all the links to show usage
*
* @param tempList
*/
private void deleteLinkUsage(List<Connection> tempList) {
// Delete all the link usages
LinkUsageContext deleteContext;
IDeleteFeature deleteFeature;
for (Connection linkConnection : tempList) {
deleteContext = new LinkUsageContext(linkConnection);
deleteFeature = this.featureProvider
.getDeleteFeature(deleteContext);
if (deleteFeature != null
&& deleteFeature.canExecute(deleteContext)) {
deleteFeature.execute(deleteContext);
}
}
}
/**
* Get all the function imports which are linked with the complex type or
* enum type
*
* @param functionImports
* @param linkMap
* @param ct
*/
private void getLinkedFunctionImports(List<FunctionImport> functionImports,
HashMap<EObject, Set<EObject>> linkMap, EObject type) {
EObject currentObject;
IFunctionReturnTypeUsage returnType;
Set<EObject> currentValueSet;
for (FunctionImport funcImport : functionImports) {
currentObject = null;
EList<Parameter> parameters = funcImport.getParameters();
for (Parameter parameter : parameters) {
IParameterTypeUsage parameterUsage = parameter.getType();
if (parameterUsage instanceof ComplexTypeUsageImpl) {
currentObject = ((ComplexTypeUsage) parameterUsage)
.getComplexType();
} else if (parameterUsage instanceof EnumTypeUsageImpl) {
currentObject = ((EnumTypeUsage) parameterUsage)
.getEnumType();
} else if (parameterUsage instanceof EntityTypeUsageImpl) {
currentObject = ((EntityTypeUsage) parameterUsage)
.getEntityType();
}
if (type.equals(currentObject)) {
currentValueSet = linkMap.get(type);
if (currentValueSet == null) {
currentValueSet = new HashSet<EObject>();
linkMap.put(type, currentValueSet);
}
currentValueSet.add(funcImport);
break;
}
}
returnType = funcImport.getReturnType();
if (returnType instanceof ComplexTypeUsageImpl) {
currentObject = ((ComplexTypeUsage) returnType)
.getComplexType();
} else if (returnType instanceof EnumTypeUsageImpl) {
currentObject = ((EnumTypeUsage) returnType).getEnumType();
} else if (returnType instanceof ReturnEntityTypeUsageImpl) {
currentObject = ((ReturnEntityTypeUsage) returnType)
.getEntityType();
}
if (type.equals(currentObject)) {
currentValueSet = linkMap.get(type);
if (currentValueSet == null) {
currentValueSet = new HashSet<EObject>();
linkMap.put(type, currentValueSet);
}
currentValueSet.add(funcImport);
}
}
}
/**
* Get all the entity types which are linked with the complex type or enum
* type
*
* @param etypes
* @param linkMap
* @param ct
*/
private void getLinkedEntityTypes(List<EntityType> etypes,
HashMap<EObject, Set<EObject>> linkMap, EObject type) {
EList<Property> eproperties;
EObject currentObject;
IPropertyTypeUsage propertyUsage;
Set<EObject> currentValueSet;
boolean isEntityType = ArtifactUtil.isEntityType(type);
EntityType baseType = null;
for (EntityType entityType : etypes) {
// Check for Base Type
if (isEntityType) {
baseType = entityType.getBaseType();
if (type.equals(baseType)) {
currentValueSet = linkMap.get(type);
if (currentValueSet == null) {
currentValueSet = new HashSet<EObject>();
linkMap.put(type, currentValueSet);
}
currentValueSet.add(entityType);
continue;
}
}
eproperties = entityType.getProperties();
for (Property property : eproperties) {
currentObject = null;
propertyUsage = property.getType();
if (propertyUsage instanceof ComplexTypeUsageImpl) {
currentObject = ((ComplexTypeUsage) propertyUsage)
.getComplexType();
} else if (propertyUsage instanceof EnumTypeUsageImpl) {
currentObject = ((EnumTypeUsage) propertyUsage)
.getEnumType();
}
if (type.equals(currentObject)) {
currentValueSet = linkMap.get(type);
if (currentValueSet == null) {
currentValueSet = new HashSet<EObject>();
linkMap.put(type, currentValueSet);
}
currentValueSet.add(entityType);
break;
}
}
eproperties = entityType.getKeys();
for (Property property : eproperties) {
currentObject = null;
propertyUsage = property.getType();
if (propertyUsage instanceof EnumTypeUsageImpl) {
currentObject = ((EnumTypeUsage) propertyUsage)
.getEnumType();
}
if (type.equals(currentObject)) {
currentValueSet = linkMap.get(type);
if (currentValueSet == null) {
currentValueSet = new HashSet<EObject>();
linkMap.put(type, currentValueSet);
}
currentValueSet.add(entityType);
break;
}
}
}
}
/**
* Get all the complex types which are linked with the complex type or enum
* type
*
* @param ctypes
* @param linkMap
* @param type
*/
private void getLinkedComplexTypes(List<ComplexType> ctypes,
HashMap<EObject, Set<EObject>> linkMap, EObject type) {
EList<Property> cproperties;
EObject currentObject;
IPropertyTypeUsage propertyUsage;
Set<EObject> currentValueSet;
boolean isComplexType = ArtifactUtil.isComplexType(type);
ComplexType baseType = null;
for (ComplexType complexType : ctypes) {
// Check for Base Type
if (isComplexType) {
baseType = complexType.getBaseType();
if (type.equals(baseType)) {
currentValueSet = linkMap.get(type);
if (currentValueSet == null) {
currentValueSet = new HashSet<EObject>();
linkMap.put(type, currentValueSet);
}
currentValueSet.add(complexType);
continue;
}
}
cproperties = complexType.getProperties();
for (Property property : cproperties) {
currentObject = null;
propertyUsage = property.getType();
if (propertyUsage instanceof ComplexTypeUsageImpl) {
currentObject = ((ComplexTypeUsage) propertyUsage)
.getComplexType();
} else if (propertyUsage instanceof EnumTypeUsageImpl) {
currentObject = ((EnumTypeUsage) propertyUsage)
.getEnumType();
}
if (type.equals(currentObject)) {
currentValueSet = linkMap.get(type);
if (currentValueSet == null) {
currentValueSet = new HashSet<EObject>();
linkMap.put(type, currentValueSet);
}
currentValueSet.add(complexType);
break;
}
}
}
}
}