Génération d'un éditeur graphique à partir d'un modèle EMF avec Eclipse GMF

Serge Bachmann

Cet article s'intéresse à la génération d'un éditeur graphique à partir d'un modèle EMF en utilisant la brique Eclipse GMF (Graphical Modeling Project).

Pour réagir à cet article, un espace de dialogue vous est proposé sur le forum Commentez .

- Titre : Génération d'un éditeur graphique à partir d'un modèle EMF avec Eclipse GMF

- Auteur : Serge Bachmann

- Parution : 2 juillet 2012

- Licence : Le contenu de cet article est rédigé par Serge Bachmann et est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.

Sommaire

- I. Introduction

- I-A. Spécification

- I-B. Lancer la plateforme

- I-C. Passer en perspective « Ecore »

- II. Installation « Graphical Modeling Framework »

- III. Création d'un projet GMF

- IV. Création d'un modèle EMF

- V. Génération de l'éditeur graphique

- V-A. Sélectionner « Domain Model » (Fichier : *.ecore)

- V-B. Dériver « Domain Gen Model » (Fichier : *.genmodel)

- V-C. Générer le code

- V-D. Générer « Tooling Def Model » (Fichier : *.gmftool)

- V-E. Générer « Graphical Def Model » (Fichier : *.gmfgraph)

- V-F. Éditer « Graphical Def Model »

- V-F-1. Ajout des flèches « > » en bout d'arc

- V-F-2. Visualisation des nœuds elliptiques

- V-G. Générer « Mapping Model » (Fichier : *.gmfmap)

- V-G-1. Modifier le « Mapping »

- V-G-2. Éditer les propriétés du « mapping »

- V-H. Éditer « Graphe.gmfmap »

- V-H-1. Affichage nom de l'arc

- V-I. Générer « Diagram Editor Gen Model » (Fichier : *.gmfgen)

- V-J. Générer l'éditeur de diagramme

- VI. Test de l'éditeur

- VI-A. Créer une configuration d'exécution

- VI-B. Créer un projet

- VI-C. Éditer un graphe

- VII. Accès au modèle édité

- VII-A. Création de la commande « View Model »

- VII-A-1. Création d'un « package » pour recevoir le code de la commande

- VII-A-2. Création de l'arbre des extensions

- VII-A-3. Le code du « handler »

- VII-B. Test

- VIII. Conclusions et remerciements

- IX. Licence

I - Introduction

I-A - Spécification

À partir d'un modèle EMF de graphes précédemment défini, nous souhaitons développer un éditeur graphique de graphes. Le projet GMF (Graphical Modeling Project) fournit des outils qui facilitent ce développement en s'appuyant sur une génération de code.

I-B - Lancer la plateforme

Double-cliquer : ou le raccourci vers cet exécutable si vous l'avez créé dans le répertoire destiné à recevoir les « workspaces ». La plate-forme « Eclipse » est lancée :

Choisir le workspace :

Cliquer « OK ». Fermer la fenêtre « Welcome ».

I-C - Passer en perspective « Ecore »

Depuis le menu « Window », sélectionner le sous-menu « Open Perspective » et cliquer sur « Other... » :

Sélectionner :

Agencer la perspective « Ecore » de façon à obtenir l'aspect suivant :

II - Installation « Graphical Modeling Framework »

Sélectionner la commande « Help - Install Modeling Components » :

Dans « Eclipse Modeling Components Discovery - Eclipse Modeling Components Discovery », sélectionner « Graphical Modeling Framework Tooling » puis cliquer sur le bouton « Finish » :

Confirmer l'installation de « Graphical Modeling Framework SDK » :

Cliquer sur le bouton « Next > »

Cliquer sur le bouton « Next > » et accepter la licence :

Le logiciel procède à l'installation des extensions :

Cliquer sur « OK » pour le message de sécurité :

Cliquer sur le bouton « Restart Now » :

