Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Graphical Modeling Framework/Recipes
Recipe: HowTo reorder children in a GMF compartment with Drag & Drop
Problem:
You have created a node class which can contain other nodes. E.g. a class bookshelf that contains objects of the class book. Therefore you created a compartment. After adding books to the bookshelf in your editor, you want to rearrange the books by drag & drop. But it doesn't work...
Solution:
In the xxxCompartmentEditPart class rewrite the createFigure() method:
public IFigure createFigure() { ResizableCompartmentFigure rcf = (ResizableCompartmentFigure) super.createFigure(); FlowLayout layout = new FlowLayout(); layout.setMajorSpacing(getMapMode().DPtoLP(5)); layout.setMinorSpacing(getMapMode().DPtoLP(5)); layout.setHorizontal(false); rcf.getContentPane().setLayoutManager(layout); rcf.setTitleVisibility(false); return rcf; }
In the createDefaultEditPolicies() method of the xxxCompartmentEditPart class add an EditPolicy:
installEditPolicy(EditPolicy.LAYOUT_ROLE, new CompartmentEditPolicy(xxxPackage.Literals.xxx));
Note: xxxPackage.Literals.xxx has to be the EStructuralFeature of the EList Attribute that contains the Objects which should be reordered.
Use the classes CompartmentEditPolicy and CompartmentRepositionEObjectCommand:
package whatever.package.you.want; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gef.EditPart; import org.eclipse.gmf.runtime.common.core.command.CommandResult; import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil; import org.eclipse.gmf.runtime.emf.commands.core.commands.RepositionEObjectCommand; import org.eclipse.gmf.runtime.notation.View; public class CompartmentRepositionEObjectCommand extends RepositionEObjectCommand { EditPart childToMove = null; int newIndex = 0; public CompartmentRepositionEObjectCommand( TransactionalEditingDomain editingDomain, String label, EList elements, EObject element, int displacement) { super(editingDomain, label, elements, element, displacement); } public CompartmentRepositionEObjectCommand(EditPart childToMove, TransactionalEditingDomain editingDomain, String label, EList elements, EObject element, int displacement, int newIndex) { super(editingDomain, label, elements, element, displacement); this.childToMove = childToMove; this.newIndex = newIndex; } public CommandResult doExecuteWithResult( IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException { CommandResult rs = super.doExecuteWithResult(progressMonitor, info); EditPart compartment = childToMove.getParent(); ViewUtil.repositionChildAt((View)compartment.getModel(), (View)childToMove.getModel(), newIndex); compartment.refresh(); return rs; } }
package whatever.package.you.want; import whatever.package.you.want.CompartmentRepositionEObjectCommand; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gef.EditPart; import org.eclipse.gef.EditPolicy; import org.eclipse.gef.Request; import org.eclipse.gef.commands.Command; import org.eclipse.gef.requests.CreateRequest; import org.eclipse.gmf.runtime.diagram.core.commands.AddCommand; import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editpolicies.ResizableEditPolicyEx; import org.eclipse.gmf.runtime.emf.commands.core.commands.RepositionEObjectCommand; import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter; import org.eclipse.gmf.runtime.notation.View; public class CompartmentEditPolicy extends org.eclipse.gef.editpolicies.FlowLayoutEditPolicy { private EStructuralFeature feature = null; protected Command createAddCommand(EditPart child, EditPart after) { int index = getHost().getChildren().indexOf(after); TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()).getEditingDomain(); AddCommand command = new AddCommand(editingDomain, new EObjectAdapter((View)getHost().getModel()), new EObjectAdapter((View)child.getModel()), index); return new ICommandProxy(command); } protected EditPolicy createChildEditPolicy(EditPart child) { ResizableEditPolicyEx policy = new ResizableEditPolicyEx(); policy.setResizeDirections(0); return policy; } protected Command createMoveChildCommand(EditPart child, EditPart after) { int newIndex; int displacement; int childIndex = getHost().getChildren().indexOf(child); int afterIndex = getHost().getChildren().indexOf(after); if(afterIndex == -1) { newIndex = getHost().getChildren().size()-1; displacement = newIndex - childIndex; } else { newIndex = afterIndex; displacement = afterIndex - childIndex; if (childIndex <= afterIndex) { newIndex--; displacement--; } } TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()).getEditingDomain(); RepositionEObjectCommand command = new CompartmentRepositionEObjectCommand(child, editingDomain, "", (EList)((View)child.getParent().getModel()).getElement().eGet(feature), ((View)child.getModel()).getElement(), displacement, newIndex) { public CommandResult doExecuteWithResult( IProgressMonitor progressMonitor, IAdaptable info) { // remove target feedback after dropping eraseLayoutTargetFeedback(null); return super.doExecuteWithResult(progressMonitor, info); } }; return new ICommandProxy(command); } protected Command getCreateCommand(CreateRequest request) { return null; } protected Command getDeleteDependantCommand(Request request) { return null; } protected Command getOrphanChildrenCommand(Request request) { return null; } /** * @param feature has to be an EList */ public CompartmentEditPolicy(EStructuralFeature feature) { super(); this.feature = feature; } }
Recipe: HowTo add children in a GMF compartment at a specific position
Problem:
You have created a node class which can contain other nodes. E.g. a class bookshelf that contains objects of the class book. Therefore you created a compartment. Now you want to add a book to the bookshelf at a specific position and not always at the end.
Solution:
In the xxxCompartmentEditPart class rewrite the createFigure() method:
public IFigure createFigure() { ResizableCompartmentFigure rcf = (ResizableCompartmentFigure) super.createFigure(); FlowLayout layout = new FlowLayout(); layout.setMajorSpacing(getMapMode().DPtoLP(5)); layout.setMinorSpacing(getMapMode().DPtoLP(5)); layout.setHorizontal(false); rcf.getContentPane().setLayoutManager(layout); rcf.setTitleVisibility(false); return rcf; }
In the createDefaultEditPolicies() method of the xxxCompartmentEditPart class change the following EditPolicy:
- change installEditPolicy(EditPolicyRoles.CREATION_ROLE, new CreationEditPolicy()); + to installEditPolicy(EditPolicyRoles.CREATION_ROLE, new CompartmentChildCreationEditPolicy());
and add the CompartmentChildCreateCommand and CompartmentChildCreationEditPolicy classes:
package org.diagram.edit.commands; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gmf.runtime.common.core.command.CommandResult; import org.eclipse.gmf.runtime.diagram.core.services.ViewService; import org.eclipse.gmf.runtime.diagram.ui.commands.CreateCommand; import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest.ViewDescriptor; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.jface.util.Assert; public class CompartmentChildCreateCommand extends CreateCommand { int index; public CompartmentChildCreateCommand (TransactionalEditingDomain editingDomain, ViewDescriptor viewDescriptor, View containerView, int index) { super(editingDomain, viewDescriptor, containerView); this.index = index; } @Override protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { View view = ViewService.getInstance().createView( viewDescriptor.getViewKind(), viewDescriptor.getElementAdapter(), containerView, viewDescriptor.getSemanticHint(), index, viewDescriptor.isPersisted(), viewDescriptor.getPreferencesHint()); Assert.isNotNull(view, "failed to create a view"); //$NON-NLS-1$ viewDescriptor.setView(view); return CommandResult.newOKCommandResult(viewDescriptor); } }
package org.diagram.edit.policies; import java.util.Iterator; import java.util.List; import org.diagram.edit.commands.CompartmentChildCreateCommand; import org.eclipse.draw2d.FlowLayout; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.draw2d.geometry.Transposer; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gef.EditPart; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.gef.Request; import org.eclipse.gef.commands.Command; import org.eclipse.gef.requests.DropRequest; import org.eclipse.gmf.runtime.diagram.ui.commands.CreateCommand; import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editpolicies.CreationEditPolicy; import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramUIMessages; import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest; import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand; import org.eclipse.gmf.runtime.notation.View; public class CompartmentChildCreationEditPolicy extends CreationEditPolicy { @Override protected Command getCreateCommand(CreateViewRequest request) { TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()) .getEditingDomain(); CompositeTransactionalCommand cc = new CompositeTransactionalCommand( editingDomain, DiagramUIMessages.AddCommand_Label); Iterator descriptors = request.getViewDescriptors().iterator(); while (descriptors.hasNext()) { CreateViewRequest.ViewDescriptor descriptor = (CreateViewRequest.ViewDescriptor)descriptors.next(); CreateCommand createCommand = new CompartmentChildCreateCommand(editingDomain, descriptor, (View)(getHost().getModel()), getFeedbackIndexFor(request)); cc.compose(createCommand); } return new ICommandProxy(cc.reduce()); } protected int getFeedbackIndexFor(Request request) { List children = getHost().getChildren(); if (children.isEmpty()) return -1; Transposer transposer = new Transposer(); transposer.setEnabled (!isHorizontal()); Point p = transposer.t(getLocationFromRequest(request)); // Current row bottom, initialize to above the top. int rowBottom = Integer.MIN_VALUE; int candidate = -1; for (int i = 0; i < children.size(); i++) { EditPart child = (EditPart) children.get(i); Rectangle rect = transposer.t(getAbsoluteBounds(((GraphicalEditPart)child))); if (rect.y > rowBottom) { /* * We are in a new row, so if we don't have a candidate but yet are within the * previous row, then the current entry becomes the candidate. This is because * we know we must be to the right of center of the last Figure in the * previous row, so this Figure (which is at the start of a new row) is the * candidate. */ if (p.y <= rowBottom) { if (candidate == -1) candidate = i; break; } else candidate = -1; // Mouse's Y is outside the row, so reset the candidate } rowBottom = Math.max(rowBottom, rect.bottom()); if (candidate == -1) { /* * See if we have a possible candidate. It is a candidate if the cursor is * left of the center of this candidate. */ if (p.x <= rect.x + (rect.width / 2)) candidate = i; } if (candidate != -1) { // We have a candidate, see if the rowBottom has grown to include the mouse Y. if (p.y <= rowBottom) { /* * Now we have determined that the cursor.Y is above the bottom of the * current row of figures. Stop now, to prevent the next row from being * searched */ break; } } } return candidate; } protected boolean isHorizontal() { IFigure figure = ((GraphicalEditPart)getHost()).getContentPane(); return ((FlowLayout)figure.getLayoutManager()).isHorizontal(); } private Point getLocationFromRequest(Request request) { return ((DropRequest)request).getLocation(); } private Rectangle getAbsoluteBounds(GraphicalEditPart ep) { Rectangle bounds = ep.getFigure().getBounds().getCopy(); ep.getFigure().translateToAbsolute(bounds); return bounds; } }