ALWAYS_ROUTE
.
+ * Note: This is used by GraphLayouts which routes the path (control points)
+ * by themselves and would like to keep the path until user moves with source or target widget/anchor.
+ * @since 2.9
+ */
+ DISABLE_ROUTING_UNTIL_END_POINT_IS_MOVED,
+
+ /**
+ * Disable routing completely, so control points are kept at their previous location.
+ * Note: This is not often used unless you have to freeze a ConnectionWidget
+ * @since 2.9
+ */
+ DISABLE_ROUTING
+
+ }
+
private Anchor sourceAnchor;
private Anchor targetAnchor;
private AnchorShape sourceAnchorShape;
@@ -81,6 +121,8 @@
private Anchor.Entry sourceEntry;
private Anchor.Entry targetEntry;
+ private RoutingPolicy routingPolicy;
+
/**
* Creates a connection widget.
* @param scene the scene
@@ -100,6 +142,8 @@
controlPointCutDistance = 0;
sourceEntry = new ConnectionEntry (true);
targetEntry = new ConnectionEntry (false);
+
+ routingPolicy = RoutingPolicy.ALWAYS_ROUTE;
}
/**
@@ -338,6 +382,30 @@
}
/**
+ * Returns a routing policy.
+ * @return the routing policy
+ * @since 2.9
+ */
+ public final RoutingPolicy getRoutingPolicy () {
+ return routingPolicy;
+ }
+
+ /**
+ * Sets a routing policy. It invokes re-routing in case of routing policy change unless its is changed to DISABLE_ROUTING.
+ * @param routingPolicy the new routing policy
+ * @since 2.9
+ */
+ public final void setRoutingPolicy (RoutingPolicy routingPolicy) {
+ assert routingPolicy != null;
+ if (this.routingPolicy == routingPolicy)
+ return;
+ boolean changed = routingPolicy != RoutingPolicy.DISABLE_ROUTING;
+ this.routingPolicy = routingPolicy;
+ if (changed)
+ reroute ();
+ }
+
+ /**
* Returns the control-points-based path router of the connection widget.
* @return the path router
*/
@@ -427,8 +495,51 @@
* Forces path routing.
*/
public final void calculateRouting () {
- if (routingRequired)
- setControlPoints (router.routeConnection (this), true);
+ if (routingRequired) {
+ switch (routingPolicy) {
+ case ALWAYS_ROUTE:
+ setControlPoints (router.routeConnection (this), true);
+ break;
+ case UPDATE_END_POINTS_ONLY: {
+ Point sourcePoint = sourceAnchor != null ? sourceAnchor.compute (sourceEntry).getAnchorSceneLocation () : null;
+ Point targetPoint = targetAnchor != null ? targetAnchor.compute (targetEntry).getAnchorSceneLocation () : null;
+ if (sourcePoint == null || targetPoint == null) {
+ controlPoints.clear ();
+ break;
+ }
+ sourcePoint = convertSceneToLocal (sourcePoint);
+ targetPoint = convertSceneToLocal (targetPoint);
+ if (controlPoints.size () < 1)
+ controlPoints.add (sourcePoint);
+ else
+ controlPoints.set (0, sourcePoint);
+ if (controlPoints.size () < 2)
+ controlPoints.add (targetPoint);
+ else
+ controlPoints.set (controlPoints.size () - 1, targetPoint);
+ } break;
+ case DISABLE_ROUTING_UNTIL_END_POINT_IS_MOVED: {
+ Point sourcePoint = sourceAnchor != null ? sourceAnchor.compute (sourceEntry).getAnchorSceneLocation () : null;
+ Point firstPoint = getFirstControlPoint ();
+ if (firstPoint != null)
+ firstPoint = convertLocalToScene (firstPoint);
+ if (sourcePoint == null ? firstPoint == null : sourcePoint.equals (firstPoint)) {
+ Point targetPoint = targetAnchor != null ? targetAnchor.compute (targetEntry).getAnchorSceneLocation () : null;
+ Point lastPoint = getLastControlPoint ();
+ if (lastPoint != null)
+ lastPoint = convertLocalToScene (lastPoint);
+ if (targetPoint == null ? lastPoint == null : targetPoint.equals (lastPoint))
+ break;
+ }
+ routingPolicy = RoutingPolicy.ALWAYS_ROUTE;
+ setControlPoints (router.routeConnection (this), true);
+ } break;
+ case DISABLE_ROUTING:
+ break;
+ default:
+ throw new IllegalStateException ("Unexpected routing policy: " + routingPolicy); // NOI18N
+ }
+ }
}
/**
Index: graph/lib/src/org/netbeans/api/visual/widget/doc-files/documentation.html
===================================================================
RCS file: /cvs/graph/lib/src/org/netbeans/api/visual/widget/doc-files/documentation.html,v
--- graph/lib/src/org/netbeans/api/visual/widget/doc-files/documentation.html 10 Aug 2007 13:24:13 -0000 1.30
+++ graph/lib/src/org/netbeans/api/visual/widget/doc-files/documentation.html 23 Aug 2007 09:03:48 -0000
@@ -132,6 +132,7 @@
ActionFactory.createAddRemoveControlPointAction
-The action could be attached to FreeConnectionWidget
only and allow user to add a control point by double-clicking on path or remove control point by double-clicking on it. The action requires FreeRouter
to be set to the FreeConnectionWidget
where the action is attached - otherwise the control points are rerouted and therefore you loose the change. For fixing moving-anchor problem use FreeRectangularAnchor
.
+The action allows user to add a control point by double-clicking on path or remove control point by double-clicking on it. The action has routingPolicy
which is automatically set to ConnectionWidget
to prevent discarding of user changes by router assigned to the connection widget. For fixing moving-anchor problem use FreeRectangularAnchor
.
RouterFactory.createDirectRouter
creates a straight line between the source and the target anchor.
RouterFactory.createOrthogonalSeachRouter (CollisionsCollector)
creates an orthogonal path that tries to avoid overlapping areas specified by the CollisionsCollector
. There is a built-in implementation RouterFactory.createWidgetsCollisionCollector (LayerWidget...)
which collects all validated children widgets of the specified layer widgets and for each it gets the widget boundary and claims it as a vertical and horizontal collision. In case of ConnectionWidget, it takes the path (defined by its control points) and claims all horizontal and vertical segments as appropriate collisions.
RouterFactory.createOrthogonalSeachRouter (ConnectionWidgetCollisionsCollector)
creates an orthogonal path similarly as the previous case but the ConnectionWidgetCollisionsCollector
gets a context of currently routed connection widget.
-RouterFactory.createFreeRouter
is similar to DirectRouter
but it modifies only the first and last point of the route. The "middle" control points stay the same. This effect is used by AddRemoveControlPointAction
to maintain the control points created by user.
+RouterFactory.createFreeRouter
is similar to DirectRouter
but it modifies only the first and last point of the route. The "middle" control points stay the same. This effect is used by AddRemoveControlPointAction
to maintain the control points created by user. From now this router is no longer useful, since it can be replaced by more flexible way: use any router that you like and set "Update-end-points-only" routing policy to the ConnectionWidget.
See test.connectionlabels.ConnectionLabelsTest
for details.
+
routingPolicy
property. It ease management of control points changed by users. There are 4 values:
+ALWAYS_ROUTE
- This is default value. The router is always invoked when a ConnectionWidget is changed and needs to be re-routed.
+UPDATE_END_POINTS_ONLY
- The router is not invoked. Instead location of the first and the last control points are changed/updated to location computed by source and target anchors.
+DISABLE_ROUTING_UNTIL_END_POINT_IS_MOVED
- The router is not invoked until the first or the last control points is moved (means it has different location from one computed by source or target anchor).
+DISABLE_ROUTING
- The router is not invoked. The control points are freezed at the same locations.
+routingPolicy
value to factory method of AddRemoveControlPointAction
and MoveControlPointAction
. If not null, then the value is automatically set to a ConnectionWidget which control points are modified by the action. Usually UPDATE_END_POINT_ONLY
is used.
+UPDATE_END_POINT_ONLY
or DISABLE_ROUTING_UNTIL_END_POINT_IS_MOVED
to prevent discard of paths routed by the graph-oriented layout.
+
+For usages, see test.routing.ActionsWithRoutingPolicyTest
and test.routing.RoutingPolicyTest
examples.
+
@@ -1225,6 +1243,9 @@
setControlPoints
method.
+sceneLocations
is true
then the controlPoints
are recalculated relatively to the connection widget location otherwise controlPoints are taken as they are (and therefore they are taken as local locations). This method is usually called by the assigned router.
Index: graph/lib/src/org/netbeans/modules/visual/action/AddRemoveControlPointAction.java
===================================================================
RCS file: /cvs/graph/lib/src/org/netbeans/modules/visual/action/AddRemoveControlPointAction.java,v
--- graph/lib/src/org/netbeans/modules/visual/action/AddRemoveControlPointAction.java 14 Nov 2006 10:04:21 -0000 1.3
+++ graph/lib/src/org/netbeans/modules/visual/action/AddRemoveControlPointAction.java 23 Aug 2007 09:03:48 -0000
@@ -18,95 +18,73 @@
*/
package org.netbeans.modules.visual.action;
-import java.awt.Point;
-import java.awt.geom.Line2D;
-import java.util.ArrayList;
import org.netbeans.api.visual.action.WidgetAction;
import org.netbeans.api.visual.widget.ConnectionWidget;
import org.netbeans.api.visual.widget.Widget;
+import java.awt.*;
import java.awt.event.MouseEvent;
-import java.util.List;
-import org.netbeans.api.visual.action.WidgetAction.State;
+import java.awt.geom.Line2D;
+import java.util.ArrayList;
/**
* @author Alex
*/
public class AddRemoveControlPointAction extends WidgetAction.Adapter {
- private double createSensitivity=1.00, deleteSensitivity=5.00;
- private ConnectionWidget cWidget;
-
- public AddRemoveControlPointAction(){
-
- }
-
- public AddRemoveControlPointAction(double createSensitivity, double deleteSensitivity) {
+ private double createSensitivity;
+ private double deleteSensitivity;
+ private ConnectionWidget.RoutingPolicy routingPolicy;
+
+ public AddRemoveControlPointAction (double createSensitivity, double deleteSensitivity, ConnectionWidget.RoutingPolicy routingPolicy) {
this.createSensitivity = createSensitivity;
this.deleteSensitivity = deleteSensitivity;
+ this.routingPolicy = routingPolicy;
}
public State mouseClicked(Widget widget, WidgetMouseEvent event) {
if(event.getButton()==MouseEvent.BUTTON1 && event.getClickCount()==2 && widget instanceof ConnectionWidget) {
- cWidget=(ConnectionWidget)widget;
- Point point=event.getPoint();
- addRemoveControlPoint (point);
+ addRemoveControlPoint ((ConnectionWidget) widget, event.getPoint ());
+ return State.CONSUMED;
}
return State.REJECTED;
}
/**
* Adds or removes a control point on a specified location
+ * @param widget the connection widget
* @param localLocation the local location
*/
- private void addRemoveControlPoint (Point localLocation) {
- ArrayListResizeAction
AddRemoveControlPointAction
and MoveControlPointAction
+ConnectionWidget
OrthogonalSearchRouter
with Scene.maximumBounds
property
ScrollWidget
for scrollable view