Garder le Workspace utilisé avant le redémarrage :

Cliquer sur le bouton « OK ».

III - Création d'un projet GMF

Depuis le menu « File », cliquer sur le sous-élément « Project... » :

Sélectionner ensuite l'élément « New GMF Project » :

Cliquer sur le bouton « Next > », nommer ensuite le projet :

Cliquer sur le bouton « Next > » puis sélectionner « Show dashboard view » :

Cliquer sur le bouton « Finish », nous obtenons finalement :

La vue « GMF Dashboard » nous guidera dans le processus de création de l'éditeur graphique.

La première étape consiste à créer un modèle EMF. Nous utiliserons celui défini dans l'article précédent Édition graphique d'un modèle EMF : application à un modèle de graphe.

IV - Création d'un modèle EMF

Ouvrir le projet « exemple.graphe.gmf ». Nous créons le modèle EMF de graphes dans le répertoire « model » :

Initialiser le champ « Domain file name » puis cliquer sur le bouton « Finish » :

Redimensionner si nécessaire la zone d'édition, ouvrir la vue « Properties », éditer le modèle puis faire une sauvegarde :

Le modèle « Graphe.ecore » peut être validé :

Un message nous indique la validité du modèle.

V - Génération de l'éditeur graphique

Pour cela nous allons utiliser le « Dashboard » :

V-A - Sélectionner « Domain Model » (Fichier : *.ecore)

Sélectionner le projet « exemple.graphe.gmf » puis cliquer « Select » dans :

Sélectionner le modèle « ecore » :

Cliquer sur le bouton « OK ».

V-B - Dériver « Domain Gen Model » (Fichier : *.genmodel)

Cliquer « Derive » :

Saisir dans le champ « File name », la valeur « Graphe.genmodel », puis cliquer sur le bouton « Next> » :

Sélectionner un modèle basé sur « ecore », puis cliquer sur le bouton « Next > » :

Cliquer sur le bouton « Load » puis sur le bouton « Next > » :

Ne pas modifier « New EMF Generator Model- Package Selection » :

Cliquer sur le bouton « Finish » pour obtenir le résultat suivant :

Dans le projet « exemple.graphe.gmf » sous model apparaît un nouveau fichier :

V-C - Générer le code

Le fichier « Graphe.genmodel » est un fichier de génération, vous pouvez l'ouvrir en édition si nécessaire. Utiliser la commande « Generate All » du menu contextuel de l'éditeur pour générer le code :

Le code généré est placé dans « exemple.graphe.gmf\src » et dans trois projets Eclipse :

Nous revenons au « GMF Dashboard ».

V-D - Générer « Tooling Def Model » (Fichier : *.gmftool)

Cliquer « Derive » :

Cliquer sur le bouton « Next > » :

Dans « New - Domain Model », cliquer « Load » et sélectionner « Graphe », puis cliquer sur le bouton « Next > » :

Dans « New - Tooling Definition », ne pas modifier la sélection et cliquer finalement sur le bouton « Finish » :

Le résultat obtenu est le suivant :

Le contenu du fichier « Graphe.gmftool » est le suivant :

V-E - Générer « Graphical Def Model » (Fichier : *.gmfgraph)

Cliquer « Derive » :

Dans le champ « File name » saisir la valeur « Graphe.gmfgraph », puis cliquer sur le bouton « Next > » :

Dans « New - Domain Model », cliquer « Load », sélectionner « Graphe » puis cliquer sur le bouton « Next > » :

Dans « New - Graphical Definition », conserver les choix proposés :

Cliquer sur le bouton « Finish ».

Si vous cliquez sur « Edit », vous pouvez visualiser le fichier « Graphe.gmfgraph » avec « GMFGraph model editor » :

V-F - Éditer « Graphical Def Model »

V-F-1 - Ajout des flèches « > » en bout d'arc

