| /******************************************************************************* |
| * Copyright (c) 2005, 2012 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 |
| *******************************************************************************/ |
| package org.eclipse.bpel.ui.editparts; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.bpel.model.Activity; |
| import org.eclipse.bpel.model.Sequence; |
| import org.eclipse.bpel.ui.BPELUIPlugin; |
| import org.eclipse.bpel.ui.IHoverHelper; |
| import org.eclipse.bpel.ui.IHoverHelperSupport; |
| import org.eclipse.bpel.ui.adapters.AdapterNotification; |
| import org.eclipse.bpel.ui.adapters.IContainer; |
| import org.eclipse.bpel.ui.editparts.policies.BPELComponentEditPolicy; |
| import org.eclipse.bpel.ui.editparts.policies.BPELDirectEditPolicy; |
| import org.eclipse.bpel.ui.editparts.policies.BPELOrderedLayoutEditPolicy; |
| import org.eclipse.bpel.ui.extensions.BPELUIRegistry; |
| import org.eclipse.bpel.ui.figures.CenteredConnectionAnchor; |
| import org.eclipse.bpel.ui.util.BPELCellEditorLocator; |
| import org.eclipse.bpel.ui.util.BPELDirectEditManager; |
| import org.eclipse.bpel.ui.util.BPELDragEditPartsTracker; |
| import org.eclipse.bpel.ui.util.BPELUtil; |
| import org.eclipse.bpel.ui.util.ModelHelper; |
| import org.eclipse.bpel.ui.util.MultiObjectAdapter; |
| import org.eclipse.bpel.ui.util.marker.BPELEditPartMarkerDecorator; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.draw2d.ConnectionAnchor; |
| import org.eclipse.draw2d.IFigure; |
| import org.eclipse.draw2d.Label; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.draw2d.geometry.Rectangle; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.gef.AccessibleAnchorProvider; |
| import org.eclipse.gef.AccessibleEditPart; |
| import org.eclipse.gef.DragTracker; |
| import org.eclipse.gef.EditPolicy; |
| import org.eclipse.gef.Request; |
| import org.eclipse.gef.RequestConstants; |
| import org.eclipse.gef.commands.Command; |
| import org.eclipse.gef.editparts.AbstractGraphicalEditPart; |
| import org.eclipse.gef.tools.DirectEditManager; |
| import org.eclipse.jface.dialogs.IInputValidator; |
| import org.eclipse.jface.viewers.TextCellEditor; |
| |
| |
| /** |
| * The superclass of all BPEL edit parts. Provides a listener on the model |
| * which calls the handleModelChanged() method. |
| */ |
| @SuppressWarnings("nls") |
| public abstract class BPELEditPart extends AbstractGraphicalEditPart implements IHoverHelperSupport { |
| |
| /** |
| * The amount of spacing to place between child items. Subclasses |
| */ |
| public static final int SPACING = 14; |
| |
| static protected String EMPTY_STRING = ""; |
| |
| protected AccessibleEditPart acc; |
| |
| protected MultiObjectAdapter adapter; |
| |
| protected BPELEditPartMarkerDecorator.MarkerMotionListener markerMotionListener; |
| |
| // The direct edit manager handles the in-place editing of node names on the graphical canvas. |
| private DirectEditManager manager; |
| |
| // Mouse motion hover help support |
| protected int mouseLocation = 0; // 0 == no marker, 1 == top drawer, 2 == bottom drawer, 3 == marker on main figure |
| |
| /** |
| * Create a new BPELEditPart. |
| * |
| * Construct the model adapter. |
| */ |
| public BPELEditPart() { |
| adapter = new MultiObjectAdapter() { |
| |
| @Override |
| public void notify(Notification n) { |
| int eventGroup = n.getEventType() / 100; |
| if (eventGroup == AdapterNotification.NOTIFICATION_MARKERS_CHANGED_GROUP ) { |
| refreshVisuals(); |
| return ; |
| } |
| |
| |
| // TODO: check if we care about this notification |
| if (isActive()) { |
| handleModelChanged(); |
| } |
| refreshAdapters(); |
| } |
| }; |
| } |
| |
| /** |
| * Default implementation based on IContainer. Should be sufficient except in |
| * special cases (such as ProcessEditPart?). |
| */ |
| @Override |
| protected List getModelChildren() { |
| IContainer container = BPELUtil.adapt(getModel(), IContainer.class); |
| if (container != null) { |
| return container.getChildren(getModel()); |
| } |
| return super.getModelChildren(); |
| } |
| |
| protected void addAllAdapters() { |
| EObject modelObject = (EObject)getModel(); |
| adapter.addToObject(modelObject); |
| |
| // if the object has an extension, add adapter to that too |
| EObject extension = ModelHelper.getExtension(modelObject); |
| if (extension != null) adapter.addToObject(extension); |
| // if the object contains an implicit sequence, add adapter to that also |
| try { |
| Activity activity = ModelHelper.getActivity(modelObject); |
| if (activity instanceof Sequence) { |
| // TODO: perhaps we should check and make sure it's an implicit sequence! |
| // for now, don't worry about it. |
| adapter.addToObject(activity); |
| } |
| } catch (IllegalArgumentException e) { |
| // it's not a single-activity container. ignore. |
| } |
| // ..but we probably don't need an adapter on the implicit sequence... |
| } |
| |
| protected void removeAllAdapters() { |
| adapter.removeFromAll(); |
| } |
| |
| protected void refreshAdapters() { |
| removeAllAdapters(); |
| addAllAdapters(); |
| } |
| |
| /** |
| * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#activate() |
| */ |
| @Override |
| public void activate() { |
| if (isActive()) { |
| return; |
| } |
| super.activate(); |
| addAllAdapters(); |
| } |
| |
| /** |
| * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#deactivate() |
| */ |
| @Override |
| public void deactivate() { |
| if (!isActive()) { |
| return; |
| } |
| removeAllAdapters(); |
| super.deactivate(); |
| clearConnections(); |
| } |
| |
| |
| @Override |
| protected void createEditPolicies() { |
| // The COMPONENT_ROLE policy determines how an edit part is deleted. |
| installEditPolicy(EditPolicy.COMPONENT_ROLE, new BPELComponentEditPolicy()); |
| |
| // The DIRECT_EDIT_ROLE policy determines how in-place editing takes place. |
| installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE, new BPELDirectEditPolicy()); |
| } |
| |
| |
| /** |
| * The model has changed. Perform any actions necessary to ensure that the |
| * edit part, model and graphical representation are in sync. |
| * |
| * Subclasses may override but should call super. |
| */ |
| protected void handleModelChanged() { |
| // If property name is children, refresh children. |
| // If property name is size or location, refresh visuals. |
| // TODO: refresh connections in there somewhere too! |
| refreshChildren(); |
| refreshVisuals(); |
| |
| refresh(); |
| } |
| |
| /** |
| * Get an anchor at the given location for this edit part. |
| * |
| * This must be called after the figure for this edit part has been created. |
| * @param location |
| * @return |
| */ |
| public ConnectionAnchor getConnectionAnchor(int location) { |
| return new CenteredConnectionAnchor(getFigure(), location, 0); |
| } |
| |
| /** |
| * Return whether or not the edit part can execute the given request. |
| * The answer is determined by asking each edit policy and returning |
| * true if any policy can execute the request. |
| * @param request |
| * @return |
| */ |
| public boolean canExecuteRequest(Request request) { |
| EditPolicyIterator i = getEditPolicyIterator(); |
| while (i.hasNext()) { |
| Command cm= i.next().getCommand(request); |
| if (cm != null) |
| if (cm.canExecute()) |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Override to handle direct edit requests |
| */ |
| @Override |
| public void performRequest(Request request) { |
| if (request.getType() == RequestConstants.REQ_DIRECT_EDIT) { |
| performDirectEdit(); |
| } else { |
| super.performRequest(request); |
| } |
| } |
| |
| /** |
| * Return whether the receiver can perform direct edit. |
| */ |
| public boolean canPerformDirectEdit() { |
| return getLabelFigure() != null; |
| } |
| |
| /** |
| * Invoke direct edit on the receiver |
| */ |
| public void performDirectEdit() { |
| if (getLabelFigure() != null) { |
| // make sure we can execute it through |
| Command cmd = BPELDirectEditPolicy.getFinalizeCommand(this.getModel(), "blahblah"); //$NON-NLS-1$ |
| if (cmd == null || !cmd.canExecute()) |
| return; |
| |
| if (manager == null) { |
| manager = new BPELDirectEditManager(this, TextCellEditor.class, |
| new BPELCellEditorLocator(getLabelFigure()), getLabelValidator()); |
| } |
| manager.show(); |
| } |
| } |
| |
| /** |
| * Return the label that should be used for direct edit. |
| * |
| * The default implementation returns null. |
| * |
| * Subclasses should override to return the appropriate label. |
| */ |
| public Label getLabelFigure() { |
| return null; |
| } |
| |
| /** |
| * Return the text to display in the label for the edit part. |
| * |
| * The default implementation returns null. |
| * |
| * Subclasses should override to return the appropriate text. |
| */ |
| public String getLabelContent() { |
| return null; |
| } |
| |
| /** |
| * Set the text to display in the label for the edit part. |
| * |
| * The default implementation does nothing. |
| * |
| * Subclasses should override to set the label to the given string. |
| */ |
| public void setLabelContent(String str) { |
| } |
| |
| /** |
| * TODO: visibility increased (from protected) so I could move the edit |
| * policies to a separate package. In future, we should change it back. |
| */ |
| |
| @Override |
| public void refreshVisuals() { |
| super.refreshVisuals(); |
| refreshHoverHelp(); |
| } |
| |
| @Override |
| protected void refreshChildren() { |
| super.refreshChildren(); |
| |
| // Not the most logical place to refresh connections, but it |
| // needs to be refreshed after the children are refreshed |
| //TODO: May make more sense to put connections into adapter |
| // so connections are not refreshed unnecessarily |
| refreshConnections(); |
| } |
| |
| protected void refreshConnections(){ |
| EditPolicy policy = getEditPolicy(EditPolicy.LAYOUT_ROLE); |
| if (policy instanceof BPELOrderedLayoutEditPolicy){ |
| ((BPELOrderedLayoutEditPolicy)policy).refreshConnections(); |
| } |
| } |
| |
| protected void clearConnections(){ |
| EditPolicy policy = getEditPolicy(EditPolicy.LAYOUT_ROLE); |
| if (policy instanceof BPELOrderedLayoutEditPolicy){ |
| ((BPELOrderedLayoutEditPolicy)policy).clearConnections(); |
| } |
| } |
| |
| @Override |
| public Object getAdapter(Class key) { |
| if (key.isInstance(getModel())) { |
| return getModel(); |
| } |
| |
| if (key == AccessibleAnchorProvider.class) { |
| return new DefaultAccessibleAnchorProvider() { |
| private List<Point> getDefaultLocations() { |
| List<Point> list = new ArrayList<Point>(); |
| Rectangle r = getFigure().getBounds(); |
| |
| // when calculating the target in connection tools, it was targettig |
| // the object behind the figure we were interested in, so adding an addition |
| // fudge factor to -2 helps make sure we hit the right target |
| Point p = r.getTopRight().translate(-r.width / 2, r.height / 3); |
| getFigure().translateToAbsolute(p); |
| list.add(p); |
| return list; |
| } |
| /** |
| * @see AccessibleAnchorProvider#getSourceAnchorLocations() |
| */ |
| @Override |
| public List<Point> getSourceAnchorLocations() { |
| return getDefaultLocations(); |
| } |
| /** |
| * @see AccessibleAnchorProvider#getTargetAnchorLocations() |
| */ |
| @Override |
| public List<Point> getTargetAnchorLocations() { |
| return getDefaultLocations(); |
| } |
| }; |
| } |
| return super.getAdapter(key); |
| } |
| |
| public void regenerateVisuals() { |
| } |
| |
| // increase visibility! |
| @Override |
| public void refreshSourceConnections() { super.refreshSourceConnections(); } |
| @Override |
| public void refreshTargetConnections() { super.refreshTargetConnections(); } |
| |
| public void refreshHoverHelp() { |
| // Refresh the tooltip if we can find a helper. |
| try { |
| IHoverHelper helper = BPELUIRegistry.getInstance().getHoverHelper(); |
| if (helper != null) { |
| IFigure tooltip = helper.getHoverFigure((EObject)getModel()); |
| getFigure().setToolTip(tooltip); |
| } |
| } catch (CoreException e) { |
| getFigure().setToolTip(null); |
| BPELUIPlugin.log(e); |
| } |
| } |
| |
| @Override |
| protected IFigure createFigure() { |
| return null; |
| } |
| |
| @Override |
| protected AccessibleEditPart getAccessibleEditPart() { |
| if (acc == null) acc = createAccessible(); |
| return acc; |
| } |
| |
| protected AccessibleEditPart createAccessible() { |
| return BPELUtil.getAccessibleEditPart(this); |
| } |
| |
| protected BPELEditPartMarkerDecorator.MarkerMotionListener getMarkerMotionListener() { |
| return markerMotionListener = new BPELEditPartMarkerDecorator.MarkerMotionListener() { |
| public void markerEntered(IMarker marker) { |
| // refresh the hover help for this marker. |
| mouseLocation = 3; |
| refreshHoverHelp(); |
| } |
| }; |
| } |
| |
| @Override |
| public DragTracker getDragTracker(Request request) { |
| return new BPELDragEditPartsTracker(this); |
| } |
| |
| /** |
| * Returns the label validator for this part or <code>null</code> if not applicable. The |
| * default behavior is to return <code>null</code>. Subclasses may override this method. |
| */ |
| protected IInputValidator getLabelValidator() { |
| return null; |
| } |
| } |