Upload
mickael-baron
View
4.213
Download
1
Embed Size (px)
DESCRIPTION
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).
Citation preview
Développement de clients riches : Plateforme Eclipse
Mickaël BARON – 2009 (Rev. Juillet 2010)mailto:[email protected] ou mailto:[email protected]
Chapitre 3 : Conception de plugChapitre 3 : Conception de plug--insins
Workbench : Views
2Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
Creative Commons
Contrat Paternité
Partage des Conditions Initiales à l'Identique
2.0 France
http://creativecommons.org/licenses/by-sa/2.0/fr
Licence
3Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
Organisation du cours sur le Workbench : Views
Tous les exemples du cours sont disponibles directement à l’adressembaron.developpez.com/eclipse/views
� Construction déclarative
� ViewPart, StickyView et Category
� Vues multiples
� Registre des vues
� Cycle de vie
� Communication entre vues
4Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
5Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
6Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
7Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
8Views - M. Baron - Page
keul
keul
.blo
gspo
t.comConstruction 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
9Views - M. Baron - Page
keul
keul
.blo
gspo
t.comConstruction d'une vue par extension
� Définir les attributs de l’extension
Identifiant de la vue
Nom de la vue
Objet de type ViewPartdé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
10Views - M. Baron - Page
keul
keul
.blo
gspo
t.comConstruction 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
11Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
12Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
13Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
14Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
15Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
16Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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.getCont rol());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
17Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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)
18Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
Sticky View
� Création d’une vue classique
plugin.xml du projet ViewExample
Onglet Extensions
19Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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 V iewExample series");
}
public void setFocus() {}
}
StickyViewPart.java du projet ViewExample
plugin.xml du projet ViewExample
20Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
Sticky View
� Création d’une Sticky View
Onglet Extensions
plugin.xml du projet ViewExample
21Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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 Viewpeut elle être fermée ?
La Sticky View peut elle être déplacée
plugin.xml du projet ViewExample
22Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
23Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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, …
24Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
25Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
26Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
27Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
Vue Détachée
� Exemple : Détecter qu’une vue est détachée
La vue Detach View est détachée
28Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
Vue Détachée
� Exemple (suite) : Détecter qu’une vue est détachéepublic class DetachViewPart extends ViewPart {
private Composite parent;private Label label;protected boolean isDetached;
public DetachViewPart() {}
@Overridepublic void createPartControl(Composite parent) {
this.parent = parent;parent.setLayout(new RowLayout());label = new Label(parent, SWT.NONE);parent.addControlListener(new ControlAdapter() {
@Overridepublic 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
29Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
30Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
Vue Détachée
� Exemple (suite) : Attacher et Détacher une vue par codepublic class OpenDetachViewPart extends DetachViewPar t {
public OpenDetachViewPart() {}
@Overridepublic void createPartControl(Composite parent) {
super.createPartControl(parent);Button detachViewButton = new Button(parent, SWT.NONE );detachViewButton.addSelectionListener(new Selection Adapter() {
public void widgetSelected(SelectionEvent e) {IWorkbenchPage page = getSite().getPage();final IViewReference findViewReference = page.findVie wReference(
"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
31Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
32Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
33Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
34Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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.javadu projet ViewExample
Création de deux instances de la même vue
Création statique d’instances
multiples de la vue
35Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
Vues multiples
MultipleInstancesViewFactorydu projet ViewExample
La vue Multiple Instances View 1 est instanciée deux fois
� Exemple 1 (suite) : Vues multiples à partir de IPageLayout
36Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
Vues multiples
� Exemple 2 : Vues multiples à partir de IWorkbenchPage
package eclipse.workbench.viewexample.views
public class AddSecondaryViewAction implements IWorkb enchWindowActionDelegate {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, ISelecti on selection) { }
public void dispose() { }
public void init(IWorkbenchWindow window) { }}
AddSecondaryViewAction.javadu 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
37Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
38Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
� 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
39Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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 vuepackage eclipse.workbench.viewexample.views
public class MultipleInstanceViewPart2 extends ViewP art {
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.javadu projet ViewExample
Identifiant secondaire
40Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
41Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
42Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
43Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
44Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
Registre des vues
� Exemple : interroger le registre des vuespackage 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 SelectionAda pter() {
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
45Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
Registre des vues
� Exemple (suite) : interroger le registre des vues
...Button getStickyViews = new Button(parent, SWT. FLAT);getStickyViews.addSelectionListener(new SelectionAd apter() {
public void widgetSelected(SelectionEvent e) {System. out.println("- Get Sticky Views -");IViewRegistry viewRegistry = PlatformUI.getWorkbench().getViewRegistry();IStickyViewDescriptor[] stickyViews = viewRegistry.getStickyViews();for (IStickyViewDescriptor stickyViewDescriptor : sti ckyViews) {
System. out.println(stickyViewDescriptor.getId() + stickyViewD escriptor.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
46Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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)
47Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
48Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCycle 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
49Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCycle de vie – ouverture d’une vue
Ouverture de la vue SimpleViewdans 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 …
50Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCycle 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) …
51Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCycle 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
52Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCycle 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
53Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCycle 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
54Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCycle 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
55Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCycle 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
56Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
57Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
58Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication entre vues (en direct …)
� Exemple : communication entre deux instances ViewPartpackage 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
59Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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, S WT.FLAT);getLinkView2DataButton.addSelectionListener(new Sel ectionAdapter() {
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).getFamilyN ame();String firstName = ((LinkView2)findView).getFirstNam e();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
60Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
61Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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, S WT.FLAT);getLinkView2DataButton.addSelectionListener(new Sel ectionAdapter() {
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).getFamilyN ame();String firstName = ((LinkView2)findView).getFirstNam e();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
62Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
63Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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 …
64Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication entre vues (Part Listeners)
� Exemple : écouter les changements d’une ViewPartpackage 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() {
@Overridepublic void partActivated(IWorkbenchPartReference partRef) {
IWorkbenchPart part = partRef.getPart(false);if (PartListenerViewPart.this == part) {
System. out.println(".partActivated()");}
}@Overridepublic void partBroughtToTop(IWorkbenchPartReference partRef) {
IWorkbenchPart part = partRef.getPart(false);if (PartListenerViewPart.this == part) {
System. out.println(".partBroughtToTop()");}
}@Overridepublic 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
65Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
66Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
67Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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)
68Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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 ViewPartcontenant le Viewer
Objet ISelectionProvider àconnecter au service de sélection
69Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
70Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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 certaindélai de manière à éviter les sélections multiples
ISelectionService selService = getSite().getWorkbench Window().getSelectionService()
71Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
72Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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
73Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
Communication entre vues (Selection Service)
� Exemple (suite) : 1 vue productrice, 1 vue consommatricepackage 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
74Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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 SelectionProviderIntermediatepermettant de déléguer un SelectionProvider d’une
ViewPart au service de sélection
www.eclipse.org/articles/Article-WorkbenchSelections/article.html
75Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
� 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 ViewPa rt {
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
76Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
� 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 implement s IPostSelectionProvider {private final ListenerList selectionListeners = new Li stenerList();private final ListenerList postSelectionListeners = ne w ListenerList();private ISelectionProvider delegate;
public void setSelectionProviderDelegate(ISelectionP rovider newDelegate) {if (delegate == newDelegate) { return; }if (delegate != null) {
delegate.removeSelectionChangedListener(selectionLi stener);if (delegate instanceof IPostSelectionProvider) {
((IPostSelectionProvider)delegate).removePostSelect ionChangedListener(postSelectionListener);}
}delegate = newDelegate;if (newDelegate != null) {
newDelegate.addSelectionChangedListener(selectionLi stener);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 SelectionProviderdélégué est écouté
77Views - M. Baron - Page
keul
keul
.blo
gspo
t.com
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 ViewPa rt {
private Label listenerLabel;
public void createPartControl(Composite parent) {... // Voir précédent transparent
viewer1.addSelectionChangedListener(new ISelectionC hangedListener() {public void selectionChanged(SelectionChangedEvent ev ent) {
selectionProvider.setSelectionProviderDelegate(viewer1);}
});
viewer2.addSelectionChangedListener(new ISelectionC hangedListener() {public void selectionChanged(SelectionChangedEvent ev ent) {
selectionProvider.setSelectionProviderDelegate(viewer2);}
});...
}...
}
Suite de MultipleProvidersViewPart.javadu projet MultipleProvidersExample
A chaque changement de sélection d’un TableViewer modification du SelectionProvider via la classe de
délégation
78Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
79Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
ServiceSé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 Propertiesne traite que les objets de type
IPropertySource
Objets consommés par
la vue Properties
80Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
81Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication entre vues (IAdaptable)
� Exemple : carnet d’adresse avec informations de création et
de mise à jour
Un composant ListVieweraffiche la liste des noms du carnet d’adresse
La vue Properties affiche des informations complémentaires
lorsque un contact est sélectionné
82Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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(contai ner, SWT. BORDER);contactsList.setLabelProvider(new ListLabelProvider ());contactsList.setContentProvider(new ContentProvider ());contactsList.setInput(Activator. getDefault().getContactManager());getViewSite().setSelectionProvider(contactsList);
}
class ContentProvider implements IStructuredContentPr ovider {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.javacommune aux trois approches
83Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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 ru e 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 de s 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
84Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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> getPropertie s() {if (this.properties == null) {
return Collections. emptyMap();}return new HashMap<String, Object>(this.properties) ;
}
public synchronized void setProperty(String key, Seri alizable value) {if (this.properties == null) {
this.properties = new HashMap<String, Object>();}this.properties.put(key, value);
}... // Le reste est spécifique à chaque approche, à v oir dans la suite
}
Classe Contact.java qui décrit l’objet envoyé lors d’une sélection
85Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
86Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication entre vues (IAdaptable)
� Approche 1 : typer l’objet du producteur du type de l’objet
manipulé par l’écouteurpackage 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
87Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
88Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
89Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
90Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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.getPro perties();for (String key : properties.keySet()) {
PropertyDescriptor descriptor = new PropertyDescripto r(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.getPro perties();return properties.get(id);
}
public boolean isPropertySet(Object id) { return fal se; }public void resetPropertyValue(Object id) {}public void setPropertyValue(Object id, Object value ) {}
}
Classe ContactPropertySourceAdapter.javadu projet IAdaptableExample2
Code spécifique àIPropertySource découplé
de l’objet Contact
91Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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 …
92Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
93Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
94Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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
95Views - M. Baron - Page
keul
keul
.blo
gspo
t.comCommunication 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 IAdapte rFactory {
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