GefAgeDiagramUtil.java
/**
* Copyright (c) 2004-2025 Carnegie Mellon University and others. (see Contributors file).
* All Rights Reserved.
*
* NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE
* OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT
* MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
* SPDX-License-Identifier: EPL-2.0
*
* Created, in part, with funding and support from the United States Government. (see Acknowledgments file).
*
* This program includes and/or can make use of certain third party source code, object code, documentation and other
* files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system
* configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and
* conditions contained in any such Third Party Software or separate license file distributed with such Third Party
* Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici-
* aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li-
* censes only apply to the Third Party Software and not any other portion of this program or this program as a whole.
*/
package org.osate.ge.gef.ui.diagram;
import org.eclipse.gef.fx.anchors.IAnchor;
import org.osate.ge.gef.AgeGefRuntimeException;
import org.osate.ge.gef.BaseConnectionNode;
import org.osate.ge.gef.ContainerShape;
import org.osate.ge.gef.DockSide;
import org.osate.ge.gef.DockedShape;
import org.osate.ge.internal.diagram.runtime.DiagramElement;
import org.osate.ge.internal.diagram.runtime.DiagramNode;
import org.osate.ge.internal.diagram.runtime.DockArea;
import javafx.geometry.Point2D;
import javafx.scene.Node;
/**
* Utility class for working with {@link GefAgeDiagram} instances
*/
public final class GefAgeDiagramUtil {
private GefAgeDiagramUtil() {
}
/**
* Returns the anchor to use to reference the specified diagram element.
* @param gefDiagram is the diagram which contains the mapping between diagram elements to scene nodes
* @param de the element to retrieve the anchor for
* @param other is the element at the other end of the connection.
* Used for docked shapes to determine which anchor to use. If null, the interior anchor will be used.
* @return the anchor for the diagram element.
*/
public static IAnchor getAnchor(final GefAgeDiagram gefDiagram, final DiagramElement de,
final DiagramElement other) {
final Node sceneNode = gefDiagram.getSceneNode(de);
if (sceneNode == null) {
return null;
}
if (sceneNode instanceof ContainerShape) {
return ((ContainerShape) sceneNode).getAnchor();
} else if (sceneNode instanceof DockedShape) {
final DockedShape ds = (DockedShape) sceneNode;
return (other == null || useInteriorAnchor(de, other)) ? ds.getInteriorAnchor() : ds.getExteriorAnchor();
} else if (sceneNode instanceof BaseConnectionNode) {
return ((BaseConnectionNode) sceneNode).getMidpointAnchor();
} else {
throw new AgeGefRuntimeException(
"Unexpected case. Attempt to get anchor for node of type : " + sceneNode.getClass().getName());
}
}
/**
* Returns whether the connection going from e1 to e2 should use the interior anchor for e1 if it exists.
* @param e1
* @param e2
* @return
*/
private static boolean useInteriorAnchor(final DiagramElement e1, final DiagramElement e2) {
return isInsideUndockedContainer(e2, e1);
}
/**
* Returns whether e1 is inside the first undocked container in the hierarchy of e2
* @param e1
* @param e2
* @return
*/
private static boolean isInsideUndockedContainer(final DiagramElement e1, final DiagramElement e2) {
// Get the first diagram element in each hierarchy which doesn't have a dock area set.
DiagramNode nd2 = e2;
while (nd2 instanceof DiagramElement && ((DiagramElement) nd2).getDockArea() != null) {
nd2 = nd2.getParent();
}
if (!(nd2 instanceof DiagramElement)) {
return false;
}
// Check if e1 is inside the first undocked element in the e2 hierarchy
for (DiagramNode t1 = e1; t1 != null; t1 = t1.getParent()) {
if (t1 == nd2) {
return true;
}
}
return false;
}
/**
* Converts a {@link DockArea} to an equivalent {@link DockSide}.
* @param value the dock area for which to return the dock side.
* @return the dock side. Returns null if value is null or if value is {@link DockArea#GROUP}
*/
public static DockSide toDockSide(final DockArea value) {
if (value == null) {
return null;
}
switch (value) {
case LEFT:
return DockSide.LEFT;
case RIGHT:
return DockSide.RIGHT;
case TOP:
return DockSide.TOP;
case BOTTOM:
return DockSide.BOTTOM;
default:
return null;
}
}
/**
* Converts a {@link DockSide} to an equivalent {@link DockArea}.
* @param value the dock side for which to return the dock area..
* @return the dock area. Returns null if value is null.
*/
public static DockArea toDockArea(final DockSide value) {
if (value == null) {
return null;
}
switch (value) {
case LEFT:
return DockArea.LEFT;
case RIGHT:
return DockArea.RIGHT;
case TOP:
return DockArea.TOP;
case BOTTOM:
return DockArea.BOTTOM;
default:
throw new AgeGefRuntimeException("Unexpected value: " + value);
}
}
/**
* Converts a {@link Point2D} to a {@link org.osate.ge.graphics.Point}.
* @param value the point to convert.
* @return the converted point. Returns null if value is null/
*/
public static org.osate.ge.graphics.Point toAgePoint(final Point2D value) {
return value == null ? null : new org.osate.ge.graphics.Point(value.getX(), value.getY());
}
}