/*******************************************************************************
* 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.emfstore.client.ui.views.changes;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.emfstore.client.ui.Activator;
import org.eclipse.emf.emfstore.common.model.ModelElementId;
import org.eclipse.emf.emfstore.common.model.ModelFactory;
import org.eclipse.emf.emfstore.common.model.Project;
import org.eclipse.emf.emfstore.common.model.util.ModelUtil;
import org.eclipse.emf.emfstore.server.model.provider.AbstractOperationCustomLabelProvider;
import org.eclipse.emf.emfstore.server.model.provider.CustomOperationLabelProviderManager;
import org.eclipse.emf.emfstore.server.model.versioning.ChangePackage;
import org.eclipse.emf.emfstore.server.model.versioning.operations.AbstractOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.AttributeOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.CompositeOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.CreateDeleteOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.MultiReferenceMoveOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.MultiReferenceOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.ReferenceOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.SingleReferenceOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.UnkownFeatureException;
import org.eclipse.emf.emfstore.server.model.versioning.operations.provider.AbstractOperationItemProvider;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.swt.graphics.Image;
/**
* A helper class for the visualization of change packages.
*
* @author koegel
* @author shterev
* @author emueller
*/
public class ChangePackageVisualizationHelper {
private Map<ModelElementId, EObject> modelElementMap;
private CustomOperationLabelProviderManager customLabelProviderManager;
private DefaultOperationLabelProvider defaultOperationLabelProvider;
/**
* Constructor.
*
* @param changePackages
* a list of change packages
* @param project
* a project
*/
public ChangePackageVisualizationHelper(List<ChangePackage> changePackages,
Project project) {
this.modelElementMap = new HashMap<ModelElementId, EObject>();
for (ChangePackage changePackage : changePackages) {
initModelElementMap(changePackage);
}
for (ModelElementId id : project.getAllModelElementIds()) {
modelElementMap.put(id, project.getModelElement(id));
}
defaultOperationLabelProvider = new DefaultOperationLabelProvider();
defaultOperationLabelProvider.setModelElementMap(modelElementMap);
this.customLabelProviderManager = new CustomOperationLabelProviderManager(
modelElementMap);
}
private void initModelElementMap(ChangePackage changePackage) {
List<AbstractOperation> operations = changePackage.getLeafOperations();
for (AbstractOperation abstractOperation : operations) {
if (abstractOperation instanceof CreateDeleteOperation) {
for (Map.Entry<EObject, ModelElementId> entry : ((CreateDeleteOperation) abstractOperation)
.getEObjectToIdMap().map().entrySet()) {
ModelElementId orgModelElementId = entry.getValue();
EObject modelElement = entry.getKey();
modelElementMap.put(ModelUtil.clone(orgModelElementId),
modelElement);
}
}
}
}
/**
* Get the overlay image for an operation.
*
* @param operation
* the operation
* @return the ImageDescriptor
*/
public ImageDescriptor getOverlayImage(AbstractOperation operation) {
String overlay = null;
if (operation instanceof CreateDeleteOperation) {
CreateDeleteOperation op = (CreateDeleteOperation) operation;
if (op.isDelete()) {
overlay = "icons/delete_overlay.png";
} else {
overlay = "icons/add_overlay.png";
}
} else if (operation instanceof AttributeOperation) {
AttributeOperation op = (AttributeOperation) operation;
if (op.getNewValue() == null) {
overlay = "icons/delete_overlay.png";
} else if (op.getOldValue() == null) {
overlay = "icons/add_overlay.png";
} else {
overlay = "icons/modify_overlay.png";
}
} else if (operation instanceof SingleReferenceOperation) {
SingleReferenceOperation op = (SingleReferenceOperation) operation;
if (op.getNewValue() == null) {
overlay = "icons/delete_overlay.png";
} else {
overlay = "icons/link_overlay.png";
}
} else if (operation instanceof MultiReferenceOperation) {
MultiReferenceOperation op = (MultiReferenceOperation) operation;
if (op.getReferencedModelElements().size() > 0) {
overlay = "icons/link_overlay.png";
}
} else if (operation instanceof MultiReferenceMoveOperation) {
overlay = "icons/link_overlay.png";
} else {
overlay = "icons/modify_overlay.png";
}
// TODO: ChainSaw
ImageDescriptor overlayDescriptor = Activator
.getImageDescriptor(overlay);
return overlayDescriptor;
}
/**
* Get an image for the operation.
*
* @param emfProvider
* the label provider
* @param operation
* the operation
* @return an image
*/
public Image getImage(ILabelProvider emfProvider,
AbstractOperation operation) {
// check if a custom label provider can provide an image
Image image = getCustomOperationProviderLabel(operation);
if (image != null) {
return image;
}
return emfProvider.getImage(operation);
}
private Image getCustomOperationProviderLabel(AbstractOperation operation) {
AbstractOperationCustomLabelProvider customLabelProvider = customLabelProviderManager
.getCustomLabelProvider(operation);
if (customLabelProvider != null) {
try {
return (Image) customLabelProvider.getImage(operation);
// BEGIN SUPRESS CATCH EXCEPTION
} catch (RuntimeException e) {
// END SUPRESS CATCH EXCEPTION
ModelUtil
.logWarning(
"Image load from custom operation item provider failed!",
e);
}
}
return null;
}
/**
* @param op
* the operation to generate a description for
* @return the description for given operation
*/
public String getDescription(AbstractOperation op) {
// check of a custom operation label provider can provide a label
AbstractOperationCustomLabelProvider customLabelProvider = customLabelProviderManager
.getCustomLabelProvider(op);
if (customLabelProvider != null) {
return decorate(customLabelProvider, op);
}
if (op instanceof CompositeOperation) {
CompositeOperation compositeOperation = (CompositeOperation) op;
// artificial composite because of opposite ref, take description of
// mainoperation
if (compositeOperation.getMainOperation() != null) {
return getDescription(compositeOperation.getMainOperation());
}
}
return decorate(defaultOperationLabelProvider, op);
}
private String decorate(AbstractOperationCustomLabelProvider labelProvider,
AbstractOperation op) {
String namesResolved = resolveIds(labelProvider,
labelProvider.getDescription(op),
AbstractOperationItemProvider.NAME_TAG__SEPARATOR);
String allResolved = resolveIds(labelProvider, namesResolved,
AbstractOperationItemProvider.NAME_CLASS_TAG_SEPARATOR);
if (op instanceof ReferenceOperation) {
return resolveTypes(allResolved, (ReferenceOperation) op);
}
return allResolved;
}
private String resolveTypes(String unresolvedString, ReferenceOperation op) {
EObject modelElement = getModelElement(op.getModelElementId());
String type;
if (modelElement == null) {
type = "ModelElement";
} else {
try {
EStructuralFeature feature = op.getFeature(modelElement);
type = feature.getEType().getName();
} catch (UnkownFeatureException e) {
type = "ModelElement";
}
}
return unresolvedString.replace(
AbstractOperationItemProvider.REFERENCE_TYPE_TAG_SEPARATOR,
type);
}
private String resolveIds(
AbstractOperationCustomLabelProvider labelProvider,
String unresolvedString, String devider) {
String[] strings = unresolvedString.split(devider);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < strings.length; i++) {
if (i % 2 == 1) {
ModelElementId modelElementId = ModelFactory.eINSTANCE
.createModelElementId();
modelElementId.setId(strings[i]);
stringBuilder.append(labelProvider
.getModelElementName(modelElementId));
} else {
stringBuilder.append(strings[i]);
}
}
return stringBuilder.toString();
}
/**
* Get all model elements of type T from the given collection of model
* elements.
*
* @param <T>
* Type of the model elements in the resulting collection
* @param <S>
* Type of the Collection of model element ids
* @param modelElementIds
* the collection of model element ids
* @param resultCollection
* the transparent parameter of the collection of type T that
* will be return as result also
* @return the collection of model elements of type T
*/
public <T extends Collection<EObject>, S extends Collection<ModelElementId>> T getModelElements(
S modelElementIds, T resultCollection) {
for (ModelElementId modelElementId : modelElementIds) {
EObject modelElement = getModelElement(modelElementId);
if (modelElement != null) {
resultCollection.add(modelElement);
}
}
return resultCollection;
}
/**
* Get a model element instance from the project for the given id.
*
* @param modelElementId
* the id
* @return the model element instance
*/
public EObject getModelElement(ModelElementId modelElementId) {
if (modelElementId == null) {
return null;
}
return modelElementMap.get(modelElementId);
}
public void dispose() {
defaultOperationLabelProvider.dispose();
}
}