blob: ba82e59158d5523a254661d40f6978d63b0d8b4a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 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.common.ui.markers.IModelMarkerConstants;
import org.eclipse.bpel.model.Activity;
import org.eclipse.bpel.model.CompensationHandler;
import org.eclipse.bpel.model.EventHandler;
import org.eclipse.bpel.model.FaultHandler;
import org.eclipse.bpel.model.TerminationHandler;
import org.eclipse.bpel.ui.BPELUIPlugin;
import org.eclipse.bpel.ui.IBPELUIConstants;
import org.eclipse.bpel.ui.adapters.ICompensationHandlerHolder;
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.ILabeledElement;
import org.eclipse.bpel.ui.adapters.IMarkerHolder;
import org.eclipse.bpel.ui.adapters.ITerminationHandlerHolder;
import org.eclipse.bpel.ui.editparts.borders.DrawerBorder;
import org.eclipse.bpel.ui.editparts.borders.LeafBorder;
import org.eclipse.bpel.ui.editparts.borders.ScopeBorder;
import org.eclipse.bpel.ui.editparts.figures.CollapsableContainerFigure;
import org.eclipse.bpel.ui.editparts.figures.CollapsableScopeContainerFigure;
import org.eclipse.bpel.ui.editparts.policies.BPELOrderedLayoutEditPolicy;
import org.eclipse.bpel.ui.editparts.policies.ContainerHighlightEditPolicy;
import org.eclipse.bpel.ui.figures.CenteredConnectionAnchor;
import org.eclipse.bpel.ui.util.BPELDragEditPartsTracker;
import org.eclipse.bpel.ui.util.BPELUtil;
import org.eclipse.bpel.ui.util.marker.BPELEditPartMarkerDecorator;
import org.eclipse.core.resources.IMarker;
import org.eclipse.draw2d.Border;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FlowLayout;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.LayoutManager;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.emf.ecore.EObject;
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.swt.graphics.Image;
/**
* Needs refactoring. Has the following responsibilities:
* -Knows whether or not FH/EH/CH/TH are showing
* -Marker decorator works when expanded and collapsed
* -Has a ScopeBorder which knows about FH/EH/CH/TH decorations
*/
public class ScopeEditPart extends CollapsableEditPart {
// The amount of spacing to place between child items. Subclasses
// may use this value when creating a flow layout
// TODO: Fix this magic value
public static final int SPACING = 19;
// Whether to show each of the handlers.
// TODO: Initialize these from the preferences store
private boolean showFH = false, showEH = false, showCH = false, showTH = false;
// The images for the top and bottom drawer, if any.
private Image topImage, bottomImage;
// The figure which holds contentFigure and auxilaryFigure as children
private IFigure parentFigure;
// The figure which holds fault handler, compensation handler and event handler
private IFigure auxilaryFigure;
// The figure which holds the activity
private CollapsableScopeContainerFigure contentFigure;
// The text and image labels to show when collapsed.
private Image collapsedImage;
private Label collapsedNameLabel, collapsedImageLabel;
public class ScopeOrderedLayoutEditPolicy extends BPELOrderedLayoutEditPolicy {
// return list of children to create vertical connections for.
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;
}
}
protected void createEditPolicies() {
super.createEditPolicies();
// Show the selection rectangle
installEditPolicy(EditPolicy.SELECTION_FEEDBACK_ROLE, new ContainerHighlightEditPolicy(false, true) {
protected int getDrawerInset() {
return LeafBorder.DRAWER_WIDTH;
}
protected int getNorthInset() {
return 5;
}
protected int getSouthInset() {
return 3;
}
protected int getEastInset() {
return LeafBorder.DRAWER_WIDTH;
}
protected int getWestInset() {
return LeafBorder.DRAWER_WIDTH + 2;
}
});
installEditPolicy(EditPolicy.LAYOUT_ROLE, new ScopeOrderedLayoutEditPolicy());
}
protected DrawerBorder getDrawerBorder() {
Border border = getContentPane().getBorder();
if (border instanceof DrawerBorder) return (DrawerBorder)border;
return null;
}
/**
* The label figure to return for direct editing
* TODO: Enable this
*/
public Label getLabelFigure() {
return null;
}
protected IFigure createFigure() {
// TODO: Shouldn't have to initialize labels in each subclass.
initializeLabels();
if (collapsedImage == null) {
// Create the actual figure for the collapsed edit part
ILabeledElement element = (ILabeledElement)BPELUtil.adapt(getActivity(), ILabeledElement.class);
collapsedImage = element.getSmallImage(getActivity());
}
this.collapsedImageLabel = new Label(collapsedImage);
this.collapsedNameLabel = new Label(getLabel());
// TODO: Shouldn't have to set the decorator in each subclass.
editPartMarkerDecorator = new BPELEditPartMarkerDecorator((EObject)getModel(),
new CollapsableDecorationLayout(/*collapsedImage.getBounds().width*/0));
editPartMarkerDecorator.addMarkerMotionListener(getMarkerMotionListener());
this.parentFigure = new Figure();
AlignedFlowLayout layout = new AlignedFlowLayout();
layout.setHorizontal(true);
layout.setHorizontalSpacing(0);
layout.setVerticalSpacing(0);
parentFigure.setLayoutManager(layout);
this.contentFigure = new CollapsableScopeContainerFigure(getModel(), getImage(), getLabel());
contentFigure.addMouseMotionListener(getMouseMotionListener());
contentFigure.setEditPart(this);
contentFigure.setForegroundColor(BPELUIPlugin.getPlugin().getColorRegistry().get(IBPELUIConstants.COLOR_BLACK));
parentFigure.add(contentFigure);
// Configure the border and contents based on collapsed state
if (isCollapsed()) {
configureCollapsedFigure(contentFigure);
} else {
configureExpandedFigure(contentFigure);
}
this.auxilaryFigure = new Figure();
layout = new AlignedFlowLayout();
layout.setHorizontal(true);
auxilaryFigure.setLayoutManager(layout);
parentFigure.add(auxilaryFigure);
ScopeBorder border = getScopeBorder();
border.setShowFault(getFaultHandler() != null);
border.setShowCompensation(getCompensationHandler() != null);
border.setShowTermination(getTerminationHandler() != null);
border.setShowEvent(getEventHandler() != null);
return editPartMarkerDecorator.createFigure(parentFigure);
}
protected CollapsableContainerFigure getContentFigure() {
return this.contentFigure;
}
protected void unregisterVisuals() {
super.unregisterVisuals();
this.editPartMarkerDecorator = null;
this.topImage = null;
this.bottomImage = null;
}
protected List getModelChildren() {
return getModelChildren(!isCollapsed());
}
/**
* @see org.eclipse.gef.editparts.AbstractEditPart#refreshVisuals()
*/
public void refreshVisuals() {
refreshDrawerImages();
super.refreshVisuals();
// Refresh any decorations on this edit part
editPartMarkerDecorator.refresh();
ScopeBorder border = getScopeBorder();
border.setShowFault(getFaultHandler() != null);
border.setShowCompensation(getCompensationHandler() != null);
border.setShowTermination(getTerminationHandler() != null);
border.setShowEvent(getEventHandler() != null);
// Force a repaint, as the drawer images may have changed.
getFigure().repaint();
}
/**
* Return a string which should be displayed in this node while collapsed.
*/
protected String getLabel() {
ILabeledElement element = (ILabeledElement)BPELUtil.adapt(getActivity(), ILabeledElement.class);
if (element != null) {
return element.getLabel(getActivity());
}
return null;
}
/**
* Make sure the images in the drawers are up to date. Recalculate them and
* inform the border of any changes.
*/
protected void refreshDrawerImages() {
ScopeBorder border = getScopeBorder();
if (topImage != null) {
topImage.dispose();
topImage = null;
}
if (bottomImage != null) {
bottomImage.dispose();
bottomImage = null;
}
IMarkerHolder holder = (IMarkerHolder)BPELUtil.adapt(getActivity(), IMarkerHolder.class);
IMarker[] markers = holder.getMarkers(getActivity());
int topMarkerPriority = Integer.MIN_VALUE;
int bottomMarkerPriority = Integer.MIN_VALUE;
IMarker topMarker = null;
IMarker bottomMarker = null;
for (int i = 0; i < markers.length; i++) {
IMarker marker = markers[i];
String value = marker.getAttribute(IModelMarkerConstants.DECORATION_GRAPHICAL_MARKER_ANCHOR_POINT_ATTR, ""); //$NON-NLS-1$
if (value.equals(IBPELUIConstants.MARKER_ANCHORPOINT_DRAWER_TOP)) {
if (marker.getAttribute(IModelMarkerConstants.DECORATION_MARKER_VISIBLE_ATTR, true)) {
int priority = marker.getAttribute(IModelMarkerConstants.DECORATION_MARKER_PRIORITY_ATTR, Integer.MIN_VALUE);
if (priority > topMarkerPriority) {
topMarkerPriority = priority;
topImage = BPELUtil.getImage(marker);
topMarker = marker;
}
}
} else if (value.equals(IBPELUIConstants.MARKER_ANCHORPOINT_DRAWER_BOTTOM)) {
if (marker.getAttribute(IModelMarkerConstants.DECORATION_MARKER_VISIBLE_ATTR, true)) {
int priority = marker.getAttribute(IModelMarkerConstants.DECORATION_MARKER_PRIORITY_ATTR, Integer.MIN_VALUE);
if (priority > bottomMarkerPriority) {
bottomMarkerPriority = priority;
bottomImage = BPELUtil.getImage(marker);
bottomMarker = marker;
}
}
}
}
border.setTopImage(topImage);
border.setBottomImage(bottomImage);
border.setTopMarker(topMarker);
border.setBottomMarker(bottomMarker);
}
/**
* Return a list of the model children that should be displayed.
* This includes activities (if includeActivity is true), fault handlers,
* compensation handlers and event handlers.
*/
protected List getModelChildren(boolean includeActivity) {
ArrayList children = new ArrayList();
if (includeActivity) {
// Use IContainer here for implicit sequence handling
IContainer container = (IContainer)BPELUtil.adapt(getModel(), IContainer.class);
for (Iterator it = container.getChildren(getModel()).iterator(); it.hasNext(); ) {
EObject child = (EObject)it.next();
if (child instanceof Activity) children.add(child);
}
}
if (showFH) {
FaultHandler faultHandler = this.getFaultHandler();
if (faultHandler != null) children.add(children.size(), faultHandler);
}
if (showCH) {
CompensationHandler compensationHandler = this.getCompensationHandler();
if (compensationHandler != null) children.add(children.size(), compensationHandler);
}
if (showTH) {
TerminationHandler terminationHandler = this.getTerminationHandler();
if (terminationHandler != null) children.add(children.size(), terminationHandler);
}
if (showEH) {
EventHandler eventHandler = this.getEventHandler();
if (eventHandler != null) children.add(children.size(), eventHandler);
}
return children;
}
/**
* The top inner implicit connection needs an offset of eight to compensate for
* the expansion icon. All other connections are centered on the contentFigure
* with an offset of 0.
*/
public ConnectionAnchor getConnectionAnchor(int location) {
if (location == CenteredConnectionAnchor.TOP_INNER) {
return new CenteredConnectionAnchor(contentFigure, location, 8);
}
return new CenteredConnectionAnchor(contentFigure, location, 0);
}
/**
* Override addChildVisual so that it adds the childEditPart to the correct
* figure. FH/EH/CH go in a different figure than the activity does.
*/
protected void addChildVisual(EditPart childEditPart, int index) {
IFigure child = ((GraphicalEditPart)childEditPart).getFigure();
IFigure content = getContentPane(childEditPart);
if (content != null) {
if (childEditPart instanceof ActivityEditPart) {
content.add(child, index);
} else {
content.add(child);
}
}
}
/**
* Override removeChildVisual so that it removes the childEditPart from
* the correct figure. FH/EH/CH live in a different figure than the
* activity does.
*/
protected void removeChildVisual(EditPart childEditPart) {
IFigure child = ((GraphicalEditPart)childEditPart).getFigure();
getContentPane(childEditPart).remove(child);
}
/**
* Also overridden to call getContentPane(child) in the appropriate place.
*/
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);
}
/**
* Yet Another Overridden Method.
*/
public void setLayoutConstraint(EditPart child, IFigure childFigure, Object constraint) {
getContentPane(child).setConstraint(childFigure, constraint);
}
/**
* This method hopefully shouldn't be called, in favour of getContentPane(EditPart).
*/
public IFigure getContentPane() {
return contentFigure;
}
/**
* Return the appropriate content pane into which the given child
* should be inserted. For faultHandler, compensationHandler and
* eventHandler, the answer is auxilaryFigure; for activities it
* is the contentFigure.
*/
protected IFigure getContentPane(EditPart childEditPart) {
Object model = childEditPart.getModel();
if (model instanceof FaultHandler) {
return auxilaryFigure;
} else if (model instanceof CompensationHandler) {
return auxilaryFigure;
} else if (model instanceof TerminationHandler) {
return auxilaryFigure;
} else if (model instanceof EventHandler) {
return auxilaryFigure;
} else if (model instanceof Activity) {
return contentFigure;
}
return contentFigure;
}
// Support for collapsability
public DragTracker getDragTracker(Request request) {
return new BPELDragEditPartsTracker(this) {
protected boolean handleDoubleClick(int button) {
//if (isCollapsed()) setCollapsed(false);
setCollapsed(!isCollapsed());
return true;
}
protected boolean handleButtonDown(int button) {
Point point = getLocation();
ScopeBorder border = getScopeBorder();
if (border.isPointInFaultImage(point.x, point.y)) {
setShowFaultHandler(!showFH);
return true;
}
if (border.isPointInCompensationImage(point.x, point.y)) {
setShowCompensationHandler(!showCH);
return true;
}
if (border.isPointInTerminationImage(point.x, point.y)) {
setShowTerminationHandler(!showTH);
return true;
}
if (border.isPointInEventImage(point.x, point.y)) {
setShowEventHandler(!showEH);
return true;
}
if (isPointInCollapseIcon(getLocation())) {
setCollapsed(!isCollapsed());
return true;
}
return super.handleButtonDown(button);
}
};
}
protected boolean isPointInCollapseIcon(Point point) {
return getContentFigure().isPointInCollapseImage(point.x, point.y);
}
public boolean isCollapsed() {
return getContentFigure().isCollapsed();
}
public void setCollapsed(boolean collapsed) {
if (isCollapsed() == collapsed) return;
getContentFigure().setCollapsed(collapsed);
IFigure figure = getContentPane();
if (isCollapsed()) {
// First refresh children, which removes all model children's figures
refreshChildren();
// Manually remove the rest of the children
IFigure[] children = (IFigure[])figure.getChildren().toArray(new IFigure[0]);
for (int i = 0; i < children.length; i++) {
figure.remove(children[i]);
}
// Now restore the collapsed children, border and layout
configureCollapsedFigure(figure);
} else {
// Manually remove the children
IFigure[] children = (IFigure[])figure.getChildren().toArray(new IFigure[0]);
for (int i = 0; i < children.length; i++) {
figure.remove(children[i]);
}
// Now restore the expanded children, border and layout
configureExpandedFigure(figure);
refreshChildren();
}
refreshSourceConnections();
refreshTargetConnections();
// Switching collapsed states may have changed the border, which is
// responsible for drawing the drawer markers. Refresh these markers
// now.
// TODO: This isn't necessary anymore
refreshDrawerImages();
// Force a repaint, as the drawer images may have changed.
getFigure().repaint();
}
protected void configureCollapsedFigure(IFigure figure) {
figure.setLayoutManager(new FlowLayout());
figure.addMouseMotionListener(getMouseMotionListener());
figure.add(collapsedImageLabel);
figure.add(collapsedNameLabel);
}
/**
* Set the layout of the figure for expanded state.
*/
protected void configureExpandedFigure(IFigure figure) {
FlowLayout layout = new FlowLayout();
layout.setMajorAlignment(FlowLayout.ALIGN_CENTER);
layout.setMinorAlignment(FlowLayout.ALIGN_CENTER);
layout.setHorizontal(false);
layout.setMajorSpacing(SPACING);
layout.setMinorSpacing(SPACING);
figure.setLayoutManager(layout);
}
private ScopeBorder getScopeBorder() {
return (ScopeBorder)getContentPane().getBorder();
}
public void setShowFaultHandler(boolean showFaultHandler) {
this.showFH = showFaultHandler;
// Call refresh so that both refreshVisuals and refreshChildren will be called.
refresh();
}
public void setShowCompensationHandler(boolean showCompensationHandler) {
this.showCH = showCompensationHandler;
// Call refresh so that both refreshVisuals and refreshChildren will be called.
refresh();
}
public void setShowTerminationHandler(boolean showTerminationHandler) {
this.showTH = showTerminationHandler;
// 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();
}
public boolean getShowFaultHandler() {
return showFH;
}
public boolean getShowEventHandler() {
return showEH;
}
public boolean getShowCompensationHandler() {
return showCH;
}
public boolean getShowTerminationHandler() {
return showTH;
}
public FaultHandler getFaultHandler() {
IFaultHandlerHolder holder = (IFaultHandlerHolder)BPELUtil.adapt(getActivity(), IFaultHandlerHolder.class);
if (holder != null) {
return holder.getFaultHandler(getActivity());
}
return null;
}
public CompensationHandler getCompensationHandler() {
ICompensationHandlerHolder holder = (ICompensationHandlerHolder)BPELUtil.adapt(getActivity(), ICompensationHandlerHolder.class);
if (holder != null) {
return holder.getCompensationHandler(getActivity());
}
return null;
}
public TerminationHandler getTerminationHandler() {
ITerminationHandlerHolder holder = (ITerminationHandlerHolder)BPELUtil.adapt(getActivity(), ITerminationHandlerHolder.class);
if (holder != null) {
return holder.getTerminationHandler(getActivity());
}
return null;
}
public EventHandler getEventHandler() {
IEventHandlerHolder holder = (IEventHandlerHolder)BPELUtil.adapt(getActivity(), IEventHandlerHolder.class);
if (holder != null) {
return holder.getEventHandler(getActivity());
}
return null;
}
public IFigure getMainActivityFigure() {
return contentFigure;
}
}