Construction de vues avec la plateforme Eclipse

  • 3,819 views
Uploaded on

Ce support de cours s'intéresse à détailler la construction de vues avec la plateforme Eclipse. Il fait partie de la série des supports de cours liée au Workbench. Les aspects suivants sont étudiés : …

Ce support de cours s'intéresse à détailler la construction de vues avec la plateforme Eclipse. Il fait partie de la série des supports de cours liée au Workbench. Les aspects suivants sont étudiés : construction déclarative, étude des classes ViewPart StickyView et Category, vues multiples, registre des vues, cycle de vie, communication entre vues (en direct, le service de sélection et IAdaptable).

More in: Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
3,819
On Slideshare
0
From Embeds
0
Number of Embeds
8

Actions

Shares
Downloads
98
Comments
0
Likes
2

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Développement de clients riches : Plateforme Eclipse Chapitre 3 : Conception de plug-ins Workbench : Views Mickaël BARON – 2009 (Rev. Juillet 2010) mailto:baron.mickael@gmail.com ou mailto:baron@ensma.fr
  • 2. Licence Creative Commons Contrat Paternité Partage des Conditions Initiales à l'Identique 2.0 France keulkeul.blogspot.com http://creativecommons.org/licenses/by-sa/2.0/fr Views - M. Baron - Page 2
  • 3. Organisation du cours sur le Workbench : Views Construction déclarative ViewPart, StickyView et Category Vues multiples Registre des vues Cycle de vie keulkeul.blogspot.com Communication entre vues Tous les exemples du cours sont disponibles directement à l’adresse mbaron.developpez.com/eclipse/views Views - M. Baron - Page 3
  • 4. Déroulement du cours Pédagogie du cours Illustration avec de nombreux exemples qui sont disponibles à l’adresse mbaron.developpez.com/eclipse/views Des bulles d’aide tout au long du cours Logiciels utilisés Ceci est une astuce Eclipse 3.4.2 Ganymede Pré-requis Ceci est une alerte Connaître la boite à outils SWT, JFace keulkeul.blogspot.com Connaître la structure d’un plug-ins et savoir créer une extension Remerciements Developpez.com : djo.mos (Jawher MOUSSA) … Views - M. Baron - Page 4
  • 5. Ressources … Des articles sur la construction des vues www.eclipse.org/articles/viewArticle/ViewArticle2.html www.vogella.de/articles/RichClientPlatform/article.html eclipsesource.com/blogs/2010/06/23/tip-how-to-detect-that-a-view-was-detached/ Des articles sur la communication entre vues www.eclipse.org/articles/Article-WorkbenchSelections/article.html www.eclipse.org/articles/Article-Properties-View/properties-view.html wiki.eclipse.org/FAQ_How_do_I_find_out_what_object_is_selected%3F wiki.eclipse.org/FAQ_How_do_I_use_IAdaptable_and_IAdapterFactory%3F keulkeul.blogspot.com Des livres Eclipse – Building Commercial-Quality Plug-ins, 2004 - ISBN : 0-321-22847-2 Eclipse – Rich Client Platform, 2005 – ISBN : 0-321-33461-2 Views - M. Baron - Page 5
  • 6. Généralités Dans la partie précédente nous avons étudié les perspectives qui permettent d’agencer vues et éditeurs Une vue est utilisée pour naviguer dans une hiérarchie d’information, ouvrir un éditeur ou afficher des propriétés en relation directe avec l’éditeur actif Cette partie sera l’occasion d’étudier en détail les construc- tions des vues et les possibilités d’interaction construction d’une vue par extension keulkeul.blogspot.com construction de vues multiples construction de vues de type Sticky Views registre des vues mécanismes de communication entre les vues Views - M. Baron - Page 6
  • 7. Généralités Principales interfaces et classes pour la gestion des vues IWorkbenchPage activate(IWorkbenchPart) bringToTop(IWorkbenchPart) findView(String) getViewReferences() hideView(IViewPart) showView(String) IWorkbenchSite getPage() IWorkbenchPartReference getSelectionProvider() getId() getShell() getPage() getWorkbenchWindow() getPart(boolean) setSelectionProvider(ISelectionProvider) IWorkbenchPart IViewReference createPartControl(Composite) IWorkbenchPartSite getView(boolean) dispose() getKeyBindingService() isFastView() getSite() registerContextMenu(MenuManager, ISelectionProvider) registerContextMenu(String, MenuManager, ISelectionProvider) IViewPart WorkbenchPart getViewSite() keulkeul.blogspot.com dispose() IViewSite init(IViewSite) getActionBars() getConfigurationElement() init(IViewSite, IMemento) getSite() saveState(IMemento) setPartName(String) Héritage ViewPart getViewSite() init(IViewSite) Dépendance init(IViewSite, IMemento) saveState(IMemento) Views - M. Baron - Page 7
  • 8. Construction d'une vue par extension Sélectionner le point d’extension org.eclipse.ui.views Création d’une extension à partir du point d’extension org.eclipse.ui.views keulkeul.blogspot.com Création d’une vue à partir du template Sample View Views - M. Baron - Page 8
  • 9. Construction d'une vue par extension Définir les attributs de l’extension Identifiant de la vue Nom de la vue Objet de type ViewPart décrivant le contenu d’une vue Ratio pour l’ouverture de la vue en mode FastView keulkeul.blogspot.com Possibilité de retrouver la Possibilité d’avoir vue après un redémarrage plusieurs instances de du Workbench cette vue Views - M. Baron - Page 9
  • 10. Construction d'une vue par extension Etendre une vue de type ViewPart SimpleView.java du Projet ViewExample package eclipse.workbench.viewexample.views public class SimpleView extends ViewPart { public SampleView() { } public void createPartControl(Composite parent) { Label myLabel = new Label(parent, SWT.NONE); myLabel.setText("Simple View"); } keulkeul.blogspot.com public void setFocus() { } Création du contenu en } utilisant des composants SWT Views - M. Baron - Page 10
  • 11. ViewPart La définition d’une nouvelle vue est obtenue en héritant de la classe ViewPart Des méthodes abstraites doivent être implémentées void createPartControl(Composite parent) : création de l’IHM par des composants SWT où parent est le conteneur de la vue void setFocus() : précise le composant SWT qui aura le focus à chaque activation de la vue Des méthodes qui peuvent être redéfinies (à voir plus tard) setInitializationData(…) : appelée lors de la création de l’extension init(IWorkbenchPartSite p) : appelée pour initialiser le contexte de la keulkeul.blogspot.com vue (quelle est la Shell parente, la page active, …) Des méthodes à exploiter IViewSite getViewSite() : site de la vue (étudier par la suite) void setPartName(String ti) : modifie le titre Views - M. Baron - Page 11
  • 12. ViewPart L’implémentation de la méthode createPartControl suit un processus assez similaire Modifier l’agent de placement du parent si nécessaire Créer un ou plusieurs composants SWT / JFace à l’intérieur du parent Déclarer des nouvelles actions avec la barre d’actions du site Déclarer un nouveau menu contextuel dans le Workbench avec le site Déclarer l’écoute de la sélection d’un composant avec le site keulkeul.blogspot.com Les déclarations d’actions, d’un menu contextuel et de la sélection seront étudiés en détail dans la suite Views - M. Baron - Page 12
  • 13. ViewPart et IViewSite Le site d’une vue est une sorte de pont entre la vue (définit par ViewPart) et le Workbench Il faut voir le site comme un objet qui permet de lier la vue au contexte de l’application L’interface IWorkbenchSite est une abstraction d’un site IWorkbenchPage getPage() : la page dans laquelle la vue est stockée Shell getShell() : la fenêtre physique d’où est contenue la vue IWorkbenchWindow getWorkbenchWindow() : la fenêtre déclarative contenant la vue void registerContextMenu(MenuManager mM, ISelectionProvider sP) : keulkeul.blogspot.com expose un menu vers le Workbench pour permettre son extension ultérieur void setSelectionProvider(ISelectionProvider sP) : déclare un SelectionProvider (TableViewer par exemple) au service de sélection Views - M. Baron - Page 13
  • 14. ViewPart et IViewSite L’interface IViewSite (sous type de IWorkbenchSite) fournit des méthodes spécifiques IActionBars getActionBars() : la barre d’action de la vue String getSecondaryId() : identifiant secondaire utilisé pour gérer des instances multiples de la vue L’ajout d’actions se fait via le site de la vue Sera utilisée dans la partie Vues Multiples keulkeul.blogspot.com Le contenu de la vue est défini par la méthode createPartControl Views - M. Baron - Page 14
  • 15. ViewPart et IViewSite Exemple : accéder aux éléments du site d’une vue SiteView.java du Projet ViewExample package eclipse.workbench.viewexample.views Modification de l’agent de public class SiteView extends ViewPart { placement du parent public void createPartControl(Composite parent) { parent.setLayout(new GridLayout(2,true)); Button buttonLeft = new Button(parent, SWT.FLAT); buttonLeft.setText("LEFT_Button"); Construction de Button buttonRight = new Button(parent, SWT.FLAT); l’interface à partir de buttonRight.setText("RIGHT_Button"); composants SWT GridData myGridData = new GridData(GridData.FILL_BOTH); myGridData.horizontalSpan = 2; viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); viewer.setContentProvider(new ViewContentProvider()); viewer.setLabelProvider(new ViewLabelProvider()); keulkeul.blogspot.com viewer.getControl().setLayoutData(myGridData); viewer.setInput(this.getViewSite()); this.createActions(); this.createToolBar(); this.createContextMenu(); Création des actions, de la } barre d’outils et du menu } contextuel Views - M. Baron - Page 15
  • 16. ViewPart et IViewSite Exemple (suite) : accéder aux éléments du site d’une vue ... private void createActions() { SiteView.java du action1 = new Action("Action 1") { public void run() { System.out.println("Action 1 Performed"); } Projet ViewExample }; action2 = new Action("Action 2") { public void run() { System.out.println("Action 2 Performed"); } }; } private void createToolBar() { IToolBarManager mgr = getViewSite().getActionBars().getToolBarManager(); mgr.add(this.action1); mgr.add(this.action2); } private void createContextMenu() { MenuManager menuMgr = new MenuManager(); menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager mgr) { mgr.add(action1); mgr.add(new Separator()); keulkeul.blogspot.com mgr.add(action2); } }); Menu menu = menuMgr.createContextMenu(viewer.getControl()); Viewer.getControl().setMenu(menu); getSite().registerContextMenu(menuMgr, viewer); } Ce menu est déclaré dans le Workbench. L’extension du menu devient possible Views - M. Baron - Page 16
  • 17. Sticky View Une Sticky View est une vue partagée à toutes les perspec- tives d’une application Eclipse Une Sticky View n’est pas associée explicitement à une perspective, la déclaration est implicite Lors du chargement d’une perspective, une Sticky View déjà ouverte le reste et conserve sa position Un « reset » sur une perspective ne fermera pas une Sticky View keulkeul.blogspot.com La fermeture d’une Sticky View ne peut se faire que par une demande explicite (fermeture de la vue associée) Pour quelle occasion ? Cheat Sheets (aide contextualisée) Views - M. Baron - Page 17
  • 18. Sticky View Création d’une vue classique keulkeul.blogspot.com plugin.xml du projet ViewExample Onglet Extensions Views - M. Baron - Page 18
  • 19. Sticky View Création d’une vue classique (suite) plugin.xml du projet ViewExample StickyViewPart.java du projet ViewExample package eclipse.workbench.viewexample.views public class StickyViewPart extends ViewPart { public StickyViewPart() { } keulkeul.blogspot.com public void createPartControl(Composite parent) { Label myCurrentLabel = new Label(parent, SWT.NONE); myCurrentLabel.setText("View used for the StickyView ViewExample series"); } public void setFocus() { } } Views - M. Baron - Page 19
  • 20. Sticky View Création d’une Sticky View plugin.xml du projet ViewExample keulkeul.blogspot.com Onglet Extensions Views - M. Baron - Page 20
  • 21. Sticky View Association d’une vue avec une Sticky View Vue qui sera transformée en Sticky View plugin.xml du projet Identifiant d’une vue existante ViewExample Position de la Sticky View dans les perspectives (BOTTOM, RIGHT, LEFT, TOP) Précise si la Sticky View peut elle être fermée ? keulkeul.blogspot.com La Sticky View peut elle être déplacée Views - M. Baron - Page 21
  • 22. Sticky View Exemple : une vue transformée en Sticky View keulkeul.blogspot.com La Sticky View est visible et Projet conserve son emplacement lors des ViewExample changements des perspectives Views - M. Baron - Page 22
  • 23. Category Une Category est un regroupement de vues utilisée pour organiser la liste des vues dans le menu Window -> Show View -> Other Possibilité d’associer une vue à une nouvelle catégorie ou à une catégorie déjà existante Les catégories sont hiérarchiques, possibilité de spécifier à une catégorie keulkeul.blogspot.com une catégorie parente existante Les catégories sont identifiées par un Plusieurs catégories identifiant unique existantes : General, Debug, Help, Java, … Views - M. Baron - Page 23
  • 24. Category Création d’une Category Création d’une nouvelle catégorie Identifiant de la nouvelle catégorie Nom de la nouvelle keulkeul.blogspot.com plugin.xml du projet catégorie ViewExample Parent de la catégorie (optionnelle) Onglet Extensions Views - M. Baron - Page 24
  • 25. Category Associer la vue à la catégorie plugin.xml du projet ViewExample La liste des vues est accessible via le menu Window -> Show View -> Other La vue ViewCategory est associée à la catégorie *.ViewExample.Category keulkeul.blogspot.com Onglet Extensions La vue ViewCategory est contenu dans la catégorie Category Example Views - M. Baron - Page 25
  • 26. Vue Détachée Une vue détachée est une vue affichée dans une fenêtre autre que celle de la WorkbenchWindow Une vue détachée appartient toujours à sa perspective Pour détacher une vue, afficher le menu contextuel (bouton droit) puis option Detached Au niveau des APIs de manipulation des vues détachées c’est le grand vide … Savoir si une vue est détachée ? Pas d’écouteur pour savoir si une vue est détachée keulkeul.blogspot.com Solution : titre de la fenêtre est vide, quand la vue est détachée les événements de redimensionnement sont déclenchés Détacher une vue Utilisation des APIs internes Views - M. Baron - Page 26
  • 27. Vue Détachée Exemple : Détecter qu’une vue est détachée La vue Detach View est détachée keulkeul.blogspot.com Views - M. Baron - Page 27
  • 28. Vue Détachée Exemple (suite) : Détecter qu’une vue est détachée public class DetachViewPart extends ViewPart { private Composite parent; private Label label; protected boolean isDetached; public DetachViewPart() { } @Override public void createPartControl(Composite parent) { this.parent = parent; parent.setLayout(new RowLayout()); label = new Label(parent, SWT.NONE); parent.addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { updateDetached(); } }); updateDetached(); } keulkeul.blogspot.com private void updateDetached() { isDetached = parent.getShell().getText().length() == 0; label.setText("View isDetached? " + isDetached); } ... } DetachViewPart.java du Projet ViewExample Views - M. Baron - Page 28
  • 29. Vue Détachée Exemple : Attacher et Détacher une vue par code keulkeul.blogspot.com Attache ou Détache une vue selon son état Détaché ou pas Views - M. Baron - Page 29
  • 30. Vue Détachée Exemple (suite) : Attacher et Détacher une vue par code public class OpenDetachViewPart extends DetachViewPart { public OpenDetachViewPart() { } Réutilise la vue @Override DetachViewPart pour public void createPartControl(Composite parent) { connaître l’état de la vue super.createPartControl(parent); Button detachViewButton = new Button(parent, SWT.NONE); detachViewButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IWorkbenchPage page = getSite().getPage(); final IViewReference findViewReference = page.findViewReference( "eclipse.workbench.ViewExample.openDetachViewId"); if (!isDetached) { ((WorkbenchPage) page).detachView(findViewReference); } else { ((WorkbenchPage) page).attachView(findViewReference); } } }); keulkeul.blogspot.com detachViewButton.setText("Attach/Detach"); } ... } AttachOrDetachViewPart.java du Projet ViewExample Views - M. Baron - Page 30
  • 31. Vues multiples Jusque là nous avons vu qu’une vue est identifiée par un identifiant unique définie lors de la création d’une extension (attribut id) Le conteneur de la plateforme Eclipse s’appuie sur cet identifiant pour la création de l’instance de la vue Par conséquent, une seule instance de la vue ne peut être créée par le conteneur de la plateforme Eclipse Or, il peut être intéressant d’afficher plusieurs instances keulkeul.blogspot.com d’une même vue Un second identifiant est utilisé pour la création d’instances multiples Views - M. Baron - Page 31
  • 32. Vues multiples Une vue est donc identifiée par un identifiant primaire et un identifiant secondaire (par défaut est vide) Une instance d’une vue est identifiée de la manière suivante Identifiant_Primaire:Identifiant_Secondaire Identifiant primaire déclaré Identifiant secondaire déclaré pour lors de la définition de la vue chaque nouvelle instance de la vue Pour activer la gestion des instances multiples d’une vue, il keulkeul.blogspot.com faut modifier le paramètre allowMultiple à true Différentes manières de construire une instance multiple d’une vue Views - M. Baron - Page 32
  • 33. Vues multiples Activation de la gestion multiple d’une vue Ne pas ajouter un identifiant secondaire lors de la définition de la vue Identifiant primaire de la vue Multiple Instances View 1 keulkeul.blogspot.com La gestion multiple de cette vue est activée Views - M. Baron - Page 33
  • 34. Vues multiples Exemple 1 : Vues multiples à partir de IPageLayout MultipleInstancesViewFactory.java du projet ViewExample package eclipse.workbench.viewexample.views public class MultipleInstancesViewFactory implements IPerspectiveFactory { public void createInitialLayout(IPageLayout layout) { String editorAreaId = layout.getEditorArea(); layout.addView("eclipse.workbench.ViewExample.MultipleInstanceView1:1", IPageLayout.LEFT, 0.25f, editorAreaId); layout.addView("eclipse.workbench.ViewExample.MultipleInstanceView1:2", IPageLayout.BOTTOM, 0.25f, editorAreaId); } } keulkeul.blogspot.com Création statique d’instances Création de deux instances multiples de la vue de la même vue Views - M. Baron - Page 34
  • 35. Vues multiples Exemple 1 (suite) : Vues multiples à partir de IPageLayout La vue Multiple Instances View 1 est instanciée deux fois keulkeul.blogspot.com MultipleInstancesViewFactory du projet ViewExample Views - M. Baron - Page 35
  • 36. Vues multiples Exemple 2 : Vues multiples à partir de IWorkbenchPage package eclipse.workbench.viewexample.views public class AddSecondaryViewAction implements IWorkbenchWindowActionDelegate { private int secondaryIdCount = 0; public AddSecondaryViewAction() { } public void run(IAction action) { try { PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView( "eclipse.workbench.ViewExample.MultipleInstanceView2", Integer.toString(secondaryIdCount), IWorkbenchPage.VIEW_ACTIVATE); secondaryIdCount++; } catch (PartInitException e) { La méthode showView permet e.printStackTrace(); } d’ajouter une vue en donnant un } identifiant secondaire public void selectionChanged(IAction action, ISelection selection) { } keulkeul.blogspot.com public void dispose() { } public void init(IWorkbenchWindow window) { } Création dynamique } d’instances multiples de la vue AddSecondaryViewAction.java du projet ViewExample Views - M. Baron - Page 36
  • 37. Vues multiples Exemple 2 (suite) : Vues multiples à partir de IWorkbench… Action permettant la création de Plusieurs instances nouvelles de vue instances de vue keulkeul.blogspot.com AddSecondaryViewAction du projet ViewExample Views - M. Baron - Page 37
  • 38. Vues multiples La création d’une vue via la méthode showView(…) varie selon le mode de fonctionnement utilisé IViewPart showView(String id, String secId, int mode) throws PartInitException : crée une vue à partir d’un identifiant primaire id, d’un identifiant secondaire secId et d’un mode Différentes valeurs pour mode VIEW_ACTIVATE : vue est visible et a le focus keulkeul.blogspot.com VIEW_VISIBLE : vue visible mais n’a pas le focus VIEW_CREATE : vue créée mais n’a pas forcément le focus Views - M. Baron - Page 38
  • 39. Vues multiples A partir du code d’une ViewPart il est possible de connaître l’identifiant secondaire au travers du site de la vue via l’interface IViewSite String getSecondaryId() : identifiant secondaire utilisé pour gérer des instances multiples de la vue Exemple : afficher l’identifiant secondaire d’une vue package eclipse.workbench.viewexample.views public class MultipleInstanceViewPart2 extends ViewPart { public MultipleInstanceViewPart2() { } public void createPartControl(Composite parent) { Button myButton = new Button(parent, SWT.FLAT); Identifiant secondaire myButton.setText("Give me the Secondary ID"); keulkeul.blogspot.com myButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { String secondaryId = getViewSite().getSecondaryId(); System.out.println(secondaryId); } }); } public void setFocus() { } MultipleInstanceViewPart2.java } du projet ViewExample Views - M. Baron - Page 39
  • 40. Registre des vues Le registre des vues est utilisé par le conteneur Eclipse pour stocker l’intégralité des vues créées (incluant également les Sticky Views et les Categories) Il n’existe qu’un seul registre de vue géré par le Workbench A partir de ce registre il est possible de Chercher une vue par son identifiant Récupérer l’ensemble des Categories, des Sticky Views ou des Views keulkeul.blogspot.com IViewRegistry viewRegistry = PlatformUI.getWorkbench().getViewRegistry(); L’interface IViewRegistry est détaillée dans la suite Views - M. Baron - Page 40
  • 41. Registre des vues L’interface IViewRegistry dispose des méthodes suivantes IViewDescriptor find(String id) : recherche une vue par son id IViewCategory[] getCategories() : récupère l’intégralité des catégories IStickyViewDescriptor[] getStickyViews() : retourne l’intégralité des Sticky Views IViewDescriptor[] getViews() : retourne l’intégralité des vues issues du registre des vues L’interface IViewCategory représente une catégorie de vues keulkeul.blogspot.com String getId() : id de la catégorie String getLabel() : nom de la catégorie IPath getPath() : chemin de la catégorie (parent) IViewDescriptor getViews() : liste des vues Views - M. Baron - Page 41
  • 42. Registre des vues L’interface IViewDescriptor décrit le contenu d’une vue String getId() : identifiant de la vue String getLabel() : nom String getDescription() : description float getFastViewWithRatio() : ratio boolean getAllowMultiple() : instances multiples ou pas String getCategoryPath() : chemin des catégories isRestorable() : vue reconstruite au redémarrage de l’application keulkeul.blogspot.com IViewPart createView() : création d’une instance (peu utilisé car réalisé par le conteneur) Le registre des vues ne gère pas les instances IViewPart, elles le sont au niveau de la page Views - M. Baron - Page 42
  • 43. Registre des vues L’interface IStickyViewDescriptor représente une Sticky View String getId() : identifiant de la vue int getLocation() : position de la vue dans la WorkbenchWindow boolean isCloseable() : la vue peut-elle être fermée isMoveable() : la vue peut-elle être déplacée keulkeul.blogspot.com Views - M. Baron - Page 43
  • 44. Registre des vues Exemple : interroger le registre des vues package eclipse.workbench.viewexample.views public class ViewRegistryViewPart extends ViewPart { public void createPartControl(Composite parent) { ... Button findView = new Button(parent, SWT.FLAT); findView.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { System.out.println("- Find View -"); IViewRegistry viewRegistry = PlatformUI.getWorkbench().getViewRegistry(); ViewDescriptor find = viewRegistry.find("eclipse.workbench.ViewExample.views.ViewRegistryId"); System.out.println(find.getLabel()); System.out.println(find.getAllowMultiple()); } }); findView.setText("Find : ViewRegistryId"); Button getCategories = new Button(parent, SWT.FLAT); getCategories.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { System.out.println("- Get Categories -"); IViewRegistry viewRegistry = PlatformUI.getWorkbench().getViewRegistry(); keulkeul.blogspot.com IViewCategory[] categories = viewRegistry.getCategories(); for (IViewCategory viewCategory : categories) { System.out.println(viewCategory.getLabel()); } } }); getCategories.setText("Get Categories"); } ... ViewRegistryViewPart.java du } projet ViewExample Views - M. Baron - Page 44
  • 45. Registre des vues Exemple (suite) : interroger le registre des vues ... Button getStickyViews = new Button(parent, SWT.FLAT); getStickyViews.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { System.out.println("- Get Sticky Views -"); IViewRegistry viewRegistry = PlatformUI.getWorkbench().getViewRegistry(); IStickyViewDescriptor[] stickyViews = viewRegistry.getStickyViews(); for (IStickyViewDescriptor stickyViewDescriptor : stickyViews) { System.out.println(stickyViewDescriptor.getId() + stickyViewDescriptor.getLocation()); } } }); getStickyViews.setText("Get Sticky Views"); Button getViews = new Button(parent, SWT.FLAT); getViews.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { System.out.println("- Get Views -"); IViewRegistry viewRegistry = PlatformUI.getWorkbench().getViewRegistry(); IViewDescriptor[] views = viewRegistry.getViews(); for (IViewDescriptor viewDescriptor : views) { System.out.println(viewDescriptor.getId()); } keulkeul.blogspot.com } }); getViews.setText("Get Views"); } } ViewRegistryViewPart.java du projet ViewExample Views - M. Baron - Page 45
  • 46. Cycle de vie Un objet IWorkbenchPage permet de gérer le cycle de vie des instances d’une classe ViewPart (celle utilisée pour programmer l’interface d’une vue) Pour rappel l’agencement des objets ViewPart d’une page est réalisé par les perspectives L’instance d’une ViewPart est associée à son identifiant (id) keulkeul.blogspot.com Il peut exister plusieurs instances d’une ViewPart dans le cas ou dans la description de la vue, la gestion des instances multiples est activée (id:idSecondaire) Views - M. Baron - Page 46
  • 47. Cycle de vie L’interface IViewReference décrit la relation entre identifiant et instance de ViewPart String getId() : identifiant primaire de la vue String getSecondaryId() : identifiant secondaire de la vue IViewPart getView(boolean restore) : référence à la ViewPart, restore à TRUE pour tenter de la restaurer si elle n’existe pas boolean isFastView() : cette vue est de type FastView IWorkbenchPage getPage() : Workbench Page dans laquelle cette vue est référencée keulkeul.blogspot.com String getPartName() : le nom à afficher … L’accès à un objet IViewReference se fait par l’intermédiaire du Workbench Page actif Views - M. Baron - Page 47
  • 48. Cycle de vie – ouverture d’une vue Ouverture d’une vue procède à la création d’une instance ViewPart dans le cas où il n’existe aucune instance de cette ViewPart dans le Workbench Page actif L’ouverture d’une vue déjà présente dans une perspective rend active cette vue. Aucune nouvelle instance est créée L’ouverture d’une vue dans une autre perspective affiche la vue sans re-créér une nouvelle instance (les ViewPart sont partagées dans les perspectives) keulkeul.blogspot.com Dans le cas des vues avec instances multiples, la stratégie d’ouverture est identique sauf qu’il peut exister plusieurs instances d’une même ViewPart Views - M. Baron - Page 48
  • 49. Cycle de vie – ouverture d’une vue Démonstration … Ouverture de la vue SimpleView dans la perspective Resource keulkeul.blogspot.com Création d’une instance de la La vue SimpleView n’a jamais classe SimpleView.java du encore été ouverte projet ViewExample stockée dans la page courante Views - M. Baron - Page 49
  • 50. Cycle de vie – ouverture d’une vue Démonstration (suite) … La vue SimpleView est ajoutée à la perspective SimplePerspective keulkeul.blogspot.com Comme une instance à La vue SimpleView est déjà SimpleView existe, aucune ouverte dans la perspective autre instance n’est créée Resource Views - M. Baron - Page 50
  • 51. Cycle de vie – ouverture d’une vue Lors de l’analyse de la classe ViewPart seules les méthodes createPartControl(…) et setFocus() avaient été étudiées D’autres méthodes sont fournies et appelées par le conte- neur (suivant un ordre donné) pour instancier la ViewPart 1 Constructeur de la classe 2 void setInitializationData(IConfigurationElement, String, Object) : les informations de l’extension sont passées en paramètre permettant de connaître le titre, le nom, l’image, … 3 void init(IViewSite) : initialise l’instance avec le site keulkeul.blogspot.com 4 void init(IViewSite, IMemento) : idem sauf que l’objet IMemento permet de restaurer un état (voir fermeture d’une vue) 5 void createPartControl(Composite) : pour programmer l’IHM Méthodes appelées uniquement à la création de l’instance Views - M. Baron - Page 51
  • 52. Cycle de vie – ouverture d’une vue Exemple : accès aux informations de l’extension d’une vue public class OpenLifeCycle extends ViewPart { public void setInitializationData(IConfigurationElement cfig, String propertyName, Object data) { super.setInitializationData(cfig, propertyName, data); System.out.println(cfig.getAttribute("name")); } public OpenLifeCycle() { Récupération des } informations de l’extension public void createPartControl(Composite parent) { utilisée par la création de } cette vue public void setFocus() { } } keulkeul.blogspot.com OpenLifeCycle du projet ViewExample Views - M. Baron - Page 52
  • 53. Cycle de vie – ouverture d’une vue A l’ouverture, la vue passe par différents états Opened : lors de la création de l’instance d’une ViewPart La vue SimpleView a Visible : la vue est visible été ajoutée par le menu Show View Activated : la vue a le focus keulkeul.blogspot.com Les différents états de la vue : Opened -> Visible -> Activated Views - M. Baron - Page 53
  • 54. Cycle de vie – fermeture d’une vue Lors de la fermeture d’une vue dans une perspective le Workbench Page vérifie si cette vue est également présente dans d’autres perspectives Présente : la vue est cachée Non présente : la référence ViewPart est disposée Quand une référence ViewPart est disposée, elle est suppri- keulkeul.blogspot.com mée de la liste des IViewReference du Workbench Page Une nouvelle référence doit être créée pour ré-ouvrir la vue Views - M. Baron - Page 54
  • 55. Cycle de vie – fermeture d’une vue D’autres méthodes sont appelées par le conteneur (suivant un ordre donné) lors de la fermeture d’une vue void saveState(IMemento memento) : appelée uniquement quand l’application Eclipse doit être fermée. Cette méthode n’est pas appelée s’il n’existe pas de vue ouverte (référence n’existe pas) void dispose() : suppression de la référence quand la vue doit être disposée A la fermeture, la vue passe par différents états keulkeul.blogspot.com Deactivated : la vue n’a plus le focus Hidden : la vue est cachée Closed : l’instance de la vue est disposée Views - M. Baron - Page 55
  • 56. Communication entre vues Dans tous les exemples que nous avons étudiés nous n’avons encore jamais échangé d’information entre vues Informations à partager Des attributs d’une classe ViewPart Sélection courante d’une TableViewer Et pourtant, la plateforme Eclipse fournit un ensemble de mécanismes pour faciliter la communication entre vues Nous étudions dans cette partie ces mécanismes keulkeul.blogspot.com Communication directe entre des ViewParts Communication à partir des écouteurs de vues Service de sélection Le patron Adaptateur via IAdaptable Views - M. Baron - Page 56
  • 57. Communication entre vues (en direct …) Le premier mécanisme consiste à récupérer l’instance d’une ViewPart à partir de l’identifiant de sa vue Une classe ViewPart spécialisée peut éventuellement disposer d’attributs ou d’un modèle de données à partager Le registre des vues ne permet pas de récupérer des instances de ViewPart puisque ces instances sont gérées au niveau de la page (voir cycle de vie) Il faut passer par la page active pour récupérer cette instance de ViewPart en fonction de l’identifiant de la vue keulkeul.blogspot.com IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); IViewPart viewPart = page.findViewReference(String id).getView(true); Récupération de la page active Récupération de l’instance ViewPart d’une vue en fonction de son identifiant par rapport à la page active Views - M. Baron - Page 57
  • 58. Communication entre vues (en direct …) Exemple : communication entre deux instances ViewPart package eclipse.workbench.linkviewexample.views public class LinkView2 extends ViewPart { private String familyName; private String firstName; Perspective Link Direct Attribut spécifique à la public LinkView2() { } classe LinkView2.java public void createPartControl(Composite parent) { parent.setLayout(new GridLayout(2, false)); Label nameLabel = new Label(parent, SWT.NONE); nameLabel.setText("Family Name"); Label fnameLabel = new Label(parent, SWT.NONE); fnameLabel.setText("First Name"); final Text nameText = new Text(parent, SWT.BORDER); nameText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { familyName = nameText.getText(); } }); final Text fnameText = new Text(parent, SWT.BORDER); keulkeul.blogspot.com fnameText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { firstName = fnameText.getText(); } }); } ... } LinkView2.java du projet LinkViewExample Views - M. Baron - Page 58
  • 59. Communication entre vues (en direct …) Exemple (suite) : communication entre deux instances … package eclipse.workbench.linkviewexample.views public class LinkView1 extends ViewPart { public void createPartControl(Composite parent) { Button getLinkView2DataButton = new Button(parent, SWT.FLAT); getLinkView2DataButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); IViewPart findView = activePage.findViewReference("eclipse.workbench.LinkViewExample.views.linkviewid2"); if (findView != null) { String familyName = ((LinkView2)findView).getFamilyName(); String firstName = ((LinkView2)findView).getFirstName(); System.out.println(familyName + " " + firstName); } else { System.out.println("Instance de vue non créée"); } } keulkeul.blogspot.com }); getLinkView2DataButton.setText("Retrieve information from LinkView2"); } ... } LinkView1.java du projet LinkViewExample Views - M. Baron - Page 59
  • 60. Communication entre vues (en direct …) Comme les instances ViewPart sont gérées au niveau de la page, il se peut que des instances d’une vue ne soient pas encore créées Par conséquent il existe un couplage fort entre ViewPart Le scénario suivant peut se produire Une vue identifiée par id1 (dans le contenu de sa ViewPart) souhaite accéder à une instance ViewPart d’une vue identifiée par id2 Si la vue id2 n’a pas été créée (par exemple par encore visible dans une perspective) l’instance de sa ViewPart sera null keulkeul.blogspot.com La vue id1 ne pourra pas accéder aux informations de la ViewPart de id2 tant que la création n’a pas été réalisée Le problème se complexifie si les vues gère les instances multiples Views - M. Baron - Page 60
  • 61. Communication entre vues (en direct …) Exemple : communication entre deux instances ViewPart package eclipse.workbench.linkviewexample.views public class MultipleLinkView extends ViewPart { public void createPartControl(Composite parent) { Button getLinkView2DataButton = new Button(parent, SWT.FLAT); getLinkView2DataButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); IViewPart findView = activePage.findViewReference("eclipse.workbench.LinkViewExample.views.linkviewid2","1") .getView(true); if (findView != null) { String familyName = ((LinkView2)findView).getFamilyName(); Récupération de String firstName = ((LinkView2)findView).getFirstName(); System.out.println(familyName + " " + firstName); l’instance d’une } else { ViewPart par rapport à } System.out.println("Instance de vue non créée"); l’identifiant primaire et } secondaire }); keulkeul.blogspot.com getLinkView2DataButton.setText("Retrieve information from LinkView2"); } ... } MultipleLinkView.java du projet LinkViewExample Views - M. Baron - Page 61
  • 62. Communication entre vues (Part Listeners) Une vue peut subir des modifications comme l’activation, l’ouverture ou la visibilité et permet d’effectuer des changements à la réponse des événements L’activation et la création des vues peuvent être écoutées via l’interface IPartService implémentées par IWorkbenchPage void addPartListener(IPartListener pl) : écouteur « 1ère » version void addPartListener(IPartListener2 pl) : écouteur « 2nd » version IWorkbenchPart getActivePart() : Part active keulkeul.blogspot.com IWorkbenchPartReference getActivePartReference() : Part référence active L’écouteur IPartListener est à remplacer par l’interface IPartListener2 Views - M. Baron - Page 62
  • 63. Communication entre vues (Part Listeners) IPartListener2 fournit les méthodes suivantes pour les réponses aux événements sur la vue ( void partActivated(IWorkbenchPartReference pr) : part activée void partBroughtToTop(IWorkbench… pr) : part au premier plan void partClosed(IWorkbench… pr) : part fermée void partDeactivated(IWorkbench… pr) : part désactivée void partHidden(IWorkbench… pr) : part cachée void partInputChanged(IWorkbench… pr) : saisie de l’utilisateur void partOpened(IWorkbench… pr) : part ouverte keulkeul.blogspot.com void partVisible(IWorkbench… pr) : part visible Malheureusement certaines méthodes sont manquantes comme : vue détachée, vue transformée en Fast View, vue dockée … Views - M. Baron - Page 63
  • 64. Communication entre vues (Part Listeners) Exemple : écouter les changements d’une ViewPart package eclipse.workbench.ipartserviceexample.views public class PartListenerViewPart extends ViewPart { PartListenerViewPart.java du public void createPartControl(Composite parent) { parent.setLayout(new GridLayout(1, false)); projet IPartServiceExample Label myLabel = new Label(parent, SWT.NONE); myLabel.setText("Listened View"); IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); activePage.addPartListener(new IPartListener2() { @Override public void partActivated(IWorkbenchPartReference partRef) { IWorkbenchPart part = partRef.getPart(false); if (PartListenerViewPart.this == part) { System.out.println(".partActivated()"); Liste des méthodes déclenchées lors } ViewPart de l’écoute de la } @Override public void partBroughtToTop(IWorkbenchPartReference partRef) { IWorkbenchPart part = partRef.getPart(false); if (PartListenerViewPart.this == part) { System.out.println(".partBroughtToTop()"); } keulkeul.blogspot.com } @Override public void partClosed(IWorkbenchPartReference partRef) { IWorkbenchPart part = partRef.getPart(false); if (PartListenerViewPart.this == part) { System.out.println(".partClosed()"); } } } ... } Views - M. Baron - Page 64
  • 65. Communication entre vues (Selection Service) Le service de sélection permet à des vues d’avertir la plate- forme Eclipse qu’une sélection sur des objets a été réalisée Exemple : vues Package Explorer et Properties keulkeul.blogspot.com Le changement de sélection d’un fichier provoque la modification de la vue Properties Views - M. Baron - Page 65
  • 66. Communication entre vues (Selection Service) Toutes modifications de sélection réalisées par les fournis- seurs (Provider) sont transmises aux écouteurs (Listener) Le service de sélection est unique pour chaque Workbench Window Il fonctionne à la manière d’un Bus où tout fournisseur peut se connecter et où tout écouteur peut s’abonner Des fournisseurs spécifiques Des écouteurs existants de la plateforme keulkeul.blogspot.com Des fournisseurs existants de la plateforme Instance unique par Workbench Window Views - M. Baron - Page 66
  • 67. Communication entre vues (Selection Service) L’écouteur reçoit des informations liées à la sélection L’origine de la sélection (le fournisseur) Les informations de la sélection (les objets) Les informations de la sélection sont de deux natures Une liste d’objets (une ligne d’un composant TableViewer) Une zone de texte (un bloc de texte d’un éditeur) La structure de données est définie par l’interface ISelection (vue dans la partie Composants Additionnels avec Java) keulkeul.blogspot.com Views - M. Baron - Page 67
  • 68. Communication entre vues (Selection Service) Un fournisseur doit implémenter l’interface ISelectionProvider Tous les composants Viewer de JFace sont des fournisseurs de sélection void addSelectionChangedListener(ISelectionChangedListener) : ajout d’un écouteur sur la sélection courante ISelection getSelection() : récupère la sélection courante void setSelection(ISelection) : modifie la sélection courante Toutefois, cette sélection est locale au composant Viewer Pour la diffuser au service de sélection il est nécessaire de keulkeul.blogspot.com connecter un objet ISelectionProvider au Workbench getSite().setSelectionProvider(tableViewer); Site de la ViewPart Objet ISelectionProvider à contenant le Viewer connecter au service de sélection Views - M. Baron - Page 68
  • 69. Communication entre vues (Selection Service) Différents types de données de sélections en fonction du type de composant Viewer ComboViewer IStructuredSelection ListViewer IStructuredSelection TreeViewer IStructuredSelection, ITreeSelection CheckboxTreeViewer IStructuredSelection, ITreeSelection TableViewer IStructuredSelection CheckboxTableViewer IStructuredSelection keulkeul.blogspot.com TextViewer ITextSelection, IMarkSelection SourceViewer ITextSelection, IMarkSelection ProjectionViewer ITextSelection, IMarkSelection Views - M. Baron - Page 69
  • 70. Communication entre vues (Selection Service) Chaque Workbench Window fournit un service de sélection de type ISelectionService ISelectionService selService = getSite().getWorkbenchWindow().getSelectionService() Le service de sélection fournit les méthodes suivantes ISelection getSelection() : récupère la dernière sélection active ISelection getSelection(String partId) : récupère la sélection de la ViewPart définie par partId void addSelectionListener(ISelectionListener listener) : ajoute un écouteur sur les changements de sélection (voir transparent suivant) void addSelectionListener(String partId, ISelectionListener listener) : keulkeul.blogspot.com ajoute un écouteur sur les changements de la sélection d’une vue void addPostSelectionListener(ISelectionListener listener) : ajoute un écouteur sur des changements finaux Exemple ListViewer : l’écouteur ne sera averti qu’après un certain délai de manière à éviter les sélections multiples - M. Baron - Page 70 Views
  • 71. Communication entre vues (Selection Service) L’interface ISelectionListener fournit une seule méthode public void selectionChanged(IWorkbenchPart part, ISelection s) : déclenchée lors du changement de la sélection courante L’interface INullSelectionListener (étend ISelectionListener) ne fournit aucune méthode (Interface de marquage), elle est utilisée dans les cas d’une non sélection keulkeul.blogspot.com Activation d’une ViewPart non connectée au service de sélection Toutes les vues et éditeurs du Workbench Window sont fermées Views - M. Baron - Page 71
  • 72. Communication entre vues (Selection Service) Exemple : 1 vue productrice, 1 vue consommatrice ProviderViewPart.java du projet LinkViewExample package eclipse.workbench.linkviewexample.views public class ProviderViewPart extends ViewPart { private TableViewer viewer; public void createPartControl(Composite parent) { viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); viewer.setContentProvider(new ViewContentProvider()); viewer.setLabelProvider(new ViewLabelProvider()); viewer.setInput(getViewSite()); this.getSite().setSelectionProvider(viewer); } ... } keulkeul.blogspot.com Connexion du SelectionProvider (viewer) au service de sélection Views - M. Baron - Page 72
  • 73. Communication entre vues (Selection Service) Exemple (suite) : 1 vue productrice, 1 vue consommatrice package eclipse.workbench.linkviewexample.views ListenerViewPart.java du projet public class ListenerViewPart extends ViewPart { LinkViewExample private Label listenerLabel; Récupération du service de public void createPartControl(Composite parent) { parent.setLayout(new GridLayout(1, false)); sélection du Workbench Window listenerLabel = new Label(parent, SWT.NONE); this.getSite().getWorkbenchWindow().getSelectionService().addSelectionListener(" eclipse.workbench.LinkViewExample.views.ProviderViewPartId", new ISelectionListener() { public void selectionChanged(IWorkbenchPart part, ISelection selection) { if (selection == null) { return; Ecouteur sur la sélection de } la vue ProviderViewPartId if (selection instanceof IStructuredSelection) { IStructuredSelection structuredSelection = (IStructuredSelection)selection; Object firstElement = structuredSelection.getFirstElement(); if (firstElement != null) { listenerLabel.setText(firstElement.toString()); listenerLabel.getParent().pack(); keulkeul.blogspot.com } } } }); } Utile pour redimensionner } ... le parent Views - M. Baron - Page 73
  • 74. Communication entre vues (Selection Service) Exemple : plusieurs TableViewers d’une ViewPart connectés au service de sélection Une vue utilisée pour écouter les changements de sélection de la vue Une vue contient deux Multiple Providers composants TableViewer keulkeul.blogspot.com Utilisation de la classe SelectionProviderIntermediate permettant de déléguer un SelectionProvider d’une ViewPart au service de sélection www.eclipse.org/articles/Article-WorkbenchSelections/article.html Views - M. Baron - Page 74
  • 75. Communication entre vues (Selection Service) Exemple (suite) : plusieurs TableViewers d’une ViewPart connectés au service de sélection package eclipse.workbench.multipleprovidersexample SelectionProvider « maison » utilisé pour public class MultipleProvidersViewPart extends ViewPart { connecter dynamiquement le Viewer de private Label listenerLabel; la ViewPart au service de sélection public void createPartControl(Composite parent) { final SelectionProviderIntermediate selectionProvider = new SelectionProviderIntermediate(); viewer1 = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); viewer1.setContentProvider(new ViewContentProvider()); viewer1.setLabelProvider(new ViewLabelProvider()); viewer1.setInput(getViewSite()); viewer2 = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); viewer2.setContentProvider(new ViewContentProvider()); viewer2.setLabelProvider(new ViewLabelProvider()); viewer2.setInput(getViewSite()); keulkeul.blogspot.com this.getSite().setSelectionProvider(selectionProvider); ... } Le reste du code est présenté ... dans la suite } MultipleProvidersViewPart.java du projet MultipleProvidersExample Views - M. Baron - Page 75
  • 76. Communication entre vues (Selection Service) Exemple (suite) : plusieurs TableViewers d’une ViewPart connectés au service de sélection package eclipse.workbench.multipleprovidersexample public class SelectionProviderIntermediate implements IPostSelectionProvider { private final ListenerList selectionListeners = new ListenerList(); private final ListenerList postSelectionListeners = new ListenerList(); private ISelectionProvider delegate; public void setSelectionProviderDelegate(ISelectionProvider newDelegate) { if (delegate == newDelegate) { return; } if (delegate != null) { delegate.removeSelectionChangedListener(selectionListener); if (delegate instanceof IPostSelectionProvider) { ((IPostSelectionProvider)delegate).removePostSelectionChangedListener(postSelectionListener); } } delegate = newDelegate; if (newDelegate != null) { newDelegate.addSelectionChangedListener(selectionListener); if (newDelegate instanceof IPostSelectionProvider) { ((IPostSelectionProvider)newDelegate).addPostSelectionChangedListener(postSelectionListener); } keulkeul.blogspot.com fireSelectionChanged(newDelegate.getSelection()); firePostSelectionChanged(newDelegate.getSelection()); Chaque SelectionProvider } } délégué est écouté ... } SelectionProviderIntermediate.java du projet MultipleProvidersExample inspirée de www.eclipse.org/articles/Article-WorkbenchSelections/article.html Views - M. Baron - Page 76
  • 77. Communication entre vues (Selection Service) Exemple (suite) : plusieurs TableViewers d’une ViewPart connectés au service de sélection package eclipse.workbench.multipleprovidersexample A chaque changement de sélection public class MultipleProvidersViewPart extends ViewPart { d’un TableViewer modification du private Label listenerLabel; SelectionProvider via la classe de public void createPartControl(Composite parent) { délégation ... // Voir précédent transparent viewer1.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { selectionProvider.setSelectionProviderDelegate(viewer1); } }); viewer2.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { selectionProvider.setSelectionProviderDelegate(viewer2); keulkeul.blogspot.com } }); ... } ... } Suite de MultipleProvidersViewPart.java du projet MultipleProvidersExample Views - M. Baron - Page 77
  • 78. Communication entre vues (IAdaptable) Précédemment nous avons étudié le service de sélection qui permet de récupérer la sélection courante ISelection Pour rappel un objet de type ISelection « véhicule » l’objet modèle d’un composant viewer Un écouteur du service de sélection (généralement une vue) doit interpréter l’objet véhiculé pour le traduire en un objet exploitable Inconvénients : couplage fort L’écouteur (la vue) doit connaître le type de l’objet véhiculé keulkeul.blogspot.com Nécessite une adaptation de l’écouteur à chaque nouveau type d’objet véhiculé Dans certains, il n’est pas possible de modifier le code de l’écouteur car il peut s’agir d’une vue de la plateforme : vue Properties Views - M. Baron - Page 78
  • 79. Communication entre vues (IAdaptable) Service La vue Properties n’écoutent La vue Package Sélection que les objets de type Explorer manipule IPropertySource des objets d’un certains type Objets consommés par Les objets de la vue Package la vue Explorer sont adaptés en type Properties IPropertySource keulkeul.blogspot.com Les objets de la vue Multiple Providers ne sont pas consommés car la vue Properties La vue Multiple Providers ne traite que les objets de type fournit des objets de type IPropertySource String Views - M. Baron - Page 79
  • 80. Communication entre vues (IAdaptable) L’écouteur ne doit manipuler que des objets dont il a connaissance Exemple : la vue Properties ne peut manipuler que des objets de type IPropertySource La transformation des objets du producteur en objet écouteur utilise la patron de conception : adaptateur Nous allons montrer dans la suite comment exploiter le service de sélection de manière à réduire le couplage entre keulkeul.blogspot.com l’écouteur et le producteur Pour ce faire trois approches seront étudiées appliqué à un exemple commun Views - M. Baron - Page 80
  • 81. Communication entre vues (IAdaptable) Exemple : carnet d’adresse avec informations de création et de mise à jour keulkeul.blogspot.com La vue Properties affiche des Un composant ListViewer informations complémentaires affiche la liste des noms lorsque un contact est sélectionné du carnet d’adresse Views - M. Baron - Page 81
  • 82. Communication entre vues (IAdaptable) Exemple (suite) : carnet d’adresse avec informations de création et de mise à jour public class ContactView extends ViewPart { public void createPartControl(Composite parent) { ... final ListViewer contactsList = new ListViewer(container, SWT.BORDER); contactsList.setLabelProvider(new ListLabelProvider()); contactsList.setContentProvider(new ContentProvider()); contactsList.setInput(Activator.getDefault().getContactManager()); getViewSite().setSelectionProvider(contactsList); } class ContentProvider implements IStructuredContentProvider { public Object[] getElements(Object inputElement) { Manager contactManager = (Manager) inputElement; return contactManager.contacts(); } ... } class ListLabelProvider extends LabelProvider { keulkeul.blogspot.com public String getText(Object element) { Contact contact = (Contact) element; return contact.getName(); } ... } } Vue définie par ContactView.java commune aux trois approches Views - M. Baron - Page 82
  • 83. Communication entre vues (IAdaptable) Exemple (suite) : carnet d’adresse avec informations de création et de mise à jour public class ContactManager { List<Contact> contacts; public ContactManager() { this.contacts = new ArrayList<Contact>(); Contact contact = new Contact("Mickael BARON", "1 rue des Eclipses"); contact.setProperty("Created", "2008/04/05 11:44"); contact.setProperty("Updated", "2008/04/05 11:53"); this.contacts.add(contact); contact = new Contact("Tom STORY", "11 rue du Pixar"); contact.setProperty("Created", "2008/04/05 15:21"); contact.setProperty("Updated", "2008/04/07 09:48"); this.contacts.add(contact); contact = new Contact("Sarah PRINCESSE", "32 rue des Goonies"); contact.setProperty("Created", "2008/04/06 10:34"); this.contacts.add(contact); keulkeul.blogspot.com } public Contact[] contacts() { return (Contact[])this.contacts.toArray(new Contact[0]); } } Fabrique des contacts définie par ContactManager.java commune aux trois approches Views - M. Baron - Page 83
  • 84. Communication entre vues (IAdaptable) Exemple (suite) : carnet d’adresse avec informations de création et de mise à jour public class Contact { private String address; private String name; private Map<String, Object> properties; public Contact(String name, String address) { this.name = name; this.address = address; } public String getAddress() { return this.address; } public String getName() { return this.name; } public synchronized Map<String, Object> getProperties() { if (this.properties == null) { return Collections.emptyMap(); } return new HashMap<String, Object>(this.properties); } public synchronized void setProperty(String key, Serializable value) { keulkeul.blogspot.com if (this.properties == null) { this.properties = new HashMap<String, Object>(); } this.properties.put(key, value); } ... // Le reste est spécifique à chaque approche, à voir dans la suite } Classe Contact.java qui décrit l’objet envoyé lors d’une sélection Views - M. Baron - Page 84
  • 85. Communication entre vues (IAdaptable) La première approche consiste à typer l’objet du producteur du type de l’objet manipulé par l’écouteur Avantage Très simple à mettre en œuvre Inconvénients Le producteur connaît le type de l’objet du producteur keulkeul.blogspot.com Si plusieurs écouteurs avec des types différents nécessite plusieurs implémentations (à condition que l’écouteur fournit une interface) Si nouvelle adaptation, nécessite de modifier le code du producteur Views - M. Baron - Page 85
  • 86. Communication entre vues (IAdaptable) Approche 1 : typer l’objet du producteur du type de l’objet manipulé par l’écouteur package eclipse.workbench.iadaptableexample1; La vue Properties ne public class Contact implements IPropertySource { consomme que des objets de ... // Voir code commun type IPropertySource public Object getEditableValue() { return null; } public IPropertyDescriptor[] getPropertyDescriptors() { List<PropertyDescriptor> descriptors = new ArrayList<PropertyDescriptor>(); Map<String, Object> properties = this.getProperties(); for (String key : properties.keySet()) { PropertyDescriptor descriptor = new PropertyDescriptor(key, key); descriptor.setAlwaysIncompatible(true); descriptors.add(descriptor); } return descriptors.toArray(new IPropertyDescriptor[0]); } public Object getPropertyValue(Object id) { keulkeul.blogspot.com Map<String, Object> properties = this.getProperties(); return properties.get(id); } public boolean isPropertySet(Object id) { return false; } public void resetPropertyValue(Object id) { } public void setPropertyValue(Object id, Object value) { } } Classe Contact.java du projet IAdaptableExample1 Views - M. Baron - Page 86
  • 87. Communication entre vues (IAdaptable) La première approche consiste à typer l’objet du producteur du type de l’objet manipulé par l’écouteur Avantage Très simple à mettre en œuvre Inconvénients Le producteur connaît le type de l’objet du producteur keulkeul.blogspot.com Si plusieurs écouteurs avec des types différents nécessite plusieurs implémentations (à condition que l’écouteur fournit une interface) Si nouvelle adaptation, nécessite de modifier le code du producteur Views - M. Baron - Page 87
  • 88. Communication entre vues (IAdaptable) La deuxième approche consiste à implémenter l’interface IAdaptable Object getAdapter(Class adapter) : une adaptation est demandée du type défini par adapter. Le retour est un objet adapté du type du producteur vers le type adapter (écouteur) Démarche de développement : en fonction du type du paramètre adapter déléguer l’adaptation à un objet de type adapter Avantage La gestion de plusieurs types objets est facilitée car il ne s’agit plus keulkeul.blogspot.com d’héritage mais de délégation Inconvénients Le producteur connaît le type de l’objet du producteur Si nouvelle adaptation, nécessite de modifier le code du producteur Views - M. Baron - Page 88
  • 89. Communication entre vues (IAdaptable) Approche 2 : utilisation de IAdaptable avec couplage avec le type de l’écouteur La vue Properties exploite le patron de conception adaptateur pour adapter un objet Contact en IPropertySource package eclipse.workbench.iadaptableexample2; public class Contact implements IAdaptable { ... // Voir code commun public Object getAdapter(Class adapter) { if (adapter == IPropertySource.class) { return new ContactPropertySourceAdapter(this); } else { return null; } keulkeul.blogspot.com } } La classe ContactPropertySourceAdapter est Classe Contact.java du projet de type IPropertySource IAdaptableExample2 Views - M. Baron - Page 89
  • 90. Communication entre vues (IAdaptable) Approche 2 (suite) : utilisation de IAdaptable avec couplage avec le type de l’écouteur package eclipse.workbench.iadaptableexample2; public class ContactPropertySourceAdapter implements IPropertySource { private Contact contact; public ContactPropertySourceAdapter(Contact contact) { this.contact = contact; } public Object getEditableValue() { return this; } public IPropertyDescriptor[] getPropertyDescriptors() { List<PropertyDescriptor> descriptors = new ArrayList<PropertyDescriptor>(); Map<String, Object> properties = this.contact.getProperties(); for (String key : properties.keySet()) { PropertyDescriptor descriptor = new PropertyDescriptor(key, key); descriptor.setAlwaysIncompatible(true); } descriptors.add(descriptor); Code spécifique à return descriptors.toArray(new IPropertyDescriptor[0]); IPropertySource découplé } de l’objet Contact public Object getPropertyValue(Object id) { Map<String, Object> properties = this.contact.getProperties(); keulkeul.blogspot.com return properties.get(id); } public boolean isPropertySet(Object id) { return false; } public void resetPropertyValue(Object id) {} public void setPropertyValue(Object id, Object value) {} } Classe ContactPropertySourceAdapter.java du projet IAdaptableExample2 Views - M. Baron - Page 90
  • 91. Communication entre vues (IAdaptable) La troisième approche consiste à passer par une extension pour réaliser l’adaptateur L’extension permet de définir Le type à adapter (l’objet du producteur) La fabrique des objets utilisée pour convertir le type du producteur dans les types des écouteurs La liste des types des écouteurs que la fabrique peut adapter Avantage L’adaptation en un type donné devient en partie déclarative keulkeul.blogspot.com L’adaptation peut être réalisée en dehors du code du producteur Inconvénient Pas simple à première vue, mais nous allons y remédier … Views - M. Baron - Page 91
  • 92. Communication entre vues (IAdaptable) Approche 3 : utilisation de IAdaptable sans couplage avec le type de l’écouteur L’implémentation à l’interface IAdaptable n’est La demande d’adaptation pas obligatoire est déléguée à Platform package eclipse.workbench.iadaptableexample3; public class Contact implements IAdaptable { ... // Voir code commun public Object getAdapter(Class adapter) { return Platform.getAdapterManager().getAdapter(this, adapter); } } keulkeul.blogspot.com L’objet du producteur n’est plus Classe Contact.java du projet couplé aux objets des IAdaptableExample3 écouteurs Views - M. Baron - Page 92
  • 93. Communication entre vues (IAdaptable) Approche 3 (suite) : utilisation de IAdaptable sans couplage avec le type de l’écouteur Utilisation du point d’extension org.eclipse.core.runtime.adapters keulkeul.blogspot.com Views - M. Baron - Page 93
  • 94. Communication entre vues (IAdaptable) Approche 3 (suite) : utilisation de IAdaptable sans couplage avec le type de l’écouteur Défini le type à adapter La fabrique des objets utilisée pour Liste des types des écouteurs keulkeul.blogspot.com convertir le type du producteur dans les types des écouteurs Onglet Extensions Views - M. Baron - Page 94
  • 95. Communication entre vues (IAdaptable) Approche 3 (suite) : utilisation de IAdaptable sans couplage avec le type de l’écouteur La fabrique des objets utilisée pour convertir le type du producteur dans les types des écouteurs package eclipse.workbench.iadaptableexample3; public class ContactAdapterFactory implements IAdapterFactory { private static final Class[] TYPES = { IPropertySource.class }; public Object getAdapter(Object adaptableObject, Class adapterType) { if (adapterType == IPropertySource.class) { if (adaptableObject instanceof Contact) { return new ContactPropertySourceAdapter((Contact) adaptableObject); } } return null; } Classe équivalente à celle du projet keulkeul.blogspot.com public Class[] getAdapterList() { return TYPES; IAdaptableExample2 } } Classe ContactAdapterFactory.java du projet IAdaptableExample3 Views - M. Baron - Page 95