/******************************************************************************* | |
* 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.util; | |
import java.io.IOException; | |
import java.net.MalformedURLException; | |
import java.net.URL; | |
import java.text.MessageFormat; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.Comparator; | |
import java.util.HashMap; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Vector; | |
import javax.xml.namespace.QName; | |
import org.eclipse.bpel.common.extension.model.ExtensionMap; | |
import org.eclipse.bpel.common.ui.ImageUtils; | |
import org.eclipse.bpel.common.ui.details.viewers.ComboViewer; | |
import org.eclipse.bpel.common.ui.details.widgets.DecoratedLabel; | |
import org.eclipse.bpel.common.ui.markers.ModelMarkerUtil; | |
import org.eclipse.bpel.model.BPELFactory; | |
import org.eclipse.bpel.model.BPELPackage; | |
import org.eclipse.bpel.model.Catch; | |
import org.eclipse.bpel.model.CompensateScope; | |
import org.eclipse.bpel.model.CorrelationSet; | |
import org.eclipse.bpel.model.CorrelationSets; | |
import org.eclipse.bpel.model.Flow; | |
import org.eclipse.bpel.model.ForEach; | |
import org.eclipse.bpel.model.Invoke; | |
import org.eclipse.bpel.model.OnEvent; | |
import org.eclipse.bpel.model.PartnerLink; | |
import org.eclipse.bpel.model.PartnerLinks; | |
import org.eclipse.bpel.model.Process; | |
import org.eclipse.bpel.model.Scope; | |
import org.eclipse.bpel.model.Sequence; | |
import org.eclipse.bpel.model.Variable; | |
import org.eclipse.bpel.model.Variables; | |
import org.eclipse.bpel.model.adapters.AdapterRegistry; | |
import org.eclipse.bpel.model.messageproperties.MessagepropertiesPackage; | |
import org.eclipse.bpel.model.messageproperties.PropertyAlias; | |
import org.eclipse.bpel.model.partnerlinktype.PartnerlinktypePackage; | |
import org.eclipse.bpel.model.util.BPELUtils; | |
import org.eclipse.bpel.names.NCNameWordDetector; | |
import org.eclipse.bpel.runtimes.IBPELModuleFacetConstants; | |
import org.eclipse.bpel.ui.BPELEditor; | |
import org.eclipse.bpel.ui.BPELUIPlugin; | |
import org.eclipse.bpel.ui.IBPELUIConstants; | |
import org.eclipse.bpel.ui.Messages; | |
import org.eclipse.bpel.ui.Policy; | |
import org.eclipse.bpel.ui.adapters.BPELUIAdapterFactory; | |
import org.eclipse.bpel.ui.adapters.BPELUIExtensionAdapterFactory; | |
import org.eclipse.bpel.ui.adapters.BPELUIMessagePropertiesAdapterFactory; | |
import org.eclipse.bpel.ui.adapters.BPELUIPartnerLinkTypeAdapterFactory; | |
import org.eclipse.bpel.ui.adapters.BPELUIWSDLAdapterFactory; | |
import org.eclipse.bpel.ui.adapters.BPELUIWSILAdapterFactory; | |
import org.eclipse.bpel.ui.adapters.BPELUIXSDAdapterFactory; | |
import org.eclipse.bpel.ui.adapters.IContainer; | |
import org.eclipse.bpel.ui.adapters.ILabeledElement; | |
import org.eclipse.bpel.ui.adapters.INamedElement; | |
import org.eclipse.bpel.ui.bpelactions.AbstractBPELAction; | |
import org.eclipse.bpel.ui.dialogs.NamespaceMappingDialog; | |
import org.eclipse.bpel.ui.editparts.BPELEditPart; | |
import org.eclipse.bpel.ui.editparts.FlowEditPart; | |
import org.eclipse.bpel.ui.editparts.InvokeEditPart; | |
import org.eclipse.bpel.ui.editparts.LinkEditPart; | |
import org.eclipse.bpel.ui.editparts.ScopeEditPart; | |
import org.eclipse.bpel.ui.editparts.StartNodeEditPart; | |
import org.eclipse.bpel.ui.editparts.borders.GradientBorder; | |
import org.eclipse.bpel.ui.editparts.util.OverlayCompositeImageDescriptor; | |
import org.eclipse.bpel.ui.extensions.ActionDescriptor; | |
import org.eclipse.bpel.ui.extensions.BPELUIRegistry; | |
import org.eclipse.bpel.ui.uiextensionmodel.ActivityExtension; | |
import org.eclipse.bpel.ui.uiextensionmodel.UiextensionmodelPackage; | |
import org.eclipse.bpel.validator.EmfModelQuery; | |
import org.eclipse.bpel.wsil.model.inspection.InspectionPackage; | |
import org.eclipse.core.resources.IFile; | |
import org.eclipse.core.resources.IMarker; | |
import org.eclipse.core.resources.IProject; | |
import org.eclipse.core.resources.IResource; | |
import org.eclipse.core.resources.ResourcesPlugin; | |
import org.eclipse.core.runtime.CoreException; | |
import org.eclipse.core.runtime.IPath; | |
import org.eclipse.core.runtime.IStatus; | |
import org.eclipse.core.runtime.Path; | |
import org.eclipse.draw2d.IFigure; | |
import org.eclipse.draw2d.geometry.Rectangle; | |
import org.eclipse.emf.common.notify.AdapterFactory; | |
import org.eclipse.emf.common.notify.Notification; | |
import org.eclipse.emf.common.util.BasicEList; | |
import org.eclipse.emf.common.util.EList; | |
import org.eclipse.emf.common.util.TreeIterator; | |
import org.eclipse.emf.common.util.URI; | |
import org.eclipse.emf.ecore.EClass; | |
import org.eclipse.emf.ecore.EObject; | |
import org.eclipse.emf.ecore.EPackage; | |
import org.eclipse.emf.ecore.EReference; | |
import org.eclipse.emf.ecore.EStructuralFeature; | |
import org.eclipse.emf.ecore.resource.Resource; | |
import org.eclipse.emf.ecore.resource.ResourceSet; | |
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; | |
import org.eclipse.gef.AccessibleEditPart; | |
import org.eclipse.gef.EditDomain; | |
import org.eclipse.gef.EditPart; | |
import org.eclipse.gef.EditPartViewer; | |
import org.eclipse.gef.GraphicalEditPart; | |
import org.eclipse.gef.GraphicalViewer; | |
import org.eclipse.gef.Tool; | |
import org.eclipse.jface.dialogs.IInputValidator; | |
import org.eclipse.jface.dialogs.MessageDialog; | |
import org.eclipse.jface.resource.ImageDescriptor; | |
import org.eclipse.jface.viewers.ILabelProvider; | |
import org.eclipse.jface.viewers.TableViewer; | |
import org.eclipse.jface.window.Window; | |
import org.eclipse.osgi.util.NLS; | |
import org.eclipse.swt.SWT; | |
import org.eclipse.swt.accessibility.ACC; | |
import org.eclipse.swt.accessibility.AccessibleControlEvent; | |
import org.eclipse.swt.accessibility.AccessibleEvent; | |
import org.eclipse.swt.custom.CLabel; | |
import org.eclipse.swt.events.KeyAdapter; | |
import org.eclipse.swt.events.KeyEvent; | |
import org.eclipse.swt.events.MouseEvent; | |
import org.eclipse.swt.events.MouseListener; | |
import org.eclipse.swt.events.PaintEvent; | |
import org.eclipse.swt.events.PaintListener; | |
import org.eclipse.swt.events.SelectionAdapter; | |
import org.eclipse.swt.events.SelectionEvent; | |
import org.eclipse.swt.graphics.GC; | |
import org.eclipse.swt.graphics.Image; | |
import org.eclipse.swt.graphics.ImageData; | |
import org.eclipse.swt.layout.FillLayout; | |
import org.eclipse.swt.widgets.Button; | |
import org.eclipse.swt.widgets.Composite; | |
import org.eclipse.swt.widgets.Label; | |
import org.eclipse.swt.widgets.Shell; | |
import org.eclipse.swt.widgets.Table; | |
import org.eclipse.swt.widgets.TableItem; | |
import org.eclipse.swt.widgets.Widget; | |
import org.eclipse.ui.PartInitException; | |
import org.eclipse.ui.ide.IDE; | |
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetWidgetFactory; | |
import org.eclipse.wst.common.componentcore.ComponentCore; | |
import org.eclipse.wst.common.componentcore.ModuleCoreNature; | |
import org.eclipse.wst.common.componentcore.resources.IVirtualComponent; | |
import org.eclipse.wst.common.project.facet.core.IFacetedProject; | |
import org.eclipse.wst.common.project.facet.core.IProjectFacet; | |
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; | |
import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager; | |
import org.eclipse.wst.wsdl.Definition; | |
import org.eclipse.wst.wsdl.Fault; | |
import org.eclipse.wst.wsdl.Input; | |
import org.eclipse.wst.wsdl.Message; | |
import org.eclipse.wst.wsdl.Operation; | |
import org.eclipse.wst.wsdl.Output; | |
import org.eclipse.wst.wsdl.PortType; | |
import org.eclipse.wst.wsdl.WSDLPackage; | |
import org.eclipse.wst.wsdl.util.WSDLResourceImpl; | |
import org.eclipse.xsd.XSDAttributeDeclaration; | |
import org.eclipse.xsd.XSDElementDeclaration; | |
import org.eclipse.xsd.XSDPackage; | |
/** | |
* BPELUtil is a place to put *static* helper methods for the BPEL editor. | |
* | |
* Note that helpers which have specifically to do with accessing model objects are | |
* usually found in the ModelHelper class. | |
*/ | |
public class BPELUtil { | |
private static final Variable[] EMPTY_VARIABLE_ARRAY = new Variable[0]; | |
private static final PartnerLink[] EMPTY_PARTNERLINK_ARRAY = new PartnerLink[0]; | |
private static final CorrelationSet[] EMPTY_CORRELATIONSET_ARRAY = new CorrelationSet[0]; | |
/** | |
* This global variable stores the path of the last WSDL file selected with | |
* a WorkbenchFileSelectionDialog. | |
*/ | |
public static IPath lastWSDLFilePath = null; | |
/** | |
* Global variable storing the path of the last BPEL file selected | |
*/ | |
public static IPath lastBPELFilePath = null; | |
/** | |
* Global variable storing the path of the last XSD file selected | |
*/ | |
public static IPath lastXSDFilePath; | |
static { | |
AdapterRegistry.INSTANCE.registerAdapterFactory( | |
BPELPackage.eINSTANCE, BPELUIAdapterFactory.getInstance()); | |
AdapterRegistry.INSTANCE.registerAdapterFactory( | |
WSDLPackage.eINSTANCE, BPELUIWSDLAdapterFactory.getInstance()); | |
AdapterRegistry.INSTANCE.registerAdapterFactory( | |
PartnerlinktypePackage.eINSTANCE, BPELUIPartnerLinkTypeAdapterFactory.getInstance()); | |
AdapterRegistry.INSTANCE.registerAdapterFactory( | |
XSDPackage.eINSTANCE, BPELUIXSDAdapterFactory.getInstance()); | |
AdapterRegistry.INSTANCE.registerAdapterFactory( | |
MessagepropertiesPackage.eINSTANCE, BPELUIMessagePropertiesAdapterFactory.getInstance()); | |
AdapterRegistry.INSTANCE.registerAdapterFactory( | |
UiextensionmodelPackage.eINSTANCE, BPELUIExtensionAdapterFactory.getInstance()); | |
AdapterRegistry.INSTANCE.registerAdapterFactory( | |
InspectionPackage.eINSTANCE, BPELUIWSILAdapterFactory.getInstance() ); | |
} | |
/** | |
* Register adapter factory for the given EClass. | |
* | |
* @param key | |
* @param factory | |
*/ | |
public static void registerAdapterFactory(EClass key, AdapterFactory factory) { | |
AdapterRegistry.INSTANCE.registerAdapterFactory(key,factory); | |
} | |
public static void registerAdapterFactory(EPackage key, AdapterFactory factory) { | |
AdapterRegistry.INSTANCE.registerAdapterFactory(key, factory); | |
} | |
static Class<?> adapterInterface ( Object type ) { | |
if (type instanceof Class) { | |
return (Class) type; | |
} | |
if (type instanceof String) { | |
try { | |
return Class.forName((String)type); | |
} catch (ClassNotFoundException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
throw new RuntimeException("Adapter type " + type + " is not understood."); //$NON-NLS-1$ //$NON-NLS-2$ | |
} | |
/** | |
* @param <T> | |
* @param target | |
* @param clazz | |
* @return the adapted interface or object | |
*/ | |
public static <T extends Object> T adapt ( Object target, Class<T> clazz) { | |
return AdapterRegistry.INSTANCE.adapt(target, clazz); | |
} | |
/** | |
* This method tries the registered adapter factories one by one, returning | |
* the first non-null result it gets. If none of the factories can adapt | |
* the result, it returns null. | |
* @param target target object | |
* @param type type of the adapter to find | |
* @return the adapter for the target. | |
*/ | |
public static Object adapt (Object target, Object type) { | |
return AdapterRegistry.INSTANCE.adapt(target, type); | |
} | |
/** | |
* Create an adapter for the given target of the given type. | |
* In addition, pass a context object to the adapter(s) of the target. | |
* | |
* The idea is that some adapters can be stateful and depend not only | |
* on the objects that they wrap, but also on some other context that is needed | |
* to completely and correctly implement the interface for which the adaptor is | |
* needed. | |
* | |
* Adapters that are stateless, should ignore any notifications sent to them. | |
* | |
* @param target the target object | |
* @param type the type it wants to adapt to | |
* @param context the context object | |
* | |
* @return the adapter | |
*/ | |
public static Object adapt (Object target, Object type, Object context) { | |
return AdapterRegistry.INSTANCE.adapt(target, type,context); | |
} | |
/** | |
* Returns the effective EClass for a custom activity (action). | |
*/ | |
public static EClass getEClassFor(Object target) { | |
if (target instanceof Invoke) { | |
ActionDescriptor[] descriptors = BPELUIRegistry.getInstance().getActionDescriptors(); | |
for( ActionDescriptor descriptor : descriptors ) { | |
AbstractBPELAction action = descriptor.getAction(); | |
if (action.isInstanceOf(target)) { | |
return action.getModelType(); | |
} | |
} | |
} | |
if (!(target instanceof EObject)) { | |
return null; | |
} | |
return ((EObject)target).eClass(); | |
} | |
public static boolean isCustomActivity(Object target) { | |
if (target instanceof Invoke) { | |
ActionDescriptor[] descriptors = BPELUIRegistry.getInstance().getActionDescriptors(); | |
for( ActionDescriptor descriptor : descriptors ) { | |
AbstractBPELAction action = descriptor.getAction(); | |
if (action.getModelType() == BPELPackage.eINSTANCE.getInvoke()) continue; | |
if (action.isInstanceOf(target)) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
public static boolean isBPELAction(EClass target) { | |
ActionDescriptor[] descriptors = BPELUIRegistry.getInstance().getActionDescriptors(); | |
for( ActionDescriptor descriptor : descriptors ) { | |
AbstractBPELAction action = descriptor.getAction(); | |
if (action.getModelType() == target) { | |
return true; | |
} | |
} | |
return false; | |
} | |
/** | |
* Creates a new instance of clazz using the EFactory of the EPackage clazz belongs to. | |
*/ | |
public static EObject createEObject(EClass clazz) { | |
return clazz.getEPackage().getEFactoryInstance().create(clazz); | |
} | |
// This is a hack to bundle the result of a cloneSubtree with enough state to undo/redo | |
// the extension map changes it caused. | |
public static class CloneResult { | |
/** The result of the clone */ | |
public EObject targetRoot; | |
Map<EObject,EObject> targetMap; | |
Map<EObject,EObject> targetMapAdditions = new HashMap<EObject,EObject>(); | |
/** | |
* Undo ... ? | |
*/ | |
public void undo() { | |
for (EObject next : this.targetMapAdditions.keySet()) { | |
this.targetMap.remove(next); | |
} | |
} | |
/** | |
* Redo ... ? | |
*/ | |
public void redo() { | |
for (EObject key : this.targetMapAdditions.keySet()) { | |
this.targetMap.put(key, this.targetMapAdditions.get(key)); | |
} | |
} | |
} | |
// This helper is used by the cloneSubtree() method. | |
protected static void cloneSubtreeHelper (EObject source, Map<EObject,EObject> sourceMap, Map<EObject,EObject> targetMap, | |
Map<EObject,EObject> copyMap, CloneResult result) | |
{ | |
EObject targetObject = createEObject(source.eClass()); | |
copyMap.put(source, targetObject); | |
if (sourceMap != null && sourceMap.containsKey(source)) { | |
EObject sourceExtension = sourceMap.get(source); | |
EObject targetExtension = createEObject(sourceExtension.eClass()); | |
copyMap.put(sourceExtension, targetExtension); | |
for (TreeIterator<?> it2 = sourceExtension.eAllContents(); it2.hasNext(); ) { | |
EObject source2 = (EObject)it2.next(); | |
EObject target2 = createEObject(source2.eClass()); | |
copyMap.put(source2, target2); | |
} | |
targetMap.put(targetObject, targetExtension); | |
result.targetMapAdditions.put(targetObject, targetExtension); | |
} | |
} | |
/** | |
* Clones an EObject and all EObjects contained directly or indirectly within it. All | |
* cloned objects possessing an extension in the sourceMap will also have their extensions | |
* cloned into the targetMap. Containment references and other references to any of the | |
* cloned object(s) will be fixed up to point into the target objects. Any references to | |
* non-cloned objects will be copied as-is in the cloned objects. | |
* | |
* NOTE: This method relies on BPELUtil.createEObject() knowing how to create new instances | |
* of the EClasses of all copied objects (i.e. objectFactories must contain the necessary | |
* EFactory instances for everything copied by this method). | |
* | |
* @param source The root of the source subtree to clone. | |
* @param sourceMap The extension map containing source extensions of cloned objects. | |
* @param targetMap The extension map in which cloned extensions should be recorded. | |
* @return a CloneResult containing the root of the target subtree, which can be used | |
* for undo/redo. | |
*/ | |
@SuppressWarnings("nls") | |
public static CloneResult cloneSubtree (EObject source, Map<EObject,EObject> sourceMap, Map<EObject,EObject> targetMap) { | |
HashMap<EObject,EObject> copyMap = new HashMap<EObject,EObject>(); | |
CloneResult result = new CloneResult(); | |
result.targetMap = targetMap; | |
// (1) Create target objects for each EObject in the containment subtree of source. | |
// If the source object has an extension in sourceMap, create copies of the extension | |
// and its containment tree as well. | |
// NOTE: we can NOT just recursively call cloneSubtree for the extension, it wouldn't | |
// work with fixing up references. We have to iterate its eAllContents also here. | |
cloneSubtreeHelper(source, sourceMap, targetMap, copyMap, result); | |
for (TreeIterator<?> it = source.eAllContents(); it.hasNext(); ) { | |
EObject sourceObject = (EObject)it.next(); | |
cloneSubtreeHelper(sourceObject, sourceMap, targetMap, copyMap, result); | |
} | |
// (2) Copy the features from each cloned source object to the corresponding target | |
// object. As we copy, we replace any references to cloned source objects with | |
// references to the corresponding target objects--but references to non-cloned | |
// objects are copied as-is. | |
for (Map.Entry<EObject,EObject> entry : copyMap.entrySet() ) { | |
EObject sourceObject = entry.getKey(); | |
EObject targetObject = entry.getValue(); | |
if (sourceObject.eClass() != targetObject.eClass()) { | |
throw new IllegalStateException("Source and target objects are not of the same class after cloning."); | |
} | |
if (Policy.DEBUG) { | |
System.out.println("copying a "+sourceObject.eClass().getName()); //$NON-NLS-1$ | |
} | |
for ( EStructuralFeature feature : sourceObject.eClass().getEAllStructuralFeatures()) { | |
// special cases first. | |
if (!feature.isChangeable()) { | |
if (Policy.DEBUG) System.out.println(" *** skipping unchangeable feature "+feature); //$NON-NLS-1$ | |
continue; | |
} | |
if (feature.isUnsettable() && !targetObject.eIsSet(feature)) { | |
if (Policy.DEBUG) System.out.println(" unsetting feature "+feature.getName()); //$NON-NLS-1$ | |
targetObject.eUnset(feature); | |
continue; | |
} | |
Object value = sourceObject.eGet(feature); | |
boolean treatAsReference = (feature instanceof EReference); | |
if (treatAsReference) { | |
if (feature.isMany()) { | |
// list of references. | |
EList<Object> newValues = new BasicEList<Object>(); | |
if (Policy.DEBUG) System.out.println(" copying multi-reference feature "+feature.getName()+":"); //$NON-NLS-1$ //$NON-NLS-2$ | |
for (Iterator<?> it3 = ((Collection)value).iterator(); it3.hasNext(); ) { | |
Object oldValue = it3.next(); | |
Object newValue = (oldValue==null ? null : copyMap.get(oldValue)); | |
if (newValue == null) { | |
newValue = oldValue; | |
} | |
if (Policy.DEBUG) System.out.println("+ (oldValue="+oldValue+" newValue="+newValue+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
newValues.add(newValue); | |
} | |
targetObject.eSet(feature, newValues); | |
} else { | |
// single reference. | |
Object newValue = (value==null? null : copyMap.get(value)); | |
if (newValue == null) { | |
newValue = value; | |
} | |
if (Policy.DEBUG) System.out.println(" copying reference feature "+feature.getName() //$NON-NLS-1$ | |
+" (value="+value+" newValue="+newValue+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
targetObject.eSet(feature, newValue); | |
} | |
} else { | |
/** In case of a DOM Node and the "element" feature, we simply clone the result */ | |
if (value instanceof org.w3c.dom.Node && "element".equals(feature.getName())) { | |
org.w3c.dom.Node e = (org.w3c.dom.Node)value; | |
value = e.cloneNode(true); | |
} | |
// non-reference attribute. just copy the value | |
if (Policy.DEBUG) System.out.println(" copying attr feature "+feature.getName()+" (value="+value+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
targetObject.eSet(feature, value); | |
} | |
} | |
} | |
result.targetRoot = copyMap.get(source); | |
return result; | |
} | |
/** | |
* Convenience formatting methods. | |
*/ | |
public static String formatString(String format, String arg1) { | |
return MessageFormat.format(format, new Object[] { arg1 }); | |
} | |
public static String formatString(String format, String arg1, String arg2) { | |
return MessageFormat.format(format, new Object[] { arg1, arg2 }); | |
} | |
/** | |
* strips out invalid characters to conform to QName specs. | |
* If the resulting name is null, returns "bpel" as a valid QName | |
* to guarantee that something valid is returned. | |
* | |
* TODO: This has to be a valid NCName ... | |
* | |
* @param str | |
* | |
* @return | |
*/ | |
public static String generateValidName(String str) { | |
StringBuilder result = new StringBuilder(""); //$NON-NLS-1$ | |
if (str != null) { | |
for(char ch : str.trim().toCharArray()) { | |
int destLength = result.length(); | |
if (((destLength == 0) && (Character.isLetter(ch) || ch == '_')) | |
|| ((destLength > 0) && Character.isJavaIdentifierPart(ch))) { | |
result.append(ch); | |
} | |
} | |
} | |
if (result.length() == 0) | |
result.append(IBPELUIConstants.EXTENSION_BPEL); | |
return result.toString(); | |
} | |
/** | |
* Helper that traverses the IContainer hierarchy of the given modelObject in depth | |
* first fashion and applies the given visitor to each node. | |
* | |
* DO NOT USE THIS for anything that must see "all" model objects (including implicit | |
* sequences, for example). Use TreeIterator modelObject.eAllContents() for that. | |
*/ | |
public static void visitModelDepthFirst(Object modelObject, IModelVisitor visitor) { | |
if (visitor.visit(modelObject)) { | |
IContainer container = BPELUtil.adapt(modelObject, IContainer.class); | |
if (container != null) { | |
for (Iterator it = container.getChildren(modelObject).iterator(); it.hasNext(); ) { | |
visitModelDepthFirst(it.next(), visitor); | |
} | |
} | |
// TODO: Make this go away | |
if (modelObject instanceof Flow) { | |
// Hack: also visit the links of a flow! | |
Flow flow = (Flow)modelObject; | |
for (Iterator it = FlowLinkUtil.getFlowLinks(flow).iterator(); it.hasNext(); ) { | |
visitModelDepthFirst(it.next(), visitor); | |
} | |
} | |
} | |
} | |
private static class NameUnusedVisitor implements IModelVisitor { | |
private boolean unused = true; | |
private final String candidateName; | |
private final Collection<EObject> ignoreObjects; | |
NameUnusedVisitor(String candidateName, Collection<EObject> ignoreObjects) { | |
this.candidateName = candidateName; | |
if (ignoreObjects == null) ignoreObjects = Collections.emptySet(); | |
this.ignoreObjects = ignoreObjects; | |
} | |
@Override | |
public boolean visit(Object child) { | |
if (!this.ignoreObjects.contains(child)) { | |
INamedElement namedElement = BPELUtil.adapt(child, INamedElement.class); | |
if (namedElement != null) { | |
String name = namedElement.getName(child); | |
if ((name != null) && (name.compareToIgnoreCase(this.candidateName) == 0)) | |
this.unused = false; | |
} | |
} | |
return true;//unused; | |
} | |
public boolean isUnused() { | |
return this.unused; | |
} | |
} | |
/** | |
* checks if a name is available for use within the given process (i.e. if this name | |
* were added within the modelRoot, would it be unique). | |
*/ | |
public static boolean isNameUnused(EObject modelRoot, String candidateName, Collection ignoreObjects) { | |
NameUnusedVisitor visitor = new NameUnusedVisitor(candidateName, ignoreObjects); | |
for (TreeIterator<EObject> it = modelRoot.eAllContents(); it.hasNext(); ) { | |
visitor.visit(it.next()); | |
if (visitor.isUnused() == false) return false; | |
} | |
return true; | |
} | |
/** | |
* return a mangled name (based on the given hint) which is unique in the given process. | |
*/ | |
public static String getUniqueModelName(EObject context, String hint, Collection ignoreObjects) { | |
return getUniqueModelName2(context, hint, ignoreObjects); | |
} | |
/** | |
* return a mangled name (based on the given hint) which is unique in the given WSDL definition. | |
*/ | |
public static String getUniqueModelName (Definition definition, String hint, Collection ignoreObjects) { | |
return getUniqueModelName2(definition, hint, ignoreObjects); | |
} | |
protected static String getUniqueModelName2 (EObject modelRoot, String hint, Collection ignoreObjects) { | |
// first try it exactly as hinted. | |
String result = BPELUtil.generateValidName((hint==null)?"":hint.trim()); //$NON-NLS-1$ | |
if (isNameUnused(modelRoot, result, ignoreObjects)) return result; | |
// go back to the first non-digit | |
int digitPos = result.length()-1; | |
while (digitPos >= 0 && Character.isDigit(result.charAt(digitPos))) digitPos--; | |
digitPos++; // move back to the digit | |
String nameWithoutNum = result.substring(0, digitPos); | |
// try increasing numbers until one is accepted. | |
for (int num = 1; ; num++) { | |
result = nameWithoutNum+String.valueOf(num); | |
if (isNameUnused(modelRoot, result, ignoreObjects)) return result; | |
} | |
} | |
public static String generateUniqueModelName (EObject context, String hint, EObject model) { | |
if (hint == null || "".equals(hint)) { //$NON-NLS-1$ | |
ILabeledElement element = BPELUtil.adapt(model, ILabeledElement.class); | |
hint = (element != null) ? element.getTypeLabel(model) : ""; //$NON-NLS-1$ | |
} | |
return BPELUtil.getUniqueModelName(context, hint, Collections.singletonList(model)); | |
} | |
public static String getFilenameFromUri(String uri) { | |
if (uri == null) return Messages.BPELUtil__unknown_URI__54; | |
// Hack. Why aren't we just using URI objects? | |
int idx = Math.max(uri.lastIndexOf("/"), uri.lastIndexOf("\\")); //$NON-NLS-1$ //$NON-NLS-2$ | |
return (idx >= 0)? uri.substring(idx+1) : uri; | |
} | |
/** | |
* Converts the first letter of the target String to upper case. | |
* @param target | |
* @return the name with the first letter uppercased. | |
*/ | |
public static String upperCaseFirstLetter (String target) { | |
if (target.length() < 1) { | |
return target; | |
} | |
StringBuilder buf = new StringBuilder (target.length()); | |
buf.append(target.substring(0, 1).toUpperCase()); | |
buf.append(target.substring(1, target.length())); | |
return buf.toString(); | |
} | |
/** | |
* Converts the first letter of the target String to lower case. | |
*/ | |
public static String lowerCaseFirstLetter(String target) { | |
if (target.length() < 1) { | |
return target; | |
} | |
StringBuffer buf = new StringBuffer(target.length()); | |
buf.append(target.substring(0, 1).toLowerCase()); | |
buf.append(target.substring(1, target.length())); | |
return buf.toString(); | |
} | |
/** | |
* Returns all of the PropertyAlias objects from WSDL files in the same ResourceSet as | |
* the resource containing messageType, which are aliases for messageType. | |
*/ | |
public static List<PropertyAlias> getPropertyAliasesForMessageType(Message messageType) { | |
List<PropertyAlias> aliases = new ArrayList<PropertyAlias>(); | |
Resource resource = messageType.eResource(); | |
if (resource == null) { | |
return aliases; | |
} | |
ResourceSet resourceSet = resource.getResourceSet(); | |
for (Iterator<Resource> it = resourceSet.getResources().iterator(); it.hasNext(); ) { | |
resource = it.next(); | |
// TODO: this is a hack. Why is there no WSDLResource interface?? | |
if (resource instanceof WSDLResourceImpl) { | |
for (TreeIterator<EObject> treeIt = resource.getAllContents(); treeIt.hasNext(); ) { | |
EObject object = treeIt.next(); | |
if (object instanceof PropertyAlias) { | |
PropertyAlias alias = (PropertyAlias)object; | |
if (messageType.equals(alias.getMessageType())) | |
aliases.add(alias); | |
} | |
} | |
} | |
} | |
return aliases; | |
} | |
// Creates an implicit sequence with a name that is unique in the editor's process. | |
// Note that an ActivityExtension is created and inserted in the extension map, | |
// but the implicit sequence itself should be inserted in the model by the caller. | |
public static Sequence createImplicitSequence (Process process, ExtensionMap extensionMap) { | |
Sequence impSeq = BPELFactory.eINSTANCE.createSequence(); | |
ModelHelper.createExtensionIfNecessary(extensionMap, impSeq); | |
Collection ignoreObjects = Collections.singletonList(impSeq); | |
if (ModelHelper.isSpecCompliant(process)) { | |
impSeq.setName(getUniqueModelName(process, Messages.BPELUtil_Sequence_1, ignoreObjects)); | |
} else { | |
impSeq.setName(getUniqueModelName(process, Messages.BPELUtil_HiddenSequence_2, ignoreObjects)); | |
((ActivityExtension)ModelHelper.getExtension(impSeq)).setImplicit(true); | |
} | |
// TODO: also give sequence a unique ID marked as implicit! | |
return impSeq; | |
} | |
public static TreeIterator nodeAndAllContents(final EObject node) { | |
final TreeIterator<EObject> allContents = node.eAllContents(); | |
return new TreeIterator() { | |
boolean didNode = false; | |
@Override | |
public void prune() { | |
// TODO: This won't work when calling on the first item. | |
if (!this.didNode) throw new IllegalStateException(); | |
allContents.prune(); | |
} | |
@Override | |
public boolean hasNext() { | |
if (this.didNode) return allContents.hasNext(); | |
return node != null; | |
} | |
@Override | |
public Object next() { | |
if (this.didNode) return allContents.next(); | |
this.didNode = true; return node; | |
} | |
@Override | |
public void remove() { | |
// This won't work when calling on the first item. | |
if (!this.didNode) throw new IllegalStateException(); | |
allContents.remove(); | |
} | |
}; | |
} | |
private static class RefreshActionVisitor implements IModelVisitor { | |
private final GraphicalViewer viewer; | |
public RefreshActionVisitor(GraphicalViewer viewer) { | |
this.viewer = viewer; | |
} | |
@Override | |
public boolean visit(Object child) { | |
EditPart ep = (EditPart) this.viewer.getEditPartRegistry().get(child); | |
if (ep != null && ep instanceof BPELEditPart) { | |
IFigure fig = ((BPELEditPart)ep).getContentPane(); | |
if (fig != null) { | |
((BPELEditPart)ep).regenerateVisuals(); | |
ep.refresh(); | |
} | |
} | |
if(ep instanceof LinkEditPart){ | |
ep.refresh(); | |
} | |
return true;//unused; | |
} | |
} | |
/** | |
* refreshes all the editparts of the process. Useful for changing layouts etc | |
*/ | |
public static void regenerateVisuals(Process process, GraphicalViewer viewer) { | |
RefreshActionVisitor visitor = new RefreshActionVisitor(viewer); | |
visitModelDepthFirst(process, visitor); | |
return; | |
} | |
/** | |
* The policy for whether a BPELEditPart's edges should be hilighted or not. This one defers | |
* to the active tool if it is an IHilightControllingTool and says no otherwise. | |
*/ | |
public static boolean shouldHilightEdges(EditDomain domain, EObject modelObject) { | |
Tool tool = domain.getActiveTool(); | |
if (tool instanceof IHilightControllingTool) { | |
return ((IHilightControllingTool)tool).hilightModelTarget(modelObject); | |
} | |
return false; | |
} | |
/** | |
* Used to determine the type of pattern to paint a container in the Process. | |
* Because the nesting of containers is confusing, we want to draw nice gradients | |
* to help the user. | |
* 1 and 3 return values mean solid fill. | |
* 0 and 2 mean gradient fills. | |
*/ | |
public static int getRepaintFillType(IFigure fig) { | |
int depth = 0; | |
IFigure parent = fig.getParent(); | |
while (parent != null) { | |
if (parent != null && parent.getBorder() != null && parent.getBorder() instanceof GradientBorder) { | |
depth++; | |
} | |
parent = parent.getParent(); | |
} | |
return depth % 4; | |
} | |
public static void sortFlowList(List<FlowEditPart> listOfFlowEditParts) { | |
List<FlowEditPart> result = listOfFlowEditParts; | |
int resultSize = result.size(); | |
for (int i = 0; i<resultSize; i++) { | |
for (int j = i+1; j<resultSize; j++) { | |
Flow flow1 = (Flow)(result.get(i)).getModel(); | |
Flow flow2 = (Flow)(result.get(j)).getModel(); | |
Flow[] parents = FlowLinkUtil.getParentFlows(flow2); | |
for( Flow parent : parents ) { | |
if (parent == flow1) { | |
// flow2 must be layed out before flow1 so its size will be known! | |
FlowEditPart temp = result.get(i); | |
result.set(i, result.get(j)); | |
result.set(j, temp); | |
} | |
} | |
} | |
} | |
} | |
/** | |
* Refresh the given ComboViewer, and also make sure selectedObject is selected in it. | |
*/ | |
public static void refreshCombo(ComboViewer viewer, Object selectedObject) { | |
viewer.refresh(); | |
String s = ((ILabelProvider)viewer.getLabelProvider()).getText(selectedObject); | |
viewer.getCombo().setText(s); | |
} | |
/** | |
* Helper method to calculate the width of a button. | |
* This is necessary for internationalization and accessibility. | |
* Returned value is the calculated width or defaultSize, whichever | |
* is larger. | |
*/ | |
public static int calculateButtonWidth(Widget widget, int defaultSize){ | |
GC gc; | |
int width = 0; | |
if (widget instanceof Button) { | |
Button w = (Button)widget; | |
gc = new GC(w); | |
gc.setFont(w.getFont()); | |
width = gc.textExtent(w.getText()).x + 17; | |
gc.dispose(); | |
return Math.max(width, defaultSize); | |
} | |
return defaultSize; | |
} | |
public static String getMaxLengthString(String strings[]) { | |
int max = -1; | |
int index = -1; | |
for (int i = 0; i < strings.length; i++) { | |
if (strings[i].length() > max) { | |
max = strings[i].length(); | |
index = i; | |
} | |
} | |
if (index >= 0) return strings[index]; | |
return ""; //$NON-NLS-1$ | |
} | |
/** | |
* Helper method to calculate the width of a CLabel. | |
* This is necessary for internationalization and accessibility. | |
* | |
* Returned value is the calculated width or defaultSize, whichever | |
* is larger. | |
*/ | |
public static int calculateLabelWidth(Widget widget, int defaultSize){ | |
GC gc; | |
int width = 0; | |
if (widget instanceof CLabel) { | |
CLabel w = (CLabel)widget; | |
gc = new GC(w); | |
gc.setFont(w.getFont()); | |
width = gc.textExtent(w.getText()).x + 17; | |
gc.dispose(); | |
return Math.max(width, defaultSize); | |
} | |
if (widget instanceof DecoratedLabel) { | |
DecoratedLabel w = (DecoratedLabel)widget; | |
gc = new GC(w); | |
gc.setFont(w.getFont()); | |
width = gc.textExtent(w.getText()).x + 17; | |
gc.dispose(); | |
return Math.max(width, defaultSize); | |
} | |
if (widget instanceof Label) { | |
Label w = (Label)widget; | |
gc = new GC(w); | |
gc.setFont(w.getFont()); | |
width = gc.textExtent(w.getText()).x + 5; | |
gc.dispose(); | |
return Math.max(width, defaultSize); | |
} | |
return defaultSize; | |
} | |
public static IFile getFileFromURI(URI uri) { | |
if (uri.isFile()) { | |
return getFileFromDeviceURI(uri); | |
} | |
return getFileFromPlatformURI(uri); | |
} | |
public static IFile getFileFromDeviceURI(URI uri) { | |
String device = uri.device(); | |
Iterator pathIt = uri.segmentsList().iterator(); | |
StringBuffer path = new StringBuffer(); | |
while (pathIt.hasNext()) { | |
path.append("/" + pathIt.next()); //$NON-NLS-1$ | |
} | |
return ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(device, path.toString())); | |
} | |
public static IFile getFileFromPlatformURI(URI uri) { | |
String [] segs = uri.segments(); | |
IPath path = null; | |
// start at 1 to skip resource | |
for (int i = 1; i< segs.length; i++) { | |
if (path == null) { | |
path = new Path(segs[i]); | |
} else { | |
path = path.append(segs[i]); | |
} | |
} | |
return ResourcesPlugin.getWorkspace().getRoot().getFile(path); | |
} | |
/** | |
* Function to return a platform URI from a standard hierarchital URI. | |
* Normally we can use URI.createPlatformURI, but that function always assumes | |
* that it is non-platform | |
*/ | |
public static URI getPlatformURI(URI uri) { | |
String str = uri.toString(); | |
if (str.startsWith("platform:")) return uri; //$NON-NLS-1$ | |
return URI.createPlatformResourceURI(uri.toString()); | |
} | |
/* external fault handler helpers */ | |
public static boolean getShowFaultHandler(EditPart part) { | |
if (part instanceof ScopeEditPart) | |
return ((ScopeEditPart)part).getShowFaultHandler(); | |
else if (part instanceof InvokeEditPart) | |
return ((InvokeEditPart)part).getShowFaultHandler(); | |
else if (part instanceof StartNodeEditPart) | |
return ((StartNodeEditPart)part).getShowFaultHandler(); | |
return false; | |
} | |
public static void setShowFaultHandler(EditPart part, boolean show) { | |
if (part instanceof ScopeEditPart) | |
((ScopeEditPart)part).setShowFaultHandler(show); | |
else if (part instanceof InvokeEditPart) | |
((InvokeEditPart)part).setShowFaultHandler(show); | |
else if (part instanceof StartNodeEditPart) | |
((StartNodeEditPart)part).setShowFaultHandler(show); | |
} | |
/* external compensation handler helpers */ | |
public static boolean getShowCompensationHandler(EditPart part) { | |
if (part instanceof ScopeEditPart) | |
return ((ScopeEditPart)part).getShowCompensationHandler(); | |
else if (part instanceof InvokeEditPart) | |
return ((InvokeEditPart)part).getShowCompensationHandler(); | |
return false; | |
} | |
public static boolean getShowTerminationHandler(EditPart part) { | |
if (part instanceof ScopeEditPart) | |
return ((ScopeEditPart)part).getShowTerminationHandler(); | |
return false; | |
} | |
public static void setShowCompensationHandler(EditPart part, boolean show) { | |
if (part instanceof ScopeEditPart) | |
((ScopeEditPart)part).setShowCompensationHandler(show); | |
else if (part instanceof InvokeEditPart) | |
((InvokeEditPart)part).setShowCompensationHandler(show); | |
} | |
public static void setShowTerminationHandler(EditPart part, boolean show) { | |
if (part instanceof ScopeEditPart) | |
((ScopeEditPart)part).setShowTerminationHandler(show); | |
} | |
/* external event handler helpers */ | |
public static boolean getShowEventHandler(EditPart part) { | |
if (part instanceof ScopeEditPart) | |
return ((ScopeEditPart)part).getShowEventHandler(); | |
else if (part instanceof StartNodeEditPart) | |
return ((StartNodeEditPart)part).getShowEventHandler(); | |
return false; | |
} | |
public static void setShowEventHandler(EditPart part, boolean show) { | |
if (part instanceof ScopeEditPart) | |
((ScopeEditPart)part).setShowEventHandler(show); | |
else if (part instanceof StartNodeEditPart) | |
((StartNodeEditPart)part).setShowEventHandler(show); | |
} | |
/** | |
* Returns the extension file of the given BPEL file. | |
*/ | |
public static IFile getBPELEXFile(IFile bpelFile) { | |
IPath path = bpelFile.getFullPath().removeFileExtension().addFileExtension(IBPELUIConstants.EXTENSION_MODEL_EXTENSIONS); | |
return ResourcesPlugin.getWorkspace().getRoot().getFile(path); | |
} | |
/** | |
* Returns the artifacts WSDL of the given BPEL file. | |
*/ | |
public static IFile getArtifactsWSDLFile(IFile bpelFile) { | |
IPath wsdlPath = bpelFile.getFullPath().removeFileExtension(); | |
String fileName = wsdlPath.lastSegment() + "Artifacts"; //$NON-NLS-1$ | |
wsdlPath = wsdlPath.removeLastSegments(1).append(fileName); | |
wsdlPath = wsdlPath.addFileExtension(IBPELUIConstants.EXTENSION_WSDL); | |
return ResourcesPlugin.getWorkspace().getRoot().getFile(wsdlPath); | |
} | |
public static Image getImage(IMarker marker) { | |
Image img = ModelMarkerUtil.getImage(marker); | |
ImageData background = null; | |
if (img != null) { | |
background = img.getImageData(); | |
} | |
if (background == null) { | |
// Don't give up yet. If this is also a problem marker, we can find an image to | |
// display... | |
try { | |
if (marker.isSubtypeOf(IMarker.PROBLEM)) { | |
background = ImageUtils.getImage(marker).getImageData(); | |
} | |
} catch (CoreException e) { | |
BPELUIPlugin.log(e); | |
return null; | |
} | |
} | |
if (background == null) return null; | |
String uri = marker.getAttribute(IBPELUIConstants.MARKER_OVERLAYIMAGETOPLEFT, ""); //$NON-NLS-1$ | |
ImageData topLeft = getImageData(uri); | |
uri = marker.getAttribute(IBPELUIConstants.MARKER_OVERLAYIMAGETOPRIGHT, ""); //$NON-NLS-1$ | |
ImageData topRight = getImageData(uri); | |
uri = marker.getAttribute(IBPELUIConstants.MARKER_OVERLAYIMAGEBOTTOMLEFT, ""); //$NON-NLS-1$ | |
ImageData bottomLeft = getImageData(uri); | |
uri = marker.getAttribute(IBPELUIConstants.MARKER_OVERLAYIMAGEBOTTOMRIGHT, ""); //$NON-NLS-1$ | |
ImageData bottomRight = getImageData(uri); | |
OverlayCompositeImageDescriptor descriptor = new OverlayCompositeImageDescriptor(background, topLeft, topRight, bottomLeft, bottomRight); | |
return descriptor.createImage(); | |
} | |
private static 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(); | |
} | |
/** | |
* Returns the EditPart which is responsible for the given IFigure. | |
*/ | |
public static EditPart mapFigure2EditPart(EditPartViewer viewer, IFigure figure) { | |
Map visualPartMap = viewer.getVisualPartMap(); | |
EditPart part = null; | |
while (part == null && figure != null) { | |
part = (EditPart)visualPartMap.get(figure); | |
figure = figure.getParent(); | |
} | |
return part; | |
} | |
/** | |
* Reads the process from disk. | |
*/ | |
public static Process getProcess(IResource bpelFile, ResourceSet resourceSet) throws IOException { | |
URI uri = URI.createPlatformResourceURI(bpelFile.getFullPath().toString()); | |
Resource processResource = resourceSet.getResource(uri, true); | |
EList<EObject> contents = processResource.getContents(); | |
if (!contents.isEmpty()) { | |
return (Process) contents.get(0); | |
} | |
return null; | |
} | |
public static AccessibleEditPart getAccessibleEditPart(GraphicalEditPart part) { | |
final GraphicalEditPart thisPart = part; | |
return new AccessibleEditPart() { | |
@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()); | |
if (childType != null && displayName.equals(childType)) { | |
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 getChildCount(AccessibleControlEvent e) { | |
List<EditPart> list = thisPart.getChildren(); | |
int count = 0; | |
for (EditPart part : list) { | |
AccessibleEditPart access = (AccessibleEditPart)part.getAdapter(AccessibleEditPart.class); | |
if (access == null) | |
continue; | |
count++; | |
} | |
e.detail = count; | |
} | |
@Override | |
public void getChildren(AccessibleControlEvent e) { | |
List<EditPart> list = thisPart.getChildren(); | |
Vector<Integer> childList = new Vector<Integer>(); | |
for (EditPart part : list) { | |
AccessibleEditPart access = (AccessibleEditPart)part.getAdapter(AccessibleEditPart.class); | |
if (access == null) | |
continue; | |
childList.add( Integer.valueOf( access.getAccessibleID())); | |
} | |
e.children = childList.toArray(); | |
} | |
@Override | |
public void getLocation(AccessibleControlEvent e) { | |
Rectangle bounds = thisPart.getFigure().getBounds().getCopy(); | |
thisPart.getFigure().translateToAbsolute(bounds); | |
org.eclipse.swt.graphics.Point p = new org.eclipse.swt.graphics.Point(0, 0); | |
p = thisPart.getViewer().getControl().toDisplay(p); | |
e.x = bounds.x + p.x; | |
e.y = bounds.y + p.y; | |
e.width = bounds.width; | |
e.height = bounds.height; | |
} | |
/** | |
* @see AccessibleEditPart#getState(AccessibleControlEvent) | |
*/ | |
@Override | |
public void getState(AccessibleControlEvent e) { | |
e.detail = ACC.STATE_SELECTABLE | ACC.STATE_FOCUSABLE; | |
if (thisPart.getSelected() != EditPart.SELECTED_NONE) | |
e.detail |= ACC.STATE_SELECTED; | |
if (thisPart.getViewer().getFocusEditPart() == thisPart) | |
e.detail = ACC.STATE_FOCUSED; | |
} | |
}; | |
} | |
/** creates a table cursor that can be used to navigate tables for keyboard accessibility **/ | |
public static TableCursor createTableCursor(final Table table, final TableViewer tableViewer) { | |
// create a TableCursor to navigate around the table | |
final TableCursor cursor = new TableCursor(table, SWT.NONE); | |
cursor.addSelectionListener(new SelectionAdapter() { | |
// when the TableEditor is over a cell, select the corresponding row in the table | |
@Override | |
public void widgetSelected(SelectionEvent e) { | |
if (cursor.getRow() != null) | |
table.setSelection(new TableItem[] {cursor.getRow()}); | |
} | |
// when the user hits "ENTER" in the TableCursor, pop up an editor | |
@Override | |
public void widgetDefaultSelected(SelectionEvent e) { | |
TableItem row = cursor.getRow(); | |
if (row != null) { | |
int nRow = table.indexOf(row); | |
int column = cursor.getColumn(); | |
Object obj = tableViewer.getElementAt(nRow); | |
tableViewer.editElement(obj, column); | |
} | |
} | |
}); | |
// Hide the TableCursor when the user hits the "CTRL" or "SHIFT" key. | |
// This alows the user to select multiple items in the table. | |
cursor.addKeyListener(new KeyAdapter() { | |
@Override | |
public void keyPressed(KeyEvent e) { | |
if ((e.keyCode == SWT.CTRL) || (e.keyCode == SWT.SHIFT) || | |
(e.stateMask & SWT.CONTROL) != 0 || (e.stateMask & SWT.SHIFT) != 0) { | |
cursor.setVisible(false); | |
} | |
} | |
}); | |
cursor.addMouseListener(new MouseListener() { | |
@Override | |
public void mouseDoubleClick(MouseEvent e) { } | |
@Override | |
public void mouseDown(MouseEvent e) { | |
TableItem row = cursor.getRow(); | |
if (row != null) { | |
int nRow = table.indexOf(row); | |
int column = cursor.getColumn(); | |
Object obj = tableViewer.getElementAt(nRow); | |
tableViewer.editElement(obj, column); | |
} | |
} | |
@Override | |
public void mouseUp(MouseEvent e) { | |
} | |
}); | |
// Show the TableCursor when the user releases the "SHIFT" or "CTRL" key. | |
// This signals the end of the multiple selection task. | |
table.addKeyListener(new KeyAdapter() { | |
@Override | |
public void keyReleased(KeyEvent e) { | |
if (e.keyCode == SWT.CONTROL && (e.stateMask & SWT.SHIFT) != 0) | |
return; | |
if (e.keyCode == SWT.SHIFT && (e.stateMask & SWT.CONTROL) != 0) | |
return; | |
if (e.keyCode != SWT.CONTROL && (e.stateMask & SWT.CONTROL) != 0) | |
return; | |
if (e.keyCode != SWT.SHIFT && (e.stateMask & SWT.SHIFT) != 0) | |
return; | |
if (table.getItemCount() == 0) | |
return; | |
TableItem[] selection = table.getSelection(); | |
TableItem row = (selection.length == 0) ? table.getItem(table.getTopIndex()) : selection[0]; | |
table.showItem(row); | |
cursor.setSelection(row, 0); | |
cursor.setVisible(true); | |
cursor.setFocus(); | |
} | |
}); | |
return cursor; | |
} | |
public static ResourceSet createResourceSetImpl() { | |
// TODO: Extensibility | |
return new ResourceSetImpl(); | |
} | |
static final NCNameWordDetector NCNAME_DETECTOR = new NCNameWordDetector (); | |
/** | |
* Returns a validator that checks that the new value is a valid NCName. | |
*/ | |
public static IInputValidator getNCNameValidator() { | |
return new IInputValidator() { | |
@Override | |
public String isValid (String newText) { | |
if ( NCNAME_DETECTOR.isValid( newText ) == false ) { | |
return Messages.BPELUtil_NCName; | |
} | |
// TODO ! temporary hack | |
return null; | |
} | |
}; | |
} | |
public static void deleteNonContainmentRefs(EObject modelObject, Collection referents) { | |
if (modelObject == null) return; | |
for (EReference feature : modelObject.eClass().getEAllReferences()) { | |
if (feature.isMany()) { | |
EList<Object> list = (EList<Object>)modelObject.eGet(feature, true); | |
for (Object referent : referents) { | |
if (list.contains(referent)) list.remove(referent); | |
// TODO: support non-changeable features! print a warning. | |
} | |
} else { | |
Object oldValue = modelObject.eGet(feature, true); | |
for (Object referent : referents) { | |
if (oldValue == referent) { | |
if (feature.isUnsettable()) { | |
// this is okay, default is always null for EReferences. | |
modelObject.eUnset(feature); | |
} else { | |
modelObject.eSet(feature, null); | |
} | |
break; | |
} | |
// TODO: support non-changeable features! print a warning. | |
} | |
} | |
} | |
} | |
//@return: returns arraylist with all activities the compensate | |
// can validly point to | |
public static ArrayList getCompensableActivities(Object context){ | |
final ArrayList returnObjects = new ArrayList(); | |
if (context instanceof CompensateScope) { | |
CompensateScope compensateScope = (CompensateScope) context; | |
EObject enclosingContainer = compensateScope; | |
if (compensateScope.eContainer() != null) { | |
enclosingContainer = enclosingContainer.eContainer(); | |
// Go to parent scope where compensate is contained | |
while (!(enclosingContainer instanceof Scope) | |
&& (enclosingContainer.eContainer() != null)) { | |
enclosingContainer = enclosingContainer.eContainer(); | |
} | |
} | |
// Put all scopes and invokes within parent scope in arraylist | |
visitModelDepthFirst(enclosingContainer, | |
new IModelVisitor() { | |
@Override | |
public boolean visit(Object modelObject) { | |
if (modelObject instanceof Scope) { | |
returnObjects.add(modelObject); | |
} else if (modelObject instanceof Invoke) { | |
returnObjects.add(modelObject); | |
} | |
return true; | |
} | |
}); | |
// https://issues.jboss.org/browse/JBIDE-8044 | |
if (!returnObjects.isEmpty()) | |
returnObjects.remove(0); //remove the scope containing the compensate | |
return returnObjects; | |
} | |
throw new IllegalArgumentException(); | |
} | |
public static Object resolveXSDObject(Object xsdObject) { | |
if (xsdObject instanceof XSDElementDeclaration) { | |
XSDElementDeclaration resolvedElement = ((XSDElementDeclaration)xsdObject).getResolvedElementDeclaration(); | |
if (resolvedElement != null) xsdObject = resolvedElement; | |
} else if (xsdObject instanceof XSDAttributeDeclaration) { | |
XSDAttributeDeclaration resolvedAttribute = ((XSDAttributeDeclaration)xsdObject).getResolvedAttributeDeclaration(); | |
if (resolvedAttribute != null) xsdObject = resolvedAttribute; | |
} | |
return xsdObject; | |
} | |
public static String debugObject(Object object) { | |
if (object == null) return "null"; //$NON-NLS-1$ | |
if (object instanceof String) { return "\""+(String)object+"\""; } //$NON-NLS-1$ //$NON-NLS-2$ | |
if (object.getClass().getName().startsWith("java.lang")) { //$NON-NLS-1$ | |
return object.toString(); | |
} | |
if (object instanceof List) { | |
StringBuffer b = new StringBuffer("("); //$NON-NLS-1$ | |
for (Iterator it = ((List)object).iterator(); it.hasNext(); ) { | |
b.append(debugObject(it.next())); | |
if (it.hasNext()) b.append(", "); //$NON-NLS-1$ | |
} | |
b.append(")"); //$NON-NLS-1$ | |
return b.toString(); | |
} | |
if (object instanceof QName) { | |
QName qname = (QName)object; | |
return "QName(\""+qname.getNamespaceURI()+"\", \""+qname.getLocalPart()+"\")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
} | |
StringBuffer b = new StringBuffer(shortClassName(object.getClass())); | |
boolean proxy = (object instanceof EObject) && ((EObject)object).eIsProxy(); | |
if (proxy) b.append("-proxy"); //$NON-NLS-1$ | |
boolean isEObject = (object instanceof EObject); | |
INamedElement namedElement = null; | |
if (isEObject) { | |
namedElement = BPELUtil.adapt(object, INamedElement.class); | |
if (namedElement != null) { | |
try { | |
String s = namedElement.getName(object); | |
b.append((s==null)? "<null>" : "<\""+s+"\">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
} catch (Exception e) { | |
b.append("<???>"); //$NON-NLS-1$ | |
} | |
} | |
} | |
if (namedElement==null) { | |
b.append("{"); b.append(String.valueOf(object.hashCode())); b.append("}"); //$NON-NLS-1$ //$NON-NLS-2$ | |
} | |
return b.toString(); | |
} | |
public static String debug(Notification n) { | |
StringBuffer b = new StringBuffer(shortClassName(n.getClass())); | |
b.append("("); //$NON-NLS-1$ | |
b.append(debugObject(n.getNotifier())); | |
b.append(", "); //$NON-NLS-1$ | |
switch (n.getEventType()) { | |
case Notification.SET-1: b.append("CREATE"); break; //$NON-NLS-1$ | |
case Notification.SET: b.append("SET"); break; //$NON-NLS-1$ | |
case Notification.UNSET: b.append("UNSET"); break; //$NON-NLS-1$ | |
case Notification.ADD: b.append("ADD"); break; //$NON-NLS-1$ | |
case Notification.REMOVE: b.append("REMOVE"); break; //$NON-NLS-1$ | |
case Notification.ADD_MANY: b.append("ADD_MANY"); break; //$NON-NLS-1$ | |
case Notification.MOVE: b.append("MOVE"); break; //$NON-NLS-1$ | |
case Notification.REMOVING_ADAPTER: b.append("REMOVING_ADAPTER"); break; //$NON-NLS-1$ | |
case Notification.RESOLVE: b.append("RESOLVE"); break; //$NON-NLS-1$ | |
default: b.append("??? ("+String.valueOf(n.getEventType())+")"); //$NON-NLS-1$ //$NON-NLS-2$ | |
} | |
b.append(" "); //$NON-NLS-1$ | |
EStructuralFeature feature = (EStructuralFeature)n.getFeature(); | |
if (feature == null) b.append("???"); else b.append(feature.getName()); //$NON-NLS-1$ | |
if (n.getPosition() >= 0) { | |
b.append("["); //$NON-NLS-1$ | |
b.append(String.valueOf(n.getPosition())); | |
b.append("]"); //$NON-NLS-1$ | |
} else { | |
if (feature != null && feature.isMany()) b.append("{***}"); //$NON-NLS-1$ | |
} | |
b.append(": "); //$NON-NLS-1$ | |
b.append(debugObject(n.getOldValue())); | |
b.append(" --> "); //$NON-NLS-1$ | |
b.append(debugObject(n.getNewValue())); | |
b.append(")"); //$NON-NLS-1$ | |
return b.toString(); | |
} | |
protected static String shortClassName(Class clazz) { | |
StringBuffer b = new StringBuffer(clazz.getName()); | |
for (int i = b.indexOf("."); i >= 0; i = b.indexOf(".")) b.delete(0,i+1); //$NON-NLS-1$ //$NON-NLS-2$ | |
//if (b.indexOf("Impl") == b.length()-4) b.delete(b.length()-4, b.length())); | |
return b.toString(); | |
} | |
/** | |
* Creates a composite with a flat border around it. | |
*/ | |
public static Composite createBorderComposite(Composite parent, TabbedPropertySheetWidgetFactory wf) { | |
final Composite result = wf.createComposite(parent); | |
FillLayout layout = new FillLayout(); | |
final int margin = 1; | |
layout.marginHeight = margin; | |
layout.marginWidth = margin; | |
result.setLayout(layout); | |
result.addPaintListener(new PaintListener() { | |
@Override | |
public void paintControl(PaintEvent e) { | |
org.eclipse.swt.graphics.Rectangle bounds = result.getBounds(); | |
bounds.x = margin-1; | |
bounds.y = margin-1; | |
bounds.width = bounds.width - (margin*2) + 1; | |
bounds.height = bounds.height - (margin*2) + 1; | |
e.gc.drawRectangle(bounds); | |
} | |
}); | |
return result; | |
} | |
static void addVariablesToMap(Map<String, Variable> targetMap, Variables vars, Variable refVar ) { | |
if (vars == null) { | |
return; | |
} | |
for(Variable v : vars.getChildren()) { | |
// scoping for initialization (only visible from). | |
if (v == refVar) { | |
break; | |
} | |
if (v.getName() != null) { | |
targetMap.put(v.getName(),v); | |
} | |
} | |
} | |
static void addVisibleVariables (Map<String,Variable> targetMap, EObject target, Variable refVariable ) { | |
if (target == null) { | |
return; | |
} | |
if (target instanceof Resource) { | |
return; | |
} | |
if (target instanceof Process) { | |
addVariablesToMap(targetMap, ((Process)target).getVariables(), refVariable ); | |
return ; | |
} | |
// recursively add less local variables first | |
addVisibleVariables(targetMap, target.eContainer(), refVariable ); | |
if (target instanceof Scope) { | |
addVariablesToMap(targetMap, ((Scope)target).getVariables(), refVariable ); | |
} | |
if (target instanceof Catch) { | |
Variable v = ((Catch)target).getFaultVariable(); | |
if (v != null && v.getName() != null) { | |
targetMap.put(v.getName(), v); | |
} | |
} | |
if (target instanceof OnEvent) { | |
Variable v = ((OnEvent)target).getVariable(); | |
if (v != null && v.getName() != null) { | |
targetMap.put(v.getName(), v); | |
} | |
} | |
if (target instanceof ForEach) { | |
Variable v = ((ForEach)target).getCounterName(); | |
if (v != null && v.getName() != null) { | |
targetMap.put(v.getName(), v); | |
} | |
} | |
} | |
private static void addPartnerLinksToMap(Map<String, PartnerLink> targetMap, PartnerLinks plinks) { | |
if (plinks == null) return; | |
for (PartnerLink p : plinks.getChildren()) { | |
if (p.getName() != null) targetMap.put(p.getName(), p); | |
} | |
} | |
private static void addVisiblePartnerLinks(Map<String, PartnerLink> targetMap, EObject target) { | |
if (target == null) return; | |
if (target instanceof Resource) return; | |
if (target instanceof Process) { | |
addPartnerLinksToMap(targetMap, ((Process)target).getPartnerLinks()); | |
} else { | |
// recursively add less local partnerlinks first | |
addVisiblePartnerLinks(targetMap, target.eContainer()); | |
if (target instanceof Scope) { | |
addPartnerLinksToMap(targetMap, ((Scope)target).getPartnerLinks()); | |
} | |
} | |
} | |
private static void addCorrelationSetsToMap(Map<String, CorrelationSet> targetMap, CorrelationSets csets) { | |
if (csets == null) return; | |
for( CorrelationSet c : csets.getChildren() ) { | |
if (c.getName() != null) targetMap.put(c.getName(), c); | |
} | |
} | |
private static void addVisibleCorrelationSets(Map<String, CorrelationSet> targetMap, EObject target) { | |
if (target == null) return; | |
if (target instanceof Resource) return; | |
if (target instanceof Process) { | |
addCorrelationSetsToMap(targetMap, ((Process)target).getCorrelationSets()); | |
} else { | |
// recursively add less local correlationsets first | |
addVisibleCorrelationSets(targetMap, target.eContainer()); | |
if (target instanceof Scope) { | |
addCorrelationSetsToMap(targetMap, ((Scope)target).getCorrelationSets()); | |
} | |
} | |
} | |
/** | |
* Look up the variables visible to a certain context activity (or the whole process). | |
* Variables in BPEL follow lexical scoping rules (resolved OASIS issue 101). | |
* | |
* The returned variables are in no particular order. | |
*/ | |
public static Variable[] getVisibleVariables (EObject target) { | |
Map<String,Variable> name2Variable = new HashMap<String,Variable>(); | |
addVisibleVariables(name2Variable, target, target instanceof Variable ? (Variable) target: null ); | |
if (name2Variable.isEmpty()) { | |
return EMPTY_VARIABLE_ARRAY; | |
} | |
Collection<Variable> variables = name2Variable.values(); | |
if (variables.size() == 1) { | |
return variables.toArray(EMPTY_VARIABLE_ARRAY); | |
} | |
ArrayList<Variable> list = new ArrayList<Variable>( variables ); | |
Collections.sort(list, new Comparator<Variable>() { | |
@Override | |
public int compare(Variable o1, Variable o2) { | |
return o1.getName().compareTo(o2.getName()); | |
} | |
}); | |
return list.toArray(EMPTY_VARIABLE_ARRAY); | |
} | |
/** | |
* Look up the PartnerLinks visible to a certain context activity (or the whole process). | |
* When local PartnerLinks are added to the spec, they will follow lexical scoping rules | |
* just like variables. | |
* | |
* The returned PartnerLinks are in no particular order. | |
*/ | |
public static PartnerLink[] getVisiblePartnerLinks(EObject target) { | |
Map<String, PartnerLink> name2PartnerLink = new HashMap<String, PartnerLink>(); | |
addVisiblePartnerLinks(name2PartnerLink, target); | |
if (name2PartnerLink.isEmpty()) return EMPTY_PARTNERLINK_ARRAY; | |
PartnerLink[] result = new PartnerLink[name2PartnerLink.size()]; | |
name2PartnerLink.values().toArray(result); | |
return result; | |
} | |
/** | |
* Look up the PartnerLinks visible to a certain context activity (or the whole process). | |
* When local PartnerLinks are added to the spec, they will follow lexical scoping rules | |
* just like variables. | |
* | |
* The returned PartnerLinks are in no particular order. | |
*/ | |
public static CorrelationSet[] getVisibleCorrelationSets(EObject target) { | |
Map<String, CorrelationSet> name2CorrelationSet = new HashMap<String, CorrelationSet>(); | |
addVisibleCorrelationSets(name2CorrelationSet, target); | |
if (name2CorrelationSet.isEmpty()) return EMPTY_CORRELATIONSET_ARRAY; | |
CorrelationSet[] result = new CorrelationSet[name2CorrelationSet.size()]; | |
name2CorrelationSet.values().toArray(result); | |
return result; | |
} | |
/** | |
* If the given message is used by an operation in the same definition, | |
* returns the Operation that uses the given message. | |
* Otherwise, returns null. | |
*/ | |
public static Operation getOperationFromMessage(Message message) { | |
if (message == null) return null; | |
Definition def = message.getEnclosingDefinition(); | |
if (def == null) return null; | |
Iterator<PortType> ptIt = def.getEPortTypes().iterator(); | |
while (ptIt.hasNext()) { | |
PortType pt = ptIt.next(); | |
Iterator<Operation> it = pt.getOperations().iterator(); | |
while (it.hasNext()) { | |
Operation op = it.next(); | |
Input input = op.getEInput(); | |
if (input != null) { | |
if (input.getMessage().getQName().equals(message.getQName())) { | |
return op; | |
} | |
} | |
Output output = op.getEOutput(); | |
if (output != null) { | |
if (output.getMessage().getQName().equals(message.getQName())) { | |
return op; | |
} | |
} | |
Iterator<Fault> faultIterator = op.getEFaults().iterator(); | |
while (faultIterator.hasNext()) { | |
Fault fault = faultIterator.next(); | |
Message faultMessage = fault.getEMessage(); | |
if (faultMessage != null) { | |
if (faultMessage.getQName() != null) { | |
if (faultMessage.getQName().equals(message.getQName())) { | |
return op; | |
} | |
} | |
} | |
} | |
} | |
} | |
return null; | |
} | |
public static void openEditor(EObject modelObject, BPELEditor editor) { | |
try { | |
// https://issues.jboss.org/browse/JBIDE-8044 | |
if (modelObject==null) { | |
// https://issues.jboss.org/browse/JBIDE-8601 | |
MessageDialog.openError(editor.getEditorSite().getShell(), | |
Messages.BPELUtil__Error, | |
Messages.BPELUtil_NoEditorForNullObject); | |
return; | |
} | |
EObject resolvedObject = null; | |
if (modelObject.eResource()==null) { | |
// https://jira.jboss.org/browse/JBIDE-7351 | |
// try to resolve proxies here, otherwise we don't know editor input | |
if (modelObject.eIsProxy()) { | |
resolvedObject = EmfModelQuery.resolveProxy(editor.getProcess(), modelObject); | |
} | |
} | |
else | |
resolvedObject = modelObject; | |
if (resolvedObject==null) { | |
// https://issues.jboss.org/browse/JBIDE-8601 | |
MessageDialog.openError(editor.getEditorSite().getShell(), | |
Messages.BPELUtil__Error, NLS.bind( | |
Messages.BPELUtil_NoEditorForObject, | |
(new Object[] { modelObject.getClass().getSimpleName() }))); | |
return; | |
} | |
IFile file = BPELUtil.getFileFromURI(resolvedObject.eResource().getURI()); | |
IDE.openEditor(editor.getSite().getWorkbenchWindow().getActivePage(), file); | |
} catch (PartInitException ex) { | |
BPELUIPlugin.log(ex, IStatus.WARNING); | |
} | |
} | |
/** | |
* Returns the BPEL file associated with the given process. | |
*/ | |
public static IFile getBPELFile(Process process) { | |
return getFileFromURI(process.eResource().getURI()); | |
} | |
public static String lookupOrCreateNamespacePrefix ( EObject context, String namespace, String prefix, Shell shell ) { | |
String nsPrefix = BPELUtils.getNamespacePrefix(context, namespace); | |
if (nsPrefix != null && nsPrefix.length() > 0) { | |
return nsPrefix; | |
} | |
NamespaceMappingDialog dialog = new NamespaceMappingDialog (shell, context); | |
dialog.setNamespace(namespace); | |
if (prefix != null) { | |
dialog.setPrefix(prefix); | |
} | |
if (dialog.open() == Window.CANCEL) { | |
return nsPrefix; | |
} | |
nsPrefix = dialog.getPrefix(); | |
BPELUtils.setNamespacePrefix(context, namespace, nsPrefix); | |
return nsPrefix; | |
} | |
/** | |
* Traverses the root object and returns all objects under it that are of the same | |
* class or subclasses of "target". | |
*/ | |
public static List<EObject> getAllEObjectsOfType(EObject root, EClass eClass) { | |
List<EObject> allElems = new ArrayList<EObject>(); | |
for (TreeIterator<EObject> iter = root.eAllContents(); iter.hasNext();) { | |
EObject element = iter.next(); | |
if (eClass.isSuperTypeOf(element.eClass()) || | |
element.eClass() == eClass) { | |
allElems.add(element); | |
} | |
} | |
return allElems; | |
} | |
public static boolean isBPELProject(IProject project){ | |
if (project == null) { | |
return false; | |
} | |
if (ModuleCoreNature.isFlexibleProject(project)) { | |
IFacetedProject fproj = null; | |
try { | |
fproj = ProjectFacetsManager.create(project); | |
} catch (CoreException e) { | |
return false; | |
} | |
if (fproj.hasProjectFacet(getBPELFacetVersion())) { | |
return true; | |
} | |
} | |
return false; | |
} | |
public static IProjectFacetVersion getBPELFacetVersion() { | |
IProjectFacet bpelFacet = ProjectFacetsManager.getProjectFacet(IBPELModuleFacetConstants.BPEL20_PROJECT_FACET); | |
IProjectFacetVersion bpelFacetVersion = bpelFacet.getVersion(IBPELModuleFacetConstants.BPEL20_MODULE_VERSION); | |
return bpelFacetVersion; | |
} | |
public static org.eclipse.core.resources.IContainer getBPELContentFolder(IProject project) { | |
org.eclipse.core.resources.IContainer bpelContent = null; | |
if (BPELUtil.isBPELProject(project)) { | |
IPath rootPath = getWebContentRootPath(project); | |
if (rootPath != null && !rootPath.isEmpty()) { | |
bpelContent = project.getFolder(rootPath); | |
} | |
} | |
return bpelContent; | |
} | |
public static IPath getWebContentRootPath(IProject project) { | |
IPath path = null; | |
IVirtualComponent component = ComponentCore.createComponent(project); | |
if (component != null && component.exists()) { | |
path = component.getRootFolder().getProjectRelativePath(); | |
} | |
return path; | |
} | |
} |