blob: 5e2dbc496ad2fbacee512f3c8454450ffd5485f4 [file] [log] [blame]
/*******************************************************************************
* 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 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.bpel.ui.editparts;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.bpel.common.ui.layouts.AlignedFlowLayout;
import org.eclipse.bpel.model.BPELPackage;
import org.eclipse.bpel.model.EventHandler;
import org.eclipse.bpel.model.FaultHandler;
import org.eclipse.bpel.model.Process;
import org.eclipse.bpel.ui.BPELEditDomain;
import org.eclipse.bpel.ui.adapters.IContainer;
import org.eclipse.bpel.ui.adapters.IEventHandlerHolder;
import org.eclipse.bpel.ui.adapters.IFaultHandlerHolder;
import org.eclipse.bpel.ui.adapters.delegates.ActivityContainer;
import org.eclipse.bpel.ui.editparts.policies.BPELContainerEditPolicy;
import org.eclipse.bpel.ui.editparts.policies.BPELOrderedLayoutEditPolicy;
import org.eclipse.bpel.ui.figures.CenteredConnectionAnchor;
import org.eclipse.bpel.ui.figures.ILayoutAware;
import org.eclipse.bpel.ui.figures.ProcessHandlerLinker;
import org.eclipse.bpel.ui.uiextensionmodel.impl.StartNodeImpl;
import org.eclipse.bpel.ui.util.BPELUtil;
import org.eclipse.bpel.ui.util.ImplicitLinkHandlerConnectionRouter;
import org.eclipse.bpel.ui.util.ModelHelper;
import org.eclipse.draw2d.AbstractBorder;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Layer;
import org.eclipse.draw2d.LayeredPane;
import org.eclipse.draw2d.LayoutManager;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.ToolbarLayout;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.gef.DragTracker;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.gef.tools.MarqueeDragTracker;
import org.eclipse.jface.viewers.StructuredSelection;
public class ProcessEditPart extends BPELEditPart implements ILayoutAware{
private IFigure layeredPane;
private IFigure activityAndHandlerHolder;
private IFigure activityHolder;
private IFigure handlerHolder;
private Layer activityLayer;
// Whether to show each of the actual handlers.
// TODO: Initialize these from the preferences store
private boolean showFH = false, showEH = false;
// The Handler which handles the drawing of links to the handlers.
private ProcessHandlerLinker handlerLinker;
private class ProcessOrderedHorizontalLayoutEditPolicy extends ProcessEditPart.ProcessOrderedLayoutEditPolicy{
@Override
protected ArrayList createHorizontalConnections(BPELEditPart parent) {
ArrayList connections = new ArrayList();
List children = getConnectionChildren(parent);
BPELEditPart sourcePart, targetPart;
ConnectionAnchor sourceAnchor, targetAnchor;
for(int i=0; i < children.size(); i++){
if(i != children.size()-1){
sourcePart = (BPELEditPart)children.get(i);
targetPart = (BPELEditPart)children.get(i+1);
sourceAnchor = sourcePart.getConnectionAnchor(CenteredConnectionAnchor.RIGHT);
targetAnchor = targetPart.getConnectionAnchor(CenteredConnectionAnchor.LEFT);
PolylineConnection connection = createConnection(sourceAnchor,targetAnchor,arrowColor);
if(sourcePart instanceof StartNodeEditPart){
boolean horizontal = ModelHelper.isHorizontalLayout(getHost().getModel());
connection.setConnectionRouter(new ImplicitLinkHandlerConnectionRouter(horizontal));
}
connections.add(connection);
}
}
return connections;
}
}
public class ProcessOrderedLayoutEditPolicy extends BPELOrderedLayoutEditPolicy {
// return list of children to create vertical connections for.
@Override
protected List getConnectionChildren(BPELEditPart editPart) {
List originalChildren = getChildren();
List newChildren = new ArrayList();
Iterator it = originalChildren.iterator();
while (it.hasNext()) {
Object next = it.next();
if (next instanceof FaultHandlerEditPart) {
continue;
}
newChildren.add(next);
}
return newChildren;
}
@Override
protected Command getCreateCommand(CreateRequest request) {
EditPart insertBefore = getInsertionReference(request);
if (insertBefore == null) return null;
if (insertBefore instanceof StartNodeEditPart) return null;
return super.getCreateCommand(request);
}
}
@Override
protected void createEditPolicies() {
super.createEditPolicies();
// Override the component policy, as you can't delete the process
installEditPolicy(EditPolicy.COMPONENT_ROLE, null);
installEditPolicy(EditPolicy.CONTAINER_ROLE, new BPELContainerEditPolicy());
// The process must lay out its child activity
if(ModelHelper.isHorizontalLayout(getModel()))
installEditPolicy(EditPolicy.LAYOUT_ROLE, new ProcessOrderedHorizontalLayoutEditPolicy());
else
installEditPolicy(EditPolicy.LAYOUT_ROLE, new ProcessOrderedLayoutEditPolicy());
}
@Override
protected IFigure createFigure() {
LayeredPane result = new LayeredPane();
this.layeredPane = result;
Layer layer2 = new Layer();
this.activityLayer = layer2;
activityLayer.setLayoutManager(new ToolbarLayout());
activityLayer.setOpaque(true);
result.add(layer2, "activityLayer", 0); //$NON-NLS-1$
this.activityAndHandlerHolder = new Figure();
AlignedFlowLayout layout = new AlignedFlowLayout();
layout.setHorizontalAlignment(AlignedFlowLayout.ALIGN_CENTER);
layout.setVerticalAlignment(AlignedFlowLayout.ALIGN_BEGIN);
layout.setSecondaryAlignment(AlignedFlowLayout.ALIGN_CENTER);
this.activityAndHandlerHolder.setLayoutManager(layout);
this.handlerHolder = new Figure();
layout = new AlignedFlowLayout(true);
layout.setHorizontalAlignment(AlignedFlowLayout.ALIGN_BEGIN);;
this.handlerHolder.setLayoutManager(layout);
this.activityHolder = new Figure();
layout = new AlignedFlowLayout();
layout.setHorizontalAlignment(AlignedFlowLayout.ALIGN_CENTER);
layout.setVerticalAlignment(AlignedFlowLayout.ALIGN_BEGIN);
layout.setSecondaryAlignment(AlignedFlowLayout.ALIGN_CENTER);
layout.setVerticalSpacing(SPACING);
activityHolder.setLayoutManager(layout);
activityHolder.setOpaque(true);
activityAndHandlerHolder.add(handlerHolder);
activityAndHandlerHolder.add(activityHolder);
layer2.add(activityAndHandlerHolder);
// It's not a reals switch - just apply all layout setting here
// to avoid duplicate code
switchLayout(ModelHelper.isHorizontalLayout(getModel()));
return layeredPane;
}
@Override
public void setLayoutConstraint(EditPart child, IFigure childFigure, Object constraint) {
getContentPane(child).setConstraint(childFigure, constraint);
}
protected IFigure getContentPane(EditPart childEditPart) {
if (childEditPart instanceof StartNodeEditPart) {
return handlerHolder;
} else if (childEditPart instanceof FaultHandlerEditPart) {
return handlerHolder;
}
return activityHolder;
}
@Override
public IFigure getContentPane() {
return activityHolder;
}
/**
* @see org.eclipse.gef.editparts.AbstractEditPart#getModelChildren()
*/
@Override
protected List getModelChildren() {
Process process = getProcess();
BPELEditDomain domain = (BPELEditDomain)getViewer().getEditDomain();
List list = new ArrayList();
/* NOTE: The layoutEditPolicy relies on this order to identify the
* area the user is mousing over. Do not change the order in which these
* children are added unless you change the layoutEditPolicy too!!!!!!!!!!!!!!!!!!!!
*/
// TODO: this is way too magic. can we get rid of this?
list.add(domain.getStartNode());
IContainer container = new ActivityContainer(BPELPackage.eINSTANCE.getProcess_Activity());
list.addAll(container.getChildren(process));
list.add(domain.getEndNode());
/* END OF NOTE */
if (showFH) {
FaultHandler faultHandler = process.getFaultHandlers();
if (faultHandler != null) list.add(faultHandler);
}
if (showEH) {
EventHandler eventHandler = process.getEventHandlers();
if (eventHandler != null) list.add(eventHandler);
}
return list;
}
public boolean isShowFH() {
return showFH;
}
public boolean isShowEH() {
return showEH;
}
public FaultHandler getFaultHandler() {
IFaultHandlerHolder holder = BPELUtil.adapt(getModel(), IFaultHandlerHolder.class);
if (holder != null) {
return holder.getFaultHandler(getModel());
}
return null;
}
public EventHandler getEventHandler() {
IEventHandlerHolder holder = BPELUtil.adapt(getModel(), IEventHandlerHolder.class);
if (holder != null) {
return holder.getEventHandler(getModel());
}
return null;
}
protected Process getProcess() {
return (Process)getModel();
}
@Override
protected void addChildVisual(EditPart childEditPart, int index) {
IFigure child = ((GraphicalEditPart) childEditPart).getFigure();
IFigure content = getContentPane(childEditPart);
if (content != null) {
if (content == activityHolder) {
// The index includes the start node, which isn't in this
// content pane. Subtract one.
content.add(child, index - 1);
} else if(content == handlerHolder){
content.add(child, getIndexForChild(content, childEditPart));
}
}
}
/**
* Gets the index for the given <code>child</code> which should be
* inserted into the <code>container</code> afterwards. This method
* does a kind of really simple sorting.
* @param container The container where the child will be inserted.
* @param child The child to get the index for
* @return The index for inserting the child into the container
*/
private int getIndexForChild(IFigure container, EditPart child) {
int result = 0;
if(!(child.getModel() instanceof StartNodeImpl)){
int i = container.getChildren().size();
if (i <= 1 || child.getModel() instanceof FaultHandler) {
if (i > 1)
result = 2;
else
result = 1;
}else
result = 1;
}
return result;
}
@Override
protected void removeChildVisual(EditPart childEditPart) {
IFigure child = ((GraphicalEditPart) childEditPart).getFigure();
IFigure content = getContentPane(childEditPart);
if (content != null)
content.remove(child);
}
/**
* Also overridden to call getContentPane(child) in the appropriate place.
*/
@Override
protected void reorderChild(EditPart child, int index) {
// Save the constraint of the child so that it does not
// get lost during the remove and re-add.
IFigure childFigure = ((GraphicalEditPart) child).getFigure();
LayoutManager layout = getContentPane(child).getLayoutManager();
Object constraint = null;
if (layout != null)
constraint = layout.getConstraint(childFigure);
removeChildVisual(child);
List children = getChildren();
children.remove(child);
children.add(index, child);
addChildVisual(child, index);
setLayoutConstraint(child, childFigure, constraint);
}
/**
* Override to handle direct edit requests
*/
@Override
public void performRequest(Request request) {
if (request.getType() == RequestConstants.REQ_DIRECT_EDIT) {
// let's not activate the rename or direct edit functionality because it's annoying when
// the user clicks on the canvas and the rename box comes up.
// performDirectEdit();
return;
}
super.performRequest(request);
}
public void setShowFaultHandler(boolean showFaultHandler) {
this.showFH = showFaultHandler;
// Call refresh so that both refreshVisuals and refreshChildren will be called.
refresh();
}
public void setShowEventHandler(boolean showEventHandler) {
this.showEH = showEventHandler;
// Call refresh so that both refreshVisuals and refreshChildren will be called.
refresh();
}
@Override
public DragTracker getDragTracker(Request request) {
return new MarqueeDragTracker() {
@Override
protected void handleFinished() {
if (getViewer().getSelection().isEmpty()) {
// if nothing has been select we should select the process
getViewer().setSelection(new StructuredSelection(ProcessEditPart.this));
}
}
};
}
public void switchLayout(boolean horizontal) {
AlignedFlowLayout handlerLayout = (AlignedFlowLayout)handlerHolder.getLayoutManager();
handlerLayout.setHorizontal(!horizontal);
// Adjust the layout of the activityAndHandlerHolder
((AlignedFlowLayout)activityAndHandlerHolder.getLayoutManager()).setHorizontal(horizontal);
// Adjust the layout of the activityHolder
((AlignedFlowLayout)activityHolder.getLayoutManager()).setHorizontal(horizontal);
// Remove the LayoutPolicy which is responsible for creating the implicit links
removeEditPolicy(EditPolicy.LAYOUT_ROLE);
if(horizontal){
// Handler Holder layout
handlerLayout.setSecondaryAlignment(AlignedFlowLayout.ALIGN_BEGIN);
// If we are in horizontal mode we add a top margin
activityAndHandlerHolder.setBorder( new MarginBorder(20,20,0,20));
this.handlerHolder.setBorder(new MarginBorder(0,20,0,0));
installEditPolicy(EditPolicy.LAYOUT_ROLE, new ProcessOrderedHorizontalLayoutEditPolicy());
}else{
// Handler Holder layout
handlerLayout.setSecondaryAlignment(AlignedFlowLayout.ALIGN_BEGIN);
// If we are in horizontal mode we remove the border
activityAndHandlerHolder.setBorder(null);
this.handlerHolder.setBorder(new AbstractBorder() {
public Insets getInsets(IFigure arg0) {
return new Insets(20, 0, 10, 0);
}
public void paint(IFigure arg0, Graphics arg1, Insets arg2) {
}
});
installEditPolicy(EditPolicy.LAYOUT_ROLE, new ProcessOrderedLayoutEditPolicy());
}
}
@Override
protected void clearConnections() {
super.clearConnections();
getHandlerLinker().clearHandlerConnections();
}
/**
* Overridden to refresh the handlerLinks as needed.
*/
@Override
public void refresh() {
super.refresh();
getHandlerLinker().refreshHandlerLinks();
}
private ProcessHandlerLinker getHandlerLinker() {
if(handlerLinker == null)
handlerLinker = new ProcessHandlerLinker(this);
return handlerLinker;
}
@Override
protected void handleModelChanged() {
super.handleModelChanged();
this.showFH = getFaultHandler() != null ? true : false;
this.showEH = getEventHandler() != null ? true : false;
refresh();
}
}