lundi, mai 25, 2009

J'ai besoin de ... connecter plusieurs Viewers d'une même vue au service de sélection

Dans la série des J'ai besoin de ... je m'intéresse dans ce billet à la manière de connecter plusieurs SelectionProvider d'une même vue au service de sélection. Les SelectionProvider désignent tous les objets de type Viewer (TableViewer, TreeViewer, ListViewer, ...).

La connexion au service du sélection est obtenue par l'intermédiaire du site de la vue (le site peut être vue comme un pont entre la vue et le Workbench). Le code suivant se trouve généralement dans la méthode createPartControl de la ViewPart de la vue :
getSite().setSelectionProvider(tableViewer)
Comme vous pouvez le constater, la méthode qui consiste à "connecter" le composant TableViewer ne permet pas d'ajouter plusieurs composants de type SelectionProvider. Par ailleurs, la plateforme Eclipse n'autorise pas la modification dynamique du SelectionProvider d'une vue au service de sélection. Je me suis trouvé dans le cas où j'avais plusieurs composants TableViewer dans une même vue : cette vue contient deux composants de type TableViewer.

Une solution est proposée dans cet article qui décrit l'utilisation du service de sélection. L'auteur propose notamment d'utiliser la classe SelectionProviderIntermediate pour gérer plusieurs composants de type SelectionProvider dans une même vue. Cet objet est connecté au service de sélection puisqu'il est de type SelectionProvider. En fait, cette classe joue le rôle de classe de délégation. Associé à un viewer, l'objet SelectionProviderIntermediate délègue les modifications de sélection du viewer au service de sélection. L'intérêt est de fixer l'objet de type SelectionProviderIntermediate et de lui associer dynamiquement les composants SelectionProvider (ici des composants de type TableViewer).

Dans la suite, je vous montre comment utiliser cette classe à partir de deux composants TableViewer. Tout ce qui va être présenté se trouve dans la méthode createPartControl.

Ci-dessous, le code utilisé pour ajouter les deux composants TableViewer à la vue :
public void createPartControl(Composite parent) {
viewer1 = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
viewer1.setContentProvider(new ViewContentProvider());
viewer1.setLabelProvider(new ViewLabelProvider());
viewer1.setInput(getViewSite());
viewer2 = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
viewer2.setContentProvider(new ViewContentProvider());
viewer2.setLabelProvider(new ViewLabelProvider());
viewer2.setInput(getViewSite());
Ci-dessous, le code utilisé pour instancier le SelectionProvider qui délègue les modifications de sélection d'un viewer au service de sélection.
 final SelectionProviderIntermediate selectionProviderIntermediate = new SelectionProviderIntermediate();
this.getSite().setSelectionProvider(selectionProviderIntermediate);
Enfin, la notification du changement de la sélection locale de chaque composant TableViewer est utilisée pour modifier le SelectionProvider actif dans l'objet SelectionProviderIntermediate.
 viewer1.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
selectionProviderIntermediate.setSelectionProviderDelegate(viewer1);
}
});
viewer1.addPostSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
selectionProviderIntermediate.setSelectionProviderDelegate(viewer1);
}
});

viewer2.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
selectionProviderIntermediate.setSelectionProviderDelegate(viewer2);
}
});
viewer2.addPostSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
selectionProviderIntermediate.setSelectionProviderDelegate(viewer2);
}
});
}
Vous pouvez télécharger le code source de cet exemple ici. Cet exemple fait parti du cours sur le Workbench Eclipse que je suis en train de préparer.

8 commentaires:

  1. Slt Mr Keulkeul!

    Jai une question un peu bête, mais jme lance. Comment faire pour executer ton programme? Est ce une appli RCP à part entière ou un plug in?

    Thx

    RépondreSupprimer
  2. Ce n'est pas une question bête.

    Le fichier Zip fourni correspond en fait à la structure d'un plugin.

    Il faut donc exécuter cet exemple comme un plugin.

    Si tu as d'autres questions n'hésites pas.

    Mickael

    RépondreSupprimer
  3. Its me again!

    Je ne sais pas si c'est moi qui est un vrai dumb, mais bon...
    Dans le but d'éxécuter ton exemple, jai dézippé ton projet que j'ai ajouté ensuite à la racine de mon repertoire eclipse. Apres avoir ensuite redémarré eclipse, j'ai fais windows->Show View->Other et j'ai choisi d'afficher les deux vues qui crées par le projet.

    Cependant, j'ai l'erreur suivante: "Could not create the view: Plug-in eclipse.workbench.MultipleProvidersExample was unable to load class eclipse.workbench.multipleprovidersexample.views.SelectionListenerViewPart.", et je n'ai aucune idée d'ou elle provient.

    Peux tu m'aider?

    RépondreSupprimer
  4. Bjr @ tous!

    Avez vous réussi à faire fonctionner le plugin de M. KeulKeul?

    Si oui, merci de m'aider, car j'y arrives pas!

    RépondreSupprimer
  5. @Anonyme : je pense que tu as des problèmes de dépendances.

    Pour faire simple voici comment il faut procéder pour utiliser ce plugin.

    Prérequis : un Eclipse pour développer du RCP.

    A partir d'Eclipse faire File -> Import -> General / Existing Projects into Workspace

    A ce moment là, choisir l'option Select Archive File puis le fichier zip donné par ce billet (pas besoin de le dézipper ni le placer dans le workspace). Le plugin est maintenant dans le workspace.

    Puis s'assurer qu'il n'y ait pas de problème de compilation.

    Enfin, pour l'exécution, il faut créer une nouvelle configuration d'exécution à base d'Eclipse Application. Ajouter uniquement le plugin lié au billet puis faire "Add Required Bundles". Enfin, un Run ...

    Mickael

    RépondreSupprimer
  6. Merci, c'est tout bonnement ce qu'il me fallait. J'avais la solution en tête mais un peu la flemme de l'implémenter.

    RépondreSupprimer
  7. Juste pour signaler une coquille dans l'article :
    "this.getSite().setSelectionProvider(selectionProvider);"
    à remplacer par :
    "this.getSite().setSelectionProvider(selectionProviderIntermediate);"

    Un grand merci pour cet article qui m'a beaucoup aidée !

    RépondreSupprimer