/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.wkf.processeditor.gr; import java.util.logging.Logger; import org.openflexo.fge.ConnectorGraphicalRepresentation; import org.openflexo.fge.ShapeGraphicalRepresentation; import org.openflexo.fge.connectors.Connector.ConnectorType; import org.openflexo.fge.geom.FGEPoint; import org.openflexo.foundation.GraphicalFlexoObserver; import org.openflexo.foundation.wkf.WKFObject; import org.openflexo.wkf.processeditor.ProcessEditorConstants; import org.openflexo.wkf.processeditor.ProcessRepresentation; public abstract class WKFConnectorGR<O> extends ConnectorGraphicalRepresentation<O> implements GraphicalFlexoObserver, ProcessEditorConstants { @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(WKFConnectorGR.class.getPackage().getName()); protected WKFObject startObject; protected WKFObject endObject; private WKFObjectGR<? extends WKFObject> startObjectGR; private WKFObjectGR<? extends WKFObject> endObjectGR; public WKFConnectorGR(ConnectorType aConnectorType, WKFObject startObject, WKFObject endObject, O aDrawable, ProcessRepresentation aDrawing) { super(aConnectorType, getGraphicalRepresentation(startObject, aDrawing), getGraphicalRepresentation(endObject, aDrawing), aDrawable, aDrawing); this.startObject = startObject; this.endObject = endObject; updatePropertiesFromWKFPreferences(); } public O getModel() { return getDrawable(); } @Override public ProcessRepresentation getDrawing() { return (ProcessRepresentation) super.getDrawing(); } public abstract void updatePropertiesFromWKFPreferences(); protected static <O extends WKFObject> WKFObjectGR<? extends O> getGraphicalRepresentation(O obj, ProcessRepresentation drawing) { return (WKFObjectGR<? extends O>) drawing.getGraphicalRepresentation(obj); } /** * Bug 1007430 * * We have here to implement a very subtle scheme. It may happen that an edge relies two nodes, with one node beeing hidden by the * container of other node. This is functionnaly correct but may lead to some graphical misunderstanding. * * We try here to detect this kind of case, and if we detect that a container shape cover one of the both nodes, we set the layer to the * minimal of two layers, in order to have the edge BELOW container * * @param startObjGR * @param endObjGR * @return */ private int computeBestLayer(ShapeGraphicalRepresentation<?> startObjGR, ShapeGraphicalRepresentation<?> endObjGR) { if (isConnectorFullyVisible(startObjGR, endObjGR)) { return Math.max(startObjGR.getLayer(), endObjGR.getLayer()) + 1; } else { return minimalLayerHiding(startObjGR, endObjGR); // return Math.min(startObjGR.getLayer(),endObjGR.getLayer()); } } /** * Bug 1007430, see above * * @return */ protected boolean isConnectorFullyVisible() { return isConnectorFullyVisible(getStartObject(), getEndObject()); } /** * Bug 1007430, see above * * @param startObjGR * @param endObjGR * @return */ protected boolean isConnectorFullyVisible(ShapeGraphicalRepresentation<?> startObjGR, ShapeGraphicalRepresentation<?> endObjGR) { FGEPoint startLocation = getConnector().getStartLocation(); FGEPoint endLocation = getConnector().getEndLocation(); if (startLocation == null) { return true; } if (endLocation == null) { return true; } // boolean debug = false; // if (getText() != null && getText().equals("debug")) debug = true; if (!startObjGR.isPointVisible(startLocation)) { /*if (debug) { logger.info("DEBUG: start location is not visible"); logger.info("DEBUG: startLocation="+startLocation); logger.info("DEBUG: shape="+startObjGR.getShape().getShape()); DrawingGraphicalRepresentation<?> drawingGR = getDrawingGraphicalRepresentation(); ShapeGraphicalRepresentation<?> topLevelShape = drawingGR.getTopLevelShapeGraphicalRepresentation( convertNormalizedPoint(startObjGR, startLocation, drawingGR)); logger.info("DEBUG: topLevelShape="+topLevelShape); logger.info("DEBUG: layer="+topLevelShape.getLayer()); }*/ return false; } if (!endObjGR.isPointVisible(endLocation)) { /*if (debug) { logger.info("DEBUG: end location is not visible"); logger.info("DEBUG: endLocation="+endLocation); logger.info("DEBUG: shape="+endObjGR.getShape().getShape()); DrawingGraphicalRepresentation<?> drawingGR = getDrawingGraphicalRepresentation(); ShapeGraphicalRepresentation<?> topLevelShape = drawingGR.getTopLevelShapeGraphicalRepresentation( convertNormalizedPoint(endObjGR, endLocation, drawingGR)); logger.info("DEBUG: topLevelShape="+topLevelShape); logger.info("DEBUG: layer="+topLevelShape.getLayer()); }*/ return false; } return true; } /** * Bug 1007430, see above * * This method return top-most layer of shape hidding either start location or end location of connector * * @param startObjGR * @param endObjGR * @return */ protected int minimalLayerHiding(ShapeGraphicalRepresentation<?> startObjGR, ShapeGraphicalRepresentation<?> endObjGR) { FGEPoint startLocation = getConnector().getStartLocation(); FGEPoint endLocation = getConnector().getEndLocation(); if (startLocation == null) { return -1; } if (endLocation == null) { return -1; } ShapeGraphicalRepresentation<?> firstHiddingShape = startObjGR.shapeHiding(startLocation); ShapeGraphicalRepresentation<?> secondHiddingShape = endObjGR.shapeHiding(endLocation); if (firstHiddingShape == null) { if (secondHiddingShape == null) { return -1; } else { return secondHiddingShape.getLayer(); } } else { if (secondHiddingShape == null) { return firstHiddingShape.getLayer(); } else { return Math.min(firstHiddingShape.getLayer(), secondHiddingShape.getLayer()); } } } /** * * @param startObjGR * @param endObjGR */ private void updateLayer(ShapeGraphicalRepresentation<?> startObjGR, ShapeGraphicalRepresentation<?> endObjGR) { if (startObjGR != null && endObjGR != null && !switchedToSelectionLayer) { setLayer(computeBestLayer(startObjGR, endObjGR)); } } @Override protected void refreshConnector(boolean forceRefresh) { super.refreshConnector(forceRefresh); updateLayer(getStartObject(), getEndObject()); } @Override public WKFObjectGR<? extends WKFObject> getStartObject() { if (startObject == null) { return null; } if (startObjectGR == null) { startObjectGR = getGraphicalRepresentation(startObject, getDrawing()); enableStartObjectObserving(startObjectGR); updateLayer(startObjectGR, endObjectGR); } return startObjectGR; } @Override public WKFObjectGR<? extends WKFObject> getEndObject() { if (endObject == null) { return null; } if (endObjectGR == null) { endObjectGR = getGraphicalRepresentation(endObject, getDrawing()); enableEndObjectObserving(endObjectGR); updateLayer(startObjectGR, endObjectGR); } return endObjectGR; } @Override public void notifyObjectHierarchyHasBeenUpdated() { super.notifyObjectHierarchyHasBeenUpdated(); if (isConnectorConsistent()) { updateLayer(getStartObject(), getEndObject()); notifyConnectorChanged(); } } protected void dismissGraphicalRepresentation() { disableStartObjectObserving(); disableEndObjectObserving(); startObjectGR = null; endObjectGR = null; getDrawing().invalidateGraphicalObjectsHierarchy(getModel()); } // private int regularLayer; private boolean switchedToSelectionLayer = false; protected void switchToSelectionLayer() { // regularLayer = getLayer(); switchedToSelectionLayer = true; setLayer(SELECTION_LAYER + 1); } protected void restoreNormalLayer() { if (switchedToSelectionLayer) { switchedToSelectionLayer = false; // setLayer(regularLayer); } updateLayer(); } public void updateLayer() { setLayer(computeBestLayer(getStartObject(), getEndObject())); } }