/* * DBeaver - Universal Database Manager * Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Created on Jul 15, 2004 */ package org.jkiss.dbeaver.ext.erd.layout.algorithm.direct; import org.jkiss.dbeaver.Log; import org.eclipse.draw2d.*; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Insets; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.draw2d.graph.*; import org.eclipse.gef.EditPart; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.gef.NodeEditPart; import org.eclipse.gef.editparts.AbstractConnectionEditPart; import org.eclipse.gef.editparts.AbstractGraphicalEditPart; import org.jkiss.dbeaver.ext.erd.layout.GraphAnimation; import org.jkiss.dbeaver.ext.erd.part.EntityPart; import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; /** * Visitor with support for populating nodes and edges of DirectedGraph * from model objects * * @author Serge Rider */ public class DirectedGraphLayoutVisitor { private static final Log log = Log.getLog(DirectedGraphLayoutVisitor.class); Map<EditPart, Object> partToNodesMap; DirectedGraph graph; /** * Public method for reading graph nodes */ public void layoutDiagram(AbstractGraphicalEditPart diagram) { partToNodesMap = new IdentityHashMap<>(); graph = new DirectedGraph(); graph.setDirection(PositionConstants.EAST); addDiagramNodes(diagram); if (graph.nodes.size() > 0) { addDiagramEdges(diagram); try { //new CompoundDirectedGraphLayout().visit(graph); new NodeJoiningDirectedGraphLayout(diagram).visit(graph); } catch (Exception e) { log.error("Diagram layout error", e); } applyDiagramResults(diagram); } } //******************* DiagramPart contribution methods **********/ protected void addDiagramNodes(AbstractGraphicalEditPart diagram) { GraphAnimation.recordInitialState(diagram.getFigure()); //IFigure fig = diagram.getFigure(); for (Object child : diagram.getChildren()) { addEntityNode((NodeEditPart) child); } } /** * Adds nodes to the graph object for use by the GraphLayoutAuto */ protected void addEntityNode(NodeEditPart nodeEditPart) { Node entityNode; if (nodeEditPart instanceof EntityPart && ((EntityPart)nodeEditPart).getTable().hasSelfLinks()) { entityNode = new Subgraph(nodeEditPart); } else { entityNode = new Node(nodeEditPart); } Dimension preferredSize = nodeEditPart.getFigure().getPreferredSize(400, 300); entityNode.width = preferredSize.width; entityNode.height = preferredSize.height; entityNode.setPadding(new Insets(20, 20, 10, 20)); partToNodesMap.put(nodeEditPart, entityNode); graph.nodes.add(entityNode); if (entityNode instanceof Subgraph) { Node sourceAnchor = new Node("Fake node for source links", (Subgraph) entityNode); sourceAnchor.width = 0; sourceAnchor.height = 0; Node targetAnchor = new Node("Fake node for target links", (Subgraph) entityNode); targetAnchor.width = 0; targetAnchor.height = 0; } /* */ } protected void addDiagramEdges(AbstractGraphicalEditPart diagram) { for (Object child : diagram.getChildren()) { addEntityEdges((GraphicalEditPart) child); } } //******************* Entity contribution methods **********/ protected void addEntityEdges(GraphicalEditPart entityPart) { List<?> outgoing = entityPart.getSourceConnections(); for (int i = 0; i < outgoing.size(); i++) { AbstractConnectionEditPart connectionPart = (AbstractConnectionEditPart) entityPart.getSourceConnections().get(i); addConnectionEdges(connectionPart); } } //******************* Connection contribution methods **********/ protected void addConnectionEdges(AbstractConnectionEditPart connectionPart) { GraphAnimation.recordInitialState((Connection) connectionPart.getFigure()); Node source = (Node) partToNodesMap.get(connectionPart.getSource()); Node target = (Node) partToNodesMap.get(connectionPart.getTarget()); if (source == null || target == null) { log.warn("Source or target node not found"); return; } if (source instanceof Subgraph && target instanceof Subgraph) { source = ((Subgraph) source).members.getNode(0); target = ((Subgraph) target).members.getNode(1); } Edge e = new Edge(connectionPart, source, target); e.setPadding(10); e.weight = 2; graph.edges.add(e); partToNodesMap.put(connectionPart, e); } //******************* DiagramPart apply methods **********/ protected void applyDiagramResults(AbstractGraphicalEditPart diagram) { for (Object child : diagram.getChildren()) { applyEntityResults((GraphicalEditPart) child); } } //******************* EntityPart apply methods **********/ public void applyEntityResults(GraphicalEditPart entityPart) { Node n = (Node) partToNodesMap.get(entityPart); IFigure tableFigure = entityPart.getFigure(); Dimension preferredSize = tableFigure.getPreferredSize(); Rectangle bounds = new Rectangle(n.x, n.y, preferredSize.width, preferredSize.height); tableFigure.setBounds(bounds); for (int i = 0; i < entityPart.getSourceConnections().size(); i++) { AbstractConnectionEditPart relationship = (AbstractConnectionEditPart) entityPart.getSourceConnections().get(i); applyConnectionResults(relationship); } } //******************* Connection apply methods **********/ protected void applyConnectionResults(AbstractConnectionEditPart connectionPart) { Edge connEdge = (Edge) partToNodesMap.get(connectionPart); NodeList edgeNodes = connEdge.vNodes; PolylineConnection conn = (PolylineConnection) connectionPart.getConnectionFigure(); //conn.setOpaque(true); //conn.setLineJoin(SWT.JOIN_BEVEL); //conn.setTargetDecoration(new PolygonDecoration()); if (edgeNodes != null && edgeNodes.size() > 1) { List<AbsoluteBendpoint> bends = new ArrayList<>(); for (int i = 0; i < edgeNodes.size(); i++) { Node vn = edgeNodes.getNode(i); int x = vn.x; int y = vn.y; bends.add(new AbsoluteBendpoint(x, y)); /* if (connEdge.isFeedback()) { bends.add(new AbsoluteBendpoint(x, y + vn.height)); bends.add(new AbsoluteBendpoint(x, y)); } else { bends.add(new AbsoluteBendpoint(x, y)); bends.add(new AbsoluteBendpoint(x, y + vn.height)); } */ } conn.setRoutingConstraint(bends); } } }