/*******************************************************************************
* 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.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import org.eclipse.bpel.common.ui.CommonUIPlugin;
import org.eclipse.bpel.common.ui.ImageUtils;
import org.eclipse.bpel.common.ui.markers.IModelMarkerConstants;
import org.eclipse.bpel.common.ui.markers.ModelMarkerUtil;
import org.eclipse.bpel.model.Activity;
import org.eclipse.bpel.model.Link;
import org.eclipse.bpel.model.Source;
import org.eclipse.bpel.model.Target;
import org.eclipse.bpel.ui.BPELUIPlugin;
import org.eclipse.bpel.ui.IBPELUIConstants;
import org.eclipse.bpel.ui.adapters.ILabeledElement;
import org.eclipse.bpel.ui.adapters.IMarkerHolder;
import org.eclipse.bpel.ui.editparts.policies.LinkConnectionEditPolicy;
import org.eclipse.bpel.ui.editparts.util.OverlayCompositeImageDescriptor;
import org.eclipse.bpel.ui.figures.BPELPolylineConnection;
import org.eclipse.bpel.ui.figures.ManhattanConnectionRouterEx;
import org.eclipse.bpel.ui.util.BPELUtil;
import org.eclipse.bpel.ui.util.FlowLinkUtil;
import org.eclipse.bpel.ui.util.ModelHelper;
import org.eclipse.bpel.ui.util.MultiObjectAdapter;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.draw2d.Connection;
import org.eclipse.draw2d.ConnectionLocator;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.ManhattanConnectionRouter;
import org.eclipse.draw2d.graph.CompoundDirectedGraph;
import org.eclipse.draw2d.graph.Edge;
import org.eclipse.draw2d.graph.Node;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.AccessibleEditPart;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
import org.eclipse.gef.editpolicies.ConnectionEndpointEditPolicy;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.accessibility.AccessibleControlEvent;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
public class LinkEditPart extends AbstractConnectionEditPart {
private IFigure layer;
private MultiObjectAdapter adapter;
private Image decorationImage;
private IFigure decoration;
private Image topLeft, topRight, bottomLeft, bottomRight, arrowDown, arrowRight;
protected AccessibleEditPart acc;
public LinkEditPart() {
adapter = new MultiObjectAdapter() {
@Override
public void notify(Notification n) {
// TODO: check if we care about this notification
if (isActive()) handleModelChanged();
refreshAdapters();
}
};
}
protected void addAllAdapters() {
Link link = getLink();
adapter.addToObject(link);
if (link.eContainer() != null) {
// Links object
adapter.addToObject(link.eContainer());
}
if (link.getSources().size() > 0) {
Source source = link.getSources().get(0);
if (source != null) {
adapter.addToObject(source);
Activity sourceActivity = source.getActivity();
if (sourceActivity != null) {
adapter.addToObject(sourceActivity);
EObject sourceParent = sourceActivity.eContainer();
if (sourceParent != null) {
adapter.addToObject(sourceParent);
}
}
}
}
if (link.getTargets().size() > 0) {
Target target = link.getTargets().get(0);
if (target != null) {
adapter.addToObject(target);
Activity targetActivity = target.getActivity();
if (targetActivity != null) {
adapter.addToObject(targetActivity);
EObject targetParent = targetActivity.eContainer();
if (targetParent != null) {
adapter.addToObject(targetParent);
}
}
}
}
}
protected void removeAllAdapters() {
adapter.removeFromAll();
}
protected void refreshAdapters() {
removeAllAdapters();
addAllAdapters();
}
/**
* Overriden to change to connection router. That's needed cause ManhattanConnectionRouter
* produces bad routing in case of horizontal layout
*/
@Override
public void refresh() {
super.refresh();
applyConnectionRouter(getConnectionFigure());
}
/**
* 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() {
// refresh connections on the source edit part!
if (isActive()) {
// Link link = (Link)getModel();
// EObject sourceActivity = FlowLinkUtil.getLinkSource(link);
// if (sourceActivity != null) {
// Object editPart = getViewer().getEditPartRegistry().get(sourceActivity);
// if (editPart instanceof ActivityEditPart) {
// ((ActivityEditPart)editPart).refresh();
// }
// }
// EObject targetActivity = FlowLinkUtil.getLinkTarget(link);
// if (targetActivity != null) {
// Object editPart = getViewer().getEditPartRegistry().get(targetActivity);
// if (editPart instanceof ActivityEditPart) {
// ((ActivityEditPart)editPart).refresh();
// }
// }
// If property name is children, refresh children.
// If property name is size or location, refresh visuals.
refreshVisuals();
}
}
@Override
protected IFigure createFigure() {
if (getLink() == null) return null;
BPELUIPlugin plugin = BPELUIPlugin.INSTANCE;
topLeft = plugin.getImage(IBPELUIConstants.ICON_LINK_TOPLEFT);
topRight = plugin.getImage(IBPELUIConstants.ICON_LINK_TOPRIGHT);
bottomLeft = plugin.getImage(IBPELUIConstants.ICON_LINK_BOTTOMLEFT);
bottomRight = plugin.getImage(IBPELUIConstants.ICON_LINK_BOTTOMRIGHT);
arrowDown = plugin.getImage(IBPELUIConstants.ICON_LINK_ARROWDOWN);
arrowRight = plugin.getImage(IBPELUIConstants.ICON_LINK_ARROWRIGHT);
BPELPolylineConnection c = new BPELPolylineConnection(topLeft, topRight, bottomLeft, bottomRight, arrowDown, arrowRight);
applyConnectionRouter(c);
return c;
}
public void contributeToGraph(CompoundDirectedGraph graph, Map map) {
Node source = (Node) map.get(getSource());
Node target = (Node) map.get(getTarget());
Edge e = new Edge(this, source, target);
graph.edges.add(e);
map.put(this, e);
}
@Override
public void activate() {
if (isActive()) return;
super.activate();
addAllAdapters();
}
@Override
public void deactivate() {
if (!isActive()) return;
removeAllAdapters();
super.deactivate();
}
@Override
protected void createEditPolicies() {
installEditPolicy(EditPolicy.CONNECTION_ENDPOINTS_ROLE, new ConnectionEndpointEditPolicy());
installEditPolicy(EditPolicy.CONNECTION_ROLE, new LinkConnectionEditPolicy());
}
@Override
protected void unregisterVisuals() {
if (decorationImage != null) {
decorationImage.dispose();
decorationImage = null;
}
// NOTE: arrow images came from shared image registry, don't dispose them
super.unregisterVisuals();
}
protected Link getLink() {
return (Link)getModel();
}
/**
* Override to be sure we put the figure in the right layer
* TODO: yuck..
*/
@Override
protected void activateFigure() {
this.layer = getLayer(CONNECTION_LAYER);
this.layer.add(getFigure());
}
/**
* Override to be sure we remove the figure from the right layer
*/
@Override
protected void deactivateFigure() {
this.layer.remove(getFigure());
getConnectionFigure().setSourceAnchor(null);
getConnectionFigure().setTargetAnchor(null);
}
@Override
protected void refreshVisuals() {
super.refreshVisuals();
refreshDecorations();
}
protected void refreshDecorations() {
// Refresh any decorations on this edit part
if (decoration != null) {
getFigure().remove(decoration);
decoration = null;
}
if (decorationImage != null) {
decorationImage.dispose();
decorationImage = null;
}
Link link = getLink();
if (link.eContainer() == null) {
// Yeesh, the link hasn't even been initialized yet. Return.
return;
}
IMarkerHolder markerHolder = BPELUtil.adapt(link, IMarkerHolder.class);
IMarker[] markers = markerHolder.getMarkers(link);
IMarker markerToDisplay = null;
for (int i = 0; i < markers.length; i++) {
IMarker marker = markers[i];
// If the marker is not visible, skip it.
boolean isVisible = marker.getAttribute(IModelMarkerConstants.DECORATION_MARKER_VISIBLE_ATTR, true);
if (!isVisible) continue;
if (markerToDisplay != null) {
// There was already a marker.
// Find out which one has the highest priority and display that one.
int priority = marker.getAttribute(IModelMarkerConstants.DECORATION_MARKER_PRIORITY_ATTR, Integer.MIN_VALUE);
int existingPriority = markerToDisplay.getAttribute(IModelMarkerConstants.DECORATION_MARKER_PRIORITY_ATTR, Integer.MIN_VALUE);
if (priority > existingPriority) {
markerToDisplay = marker;
}
} else {
// There was no marker already, put this one in the map.
markerToDisplay = marker;
}
}
if (markerToDisplay != null) {
Image temp = getImage(markerToDisplay);
if (temp == null) return;
ImageData background = temp.getImageData();
String uri = markerToDisplay.getAttribute(IBPELUIConstants.MARKER_OVERLAYIMAGETOPLEFT, ""); //$NON-NLS-1$
ImageData topLeft = getImageData(uri);
uri = markerToDisplay.getAttribute(IBPELUIConstants.MARKER_OVERLAYIMAGETOPRIGHT, ""); //$NON-NLS-1$
ImageData topRight = getImageData(uri);
uri = markerToDisplay.getAttribute(IBPELUIConstants.MARKER_OVERLAYIMAGEBOTTOMLEFT, ""); //$NON-NLS-1$
ImageData bottomLeft = getImageData(uri);
uri = markerToDisplay.getAttribute(IBPELUIConstants.MARKER_OVERLAYIMAGEBOTTOMRIGHT, ""); //$NON-NLS-1$
ImageData bottomRight = getImageData(uri);
OverlayCompositeImageDescriptor descriptor = new OverlayCompositeImageDescriptor(background, topLeft, topRight, bottomLeft, bottomRight);
//TODO: can we get into image registry?
Image image = descriptor.createImage();
this.decorationImage = image;
this.decoration = new Label(this.decorationImage);
getFigure().add(this.decoration, new ConnectionLocator(getConnectionFigure(), ConnectionLocator.MIDDLE));
} else {
if (hasCondition()) {
Image image = BPELUIPlugin.INSTANCE.getImage(IBPELUIConstants.ICON_LINK_CONDITIONAL);
this.decorationImage = null;
this.decoration = new Label(image);
getFigure().add(this.decoration, new ConnectionLocator(getConnectionFigure(), ConnectionLocator.MIDDLE));
}
}
}
protected boolean hasCondition() {
Link link = getLink();
List<Source> sourcesList = link.getSources();
if (!sourcesList.isEmpty()) {
Source source = sourcesList.get(0);
return source.getTransitionCondition() != null;
}
return false;
}
/**
* Get the image to be drawn for the marker's figure. This is obtained
* from an IModelMarkerContentProvider that must be implemented by the client.
* If we can't find an image using the content provider we check to see if the
* marker is a problem marker and get the correct icon for it.
*
* May be overriden by subclasses to change the image.
*
* @param marker
* @return an image representing the marker or null if none is available
*/
private Image getImage(IMarker marker) {
Image image = ModelMarkerUtil.getImage(marker);
if (image == null) {
try {
if (marker.isSubtypeOf(IMarker.PROBLEM)) {
return ImageUtils.getImage(marker);
}
} catch (CoreException e) {
CommonUIPlugin.log(e);
}
}
return image;
}
private ImageData getImageData(String uri) {
if (uri.length() == 0) return null;
URL url = null;
try {
url = new URL(uri);
} catch (MalformedURLException e) {
return null;
}
ImageDescriptor desc = ImageDescriptor.createFromURL(url);
return desc.getImageData();
}
@Override
protected AccessibleEditPart getAccessibleEditPart() {
if (acc == null) acc = createAccessible();
return acc;
}
public AccessibleEditPart createAccessible() {
final GraphicalEditPart thisPart = this;
// kind of similar but not the same as GEF's AccessibleGraphicalEditPart class
return new AccessibleGraphicalEditPart() {
@Override
public void getName(AccessibleEvent e) {
String childType = null;
String displayName = null;
ILabeledElement labeledElement =
BPELUtil.adapt(thisPart.getModel(), ILabeledElement.class);
if (labeledElement != null) {
childType = labeledElement.getTypeLabel(thisPart.getModel());
displayName = labeledElement.getLabel(thisPart.getModel());
// bug 327644
// prevent possible NPE
if (childType != null && childType.equals(displayName)) {
childType = null;
}
} else {
e.result = null;
return;
}
// return something reasonable (type followed by name if any)
// or nothing at all
StringBuffer concat = new StringBuffer();
if (childType != null && childType.length() > 0)
concat.append(childType);
if (concat.length() > 0)
concat.append(" "); //$NON-NLS-1$
if (displayName != null && displayName.length() > 0)
concat.append(displayName);
if (concat.length() > 0)
e.result = concat.toString();
else
e.result = null;
return;
}
@Override
public void getValue(AccessibleControlEvent e) {
Link link = (Link)thisPart.getModel();
Activity source = FlowLinkUtil.getLinkSource(link);
Activity target = FlowLinkUtil.getLinkTarget(link);
if (source != null && target != null) {
ILabeledElement labeledElement1 =
BPELUtil.adapt(source, ILabeledElement.class);
ILabeledElement labeledElement2 =
BPELUtil.adapt(target, ILabeledElement.class);
if (labeledElement1 != null && labeledElement2 != null) {
e.result = labeledElement1.getLabel(source) + "-" + labeledElement2.getLabel(target); //$NON-NLS-1$
}
}
}
};
}
private void applyConnectionRouter(Connection con){
EditPart conTo = getSource() == null ? getTarget() : getSource();
if(conTo != null){
if(ModelHelper.isHorizontalLayout(conTo.getModel()))
con.setConnectionRouter(new ManhattanConnectionRouterEx(ManhattanConnectionRouterEx.RIGHT, ManhattanConnectionRouterEx.LEFT));
else
con.setConnectionRouter(new ManhattanConnectionRouter());
}
}
}