Pour cela nous allons éditer le fichier « Graphe.gmfgraph ». Si ce n'est déjà fait, sélectionner le projet « exemple.graphe.gmf ». Cliquer sur « Edit » :

Sélectionner l'élément « Polyline Decoration » comme suit :

L'élément suivant est créé :

Éditer la « property » « Name » de « Polyline Decoration » puis faire une sauvegarde :

Sélectionner l'élément de l'arbre « Polyline Connection ArcFigure ». Pour la propriété « Target Decoration », sélectionner la valeur « Polyline Decoration TargetDecoration » :

Finalement, faire une sauvegarde.

V-F-2 - Visualisation des nœuds elliptiques

Éditer dans le projet « exemple.graphe.gmf » le fichier « Graphe.gmfgraph ». Supprimer l'élément « Rectangle NoeudFigure » :

Créer à la place l'élément « Ellipse » comme suit :

Initialiser la propriété « Name » avec la valeur « Elipse », après avoir sauvegardé vous devriez obtenir :

Créer sous l'élément « Eclipse NoeudFigure » l'élément « Flow Layout » :

Ne pas modifier les propriétés et vous devriez obtenir le résultat suivant :

Sous « Ellipse NoeudFigure », créer un « Label » :

Initialiser les propriétés puis faire une sauvegarde :

Initialiser la propriété Figure de « Child Acces getFigureNull » en sélectionnant la valeur « Label NoeudNomFigure », puis faire une sauvegarde :

Finalement le fichier « Graphe.gmfgraph » devient :

Une version textuelle est donnée ci-dessous :

<?xml version="1.0" encoding="UTF-8"?>
<gmfgraph:Canvas xmi:version="2.0"
xmlns:xmi="http://www.omg.org/XMI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:gmfgraph="http://www.eclipse.org/gmf/2006/GraphicalDefinition" name="graphe">
<figures
name="Default">
<figures
xsi:type="gmfgraph:PolylineDecoration"
name="TargetDecoration"/>
<descriptors
name="NoeudFigure">
<actualFigure
xsi:type="gmfgraph:Ellipse"
name="NoeudFigure">
<layout
xsi:type="gmfgraph:FlowLayout"/>
<children
xsi:type="gmfgraph:Label"
name="NoeudNomFigure"
text="&lt;...>"/>
</actualFigure>
<accessors
accessor="getFigureNoeudNomFigure"
figure="//@figures.0/@descriptors.0/@actualFigure/@children.0"/>
</descriptors>
<descriptors
name="ArcFigure">
<actualFigure
xsi:type="gmfgraph:PolylineConnection"
name="ArcFigure"
targetDecoration="//@figures.0/@figures.0">
<children
xsi:type="gmfgraph:Label"
name="ArcNomFigure"
text="&lt;...>"/>
</actualFigure>
<accessors
figure="//@figures.0/@descriptors.1/@actualFigure/@children.0"/>
</descriptors>
</figures>
<nodes
name="Noeud"
figure="NoeudFigure"/>
<connections
name="Arc"
figure="ArcFigure"/>
<labels
name="NoeudNom"
figure="NoeudFigure"
accessor="//@figures.0/@descriptors.0/@accessors.0"/>
<labels
name="ArcNom"
figure="ArcFigure"
accessor="//@figures.0/@descriptors.1/@accessors.0"/>
</gmfgraph:Canvas>

V-G - Générer « Mapping Model » (Fichier : *.gmfmap)

Cliquer sur « Combine » :

Cliquer sur le bouton « Next > » :

Dans « Create GMFMap model - Select Domain Model », cliquer « Load » puis sélectionner « Graphe » :

Cliquer sur le bouton « Next > »

Cliquer sur le bouton « Load » puis sur le bouton « Next > » :

Le résultat obtenu est le suivant :

Remarque : si Arc apparaît avant Noeud dans Nodes la génération sera incorrecte. Aucune raison apparente n'explique cette inversion. Il faut reprendre la génération avec le « Dashboard ».

