STP/BPMN Component/STP BPMN Presentation Hands on tutorial

From Eclipsepedia

Jump to: navigation, search

This tutorial is presented as part of the STP BPMN Presentation at EclipseCon 2007.

Contents

Participants

In this section, we are going to begin to play with the modeler and try to extend its use.

We want to add a participant to our shapes. A participant represents a person with a name and a role.


Adding a property tab to create your annotation

The easiest way to add a participant to your shape is to create a property tab to represent it and enable us to enter his name and his role.

You will need to add org.eclipse.ui.views.properties.tabbed, org.eclipse.stp.bpmn and org.eclipse.stp.bpmn.diagram into the dependencies of the plugin.

Your manifest.mf file should contain these dependencies:

Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.ui.views.properties.tabbed,
org.eclipse.stp.bpmn,
org.eclipse.stp.bpmn.diagram

In the plugin.xml file, we define a new property tab named "Participants". We add one section to the tab.

The contributor for the new tab, it defines a new category

   <extension
        point="org.eclipse.ui.views.properties.tabbed.propertyContributor">
     <propertyContributor
           contributorId="org.eclipse.gmf.runtime.diagram.ui.properties">
        <propertyCategory category="Participants"/>
     </propertyContributor>
  </extension>

The definition of the tab itself

   <extension point="org.eclipse.ui.views.properties.tabbed.propertyTabs">
     <propertyTabs contributorId="org.eclipse.gmf.runtime.diagram.ui.properties">
        <propertyTab
              category="Participants"
              id="Participants"
              indented="false"
              label="Participants"/>
     </propertyTabs>
   </extension>

The definition of the section inside the property tab

   <extension point="org.eclipse.ui.views.properties.tabbed.propertySections">
     <propertySections contributorId="org.eclipse.gmf.runtime.diagram.ui.properties">
        <propertySection
              class="org.eclipse.stp.samples.eclipsecon2007.participant.properties.ParticipantPropertySection"
              id="ParticipantsSection"
              tab="Participants">
           <input type="org.eclipse.stp.bpmn.Activity"/>
           <input type="java.lang.Object"/>
        </propertySection>
     </propertySections>
   </extension>

Now we are going to code the tab itself.

A tab is an instance of AbstractPropertySection.

Create a class in org.eclipse.stp.samples.eclipsecon2007.participant.properties as ParticipantPropertySection.

Two methods are important there :

the property tab UI is defined in createPartControl, and the input management in setInput. We need to implement those two methods.

Let's create a first version of createPartControl, with two text fields:

       /**
       * Creates the UI of the section.
       */
       @Override
       public void createControls(Composite parent, 
               TabbedPropertySheetPage aTabbedPropertySheetPage) {
               super.createControls(parent, aTabbedPropertySheetPage);
               GridLayout layout = new GridLayout(2, false);
               parent.setLayout(layout);
               
               GridData gd = new GridData(SWT.FILL);
               gd.minimumWidth = 500;
               gd.widthHint = 500;
               getWidgetFactory().createCLabel(parent, "Name");
               nameText = getWidgetFactory().createText(parent, "");
               nameText.setLayoutData(gd);
               getWidgetFactory().createCLabel(parent, "Role");
               roleText = getWidgetFactory().createText(parent, "");
               roleText.setLayoutData(gd);
       }


Now let's handle the data.

       /**
       * Manages the input.
       */
       @Override
       public void setInput(IWorkbenchPart part, ISelection selection) {
       
               super.setInput(part, selection);
               if(selection instanceof IStructuredSelection) {
                       Object unknownInput = 
                              ((IStructuredSelection) selection).getFirstElement();
                       if (unknownInput instanceof IGraphicalEditPart && 
                               (((IGraphicalEditPart) unknownInput).
                                       resolveSemanticElement() != null)) {
                                unknownInput = ((IGraphicalEditPart) unknownInput).resolveSemanticElement();
                       }
                       if (unknownInput instanceof Activity) {
                                       Activity elt = (Activity) unknownInput;
                                       EAnnotation ea = elt.getEAnnotation(ParticipantConstants.PARTICIPANT_ANNOTATION);
                                       if (ea != null) {
                                               nameText.setText((String) ea.getDetails().get(ParticipantConstants.PARTICIPANT_NAME));
                                               roleText.setText((String) ea.getDetails().get(ParticipantConstants.PARTICIPANT_ROLE));
                                       }
                                       activity = (Activity) elt;
                                       nameText.setEnabled(true);
                                       roleText.setEnabled(true);
                                       return;
                       }
               }
               activity = null;
               nameText.setText("");
               roleText.setText("");
               nameText.setEnabled(false);
               roleText.setEnabled(false);
       }

