org.netbeans.modeler.widget.transferable.TransAlignWithMoveStrategyProvider Maven / Gradle / Ivy
/**
* Copyright 2013-2022 Gaurav Gupta
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.netbeans.modeler.widget.transferable;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.netbeans.api.visual.action.AlignWithMoveDecorator;
import org.netbeans.api.visual.action.AlignWithWidgetCollector;
import org.netbeans.api.visual.action.MoveProvider;
import org.netbeans.api.visual.action.MoveStrategy;
import org.netbeans.api.visual.action.WidgetAction;
import org.netbeans.api.visual.anchor.Anchor;
import org.netbeans.api.visual.graph.GraphScene;
import org.netbeans.api.visual.widget.ConnectionWidget;
import org.netbeans.api.visual.widget.LayerWidget;
import org.netbeans.api.visual.widget.Scene;
import org.netbeans.api.visual.widget.Widget;
import org.netbeans.modeler.core.NBModelerUtil;
import org.netbeans.modeler.scene.AbstractModelerScene;
import org.netbeans.modeler.specification.model.document.IModelerScene;
import org.netbeans.modeler.specification.model.document.widget.IModelerSubScene;
import org.netbeans.modeler.widget.context.ContextPaletteManager;
/**
*
*/
public class TransAlignWithMoveStrategyProvider extends TransAlignWithSupport implements MoveStrategy, MoveProvider {
private boolean outerBounds;
private static int eventID = 0;
private LayerWidget interactionLayer = null;
private LayerWidget mainLayer = null;
private ArrayList< MovingWidgetDetails> movingWidgets = null;
private Point original;
private boolean moveWidgetInitialized;
public TransAlignWithMoveStrategyProvider(AlignWithWidgetCollector collector,
LayerWidget interractionLayer,
LayerWidget widgetLayer,
AlignWithMoveDecorator decorator,
boolean outerBounds) {
super(collector, interractionLayer, decorator);
this.outerBounds = outerBounds;
this.interactionLayer = interractionLayer;
this.mainLayer = widgetLayer;
moveWidgetInitialized = false;
}
@Override
public Point locationSuggested(Widget widget, Point originalLocation, Point suggestedLocation) {
if (movingWidgets.size() > 1) {
return suggestedLocation;
}
Point widgetLocation = widget.getLocation();
Rectangle widgetBounds = outerBounds ? widget.getBounds() : widget.getClientArea();
Rectangle bounds = widget.convertLocalToScene(widgetBounds);
bounds.translate(suggestedLocation.x - widgetLocation.x, suggestedLocation.y - widgetLocation.y);
Insets insets = widget.getBorder().getInsets();
if (!outerBounds) {
suggestedLocation.x += insets.left;
suggestedLocation.y += insets.top;
}
Widget parent = widget.getParentWidget();
Point point = super.locationSuggested(widget, bounds, suggestedLocation, true, true, true, true);
if (!outerBounds) {
point.x -= insets.left;
point.y -= insets.top;
}
Point localPt = parent.convertSceneToLocal(point);
return localPt;
}
@Override
public void movementStarted(Widget widget) {
show();
Scene scene = widget.getScene();
ContextPaletteManager manager = ((AbstractModelerScene) scene).getContextPaletteManager();
if (manager != null) {
manager.cancelPalette();
}
moveWidgetInitialized = false;
}
@Override
public void movementFinished(Widget widget) {
hide();
Scene scene = widget.getScene();
if (movingWidgets != null) {
for (MovingWidgetDetails details : movingWidgets) {
Widget curWidget = details.getWidget();
Point location = curWidget.getLocation();
MoveDropTargetDropEvent dropEvent = new MoveDropTargetDropEvent(curWidget, location);
WidgetAction.WidgetDropTargetDropEvent event = new WidgetAction.WidgetDropTargetDropEvent(++eventID, dropEvent);
if (processLocationOperator(scene, event, location) == false) {
finishedOverScene(details, scene);
}
// if (details.getOwner() instanceof SubProcessWidget)
// {
// SubProcessWidget container = (SubProcessWidget) details.getOwner();
// container.firePropertyChange(SubProcessWidget.CHILDREN_CHANGED, null, null);
//
// }
// If a widgets new owner is the same as its original owner
// then make sure that the widget has the same index as it
// had before the move began.
for (MovingWidgetDetails curDetail : movingWidgets) {
curDetail.updateIndexIfRequired();
}
}
movingWidgets.clear();
movingWidgets = null;
}
// ContextPaletteManager manager = scene.getLookup().lookup(ContextPaletteManager.class);
// if(manager != null)
// {
// manager.selectionChanged(null);
// }
original = null;
}
@Override
public Point getOriginalLocation(Widget widget) {
original = widget.getPreferredLocation();
initializeMovingWidgets(widget.getScene(), widget);
lastPoint = original;
if (lastPoint != null) {
original = widget.getParentWidget().convertLocalToScene(lastPoint);
}
return original;
}
protected Point convertLocationToScene(Widget widget) {
Point retVal = widget.getLocation();
Widget curWidget = widget.getParentWidget();
while (curWidget != null) {
retVal.x += curWidget.getLocation().x;
retVal.y += curWidget.getLocation().y;
curWidget = curWidget.getParentWidget();
}
return retVal;
}
Point lastPoint = null;
@Override
public void setNewLocation(Widget widget, Point location) {
if (location != null && original != null) {
// Determine if the new location of the widget has actually moved.
//
// Originally we used the dx and dy variables to determine if the
// node moved. However, the dx and dy values are based off the
// original position of the widget. In this case the "original"
// position of the widget is defined as the location before the move
// started. Therefore if the widget is moved back to the exact
// coordinate as the origional location the widget will not be
// moved. This is not that big of a deal when using the mouse to
// move because it is not very likely that the exact coordinate will
// occur in a single move. However when using the keyboard to move
// nodes this is very likey to happen, especially on the SQD where
// the lifeline node can only be moved left and right.
int dx = location.x - widget.getPreferredLocation().x;
int dy = location.y - widget.getPreferredLocation().y;
if (dx != 0 || dy != 0) {
if (movingWidgets == null) {
//in case if this class is used only as provider and strategy isn't used
initializeMovingWidgets(widget.getScene(), widget);
}
// The dx is calcuated using a start location of when the move
// first started. However for connection points we do not have
// the connection point values from before the move started.
//
// Therefore use the reference widget to determine the dx.
lastPoint = location;
adjustControlPoints(getMovingWidgetList(), dx, dy);
for (MovingWidgetDetails details : movingWidgets) {
Point point = details.getWidget().getPreferredLocation();
if (point == null) {
point = details.getWidget().getLocation();
}
Point newPt = new Point(point.x + dx, point.y + dy);
if (details.getWidget() instanceof ConnectionWidget) {
// Do nothing because the adjustControlPoints will
// take care of this situation.
} else {
//REMOVE_PRE
// I do not understand what is different between the
// composite container and the other nodes. However
// the position is always relative to the contianers
// original owner.
//
// Since we are at the end of the release cycle I am
// not wanting to do anything big here. So special
// case the composite nodes.
if (details.getWidget() instanceof IModelerSubScene) {
newPt = details.getOwner().convertLocalToScene(newPt);
}
details.getWidget().setPreferredLocation(newPt);
}
}
}
}
}
protected ArrayList getMovingDetails() {
return movingWidgets;
}
protected List< Widget> getMovingWidgetList() {
ArrayList< Widget> retVal = new ArrayList< Widget>();
for (MovingWidgetDetails details : movingWidgets) {
retVal.add(details.getWidget());
}
return retVal;
}
/**
* Adjust the control points of all selected connection widgets attached to
* a node.
*
* @param widgets The list of widgets to update.
* @param dx The distance in the x direction.
* @param dy The distance in the y direction.
*/
public static void adjustControlPoints(List< Widget> widgets,
int dx, int dy) {
// Since child nodes are not part of the widgets (since they are moved
// when the parent widget is moved), we need to first make sure
// that we get not only the selected set of widgets, but also the
// edges attached to all child nodes. This is mostly for containers.
List< ConnectionWidget> connections = includeAllConnections(widgets);
ArrayList< Object> alreadyProcessed = new ArrayList< Object>();
for (ConnectionWidget connection : connections) {
GraphScene scene = (GraphScene) connection.getScene();
Object data = scene.findObject(connection);
if (alreadyProcessed.contains(data) == false) {
if ((connection.getState().isSelected() == true)
|| (widgets.contains(connection) == true)) {
List points = connection.getControlPoints();
for (int index = 1; index < points.size() - 1; index++) {
Point pt = points.get(index);
pt.x += dx;
pt.y += dy;
}
}
// Each node also needs to be revalidated so that the anchor
// gets a chance to update the end point
Anchor sourceAnchor = connection.getSourceAnchor();
if (sourceAnchor != null) {
sourceAnchor.getRelatedWidget().revalidate();
}
Anchor targetAnchor = connection.getTargetAnchor();
if (targetAnchor != null) {
targetAnchor.getRelatedWidget().revalidate();
}
alreadyProcessed.add(data);
}
}
}
private static List includeAllConnections(List widgets) {
ArrayList< ConnectionWidget> retVal = new ArrayList();
for (Widget widget : widgets) {
IModelerScene scene = (IModelerScene) widget.getScene();
List< ConnectionWidget> connections = buildListOfConnections(scene, widget);
if ((connections != null) && (connections.size() > 0)) {
retVal.addAll(connections);
}
}
return retVal;
}
private static List buildListOfConnections(IModelerScene scene,
Widget widget) {
ArrayList< ConnectionWidget> retVal = new ArrayList();
// First get the edges for the passed in widget. If the data object
// does not represent a node the method findNodeEdges will throw an
// assertion. Therefore check if it is a node first.
Object data = scene.findObject(widget);
if ((data != null) && (scene.isNode(data) == true)) {
// If you ask for the object of a widget it will get the object
// of the first parent that has an associated object. Therefore
// we need to first make sure that the object is associated with the
// widget in question. Otherwise we will end up with a lot of
// duplicates.
if (widget.equals(scene.findWidget(data)) == true) {
Collection edges = null;
if (scene instanceof GraphScene) {
edges = ((GraphScene) scene).findNodeEdges(data, true, true);
}
// else {
// edges = ((GraphPinScene) scene).findPinEdges(data, true, true); // BUG : Development Required
// }
if ((edges != null) && (edges.size() > 0)) {
for (Object curEdge : edges) {
ConnectionWidget connection = (ConnectionWidget) scene.findWidget(curEdge);
retVal.add(connection);
}
}
}
}
// Second get the edges for all of the children.
for (Widget child : widget.getChildren()) {
List childConns = buildListOfConnections(scene, child);
if ((childConns != null) && (childConns.size() > 0)) {
retVal.addAll(childConns);
}
}
return retVal;
}
private boolean checkIfAccepted(Widget widget,
WidgetAction.WidgetDropTargetDropEvent event,
Point pt) {
boolean retVal = false;
if (widget != null) {
for (Widget child : widget.getChildren()) {
Rectangle bounds = child.getBounds();
if (bounds.contains(pt)) {
List children = child.getChildren();
for (Widget curChild : children) {
if (curChild.isVisible() == true) {
Point childLoc = curChild.getLocation();
Point testPoint = new Point(pt.x - childLoc.x,
pt.y - childLoc.y);
retVal = checkIfAccepted(curChild, event, testPoint);
if (retVal == true) {
break;
}
}
}
if (retVal == false) {
retVal = sendEvents(child, event, pt);
}
}
}
}
return retVal;
}
private void finishedOverScene(MovingWidgetDetails details, Scene scene) {
Widget widget = details.getWidget();
List children = interactionLayer.getChildren();
if (children != null && children.contains(widget)) {
interactionLayer.removeChild(widget);
mainLayer.addChild(widget);
}
// Lookup lookup = scene.getLookup();
// if (lookup != null)
// {
// // Find out who currently owns the widgets metamodel element
// // If a new namespace is about to own the metamodel element, then
// // remove the model element from the curent namespace.
// INamedElement element = null;
// if (scene instanceof ObjectScene)
// {
// ObjectScene objScene = (ObjectScene) scene;
//
// Object data = objScene.findObject(widget);
// if (data instanceof IPresentationElement)
// {
// IPresentationElement presentation = (IPresentationElement) data;
// if(presentation.getFirstSubject() instanceof INamedElement)element = (INamedElement) presentation.getFirstSubject();
// }
//
// // Handle the namespace change. The container widget will
// // handle adding a child to the containers namespace.
// //
// // We have to have to handle the case of when the widget
// // is moved from a container to the scene.
// if (details.getOwner() instanceof ContainerWidget && element!=null)
// {
// IDiagram diagram = lookup.lookup(IDiagram.class);
// if (diagram != null)
// {
// INamespace space = diagram.getNamespace();
// INamespace curSpace = element.getOwningPackage();
//
// if (space.equals(curSpace) == false)
// {
// curSpace.removeOwnedElement(element);
// space.addOwnedElement(element);
// }
// }
// }
// }
// }
}
private void initializeMovingWidgets(Scene scene, Widget widget) {
if (movingWidgets != null) {
// We should never be here;
movingWidgets.clear();
movingWidgets = null;
}
movingWidgets = new ArrayList< MovingWidgetDetails>();
if (scene instanceof GraphScene) {
GraphScene gscene = (GraphScene) scene;
Object object = gscene.findObject(widget);
if (gscene.isNode(object)) {
Set< ?> selected = gscene.getSelectedObjects();
for (Object o : selected) {
if ((gscene.isNode(o)) && (isOwnerSelected(o, selected, gscene) == false)) {
Widget w = gscene.findWidget(o);
if (w != null) {
Point pt = w.getPreferredLocation();
Widget owner = w.getParentWidget();
if (owner != null) {
pt = owner.convertLocalToScene(pt);
w.setPreferredLocation(pt);
}
MovingWidgetDetails details = new MovingWidgetDetails(w, owner, pt);
movingWidgets.add(details);
for (ConnectionWidget c : NBModelerUtil.getAllContainedEdges(w)) {
movingWidgets.add(new MovingWidgetDetails(c,
c.getParentWidget(), c.getParentWidget().convertLocalToScene(c.getFirstControlPoint())));
}
if (details.getOwner() != null) {
details.getOwner().removeChild(w);
}
interactionLayer.addChild(w);
}
}
}
//need to sort in order to return back properly without indexOutOfBounds
Collections.sort(movingWidgets, (TransAlignWithMoveStrategyProvider.MovingWidgetDetails o1, TransAlignWithMoveStrategyProvider.MovingWidgetDetails o2) -> o1.getOriginalIndex() - o2.getOriginalIndex());
} else {
MovingWidgetDetails details = new MovingWidgetDetails(widget, widget.getParentWidget(), widget.getPreferredLocation());
movingWidgets.add(details);
}
}
moveWidgetInitialized = true;
}
public boolean isMovementInitialized() {
return moveWidgetInitialized;
}
private boolean isOwnerSelected(Object o,
Set> selected,
GraphScene gscene) {
boolean retVal = false;
Widget widget = gscene.findWidget(o);
if (widget != null) {
Widget parent = widget.getParentWidget();
Object parentObj = gscene.findObject(parent);
if (parentObj != null) {
if (selected.contains(parentObj) == true) {
retVal = true;
} else {
retVal = isOwnerSelected(parentObj, selected, gscene);
}
}
}
return retVal;
}
private boolean processLocationOperator(Widget widget,
WidgetAction.WidgetDropTargetDropEvent event,
Point cursorSceneLocation) {
Scene scene = widget.getScene();
Point location = scene.getLocation();
return processLocationOperator2(scene, event, new Point(cursorSceneLocation.x + location.x, cursorSceneLocation.y + location.y));
}
private boolean processLocationOperator2(Widget widget,
WidgetAction.WidgetDropTargetDropEvent event,
Point point) {
boolean retVal = false;
if (!widget.isVisible()) {
return false;
}
Point location = widget.getLocation();
point.translate(-location.x, -location.y);
Rectangle bounds = widget.getBounds();
if (bounds.contains(point)) {
List children = widget.getChildren();
Widget[] childrenArray = children.toArray(new Widget[children.size()]);
for (int i = childrenArray.length - 1; i >= 0; i--) {
if (processLocationOperator2(childrenArray[i], event, point) == true) {
retVal = true;
break;
}
}
if ((retVal == false) && (widget.isHitAt(point) == true)) {
retVal = sendEvents(widget, event, point);
}
}
point.translate(location.x, location.y);
return retVal;
}
private boolean sendEvents(Widget target,
WidgetAction.WidgetDropTargetDropEvent event,
Point pt) {
boolean retVal = false;
if (target != null) {
if (sendEvents(target.getActions(), target, event) == false) {
String tool = target.getScene().getActiveTool();
retVal = sendEvents(target.getActions(tool), target, event);
} else {
retVal = true;
}
}
return retVal;
}
private boolean sendEvents(WidgetAction.Chain actions,
Widget target,
WidgetAction.WidgetDropTargetDropEvent event) {
boolean retVal = false;
if (actions != null) {
for (WidgetAction action : actions.getActions()) {
if (action.drop(target, event) == WidgetAction.State.CONSUMED) {
retVal = true;
break;
}
}
}
return retVal;
}
private class MovingWidgetDetails {
private Widget widget = null;
private Widget owner = null;
private Point originalLocation = null;
private int originalIndex = -1;
public MovingWidgetDetails(Widget widget,
Widget owner,
Point location) {
this.widget = widget;
this.owner = owner;
this.originalLocation = location;
if (owner != null) {
originalIndex = owner.getChildren().indexOf(widget);
}
}
public Point getOriginalLocation() {
return originalLocation;
}
public Widget getOwner() {
return owner;
}
public Widget getWidget() {
return widget;
}
public int getOriginalIndex() {
return originalIndex;
}
public void updateIndexIfRequired() {
if (owner.equals(widget.getParentWidget())) {
owner.removeChild(widget);
//Adjust the original index.
owner.addChild(--originalIndex < 0 ? 0 : originalIndex, widget);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy