juillet
2009
A l’étape du billet précédant [step8] nous avons représenté graphiquement les instances EMF ActionType par des carrées et StateType par des ellipses. Mais la synchronisation des couches Model/View n’est pas encore tout à fait terminée. En effet si vous saisissez du contenu XML dans la page Source ou dans un autre éditeur XML, vous pourrez constater que la vue graphique n’est pas reflétée. Si vous saisissez par exemple un nouvel élément XML state dans un éditeur XML, ce nouvel élément n’apparaît pas dans la page Graphics :
En effet à cette étape nous n’avons pas gérer le cas où les modèles EMF WorkflowTytpe, ActionType, StateType sont modifiés (via un éditeur). Dans ce billet nous allons expliquer comment détecter les modifications des modèles EMF et les refléter à l’éditeur GEF Graphics.
Vous pouvez télécharger le projet org.example.workflow_step9.zip présenté dans ce billet.
GEF EditPart – Model changed
Pour rappel lorsque l’on saisit du contenu XML dans un editeur, celui-ci modifie son instance EMF associée. Par exemple lorsque l’on modifie l’attribut name de l’element XML action, ceci modifie la propriété ActionType#setName(String name) de l’instance EMF ActionType associée.
En GEF, lorsque le modèle change, la Vue doit être rafraichît. Dans le cas ou le modèle EMF ActionType#setName(String name) change, nous devons appeler ActionTypePart#refreshVisuals() pour rafraîchir la Vue Draw2d GEF. Nous devons pour cela détecter que la propriété ActionType#setName(String name) de l’instance EMF ActionType change. Heureusement EMF gère ce genre de problématique et il est possible de brancher un listener Adpater EMF qui permet d’écouter les changement du modèle. Un Adapter EMF joue le même rôle que les (comme les java.beans.PropertyChangeListener listeners utilisés dans un contexte de Java Bean.
Dans cette section chacun de nos EditPart WorkflowTypePart, ActionTypePart et StateTypePart brancheront des listeners (Adapter EMF) à leur modèle EMF pour détecter leur modification et rafraîchir la vue GEF Draw2d (via AbstractEditPart#refreshVisuals() et AbstractEditPart#refreshChildren()).
EMF Adapter
Si vous connaissez les Adapter EMF, vous pouvez passez cette section. Dans cette section nous allons montrer à travers un exemple simple comment utiliser les Adapter EMF pour détecter la modification de propriété name ActionType#steName(String name) d’une instance EMF ActionType. Les tests sont effectués dans le package org.example.workflow.test.adapaters dans le répertoire test du projet org.example.workflow.
EMF fournit une interface EMF org.eclipse.emf.common.notify.Adapter que l’on doit implémenter. Un Adapter EMF joue le même rôle que
les listeners java.beans.PropertyChangeListener. Voici un tableau de simililutde :
EMF Adapter | Bean PropertyChangeListener |
---|---|
Classe org.eclipse.emf.common.notify.Adapter | Classe java.beans.PropertyChangeListener |
Adapter#notifyChanged(org.eclipse.emf.common.notify.Notification notification) | PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent event) |
org.eclipse.emf.common.notify.Notification | java.beans.PropertyChangeEvent |
Nous allons créer un exemple qui permet de détecter (en affichant une trace dans la console Eclipse) les modifications du modèle EMF d’une instance EMF ActionType en modifiant sa propriété name.
Créer la classe EMF Adapter org.example.workflow.test.adapters.EMFAdapterAction comme suit :
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.example.workflow.model.ActionType;
public class EMFAdapterAction implements Adapter {
private Notifier target;
public void notifyChanged(Notification notification) {
// EMF Model ActionType changed
System.out.println("EMF Model ActionType changed");
System.out.println(notification);
}
public void setTarget(Notifier target) {
this.target = target;
}
public Notifier getTarget() {
return target;
}
public boolean isAdapterForType(Object type) {
return ActionType.class == type;
}
}
Le code :
// EMF Model ActionType changed
System.out.println("EMF Model ActionType changed");
System.out.println(notification);
}
permettra d’afficher dans la console les modifications du modèle EMF.
Créer la classe de test org.example.workflow.test.adapters.EMFAdapterActionTypeTest comme suit :
import org.eclipse.emf.common.notify.Adapter;
import org.example.workflow.model.ActionType;
import org.example.workflow.model.WorkflowFactory;
public class EMFAdapterActionTypeTest {
public static void main(String[] args) {
// 1) Create EMF ActionType instance
ActionType action = WorkflowFactory.eINSTANCE.createActionType();
// 2) Create EMF Adapter Action
Adapter emfAdapterAction = new EMFAdapterAction();
// 3) Add EMF Adapter Action
action.eAdapters().add(emfAdapterAction);
// 4) Change
action.setName("a1");
// 5) Remove EMF Adapter Action
action.eAdapters().remove(emfAdapterAction);
}
}
Ce code montre comment ajouter un Adapter EMF (listener) à l’instance EMF ActionType :
action.eAdapters().add(emfAdapterAction);
Lancer le test et vous verrez dans la console la trace suivante :
org.eclipse.emf.ecore.impl.ENotificationImpl (eventType: SET, position: -1, notifier: org.example.workflow.model.impl.ActionTypeImpl (name: a1), feature: org.eclipse.emf.ecore.impl.EAttributeImpl (name: name) (ordered: true, unique: true, lowerBound: 1, upperBound: 1) (changeable: true, volatile: false, transient: false, defaultValueLiteral: null, unsettable: false, derived: false) (iD: false), oldValue: null, newValue: a1, isTouch: false, wasSet: false)
EMF Model ActionType changed
org.eclipse.emf.common.notify.impl.BasicNotifierImpl$EAdapterList$1@6b97fd (eventType: REMOVING_ADAPTER, touch: true, position: 0, notifier: org.example.workflow.model.impl.ActionTypeImpl (name: a1), feature: null, oldValue: org.example.workflow.test.EMFAdapterAction, newValue: null, isTouch: true, wasSet: false)
Comme vous pouvez le constater le listener est déclenché 2 fois :
- lorsque la propriété name de l’instance EMF change :
action.setName("a1");
- lorsque l’Adapter EMF est enlevé de l’instance EMF :
action.eAdapters().remove(emfAdapterAction);
Il est important d’enlever l’Adapter EMF lorsque l’on n’en a plus besoin :
action.eAdapters().remove(emfAdapterAction);
Dans notre cas nous souhaitons uniquement détecter la modification de la propriété name de l’instance EMF. Pour cela modifier la méthode EMFAdapterAction#notifyChanged(Notification notification) comme suit :
int type = notification.getEventType();
int featureId = notification.getFeatureID(WorkflowPackage.class);
switch (type) {
case Notification.SET:
switch (featureId) {
case WorkflowPackage.ACTION_TYPE__NAME:
// EMF Model ActionType#setName() changed
System.out.println("EMF Model ActionType#setName() changed");
System.out.println(notification);
break;
}
}
}
Re-lancez le test et vous verrez dans la console la trace suivante :
org.eclipse.emf.ecore.impl.ENotificationImpl (eventType: SET, position: -1, notifier: org.example.workflow.model.impl.ActionTypeImpl (name: a1), feature: org.eclipse.emf.ecore.impl.EAttributeImpl (name: name) (ordered: true, unique: true, lowerBound: 1, upperBound: 1) (changeable: true, volatile: false, transient: false, defaultValueLiteral: null, unsettable: false, derived: false) (iD: false), oldValue: null, newValue: a1, isTouch: false, wasSet: false)
Vous pouvez constater qu’une seule trace est affichée et que l’on détecte uniquement la modification de la proprété name de l’instance EMF ActionType.
Le test sur le type Notification.SET permet d’indiquer si la modification est du à un « sette » d’une valeur. Il y a d’autres valeurs comme Notification.ADD, Notification.REMOVE qui permet d’identifier dans le cas des collections si un item a été ajouté/supprimé.
Le test sur featureId WorkflowPackage.ACTION_TYPE__NAME indique que la propriété de l’instance EMF ActionType qui a été modifiée est la propriété name.
EditPart – EMF Adapter
Les 3 EditPart (qui gère chacun une instance EMF modèle) WorkflowTypePart, ActionTypePart et StateTypePart doivent ajouter un Adapter EMF sur leur modèle pour ensuite rafraîchir la vue selon la propriété du modèle EMF qui change. Dans notre cas nos EditPart joueront le rôle d’Adapter EMF en implémentant l’interface org.eclipse.emf.common.notify.Adapter. Pour cela nous pouvons créer un classe abstraite EditPart commune (qui pourrait être utilisé dans n’importe quel projet GEF qui aurrait un modèle EMF) qui implémente l’interface org.eclipse.emf.common.notify.Adapter et qui ajoute/supprime l’Adapter EMF a son modèle :
- l’ajout de l’Adapter EMF au modèle EMF peut s’effectuer dans la méthode EditPart#activate(),méthode qui est appelée par le GraphicalViewer GEF lorsque l’EditPart devient actif.
- la suppression de l’Adapter EMF au modèle EMF peut s’effectuer dans la méthode EditPart#deactivate(), méthode qui est appelée par le GraphicalViewer GEF lorsque l’EditPart n’est plus utilisé.
Pour cela créer la classe org.example.workflow.presentation.graphical.parts.AbstractEMFModelGraphicalEditPart comme suit :
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
public abstract class AbstractEMFModelGraphicalEditPart extends
AbstractGraphicalEditPart implements Adapter {
private Notifier target;
/**
* Upon activation, attach to the model element as a property change
* listener.
*/
public void activate() {
if (!isActive()) {
hookIntoModel(getModel());
super.activate();
}
}
/**
* Upon deactivation, detach from the model element as a property change
* listener.
*/
public void deactivate() {
if (isActive()) {
unhookFromModel(getModel());
super.deactivate();
}
}
private void hookIntoModel(EObject model) {
if (model != null) {
model.eAdapters().add(this);
}
}
private void unhookFromModel(EObject model) {
if (model != null) {
model.eAdapters().remove(this);
}
}
@Override
public EObject getModel() {
return (EObject) super.getModel();
}
// EMF Adapter
public Notifier getTarget() {
return target;
}
public void setTarget(Notifier newTarget) {
target = newTarget;
}
public boolean isAdapterForType(Object type) {
return (getModel().getClass() == type);
}
}
AbstractEMFModelGraphicalEditPart implémente l’interface Adapter EMF et permet d’ajouter/supprimer un Adapter EMF au modèle EMF géré par l’EditPart. La méthode Adapter#notifyChanged(Notification notification) n’est pas implémentée ici, ce sont les EditPart qui l’hériteront (WorkflowTypePart, ActionTypePart, SateTypePart) qui implémenteront cette méthode et rafraîchiront la vue Draw2d en fonction des modification des propriétés du modèle EMF.
ActionTypePart – EMF Adapter
A cette étape si vous relancez le plugin et que vous modifiez l’attribut name de l’élement XML action (par a2), vous pourrez constater que la vue GEF n’est pas synchronisée avec le modèle :
Ici nous allons gérer la modification du modèle EMF des instance EMF ActionType. Pour cela la classe ActionTypePart doit hériter de notre classe AbstractEMFModelGraphicalEditPart et implémenter Adapter#notifyChanged(Notification notification) :
public class ActionTypePart extends AbstractEMFModelGraphicalEditPart {...
Implémentez la méthode Adapter#notifyChanged(Notification notification) comme suit :
int type = notification.getEventType();
int featureId = notification.getFeatureID(WorkflowPackage.class);
switch (type) {
case Notification.SET:
switch (featureId) {
case WorkflowPackage.ACTION_TYPE__NAME:
refreshVisuals();
break;
}
}
}
Comme vous pouvez le remarquer, la méthode ActionTypePart#refreshVisuals() est appelée lorsque la propriété name du modèle EMF ActionType change. Voici le code complet de la classe :
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.gef.GraphicalEditPart;
import org.example.workflow.model.ActionType;
import org.example.workflow.model.WorkflowPackage;
import org.example.workflow.presentation.graphical.figures.ActionTypeFigure;
public class ActionTypePart extends AbstractEMFModelGraphicalEditPart {
@Override
protected IFigure createFigure() {
return new ActionTypeFigure();
}
@Override
protected void createEditPolicies() {
}
@Override
protected void refreshVisuals() {
super.refreshVisuals();
int x = new Double(Math.random() * 400).intValue();
int y = new Double(Math.random() * 400).intValue();
Rectangle bounds = new Rectangle(x, y, 50, 50);
((GraphicalEditPart) getParent()).setLayoutConstraint(this,
getFigure(), bounds);
ActionType action = getAction();
ActionTypeFigure figure = (ActionTypeFigure) getFigure();
figure.setName(action.getName());
}
public ActionType getAction() {
return (ActionType) super.getModel();
}
public void notifyChanged(Notification notification) {
int type = notification.getEventType();
int featureId = notification.getFeatureID(WorkflowPackage.class);
switch (type) {
case Notification.SET:
switch (featureId) {
case WorkflowPackage.ACTION_TYPE__NAME:
refreshVisuals();
break;
}
}
}
}
Relancez le plugin. Modifier la valeur de l’attribut name de l’element action par la valeur « a2″. La vue GEF doit se rafraîchir :
MAIS il arrive que certaines fois (?), la vue ne se rafraîchit pas. J’ai passé un temps considérable à detecter ce problème.
GraphicalWorkflowEditor – EMF Resource
Le problème vient du fait que certaines fois (je n’ai pas réussi à trouver pourquoi pour l’instant), la méthode WorkflowEditor#handleChangedResources() est appelée. Cette méthode est générée par EMF.Edit et décharge la ressource EMF puis la recharge lorsque l’editeur considère qu’il y a une modification du contenu XML :
if (isDirty()) {
changedResources.addAll(editingDomain.getResourceSet().getResources());
}
editingDomain.getCommandStack().flush();
updateProblemIndication = false;
for (Resource resource : changedResources) {
if (resource.isLoaded()) {
resource.unload();
try {
resource.load(Collections.EMPTY_MAP);
...
Mais je ne suis pas arrivé à comprendre à ce jour, pourquoi l’éditeur considère qu’il y a une modification du contenu XML? Le fait de décharger la resource EMF, supprime tous les Adapter EMF enregistrés pré-alablement. C’est pour cette raison que la vue GEF ne se synchronise plus (car nos Adapter EMF n’existe plus). Pour résoudre ce problème, mon idée a été de rafraichir le GraphicalViewer lorsque la resource EMF se charge (via le code resource.load(Collections.EMPTY_MAP);
).
Il est heursement possible d’ajouter un Adapter EMF à la resource EMF pour détecter le chargement/décharment de la resource EMF. Pour effectuer ce que je viens d’expliquer, ajouter la méthode privée GraphicalWorkflowEditor#synchronizeModelWhenEMFResourceChanged dans la classe GraphicalWorkflowEditor :
EditingDomain editingDomain = ((IEditingDomainProvider) parent)
.getEditingDomain();
Resource resource = editingDomain.getResourceSet().getResources()
.get(0);
resource.eAdapters().add(new AdapterImpl() {
@Override
public void notifyChanged(Notification notification) {
int featureID = notification.getFeatureID(Resource.class);
if (featureID == Resource.RESOURCE__IS_LOADED) {
boolean isLoaded = notification.getNewBooleanValue();
if (isLoaded) {
GraphicalViewer viewer = getGraphicalViewer();
viewer.setContents(getWorkflow());
}
}
}
});
}
Puis appelez cette méthode dans le constructeur :
super.setEditDomain(new DefaultEditDomain(this));
this.parent = parent;
synchronizeModelWhenEMFResourceChanged();
}
Voici le code complet de GraphicalWorkflowEditor:
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.domain.IEditingDomainProvider;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette;
import org.eclipse.ui.IEditorPart;
import org.example.workflow.model.WorkflowType;
import org.example.workflow.presentation.graphical.parts.WorkflowPartFactory;
public class GraphicalWorkflowEditor extends GraphicalEditorWithFlyoutPalette {
private IEditorPart parent;
public GraphicalWorkflowEditor(IEditorPart parent) {
super.setEditDomain(new DefaultEditDomain(this));
this.parent = parent;
synchronizeModelWhenEMFResourceChanged();
}
@Override
protected void configureGraphicalViewer() {
super.configureGraphicalViewer();
GraphicalViewer viewer = getGraphicalViewer();
viewer.setEditPartFactory(WorkflowPartFactory.INSTANCE);
}
@Override
protected void initializeGraphicalViewer() {
super.initializeGraphicalViewer();
GraphicalViewer viewer = getGraphicalViewer();
viewer.setContents(getWorkflow()); // set the contents of this
// editor
}
protected WorkflowType getWorkflow() {
EditingDomain editingDomain = ((IEditingDomainProvider) parent)
.getEditingDomain();
Resource resource = editingDomain.getResourceSet().getResources()
.get(0);
return (WorkflowType) resource.getContents().get(0);
}
@Override
protected PaletteRoot getPaletteRoot() {
return null;
}
@Override
public void doSave(IProgressMonitor monitor) {
}
private void synchronizeModelWhenEMFResourceChanged() {
EditingDomain editingDomain = ((IEditingDomainProvider) parent)
.getEditingDomain();
Resource resource = editingDomain.getResourceSet().getResources()
.get(0);
resource.eAdapters().add(new AdapterImpl() {
@Override
public void notifyChanged(Notification notification) {
int featureID = notification.getFeatureID(Resource.class);
if (featureID == Resource.RESOURCE__IS_LOADED) {
boolean isLoaded = notification.getNewBooleanValue();
if (isLoaded) {
GraphicalViewer viewer = getGraphicalViewer();
viewer.setContents(getWorkflow());
}
}
}
});
}
}
ActionTypePart – Repositionnement
Lorsque l’on modifie le nom name d’une action, la figure se repositionne. Ceci est du au fait que la méthode refreshVisuals (qui est maintenant appelé lorsque le nom name de l’action est modifiée) recalcule les positions. Pour éviter cela, les positions doivent être calculées une seule fois. Modifier le code de ActionTypePart comme suit :
private int x = new Double(Math.random() * 400).intValue();
private int y = new Double(Math.random() * 400).intValue();
...
Voci le code complet de ActionTypePart :
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.gef.GraphicalEditPart;
import org.example.workflow.model.ActionType;
import org.example.workflow.model.WorkflowPackage;
import org.example.workflow.presentation.graphical.figures.ActionTypeFigure;
public class ActionTypePart extends AbstractEMFModelGraphicalEditPart {
private int x = new Double(Math.random() * 400).intValue();
private int y = new Double(Math.random() * 400).intValue();
@Override
protected IFigure createFigure() {
return new ActionTypeFigure();
}
@Override
protected void createEditPolicies() {
}
@Override
protected void refreshVisuals() {
super.refreshVisuals();
Rectangle bounds = new Rectangle(x, y, 50, 50);
((GraphicalEditPart) getParent()).setLayoutConstraint(this,
getFigure(), bounds);
ActionType action = getAction();
ActionTypeFigure figure = (ActionTypeFigure) getFigure();
figure.setName(action.getName());
}
public ActionType getAction() {
return (ActionType) super.getModel();
}
public void notifyChanged(Notification notification) {
int type = notification.getEventType();
int featureId = notification.getFeatureID(WorkflowPackage.class);
switch (type) {
case Notification.SET:
switch (featureId) {
case WorkflowPackage.ACTION_TYPE__NAME:
refreshVisuals();
break;
}
}
}
}
StateTypePart – EMF Adapter
A cette étape si vous relancez le plugin et que vous modifiez l’attribut name d’un élement XML state (remplacé s2 par s3), vous pourrez constater que la vue GEF n’est pas synchronisée avec le modèle :
Pour effectuer ceci nous allons procéder comme l’EditPart ActionTypePart. Modifier la classe StateTypePart comme ceci :
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.gef.GraphicalEditPart;
import org.example.workflow.model.StateType;
import org.example.workflow.model.WorkflowPackage;
import org.example.workflow.presentation.graphical.figures.StateTypeFigure;
public class StateTypePart extends AbstractEMFModelGraphicalEditPart {
private int x = new Double(Math.random() * 400).intValue();
private int y = new Double(Math.random() * 400).intValue();
@Override
protected IFigure createFigure() {
return new StateTypeFigure();
}
@Override
protected void createEditPolicies() {
}
@Override
protected void refreshVisuals() {
super.refreshVisuals();
Rectangle bounds = new Rectangle(x, y, 50, 50);
((GraphicalEditPart) getParent()).setLayoutConstraint(this,
getFigure(), bounds);
StateType State = getState();
StateTypeFigure figure = (StateTypeFigure) getFigure();
figure.setName(State.getName());
}
public StateType getState() {
return (StateType) super.getModel();
}
public void notifyChanged(Notification notification) {
int type = notification.getEventType();
int featureId = notification.getFeatureID(WorkflowPackage.class);
switch (type) {
case Notification.SET:
switch (featureId) {
case WorkflowPackage.STATE_TYPE__NAME:
refreshVisuals();
break;
}
}
}
}
Si vous relancez le plugin vous pourrez constater que si vous modifiez le nom name d’un state dans l’editeur XML, la vue GEF est bien synchronisée :
WorkflowTypePart – EMF Adapter
A cette étape si vous relancez le plugin et que vous tentez de supprimer/ajouter un state ou action dans l’éditeur XML, la vue GEF n’est pas synchronisée. La copie d’écran ci-dessus montre que l’ajout d’un nouvel élement state n’est pas reflétée dans la vue GEF :
Pour gérer ceci nous devons procéder comme l’EditPart ActionTypePart ou StateTypePart à la différence que :
- l’Adapter EMF doit écouter les ajouts/suppressions d’instances EMF ActionType/StateType au modèle EMF WorkflowType.
- la vue GEF doit être rafraichît via la méthode WorkflowTypePart#refreshChildren() (et pas refreshVisuals()) pour rafrîchir ses EditPart enfants (ActionTypePart et StateTypePart).
Pour cela modifiez le code de WorkflowTypePart comme suit :
import java.util.ArrayList;
import java.util.List;
import org.eclipse.draw2d.IFigure;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.example.workflow.model.WorkflowPackage;
import org.example.workflow.model.WorkflowType;
import org.example.workflow.presentation.graphical.figures.WorkflowTypeFigure;
public class WorkflowTypePart extends AbstractEMFModelGraphicalEditPart {
@Override
protected IFigure createFigure() {
return new WorkflowTypeFigure();
}
@Override
protected void createEditPolicies() {
}
@Override
protected List<EObject> getModelChildren() {
WorkflowType workflow = getWorkflow();
List<EObject> models = new ArrayList<EObject>(workflow.getState());
models.addAll(workflow.getAction());
return models;
}
public WorkflowType getWorkflow() {
return (WorkflowType) super.getModel();
}
public void notifyChanged(Notification notification) {
int type = notification.getEventType();
int featureId = notification.getFeatureID(WorkflowPackage.class);
if (type == Notification.ADD || type == Notification.REMOVE) {
switch (featureId) {
case WorkflowPackage.WORKFLOW_TYPE__ACTION:
case WorkflowPackage.WORKFLOW_TYPE__STATE:
refreshChildren();
break;
}
}
}
}
Le test sur le type Notification.ADD, Notification.REMOVE permet d’identifier si un item ActionType/StateType a été ajoputé/supprimé.
Le test sur featureId WorkflowPackage.WORKFLOW_TYPE__ACTION permet de detecter que c’est une instance EMF ActyonType qui a été ajoutée/supprimée à l’instance EMF WorkflowType et featureId WorkflowPackage.WORKFLOW_TYPE__STATE permet de detecter que c’est une instance EMF StateType qui a été ajoutée/supprimée.
Relancez le plugin et vous pourrez constater que si vous ajoutez des elements XML state ou actions dans l’éditeur XML, la vue GEF sera reflétée correctement :
2 Commentaires + Ajouter un commentaire
Articles récents
- Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step5]
- Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step4]
- Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step3]
- Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step2]
- Conception d’un client Eclipse RCP et serveur OSGI avec Spring DM [step1]
Commentaires récents
- Conception d’un Editeur Eclipse de workflow XML [step 0] dans
- Conception d’un Editeur Eclipse de workflow XML [step 19] dans
- Conception d’un Editeur Eclipse de workflow XML [step 7] dans
- Conception d’un Editeur Eclipse de workflow XML [step 7] dans
- Conception d’un Editeur Eclipse de workflow XML [step 7] dans
Et bah dis donc, que d’eloge aujourd’hui. Merci ca fait plaisir:)
Encore Bravo!