We now have a working section. Hopefully.

We need to make sure that the changes in the text fields are reflected in the EAnnotation. To do this, we need to add a ModifyListener on the text fields. Plus we need to create a command or use an existing one to do the job of modifying the resource in a transaction. We choose to create our own command, we could also have used a chain of commands with EMF.

       /**
        * Utility class that finds the files and the editing domain easily,
        * Abstractas the doExecuteWithResult method needs to be implemented.
        * @author <a href="mailto:hmalphettes@intalio.com">Hugues Malphettes</a>
        * @author <a href="mailto:atoulme@intalio.com">Antoine Toulmé</a>
        * @author <a href="http://www.intalio.com">© Intalio, Inc.</a>
        */
       private abstract class ModifyParticipantEAnnotationCommand extends AbstractTransactionalCommand {
       
       public ModifyParticipantEAnnotationCommand(Activity ann, String label) {
                super((TransactionalEditingDomain) AdapterFactoryEditingDomain.getEditingDomainFor(ann), label, getWorkspaceFiles(ann));
       }


We implement our text listener directly in the class.

      /**
        * Tracks the change occuring on the text field.
        * @author <a href="http://www.intalio.com">Hugues Malphettes</a>
        * @author <a href="http://www.intalio.com">Antoine Toulmé</a>
        * @author <a href="http://www.intalio.com">© Intalio, Inc.</a>
        */
      private class ModifyParticipantInformation implements ModifyListener {
               private String key;
               private Text field;
               
               public ModifyParticipantInformation(String k, Text field) {
                       key = k;
                       this.field = field;
               }
                                       
               public void modifyText(ModifyEvent e) {
                       if (activity == null) { // the value was just initialized
                               return;
                       }
                       ModifyParticipantEAnnotationCommand command = 
                               new ModifyParticipantEAnnotationCommand(activity, "Modifying participant") {
                                       
                               @Override
                               protected CommandResult doExecuteWithResult(IProgressMonitor arg0, IAdaptable arg1) throws ExecutionException {
                                       EAnnotation annotation  = activity.getEAnnotation(ParticipantConstants.PARTICIPANT_ANNOTATION);
                                       if (annotation == null) {
                                               annotation = EcoreFactory.eINSTANCE.createEAnnotation();
                                               annotation.setSource(ParticipantConstants.PARTICIPANT_ANNOTATION);
                                               annotation.setEModelElement(activity);
                                               annotation.getDetails().put(ParticipantConstants.PARTICIPANT_NAME, "");
                                               annotation.getDetails().put(ParticipantConstants.PARTICIPANT_ROLE, "");
                                       }
                                       annotation.getDetails().put(key, field.getText());
                                       
                                       return CommandResult.newOKCommandResult();
                               }};
                               try {
                                       command.execute(new NullProgressMonitor(), null);
                               } catch (ExecutionException exception) {
                                       STPEclipseConPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, STPEclipseConPlugin.PLUGIN_ID, IStatus.ERROR, exception.getMessage(), exception));
                               }
               }
      }


The trick is to create the EAnnotation if it doesn't exist yet.

The logical next step is to add the listener to the text fields as we initialize them in the createPartControl method.

nameText.addModifyListener(new ModifyParticipantInformation(ParticipantConstants.PARTICIPANT_NAME, nameText));
roleText.addModifyListener(new ModifyParticipantInformation(ParticipantConstants.PARTICIPANT_ROLE, roleText));

Showing your annotation on the diagram

Now, we want the annotation to appear on the diagram.

