Home » Eclipse Projects » GEF » GEF4 version 0.2.0 problem with self loop(problem with self loops while dragging a node)
GEF4 version 0.2.0 problem with self loop [message #1753078] |
Wed, 01 February 2017 11:38  |
Eclipse User |
|
|
|
Hi,
I have a problem with self loops in my graph (picture attached): Whenever I drag a StatePart (the circles labelled S1-S3 in the picture) and there are self loops of transitions between them, the self loop kind of explodes and I haven't been able to track down the problem so far.
This problem only occurs with self loops as you can see on the picture, transitions between two states are moved correctly.
EditorModule Transition bindings
@SuppressWarnings("serial")
protected void bindTransitionContentPartPolicies(MapBinder<AdapterKey<?>, Object> p_adapterMapBinder) {
// Make part focus & selectable
p_adapterMapBinder.addBinding(
AdapterKey.get(FXClickDragTool.CLICK_TOOL_POLICY_KEY)).to(
FXFocusAndSelectOnClickPolicy.class);
// provide geometry for selection handles
p_adapterMapBinder.addBinding(AdapterKey.get(new TypeToken<Provider<? extends IGeometry>>() {}, FXDefaultHandlePartFactory.SELECTION_HANDLES_GEOMETRY_PROVIDER)).to(VisualBoundsGeometryProvider.class);
// Add policy chain for moving
p_adapterMapBinder.addBinding(AdapterKey.get(FXResizeRelocatePolicy.class)).to(FXResizeRelocatePolicy.class);
// Add policy for hovering
p_adapterMapBinder.addBinding(AdapterKey.get(FXHoverTool.TOOL_POLICY_KEY)).to(FXHoverOnHoverPolicy.class);
// resize & transform
p_adapterMapBinder.addBinding(AdapterKey.get(FXBendPolicy.class)).to(TransitionBendPolicy.class);
// Add policy for addition of events
p_adapterMapBinder.addBinding(AdapterKey.get(AddEventLabelPolicy.class)).to(AddEventLabelPolicy.class);
}
EditorModule StateContentPart bindings
protected void bindStateContentPartPolicies(MapBinder<AdapterKey<?>, Object> p_adapterMapBinder) {
// Make part focus & selectable
p_adapterMapBinder.addBinding(
AdapterKey.get(FXClickDragTool.CLICK_TOOL_POLICY_KEY)).to(
FXFocusAndSelectOnClickPolicy.class);
// Add policy chain for moving
p_adapterMapBinder.addBinding(AdapterKey.get(FXClickDragTool.DRAG_TOOL_POLICY_KEY)).to(FXRelocateOnDragPolicy.class);
p_adapterMapBinder.addBinding(AdapterKey.get(FXResizeRelocatePolicy.class)).to(FXResizeRelocatePolicy.class);
p_adapterMapBinder.addBinding(AdapterKey.get(FXTransformPolicy.class)).to(StateTransformPolicy.class);
// Add policy for hovering
p_adapterMapBinder.addBinding(AdapterKey.get(FXHoverTool.TOOL_POLICY_KEY)).to(FXHoverOnHoverPolicy.class);
// Add policy for addition of prohibition events
p_adapterMapBinder.addBinding(AdapterKey.get(AddEventLabelPolicy.class)).to(AddEventLabelPolicy.class);
}
TransitionBendPolicy
public class TransitionBendPolicy extends FXBendPolicy {
@Override
public IUndoableOperation commit() {
return getHost().chainModelChanges(super.commit());
}
@Override
public TransitionContentPart getHost() {
return (TransitionContentPart) super.getHost();
}
}
TransitionContentPart
public class TransitionContentPart extends AbstractConnectionContentPart<FXConnection> implements TransitionView.IChangeListener, IHoverable {
public static class UpdateWayPointOperation extends AbstractOperation {
private final TransitionView m_model;
private final Collection<de.rwthaachen.embedded.syntacs.model.utils.Point> m_old;
private final Collection<de.rwthaachen.embedded.syntacs.model.utils.Point> m_new;
public UpdateWayPointOperation(TransitionView p_model, Collection<Point> p_old, Collection<Point> p_new) {
super("Update transition way points");
m_model = p_model;
m_old = GeometryUtils.GEFPointToModelPoint(p_old);
m_new = GeometryUtils.GEFPointToModelPoint(p_new);
}
@Override
public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
m_model.setWayPoints(m_new);
return Status.OK_STATUS;
}
@Override
public IStatus redo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
return execute(monitor, info);
}
@Override
public IStatus undo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
m_model.setWayPoints(m_old);
return Status.OK_STATUS;
}
}
@SuppressWarnings("serial")
@Override
protected void attachToAnchorageVisual(IVisualPart<Node, ? extends Node> p_anchorage, String p_role) {
IFXAnchor anchor = p_anchorage.getAdapter(new TypeToken<Provider<? extends IFXAnchor>>() {}).get();
if("START".equals(p_role)) {
getVisual().setStartAnchor(anchor);
} else if("END".equals(p_role)) {
getVisual().setEndAnchor(anchor);
} else {
throw new IllegalArgumentException("Cannot attach visual anchor with role \"" + p_role + "\"");
}
}
@Override
public void attachToContentAnchorage(Object p_contentAnchorage, String p_role) {
if(!(p_contentAnchorage instanceof StateView)) {
throw new IllegalArgumentException("Inappropriate content anchorage: wrong type");
}
final StateView state = (StateView) p_contentAnchorage;
final TransitionView trans = getContent();
try {
if("START".equals(p_role)) {
trans.setFrom(state);
} else if("END".equals(p_role)) {
trans.setTo(state);
}
} catch (ConsistencyException e) {
throw new IllegalArgumentException("Inappropriate content anchorage: cannot be attached here");
}
if(trans.isUsed() && 0 == trans.getWayPointCount()) {
final TransitionView other = trans.getTo().getTransition(trans.getFrom());
if(null != other) {
trans.addNormalizedWayPoint(new de.rwthaachen.embedded.syntacs.model.utils.Point(0, 20));
if(0 == other.getWayPointCount()) {
other.addNormalizedWayPoint(new de.rwthaachen.embedded.syntacs.model.utils.Point(0, 20));
}
}
}
}
public IUndoableOperation chainModelChanges(IUndoableOperation p_visualOperation) {
if(null == p_visualOperation) {
return null;
}
// Update waypoints in model
final Collection<Point> oldWayPoints = GeometryUtils.ModelPointToGEFPoint(getContent().getWayPoints());
final List<Point> newWayPoints = getVisual().getWayPoints();
final UpdateWayPointOperation wpOp = new UpdateWayPointOperation(getContent(), oldWayPoints, newWayPoints);
// Update anchorages in model
StateView from = getAnchorageContent(getVisual().getStartAnchor());
StateView to = getAnchorageContent(getVisual().getEndAnchor());
final ContentPolicy<Node> contentPolicy = getAdapter(ContentPolicy.class);
// Detach old anchorages if there was a change
contentPolicy.init();
SetMultimap<IVisualPart<Node, ? extends Node>, String> anchorages = HashMultimap.create(getAnchorages());
for(IVisualPart<Node, ? extends Node> anchorage: anchorages.keySet()) {
if(anchorage instanceof IContentPart) {
for(String role: anchorages.get(anchorage)) {
final Object contentAnchorage = ((IContentPart<Node, ? extends Node>) anchorage).getContent();
if("START".equals(role)) {
if(from != contentAnchorage) {
// changed, remove the old one
contentPolicy.detachFromContentAnchorage(contentAnchorage, role);
} else {
// not changed, keep the old one
from = null;
}
} else if("END".equals(role)) {
if(to != contentAnchorage) {
// changed, remove the old one
contentPolicy.detachFromContentAnchorage(contentAnchorage, role);
} else {
// not changed, keep the old one
to = null;
}
}
}
}
}
final IUndoableOperation detachOp = contentPolicy.commit();
// Attach current anchorages
contentPolicy.init();
if(null != from) {
contentPolicy.attachToContentAnchorage(from, "START");
}
if(null != to) {
contentPolicy.attachToContentAnchorage(to, "END");
}
final IUndoableOperation attachOp = contentPolicy.commit();
// Build resulting operation
return new ForwardUndoCompositeOperation(p_visualOperation.getLabel()) {
{
add(p_visualOperation);
add(wpOp);
if(detachOp != null || attachOp != null) {
add(new ReverseUndoCompositeOperation("Update anchorages") {
{
if(null != detachOp) {
add(detachOp);
}
if(null != attachOp) {
add(attachOp);
}
}
}.unwrap());
}
}
}.unwrap();
}
@Override
protected FXConnection createVisual() {
final FXConnection visual = new FXConnection();
visual.setRouter(new FXPolyBezierConnectionRouter());
visual.setEndDecoration(new ArrowHead());
visual.getCurveNode().setStrokeWidth(2.);
final DropShadow shadow = new DropShadow();
visual.setEffect(shadow);
return visual;
}
@Override
protected void detachFromAnchorageVisual(IVisualPart<Node, ? extends Node> p_anchorage, String p_role) {
// Keep position if anchorage is gone
if("START".equals(p_role)) {
getVisual().setStartPoint(getVisual().getStartPoint());
} else if("END".equals(p_role)) {
getVisual().setEndPoint(getVisual().getEndPoint());
} else {
throw new IllegalArgumentException("Cannot detach visual anchor with role \"" + p_role + "\"");
}
}
@Override
public void detachFromContentAnchorage(Object p_contentAnchorage, String p_role) {
if(null != getContent()) {
try {
if("START".equals(p_role)) {
getContent().setFrom(null);
} else if("END".equals(p_role)) {
getContent().setTo(null);
} else {
throw new IllegalArgumentException("Cannot detach anchor with role \"" + p_role + "\"");
}
} catch(ConsistencyException e) {
// ignored
}
}
}
@Override
protected void doActivate() {
super.doActivate();
getContent().addChangeListener(this);
}
@Override
protected void doDeactivate() {
getContent().removeChangeListener(this);
super.doDeactivate();
}
@Override
protected void doRefreshVisual(FXConnection p_visual) {
// Convert SynTACS UI Model points to GEF points
final Collection<de.rwthaachen.embedded.syntacs.model.utils.Point> wayPoints = getContent().getWayPoints();
System.out.print("ModelPoints" + getContent().getWayPoints() + "\n");
final List<Point> wps = new ArrayList<Point>(wayPoints.size());
for(de.rwthaachen.embedded.syntacs.model.utils.Point p: wayPoints) {
wps.add(new Point(p.x, p.y));
System.out.print("WPS" + wps + "\n");
}
// Apply way points
//p_visual.setWayPoints(wps);
// TODO HOTFIX FOR BUG IN FXConnection.setWayPoints:
int waySize = p_visual.getWayAnchorsSize();
int i = 0;
for (; i < waySize && i < wps.size(); i++) {
p_visual.setWayPoint(i, wps.get(i));
}
for (; i < wps.size(); i++) {
p_visual.addWayPoint(i, wps.get(i));
}
for (; i < waySize; i++) {
p_visual.removeWayPoint(wps.size());
}
// END HOTFIX
}
protected StateView getAnchorageContent(IFXAnchor p_anchor) {
final Node node = p_anchor.getAnchorage();
if(node != getVisual()) {
final IVisualPart<Node, ? extends Node> part = getViewer().getVisualPartMap().get(node);
if(part instanceof IContentPart) {
final Object content = ((IContentPart<Node, ? extends Node>) part).getContent();
if(content instanceof StateView) {
return (StateView) content;
}
}
}
return null;
}
@Override
public TransitionView getContent() {
return (TransitionView) super.getContent();
}
@Override
public SetMultimap<Object, String> getContentAnchorages() {
final SetMultimap<Object, String> anchorages = HashMultimap.create();
final TransitionView data = getContent();
if(null != data) {
if(null != data.getFrom()) {
anchorages.put(data.getFrom(), "START");
}
if(null != data.getTo()) {
anchorages.put(data.getTo(), "END");
}
}
return anchorages;
}
@Override
public void labelAdded(TransitionView p_trans, Label p_label) {
// ignored
}
@Override
public void labelRemoved(TransitionView p_trans, Label p_label) {
// ignored
}
@Override
public void layoutChanged(TransitionView p_trans) {
final ContentBehavior<Node> contentBehavior = getAdapter(ContentBehavior.class);
if(null != contentBehavior) {
contentBehavior.synchronizeContentAnchorages(getContentAnchorages());
}
refreshVisual();
}
@Override
public void transitionRemoved(TransitionView p_trans) {
// ignored
}
@Override
public void updateHoverState(int p_state) {
Color color = null;
switch(p_state) {
case HOVER_NONE:
color = Color.BLACK;
break;
case HOVER_ELEMENT:
color = Color.DARKBLUE;
break;
case HOVER_LABEL:
color = Color.BROWN;
break;
}
if(null != color) {
getVisual().getCurveNode().setStroke(color);
((ArrowHead) getVisual().getEndDecoration()).setColor(color);
}
}
}
Any help would be very much appreciated. I have taken over this part the GEF part of the project from a previous colleague so progress has been slow as I also need to find my way around his code and am quite new to GEF.
Best regards
|
|
|
Re: GEF4 version 0.2.0 problem with self loop [message #1753177 is a reply to message #1753078] |
Thu, 02 February 2017 08:24   |
Eclipse User |
|
|
|
Hi Arthur,
if I am not mistaken, all states changed position in the attached screenshots. However, I assume the erroneous behavior can be observed when dragging a single state, and the self-loop at that state explodes. Is that correct?
Per default, processing of user input is divided into multiple phases in GEF: 1) Tools use listeners to observe user input (e.g. FXClickDragTool); 2) Tools forward input events to the registered applicable interaction policies for processing (e.g. FXRelocateOnDragPolicy); 3) Interaction policies make use of transactional policies to perform their actions (e.g. StateTransformPolicy). 4) The operations are executed on the domain in the context of a single transaction (i.e. they can be undone/redone in a single step).
In order to identify the underlying problem, you need to investigate what happens when the operations are executed, because one of the operations is probably causing the transition to explode. Other than that, you should verify that the way points are correct. A good place for a breakpoint would be the FXRelocateOnDragPolicy#release() method, as well as the Connection#refresh() method.
Best regards,
Matthias
|
|
| | |
Goto Forum:
Current Time: Mon Apr 28 11:59:57 EDT 2025
Powered by FUDForum. Page generated in 0.03830 seconds
|