Presque tout va se passe dans notre editeur (MyGraphicalEditor). Ce que nous voulons faire, c'est pouvoir, depuis la palette, selectionner (drag-er) un element que l'on va poser (drop-er) dans notre editeur. La premiere (et a vrai dire, la seule chose a faire) est donc d'ajouter un listener particulier de type TemplateTransfertDragSourceListener sur notre palette et un listener de type TemplateTransferDropTargetListener sur notre editeur. Les noms sont transparents et parlent d'eux meme : il s'agit de templates de transfert (glisser d'un composant d'un element source x vers un element destination y, il y a bien transfert), l'un etant la source (mouvement de drag), l'autre la destination (mouvement de drop).

public class MyGraphicalEditor extends GraphicalEditorWithPalette
{
        // ...
        protected void initializeGraphicalViewer() {
                GraphicalViewer viewer = getGraphicalViewer();
                model = CreateEntreprise();
                viewer.setContents(model);
                viewer.addDropTargetListener(new MyTemplateTransferDropTargetListener(viewer));
        }
       
        @Override
        protected void initializePaletteViewer() {
                super.initializePaletteViewer();
                getPaletteViewer().addDragSourceListener(
                                new TemplateTransferDragSourceListener(getPaletteViewer()));
        }
}

Vous aurez probablement remarquer qu'on n'utilise pas directement un TemplateTransferDropTargetListener mais bel et bien notre propre version heritant de celle-ci. En effet, la notion de drop est totalement dependante du modele, elle ne peut donc pas, dans sa version generique, convenir a nos besoins specifiques et il va donc valoir surcharger cette classe. C'est parti !

public class MyTemplateTransferDropTargetListener extends TemplateTransferDropTargetListener
{
        public MyTemplateTransferDropTargetListener(EditPartViewer viewer) {
                super(viewer);
        }

        @Override
        protected CreationFactory getFactory(Object template) {
                return new NodeCreationFactory((Class<?>)template);
        }
}

Le seul point interessant dans ce bout de code est la factory, dont on retourne une instance lorsque l'on nous le demande. Dans le cadre de ce tuto, on utilise basiquement la Class de l'objet que l'on veut creer. Cependant, comme nous allons le voir juste apres, cet objet est utilise en tant que template. Il est donc probable et certainement conseille d'utiliser une instance modele d'un objet pour effectuer tout ce que nous avons vu jusqu'a maintenant. Nous ne l'avons pas fait ici car nos objets sont tres simples et ne necessitent pas d'informations particulieres venant d'un objet modele (le template) pour etre construit. Sachez donc adapter vos listeners et surtout vos CreationFactory en consequence.

Maintenant, il ne nous reste plus qu'une chose a faire : adapter les entrees de la palette a ce nouveau type d'interaction. Il existe un certain type de CreationToolEntry qui supporte, non seulement, la creation comme nous l'avons fait initialement mais egalement le drag-and-drop : CombinedTemplateCreationEntry.
public class MyGraphicalEditor extends GraphicalEditorWithPalette
{
        // ...
        @Override
        protected PaletteRoot getPaletteRoot()
        {
                // ...
                instGroup.add(new CombinedTemplateCreationEntry("Service", "Creation d'un service type",
                                Service.class, new NodeCreationFactory(Service.class),
                                AbstractUIPlugin.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/services-low.png"),
                                AbstractUIPlugin.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/services-high.png")));

                instGroup.add(new CombinedTemplateCreationEntry("Employe", "Creation d'un employe model",
                                Employe.class, new NodeCreationFactory(Employe.class),
                                AbstractUIPlugin.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/employe-low.png"),
                                AbstractUIPlugin.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/employe-high.png")));
                // ...
        }
}

La difference entre les deux prototypes est simple : il faut inserer l'objet template dont nous avons parle precedemment juste avant la factory. Dans notre cas et pour les raisons evoquees precedemment, nous inserons les Class des objets en question. Il ne reste plus qu'a tester !

Vous pouvez telecharger l'archive de ce tutorial ICI.
Tutorial rédigé par Romain MESON.