1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2016 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 * Semantum Oy - refactoring
\r
12 *******************************************************************************/
\r
13 package org.simantics.diagram.adapter;
\r
15 import java.util.ArrayList;
\r
16 import java.util.Collection;
\r
17 import java.util.Collections;
\r
18 import java.util.Set;
\r
20 import org.simantics.db.AsyncReadGraph;
\r
21 import org.simantics.db.ReadGraph;
\r
22 import org.simantics.db.Resource;
\r
23 import org.simantics.db.Session;
\r
24 import org.simantics.db.exception.DatabaseException;
\r
25 import org.simantics.db.procedure.AsyncProcedure;
\r
26 import org.simantics.diagram.adapter.RouteGraphUtils.BackendConnection;
\r
27 import org.simantics.diagram.connection.RouteGraph;
\r
28 import org.simantics.diagram.connection.RouteGraphConnectionClass;
\r
29 import org.simantics.diagram.connection.rendering.ConnectionStyle;
\r
30 import org.simantics.diagram.connection.rendering.StyledRouteGraphRenderer;
\r
31 import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle;
\r
32 import org.simantics.diagram.content.ResourceTerminal;
\r
33 import org.simantics.diagram.stubs.DiagramResource;
\r
34 import org.simantics.diagram.ui.DiagramModelHints;
\r
35 import org.simantics.g2d.canvas.ICanvasContext;
\r
36 import org.simantics.g2d.connection.ConnectionEntity;
\r
37 import org.simantics.g2d.diagram.IDiagram;
\r
38 import org.simantics.g2d.diagram.handler.DataElementMap;
\r
39 import org.simantics.g2d.diagram.handler.Topology.Connection;
\r
40 import org.simantics.g2d.diagram.handler.Topology.Terminal;
\r
41 import org.simantics.g2d.element.ElementClass;
\r
42 import org.simantics.g2d.element.ElementHints;
\r
43 import org.simantics.g2d.element.IElement;
\r
44 import org.simantics.g2d.element.handler.TerminalTopology;
\r
45 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;
\r
46 import org.simantics.g2d.utils.TopologicalSelectionExpander;
\r
47 import org.simantics.layer0.Layer0;
\r
48 import org.simantics.modeling.ModelingResources;
\r
49 import org.simantics.scenegraph.g2d.nodes.connection.IRouteGraphListener;
\r
50 import org.simantics.scenegraph.g2d.nodes.connection.RouteGraphChangeEvent;
\r
51 import org.simantics.structural.stubs.StructuralResource2;
\r
52 import org.simantics.structural2.modelingRules.IModelingRules;
\r
54 import gnu.trove.set.hash.THashSet;
\r
57 * An element class for single connection entity elements. A connection entity
\r
58 * consists of connection edge segments and branch points as its children.
\r
60 * @author Tuukka Lehtonen
\r
62 public class RouteGraphConnectionClassFactory extends SyncElementFactory {
\r
64 public static final ElementClass CLASS = RouteGraphConnectionClass.CLASS;
\r
66 public static final ILineEndStyle HEAD = RouteGraphUtils.HEAD;
\r
67 public static final ILineEndStyle TAIL = RouteGraphUtils.TAIL;
\r
69 protected Layer0 L0;
\r
70 protected DiagramResource DIA;
\r
71 protected StructuralResource2 STR;
\r
72 protected ModelingResources MOD;
\r
74 public RouteGraphConnectionClassFactory(ReadGraph graph) {
\r
75 this.L0 = Layer0.getInstance(graph);
\r
76 this.DIA = DiagramResource.getInstance(graph);
\r
77 this.STR = StructuralResource2.getInstance(graph);
\r
78 this.MOD = ModelingResources.getInstance(graph);
\r
82 public void create(AsyncReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource elementType,
\r
83 final AsyncProcedure<ElementClass> procedure) {
\r
84 procedure.execute(graph, CLASS.newClassWith(false, new StaticObjectAdapter(elementType)));
\r
88 protected Resource getElementClassBaseType(AsyncReadGraph graph) {
\r
89 return DIA.Connection;
\r
93 public void load(ReadGraph graph, ICanvasContext canvas, IDiagram diagram, final Resource connection,
\r
94 IElement element) throws DatabaseException {
\r
96 IModelingRules modelingRules = diagram.getHint(DiagramModelHints.KEY_MODELING_RULES);
\r
97 Resource diagramRuntime = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RUNTIME_RESOURCE);
\r
99 Set<BackendConnection> backendConnections = new THashSet<>();
\r
100 RouteGraph rg = RouteGraphUtils.load(graph, diagramRuntime, connection, canvas, diagram, modelingRules, backendConnections);
\r
102 // Load connection line style.
\r
103 ConnectionStyle style = RouteGraphUtils.readConnectionStyle(graph, modelingRules, connection, STR);
\r
104 StyledRouteGraphRenderer renderer = RouteGraphUtils.getRenderer(graph, style);
\r
106 // Finish element load
\r
107 element.setHint(RouteGraphConnectionClass.KEY_ROUTEGRAPH, rg);
\r
108 element.setHint(RouteGraphConnectionClass.KEY_RENDERER, renderer);
\r
109 element.setHint(RouteGraphConnectionClass.KEY_PICK_TOLERANCE, 0.5);
\r
111 // Initialize ConnectionEntity in element
\r
112 element.setHint(ElementHints.KEY_CONNECTION_ENTITY, new CE(diagram, connection, element, backendConnections));
\r
114 // Setup graph writeback support for route graph modifications
\r
115 Session session = graph.getSession();
\r
116 element.setHint(RouteGraphConnectionClass.KEY_RG_LISTENER, new IRouteGraphListener() {
\r
118 public void routeGraphChanged(RouteGraphChangeEvent event) {
\r
119 RouteGraphUtils.scheduleSynchronize(session, connection, event);
\r
125 * Must have this in order for {@link TopologicalSelectionExpander} to work.
\r
126 * Otherwise this is pretty useless and should be deprecated altogether.
\r
128 * @see ElementHints#KEY_CONNECTION_ENTITY
\r
130 private static class CE implements ConnectionEntity {
\r
133 * Needed to gain access to {@link DataElementMap}.
\r
135 final IDiagram diagram;
\r
138 * The connection instance resource in the graph database back-end.
\r
140 final Resource connection;
\r
143 * The current element mapped to connection.
\r
145 IElement connectionElement;
\r
148 * @see #getTerminalConnections(Collection)
\r
150 final Set<BackendConnection> backendConnections;
\r
155 transient Set<Connection> terminalConnections;
\r
157 public CE(IDiagram diagram, Resource connection, IElement connectionElement, Set<BackendConnection> backendConnections) {
\r
158 if (connectionElement == null)
\r
159 throw new NullPointerException("null connection element");
\r
160 this.diagram = diagram;
\r
161 this.connection = connection;
\r
162 this.connectionElement = connectionElement;
\r
163 this.backendConnections = backendConnections;
\r
164 IElement ce = getConnection0();
\r
166 this.connectionElement = ce;
\r
169 public IElement getConnection0() {
\r
170 DataElementMap dem = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
\r
171 IElement connectionElement = dem.getElement(diagram, connection);
\r
172 return connectionElement;
\r
176 public IElement getConnection() {
\r
177 IElement c = getConnection0();
\r
179 c = this.connectionElement;
\r
184 public Collection<IElement> getBranchPoints(Collection<IElement> result) {
\r
185 return result != null ? result : Collections.<IElement> emptyList();
\r
189 public Collection<IElement> getSegments(Collection<IElement> result) {
\r
190 return result != null ? result : Collections.<IElement> emptyList();
\r
194 public Collection<Connection> getTerminalConnections(Collection<Connection> result) {
\r
195 if (terminalConnections == null)
\r
196 terminalConnections = calculateTerminalConnections();
\r
197 if (result == null)
\r
198 result = new ArrayList<Connection>(terminalConnections);
\r
200 result.addAll(terminalConnections);
\r
201 return terminalConnections;
\r
204 private Set<Connection> calculateTerminalConnections() {
\r
205 Set<Connection> result = new THashSet<Connection>(backendConnections.size());
\r
206 DataElementMap dem = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
\r
207 IElement connectionElement = dem.getElement(diagram, connection);
\r
208 if (connectionElement == null)
\r
209 throw new NullPointerException("connection is not mapped");
\r
210 ArrayList<Terminal> ts = new ArrayList<Terminal>();
\r
211 for (BackendConnection bc : backendConnections) {
\r
212 IElement e = dem.getElement(diagram, bc.node);
\r
215 TerminalTopology tt = e.getElementClass().getSingleItem(TerminalTopology.class);
\r
217 tt.getTerminals(e, ts);
\r
218 for (Terminal t : ts) {
\r
219 if (t instanceof ResourceTerminal) {
\r
220 ResourceTerminal rt = (ResourceTerminal) t;
\r
221 if (bc.terminal.equals(rt.getResource())) {
\r
222 result.add(new Connection(connectionElement, bc.end, e, t));
\r
232 public void setListener(ConnectionListener listener) {
\r
233 throw new UnsupportedOperationException();
\r
237 public String toString() {
\r
238 return getClass().getSimpleName() + "[resource=" + connection + ", connectionElement=" + getConnection()
\r