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

Image non disponible

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 5 commentaires Donner une note à l'article (5).

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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 : Image non disponibleou 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 :

Image non disponible

Choisir le workspace :

Image non disponible

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... » :

Image non disponible

Sélectionner :

Image non disponible

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

Image non disponible

II. Installation « Graphical Modeling Framework »

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

Image non disponible

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

Image non disponible

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

Image non disponible

Cliquer sur le bouton « Next > »

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

Cliquer sur le bouton « Restart Now » :

Image non disponible

Garder le Workspace utilisé avant le redémarrage :

Image non disponible

Cliquer sur le bouton « OK ».

III. Création d'un projet GMF

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

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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 » :

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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

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

Pour cela nous allons utiliser le « Dashboard » :

Image non disponible

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

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

Image non disponible

Sélectionner le modèle « ecore » :

Image non disponible

Cliquer sur le bouton « OK ».

Image non disponible

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

Cliquer « Derive » :

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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 :

Image non disponible

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

Image non disponible

Nous revenons au « GMF Dashboard ».

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

Cliquer « Derive » :

Image non disponible

Cliquer sur le bouton « Next > » :

Image non disponible

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

Image non disponible

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

Image non disponible

Le résultat obtenu est le suivant :

Image non disponible

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

Image non disponible

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

Cliquer « Derive » :

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

Cliquer sur le bouton « Finish ».

Image non disponible

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

Image non disponible

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 » :

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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 » :

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

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

Image non disponible

Finalement le fichier « Graphe.gmfgraph » devient :

Image non disponible

Une version textuelle est donnée ci-dessous :

 
Sélectionnez
<?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 » :

Image non disponible

Cliquer sur le bouton « Next > » :

Image non disponible

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

Image non disponible

Cliquer sur le bouton « Next > »

Image non disponible

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

Image non disponible

Le résultat obtenu est le suivant :

Image non disponible

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 :

Image non disponible

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... » :

Image non disponible

Éditer les « properties » :

Image non disponible

Cliquer sur le bouton « OK » :

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

Image non disponible

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 ».

Image non disponible

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

Image non disponible

V-H. Éditer « Graphe.gmfmap »

Cliquer « Edit » :

Image non disponible

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 » :

Image non disponible

Le résultat obtenu est le suivant :

Image non disponible

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

Image non disponible

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

Image non disponible

La version textuelle de « Graphe.gmfmap » :

 
Sélectionnez
<?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 » :

Image non disponible

Nous obtenons le résultat :

Image non disponible

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

Image non disponible

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

Cliquer « Generate diagram editor » :

Image non disponible
Image non disponible

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

Image non disponible

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 :

Image non disponible

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 » :

Image non disponible

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 :

Image non disponible

VI-B. Créer un projet

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

Image non disponible

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

Image non disponible

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

Image non disponible

Cliquer sur le bouton « Finish ».

VI-C. Éditer un graphe

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

Image non disponible

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

Image non disponible

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

Image non disponible

Conserver le nom du graphe « G1.graphe » :

Image non disponible

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

Image non disponible

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 :

Image non disponible

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

Image non disponible

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 :

Image non disponible

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

 
Sélectionnez
<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 »

 
Sélectionnez
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: Image non disponible

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

Image non disponible

On sélectionne notre commande :

Image non disponible

Le message suivant s'affiche :

Image non disponible

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

Image non disponible

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/.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Licence Creative Commons
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.