Construction de vues avec la plateforme Eclipse

5 279 vues

Publié le

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

Publié dans : Technologie, Business
0 commentaire
2 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

Aucun téléchargement
Vues
Nombre de vues
5 279
Sur SlideShare
0
Issues des intégrations
0
Intégrations
1 507
Actions
Partages
0
Téléchargements
141
Commentaires
0
J’aime
2
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Construction de vues avec la plateforme Eclipse

  1. 1. Développement de clients riches : Plateforme Eclipse Mickaël BARON – 2009 (Rev. Juillet 2010) mailto:baron.mickael@gmail.com ou mailto:baron@ensma.fr @mickaelbaron Chapitre 3 : Conception de plug-ins Workbench : Views
  2. 2. 2Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Creative Commons Contrat Paternité Partage des Conditions Initiales à l'Identique 2.0 France http://creativecommons.org/licenses/by-sa/2.0/fr Licence
  3. 3. 3Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Organisation du cours sur le Workbench : Views Tous les exemples du cours sont disponibles directement à l’adresse mbaron.developpez.com/eclipse/views † Construction déclarative † ViewPart, StickyView et Category † Vues multiples † Registre des vues † Cycle de vie † Communication entre vues
  4. 4. 4Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † Eclipse 3.4.2 Ganymede † Pré-requis † Connaître la boite à outils SWT, JFace † Connaître la structure d’un plug-ins et savoir créer une extension † Remerciements † Developpez.com : djo.mos (Jawher MOUSSA) † … Ceci est une alerte Ceci est une astuce
  5. 5. 5Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † Des livres † Eclipse – Building Commercial-Quality Plug-ins, 2004 - ISBN : 0-321-22847-2 † Eclipse – Rich Client Platform, 2005 – ISBN : 0-321-33461-2
  6. 6. 6Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † construction de vues multiples † construction de vues de type Sticky Views † registre des vues † mécanismes de communication entre les vues
  7. 7. 7Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Généralités IWorkbenchPage activate(IWorkbenchPart) bringToTop(IWorkbenchPart) findView(String) getViewReferences() hideView(IViewPart) showView(String) IWorkbenchPartReference getId() getPage() getPart(boolean) IViewReference getView(boolean) isFastView() WorkbenchPart dispose() getConfigurationElement() getSite() setPartName(String) ViewPart getViewSite() init(IViewSite) init(IViewSite, IMemento) saveState(IMemento) IWorkbenchPart createPartControl(Composite) dispose() getSite() IViewPart getViewSite() init(IViewSite) init(IViewSite, IMemento) saveState(IMemento) IWorkbenchSite getPage() getSelectionProvider() getShell() getWorkbenchWindow() setSelectionProvider(ISelectionProvider) IWorkbenchPartSite getKeyBindingService() registerContextMenu(MenuManager, ISelectionProvider) registerContextMenu(String, MenuManager, ISelectionProvider) IViewSite getActionBars() † Principales interfaces et classes pour la gestion des vues Dépendance Héritage
  8. 8. 8Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Construction d'une vue par extension † Sélectionner le point d’extension org.eclipse.ui.views Création d’une vue à partir du template Sample View Création d’une extension à partir du point d’extension org.eclipse.ui.views
  9. 9. 9Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 Possibilité d’avoir plusieurs instances de cette vue Possibilité de retrouver la vue après un redémarrage du Workbench
  10. 10. 10Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Construction d'une vue par extension † Etendre une vue de type ViewPart 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"); } public void setFocus() { } } SimpleView.java du Projet ViewExample Création du contenu en utilisant des composants SWT
  11. 11. 11Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 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
  12. 12. 12Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 Les déclarations d’actions, d’un menu contextuel et de la sélection seront étudiés en détail dans la suite
  13. 13. 13Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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) : 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
  14. 14. 14Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 Le contenu de la vue est défini par la méthode createPartControl L’ajout d’actions se fait via le site de la vue Sera utilisée dans la partie Vues Multiples
  15. 15. 15Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron ViewPart et IViewSite † Exemple : accéder aux éléments du site d’une vue package eclipse.workbench.viewexample.views public class SiteView extends ViewPart { public void createPartControl(Composite parent) { parent.setLayout(new GridLayout(2,true)); Button buttonLeft = new Button(parent, SWT.FLAT); buttonLeft.setText("LEFT_Button"); Button buttonRight = new Button(parent, SWT.FLAT); buttonRight.setText("RIGHT_Button"); 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()); viewer.getControl().setLayoutData(myGridData); viewer.setInput(this.getViewSite()); this.createActions(); this.createToolBar(); this.createContextMenu(); } } SiteView.java du Projet ViewExample Modification de l’agent de placement du parent Construction de l’interface à partir de composants SWT Création des actions, de la barre d’outils et du menu contextuel
  16. 16. 16Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron ViewPart et IViewSite † Exemple (suite) : accéder aux éléments du site d’une vue ... private void createActions() { action1 = new Action("Action 1") { public void run() { System.out.println("Action 1 Performed"); } }; 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()); mgr.add(action2); } }); Menu menu = menuMgr.createContextMenu(viewer.getControl()); Viewer.getControl().setMenu(menu); getSite().registerContextMenu(menuMgr, viewer); } SiteView.java du Projet ViewExample Ce menu est déclaré dans le Workbench. L’extension du menu devient possible
  17. 17. 17Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † 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)
  18. 18. 18Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Sticky View † Création d’une vue classique plugin.xml du projet ViewExample Onglet Extensions
  19. 19. 19Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Sticky View † Création d’une vue classique (suite) package eclipse.workbench.viewexample.views public class StickyViewPart extends ViewPart { public StickyViewPart() { } public void createPartControl(Composite parent) { Label myCurrentLabel = new Label(parent, SWT.NONE); myCurrentLabel.setText("View used for the StickyView ViewExample series"); } public void setFocus() { } } StickyViewPart.java du projet ViewExample plugin.xml du projet ViewExample
  20. 20. 20Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Sticky View † Création d’une Sticky View Onglet Extensions plugin.xml du projet ViewExample
  21. 21. 21Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Sticky View † Association d’une vue avec une Sticky View Vue qui sera transformée en Sticky View Identifiant d’une vue existante Position de la Sticky View dans les perspectives (BOTTOM, RIGHT, LEFT, TOP) Précise si la Sticky View peut elle être fermée ? La Sticky View peut elle être déplacée plugin.xml du projet ViewExample
  22. 22. 22Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Sticky View † Exemple : une vue transformée en Sticky View La Sticky View est visible et conserve son emplacement lors des changements des perspectives Projet ViewExample
  23. 23. 23Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 une catégorie parente existante † Les catégories sont identifiées par un identifiant unique Plusieurs catégories existantes : General, Debug, Help, Java, …
  24. 24. 24Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Category † Création d’une Category plugin.xml du projet ViewExample Création d’une nouvelle catégorie Identifiant de la nouvelle catégorie Nom de la nouvelle catégorie Parent de la catégorie (optionnelle) Onglet Extensions
  25. 25. 25Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Category † Associer la vue à la catégorie plugin.xml du projet ViewExample Onglet Extensions La vue ViewCategory est associée à la catégorie *.ViewExample.Category La liste des vues est accessible via le menu Window -> Show View -> Other La vue ViewCategory est contenu dans la catégorie Category Example
  26. 26. 26Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † 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
  27. 27. 27Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Vue Détachée † Exemple : Détecter qu’une vue est détachée La vue Detach View est détachée
  28. 28. 28Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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(); } private void updateDetached() { isDetached = parent.getShell().getText().length() == 0; label.setText("View isDetached? " + isDetached); } ... } DetachViewPart.java du Projet ViewExample
  29. 29. 29Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Vue Détachée † Exemple : Attacher et Détacher une vue par code Attache ou Détache une vue selon son état Détaché ou pas
  30. 30. 30Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Vue Détachée † Exemple (suite) : Attacher et Détacher une vue par code public class OpenDetachViewPart extends DetachViewPart { public OpenDetachViewPart() { } @Override public void createPartControl(Composite parent) { 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); } } }); detachViewButton.setText("Attach/Detach"); } ... } AttachOrDetachViewPart.java du Projet ViewExample Réutilise la vue DetachViewPart pour connaître l’état de la vue
  31. 31. 31Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 d’une même vue † Un second identifiant est utilisé pour la création d’instances multiples
  32. 32. 32Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † Pour activer la gestion des instances multiples d’une vue, il faut modifier le paramètre allowMultiple à true † Différentes manières de construire une instance multiple d’une vue Identifiant_Primaire:Identifiant_Secondaire Identifiant primaire déclaré lors de la définition de la vue Identifiant secondaire déclaré pour chaque nouvelle instance de la vue
  33. 33. 33Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Vues multiples Identifiant primaire de la vue Multiple Instances View 1 Ne pas ajouter un identifiant secondaire lors de la définition de la vue † Activation de la gestion multiple d’une vue La gestion multiple de cette vue est activée
  34. 34. 34Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Vues multiples † Exemple 1 : Vues multiples à partir de IPageLayout 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); } } MultipleInstancesViewFactory.java du projet ViewExample Création de deux instances de la même vue Création statique d’instances multiples de la vue
  35. 35. 35Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Vues multiples MultipleInstancesViewFactory du projet ViewExample La vue Multiple Instances View 1 est instanciée deux fois † Exemple 1 (suite) : Vues multiples à partir de IPageLayout
  36. 36. 36Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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) { e.printStackTrace(); } } public void selectionChanged(IAction action, ISelection selection) { } public void dispose() { } public void init(IWorkbenchWindow window) { } } AddSecondaryViewAction.java du projet ViewExample La méthode showView permet d’ajouter une vue en donnant un identifiant secondaire Création dynamique d’instances multiples de la vue
  37. 37. 37Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Vues multiples † Exemple 2 (suite) : Vues multiples à partir de IWorkbench… AddSecondaryViewAction du projet ViewExample Action permettant la création de nouvelles instances de vue Plusieurs instances de vue
  38. 38. 38Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron † 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 † VIEW_VISIBLE : vue visible mais n’a pas le focus † VIEW_CREATE : vue créée mais n’a pas forcément le focus Vues multiples
  39. 39. 39Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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); myButton.setText("Give me the Secondary ID"); 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 Identifiant secondaire
  40. 40. 40Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 IViewRegistry viewRegistry = PlatformUI.getWorkbench().getViewRegistry(); L’interface IViewRegistry est détaillée dans la suite
  41. 41. 41Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † 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
  42. 42. 42Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † 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
  43. 43. 43Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  44. 44. 44Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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(); IViewCategory[] categories = viewRegistry.getCategories(); for (IViewCategory viewCategory : categories) { System.out.println(viewCategory.getLabel()); } } }); getCategories.setText("Get Categories"); ... } } ViewRegistryViewPart.java du projet ViewExample
  45. 45. 45Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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()); } } }); getViews.setText("Get Views"); } } ViewRegistryViewPart.java du projet ViewExample
  46. 46. 46Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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) † 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)
  47. 47. 47Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † String getPartName() : le nom à afficher † … † L’accès à un objet IViewReference se fait par l’intermédiaire du Workbench Page actif
  48. 48. 48Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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) † 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
  49. 49. 49Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie – ouverture d’une vue Ouverture de la vue SimpleView dans la perspective Resource Création d’une instance de la classe SimpleView.java du projet ViewExample stockée dans la page courante La vue SimpleView n’a jamais encore été ouverte † Démonstration …
  50. 50. 50Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie – ouverture d’une vue La vue SimpleView est déjà ouverte dans la perspective Resource La vue SimpleView est ajoutée à la perspective SimplePerspective Comme une instance à SimpleView existe, aucune autre instance n’est créée † Démonstration (suite) …
  51. 51. 51Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † Constructeur de la classe † 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, … † void init(IViewSite) : initialise l’instance avec le site † void init(IViewSite, IMemento) : idem sauf que l’objet IMemento permet de restaurer un état (voir fermeture d’une vue) † void createPartControl(Composite) : pour programmer l’IHM † Méthodes appelées uniquement à la création de l’instance 1 2 3 4 5
  52. 52. 52Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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() { } public void createPartControl(Composite parent) { } public void setFocus() { } } OpenLifeCycle du projet ViewExample Récupération des informations de l’extension utilisée par la création de cette vue
  53. 53. 53Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † Visible : la vue est visible † Activated : la vue a le focus La vue SimpleView a été ajoutée par le menu Show View Les différents états de la vue : Opened -> Visible -> Activated
  54. 54. 54Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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- mée de la liste des IViewReference du Workbench Page † Une nouvelle référence doit être créée pour ré-ouvrir la vue
  55. 55. 55Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † Deactivated : la vue n’a plus le focus † Hidden : la vue est cachée † Closed : l’instance de la vue est disposée
  56. 56. 56Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † Communication directe entre des ViewParts † Communication à partir des écouteurs de vues † Service de sélection † Le patron Adaptateur via IAdaptable
  57. 57. 57Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 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
  58. 58. 58Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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; public LinkView2() { } 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); fnameText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { firstName = fnameText.getText(); } }); } ... } LinkView2.java du projet LinkViewExample Attribut spécifique à la classe LinkView2.java Perspective Link Direct
  59. 59. 59Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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"); } } }); getLinkView2DataButton.setText("Retrieve information from LinkView2"); } ... } LinkView1.java du projet LinkViewExample
  60. 60. 60Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † 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
  61. 61. 61Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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(); String firstName = ((LinkView2)findView).getFirstName(); System.out.println(familyName + " " + firstName); } else { System.out.println("Instance de vue non créée"); } } }); getLinkView2DataButton.setText("Retrieve information from LinkView2"); } ... } MultipleLinkView.java du projet LinkViewExample Récupération de l’instance d’une ViewPart par rapport à l’identifiant primaire et secondaire
  62. 62. 62Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † IWorkbenchPartReference getActivePartReference() : Part référence active † L’écouteur IPartListener est à remplacer par l’interface IPartListener2
  63. 63. 63Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † 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 …
  64. 64. 64Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (Part Listeners) † Exemple : écouter les changements d’une ViewPart package eclipse.workbench.ipartserviceexample.views public class PartListenerViewPart extends ViewPart { public void createPartControl(Composite parent) { parent.setLayout(new GridLayout(1, false)); 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()"); } } @Override public void partBroughtToTop(IWorkbenchPartReference partRef) { IWorkbenchPart part = partRef.getPart(false); if (PartListenerViewPart.this == part) { System.out.println(".partBroughtToTop()"); } } @Override public void partClosed(IWorkbenchPartReference partRef) { IWorkbenchPart part = partRef.getPart(false); if (PartListenerViewPart.this == part) { System.out.println(".partClosed()"); } } } ... } PartListenerViewPart.java du projet IPartServiceExample Liste des méthodes déclenchées lors de l’écoute de la ViewPart
  65. 65. 65Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 Le changement de sélection d’un fichier provoque la modification de la vue Properties
  66. 66. 66Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 Instance unique par Workbench Window Des fournisseurs existants de la plateforme Des écouteurs existants de la plateforme Des fournisseurs spécifiques
  67. 67. 67Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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)
  68. 68. 68Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 connecter un objet ISelectionProvider au Workbench getSite().setSelectionProvider(tableViewer); Site de la ViewPart contenant le Viewer Objet ISelectionProvider à connecter au service de sélection
  69. 69. 69Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (Selection Service) † Différents types de données de sélections en fonction du type de composant Viewer † ComboViewer † ListViewer † TreeViewer † CheckboxTreeViewer † TableViewer † CheckboxTableViewer † TextViewer † SourceViewer † ProjectionViewer IStructuredSelection IStructuredSelection IStructuredSelection, ITreeSelection IStructuredSelection, ITreeSelection IStructuredSelection IStructuredSelection ITextSelection, IMarkSelection ITextSelection, IMarkSelection ITextSelection, IMarkSelection
  70. 70. 70Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (Selection Service) † Chaque Workbench Window fournit un service de sélection de type ISelectionService † 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) : 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 ISelectionService selService = getSite().getWorkbenchWindow().getSelectionService()
  71. 71. 71Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † Activation d’une ViewPart non connectée au service de sélection † Toutes les vues et éditeurs du Workbench Window sont fermées
  72. 72. 72Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (Selection Service) † Exemple : 1 vue productrice, 1 vue consommatrice 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); } ... } ProviderViewPart.java du projet LinkViewExample Connexion du SelectionProvider (viewer) au service de sélection
  73. 73. 73Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (Selection Service) † Exemple (suite) : 1 vue productrice, 1 vue consommatrice package eclipse.workbench.linkviewexample.views public class ListenerViewPart extends ViewPart { private Label listenerLabel; public void createPartControl(Composite parent) { parent.setLayout(new GridLayout(1, false)); 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; } if (selection instanceof IStructuredSelection) { IStructuredSelection structuredSelection = (IStructuredSelection)selection; Object firstElement = structuredSelection.getFirstElement(); if (firstElement != null) { listenerLabel.setText(firstElement.toString()); listenerLabel.getParent().pack(); } } } }); } ... } ListenerViewPart.java du projet LinkViewExample Ecouteur sur la sélection de la vue ProviderViewPartId Utile pour redimensionner le parent Récupération du service de sélection du Workbench Window
  74. 74. 74Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (Selection Service) † Exemple : plusieurs TableViewers d’une ViewPart connectés au service de sélection Une vue contient deux composants TableViewer Une vue utilisée pour écouter les changements de sélection de la vue Multiple Providers 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
  75. 75. 75Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron † Exemple (suite) : plusieurs TableViewers d’une ViewPart connectés au service de sélection Communication entre vues (Selection Service) package eclipse.workbench.multipleprovidersexample public class MultipleProvidersViewPart extends ViewPart { private Label listenerLabel; 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()); this.getSite().setSelectionProvider(selectionProvider); ... } ... } MultipleProvidersViewPart.java du projet MultipleProvidersExample SelectionProvider « maison » utilisé pour connecter dynamiquement le Viewer de la ViewPart au service de sélection Le reste du code est présenté dans la suite
  76. 76. 76Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron † Exemple (suite) : plusieurs TableViewers d’une ViewPart connectés au service de sélection Communication entre vues (Selection Service) 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); } fireSelectionChanged(newDelegate.getSelection()); firePostSelectionChanged(newDelegate.getSelection()); } } ... } SelectionProviderIntermediate.java du projet MultipleProvidersExample inspirée de www.eclipse.org/articles/Article-WorkbenchSelections/article.html Chaque SelectionProvider délégué est écouté
  77. 77. 77Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 MultipleProvidersViewPart extends ViewPart { private Label listenerLabel; public void createPartControl(Composite parent) { ... // 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); } }); ... } ... } Suite de MultipleProvidersViewPart.java du projet MultipleProvidersExample A chaque changement de sélection d’un TableViewer modification du SelectionProvider via la classe de délégation
  78. 78. 78Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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é † 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
  79. 79. 79Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (IAdaptable) La vue Properties n’écoutent que les objets de type IPropertySource La vue Package Explorer manipule des objets d’un certains type La vue Multiple Providers fournit des objets de type String Service Sélection Les objets de la vue Package Explorer sont adaptés en type IPropertySource Les objets de la vue Multiple Providers ne sont pas consommés car la vue Properties ne traite que les objets de type IPropertySource Objets consommés par la vue Properties
  80. 80. 80Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 l’écouteur et le producteur † Pour ce faire trois approches seront étudiées appliqué à un exemple commun
  81. 81. 81Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (IAdaptable) † Exemple : carnet d’adresse avec informations de création et de mise à jour Un composant ListViewer affiche la liste des noms du carnet d’adresse La vue Properties affiche des informations complémentaires lorsque un contact est sélectionné
  82. 82. 82Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 { public String getText(Object element) { Contact contact = (Contact) element; return contact.getName(); } ... } } Vue définie par ContactView.java commune aux trois approches
  83. 83. 83Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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); } public Contact[] contacts() { return (Contact[])this.contacts.toArray(new Contact[0]); } } Fabrique des contacts définie par ContactManager.java commune aux trois approches
  84. 84. 84Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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) { 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
  85. 85. 85Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † 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
  86. 86. 86Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (IAdaptable) † Approche 1 : typer l’objet du producteur du type de l’objet manipulé par l’écouteur package eclipse.workbench.iadaptableexample1; public class Contact implements IPropertySource { ... // Voir code commun 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) { 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 La vue Properties ne consomme que des objets de type IPropertySource
  87. 87. 87Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † 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
  88. 88. 88Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 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
  89. 89. 89Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (IAdaptable) † Approche 2 : utilisation de IAdaptable avec couplage avec le type de l’écouteur 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; } } } Classe Contact.java du projet IAdaptableExample2 La vue Properties exploite le patron de conception adaptateur pour adapter un objet Contact en IPropertySource La classe ContactPropertySourceAdapter est de type IPropertySource
  90. 90. 90Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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); } return descriptors.toArray(new IPropertyDescriptor[0]); } public Object getPropertyValue(Object id) { Map<String, Object> properties = this.contact.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 ContactPropertySourceAdapter.java du projet IAdaptableExample2 Code spécifique à IPropertySource découplé de l’objet Contact
  91. 91. 91Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 † 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 …
  92. 92. 92Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (IAdaptable) † Approche 3 : utilisation de IAdaptable sans couplage avec le type de l’écouteur package eclipse.workbench.iadaptableexample3; public class Contact implements IAdaptable { ... // Voir code commun public Object getAdapter(Class adapter) { return Platform.getAdapterManager().getAdapter(this, adapter); } } Classe Contact.java du projet IAdaptableExample3 La demande d’adaptation est déléguée à Platform L’objet du producteur n’est plus couplé aux objets des écouteurs L’implémentation à l’interface IAdaptable n’est pas obligatoire
  93. 93. 93Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  94. 94. 94Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (IAdaptable) † Approche 3 (suite) : utilisation de IAdaptable sans couplage avec le type de l’écouteur Onglet Extensions Défini le type à adapter La fabrique des objets utilisée pour convertir le type du producteur dans les types des écouteurs Liste des types des écouteurs
  95. 95. 95Views - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Communication entre vues (IAdaptable) † Approche 3 (suite) : utilisation de IAdaptable sans couplage avec le type de l’écouteur 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; } public Class[] getAdapterList() { return TYPES; } } Classe ContactAdapterFactory.java du projet IAdaptableExample3 La fabrique des objets utilisée pour convertir le type du producteur dans les types des écouteurs Classe équivalente à celle du projet IAdaptableExample2

×