blob: 1a11bba835ca78b1f9d049a580fca0d9e4f0e0df [file] [log] [blame]
/*
* Copyright (c) 2005, 2008 Borland Software Corporation
*
* 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:
* Artem Tikhomirov (Borland) - initial API and implementation
*/
package org.eclipse.gmf.internal.bridge.genmodel;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import org.eclipse.emf.codegen.util.CodeGenUtil;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.gmf.codegen.gmfgen.FigureViewmap;
import org.eclipse.gmf.codegen.gmfgen.GMFGenFactory;
import org.eclipse.gmf.codegen.gmfgen.InnerClassViewmap;
import org.eclipse.gmf.codegen.gmfgen.ParentAssignedViewmap;
import org.eclipse.gmf.codegen.gmfgen.Viewmap;
import org.eclipse.gmf.gmfgraph.Border;
import org.eclipse.gmf.gmfgraph.BorderRef;
import org.eclipse.gmf.gmfgraph.ChildAccess;
import org.eclipse.gmf.gmfgraph.Compartment;
import org.eclipse.gmf.gmfgraph.CompoundBorder;
import org.eclipse.gmf.gmfgraph.Connection;
import org.eclipse.gmf.gmfgraph.CustomBorder;
import org.eclipse.gmf.gmfgraph.CustomFigure;
import org.eclipse.gmf.gmfgraph.CustomLayout;
import org.eclipse.gmf.gmfgraph.DiagramLabel;
import org.eclipse.gmf.gmfgraph.Figure;
import org.eclipse.gmf.gmfgraph.FigureDescriptor;
import org.eclipse.gmf.gmfgraph.FigureGallery;
import org.eclipse.gmf.gmfgraph.FigureRef;
import org.eclipse.gmf.gmfgraph.GMFGraphPackage;
import org.eclipse.gmf.gmfgraph.LayoutRef;
import org.eclipse.gmf.gmfgraph.Node;
import org.eclipse.gmf.gmfgraph.RealFigure;
import org.eclipse.gmf.graphdef.codegen.FigureGenerator;
import org.eclipse.gmf.graphdef.codegen.MapModeCodeGenStrategy;
/**
* @author artem
*/
public class InnerClassViewmapProducer extends DefaultViewmapProducer {
private final FigureGenerator figureGenerator;
private final int[] figuresWithExtraRTBehaviour;
public InnerClassViewmapProducer() {
this(null, MapModeCodeGenStrategy.DYNAMIC, null);
}
public InnerClassViewmapProducer(String runtimeToken, MapModeCodeGenStrategy mapModeCodeGenStrategy, URL[] dynamicFigureTemplates) {
figureGenerator = new FigureGenerator(runtimeToken, null, mapModeCodeGenStrategy, null, true, dynamicFigureTemplates);
if (runtimeToken == null || "full".equalsIgnoreCase(runtimeToken)) {
figuresWithExtraRTBehaviour = new int[] { GMFGraphPackage.POLYLINE_CONNECTION, GMFGraphPackage.LABEL };
Arrays.sort(figuresWithExtraRTBehaviour);
} else {
figuresWithExtraRTBehaviour = new int[0];
}
}
@Override
public Viewmap create(Node node) {
if (node.getFigure() == null) {
return super.create(node);
}
final Viewmap viewmap = createViewmap(node.getFigure());
setupResizeConstraints(viewmap, node);
setupLayoutType(viewmap, node);
setupDefaultSize(viewmap, node);
return viewmap;
}
@Override
public Viewmap create(Connection link) {
if (link.getFigure() == null) {
return super.create(link);
}
return createViewmap(link.getFigure());
}
@Override
public Viewmap create(DiagramLabel diagramLabel) {
if (diagramLabel.getFigure() == null) {
return super.create(diagramLabel);
}
if (diagramLabel.getAccessor() == null) {
return createViewmap(diagramLabel.getFigure());
} else {
return createViewmap(diagramLabel.getFigure(), diagramLabel.getAccessor());
}
}
@Override
public Viewmap create(Compartment compartment) {
if (compartment.getFigure() == null){
return super.create(compartment);
}
if (compartment.getAccessor() == null) {
return createViewmap(compartment.getFigure());
} else {
return createViewmap(compartment.getFigure(), compartment.getAccessor());
}
}
private Viewmap createViewmap(FigureDescriptor figureDescriptor) {
Viewmap result;
if (figureDescriptor.getActualFigure() == null) {
throw new NullPointerException();
}
final Figure figure = figureDescriptor.getActualFigure();
if (figure instanceof RealFigure && isBareInstance((RealFigure) figure)) {
FigureViewmap v = GMFGenFactory.eINSTANCE.createFigureViewmap();
v.setFigureQualifiedClassName(figureGenerator.fqnSwitch(figure));
result = v;
// XXX perhaps, create SnippetViewmap when there are no children but some props
} else {
InnerClassViewmap v = GMFGenFactory.eINSTANCE.createInnerClassViewmap();
v.setClassBody(figureGenerator.go(figureDescriptor));
v.setClassName(getCompilationUnitName(figureDescriptor));
result = v;
}
setupPluginDependencies(result, figureDescriptor.getActualFigure());
setupStyleAttributes(result, figureDescriptor.getActualFigure());
return result;
}
private Viewmap createViewmap(FigureDescriptor owner, ChildAccess labelAccess) {
ParentAssignedViewmap v = GMFGenFactory.eINSTANCE.createParentAssignedViewmap();
v.setGetterName(labelAccess.getAccessor());
v.setFigureQualifiedClassName(figureGenerator.fqnSwitch(labelAccess.getFigure()));
setupStyleAttributes(v, labelAccess.getFigure());
return v;
}
// XXX shouldn't that reside in superclass -
// use of fqnSwitch is questionable anyway, for all but first gallery
// we don't need to delegate to switch, and should rather use
// implementationBundle field directly (though that's true only
// if borders and layouts are from another FG, if there are FigureRefs,
// delegating to fqnSwitch to find out dependencies may be reasonable)
private void setupPluginDependencies(Viewmap viewmap, Figure figure){
for (FigureGallery gallery : findAllGalleriesForImport(figure)) {
if (gallery.getImplementationBundle() != null){
myDependencies.add(gallery.getImplementationBundle());
}
}
if (figuresWithExtraRTBehaviour.length > 0 && Arrays.binarySearch(figuresWithExtraRTBehaviour, figure.eClass().getClassifierID()) >= 0) {
myDependencies.add("org.eclipse.gmf.runtime.draw2d.ui"); //$NON-NLS-1$
}
}
// public to have access from tests. FIXME may need extra check for endless
// recursion (like CompoundBorder.outer = BorderRef which points to same CompoundBorder)
public static Collection<FigureGallery> findAllGalleriesForImport(Figure figure) {
LinkedHashSet<FigureGallery> rv = new LinkedHashSet<FigureGallery>();
rv.add(findAncestorFigureGallery(figure));
LinkedList<Figure> queue = new LinkedList<Figure>();
queue.add(figure);
do {
final RealFigure fig;
if (queue.peek() instanceof RealFigure) {
fig = (RealFigure) queue.removeFirst();
} else if (queue.peek() instanceof FigureRef) {
fig = ((FigureRef) queue.removeFirst()).getFigure();
} else {
assert false; // no more known subclasses of Figure at the time.
queue.removeFirst();
continue;
}
if (fig.getLayout() instanceof LayoutRef && ((LayoutRef) fig.getLayout()).getActual() instanceof CustomLayout) {
rv.add(findAncestorFigureGallery(((LayoutRef) fig.getLayout()).getActual()));
}
if (fig.getBorder() != null) {
LinkedList<Border> borderQueue = new LinkedList<Border>();
borderQueue.add(fig.getBorder());
do {
if (borderQueue.peek() instanceof BorderRef) {
borderQueue.add(((BorderRef) borderQueue.peek()).getActual());
} else if (borderQueue.peek() instanceof CompoundBorder) {
CompoundBorder b = (CompoundBorder) borderQueue.peek();
borderQueue.addLast(b.getInner());
borderQueue.addLast(b.getOuter());
} else if (borderQueue.peek() instanceof CustomBorder) {
rv.add(findAncestorFigureGallery(borderQueue.peek()));
}
borderQueue.removeFirst(); // effectively removes any null value as well
} while (!borderQueue.isEmpty());
}
queue.addAll(fig.getChildren());
} while (!queue.isEmpty());
rv.remove(null);
return rv;
}
public static FigureGallery findAncestorFigureGallery(EObject figure){
EObject current = figure;
while (true){
EObject next = current.eContainer();
if (next == null){
return null;
} else if (next instanceof FigureGallery){
return (FigureGallery)next;
} else {
current = next;
}
}
}
private static String getCompilationUnitName(FigureDescriptor fd) {
// XXX either use Util.ext or have some template to invoke
return CodeGenUtil.validJavaIdentifier(CodeGenUtil.capName(fd.getName()));
}
private static boolean isBareInstance(RealFigure figure) {
if (!figure.getChildren().isEmpty()) {
return false;
}
final Collection<EStructuralFeature> featuresToCheck = new LinkedList<EStructuralFeature>(figure.eClass().getEAllStructuralFeatures());
featuresToCheck.remove(GMFGraphPackage.eINSTANCE.getRealFigure_Name());
featuresToCheck.remove(GMFGraphPackage.eINSTANCE.getRealFigure_Children());
if (figure instanceof CustomFigure) {
featuresToCheck.remove(GMFGraphPackage.eINSTANCE.getCustomClass_QualifiedClassName());
featuresToCheck.remove(GMFGraphPackage.eINSTANCE.getCustomFigure_CustomChildren());
}
for (EStructuralFeature next : featuresToCheck) {
if (next.isDerived()) {
continue;
}
if (figure.eIsSet(next)) {
return false;
}
}
return true;
}
}