1 /*******************************************************************************
2 * Copyright (c) 2007, 2016 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 * Semantum Oy - refactoring
12 *******************************************************************************/
13 package org.simantics.diagram.adapter;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.Collections;
20 import org.simantics.db.AsyncReadGraph;
21 import org.simantics.db.ReadGraph;
22 import org.simantics.db.Resource;
23 import org.simantics.db.Session;
24 import org.simantics.db.common.procedure.guarded.GuardedAsyncProcedureWrapper;
25 import org.simantics.db.exception.DatabaseException;
26 import org.simantics.db.procedure.AsyncProcedure;
27 import org.simantics.diagram.adapter.RouteGraphUtils.BackendConnection;
28 import org.simantics.diagram.connection.RouteGraph;
29 import org.simantics.diagram.connection.rendering.ConnectionStyle;
30 import org.simantics.diagram.connection.rendering.StyledRouteGraphRenderer;
31 import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle;
32 import org.simantics.diagram.content.ResourceTerminal;
33 import org.simantics.diagram.stubs.DiagramResource;
34 import org.simantics.diagram.ui.DiagramModelHints;
35 import org.simantics.g2d.canvas.ICanvasContext;
36 import org.simantics.g2d.connection.ConnectionEntity;
37 import org.simantics.g2d.diagram.IDiagram;
38 import org.simantics.g2d.diagram.handler.DataElementMap;
39 import org.simantics.g2d.diagram.handler.Topology.Connection;
40 import org.simantics.g2d.diagram.handler.Topology.Terminal;
41 import org.simantics.g2d.element.ElementClass;
42 import org.simantics.g2d.element.ElementHints;
43 import org.simantics.g2d.element.IElement;
44 import org.simantics.g2d.element.handler.TerminalTopology;
45 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
46 import org.simantics.g2d.elementclass.RouteGraphConnectionClass;
47 import org.simantics.g2d.utils.TopologicalSelectionExpander;
48 import org.simantics.layer0.Layer0;
49 import org.simantics.modeling.ModelingResources;
50 import org.simantics.scenegraph.g2d.nodes.connection.IRouteGraphListener;
51 import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphChangeEvent;
52 import org.simantics.structural.stubs.StructuralResource2;
53 import org.simantics.structural2.modelingRules.IModelingRules;
55 import gnu.trove.set.hash.THashSet;
58 * An element class for single connection entity elements. A connection entity
59 * consists of connection edge segments and branch points as its children.
61 * @author Tuukka Lehtonen
63 public class RouteGraphConnectionClassFactory extends SyncElementFactory {
65 public static final ElementClass CLASS = RouteGraphConnectionClass.CLASS;
67 public static final ILineEndStyle HEAD = RouteGraphUtils.HEAD;
68 public static final ILineEndStyle TAIL = RouteGraphUtils.TAIL;
71 protected DiagramResource DIA;
72 protected StructuralResource2 STR;
73 protected ModelingResources MOD;
75 public RouteGraphConnectionClassFactory(ReadGraph graph) {
76 this.L0 = Layer0.getInstance(graph);
77 this.DIA = DiagramResource.getInstance(graph);
78 this.STR = StructuralResource2.getInstance(graph);
79 this.MOD = ModelingResources.getInstance(graph);
83 public void create(AsyncReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource elementType,
84 final AsyncProcedure<ElementClass> procedure) {
85 procedure.execute(graph, CLASS.newClassWith(false, new StaticObjectAdapter(elementType)));
89 protected Resource getElementClassBaseType(AsyncReadGraph graph) {
90 return DIA.Connection;
94 public void load(AsyncReadGraph graph, final ICanvasContext canvas, final IDiagram diagram,
95 final Resource elementResource, final IElement element, final AsyncProcedure<IElement> procedure) {
96 GuardedAsyncProcedureWrapper<IElement> guard = new GuardedAsyncProcedureWrapper<IElement>(procedure, 2);
97 super.load(graph, canvas, diagram, elementResource, element, guard);
98 ElementFactoryUtil.loadLayersForElement(graph, diagram, element, elementResource, guard);
102 public void load(ReadGraph graph, ICanvasContext canvas, IDiagram diagram, final Resource connection,
103 IElement element) throws DatabaseException {
105 IModelingRules modelingRules = diagram.getHint(DiagramModelHints.KEY_MODELING_RULES);
106 Resource diagramRuntime = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RUNTIME_RESOURCE);
108 Set<BackendConnection> backendConnections = new THashSet<>();
109 RouteGraph rg = RouteGraphUtils.load(graph, diagramRuntime, connection, canvas, diagram, element, modelingRules, backendConnections);
111 // Load connection line style.
112 ConnectionStyle style = RouteGraphUtils.readConnectionStyle(graph, modelingRules, connection, STR, DIA);
113 StyledRouteGraphRenderer renderer = RouteGraphUtils.getRenderer(graph, style);
115 // Finish element load
116 element.setHint(RouteGraphConnectionClass.KEY_ROUTEGRAPH, rg);
117 element.setHint(RouteGraphConnectionClass.KEY_RENDERER, renderer);
118 element.setHint(RouteGraphConnectionClass.KEY_PICK_TOLERANCE, 0.5);
120 // Initialize ConnectionEntity in element
121 element.setHint(ElementHints.KEY_CONNECTION_ENTITY, new CE(diagram, connection, element, backendConnections));
123 // Setup graph writeback support for route graph modifications
124 Session session = graph.getSession();
125 element.setHint(RouteGraphConnectionClass.KEY_RG_LISTENER, new IRouteGraphListener() {
127 public void routeGraphChanged(RouteGraphChangeEvent event) {
128 RouteGraphUtils.scheduleSynchronize(session, connection, event);
134 * Must have this in order for {@link TopologicalSelectionExpander} to work.
135 * Otherwise this is pretty useless and should be deprecated altogether.
137 * @see ElementHints#KEY_CONNECTION_ENTITY
139 public static class CE implements ConnectionEntity {
142 * Needed to gain access to {@link DataElementMap}.
144 final IDiagram diagram;
147 * The connection instance resource in the graph database back-end.
149 final Resource connection;
152 * The current element mapped to connection.
154 IElement connectionElement;
157 * @see #getTerminalConnections(Collection)
159 final Set<BackendConnection> backendConnections;
164 transient Set<Connection> terminalConnections;
166 public CE(IDiagram diagram, Resource connection, IElement connectionElement, Set<BackendConnection> backendConnections) {
167 if (connectionElement == null)
168 throw new NullPointerException("null connection element");
169 this.diagram = diagram;
170 this.connection = connection;
171 this.connectionElement = connectionElement;
172 this.backendConnections = backendConnections;
173 IElement ce = getConnection0();
175 this.connectionElement = ce;
178 public IElement getConnection0() {
179 DataElementMap dem = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
180 IElement connectionElement = dem.getElement(diagram, connection);
181 return connectionElement;
185 public IElement getConnection() {
186 IElement c = getConnection0();
188 c = this.connectionElement;
193 public Collection<IElement> getBranchPoints(Collection<IElement> result) {
194 return result != null ? result : Collections.<IElement> emptyList();
198 public Collection<IElement> getSegments(Collection<IElement> result) {
199 return result != null ? result : Collections.<IElement> emptyList();
203 public Collection<Connection> getTerminalConnections(Collection<Connection> result) {
204 if (terminalConnections == null)
205 terminalConnections = calculateTerminalConnections();
207 result = new ArrayList<Connection>(terminalConnections);
209 result.addAll(terminalConnections);
210 return terminalConnections;
213 private Set<Connection> calculateTerminalConnections() {
214 Set<Connection> result = new THashSet<Connection>(backendConnections.size());
215 DataElementMap dem = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
216 IElement connectionElement = dem.getElement(diagram, connection);
217 if (connectionElement == null)
218 throw new NullPointerException("connection is not mapped");
219 ArrayList<Terminal> ts = new ArrayList<Terminal>();
220 for (BackendConnection bc : backendConnections) {
221 IElement e = dem.getElement(diagram, bc.node);
224 TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);
226 tt.getTerminals(e, ts);
227 for (Terminal t : ts) {
228 if (t instanceof ResourceTerminal) {
229 ResourceTerminal rt = (ResourceTerminal) t;
230 if (bc.terminal.equals(rt.getResource())) {
231 result.add(new Connection(connectionElement, bc.end, e, t));
241 public void setListener(ConnectionListener listener) {
242 throw new UnsupportedOperationException();
246 public String toString() {
247 return getClass().getSimpleName() + "[resource=" + connection + ", connectionElement=" + getConnection()