X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.interop.diagram%2Fsrc%2Forg%2Fsimantics%2Finterop%2Fdiagram%2FDiagram.java;fp=org.simantics.interop.diagram%2Fsrc%2Forg%2Fsimantics%2Finterop%2Fdiagram%2FDiagram.java;h=5695798e65946d0ffaa59918053f81dbfa933eb7;hb=3e6e743ffe75f5724406e1dd01589386efe04782;hp=0000000000000000000000000000000000000000;hpb=346583f7344dc5dce3ebb7b183aaa22c9e2a1aa3;p=simantics%2Finterop.git diff --git a/org.simantics.interop.diagram/src/org/simantics/interop/diagram/Diagram.java b/org.simantics.interop.diagram/src/org/simantics/interop/diagram/Diagram.java new file mode 100644 index 0000000..5695798 --- /dev/null +++ b/org.simantics.interop.diagram/src/org/simantics/interop/diagram/Diagram.java @@ -0,0 +1,711 @@ +package org.simantics.interop.diagram; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.RequestProcessor; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.procedure.adapter.TransientCacheListener; +import org.simantics.db.common.request.ResourceRead; +import org.simantics.db.common.utils.OrderedSetUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.exception.ManyObjectsForFunctionalRelationException; +import org.simantics.db.exception.NoSingleResultException; +import org.simantics.db.exception.ServiceException; +import org.simantics.db.layer0.adapter.Template; +import org.simantics.diagram.stubs.DiagramResource; +import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; +import org.simantics.g2d.page.DiagramDesc; +import org.simantics.layer0.Layer0; +import org.simantics.modeling.ModelingResources; +import org.simantics.operation.Layer0X; +import org.simantics.simulation.ontology.SimulationResource; +import org.simantics.structural.stubs.StructuralResource2; +import org.simantics.utils.datastructures.Arrays; +import org.simantics.utils.page.PageDesc; + + +/** + * @author Marko Luukkainen + */ +public abstract class Diagram { + + public static boolean DO_NO_MIX_SECTION_NAMES = false; + public static boolean USE_MERGE_CONNECTS = true; + + private Resource composite; + private Resource diagram; + + private Map indexMap = new HashMap(); + + private Map elementToSymbolMap = new HashMap(); + + private Map> compositeToDiagramMap = new HashMap>(); + + protected Diagram(ReadGraph g, Resource composite, Resource diagram) throws DatabaseException { + this.composite = composite; + this.diagram = diagram; + } + + protected abstract Diagram construct(ReadGraph g, Resource composite, Resource diagram) throws DatabaseException; + protected abstract T constructSymbol(ReadGraph g, Resource element, Resource component) throws DatabaseException; + + public Resource getComposite() { + return composite; + } + + public Resource getDiagram() { + return diagram; + } + + + public void clearCaches() { + for (Diagram d : compositeToDiagramMap.values()) { + for (T s : d.elementToSymbolMap.values()) + s.dispose(); + d.elementToSymbolMap.clear(); + } + compositeToDiagramMap.clear(); + } + + + public String generateName(ReadGraph g, Resource type, String name) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(g); + Layer0X l0x = Layer0X.getInstance(g); + String prefix = g.getPossibleRelatedValue(type, l0x.HasGeneratedNamePrefix); + if (prefix == null || prefix.length() == 0) + prefix = g.getRelatedValue(type, l0.HasName); + prefix += "_"; + Set reserved = null; + if (name != null) { + reserved = getAllModuleNamesForModel(g, composite); + int index = 0; + String realname = name + "_" + prefix; + while (true) { + String toTry = realname + Integer.toString(index); + if (!reserved.contains(toTry)) + break; + index++; + } + realname += Integer.toString(index); + return realname; + } + Integer index = indexMap.get(type); + if (index != null) { + index++; + } else { + if (reserved == null) + reserved = getAllModuleNamesForModel(g, composite); + index = 0; + while (true) { + String toTry = prefix + Integer.toString(index); + if (!reserved.contains(toTry)) + break; + index++; + } + + } + indexMap.put(type, index); + return prefix + index; + } + + private Set getAllModuleNamesForModel(ReadGraph graph, final Resource res) throws DatabaseException { + + Resource model = DiagramUtils.getModel(graph, res); + Resource configuration = DiagramUtils.getConfiguration(graph, model); + Set names = new HashSet(); + Collection composites = getAllComposites(graph, configuration); + for (Resource composite : composites) { + names.addAll(getAllModuleNamesForComposite(graph, composite)); + } + return names; + } + + protected abstract Resource getGraphicalCompositeType(ReadGraph graph) throws DatabaseException; + protected abstract Resource getFolderType(ReadGraph graph) throws DatabaseException; + + @SuppressWarnings("unchecked") + private Collection getAllComposites(RequestProcessor processor, Resource configuration) throws DatabaseException { + return (Set)processor.syncRequest(new ResourceRead(configuration) { + @Override + public Object perform(ReadGraph graph) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(graph); + Set composites = new HashSet(); + Stack resources = new Stack(); + Resource graphicalCompositeType = getGraphicalCompositeType(graph); + Resource folderType = getFolderType(graph); + resources.add(resource); + while (!resources.isEmpty()) { + Resource r = resources.pop(); + if (graph.isInstanceOf(r, graphicalCompositeType)) { + composites.add(r); + } else if (folderType != null && graph.isInstanceOf(r, folderType)){ + resources.addAll(graph.getObjects(r, l0.ConsistsOf)); + } + } + return composites; + } + }, TransientCacheListener.instance()); + } + + @SuppressWarnings("unchecked") + private Set getAllModuleNamesForComposite(RequestProcessor processor, Resource composite) throws DatabaseException { + return (Set)processor.syncRequest(new ResourceRead(composite) { + @Override + public Object perform(ReadGraph graph) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(graph); + Set names = new HashSet(); + Collection components = graph.getObjects(resource, l0.ConsistsOf); + for (Resource component : components) { + String n = graph.getPossibleRelatedValue(component, l0.HasName, Bindings.STRING); + if (n != null) + names.add(n); + } + return names; + } + }, TransientCacheListener.instance()); + + } + + public Diagram createDiagram(WriteGraph g,String name, Resource compositeType, Resource parent) throws DatabaseException { + return createDiagram(g, name, null, null,compositeType, parent); + } + + + + /** + * Creates a new Diagram + * @param g + * @param name name of the diagram + * @param compositeType composite type of the diagram + * @param parent resource where diagram is added + * @return + * @throws DatabaseException + */ + @SuppressWarnings("deprecation") + public Diagram createDiagram(WriteGraph g,String name, DiagramDesc desc, Template tpl, Resource compositeType, Resource parent) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(g); + Layer0X l0x = Layer0X.getInstance(g); + ModelingResources m = ModelingResources.getInstance(g); + + // create composite + Resource composite = g.newResource(); + g.claim(composite, l0.InstanceOf, compositeType); + + // create diagram + Resource diagramType = getDiagramFromComposite(g, compositeType); + + Resource diagram = OrderedSetUtils.create(g, diagramType); + + g.claim(composite, m.CompositeToDiagram, diagram); + + // link to parent and set name + g.claimLiteral(composite, l0.HasName, name); + g.claim(composite, l0.PartOf, parent); + + // activate mapping + Resource mapping = g.newResource(); + g.claim(mapping, l0.InstanceOf, m.DiagramToCompositeMapping); + g.claim(diagram, l0x.HasTrigger, mapping); + + if (tpl != null) { + Map params = new HashMap(); + params.put("diagram", diagram); + tpl.apply(g, params); + } + + + // Make diagram part of a dummy container library attached to the parent + // composite if it's not already part of something. + // This gives the diagram a proper URI without connecting it directly to the composite with ConsistsOf. + // This would cause problems because a diagram is a structural composite/component also. + g.claimLiteral(diagram, l0.HasName, name, Bindings.STRING); + Resource container = g.newResource(); + g.claim(container, l0.InstanceOf, null, l0.Library); + g.addLiteral(container, l0.HasName, l0.NameOf, l0.String, "__CONTAINER__", Bindings.STRING); + g.claim(container, l0.ConsistsOf, diagram); + g.claim(composite, l0.ConsistsOf, container); + + if (desc != null) + DiagramGraphUtil.setDiagramDesc(g, diagram, desc); + + Diagram diag = construct(g, composite, diagram); + diag.compositeToDiagramMap = compositeToDiagramMap; + compositeToDiagramMap.put(composite, diag); + return diag; + } + + public Diagram fromExisting(ReadGraph g, Resource diagram) throws DatabaseException { + ModelingResources m = ModelingResources.getInstance(g); + StructuralResource2 s = StructuralResource2.getInstance(g); + Resource composite = null; + if (g.isInstanceOf(diagram, s.Composite)) { + composite = diagram; + diagram = g.getPossibleObject(composite, m.CompositeToDiagram); + if (diagram == null) + return null; + } else { + composite = g.getPossibleObject(diagram, m.DiagramToComposite); + if (composite == null) + return null; + } + + Diagram diag = compositeToDiagramMap.get(composite); + if (diag != null) + return diag; + + diag = construct(g,composite, diagram); + diag.compositeToDiagramMap = compositeToDiagramMap; + compositeToDiagramMap.put(composite, diag); + return diag; + } + + + + + + /** + * Returns diagram type from composite type + * @param g + * @param compositeType + * @return diagram type + * @throws NoSingleResultException + * @throws ManyObjectsForFunctionalRelationException + * @throws ServiceException + */ + private static Resource getDiagramFromComposite(ReadGraph g, Resource compositeType) throws DatabaseException { + ModelingResources m = ModelingResources.getInstance(g); + Collection diagramTemplates = g.getAssertedObjects(compositeType, m.HasModelingTemplate); + for (Resource diagramTemplate : diagramTemplates) { + Resource diagramType = g.getPossibleObject(diagramTemplate, m.HasDiagramType); + if (diagramType != null) + return diagramType; + + } + throw new RuntimeException("Cannot find diagramType for composite " + compositeType); + } + + + + + /** + * Adds new symbol to a diagram + * @param g + * @param symbolType + * @return + * @throws DatabaseException + */ + public T addSymbol(WriteGraph g, Resource symbolType) throws DatabaseException { + return addSymbol(g, symbolType, 0, 0); + } + + /** + * Adds new symbol to a diagram + * @param g + * @param symbolType + * @param name + * @return + * @throws DatabaseException + */ + public T addSymbol(WriteGraph g, Resource symbolType, String name) throws DatabaseException { + return addSymbol(g, symbolType, name, 0, 0); + } + + /** + * Adds new symbol to a diagram + * @param g + * @param diagramConf Diagram configuration + * @param symbolType type of the new symbol + * @param x + * @param y + * @return configuration of the new Symbol + * @throws DatabaseException + */ + public T addSymbol(WriteGraph g, Resource symbolType, double x, double y) throws DatabaseException { + return addSymbol(g, symbolType,null,x,y); + } + + /** + * Adds new symbol to a diagram + * @param g + * @param elementType + * @param name + * @param x + * @param y + * @return + * @throws DatabaseException + */ + public T addSymbol(WriteGraph g, Resource elementType, String name, double x, double y) throws DatabaseException { + if (elementType == null) + throw new NullPointerException("Element type is null"); + Layer0 l0 = Layer0.getInstance(g); + + DiagramResource d = DiagramResource.getInstance(g); + ModelingResources m = ModelingResources.getInstance(g); + + Resource componentType = null; + if (g.isInheritedFrom(elementType, d.DefinedElement)) + componentType = Symbol.getComponentTypeFromSymbolType(g, elementType); + else { + componentType = elementType; + elementType = Symbol.getSymbolTypeFromComponentType(g,componentType); + } + + + Resource element = g.newResource(); + g.claim(element, l0.InstanceOf, elementType); + + Resource module = g.newResource(); + g.claim(module, l0.InstanceOf, componentType); + + g.claim(module, m.ComponentToElement, element); + g.claim(module, m.Mapped, module); + + String id = generateName(g, componentType, name); + g.claimLiteral(module, l0.HasName, id); + g.claimLiteral(element, l0.HasName, id); + + OrderedSetUtils.add(g, this.diagram, element); + g.claim(this.diagram, l0.ConsistsOf, element); + g.claim(this.composite, l0.ConsistsOf, module); + + T s = constructSymbol(g, element, module); + s.setSymbolTranslation(g, x, y); + + elementToSymbolMap.put(element, s); + return s; + } + + /** + * Returns a Symbol for given resource. + * @param g + * @param element Element or Component of the Symbol. + * @return + * @throws ManyObjectsForFunctionalRelationException + * @throws ServiceException + * @throws NoSingleResultException + */ + public T getSymbol(ReadGraph g, Resource element) throws DatabaseException { + ModelingResources mr = ModelingResources.getInstance(g); + DiagramResource dr = DiagramResource.getInstance(g); + if (g.isInstanceOf(element, dr.Element)) + return getSymbol(g, element, g.getPossibleObject(element, mr.ElementToComponent)); + else + return getSymbol(g, g.getSingleObject(element, mr.ComponentToElement), element); + } + + /** + * Returns a Symbol for given resource. + * @param g + * @param element Element Resource of the Symbol. + * @param component Component Resource of the symbol. + * @return + */ + public T getSymbol(ReadGraph g, Resource element, Resource component) throws DatabaseException { + T s = elementToSymbolMap.get(element); + if (s == null) { + // TODO : check that symbol actually belongs to this diagram + s = constructSymbol(g, element, component); + elementToSymbolMap.put(element, s); + } else { + if (s.component == null) + s.component = component; + else if (!s.component.equals(component)) { + // FIXME : ? + return constructSymbol(g, element, component); + } + } + return s; + } + + /** + * Adds new element to a diagram + * @param g + * @param symbolType type of the element. + * @param x + * @param y + * @return + * @throws DatabaseException + */ + public T addElement(WriteGraph g, Resource symbolType, double x, double y) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(g); + + Resource element = g.newResource(); + g.claim(element, l0.InstanceOf, symbolType); + + DiagramUtils.addElement(g, this, element); + + T s = constructSymbol(g,element,null); + + s.setSymbolTranslation(g, x, y); + + elementToSymbolMap.put(element, s); + return s; + } + + public T getSingleSymbol(ReadGraph g, String symbolName) throws DatabaseException { + List matching = getSymbol(g, symbolName); + if (matching.size() == 1) + return matching.get(0); + if (matching.size() == 0) + return null; + throw new NoSingleResultException("There are multiple symbols with name '" + symbolName); + } + + public T getPossibleSymbol(ReadGraph g, String symbolName) throws DatabaseException { + List matching = getSymbol(g, symbolName); + if (matching.size() == 1) + return matching.get(0); + return null; + } + + /** + * Returns all symbols on the diagram + * @param g + * @return + * @throws DatabaseException + */ + public List getSymbols(ReadGraph g) throws DatabaseException { + ModelingResources m = ModelingResources.getInstance(g); + List matching = new ArrayList(); + for (Resource element : OrderedSetUtils.toList(g, diagram)) { + Resource component = g.getPossibleObject(element, m.ElementToComponent); + matching.add(getSymbol(g,element, component)); + } + return matching; + } + + /** + * Returns symbols that have matching name. + * + * Prioritizes L0.HasLabel over L0.HasName (If symbol has label, it is used for comparison). + * + * ';' character acts as a splitter, allowing input parameter and a label contain multiple identifiers. + * + * All the splits + * + * @param g + * @param symbolName + * @return + * @throws DatabaseException + */ + public List getSymbol(ReadGraph g, String symbolName) throws DatabaseException { + ModelingResources m = ModelingResources.getInstance(g); + Layer0 b = Layer0.getInstance(g); + List matching = new ArrayList(); + + String splitId[] = symbolName.split(";"); + + for (Resource element : OrderedSetUtils.toList(g, diagram)) { + Resource component = g.getPossibleObject(element, m.ElementToComponent); + if (component == null) + component = g.getPossibleObject(element, m.HasParentComponent); + if (component == null) + continue; + String label = g.getPossibleRelatedValue(component, b.HasLabel); + String name = g.getRelatedValue(component, b.HasName); + if (label != null) { + String splitLabel[] = label.split(";"); + + boolean match = true; + for (int i = 0; i < splitId.length; i++) { + if(!Arrays.contains(splitLabel, splitId[i])) { + match = false; + break; + } + } + if (match) { + matching.add(getSymbol(g,element, component)); + } else { + if (label.equals(symbolName) || name.equals(symbolName)) { + matching.add(getSymbol(g,element, component)); + + } + } + + } else { + for (String split : splitId) { + if (name.equals(split)) { + matching.add(getSymbol(g,element, component)); + } + } + + } + } + return matching; + } + + /** + * Returns a single symbol matching given name and type. If matching symbol cannot be found, returns null. + * Throws a NoSingleResultException if the re are multiple symbols matching the criteria. + * + * @param g + * @param symbolName + * @param symbolType + * @return + * @throws DatabaseException + */ + public T getSingleSymbol(ReadGraph g, String symbolName, Resource symbolType) throws DatabaseException { + List matching = getSymbol(g, symbolName, symbolType); + if (matching.size() == 1) + return matching.get(0); + if (matching.size() == 0) + return null; + throw new NoSingleResultException("There are multiple symbols with name '" + symbolName + "' and type " + symbolType); + } + + public T getPossibleSymbol(ReadGraph g, String symbolName, Resource symbolType) throws DatabaseException { + List matching = getSymbol(g, symbolName, symbolType); + if (matching.size() == 1) + return matching.get(0); + return null; + } + + /** + * Returns symbols matching given name and type. + * + * @param g + * @param symbolName + * @param symbolType + * @return + * @throws DatabaseException + */ + public List getSymbol(ReadGraph g, String symbolName, Resource symbolType) throws DatabaseException { + + List nameMatching = getSymbol(g, symbolName); + List matching = new ArrayList(); + for (T s : nameMatching) { + if ((g.isInstanceOf(s.getElement(), symbolType)|| + g.isInstanceOf(s.getComponent(), symbolType))) { + matching.add(s); + } + } + return matching; + } + + public Symbol getFlag(ReadGraph g, Resource flagType, String symbolName, Resource symbolType) throws DatabaseException { + Layer0 b = Layer0.getInstance(g); + DiagramResource dr = DiagramResource.getInstance(g); + List matching = new ArrayList(); + for (Resource flag : OrderedSetUtils.toList(g, diagram)) { + if (!g.isInstanceOf(flag, dr.Flag)) + continue; + if (!g.getSingleObject(flag, dr.HasFlagType).equals(flagType)) + continue; + Symbol flagSymbol = getSymbol(g,flag, null); + + Symbol connectedSymbol = flagSymbol.getDiagramSingleConnected(g, dr.Flag_ConnectionPoint); + Resource component = connectedSymbol.getComponent(); + if (component == null) + continue; + String label = g.getPossibleRelatedValue(component, b.HasLabel); + String name = g.getRelatedValue(component, b.HasName); + if (label != null) { + String splitId[] = symbolName.split(";"); + if (splitId.length > 1) { + String splitLabel[] = label.split(";"); + boolean match = true; + for (int i = 0; i < splitId.length; i++) { + if(!Arrays.contains(splitLabel, splitId[i])) { + match = false; + break; + } + } + if (match) { + if (g.isInstanceOf(connectedSymbol.getElement(), symbolType)|| + g.isInstanceOf(component, symbolType)) { + matching.add(getSymbol(g,flag, null)); + } + + } + } else { + if (label.equals(symbolName) || name.equals(symbolName)) { + if (g.isInstanceOf(connectedSymbol.getElement(), symbolType)|| + g.isInstanceOf(component, symbolType)) { + matching.add(getSymbol(g,flag, null)); + } + + } + } + + } else { + if (name.equals(symbolName)) { + if (g.isInstanceOf(connectedSymbol.getElement(), symbolType)|| + g.isInstanceOf(component, symbolType)) { + matching.add(getSymbol(g,flag, null)); + } + } + + } + } + if (matching.size() == 1) + return matching.get(0); + if (matching.size() == 0) + return null; + throw new NoSingleResultException("There are multiple flags connecting symbol with name '" + symbolName + "' and type " + symbolType); + + } + + public PageDesc getPageDesc(ReadGraph g) throws DatabaseException { + PageDesc pDesc = DiagramGraphUtil.getPageDesc(g, diagram, PageDesc.DEFAULT); + return pDesc; + } + + @Override + public boolean equals(Object o) { + if (o == null) + return false; + if (this.getClass() != o.getClass()) + return false; + Diagram other = (Diagram)o; + return diagram.equals(other.diagram); + } + + @Override + public int hashCode() { + return diagram.hashCode(); + } + + void merge(Symbol to, Symbol from) { + Resource element = from.getElement(); + for (Symbol s : elementToSymbolMap.values()) { + if (s.element.equals(element)) { + s.element = to.element; + s.component = to.component; + } + } + from.element = to.element; + from.component = to.component; + } + + /** + * Returns a model containing the diagram. + * @param g + * @return + * @throws DatabaseException + */ + public Resource getModel(ReadGraph g) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(g); + SimulationResource sim = SimulationResource.getInstance(g); + Resource r = composite; + while (true) { + Resource parent = g.getSingleObject(r, l0.PartOf); + if (g.isInstanceOf(parent, sim.Model)) + return parent; + r = parent; + } + } + + + +} +