Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "BPMN2-Modeler/DeveloperTutorials/Adapters"

Line 77: Line 77:
  
 
==== Creating the ObjectDescriptor ====
 
==== Creating the ObjectDescriptor ====
 +
The ObjectDescriptor controls certain UI aspects of the object itself, such as the text label that appears on Section and List headers. Use the ''setObjectDescriptor(ObjectDescriptor<T> od)'' method to create and set an '''ObjectDescriptor''', for example:
 +
 +
<pre>
 +
setObjectDescriptor(new ObjectDescriptor<DataObjectReference>(this, object) {
 +
    @Override
 +
    public String getTextValue() {
 +
        // If the Data Object has a state, include it in [] brackets
 +
        String text = super.getTextValue();
 +
        text += " ["; //$NON-NLS-1$
 +
        if (object.getDataState()!=null) {
 +
            text += object.getDataState().getName();
 +
        }
 +
        text += "]"; //$NON-NLS-1$
 +
        return text;
 +
    }
 +
});
 +
</pre>
 +
 +
See the Javadoc for a complete description of ObjectDescriptor and its functionality.
  
 
==== Creating one or more FeatureDescriptors ====
 
==== Creating one or more FeatureDescriptors ====
 +
You must create a '''FeatureDescriptor''' for each '''EStructuralFeature''' whose behavior you want to change. The feature can be either from a BPMN2 model object, or from an external model. The '''FeatureDescriptors''' must be set in your '''ExtendedPropertiesAdapter''' constructor. Here is an example taken from the editor's '''ActivityPropertiesAdapter''':
  
 +
<pre>
 +
EStructuralFeature feature = Bpmn2Package.eINSTANCE.getActivity_IsForCompensation();
 +
setFeatureDescriptor(feature,
 +
    new FeatureDescriptor<T>(this,object,feature) {
 +
        @Override
 +
        protected void internalSet(T object, EStructuralFeature feature, Object value, int index) {
 +
            if (value instanceof Boolean) {
 +
                if (!(Boolean)value) {
 +
                    // This Activity is no longer being used for Compensation.
 +
                    // If any Compensation Boundary Events reference this
 +
                    // Activity, set their Activity References to null.
 +
                    TreeIterator<EObject> iter = ModelUtil.getDefinitions(object).eAllContents();
 +
                    while (iter.hasNext()) {
 +
                        EObject o = iter.next();
 +
                        if (o instanceof CompensateEventDefinition) {
 +
                            CompensateEventDefinition ced = (CompensateEventDefinition) o;
 +
                            if (ced.getActivityRef() == object) {
 +
                                ExtendedPropertiesProvider.setValue(ced, Bpmn2Package.eINSTANCE.getCompensateEventDefinition_ActivityRef(), null);
 +
                            }
 +
                        }
 +
                    }
 +
                }
 +
            }
 +
            super.internalSet(object, feature, value, index);
 +
        }
 +
    }
 +
);
 +
</pre>
  
 
== InsertionAdapter ==
 
== InsertionAdapter ==
  
 
== StyleChangeAdapter ==
 
== StyleChangeAdapter ==

Revision as of 16:04, 13 March 2015

Versions

This tutorial was developed with Eclipse 4.4 (Luna) and BPMN2-Plugin version 1.1.3.

Introduction

One of the features that allows the BPMN2 Modeler to be extensible is the ability to attach a so-called "adapter" to any EObject. All EObjects contain a list of adapters that are notified during the object's lifecycle. Thus, events like feature changes, proxy resolution, EMF Resource changes, etc. are reported to these adapters.

This tutorial describes two adapters that are used throughout the editor code, what they do and how to use them in your extension plugin.


ExtendedPropertiesAdapter

Background (feel free to skip this)

The EMF genmodel editor, which is used to generate Java interfaces and implementation classes for your ecore model, can optionally create a simple, tree-based editor that can be used during testing of your model. This editor consists of two plugin components: the tree editor itself which implements a MultiPageEditorPart, and a content provider. The editor plugin is usually named something like mymodel.editor and the provider is mymodel.edit.

The EMF model generator creates one provider class for each generated Java class; a Java class roughly corresponds to an EClass in your ecore definition. This provider plugin is used by the editor UI to obtain (among other things) an icon image that represents the EClass, and text labels for the EClass and all of its EStructuralFeatures.

Unfortunately this provider plugin is insufficient to support all of the functionality the BPMN2 Modeler needs to be extensible. For example, these providers are unaware that a feature may be a "one-of-many" valued entity (e.g. the ServiceTask.implementation, or ItemDefinition.structureRef) or that a feature value has a specific text representation that can't be satisfied with a toString() method.

This is where the ExtendedPropertiesAdapter comes in. We could have simply extended the generated provider classes, but we wanted to decouple the BPMN2 Modeler from the underlying model.

When to use an ExtendedPropertiesAdapter

The BPMN2 Modeler UI uses this adapter as a provider for all aspects of the Property Views. Here is a short list of some of its uses:

  • text labels for editing widgets
  • descriptive text used in tooltips and the Description area of the "General" property tab
  • value-to-string and string-to-value conversions for editing widgets
  • combo-box values
  • editing widget-specific flags to indicate:
    • multiline edit box
    • multi-valued field (combo box)
    • inline editing (for text and combo box widgets)
    • visibility of a "can create" button for text-and-button widgets
    • visibility of a "can edit" button for text-and-button widgets
  • the list of EStructuralFeatures that are BPMN2 language extensions provided by your plugin
  • feature value getter and setter methods. The setter method is wrapped in a transaction whenever necessary, to prevent the mysterious IllegalStateException.
  • object and feature value creation methods that can be used to perform additional initialization
  • custom editing widget provided by your extension plugin to a specific feature. This allows you to provide your own ObjectEditor for a feature if none of the included widgets works for your needs.

The core UI of BPMN2 Modeler itself defines ExtendedPropertiesAdapters for most of the BPMN2 model elements. These adapters can be extended by your plugin if desired.

How to add an ExtendedPropertiesAdapter to your plugin

Start by editing your plugin.xml: in the "org.eclipse.bpmn2.modeler.runtime" extension point, add a new propertyAdapter:

BPMN2-Modeler-Adapters-propertyAdapter.png

Give it a unique ID, and the model type to which this adapter applies. Note that you can specify types declared in your own (or an external) model as well, so you must provide the fully-qualified Java name. The runtime ID should be the same as that defined in the "org.eclipse.bpmn2.modeler.runtime" extension point, unless you wish to provide behavior for another plugin. Note that if your intention is to override a propertyExtension provided by a different plugin, there is no guarantee this will work because the order in which plugins are loaded is indeterminate.

Finally, provide an implementation class. Clicking the "class" link in the plugin.xml editor will allow you to create a new Java class.

How to extend your ExtendedPropertiesAdapter

There are essentially three areas of the ExtendedPropertiesAdapter definition you need to be concerned about:

  1. Setting flags for the UI editing widgets
  2. Creating an optional ObjectDescriptor
  3. Creating one or more optional FeatureDescriptors

Setting UI Flags

UI flags are set on a feature because each feature will cause a separate editing widget to be rendered in the Property View. To set a flag, call the setProperty(EStructuralFeature feature, String key, Object value) method in your ExtendedPropertiesAdapter constructor, for example:

    EStructuralFeature feature = Bpmn2Package.eINSTANCE.getAssociation_SourceRef();
    setProperty(feature, UI_CAN_EDIT_INLINE, Boolean.FALSE);

The flags and their meanings are as follows. Note that the type of object to set for each property is indicated in parentheses:

  • LONG_DESCRIPTION (String) - verbose description of the model object that owns this ExtendedPropertiesAdapter.
  • UI_CAN_EDIT (Boolean) - indicates if this object can be edited, or is read-only.
  • UI_CAN_EDIT_INLINE (Boolean) - used only by the ComboObjectEditor widget. Any adapter that uses this must also override the feature's setValue() and getValue() which must be able to convert an arbitrary String to the required type of the feature's value (set) and back (get).
  • UI_CAN_CREATE_NEW (Boolean) - controls the visibility of a "Create" button in some editing widgets.
  • UI_CAN_SET_NULL (Boolean) - For Combo boxes (ComboObjectEditor), this indicates that an empty selection should be added to the list of possible choices; For Text fields (TextObjectEditor), this indicates that the actual value of a feature should be used as the edit field text instead of its textual representation as returned by @link ModelUtil#getDisplayName(). In this
case, if the value is null, it will be replaced with an empty string.
  • UI_IS_MULTI_CHOICE (Boolean) - indicates that this feature is multi-valued and requires a ComboObjectEditor widget.
  • UI_OBJECT_EDITOR_CLASS (ObjectEditor) - defines the ObjectEditor class that should be used for the given feature instead of the default based on the feature type. A new instance of this ObjectEditor type is constructed and displayed in the Property sheets to edit the feature value.
  • LINE_NUMBER (int) - the line number in the XML document where this object is defined. This is a read-only property.
  • IS_EXTENSION_FEATURE (Boolean) - indicates the feature is a BPMN2 extension defined by your plugin. This should also be treated as a read-only property.

Creating the ObjectDescriptor

The ObjectDescriptor controls certain UI aspects of the object itself, such as the text label that appears on Section and List headers. Use the setObjectDescriptor(ObjectDescriptor<T> od) method to create and set an ObjectDescriptor, for example:

setObjectDescriptor(new ObjectDescriptor<DataObjectReference>(this, object) {
    @Override
    public String getTextValue() {
        // If the Data Object has a state, include it in [] brackets
        String text = super.getTextValue();
        text += " ["; //$NON-NLS-1$
        if (object.getDataState()!=null) {
            text += object.getDataState().getName();
        }
        text += "]"; //$NON-NLS-1$
        return text;
    }
});

See the Javadoc for a complete description of ObjectDescriptor and its functionality.

Creating one or more FeatureDescriptors

You must create a FeatureDescriptor for each EStructuralFeature whose behavior you want to change. The feature can be either from a BPMN2 model object, or from an external model. The FeatureDescriptors must be set in your ExtendedPropertiesAdapter constructor. Here is an example taken from the editor's ActivityPropertiesAdapter:

EStructuralFeature feature = Bpmn2Package.eINSTANCE.getActivity_IsForCompensation();
setFeatureDescriptor(feature,
    new FeatureDescriptor<T>(this,object,feature) {
        @Override
        protected void internalSet(T object, EStructuralFeature feature, Object value, int index) {
            if (value instanceof Boolean) {
                if (!(Boolean)value) {
                    // This Activity is no longer being used for Compensation.
                    // If any Compensation Boundary Events reference this
                    // Activity, set their Activity References to null.
                    TreeIterator<EObject> iter = ModelUtil.getDefinitions(object).eAllContents();
                    while (iter.hasNext()) {
                        EObject o = iter.next();
                        if (o instanceof CompensateEventDefinition) {
                            CompensateEventDefinition ced = (CompensateEventDefinition) o;
                            if (ced.getActivityRef() == object) {
                                ExtendedPropertiesProvider.setValue(ced, Bpmn2Package.eINSTANCE.getCompensateEventDefinition_ActivityRef(), null);
                            }
                        }
                    }
                }
            }
            super.internalSet(object, feature, value, index);
        }
    }
);

InsertionAdapter

StyleChangeAdapter

Back to the top