V-G-1 - Modifier le « Mapping »

1. Dans la zone « Links », pour chaque élément « origine » et « extremite » cliquer sur le bouton « Remove » pour les supprimer.

2. Dans la zone « Nodes », sélectionner l'élément « Arc » et cliquer sur le bouton « As link --> ».

Remarque: les commandes s'appliquent aux objets sélectionnés.

Le résultat attendu est le suivant :

Attention ne pas cliquer sur le bouton « Finish » tout de suite.

V-G-2 - Éditer les propriétés du « mapping »

Sélectionner dans la zone « Links » l'élément « Arc » et cliquer sur le bouton « Change... » :

Éditer les « properties » :

Cliquer sur le bouton « OK » :

Remarque: pour effectuer les mises à jour, cliquer la zone à initialiser :

Utiliser ensuite le bouton contenant le triangle pointé vers le bas pour faire apparaître toutes les possibilités.

Dans « Create GMFMap model - Mapping », cliquer sur le bouton « Finish ».

Le contenu du fichier « Graphe.gmfmap » est le suivant :

V-H - Éditer « Graphe.gmfmap »

Cliquer « Edit » :

V-H-1 - Affichage nom de l'arc

Cette modification a pour but d'afficher le nom des arcs. Faire un clic droit sur « LinkMapping... » et sélectionner « New Child > Feature Label Mapping » :

Le résultat obtenu est le suivant :

Sélectionner « Feature Label Mapping false » et initialiser ses propriétés, puis faire une sauvegarde :

Le fichier « Graphe.gmfmap » visualisé avec « GMFMap Model Editor » est le suivant :

La version textuelle de « Graphe.gmfmap » :

<?xml version="1.0" encoding="UTF-8"?>
<gmfmap:Mapping xmi:version="2.0"
xmlns:xmi="http://www.omg.org/XMI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
xmlns:gmfmap="http://www.eclipse.org/gmf/2008/mappings"
xmlns:gmftool="http://www.eclipse.org/gmf/2005/ToolDefinition">
<nodes>
<containmentFeature
href="Graphe.ecore#//Graphe/listeNoeuds"/>
<ownedChild>
<domainMetaElement
href="Graphe.ecore#//Noeud"/>
<labelMappings
xsi:type="gmfmap:FeatureLabelMapping">
<diagramLabel
href="Graphe.gmfgraph#NoeudNom"/>
<features
href="Graphe.ecore#//Noeud/nom"/>
</labelMappings>
<tool
xsi:type="gmftool:CreationTool"
href="Graphe.gmftool#//@palette/@tools.0/@tools.0"/>
<diagramNode
href="Graphe.gmfgraph#Noeud"/>
</ownedChild>
</nodes>
<links>
<domainMetaElement
href="Graphe.ecore#//Arc"/>
<labelMappings
xsi:type="gmfmap:FeatureLabelMapping"
editPattern="">
<diagramLabel
href="Graphe.gmfgraph#ArcNom"/>
<features
href="Graphe.ecore#//Arc/nom"/>
</labelMappings>
<containmentFeature
href="Graphe.ecore#//Graphe/listeArcs"/>
<tool
xsi:type="gmftool:CreationTool"
href="Graphe.gmftool#//@palette/@tools.0/@tools.1"/>
<diagramLink
href="Graphe.gmfgraph#Arc"/>
<sourceMetaFeature
xsi:type="ecore:EReference"
href="Graphe.ecore#//Arc/origine"/>
<linkMetaFeature
xsi:type="ecore:EReference"
href="Graphe.ecore#//Arc/extremite"/>
</links>
<diagram>
<diagramCanvas
href="Graphe.gmfgraph#graphe"/>
<domainModel
href="Graphe.ecore#/"/>
<domainMetaElement
href="Graphe.ecore#//Graphe"/>
<palette
href="Graphe.gmftool#//@palette"/>
</diagram>
</gmfmap:Mapping>

