/******************************************************************************* * Copyright (c) 2020 Association for Decentralized Information Management in * Industry THTH ry. * 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: * Semantum Oy - initial API and implementation *******************************************************************************/ package org.simantics.diagram.participant; import org.simantics.Simantics; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.request.UnaryRead; import org.simantics.db.exception.DatabaseException; import org.simantics.db.procedure.Listener; import org.simantics.diagram.connection.rendering.ConnectionCrossings; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.canvas.SGDesignation; import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup; import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit; import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant; import org.simantics.scenegraph.g2d.G2DParentNode; import org.simantics.scenegraph.g2d.nodes.ConnectionCrossingsNode; import org.simantics.utils.datastructures.Pair; import org.simantics.utils.ui.ErrorLogger; public class ConnectionCrossingsParticipant extends AbstractDiagramParticipant { private static final String CONNECTION_CROSSINGS_NODE_KEY = "connection-crossings"; private ConnectionCrossingsNode ccNode; private final ConnectionCrossings crossings = new ConnectionCrossings(); private ConnectionCrossingStyleListener listener; private Resource diagram; public ConnectionCrossingsParticipant(Resource diagram) { this.diagram = diagram; } public ConnectionCrossingsParticipant(double width, ConnectionCrossings.Type type) { crossings.setWidth(width); crossings.setType(type); } @SGInit(designation = SGDesignation.CONTROL) public void initSG(G2DParentNode parent) { ccNode = parent.addNode(CONNECTION_CROSSINGS_NODE_KEY, ConnectionCrossingsNode.class); ccNode.setCrossings(crossings); ccNode.setZIndex(Integer.MIN_VALUE / 4); } @SGCleanup public void cleanupSG() { if (ccNode != null) { ccNode.remove(); ccNode = null; } } @Override public void addedToContext(ICanvasContext ctx) { super.addedToContext(ctx); if (diagram != null) { listener = new ConnectionCrossingStyleListener(ctx); Simantics.getSession().async(new UnaryRead>(diagram){ @Override public Pair perform(ReadGraph graph) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); Double gap = graph.getPossibleRelatedValue(diagram, DIA.ConnectionCrossingStyle_Width); Resource typeRes = graph.getPossibleObject(diagram, DIA.ConnectionCrossingStyle_HasType); ConnectionCrossings.Type type; if (DIA.ConnectionCrossingStyle_Type_Gap.equals(typeRes)) { type = ConnectionCrossings.Type.GAP; } else if (DIA.ConnectionCrossingStyle_Type_Arc.equals(typeRes)) { type = ConnectionCrossings.Type.ARC; } else if (DIA.ConnectionCrossingStyle_Type_Square.equals(typeRes)) { type = ConnectionCrossings.Type.SQUARE; } else { type = ConnectionCrossings.Type.NONE; } return new Pair<>(gap, type); } }, listener); } } @Override public void removedFromContext(ICanvasContext ctx) { if (listener != null) { listener.dispose(); listener = null; } super.removedFromContext(ctx); } class ConnectionCrossingStyleListener implements Listener> { ICanvasContext context; public ConnectionCrossingStyleListener(ICanvasContext context) { this.context = context; } @Override public void execute(final Pair result) { context.getThreadAccess().asyncExec(new Runnable() { @Override public void run() { ICanvasContext ctx = context; if (ctx == null) return; if (ctx.isDisposed()) return; crossings.setWidth(result.first != null ? result.first : 0.0); crossings.setType(result.second); ccNode.repaint(); } }); } public void dispose() { context = null; } @Override public boolean isDisposed() { return context == null || context.isDisposed(); } @Override public void exception(Throwable t) { ErrorLogger.defaultLogError(t); } } }