Tutorial: GEF (Graphical Editing Framework) [Part 12]
Par Jean Charles MAMMANA, jeudi 02 août 2007 à 18:44 :: Programmation :: #28 :: rss
Nous avons la possibilite de creer graphiquement des services et des employes, en cliquant et dessinant ces entites mais ce n'est pas forcement tres convivial et tres pratique. Nous allons maintenant integrer une fonctionnalite indispensable dans toute interface moderne digne de ce nom : le bien nomme drag-and-drop (alias dnd).
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()));
}
}
{
// ...
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);
}
}
{
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")));
// ...
}
}
{
// ...
@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.

Commentaires
1. Le vendredi 03 août 2007 à 08:05, par Psykokwak
2. Le lundi 27 octobre 2008 à 10:01, par osy
Ajouter un commentaire