V-I - Générer « Diagram Editor Gen Model » (Fichier : *.gmfgen)

Cliquer « Transform » :

Nous obtenons le résultat :

Dans « model », l'affichage attendu doit être le suivant :

V-J - Générer l'éditeur de diagramme

Cliquer « Generate diagram editor » :

Le projet « exemple.graphe.gmf.diagram » est créé.

VI - Test de l'éditeur

VI-A - Créer une configuration d'exécution

Sélectionner le projet « exemple.graphe.gmf.diagram » et afficher la configuration d'exécution :

Créer la nouvelle configuration d'exécution de type : « Eclipse Application » en double-cliquant « Eclipse Application ». Nommer la configuration, cliquer sur le bouton « Apply » et exécuter la configuration d'exécution en cliquant sur le bouton « Run » :

Une nouvelle plateforme « Eclipse » est lancée avec pour « workspace » : « ...\runtime-GenerationEditeurGraphique ». Fermer ensuite la fenêtre « Welcome » et quelques vues afin d'obtenir le résultat suivant :

VI-B - Créer un projet

Créer un nouveau projet via le menu « File -> New -> Project... » :

Sélectionner l'élément « Project » :

Cliquer sur le bouton « Next > », puis nommer le projet « testEditGraphique » :

Cliquer sur le bouton « Finish ».

VI-C - Éditer un graphe

Ouvrir l'éditeur de construction de diagrammes « Graphe Diagram » via le menu « New -> Other... » :

Puis sélectionner l'élément Graphe Diagram :

Cliquer sur le bouton « Next > », nommer le diagramme « G1.graphe_diagram » puis cliquer sur le bouton « Next > » :

Conserver le nom du graphe « G1.graphe » :

Cliquer sur le bouton « Finish », éditer un graphe puis faire une sauvegarde.

VII - Accès au modèle édité

Nous souhaitons accéder au modèle édité afin de réaliser, par exemple, un traitement sur le modèle. Nous allons ainsi créer une commande qui affiche dans un message le graphe édité. À noter que pour des raisons de simplicité nous avons directement modifié le plugin généré. Toutefois afin d'avoir un diagramme GMF maintenable et évolutif, il n'est pas recommandé de toucher au code généré. Il est préférable de créer un plugin séparé contenant les modifications personnalisées.

VII-A - Création de la commande « View Model »

VII-A-1 - Création d'un « package » pour recevoir le code de la commande

Dans le projet « exemple.graphe.gmf.diagram », créer sous le dossier « src » un « package » destiné à recevoir le code (Handler) associé à la commande :

Nommer le package « monCode » puis cliquer sur « Finish » pour le créer.

VII-A-2 - Création de l'arbre des extensions

Pour créer la commande dans le projet « exemple.graphe.gmf.diagram » ouvrir le « plugin Manifest Editor » onglet « Extension » afin de compléter l'arbre des extensions avec :

Nous retrouvons l'ensemble des « Extension Details » associées dans le fichier « plugin.xml » :

<extension
point="org.eclipse.ui.commands">
<command
id="exemple.graphe.gmf.diagram.viewModel"
name="View Model">
</command>
</extension>
<extension
point="org.eclipse.ui.handlers">
<handler
class="monCode.ViewModel"
commandId="exemple.graphe.gmf.diagram.viewModel">
</handler>
</extension>
<extension
point="org.eclipse.ui.menus">
<menuContribution
allPopups="false"
locationURI="menu:org.eclipse.ui.main.menu?after=additions">
<menu
id="processModel"
label="Process Model">
<command
commandId="exemple.graphe.gmf.diagram.viewModel"
style="push">
</command>
</menu>
</menuContribution>
</extension>

