/* * (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.fge.connectors; import java.awt.geom.AffineTransform; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.ImageIcon; import org.openflexo.fge.ConnectorGraphicalRepresentation; import org.openflexo.fge.GraphicalRepresentation; import org.openflexo.fge.ShapeGraphicalRepresentation; import org.openflexo.fge.connectors.rpc.RectPolylinConnector; import org.openflexo.fge.cp.ControlArea; import org.openflexo.fge.geom.FGEDimension; import org.openflexo.fge.geom.FGEGeometricObject.Filling; import org.openflexo.fge.geom.FGEPoint; import org.openflexo.fge.geom.FGERectangle; import org.openflexo.fge.geom.area.FGEArea; import org.openflexo.fge.geom.area.FGEEmptyArea; import org.openflexo.fge.geom.area.FGEUnionArea; import org.openflexo.fge.graphics.FGEConnectorGraphics; import org.openflexo.fge.shapes.Shape; import org.openflexo.kvc.KVCObject; import org.openflexo.xmlcode.XMLSerializable; public abstract class Connector extends KVCObject implements XMLSerializable, Cloneable { private static final Logger logger = Logger.getLogger(Connector.class.getPackage().getName()); private transient ConnectorGraphicalRepresentation graphicalRepresentation; private boolean debug = false; protected FGERectangle NORMALIZED_BOUNDS = new FGERectangle(0, 0, 1, 1, Filling.FILLED); public Connector(ConnectorGraphicalRepresentation aGraphicalRepresentation) { super(); graphicalRepresentation = aGraphicalRepresentation; // labelCP1 = new LabelControlPoint(aGraphicalRepresentation,new FGEPoint()); // labelCP2 = new LabelControlPoint(aGraphicalRepresentation,new FGEPoint()); } public static Connector makeConnector(ConnectorType type, ConnectorGraphicalRepresentation aGraphicalRepresentation) { if (type == ConnectorType.LINE) { return new LineConnector(aGraphicalRepresentation); } /* * else if (type == ConnectorType.RECT_LINE) { return new RectLineConnector(aGraphicalRepresentation); } */ else if (type == ConnectorType.RECT_POLYLIN) { return new RectPolylinConnector(aGraphicalRepresentation); } else if (type == ConnectorType.CURVE) { return new CurveConnector(aGraphicalRepresentation); } else if (type == ConnectorType.CURVED_POLYLIN) { return new CurvedPolylinConnector(aGraphicalRepresentation); } else if (type == ConnectorType.CUSTOM) { return null; } logger.warning("Unexpected type: " + type); return null; } // ******************************************************************************* // * Methods * // ******************************************************************************* public ConnectorGraphicalRepresentation<?> getGraphicalRepresentation() { return graphicalRepresentation; } public void setGraphicalRepresentation(ConnectorGraphicalRepresentation aGraphicalRepresentation) { graphicalRepresentation = aGraphicalRepresentation; } public abstract double getStartAngle(); public abstract double getEndAngle(); public Object getDrawable() { return graphicalRepresentation.getDrawable(); } public ShapeGraphicalRepresentation<?> getStartObject() { if (graphicalRepresentation == null) { return null; } return graphicalRepresentation.getStartObject(); } public ShapeGraphicalRepresentation<?> getEndObject() { if (graphicalRepresentation == null) { return null; } return graphicalRepresentation.getEndObject(); } /** * Return value indicating distance from aPoint to connector, asserting aPoint is related to local normalized coordinates system * * @param aPoint * @return */ public abstract double distanceToConnector(FGEPoint aPoint, double scale); public void setPaintAttributes(FGEConnectorGraphics g) { // Foreground if (getGraphicalRepresentation().getIsSelected()) { if (getGraphicalRepresentation().getHasSelectedForeground()) { g.setDefaultForeground(getGraphicalRepresentation().getSelectedForeground()); } else if (getGraphicalRepresentation().getHasFocusedForeground()) { g.setDefaultForeground(getGraphicalRepresentation().getFocusedForeground()); } else { g.setDefaultForeground(getGraphicalRepresentation().getForeground()); } } else if (getGraphicalRepresentation().getIsFocused() && getGraphicalRepresentation().getHasFocusedForeground()) { g.setDefaultForeground(getGraphicalRepresentation().getFocusedForeground()); } else { g.setDefaultForeground(getGraphicalRepresentation().getForeground()); } g.setDefaultTextStyle(getGraphicalRepresentation().getTextStyle()); } public final void paintConnector(FGEConnectorGraphics g) { /* * if (FGEConstants.DEBUG || getGraphicalRepresentation().getDebugCoveringArea()) { drawCoveringAreas(g); } */ setPaintAttributes(g); drawConnector(g); } public abstract void drawConnector(FGEConnectorGraphics g); public abstract List<? extends ControlArea> getControlAreas(); public static enum ConnectorType { LINE, // RECT_LINE, RECT_POLYLIN, CURVE, CURVED_POLYLIN, CUSTOM; public ImageIcon getIcon() { if (this == RECT_POLYLIN) { return org.openflexo.fge.FGEIconLibrary.RECT_POLYLIN_CONNECTOR_ICON; } else if (this == CURVE) { return org.openflexo.fge.FGEIconLibrary.CURVE_CONNECTOR_ICON; } else if (this == LINE) { return org.openflexo.fge.FGEIconLibrary.LINE_CONNECTOR_ICON; } return null; } } public abstract ConnectorType getConnectorType(); public final void refreshConnector() { refreshConnector(false); } public void refreshConnector(boolean forceRefresh) { /* * if (FGEConstants.DEBUG || getGraphicalRepresentation().getDebugCoveringArea()) { computeCoveringAreas(); } */ storeLayoutOfStartOrEndObject(); } public boolean needsRefresh() { return getGraphicalRepresentation().isRegistered() && layoutOfStartOrEndObjectHasChanged(); } private void storeLayoutOfStartOrEndObject() { startShape = getStartObject().getShape(); startShapeDimension = getStartObject().getSize(); startShapeLocation = getStartObject().getLocationInDrawing(); endShape = getEndObject().getShape(); endShapeDimension = getEndObject().getSize(); endShapeLocation = getEndObject().getLocationInDrawing(); knownConnectorUsedBounds = getConnectorUsedBounds(); } private boolean layoutOfStartOrEndObjectHasChanged() { // if (true) return true; if (startShape == null || startShape != null && startShape.getShapeType() != getStartObject().getShape().getShapeType()) { // logger.info("Layout has changed because start shape change"); return true; } if (startShapeDimension == null || startShapeDimension != null && !startShapeDimension.equals(getStartObject().getSize())) { // logger.info("Layout has changed because start shape dimension change"); return true; } if (startShapeLocation == null || startShapeLocation != null && !startShapeLocation.equals(getStartObject().getLocationInDrawing())) { // logger.info("Layout has changed because start shape location change"); return true; } if (endShape == null || endShape != null && endShape.getShapeType() != getEndObject().getShape().getShapeType()) { // logger.info("Layout has changed because end shape change"); return true; } if (endShapeDimension == null || endShapeDimension != null && !endShapeDimension.equals(getEndObject().getSize())) { // logger.info("Layout has changed because end shape dimension change"); return true; } if (endShapeLocation == null || endShapeLocation != null && !endShapeLocation.equals(getEndObject().getLocationInDrawing())) { // logger.info("Layout has changed because end shape location change"); return true; } if (knownConnectorUsedBounds == null || knownConnectorUsedBounds != null && !knownConnectorUsedBounds.equals(getConnectorUsedBounds())) { // logger.info("Layout has changed because knownConnectorUsedBounds change"); return true; } return false; } private Shape startShape; private FGEDimension startShapeDimension; private FGEPoint startShapeLocation; private Shape endShape; private FGEDimension endShapeDimension; private FGEPoint endShapeLocation; private FGERectangle knownConnectorUsedBounds; public void connectorWillBeModified() { } public void connectorHasBeenModified() { } /* * private FGEArea trivialCoveringArea; private FGEArea firstDegreeCoveringArea; private FGEArea secondDegreeCoveringArea; private * ForegroundStyle fs0 = ForegroundStyle.makeStyle(Color.BLUE); private BackgroundStyle bs0 = * BackgroundStyle.makeTexturedBackground(TextureType.TEXTURE8,Color.RED,Color.YELLOW); private ForegroundStyle fs1 = * ForegroundStyle.makeStyle(Color.RED); private BackgroundStyle bs1 = * BackgroundStyle.makeTexturedBackground(TextureType.TEXTURE1,Color.RED,Color.WHITE); private ForegroundStyle fs2 = * ForegroundStyle.makeStyle(Color.RED); private BackgroundStyle bs2 = * BackgroundStyle.makeTexturedBackground(TextureType.TEXTURE4,Color.GREEN,Color.LIGHT_GRAY); private ForegroundStyle fs3 = * ForegroundStyle.makeStyle(Color.MAGENTA); private BackgroundStyle bs3 = * BackgroundStyle.makeTexturedBackground(TextureType.TEXTURE8,Color.BLACK,Color.WHITE); */ /* * private void computeCoveringAreas() { trivialCoveringArea = computeCoveringArea(0); firstDegreeCoveringArea = computeCoveringArea(1); * secondDegreeCoveringArea = computeCoveringArea(2); } * * private void drawCoveringAreas(FGEConnectorGraphics g) { if (trivialCoveringArea == null || firstDegreeCoveringArea == null || * secondDegreeCoveringArea == null) { computeCoveringAreas(); } g.setDefaultForeground(fs0); g.setDefaultBackground(bs0); * trivialCoveringArea.paint(g); g.setDefaultForeground(fs1); g.setDefaultBackground(bs1); firstDegreeCoveringArea.paint(g); * g.setDefaultForeground(fs2); g.setDefaultBackground(bs2); secondDegreeCoveringArea.paint(g); * * * AffineTransform at1 = GraphicalRepresentation.convertNormalizedCoordinatesAT( getStartObject(), getGraphicalRepresentation()); * FGEArea testFromWest = getStartObject().getShape().getAllowedHorizontalConnectorLocationFromWest().transform(at1); * System.out.println("Was:"+getStartObject().getShape().getAllowedHorizontalConnectorLocationFromWest()); * System.out.println("Is:"+testFromWest); g.setDefaultForeground(fs3); g.setDefaultBackground(bs3); testFromWest.paint(g); * * setPaintAttributes(g); } */ public abstract FGEPoint getMiddleSymbolLocation(); /** * Perform an area computation related to the both extremity objects * * If order equals 0, return intersection between shapes representing the two object If order equals 1, return intersection of * * @param order * @return */ public FGEArea computeCoveringArea(int order) { AffineTransform at1 = GraphicalRepresentation.convertNormalizedCoordinatesAT(getStartObject(), getGraphicalRepresentation()); AffineTransform at2 = GraphicalRepresentation.convertNormalizedCoordinatesAT(getEndObject(), getGraphicalRepresentation()); if (order == 0) { FGEArea startObjectShape = getStartObject().getShape().getShape().transform(at1); FGEArea endObjectShape = getEndObject().getShape().getShape().transform(at2); FGEArea returned = startObjectShape.intersect(endObjectShape); if (logger.isLoggable(Level.FINE)) { logger.fine("computeCoveringArea(" + order + ") = " + returned); } return returned; } FGEArea start_east = getStartObject().getShape().getAllowedHorizontalConnectorLocationFromEast().transform(at1); FGEArea start_west = getStartObject().getShape().getAllowedHorizontalConnectorLocationFromWest().transform(at1); FGEArea start_north = getStartObject().getShape().getAllowedVerticalConnectorLocationFromNorth().transform(at1); FGEArea start_south = getStartObject().getShape().getAllowedVerticalConnectorLocationFromSouth().transform(at1); FGEArea end_east = getEndObject().getShape().getAllowedHorizontalConnectorLocationFromEast().transform(at2); FGEArea end_west = getEndObject().getShape().getAllowedHorizontalConnectorLocationFromWest().transform(at2); FGEArea end_north = getEndObject().getShape().getAllowedVerticalConnectorLocationFromNorth().transform(at2); FGEArea end_south = getEndObject().getShape().getAllowedVerticalConnectorLocationFromSouth().transform(at2); FGEArea returned = new FGEEmptyArea(); if (order == 1) { returned = FGEUnionArea.makeUnion(start_east.intersect(end_west), start_west.intersect(end_east), start_north.intersect(end_south), start_south.intersect(end_north)); } else if (order == 2) { returned = FGEUnionArea.makeUnion(start_east.intersect(end_north), start_east.intersect(end_south), start_west.intersect(end_north), start_west.intersect(end_south), start_north.intersect(end_east), start_north.intersect(end_west), start_south.intersect(end_east), start_south.intersect(end_west)); } if (logger.isLoggable(Level.FINE)) { logger.fine("computeCoveringArea(" + order + ") = " + returned); } return returned; } public boolean getDebug() { return debug; } public void setDebug(boolean debug) { this.debug = debug; refreshConnector(); } /** * Return bounds of actually required area to fully display current connector (which might require to be paint outside normalized * bounds) * * @return */ public abstract FGERectangle getConnectorUsedBounds(); @Override public abstract Connector clone(); /** * Return start point, relative to start object * * @return */ public abstract FGEPoint getStartLocation(); /** * Return end point, relative to end object * * @return */ public abstract FGEPoint getEndLocation(); }