/******************************************************************************* * 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.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(); } }