Remarque : on peut directement éditer « plugin.xml » . Ne pas oublier de créer l'handler et de faire une sauvegarde générale.

VII-A-3 - Le code du « handler »

package monCode;

import java.util.Iterator;

import graphe.Arc;
import graphe.Noeud;
import graphe.diagram.navigator.GrapheDomainNavigatorItem;
import graphe.impl.GrapheImpl;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.commands.IHandlerListener;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.handlers.HandlerUtil;

publicclass ViewModel implements IHandler {

@Override
publicvoid addHandlerListener(IHandlerListener handlerListener) {
// TODO Auto-generated method stub

}

@Override
publicvoid dispose() {
// TODO Auto-generated method stub

}

Shell shell;

@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
shell = HandlerUtil.getActiveWorkbenchWindow(event).getShell();
ISelection selection = HandlerUtil.getCurrentSelection(event);
Object first = ((TreeSelection) selection).getFirstElement();
GrapheImpl graphe;
String nomGraphe;
try {
GrapheDomainNavigatorItem graf = (GrapheDomainNavigatorItem) first;
nomGraphe= (graf.getParent().toString()).substring(2);
graphe = (GrapheImpl)graf.getEObject();
} catch (Exception e) {
MessageDialog.openError(shell, "View Model",
"In view \"Project Explorer\" select: \"*.graphe/Graphe\"");
returnnull;
}
vueModel(nomGraphe, graphe);
returnnull;
}

privatevoid vueModel(String nomGraphe, GrapheImpl graphe){
String message = new String("Nom du graphe: "+ nomGraphe +"\n");
message += "Liste des noeuds\n";
EList<Noeud> listeNoeuds = graphe.getListeNoeuds();
Iterator<Noeud> in = listeNoeuds.iterator();
while (in.hasNext()){
Noeud n = in.next();
message += "   "+n.getNom()+"\n";
}
message += "Liste des arcs\n";
EList<Arc> listeArcs = graphe.getListeArcs();
Iterator<Arc> ia = listeArcs.iterator();
while (ia.hasNext()){
Arc a = ia.next();
message += "   "+a.getNom()+
"("+a.getOrigine().getNom()+
"->"+a.getExtremite().getNom()+")\n";
}
MessageDialog.openInformation(shell, "View Model", message);

}

@Override
publicboolean isEnabled() {
// TODO Auto-generated method stub
returntrue;
}

@Override
publicboolean isHandled() {
// TODO Auto-generated method stub
returntrue;
}

@Override
publicvoid removeHandlerListener(IHandlerListener handlerListener) {
// TODO Auto-generated method stub

}

}

VII-B - Test

On lance le test:

On retrouve le graphe précédemment édité. On ouvre « G1.graphe » et on sélectionne « Graphe »:

On sélectionne notre commande :

Le message suivant s'affiche :

Si la sélection ne correspond pas à un « Graphe », le message d'erreur ci-dessous est visualisé :

VIII - Conclusions et remerciements

Le « DashBoard » facilite le processus de génération de l'éditeur. Cependant, comme nous avons pu le voir, tout changement dans la représentation du graphe implique des modifications non triviales. Des solutions existent et peuvent être explorées par le lecteur :

- créer des figures Draw2D dans le GMFGraph. Un exemple d'implémentation est disponible ici ;

- créer des diagrammes GMF de manière graphique et donc de proposer une expérience utilisateur plus riche que le GMF Dashboard.

Nous tenons à remercier ClaudeLELOUP pour sa relecture attentive de cet article puis djibril et Keulkeul pour la mise au gabarit de l'article original. Enfin, nous tenons à remercier Aurélien Pupier, contributeur sur le projet Eclipse GMF-Runtime, pour ses commentaires techniques.

IX - Licence

La licence « Creative Commons » s'applique à ce document, veuillez-vous référer à ce site pour de plus amples informations : http://creativecommons.org/licenses/by-nc-nd/2.0/fr/.