(publié le 15/12/2007)
Tutorial : développement d'applications Eclipse
RCP (1ère partie)
Depuis son lancement en 2004, le framework Eclipse RCP s'est imposé
comme une solution de choix pour le développement d'applications
clientes en Java. Avant de suivre ce tutorial il est conseillé
de lire notre 'Présentation
d'Eclipse RCP' qui pourrait se résumer ainsi :
Une application Eclipse RCP est un ensemble de modules (les plug-ins)
s'appuyant sur le framework Eclipse RCP. Ce framework est constitué
de deux briques principales :
- le gestionnaire de plug-ins (implémentations d'OSGi
et support de la notion de point d'extension).
- le cadre graphique avec au niveau le plus bas la librairie
graphique SWT, complétée par la librairie JFace,
et au niveau le plus haut la notion de Workbench qui reprend
le principe ergonomique de fenêtre unique proposé par
Eclipse (avec essentiellement les notions de perspectives, de vues
et d'éditeurs).
Les connaissances nécessaires pour développer une
application Eclipse RCP sont les suivantes :
- bien évidemment, la maîtrise du langage Java
: le framework Eclipse est écrit en Java, une application
Eclipse RCP est constituée de classes Java utilisant ce framework.
- le développement de plug-ins Eclipse : une application
Eclipse RCP est un ensemble de plug-ins Eclipse.
- la connaissance des librairies graphiques SWT et JFace
: la plupart des applications Eclipse RCP sont des applications
graphiques, le développeur doit donc apprendre à utiliser
les librairies graphiques proposées par le framework Eclipse
RCP.
- la maîtrise des briques de base d'une application Eclipse
RCP, notamment les classes permettant de mettre en oeuvre la
notion de workbench.
Ce tutorial se focalise sur le dernier point.
NB1 : nous avons abordé le développement de
plug-ins dans les tutoriaux suivants : 'Développement
de plug-ins (1ère partie)' et 'Développement
de plug-ins (2ème partie)'.
NB2 : concernant les librairies graphiques SWT et JFace de
nombreux exemples sont disponibles. Les sources les plus complètes
sont les exemples de code (les 'snippets') proposés
par le site eclipse.org : 'Snippets
SWT' et 'Snippets
JFace'.
|
Framework
Eclipse et notion d'applications
La création d'une application Eclipse RCP minimale
se fait en utilisant un assistant proposé par le PDE. Avant de
découvrir cet assistant, voyons la notion de base qui permet de
transformer un plug-in en application : le point d'extension org.eclipse.core.runtime.applications.
Ce point d'extension permet à un plug-in d'indiquer la classe qui
sera exécutée juste après l'initialisation du framework
Eclipse.
Créer
un plug-in 'com.eclipsetotale.rcp.application'. Dans l'assistant
laisser les valeurs par défaut et ne pas sélectionner
'Yes' pour le choix 'Would you like to create a rich client application'
Utiliser
l'onglet 'Extensions' de l'éditeur de fichiers manifestes
pour définir une extension sur le point d'extension org.eclipse.core.runtime.applications
:
Ajouter
l'élément 'run' en utilisant le menu contextuel et
faire générer la classe associée (en cliquant sur
le lien hypertexte 'class'). Cette classe doit implémenter
l'interface IApplication qui définit les méthodes start
et stop. Modifier le code de la méthode start :
package
com.eclipsetotale.rcp.application;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
public class
Application implements IApplication
{
public
Object start(IApplicationContext context) throws
Exception {
System.out.println("Application
de base");
return
null;
}
public
void stop() {
//
TODO Auto-generated method stub
}
}
|
Tester
: sélectionner le projet et utiliser le menu contextuel 'Run
as -> Eclipse Application'. La console doit afficher le résultat
de la méthode start. Le test a été lancé de
façon similaire à celui des plug-ins développés
dans nos tutoriaux précédents, à la différence
près que le plug-in n'a pas nécessité le lancement
d'un eclipse complet. L'application à éxécuter est
en fait indiquée dans la fenêtre des configurations de lancement
(Menu Run->Open Run Dialog...) :
Première
application Eclipse RCP
Création
de l'application
Pour créer une application Eclipse RCP, le PDE
propose une application minimale dont le code est composé de plusieurs
classes générées. La création de cette application
minimale se fait en utilisant l'assistant de création de plug-in.
Dans la deuxième page de l'assistant sélectionner 'Yes'
pour le choix 'Would you like to create a rich client application'
:
Dans la page suivante sélectionner, le template 'Hello RCP'
:
Les valeurs de la quatrième page sont utilisées dans le
code généré. Ne pas cocher 'Add branding',
nous étudierons cette notion plus loin dans ce tutorial.
L'application générée peut être
testée de la même façon que précédemment
(menu contextuel sur le projet puis 'Run as -> Eclipse Application'),
elle est constituée d'une simple fenêtre :
Cette application minimale est le point de départ
pour toutes les applications Eclipse RCP, elle va ensuite être enrichie
:
- en modifiant les classes générées
qui permettent de jouer sur certains aspects de la fenêtre (le workbench).
- en utilisant les principaux points d'extension pour
enrichir le workbench (ajout de vues, de perspectives, de menus, de pages
de préférences...).
- en codant le contenu des sous-fenêtres (les vues).
Ce code s'appuie sur les librairies graphiques SWT et JFace qui font parties
du framework Eclipse RCP.
Rôles
des classes générées et exemples de modifications
L'assistant a généré une application
Eclipse RCP minimale composée de plusieurs classes. Ces classes
sont appelées successivement lors de l'initialisation de l'application.
La modification du code de ces classes permet essentiellement de jouer
sur l'aspect graphique de l'application.
- Activator : comme pour tous les plug-ins (applications RCP ou
non), cette classe permet d'une part de réagir au cycle de vie
du plug-in et d'autre part d'accéder à diverses méthodes
utilitaires par héritage.
- Application : l'assistant agénérée une application
Eclipse comme indiquée dans la première partie de cet article
: une extension sur le point d'extension 'org.eclipse.core.runtime.applications'
a été ajoutée au fichier plugin.xml. Cette classe
est celle indiquée par le point d'extension, elle est donc la première
appelée juste après l'initialisation du framework Eclipse
RCP. Son code peut éventuellement être modifié, par
exemple pour ajouter l'ouverture d'une boîte de login. Son fonctionnement
par défaut est d'appeler l'API 'PlatformUI.createAndRunWorkbench'
pour demander la création d'un Workbench en passant en paramètre
une instance d'une autre classe générée : ApplicationWorkbenchAdvisor.
- ApplicationWorkbenchAdvisor : première classe appelée
pendant l'initialisation du Workbench. Elle permet la redéfinition
d'un certain nombre de méthodes liées au cycle de vie du
Workbench. C'est notamment dans cette classe que nous pouvons indiquer
si l'état du Workbench doit être sauvegardé après
chaque fermeture de l'application, c'est aussi dans cette classe qu'est
indiquée l'ID de la perspective qui sera affichée une fois
l'application lancée.
package com.eclipsetotale.tutorial.rcp;
import org.eclipse.ui.application.IWorkbenchConfigurer;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchAdvisor;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;
public class ApplicationWorkbenchAdvisor
extends WorkbenchAdvisor {
// Perspective à
afficher par défaut
private static final
String PERSPECTIVE_ID = "com.eclipsetotale.tutorial.rcp.perspective";
public WorkbenchWindowAdvisor
createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer)
{
return
new ApplicationWorkbenchWindowAdvisor(configurer);
}
 public String getInitialWindowPerspectiveId()
{
return
PERSPECTIVE_ID;
}
public void initialize(IWorkbenchConfigurer
configurer) {
// Utiliser
la valeur 'true' pour que l'état du workbench soit sauvegardé.
configurer.setSaveAndRestore(false);
// Attention,
si sauvegarde de l'état, la méthode createInitialLayout
de la
// perspective sera appelée
uniquement au premier lancement de l'application.
// Il est alors préférable
de prévoir une entrée dans un menu permettant
// à l'utilisateur de
réinitialiser la vue avec le code suivant :
// PlatformUI.getWorkbench().getActiveWorkbenchWindow().
// getActivePage().resetPerspective();
}
}
|
- ApplicationWorkbenchWindowAdvisor : deuxième
classe appelée pendant l'initialisation du workbench. Elle permet
d'intervenir à plusieurs étapes du cycle d'ouverture de
la fenêtre du workbench. La méthode 'preWindowOpen'
est la plus couramment modifiée, elle permet de 'jouer' sur l'aspect
de la fenêtre avant son ouverture :
package
com.eclipsetotale.tutorial.rcp;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;
public class ApplicationWorkbenchWindowAdvisor
extends WorkbenchWindowAdvisor {
public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer
configurer) {
super(configurer);
}
public ActionBarAdvisor
createActionBarAdvisor(IActionBarConfigurer configurer) {
return
new ApplicationActionBarAdvisor(configurer);
}
public void preWindowOpen()
{
IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
// Taille
initiale
configurer.setInitialSize(new
Point(600, 500));
// Non
affichage de la barre de boutons
configurer.setShowCoolBar(false);
// Zone
de status
configurer.setShowStatusLine(true);
// Titre
de la fenêtre
configurer.setTitle("Tutorial
Eclipse RCP");
}
// Après l'ouverture
de la fenêtre, d'autres actions sont possibles
public void postWindowCreate()
{
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell().setMaximized(true);
}
}
|
- ApplicationActionBarAdvisor : cette classe permet la construction
par programmation du menu principal et de la barre de boutons. Elle est
généralement utilisée pour définir la structure
de base du menu en y faisant apparaître des entrées prédéfinies
par le framework Eclipse ('Exit', 'About', 'Preferences', ...). Les actions
spécifiques à l'application peuvent aussi être ajoutées
par programmation mais il est généralement plus souple de
les ajouter en utilisant le points d'extension 'org.eclipse.ui.actionSets',
ce que nous étudierons plus bas.
package
com.eclipsetotale.tutorial.rcp;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
public class ApplicationActionBarAdvisor
extends ActionBarAdvisor {
private IWorkbenchAction
exitAction;
private IWorkbenchAction
resetAction;
private IWorkbenchAction
aboutAction;
public ApplicationActionBarAdvisor(IActionBarConfigurer
configurer) {
super(configurer);
}
// Instanciation des actions
à ajouter aux menus et à la barre de boutons.
// Utilisation de ActionFactory pour récupérer
les actions prédéfinies.
protected void makeActions(IWorkbenchWindow
window) {
exitAction
= ActionFactory.QUIT.create(window);
exitAction.setText("Quitter");
register(exitAction);
resetAction
= ActionFactory.RESET_PERSPECTIVE.create(window);
resetAction.setText("Réinitialiser");
register(resetAction);
aboutAction
= ActionFactory.ABOUT.create(window);
aboutAction.setText("A
propos... ");
register(aboutAction);
}
// Construction du menu
principal
protected void fillMenuBar(IMenuManager
menuBar) {
MenuManager fileMenu = new
MenuManager("Fichier", "file");
fileMenu.add(resetAction);
fileMenu.add(new
Separator());
fileMenu.add(exitAction);
MenuManager helpMenu = new MenuManager("Aide",
"help");
helpMenu.add(aboutAction);
menuBar.add(fileMenu);
menuBar.add(new GroupMarker("additions"));
menuBar.add(helpMenu);
// Le
groupMarker avec l'id 'additions' permet d'indiquer
// l'endroit ou devront apparaître
les menus définis
// via le point d'extension
'org.eclipse.ui.actionSets',
// dans notre cas entre les
menus 'Fichier' et 'Aide'
}
}
|
- Perspective : la dernière classe générée
est la classe nommée par défaut 'Perspective'. Elle correspond
à la notion de perspective définies par le Workbench Eclipse.
Dans le cas d'une application Eclipse il faut au moins une perspective
qui sera utilisée pour définir le contenu initial de la
fenêtre du workbench. La perspective générée
par défaut n'affiche rien. En plus de la classe générée,
une extension de type 'org.eclipse.ui.perspectives' a été
ajoutée par l'assistant dans le fichier plugin.xml. C'est cette
extension qui fait le lien entre l'id indiqué par la méthode
getInitialWindowPerspectiveId de la
classe ApplicationWorkbenchAdvisor et la classe 'Perspective'.
Ajout
d'une vue et d'un menu
L'étape incontournable de la création d'une
application Eclipse RCP est la définition d'au moins une vue. Nous
avons déjà mis en pratique le point d'extension 'org.eclipse.ui.views'
dans un tutorial précédent : 'Développement
de plug-ins (2ème partie)'. Procédons de la même
façon pour définir une nouvelle vue avec les propriétés
suivantes :
(NB: dans ce cas particulier nous exploitons la possibilité
d'affichage de plusieurs instances de la vue en modifiant la propriété
'allowMultiple')
Le but de ce tutorial n'étant pas d'étudier
les librairies SWT et JFace, nous utiliserons le code suivant (il affiche
une page web à l'intérieur de la vue) :
package
com.eclipsetotale.tutorial.rcp;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
/**
* Cette vue affiche une page du site EclipseTotale dans un
* composant navigateur.
*/
public class ETView extends ViewPart
{
public void createPartControl(Composite
parent) {
parent.setLayout(new
FillLayout());
Browser browser = new
Browser(parent, SWT.NONE);
// Construction
de l'URL
String id = this.getViewSite().getSecondaryId();
String url = "http://www.eclipsetotale.com";
if(id
!= null) {
this.setPartName("ET
- " + id);
url += "/index.html?keywords="
+ id;
}
// Affichage
de la page
browser.setUrl(url);
// Affichage
de l'URL dans la barre de status
getViewSite().getActionBars().getStatusLineManager().setMessage(url);
}
public void setFocus()
{
}
}
|
Dans une application Eclipse RCP, il existe deux façons
principales de faire afficher une vue :
- modifier le code de la perspective pour que la vue y apparaisse à
l'initialisation de la perspective.
- utiliser une API pour forcer l'affichage d'une vue (IWorkbenchPage.showView).
Pour mettre en oeuvre la première technique modifions
le code de la classe Perspective :
package
com.eclipsetotale.tutorial.rcp;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPerspectiveFactory;
public class Perspective implements
IPerspectiveFactory {
public void createInitialLayout(IPageLayout
layout) {
// On
masque la zone d'édition
layout.setEditorAreaVisible(false);
// Affichage
de la vue en lui donnant toute la place disponible
layout.addView("com.eclipsetotale.tutorial.rcp.etview",
layout.TOP,
layout.RATIO_MAX, layout.getEditorArea());
// Affichage
du menu qui sera créé plus en avant dans ce tutorial
layout.addActionSet("com.eclipsetotale.tutorial.rcp.etactionset");
}
}
|
Pour utiliser la deuxième technique, ajoutons
un menu dont les entrées déclenchent l'affichage de la vue.
Pour ce faire il faut étendre le point d'extension 'org.eclipse.ui.actionSets'.
Pour simplifier ce tutorial voici le code à ajouter dans le fichier
plugin.xml :
<extension
point="org.eclipse.ui.actionSets">
<actionSet
id="com.eclipsetotale.tutorial.rcp.etactionset"
label="EclipseTotale
actionSet"
visible="false">
<menu
id="etmenu"
label="EclipseTotale">
<groupMarker
name="etgroup">
</groupMarker>
</menu>
<action
class="com.eclipsetotale.tutorial.rcp.ShowSWTNewsAction"
id="com.et.tutorial.rcp.actionSWT"
label="SWT"
menubarPath="etmenu/etgroup">
</action>
<action
class="com.eclipsetotale.tutorial.rcp.ShowSWTNewsAction"
id="com.et.tutorial.rcp.actionRCP"
label="RCP"
menubarPath="etmenu/etgroup">
</action>
<action
class="com.eclipsetotale.tutorial.rcp.ShowSWTNewsAction"
id="com.et.tutorial.rcp.actionEquinox"
label="Equinox"
menubarPath="etmenu/etgroup">
</action>
<action
class="com.eclipsetotale.tutorial.rcp.ShowSWTNewsAction"
id="com.et.tutorial.rcp.actionJFace"
label="JFace"
menubarPath="etmenu/etgroup">
</action>
</actionSet>
</extension>
|
Dans le cas particulier de ce tutorial toutes les actions déclenchent
l'exécution de la même classe 'com.eclipsetotale.tutorial.rcp.ShowSWTNewsAction'
(le code utilise le libellé de l'action comme paramètre).
Créer cette classe en utilisant le code suivant :
package
com.eclipsetotale.tutorial.rcp;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
public class ShowSWTNewsAction implements
IWorkbenchWindowActionDelegate {
public void run(IAction
action) {
try
{
IWorkbenchPage
page =
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
//
Ouverture de la vue, la version de showView utilisée est
celle
//
permettant d'ouvrir plusieurs instances de la même vue.
//
Dans notre cas le 2ème paramètre est le libellé
de l'action dans le menu
//
Cette valeur sera utilisée pour construire l'URL affichée
par la vue
page.showView(
"com.eclipsetotale.tutorial.rcp.etview",
action.getText(),
IWorkbenchPage.VIEW_ACTIVATE);
}
catch (PartInitException e) {
e.printStackTrace();
}
}
public void selectionChanged(IAction
action, ISelection selection) {
}
public void dispose()
{
}
public void init(IWorkbenchWindow
window) {
}
}
|
Tester l'application, le résultat doit être
le suivant :
Conclusion
Dans cette première partie, nous avons étudié
les principes de base de la création d'une application Eclipse
RCP. La seconde partie nous permettra de découvrir comment produire
un livrable et comment configurer plus finement l'interface graphique
de l'application (icône de la fenêtre, image d'attente, contenu
de la boîte 'about', ...).
|