/*******************************************************************************
* Copyright (c) 2006-2012
* Software Technology Group, Dresden University of Technology
* DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026
*
* 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:
* Software Technology Group - TU Dresden, Germany;
* DevBoost GmbH - Berlin, Germany
* - initial API and implementation
******************************************************************************/
package org.reuseware.lacome.layoutlanguage.emftext;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.emftext.access.EMFTextAccessProxy;
import org.emftext.access.resource.IResource;
import org.reuseware.lacome.CompositionDiagramUtil;
import org.reuseware.lacome.DiagramDescription;
import org.reuseware.lacome.provider.TargetDiagramInformationProvider;
/**
* A target information provider that extracts information from textual models
* (which act as composition programs) processed with EMFText.
*/
public class EMFTextTargetDiagramInformationProvider implements
TargetDiagramInformationProvider {
/**
* @param diagram the diagram to compute information from
*
* @return true if the context of the diagram can be mapped
* to a line in the textual model
*/
public boolean canProvide(DiagramDescription diagram) {
EObject context = diagram.getContext();
return getLine(context) != -1;
}
/**
* Computes X, Y, and model position based on column and line
* position of the context object (i.e., the element in
* the textual model that represents a fragment instance).
*
* @param diagram the diagram to compute information for
*/
public void provideBounds(DiagramDescription diagram) {
EObject context = diagram.getContext();
int line = getLine(context);
if (line != -1) {
diagram.getTargetBounds().setY(findTarget(context));
diagram.getTargetBounds().setX(getColumn(context));
diagram.getTargetBounds().setModelPosition(findTarget(context));
}
}
/**
* In order to get the target layout information, the line number of the
* model element is taken from the EMFText document. This will be the y value.
*
* @param context the context object
* @return line number
*/
private int getLine(EObject context) {
if (!CompositionDiagramUtil.getDerivedFrom(context).isEmpty()) {
EObject semanticElement = getFirstSource(context);
if (semanticElement == null) {
return -1;
}
Resource resource = semanticElement.eResource();
if (resource == null) {
return -1;
}
IResource textRess = castToTextResource(resource);
if (textRess == null) {
return -1;
}
int line = textRess.getLocationMap().getLine(semanticElement);
return line;
}
return -1;
}
/**
* In order to get the target layout information, the column number of the
* model element is taken from the EMFText document. This will be the x value.
*
* @param context the context object
* @return column number
*/
private int getColumn(EObject context) {
if (!CompositionDiagramUtil.getDerivedFrom(context).isEmpty()) {
EObject semanticElement = getFirstSource(context);
if (semanticElement == null) {
return -1;
}
Resource resource = semanticElement.eResource();
if (resource == null) {
return -1;
}
IResource textRess = castToTextResource(resource);
if (textRess == null) {
return -1;
}
int column = textRess.getLocationMap().getColumn(semanticElement);
return column;
}
return -1;
}
/**
* Returns the index of the current element in the EMFText model.
*
* @param context the context object
* @return index of the element
*/
private int findTarget(EObject context) {
if (!CompositionDiagramUtil.getDerivedFrom(context).isEmpty()) {
EObject semanticElement = getFirstSource(context);
if ((semanticElement == null)) {
return -1;
}
EObject container = semanticElement.eContainer();
if (container == null) {
Resource resource = semanticElement.eResource();
if (resource == null) {
return -1;
}
return resource.getContents().indexOf(semanticElement);
}
Object object = container.eGet(semanticElement.eContainmentFeature());
if (object instanceof List) {
List<?> list = (List<?>) object;
return list.indexOf(semanticElement);
}
}
return -1;
}
private EObject getFirstSource(EObject context) {
if (CompositionDiagramUtil.getDerivedFrom(context).isEmpty()) {
return null;
}
EObject copy = CompositionDiagramUtil.getDerivedFrom(context).get(0);
EObject original = CompositionDiagramUtil.getOriginal(copy);
return original != null ? original : copy;
}
private IResource castToTextResource(Resource resource) {
try {
//check if this resource provides "getLocationMap"
resource.getClass().getMethod("getLocationMap", new Class[]{});
} catch (Exception e) {
return null;
}
return (IResource) EMFTextAccessProxy.get(resource, IResource.class);
}
}