/* * 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; } }