Le site francophone consacré au projet Eclipse et à OSGi
 
 

 

 

(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'.

(L'auteur de cet article est le concepteur et l'animateur de notre formation 'Développement d'applications Eclipse RCP')

 

 

Sommaire


 

 

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

(L'auteur de cet article est le concepteur et l'animateur de notre formation 'Développement d'applications Eclipse RCP')

 

 


 

 

 

 


 

 

(c) EclipseTotale - contact(arobase)eclipsetotale.com