/* * (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.ArrayList; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.fge.ConnectorGraphicalRepresentation; import org.openflexo.fge.GraphicalRepresentation; import org.openflexo.fge.shapes.Shape.ShapeType; import org.openflexo.foundation.GraphicalFlexoObserver; import org.openflexo.foundation.wkf.node.WKFNode; import org.openflexo.wkf.processeditor.DrawEdgeControl; import org.openflexo.wkf.processeditor.ProcessEditorConstants; import org.openflexo.wkf.processeditor.ProcessRepresentation; import org.openflexo.wkf.swleditor.SWLEditorConstants; public abstract class WKFNodeGR<O extends WKFNode> extends WKFObjectGR<O> implements GraphicalFlexoObserver, ProcessEditorConstants { private static final Logger logger = Logger.getLogger(WKFNodeGR.class.getPackage().getName()); protected boolean isUpdatingPosition = false; protected double defaultX = -1; protected double defaultY = -1; public WKFNodeGR(O object, ShapeType shapeType, ProcessRepresentation aDrawing) { super(object, shapeType, aDrawing); addToMouseDragControls(new DrawEdgeControl()); } @Override public final double getX() { if (!getNode().hasLocationForContext(BASIC_PROCESS_EDITOR)) { if (!isRegistered()) { return 0; } return getNode().getX(BASIC_PROCESS_EDITOR, getDefaultX()); } return getNode().getX(BASIC_PROCESS_EDITOR); } @Override public final void setXNoNotification(double posX) { isUpdatingPosition = true; getNode().setX(posX, BASIC_PROCESS_EDITOR); isUpdatingPosition = false; } @Override public final double getY() { if (!getNode().hasLocationForContext(BASIC_PROCESS_EDITOR)) { if (!isRegistered()) { return 0; } return getNode().getY(BASIC_PROCESS_EDITOR, getDefaultY()); } return getNode().getY(BASIC_PROCESS_EDITOR); } @Override public final void setYNoNotification(double posY) { isUpdatingPosition = true; getNode().setY(posY, BASIC_PROCESS_EDITOR); isUpdatingPosition = false; } @Override public double getAbsoluteTextX() { if (!getNode().hasLabelLocationForContext(BASIC_PROCESS_EDITOR)) { if (!isRegistered()) { return 0; } return getNode().getLabelX(BASIC_PROCESS_EDITOR, getDefaultLabelX()); } return getNode().getLabelX(BASIC_PROCESS_EDITOR); } @Override public void setAbsoluteTextXNoNotification(double posX) { getNode().setLabelX(posX, BASIC_PROCESS_EDITOR); } @Override public double getAbsoluteTextY() { if (!getNode().hasLabelLocationForContext(BASIC_PROCESS_EDITOR)) { return getNode().getLabelY(BASIC_PROCESS_EDITOR, getDefaultLabelY()); } return getNode().getLabelY(BASIC_PROCESS_EDITOR); } @Override public void setAbsoluteTextYNoNotification(double posY) { getNode().setLabelY(posY, BASIC_PROCESS_EDITOR); } @Override public void notifyObjectHierarchyHasBeenUpdated() { if (getDrawing() != null) { getDrawing().getDrawingGraphicalRepresentation().updateConstraintsForObject(this); } super.notifyObjectHierarchyHasBeenUpdated(); } public O getNode() { return getDrawable(); } public double getDefaultX() { if (defaultX < 0) { doDefaultLayout(_getDefaultX(), _getDefaultY()); } return defaultX; } public double getDefaultY() { if (defaultY < 0) { doDefaultLayout(_getDefaultX(), _getDefaultY()); } return defaultY; } protected double _getDefaultX() { return 10; } protected double _getDefaultY() { return 10; } private boolean isLayingout = false; protected boolean hasLocation() { return getModel().hasLocationForContext(BASIC_PROCESS_EDITOR); } protected void doDefaultLayout(double x, double y) { if (!isRegistered()) { return; } if (isLayingout) { return; } isLayingout = true; try { if (getContainerGraphicalRepresentation() != null) { doLayoutMethod1(); if (defaultX < 0 || defaultY < 0) { doLayoutMethod2(); } if (defaultX < 0 || defaultY < 0) { doLayoutMethod3(x, y); } if (defaultX >= 0 && defaultY >= 0) { notifyObjectMoved(); } } } finally { isLayingout = false; } } protected void doLayoutMethod1() { // Override this method if the view can do a more clever thing than method 2 and 3 } /** * Looks for relative position in BPE view on related objects */ protected void doLayoutMethod2() { for (WKFNodeGR<?> nodeGR : getFromInterestingNodeGR()) { double x, y; if (!nodeGR.hasLocation()) { nodeGR.doDefaultLayout(-1, -1); x = nodeGR.defaultX; y = nodeGR.defaultY; } else { x = nodeGR.getX(); y = nodeGR.getY(); } if (x >= 0 && y >= 0) { defaultX = x + nodeGR.getWidth() + 30; defaultY = y; break; } } if (defaultX < 0 && defaultY < 0) { for (WKFNodeGR<?> nodeGR : getToInterestingNodeGR()) { double x, y; if (!nodeGR.getModel().hasLocationForContext(BASIC_PROCESS_EDITOR)) { nodeGR.doDefaultLayout(-1, -1); x = nodeGR.defaultX; y = nodeGR.defaultY; } else { x = nodeGR.getModel().getLocation(BASIC_PROCESS_EDITOR).getX(); y = nodeGR.getModel().getLocation(BASIC_PROCESS_EDITOR).getY(); } if (x >= 0 && y >= 0) { defaultX = x - getWidth() - 30; defaultY = y; } } } } /** * Performs dumb layout to try not to be on other views of this level */ protected void doLayoutMethod3(double x, double y) { Iterator<GraphicalRepresentation<?>> en = null; double attemptX = x, attemptY = y; boolean found = false; while (!found) { en = getContainerGraphicalRepresentation().getContainedGraphicalRepresentations().iterator(); found = true; while (en.hasNext()) { GraphicalRepresentation<?> gr = en.next(); if (gr instanceof WKFNodeGR<?>) { WKFNodeGR<?> rgr = (WKFNodeGR<?>) gr; if (rgr != this) { if (rgr.hasLocation()) { java.awt.Rectangle viewBounds = gr.getViewBounds(1.0); if (viewBounds.intersects(new java.awt.Rectangle((int) attemptX, (int) attemptY, (int) getWidth(), (int) getHeight()))) { // The attempt location intersects with another one, let's move forward found = false; if (viewBounds.x + viewBounds.width + getWidth() > getDrawingGraphicalRepresentation().getWidth()) { // End of line, we go to the next one if (attemptY + 10 + getHeight() < getDrawingGraphicalRepresentation().getHeight()) { attemptX = x; attemptY = attemptY + 10 + getHeight(); break; } else { if (logger.isLoggable(Level.WARNING)) { logger.warning("Could not find suitable location for node (bpe): " + getModel()); } break; } } else { attemptX = viewBounds.x + viewBounds.width + 10; break; } } } } } } } if (found) { defaultX = attemptX; defaultY = attemptY; } else { defaultX = x; defaultY = y; } } protected List<WKFNodeGR<?>> getFromInterestingNodeGR() { List<WKFNodeGR<?>> v = new ArrayList<WKFNodeGR<?>>(); Iterator<GraphicalRepresentation<?>> en = getDrawingGraphicalRepresentation().getContainedGraphicalRepresentations().iterator(); while (en.hasNext()) { GraphicalRepresentation<?> gr = en.next(); if (gr instanceof ConnectorGraphicalRepresentation<?>) { ConnectorGraphicalRepresentation<?> connector = (ConnectorGraphicalRepresentation<?>) gr; if (connector.getEndObject() == this && connector.getStartObject() instanceof WKFObjectGR<?>) { findSiblingGRFromNodeAndAddToVector((WKFObjectGR<?>) connector.getStartObject(), v); } } } return v; } protected List<WKFNodeGR<?>> getToInterestingNodeGR() { List<WKFNodeGR<?>> v = new ArrayList<WKFNodeGR<?>>(); Iterator<GraphicalRepresentation<?>> en = getDrawingGraphicalRepresentation().getContainedGraphicalRepresentations().iterator(); while (en.hasNext()) { GraphicalRepresentation<?> gr = en.next(); if (gr instanceof ConnectorGraphicalRepresentation<?>) { ConnectorGraphicalRepresentation<?> connector = (ConnectorGraphicalRepresentation<?>) gr; if (connector.getStartObject() == this && connector.getEndObject() instanceof WKFObjectGR<?>) { findSiblingGRFromNodeAndAddToVector((WKFObjectGR<?>) connector.getEndObject(), v); } } } return v; } protected void findSiblingGRFromNodeAndAddToVector(WKFObjectGR<?> gr, List<WKFNodeGR<?>> list) { while (gr != null && gr.getParentGraphicalRepresentation() != getParentGraphicalRepresentation()) { if (gr.getParentGraphicalRepresentation() instanceof WKFObjectGR<?>) { gr = (WKFObjectGR<?>) gr.getParentGraphicalRepresentation(); } else { gr = null; } } if (gr != null && gr instanceof WKFNodeGR<?> && !list.contains(gr)) { list.add((WKFNodeGR<?>) gr); } } public double getDefaultLabelX() { if (getModel().hasLabelLocationForContext(SWLEditorConstants.SWIMMING_LANE_EDITOR)) { return getModel().getLabelLocation(SWLEditorConstants.SWIMMING_LANE_EDITOR).getX(); } return 0; } public double getDefaultLabelY() { if (getModel().hasLabelLocationForContext(SWLEditorConstants.SWIMMING_LANE_EDITOR)) { return getModel().getLabelLocation(SWLEditorConstants.SWIMMING_LANE_EDITOR).getY(); } return 0; } }