/******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Exadel, Inc. * Red Hat, Inc. *******************************************************************************/ package org.jboss.tools.seam.ui.pages.editor.edit.xpl; import java.util.*; import org.eclipse.draw2d.AbstractRouter; import org.eclipse.draw2d.Connection; import org.eclipse.draw2d.IFigure; //import org.eclipse.draw2d.ConnectionAnchor; import org.eclipse.draw2d.geometry.*; import org.jboss.tools.seam.ui.pages.editor.ecore.pages.PagesElement; import org.jboss.tools.seam.ui.pages.editor.figures.ConnectionFigure; import org.jboss.tools.seam.ui.pages.editor.figures.ExceptionFigure; import org.jboss.tools.seam.ui.pages.editor.figures.PageFigure; final public class PagesConnectionRouter extends AbstractRouter { private Set<Integer> rowsUsed = new HashSet<Integer>(); private Set<Integer> colsUsed = new HashSet<Integer>(); private final static int STEP = 8; private final static int STATUS_NOTHING = 0; private final static int STATUS_HOLD = 2; private final static int STATUS_SHIFT = 3; private Map<Connection,ReservedInfo> reservedInfo = new HashMap<Connection,ReservedInfo>(); private class ReservedInfo { public List<Integer> reservedRows = new ArrayList<Integer>(2); public List<Integer> reservedCols = new ArrayList<Integer>(2); } private static Ray UP = new Ray(0,-1), DOWN = new Ray(0,1), LEFT = new Ray(-1,0), RIGHT = new Ray(1,0); public void invalidate(Connection connection) { removeReservedLines(connection); } private int getColumnNear(Connection conn, int r, int n, int x, boolean flag){ int index=0, size=0; int min = Math.min(n,x), max = Math.max(n,x); if (min > r){ max = min; min = r - (min-r); } if (max < r){ min = max; max = r + (r-max); } if(flag){ if(conn.getTargetAnchor().getOwner() != null){ IFigure fig = conn.getTargetAnchor().getOwner(); PagesElement element=null; if(fig instanceof PageFigure) element = ((PageFigure)fig).page; else if(fig instanceof ExceptionFigure) element = ((ExceptionFigure)fig).exc; if(element != null){ index = element.getInputLinks().indexOf(((ConnectionFigure)conn).getLinkModel()); size = element.getInputLinks().size(); }else flag = false; }else flag = false; if(flag && size > 1){ int value = max-20-(size-index)*STEP; if(value <= min) return min+STEP; if(value >= max) return max-STEP; return value; } size = 0; flag = true; if(conn.getSourceAnchor().getOwner() != null){ IFigure fig = conn.getSourceAnchor().getOwner(); PagesElement element=null; if(fig instanceof PageFigure) element = ((PageFigure)fig).page; else if(fig instanceof ExceptionFigure) element = ((ExceptionFigure)fig).exc; if(element != null){ index = element.getOutputLinks().indexOf(((ConnectionFigure)conn).getLinkModel()); size = element.getOutputLinks().size(); }else flag = false; }else flag = false; if(flag){ int value = min+100+(size-index)*STEP-size/2*STEP; if(value <= min) return min+STEP; if(value >= max) return max-STEP; return value; } } int proximity = 0; int direction = -1; if (r%2 == 1) r--; Integer i; while (proximity < r){ i = Integer.valueOf(r + proximity*direction); if (!colsUsed.contains(i)){ colsUsed.add(i); reserveColumn(conn, i); return i.intValue(); } int j = i.intValue(); if (j <= min) return j+STEP; if (j >= max) return j-STEP; if (direction == 1) direction = -1; else { direction = 1; proximity += STEP; } } return r; } protected Ray getDirection(Rectangle r, Point p){ int i, distance = Math.abs(r.x - p.x); Ray direction; direction = LEFT; i = Math.abs(r.y - p.y); if (i <= distance){ distance = i; direction = UP; } i = Math.abs(r.bottom()-p.y); if (i <= distance){ distance = i; direction = DOWN; } i = Math.abs(r.right()-p.x); if (i < distance){ distance = i; direction = RIGHT; } return direction; } protected Ray getEndDirection(Connection conn){ return LEFT; } protected int getRowNear(Connection connection, int r, int n, int x){ int min = Math.min(n,x), max = Math.max(n,x); if (min > r){ max = min; min = r - (min-r); } if (max < r){ min = max; max = r + (r-max); } int proximity = 0; int direction = -1; if (r%2 == 1) r--; Integer i; while (proximity < r){ i = Integer.valueOf(r + proximity*direction); if (!rowsUsed.contains(i)){ rowsUsed.add(i); reserveRow(connection, i); return i.intValue(); } int j = i.intValue(); if (j <= min) return j+STEP; if (j >= max) return j-STEP; if (direction == 1) direction = -1; else { direction = 1; proximity += STEP; } } return r; } protected Ray getStartDirection(Connection conn){ return RIGHT; } protected void processPositions(Ray start, Ray end, List positions, boolean horizontal, Connection conn) { removeReservedLines(conn); int pos[] = new int[positions.size()+2]; if (horizontal) pos[0] = start.x; else pos[0] = start.y; int i; for (i=0; i< positions.size(); i++){ pos[i+1] = ((Integer)positions.get(i)).intValue(); } if (horizontal == (positions.size()%2 == 1)) pos[++i] = end.x; else pos[++i] = end.y; PointList points = new PointList(); points.addPoint(new Point(start.x, start.y)); Point p; int current, prev, min, max; boolean adjust; for (i=2; i < pos.length - 1; i++){ horizontal = !horizontal; prev = pos[i-1]; current = pos[i]; adjust = (i != pos.length-2); if (horizontal){ if (adjust){ min = pos[i-2]; max = pos[i+2]; pos[i] = current = getRowNear(conn,current,min,max); current -= current%STEP; pos[i] -= pos[i]%STEP; } p = new Point(prev,current); } else{ if (adjust){ min = pos[i-2]; max = pos[i+2]; boolean flag; if(i == 2 && pos.length == 5){ flag = true; }else flag = false; pos[i] = current = getColumnNear(conn, current,min,max,flag); current -= current%STEP; pos[i] -= pos[i]%STEP; } p = new Point(current,prev); } points.addPoint(p); } points.addPoint(new Point(end.x, end.y)); conn.setPoints(points); } /** * Removes the given connection from the map of constraints. * * @param connection The connection to remove. */ public void remove(Connection connection){ removeReservedLines(connection); } protected void removeReservedLines(Connection connection) { ReservedInfo rInfo = (ReservedInfo) reservedInfo.get(connection); if (rInfo == null) return; for (int i = 0; i < rInfo.reservedRows.size(); i++){ rowsUsed.remove(rInfo.reservedRows.get(i)); } for (int i = 0; i < rInfo.reservedCols.size(); i++){ colsUsed.remove(rInfo.reservedCols.get(i)); } reservedInfo.remove(connection); } protected void reserveColumn(Connection connection, Integer column) { ReservedInfo info = (ReservedInfo) reservedInfo.get(connection); if (info == null) { info = new ReservedInfo(); reservedInfo.put(connection, info); } info.reservedCols.add(column); } protected void reserveRow(Connection connection, Integer row) { ReservedInfo info = (ReservedInfo) reservedInfo.get(connection); if (info == null) { info = new ReservedInfo(); reservedInfo.put(connection, info); } info.reservedRows.add(row); } /** * Routes the {@link Connection}. * * @param conn The {@link Connection} to route. */ public void route(Connection conn) { if ((conn.getSourceAnchor() == null) || (conn.getTargetAnchor() == null)){ return; } if(((ConnectionFigure)conn).getLinkModel() != null && ((ConnectionFigure)conn).getLinkModel().isShortcut()){ Point startPoint = getStartPoint(conn); conn.translateToRelative(startPoint); List<Integer> positions = new ArrayList<Integer>(5); Ray start = new Ray(startPoint); positions.add(Integer.valueOf(start.y)); Point endPoint = new Point(startPoint.x+18, startPoint.y); Ray end = new Ray(endPoint); processPositions(start, end, positions,true, conn); return; } if(((ConnectionFigure)conn).isManual()){ if(conn.getPoints().size() < 4){ PointList list = ((ConnectionFigure)conn).getLinkModel().getPointList(); ((ConnectionFigure)conn).setOldPoints(list.getFirstPoint(), list.getLastPoint()); conn.setPoints(list); } if(hold((ConnectionFigure)conn)) return; else{ ((ConnectionFigure)conn).setManual(false); ((ConnectionFigure)conn).clear(); } } int i; Point startPoint = getStartPoint(conn); conn.translateToRelative(startPoint); Point endPoint = getEndPoint(conn); conn.translateToRelative(endPoint); Ray start = new Ray(startPoint); Ray end = new Ray(endPoint); Ray average = start.getAveraged(end); Ray direction = new Ray(start, end); Ray startNormal = getStartDirection(conn); Ray endNormal = getEndDirection(conn); List<Integer> positions = new ArrayList<Integer>(5); boolean horizontal = true; // start horizontal segment positions.add(Integer.valueOf(start.y)); horizontal = !horizontal; if((start.x > (end.x+20)) && (Math.abs(end.y-start.y) < 100)){ i = startNormal.similarity(start.getAdded(startNormal.getScaled(10))); positions.add(Integer.valueOf(i)); horizontal = !horizontal; if(conn.getSourceAnchor().getOwner() == null){ i = average.y; }else{ Rectangle rec = conn.getSourceAnchor().getOwner().getBounds(); i = rec.y+rec.height+8; } i -= i%STEP; positions.add(Integer.valueOf(i)); horizontal = !horizontal; i = endNormal.similarity(end.getAdded(endNormal.getScaled(10))); i -= i%STEP; positions.add(Integer.valueOf(i)); horizontal = !horizontal; }else{ // vertical segment if (startNormal.dotProduct(direction) < STEP*2){ i = startNormal.similarity(start.getAdded(startNormal.getScaled(10))); i -= i%STEP; positions.add(Integer.valueOf(i)); horizontal = !horizontal; } // middle vertical or horizontal segment if (horizontal) i = average.y; else i = average.x; i -= i%STEP; positions.add(Integer.valueOf(i)); horizontal = !horizontal; // vertical segment if (startNormal.dotProduct(direction) < STEP*2){ i = endNormal.similarity(end.getAdded(endNormal.getScaled(10))); i -= i%STEP; positions.add(Integer.valueOf(i)); horizontal = !horizontal; } } // end horizontal segment positions.add(Integer.valueOf(end.y)); processPositions(start, end, positions,true, conn); ((ConnectionFigure)conn).setOldPoints(startPoint, endPoint); } private boolean hold(ConnectionFigure conn){ Point p1,p2; Point startPoint = getStartPoint(conn); conn.translateToRelative(startPoint); Point endPoint = getEndPoint(conn); conn.translateToRelative(endPoint); int status = check(conn); if(status == STATUS_NOTHING) return true; else if(status == STATUS_SHIFT){ shift(conn); conn.setOldPoints(startPoint, endPoint); conn.save(); return true; } PointList list = conn.getPoints(); list.removePoint(0); list.insertPoint(startPoint, 0); list.removePoint(list.size()-1); list.addPoint(endPoint); if(list.size() > 2){ p1 = list.getPoint(1); p1.y = startPoint.y; if(p1.x <= startPoint.x) return false; p2 = list.getPoint(list.size()-2); p2.y = endPoint.y; if(p2.x >= endPoint.x) return false; list.removePoint(1); list.insertPoint(p1, 1); int index = list.size()-2; list.removePoint(index); list.insertPoint(p2, index); } conn.setPoints(list); conn.setOldPoints(startPoint, endPoint); conn.save(); return true; } private void shift(ConnectionFigure conn){ Point startPoint = getStartPoint(conn); conn.translateToRelative(startPoint); Point oldStartPoint = conn.getOldStartPoint(); Point shiftPoint = new Point(startPoint.x-oldStartPoint.x, startPoint.y-oldStartPoint.y); Point point; PointList list = conn.getPoints(); if(list.getPoint(0).x == startPoint.x && list.getPoint(0).y == startPoint.y) return; for(int i=0;i<list.size();i++){ point = list.getPoint(i); point.x += shiftPoint.x; point.y += shiftPoint.y; list.removePoint(i); list.insertPoint(point, i); } conn.setPoints(list); } private int check(ConnectionFigure conn){ Point startPoint = getStartPoint(conn); conn.translateToRelative(startPoint); Point endPoint = getEndPoint(conn); conn.translateToRelative(endPoint); Point oldStartPoint = ((ConnectionFigure)conn).getOldStartPoint(); Point oldEndPoint = ((ConnectionFigure)conn).getOldEndPoint(); if(startPoint.x == oldStartPoint.x && startPoint.y == oldStartPoint.y && endPoint.x == oldEndPoint.x && endPoint.y == oldEndPoint.y) return STATUS_NOTHING; if((startPoint.x - oldStartPoint.x) == (endPoint.x - oldEndPoint.x) && (startPoint.y - oldStartPoint.y) == (endPoint.y - oldEndPoint.y)){ return STATUS_SHIFT; } return STATUS_HOLD; } }