We need to implement the decorator extension point to do that.

  <extension
        point="org.eclipse.stp.bpmn.diagram.EAnnotationDecorator">
     <decorator
           class="org.eclipse.stp.samples.eclipsecon2007.participant.drop.ParticipantDecorator"
           source="participant"/>
  </extension>

The ParticipantDecorator class is implementing the IEAnnotationDecorator interface.

Create your own implementation of the decorator :

In the decorator, you will need to give the source of the EAnnotations the decorator will decorate:

       public String getAssociatedAnnotationSource() {
               return ParticipantConstants.PARTICIPANT_ANNOTATION;
       } 

You can choose where the decoration will appear on the shape (whatever constant defined by Direction is supported):

       public Direction getDirection(EditPart part, EModelElement elt, EAnnotation ann) {
              return Direction.SOUTH_EAST;
       }

The decoration itself will be constituted into an image that you create in this method:

       public Image getImage(EditPart part, EModelElement element, EAnnotation annotation) {
               ImageDescriptor desc = STPEclipseConPlugin.imageDescriptorFromPlugin(STPEclipseConPlugin.PLUGIN_ID, "icons/participant.gif");
               return desc == null ? null : desc.createImage();
       }

Finally you can show a IFigure object that will appear as the tooltip of the decoration.

We choose to show a simple label, we could do something more complicated.

      public IFigure getToolTip(EditPart part, EModelElement element, EAnnotation annotation) {
               String name = (String) annotation.getDetails(). get(ParticipantConstants.PARTICIPANT_NAME);
               String role = (String) annotation.getDetails(). get(ParticipantConstants.PARTICIPANT_ROLE);
               return new Label("Performed by " + name + " (" + role + ")");
      }


Adding an annotation through a drag and drop action

We want to have some more interaction now, and the best way to do that for the end-user is to do some drag and drop on the diagram.

We are going to use a Participant view that will be complete enough to represent some participants. We will see how to drop them on the diagram just next.

The participant view

We are going to implement a simple tree viewer view.

In the plugin.xml:

 Definition of the view for the participants
 <extension point="org.eclipse.ui.views">
    <view class="org.eclipse.stp.samples.eclipsecon2007.participant.view.ParticipantView"
        id="org.eclipse.stp.samples.eclipsecon2007.participantView"
        name="Participants"/>
 </extension>

The view should extend ViewPart.

We only care about creating some content in there, so we will only implement createPartControl:

     public void createPartControl(Composite parent) {

tree = new TreeViewer(parent);

We need a content provider for the tree. Here is a simple content provider with some static content:

        /**
         * a static content provider representing some simple participants.
         * @author <a href="http://www.intalio.com">Hugues Malphettes</a>
         * @author <a href="http://www.intalio.com">Antoine Toulmé</a>
         * @author <a href="http://www.intalio.com">© Intalio, Inc.</a>
         */
        private class ParticipantContentProvider implements ITreeContentProvider {
   
                 /**
                  * The String representing the root of the tree.
                  */
                 private String ROOT = "Participants";
                 /**
                  * Adds some static children under the root,
                 */
                 public Object[] getChildren(Object parentElement) {
                          if (ROOT.equals(parentElement)) {
                                   return new Object[] {
                                            new ParticipantImpl("Hugues", "Developer"),
                                            new ParticipantImpl("Antoine", "Developer"),
                                            new ParticipantImpl("Janet", "attendee"),
                                            new ParticipantImpl("John", "attendee"),
                                            new ParticipantImpl("Denis", "Eclipse Organization"),
                                            new ParticipantImpl("Vanessa", "Eclipse Organization")
                                   };
                          }
                 return null;
                 }
        
                 public Object getParent(Object element) {
                          return ROOT;
                 }
        
                 public boolean hasChildren(Object element) {
                          if (ROOT.equals(element)) {
                                   return true;
                          }
                          return false;
                 }
        
                 public Object[] getElements(Object inputElement) {
                          return new Object[] {ROOT};
                 }
        
                 public void dispose() {
                 // not implemented
                 }
        
                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
                 // not implemented   	
                 }
        }