View
5.247
Download
1
Category
Preview:
DESCRIPTION
Ce support de cours s'intéresse à détailler la construction d'éditeurs 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, registre des éditeurs, cycle de vie, MultiPageEditorPart, écouteurs, éditeur et les commandes, Workspace et les ressources, éditeur et le texte via TextEditor (coloration syntaxique, assistant de contenu, template, outline, spelling checking, ...).
Citation preview
Développement de clients riches : Plateforme Eclipse
Mickaël BARON - 2010 mailto:baron.mickael@gmail.com ou mailto:baron@ensma.fr
Chapitre 3 : Conception de plugChapitre 3 : Conception de plug--insins
Workbench : Editors
2Editors - 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
3Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
� Construction déclarative
� IEditorPart, IEditorSite, IEditorInput
� Registre des éditeurs
� Cycle de vie
� MultiPageEditorPart
� Ecouteurs
� Editeur et les commandes
� Workspace et les ressources
� Editeur et le texte via TextEditor
Organisation du cours sur le Workbench : Editors
4Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkbench Editors : déroulement du cours
Ceci est une alerte
Ceci est une astuce
� Pédagogie du cours
� Illustration avec de nombreux exemples qui sont disponibles à
l’adresse mbaron.developpez.com/eclipse/editors
� Des bulles d’aide tout au long du cours
� Logiciels utilisés
� Eclipse 3.5.2 Galileo
� Pré-requis
� Connaître la structure d’un plug-ins et savoir créer une extension
� Structure du Workbench
5Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workbench Editors : ressources …
� Des liens sur les éditeurs de manière générale� www.vogella.de/articles/RichClientPlatform/article.html#editor
� wiki.eclipse.org/FAQ_What_is_the_difference_between_a_view_and_an_editor%3F
� wiki.eclipse.org/FAQ_How_do_I_open_an_editor_on_something_that_is_not_a_file%3F
� eclipse.dzone.com/tips/programmatically-split-editor-
� www.pajbam.com/wp-content/uploads/2008/04/cours_plugin_eclipse.pdf
� Des liens sur le Workspace (gestion de fichiers)� wiki.eclipse.org/FAQ_How_do_I_open_an_editor_on_a_file_outside_the_workspace%3F
� www.eclipsezone.com/eclipse/forums/t83786.html
� wiki.eclipse.org/index.php/EFS
� www.eclipse.org/eclipse/platform-team/docs/ABC%20of%20Platform%20Workspace.ppt
� www.eclipse.org/articles/Article-Resource-deltas/resource-deltas.html
� hexapixel.com/2009/01/12/rcp-workspaces
� www.eclipse.org/articles/Article-Mark My Words/mark-my-words.html
� www.eclipse.org/articles/Article-Builders/builders.html
� wiki.eclipse.org/FAQ_How_do_I_make_my_compiler_incremental%3F
� wiki.eclipse.org/FAQ_How_do_I_implement_an_Eclipse_builder%3F
� www.eclipsepluginsite.com/builders-natures-markers.html
6Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workbench Editors : ressources …
� Des liens sur l’amélioration d’un TextEditor� beuss.developpez.com/tutoriels/eclipse/plug-in/editor/colors
� www.eclipse.org/eclipse/platform-text/development/dev.html
� wiki.eclipse.org/FAQ_How_do_I_provide_syntax_coloring_in_an_editor%3F
� wiki.eclipse.org/FAQ_What_is_a_document_partition%3F
� wiki.eclipse.org/FAQ_How_do_I_add_Content_Assist_to_my_editor%3F
� www.eclipse.org/articles/Article-Folding-in-Eclipse-Text-Editors/folding.html
� www.ibm.com/developerworks/opensource/library/os-ecca
� www.java2s.com/Code/Java/SWT-JFace-Eclipse/SWTCompletionEditor.htm
� Des livres
� Eclipse – Building Commercial-Quality Plug-ins, 2004 - ISBN : 0-321-22847-2
� Eclipse – Rich Client Platform, 2005 – ISBN : 0-321-33461-2
7Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Généralités : Différences entre Vue et Editeur
� Un éditeur est commun à toutes les perspectives d’une
fenêtre
� Si l’éditeur est fermé à partir d’une perspective il est fermé pour
toutes les perspectives
� Il n’est pas possible d’empiler une vue avec un éditeur
� Un éditeur n’est pas détachable
� Un éditeur a obligatoirement une barre de titre
� Un éditeur n’a pas de barre de menus et de barre d’outils
localisées, il partage avec les barres de la fenêtre
8Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Généralités : Différences entre Vue et Editeur
� Un éditeur peut être instancié plusieurs fois pour un type
d’éditeur donné
� Une vue ne possède qu’une seule instance (cas particulier avec
l’identifiant secondaire)
� Un éditeur apparaît à un seul endroit de la page alors qu’une
vue peut être déplacée
� Un éditeur peut être dans un état « modifié », son contenu
peut ainsi être sauvegardé
� Un éditeur peut être associé à un nom de fichier ou à une
extension et cette association peut être modifiée par
l’utilisateur
9Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Généralités : Usage de l’éditeur
� Les fausses idées concernant un éditeur …
� Editeur est dédié uniquement à l’affichage et à la manipulation du
contenu d’un fichier
� Une vue peut réaliser la même chose
� Editeur est dédié à l’affichage du texte
� Un éditeur peut aussi afficher des IHMs types formulaires (PDE)
� La vue console affiche uniquement du texte
� Quand utiliser un éditeur ?
� Quand le contenu est considéré comme l’élément central de la fenêtre.
Toutes les vues sont utilisées comme support (outline, explorer, …)
� Quand il est nécessaire de fournir des actions spécifiques pour l’édition
(sauvegarde, menu contextuel, …)
10Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comGénéralités : Editeur interne et externe
� Editeur interne
� Intégré dans une page d’une fenêtre du Workbench
� Le menu et la barre d’outils sont issus de la fenêtre du Workbench
� Editeur externe (System Editor)
� Démarré dans une fenêtre séparée au Workbench
� Après le démarrage d’un éditeur externe, le Workbench n’a plus la
main sur l’état de l’éditeur (pas de possibilité d’arrêt)
� La collaboration ne peut s’effectuer que par le système de fichier
� Editeur mixte (In-Place Editor)
� Intégré dans une page d’une fenêtre du Workbench, un éditeur
externe (intégration OLE)
� Le menu de l’éditeur externe intégré utilise le menu de la fenêtre du
Workbench
11Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comGénéralités : Editeur interne et externe
� Exemple : Utilisation d’un éditeur Word en mode « In-Place »
L’éditeur externe Word est intégré dans une page d’une WorkbenchWindow
Le menu de l’application Eclipse est complété par les éléments
du menu de Word
12Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Généralités : Editeur par défaut
� Un éditeur par défaut est celui à utiliser en priorité si
d’autres éditeurs traitent le même type d’entrées
� Exemple : fichier xml
� Plusieurs éditeurs disponibles (texte, xml, m2eclipse, …)
� Si l’éditeur xml est utilisé comme défaut, il sera ouvert en priorité
� Lors de la définition d’un éditeur (voir extension editors), il
est possible de spécifier qu’un éditeur est par défaut
� Un éditeur est définit implicitement par défaut, si aucun
autre éditeur ne peut traiter son type d’entrée
� Si un fichier est ouvert avec un éditeur, cet éditeur ne
devient pas par défaut mais sera utilisé pour ré-ouvrir de
nouveau ce fichier
13Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comGénéralités : Carte des classes de l’éditeur
� Principales interfaces et classes pour la gestion des éditeursIWorkbenchPage
activate(IWorkbenchPart)
bringToTop(IWorkbenchPart)
findEditor(String)
getEditorReferences()
hideEditor(IEditorReference)
showEditor(IEditorReference)
IWorkbenchPartReference
getId()
getPage()
getPart(boolean)IWorkbenchSite
getPage()
getSelectionProvider()
getShell()
getWorkbenchWindow()
setSelectionProvider(ISelectionProvider)
IWorkbenchPart
createPartControl(Composite)
dispose()
getSite()
IEditorPart
getEditorSite()
getEditorInput()
init(IEditorSite, IEditorInput)
IWorkbenchPartSite
getKeyBindingService()
registerContextMenu(MenuManager, ISelectionProvider)
registerContextMenu(String, MenuManager, ISelectionProvider)
IEditorReference
getEditor(boolean)
getEditorInput()
getFactoryId()
getName()
isPinned()
WorkbenchPart
dispose()
getConfigurationElement()
getSite()
setPartName(String)
EditorPart
getEditorSite()
getEditorInput()
init(IEditorSite, IEditorInput)
IEditorSite
getActionBars()
getActionBarContributor()
EditorInput
getEditorSite()
getEditorInput()
init(IEditorSite, IEditorInput)
Dépendance
Héritage Généraliste
Spécifique à un éditeur
14Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Généralités : Principales classes de l’éditeur
� IEditorPart : Contient le code de l’IHM de l’éditeur
� IEditorSite : Pont entre l’éditeur et le Workbench
� IEditorInput : Descripteur du contenu d’un éditeur
� IEditorDescriptor : Descripteur utilisé dans le registre des
éditeurs
� IEditorReference : Représenter une instance d’un éditeur
dans la page active
� IEditorActionBarContributor : Utilisé pour contribuer à
l’ajout d’actions dans la barre de menus et d’outils
15Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Construction d’un éditeur interne par extension
� Sélectionner le point d’extension org.eclipse.ui.editors
Création d’une extension àpartir du point d’extension
org.eclipse.ui.editors
Création d’un éditeur à partir des templates Editor et
Multi-page Editor
16Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Construction d’un éditeur interne par extension
� Définir les attributs de l’extension
Identifiant de l’éditeur
Nom de l’éditeur
Extensions des fichiers (ex : html) gérées par l’éditeur
Objet de type EditorPart implémentant le contenu d’un éditeur interne
Utiliser pour démarrer un éditeur externe (mutuellement
exclusif avec class)
Objet de type IEditorActionBarContributor utilisé pour ajouter des actions à la barre de menu
et à la barre d’outils
Les noms des fichiers gérés par l’éditeur
L’attribut default permet d’indiquer que cet éditeur est à
utiliser en priorité pour les fichiers dont l’extension est html ou txtUtilisation d’une police
par défaut
17Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Construction d’un éditeur interne par extension
� Etendre un éditeur de type EditorPart
package eclipse.workbench.viewexample.views
public class SimpleEditor extends EditorPart {
public SimpleEditor() { }public void doSaveAs() { }
public void init(IEditorSite site, IEditorInput input) throws PartInitException {setSite(site);setInput(input);
}
public boolean isDirty() {return false;
}
public boolean isSaveAsAllowed() {return false;
}
public void createPartControl(Composite parent) {Label myLabel = new Label(parent, SWT.NONE);myLabel.setText("Simple View");
}
public void setFocus() { }public void doSave(IProgressMonitor monitor) { }
}
SimpleEditor.java du Projet EditorExample
18Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Construction d’un éditeur interne par extension
� Pour utiliser cet éditeur plusieurs solutions sont à envisager
� Ouvrir un fichier au format html ou txt (File -> Open File …)
� Faire appel explicitement à la méthode openEditor à partir d’un
WorkbenchPage (voir plus tard)
� A noter que si aucun éditeur n’est défini pour une extension
donnée d’un fichier
� Ce fichier n’est pas ouvert par un éditeur Eclipse
� Un éditeur externe (System Editor) est utilisé si l’extension a été
associée à un éditeur
� Si l’éditeur d’Eclipse est défini comme éditeur par défaut, le
fichier est automatiquement ouvert dans cet éditeur
� Il est possible d’utiliser d’autres éditeurs en utilisant le
menu Open With
19Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Construction d’un éditeur interne par extension
� Exemple : Ouverture du fichier pom.xml par trois éditeurs
Plusieurs éditeurs peuvent éditer ce fichier
Via l’éditeur de M2 Eclipse Via l’éditeur XML
Des éditeurs fournis par Eclipse
L’éditeur système
Via l’éditeur sytème« Firefox »
20Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Construction d’un éditeur externe par extension
� Précédemment l’attribut class a permis de développer un
éditeur interne
� Pour développer des éditeurs externes il faut utiliser les
attributs launcher ou command
� A noter que class, launcher et command sont mutuellement
exclusif
� Utilisation de l’attribut launcher
� Nécessite la création d’une classe implémentant IEditorLauncher
� void open(IPath file) : appelée pour ouvrir le fichier dont le chemin
est passé en paramètre
� Utilisation de l’attribut command
� Commande du système (par exemple : notepad.exe)
� Ne pas confondre avec les commandes Eclipse !!!!
21Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Construction d’un éditeur externe par extension
� Exemple : Création d’un éditeur externe via launcher
L’attribut launcher est renseigné
Si l’attribut launcher doit être renseigné, ne pas modifier les attributs class et command
Cet éditeur est associé aux fichiers dont l’extension est
extlaunch
22Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Construction d’un éditeur externe par extension
� Exemple (suite) : Création d’un éditeur externe via launcher
public class SimpleEditorEditorLauncher implements IE ditorLauncher {
public void open(IPath file) {final Program findProgram = Program.findProgram("txt");boolean result = findProgram.execute(file.toFile().ge tAbsolutePath());
System.out.println("External Editor has been launche d ? : " + result);}
}
SimpleEditor.java du Projet EditorExample
Utilisation de l’API Program pour démarrer un éditeur externe
Recherche au niveau du système d’exploitation le programme associé
à l’extension txt(pour être sur d’obtenir un résultat)
Exécution du programme (notepad.exe) en donnant en paramètre le chemin du fichier
23Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Construction d’un éditeur externe par extension
� Exemple (suite) : Création d’un éditeur externe via launcher
Utilisation de l’éditeur interne texte (via Open With)
Utilisation de l’éditeur externe (notepad.exe)
(également via Open With)
24Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Construction d’un éditeur externe par extension
� Exemple : Création d’un éditeur externe via command
L’attribut command est renseigné
Cet éditeur est associé aux fichiers dont l’extension est
extCommand
Si l’attribut command doit être renseigné, ne pas modifier les
attributs class et launcher
Très simple d’utilisation mais ne permet pas de définir des
paramètres dérivés
25Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
EditorPart
� La définition d’un nouvel éditeur est obtenue en héritant de la classe EditorPart
� Des méthodes abstraites doivent être implémentées
� void init(IEditorSite site, IEditorInput input) : initialise l’éditeur
� void createPartControl(Composite parent) : création de l’IHM par des composants SWT où parent est le conteneur de la vue
� void setFocus() : composant qui aura le focus lors de l’activation
� void doSave(IProgressMonitor monitor) : sauvegarde le contenu de l’éditeur
� void doSaveAs() : sauvegarde le contenu de l’éditeur dans un autre emplacement
� boolean isDirty() : indique si le contenu a changé
� boolean isSaveAsAllowed() : « Save As » est-il supporté ?
� boolean isSaveOnCloseNeeded() : La sauvegarde est-elle nécessaire avant la fermeture de l’éditeur ?
26Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
EditorPart
� Des méthodes qui peuvent être redéfinies …
� void setInitializationData(…) : appelée lors de la création de
l’extension
� String getTitleToolTip() : message pour la bulle d’aide de l’éditeur
� Des méthodes à exploiter …
� IEditorSite getEditorSite() : retourne le site de l’éditeur (étudier par la
suite)
� IEditorInput getEditorInput() : retourne l’EditorInput de l’éditeur
(étudier par la suite)
� void setPartName(String ti) : modifie directement le titre de l’éditeur
en place d’utiliser les données de l’extension
27Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
EditorPart et IEditorSite
� Le site d’un éditeur est une sorte de pont entre l’éditeur
(définit par EditorPart) et le Workbench
� Il faut voir le site comme un objet qui permet de lier l’éditeur
au contexte de l’application
� L’interface IWorkbenchSite est une abstraction d’un site
� IWorkbenchPage getPage() : la page dans laquelle l’éditeur est stockée
� Shell getShell() : la fenêtre physique d’où est contenue l’éditeur
� IWorkbenchWindow getWorkbenchWindow() : la fenêtre déclarative contenant l’éditeur
� 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
28Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
EditorPart et IEditorSite
� L’interface IEditorSite (sous type de IWorkbenchSite) fournit
des méthodes spécifiques
� IActionBars getActionBars() : la barre d’action de l’éditeur
� IEditorActionBarContributor getActionBarContributor() : retourne un
objet IEditorActionBarContributor utilisé pour la création des actions
A l’ouverture de l’éditeur des commandes (ou actions) sont
ajoutées à la barre d’action et menu
L’ajout d’éléments dans la barre de menu
et la barre d’outils sera étudié dans la
suite
29Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
IEditorInput
� Un objet IEditorInput est un descripteur léger sur le contenu
d’un éditeur
� Il ne s’agit pas du modèle de l’éditeur mais d’une description
sur la source de l’éditeur utilisé par l’EditorPart
� A chaque création d’une nouvelle instance d’EditorPart, un
objet de type IEditorInput doit être passé en paramètre
� L’éditeur à ouvrir doit supporter l’objet IEditorInput passé en
paramètre
� Possibilité d’adapter un objet IEditorInput en autre objet
puisque l’objet est de type IAdaptable
� Exemple : adapter un CustomEditorInput en FileEditorInput de telle
sorte que CustomEditorInput soit utilisable par des éditeurs
manipulant des fichiers
30Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
IEditorInput
� Principales méthodes de IEditorInput
� boolean exists() : vérifie si l’éditeur existe
� ImageDescriptor getImageDescriptor() : retourne une image
� String getToolTipText() : retourne le texte de la bulle d’aide
� String getName() : retourne un nom
� En pratique un éditeur qui édite le contenu
d’un fichier utilise en FileEditorInput
� Contient un attribut de type File permettant d’accéder au contenu du
fichier
� Principales méthodes de FileEditorInput
� IFile getFile() : retourne le fichier contenant la source
Lors de la définition de votre propre IEditorInput redéfinissez obligatoirement
la méthode equals
31Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Registre des éditeurs
� Le registre des éditeurs est utilisé par le conteneur Eclipse
pour stocker l’intégralité des éditeurs créés
� Il n’existe qu’un seul registre d’éditeur géré par le Workbench
� A partir de ce registre il est possible de
� Chercher un éditeur par son identifiant
� Chercher tous les éditeurs associés à un nom de fichier
� Chercher l’éditeur par défaut par son nom
IEditorRegistry editorRegistry = PlatformUI.getWorkbe nch().getEditorRegistry();
L’interface IEditorRegistry est détaillée dans la suite
32Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Registre des éditeurs
� L’interface IEditorRegistry dispose des méthodes suivantes
� IEditorDescriptor findEditor(String id) : recherche un éditeur par son id
� IEditorDescriptor[] getEditors(String fileName) : retourne les éditeurs
disponibles pour un fichier donné
� IEditorDescriptor getDefaultEditor(String fileName) : retourne l’éditeur
par défaut pour un fichier donné
� boolean isSystemExternalEditorAvailable(String fileName) : vérifie s’il
existe un éditeur externe disponible pour un fichier donné
� void setDefaultEditor(String fileNameOrExt, String id) : modifie
l’éditeur par défaut suivant le nom de fichier ou l’extension
� Un objet IEditorDescriptor décrit un éditeur du point de vue
de sa déclaration (informations de l’extension)
33Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Registre des éditeurs
� Exemple : Modifier et accéder à l’éditeur par défaut
Deux commandes permettent de modifier l’éditeur par défaut des
fichiers de type html
La commande Launcher Editor Default associe l’éditeur SimpleExternalEditorWithLauncherId au
fichier html
Le traitement de cette commande • affiche l’ancien éditeur par défaut• affecte le nouveau éditeur par défaut• affiche enfin le nouveau éditeur par défaut
1
2
3
34Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Registre des éditeurs
� Exemple (suite) : Modifier et accéder à l’éditeur par défaut
public class LauncherEditorCommandHandler extends Abs tractHandler {
public Object execute(ExecutionEvent event) throws Ex ecutionException {final IEditorRegistry editorRegistry = PlatformUI.get Workbench().getEditorRegistry();
IEditorDescriptor defaultEditor = editorRegistry.getD efaultEditor("*.html");if (defaultEditor != null) {
System.out.println(defaultEditor.getLabel());}
editorRegistry.setDefaultEditor("*.html","eclipse.w orkbench.EditorExample.SimpleExternalEditorWithLaun cherId");
defaultEditor = editorRegistry.getDefaultEditor("*.h tml");if (defaultEditor != null) {
System.out.println(defaultEditor.getLabel());}
return null;}
}
LauncherEditorCommandHandler.javadu Projet EditorExample
Récupération de l’éditeur par défaut des fichiers dont l’extension est html
Modification de l’éditeur par défaut des fichiers de type html
35Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Registre des éditeurs
� L’interface IEditorDescriptor décrit l’éditeur dans le registre
des éditeurs (relation avec les extensions)
� String getId() : identifiant de l’éditeur
� String getLabel() : le nom de l’éditeur
� ImageDescriptor getImageDescriptor() : image de l’éditeur
� boolean isInternal() : utilise un éditeur interne pour l’ouverture ?
� boolean isOpenExternal() : utilise un éditeur externe pour l’ouverture ?
� boolean isOpenInPlace() : utilise un éditeur externe intégré à Eclipse ?
� …
� Le registre ne donne pas accès aux instances des objets
IEditorPart (voir cycle de vie)
36Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Registre des éditeurs
� Exemple : Interroger le registre des éditeurs
public class EditorRegistryCommandHandler extends Abs tractHandler {
@Overridepublic Object execute(ExecutionEvent event) throws Ex ecutionException {
final IEditorRegistry editorRegistry = PlatformUI.get Workbench().getEditorRegistry();
final IEditorDescriptor[] editors = editorRegistry. getEditors("*.txt");
for (IEditorDescriptor iEditorDescriptor : editors) {System.out.println(iEditorDescriptor.getLabel());
}
return null;}
}
EditorRegistryCommandHandler.javadu Projet EditorExample
Récupère les éditeurs associés àce type d’extension
Deux éditeurs sont disponibles
37Editors - 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 IEditorPart (celle utilisée pour
programmer l’interface d’un éditeur)
� Chaque instance de type IEditorPart est associée un objet
de type IEditorReference
� Une instance IEditorReference est associée une instance IEditorPart
� Il peut exister dans une même page plusieurs instances du
même éditeur (pas d’identifiant secondaire)
� Les méthodes fournies par la page permettent généralement
d’afficher ou de cacher des éditeurs
38Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie
� Principales méthodes de IWorkbenchPage en relation avec la notion d’éditeur
� IEditorPart getActiveEditor() : l’éditeur actuellement actif
� boolean closeAllEditors(boolean save) : ferme tous les éditeurs sans
possibilité de sauvegarde si save vaut false
� boolean closeEditor(IEditorPart e, boolean save) : ferme un éditeur désigné par e
� IEditorPart findEditor(IEditorInput e) : cherche un éditeur via son IEditorInput
� IEditorPart[] getDirtyEditors() : retourne l’ensemble des éditeurs dont le contenu a changé (nécessite une sauvegarde)
� IEditorReferences[] getEditorReferences() : retourne l’ensemble des éditeurs
� IEditorPart openEditor(…) : ouvre un éditeur (détailler dans le prochain transparent)
39Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : openEditor …
� Le comportement de l’ouverture d’un éditeur est différent
selon la configuration utilisée pour la méthode openEditor
� Trois configurations différentes
� Ouvre un nouvel éditeur s’il n’existe pas un éditeur ayant un même
input (MATCH_INPUT)
� Ouvre un nouvel éditeur s’il n’existe pas un éditeur ayant un même
identifiant (MATCH_ID)
� Ouvre un nouvel éditeur même s’il existe un éditeur ayant un même
input ou un même identifiant (MATCH_NONE)
� Surcharge de la méthode openEditor
� IEditorPart openEditor(IEditorInput input, String editorID) : ouvre un éditeur s’il n’existe pas un éditeur ouvert ayant un même input
� IEditorPart openEditor(final IEditorInput input, final String editorID, final boolean activate, final int matchFlags) : ouvre un éditeur en spécifiant la configuration
40Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : openEditor …
� Exemple : Ouvrir un éditeur pour un fichier
présent dans le Workspace
public class OpenEditorCommandHandler extends Abstrac tHandler {
@Overridepublic Object execute(ExecutionEvent event) throws Ex ecutionException {
final IWorkbenchPage activePage = PlatformUI.getWorkb ench().getActiveWorkbenchWindow().getActivePage();
ISelectionService selService = PlatformUI.getWorkbenc h().getActiveWorkbenchWindow().getSelectionService( );final ISelection selection = selService.getSelection( );if (selection instanceof TreeSelection) {
TreeSelection currentFile = (TreeSelection)selection;final IFile firstElement = (IFile)currentFile.getFirs tElement();IEditorDescriptor desc = PlatformUI.getWorkbench().ge tEditorRegistry().getDefaultEditor(firstElement.get Name());try {
activePage.openEditor(new FileEditorInput(firstElem ent), desc.getId());} catch (PartInitException e) {
e.printStackTrace();}
}
return null;}
}
OpenEditorCommandHandler.java du Projet EditorExample
Récupération de l’éditeur associé au type du fichier sélectionné(ici le fichier sample.html)
Ouverture de l’éditeur s’il n’existe pas un éditeur déjà ouvert ayant le même input
41Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : openEditor …
� Exemple (suite) : Ouvrir un éditeur pour un fichier présent
dans le Workspace
Les fichiers doivent être présents dans le répertoire du workspace pour être ouvert
via la méthode open(…)
L’utilisation de la méthode openEditor ne s’applique que pour
les fichiers présents dans le Workspace, sauf cas …
42Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : openEditor …
� Exemple : Ouvrir un éditeur pour un fichier non présent
dans le Workspace (solution 1)public class OpenExternalEditorCommandHandler extend s AbstractHandler {
public Object execute(ExecutionEvent event) throws Ex ecutionException {try {
IWorkspace ws = ResourcesPlugin.getWorkspace();IProject project = ws.getRoot().getProject("SimpleEdi tor");
if (!project.exists())project.create(null);
if (!project.isOpen())project.open(null);
final IWorkbenchWindow activeWorkbenchWindow = Platfo rmUI.getWorkbench().getActiveWorkbenchWindow();final Shell shell = activeWorkbenchWindow.getShell() ;
String name = new FileDialog(shell, SWT.OPEN).open() ;if (name == null)
return null;
IPath location = new Path(name);IFile file = project.getFile(location.lastSegment()) ;file.createLink(location, IResource.NONE, null);IWorkbenchPage page = activeWorkbenchWindow.getActiv ePage();if (page != null)
IEditorDescriptor desc = PlatformUI.getWorkbench().ge tEditorRegistry().getDefaultEditor(file.getName());page.openEditor(new FileEditorInput(file), desc.get Id());
} catch(Exception e) {e.printStackTrace();
}return null;
}}
OpenExternalEditorCommandHandler.javadu Projet EditorExample
Une boîte de dialogue est utilisée pour choisir un
fichier sur le système hôte
Création d’un lien entre le fichier physique et le
workspace
Utilisation de l’éditeur par défaut pour l’ouverture
43Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : openEditor …
� Exemple (suite) : Ouvrir un éditeur pour un fichier non
présent dans le Workspace (solution 1)
Le fichier setup.log est localisé à l’emplacement
c:\setup.log
L’icône précise qu’il s’agit d’un lien
Pas de fichier setup.logdans le répertoire du
workspace
44Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : openEditor …
� Exemple : Ouvrir un éditeur pour un fichier non présent
dans le Workspace (solution 2)
public class OpenExternalEditorWithEFSCommandHandle r extends AbstractHandler {
public Object execute(ExecutionEvent event) throws Ex ecutionException {final IWorkbenchWindow activeWorkbenchWindow = Platfo rmUI.getWorkbench().getActiveWorkbenchWindow();final Shell shell = activeWorkbenchWindow.getShell() ;
String name= new FileDialog(shell, SWT.OPEN).open() ;if (name == null)
return null;name = name.replace('\\','/');IFileStore fileStore = EFS.getLocalFileSystem().getSt ore(URI.create(name));if (!fileStore.fetchInfo().isDirectory() && fileSto re.fetchInfo().exists()) {
IWorkbenchPage page= activeWorkbenchWindow.getActiv ePage();try {
IDE.openEditorOnFileStore(page, fileStore);} catch (PartInitException e) {
e.printStackTrace();}
}return null;
}}
OpenExternalEditorWithEFCCommandHandler.javadu Projet EditorExample
Depuis la version Eclipse 3.3, EFS (Eclipse File System) a été défini pour
simplifier la gestion des fichiers
Utilisation de la méthode openEditorOnFileStore définie
dans la classe IDE
45Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : openEditor …
� Exemple : Ouvrir un éditeur pour un contenu qui n’est pas
un fichier Affichage du contenu qui ne provient pas d’un fichier (une chaîne de texte)
Exemple issu de la FAQ Eclipse
http://wiki.eclipse.org/FAQ_How_do_I_open_an_editor_on_something_that_is_not_a_file%3F
46Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : openEditor …
� Exemple (suite) : Ouvrir un éditeur pour un contenu qui
n’est pas un fichierpublic class OpenEditorWithNoFileCommandHandler exte nds AbstractHandler {
class StringStorage implements IStorage {priva te String string;
StringStorage(String input) {this.string = input;
}
public InputStream getContents() throws CoreException {return new ByteArrayInputStream(string.getBytes());
}
public IPath getFullPath() {return null;
}
public Object getAdapter(Class adapter) {return null;
}
public String getName() {int len = Math.min(5, string.length());return string.substring(0, len).concat("...");
}
public boolean isReadOnly() {return true;
}}... // Suite dans le prochain transparent
OpenEditorWithNoFileCommandHandler.javadu projet EditorExample
47Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : openEditor …
� Exemple (suite) : Ouvrir un éditeur pour un contenu qui
n’est pas un fichierpublic class OpenEditorWithNoFileCommandHandler exte nds AbstractHandler {
class StringInput implements IStorageEditorInput {private IStorage storage;
StringInput(IStorage storage) {this.storage = storage;
}
public boolean exists() { return true; }
public ImageDescriptor getImageDescriptor() { return null; }
public String getName() {return storage.getName();
}
public IPersistableElement getPersistable() { return null; }
public IStorage getStorage() {return storage;
}
public String getToolTipText() {return "String-based file: " + storage.getName();
}
public Object getAdapter(Class adapter) { return nu ll; }}... // Suite dans le prochain transparent
OpenEditorWithNoFileCommandHandler.javadu projet EditorExample
48Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : openEditor …
� Exemple (suite) : Ouvrir un éditeur pour un contenu qui
n’est pas un fichier
public class OpenEditorWithNoFileCommandHandler exte nds AbstractHandler {
public Object execute(ExecutionEvent event) throws Ex ecutionException {IWorkbenchWindow window = PlatformUI.getWorkbench().g etActiveWorkbenchWindow();
String string = "This is the text file contents";
IStorage storage = new StringStorage(string);IStorageEditorInput input = new StringInput(storage) ;IWorkbenchPage page = window.getActivePage();
if (page != null) {try {
page.openEditor(input, "org.eclipse.ui.DefaultTextE ditor");} catch (PartInitException e) {
e.printStackTrace();}
}
return null;}
OpenEditorWithNoFileCommandHandler.javadu projet EditorExample
Contenu à afficher
Définition d’un IEditorInputdédié à la gestion d’une chaîne
de caractères
Ouverture de l’éditeur qui gère l’édition et l’affichage du texte
49Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : openEditor …
� Exemple : Ouvrir plusieurs instances d’un même éditeur
Plusieurs instances d’un même éditeur
50Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : openEditor …
� Exemple (suite) : Ouvrir plusieurs instances d’un même
éditeurpublic class OpenSeveralEditorInstances extends Abstr actHandler {
public Object execute(ExecutionEvent event) throws Ex ecutionException {final IWorkbenchPage activePage = PlatformUI.getWorkb ench().getActiveWorkbenchWindow().getActivePage();
ISelectionService selService = PlatformUI.getWorkbenc h().getActiveWorkbenchWindow().getSelectionService( );final ISelection selection = selService.getSelection( );if (selection instanceof TreeSelection) {
TreeSelection currentFile = (TreeSelection)selection;final IFile firstElement = (IFile)currentFile.getFirs tElement();IEditorDescriptor desc =
PlatformUI.getWorkbench().getEditorRegistry().getDe faultEditor(firstElement.getName());try {
activePage.openEditor(new FileEditorInput(firstElement), desc.getId(), true, IWorkbenchPage.MATCH_NONE);
} catch (PartInitException e) {e.printStackTrace();
}}
return null;}
}
OpenSeveralEditorInstances.javadu projet EditorExample
Précise qu’il n’y a pas de comparaison entre les instances d’éditeur
51Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie
� L’interface IEditorReference permet de représenter une
instance d’un éditeur dans la page active
� String getName() : le nom de l’éditeur
� IEditorPart getEditor(boolean restore) : l’éditeur associé à cette
instance
� IEditorInput getEditorInput() : l’EditorInput associé à cette instance
� boolean isPinned() : indique si l’éditeur est épinglé (voir transparent
suivant pour explication)
� L’accès à un objet IViewReference se fait par l’intermédiaire
du Workbench Page actif
52Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : isPinned ?
� Possibilité d’ouvrir plusieurs éditeurs dans une page pouvant
aboutir à un nombre important d’éditeurs ouverts
� La plateforme Eclipse permet de restreindre le nombre
d’éditeur ouvert dans une page en fermant automatique-
ment les anciens éditeurs
� Preferences -> General -> Editors … activer l’option Close editors …
Seuls trois éditeurs doivent rester ouverts
53Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : isPinned ?
� Un éditeur ne peut être fermé automatiquement dans les
cas suivants
� si son état est dirty (contenu modifié)
� si son état est pinned (épinglé)
� Comment « épingler » un éditeur …Dés que l’option Close Editors
automatically est activée, l’action Pin Editor est disponible
Possibilité de modifier programmatiquement l’état de la
caractéristique pinned d’un éditeur
L’action Pin Editor sur l’éditeur courant active ou pas l’état épinglé
54Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comCycle de vie : de l’ouverture à la fermeture
� Ouverture de l’éditeur
� void init(IEditorSite site, IEditorInput input) : initialisation du
contenu de l’éditeur
� void createPartControl(Composite parent) : création de l’IHM
� Modification du contenu
� void firePropertyChange(PROP_INPUT) : déclenche un changement
� boolean isDirty() : précise s’il y a des changements
� Persistance
� void doSave(IProgressMonitor monitor) : sauvegarder le contenu
� void doSaveAs() : sauvegarder le contenu dans un autre objet
� Fermeture
� dispose() : destruction des objets
1
2
3
4
55Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : ouverture d’un éditeur
� Ouverture d’un éditeur procède à la création d’une instance
EditorPart dans le Workbench Page actif
� Ordre d’appel des méthodes de la classe de type EditorPart
� Constructeur de la classe de type EditorPart
� void init(IEditorSite site, IEditorInput input) : ne pas oublier de
stocker le site et l’input dans le traitement de cette méthode
� void createPartControl(Composite parent)
� Méthodes appelées par la plateforme Eclipse uniquement à
la création de l’instance d’un éditeur
1
2
3
56Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : éditeur en utilisation
� Tout au long de l’utilisation d’une instance d’un EditorPart,
son contenu peut évoluer
� Exemple : un texte a été modifié, une sauvegarde peut être réalisée
� La méthode isDirty() permet de retourner à la page courante
l’état de ce changement
� Si un changement est repéré, les procédures de sauvegarde
du contenu sont proposées
� La commande Save est activée
� La commande Save As est activée si la méthode isSaveAsAllowed()
retourne vraie
� La sauvegarde est proposée à l’utilisateur si la méthode
isSaveOnCloseNeeded() retourne vraie
57Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : fermeture d’un éditeur
� La sauvegarde du contenu est gérée directement par
l’éditeur dans la classe de type EditorPart
� Plusieurs méthodes sont appelées en fonction du type de
sauvegarde à réaliser
� void doSave(IProgressMonitor monitor) : appelée pour réaliser une
sauvegarde sur une ressource
� void doSaveAs() : appelée pour effectuer une sauvegarde de type
« Sauvegarder Comme »
� A la suite de la sauvegarde, il faut penser à modifier l’état
du changement retourné par la méthode isDirty()
� La fermeture d’un éditeur provoque la suppression d’une
instance de type EditorPart (méthode dispose() appelée)
58Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : show et hide
� Depuis la version Eclipse 3.5 (Galileo), une API permet de
cacher et de rendre visible un éditeur sans destruction de
ces instances
� Son utilisation reste limitée et seulement deux méthodes
sont proposées
� void hideEditor(IEditorReference) : cache un éditeur en utilisant son
EditorReference
� void showEditor(IEditorReference) : affiche un éditeur précédemment
caché
� Il n’est pas possible de récupérer la liste des éditeurs qui
sont dans un état caché
59Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : show et hide
� Exemple : Cacher et ouvrir un éditeur
public class HideEditorCommandHandler extends Abstrac tHandler {
public Object execute(ExecutionEvent event) throws Ex ecutionException {final IWorkbenchPage activePage = PlatformUI.getWorkb ench().getActiveWorkbenchWindow().getActivePage();
final IWorkbenchPartReference reference = activePage. getReference(activePage.getActiveEditor());if (reference instanceof IEditorReference) {
activePage.hideEditor((IEditorReference)reference);Activator.getDefault().getHiddenEditors().add((IEdi torReference)reference);
}
return null;}
}
HideEditorCommandHandler.javadu projet EditorExample
Ajoute chaque référence (IEditorReference) des éditeurs à
cacher dans l’Activator
Handler utilisé pour cacher des éditeurs
L’ajout explicite des éditeurs dans l’Activator est nécessaire puisque l’API ne permet pas de connaître les éditeurs
cachés
60Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Cycle de vie : show et hide
� Exemple (suite) : Cacher et ouvrir un éditeur
public class ShowEditorCommandHandler extends Abstrac tHandler {
public Object execute(ExecutionEvent event) throws Ex ecutionException {final IWorkbenchPage activePage = PlatformUI.getWorkb ench().getActiveWorkbenchWindow().getActivePage();
final List<IEditorReference> hiddenEditors = Activat or.getDefault().getHiddenEditors();if (!hiddenEditors.isEmpty()) {
activePage.showEditor(hiddenEditors.get(0));hiddenEditors.remove(0);
}return null;
}}
ShowEditorCommandHandler.javadu projet EditorExample
public class ShowAllHiddenEditorsHandler extends Abst ractHandler {
public Object execute(ExecutionEvent event) throws Ex ecutionException {final IWorkbenchPage activePage = PlatformUI.getWorkb ench().getActiveWorkbenchWindow().getActivePage();
WorkbenchPage activeWorkbencPage = (WorkbenchPage)act ivePage;
final List<IEditorReference> hiddenEditors = Activat or.getDefault().getHiddenEditors();hiddenEditors.clear();activeWorkbencPage.resetHiddenEditors();return null;
}}
ShowAllHiddenEditorsHandler.javadu projet EditorExample
Appel de showEditor pour afficher l’éditeur puis suppression dans l’Activator
Appel de resetHiddenEditors pour réafficher tous les éditeurs cachés
ou
Permet de réafficher un seul éditeur
Permet de réafficher tous les éditeurs
61Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
MultiPageEditorPart
� Un MultiPageEditorPart est un éditeur avec plusieurs pages
où chaque page peut contenir
� un éditeur (EditorPart) ou
� un composant SWT
� Un MultiPageEditorPart hérite de EditorPart et par
conséquent il se comporte comme un éditeur classique
(cycle de vie identique)
Une page contenant un éditeur
Une page contenant des composants SWT (Composite, Button, …)
62Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
MultiPageEditorPart
� Les méthodes utiles de la classe MultiPageEditorPart
� int addPage(IEditorPart editor, IEditorInput input) : ajoute un éditeur
à la dernière page et retourne l’index de la page ajoutée
� int addPage(Control p) : ajoute un composant SWT à la dernière page
et retourne l’index de la page ajoutée
� void setPageText(int index, String title) : modifie le titre de la page en
fonction de l’index donné
� Les méthodes à implémenter et à redéfinir
� void createPages() : appeler pour construire les pages
� void doSave(IProgressMonitor p) : sauvegarde de l’éditeur multiple
� void doSaveAs() : sauvegarde de type « Sauvegarder Comme »
� boolean isSaveAsAllowed() : autoriser le « Sauvegarder Comme »
� void pageChange(int new) : à redéfinir si besoin d’être notifié du
changement de page
63Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
MultiPageEditorPart
� Exemple : Un éditeur multiple avec trois pages
Une page contenant un éditeur de texte affichant le contenu
d’un fichier
Une page contenant un composite avec un bouton
permettant de choisir une police de caractères
Une dernière page contenant un composite avec un composant
StyledText permettant d’afficher chaque mot (donné par le texte de la page 1) avec une police définie par la page 2
Exemple basé sur le template fourni par la plateforme Eclipse
utilisé pour illustrer la construction d’éditeurs
64Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
MultiPageEditorPart
� Exemple (suite) : Un éditeur multiple avec trois pagespublic class MultiPageEditor extends MultiPageEditorP art implements IResourceChangeListener {
public MultiPageEditor() {super();ResourcesPlugin.getWorkspace().addResourceChangeLis tener(this);
}
protected void createPages() {createPage0();createPage1();createPage2();
}private void createPage0() {
try {editor = new TextEditor();int index = addPage(editor, getEditorInput());setPageText(index, editor.getTitle());
} catch (PartInitException e) {ErrorDialog.openError(getSite().getShell(), "Error c reating nested text editor", null, e.getStatus());
}}private void createPage2() {
...text = new StyledText(composite, SWT.H_SCROLL | SWT. V_SCROLL);int index = addPage(composite);setPageText(index, "Preview");
}
protected void pageChange(int newPageIndex) {super.pageChange(newPageIndex);if (newPageIndex == 2) sortWords();
}
// Suite dans le prochain transparent}
MultiPageEditor.javadu projet MultiPageEditorExample
Ajoute un écouteur sur les changements des ressources
Demande la création de chaque page
Ajoute un éditeur dans la page 0
Ajoute un composite dans la page 2
A chaque changement de page une action est réalisée
65Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
MultiPageEditorPart
� Exemple (suite) : Un éditeur multiple avec trois pagespublic class MultiPageEditor extends MultiPageEditorP art implements IResourceChangeListener {
public void doSave(IProgressMonitor monitor) {getEditor(0).doSave(monitor);
}
public void doSaveAs() {IEditorPart editor = getEditor(0);editor.doSaveAs();setPageText(0, editor.getTitle());setInput(editor.getEditorInput());
}
public void resourceChanged(final IResourceChangeEve nt event) {if(event.getType() == IResourceChangeEvent.PRE_CLOS E){
Display.getDefault().asyncExec(new Runnable(){public void run(){
IWorkbenchPage[] pages = getSite().getWorkbenchWind ow().getPages();for (int i = 0; i<pages.length; i++){
if(((FileEditorInput)editor.getEditorInput()).getFi le().getProject().equals(event.getResource())) {IEditorPart editorPart = pages[i].findEditor(editor.g etEditorInput());pages[i].closeEditor(editorPart,true);
}}
} });
}}
public void dispose() {ResourcesPlugin.getWorkspace().removeResourceChange Listener(this);super.dispose();
}}
Sauvegarde le contenu si des modifications ont été apportées
Si le projet est fermé, les éditeurs associés sont fermés
MultiPageEditor.javadu projet MultiPageEditorExample
66Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Diviser un éditeur
� Dans une page la zone de l’éditeur est unique et plusieurs
instances d’éditeurs peuvent cohabiter dans la zone
� L’affichage des éditeurs peut se faire
� Soit en empilant les différents éditeurs
� Soit en divisant (split) les éditeurs
� Soit de manière mixte (empiler + diviser)
� Pour diviser des éditeurs, l’utilisateur peut faire glisser un
éditeur dans la zone
� Toutefois, il n’existe pas d’API « publics » pour réaliser
cette opération de manière programmatique, il faut penser
par l’implémentation interne
67Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Diviser un éditeur
� Exemple : Diviser programmatiquement la zone de l’éditeur
Exemple issu du blog …http://swarmy.free.fr/wordpress/?p=17
La zone de l’éditeur est séparée en deux
68Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Diviser un éditeur
� Exemple (suite) : Diviser programmatiquement la zone de
l’éditeurpublic class CreateSplitEditorHandler extends Abstra ctHandler {
public Object execute(ExecutionEvent event) throws E xecutionException {IWorkbenchPage workbenchPage = PlatformUI.getWorkbenc h().getActiveWorkbenchWindow().getActivePage();IWorkbenchPart part = workbenchPage.getActivePart();PartPane partPane = ((PartSite) part.getSite()).getPa ne();LayoutPart layoutPart = partPane.getPart();
IEditorReference[] editorReferences = workbenchPage. getEditorReferences();if (editorReferences.length > 1) {
PartPane currentEditorPartPane = ((PartSite) workbenc hPage.getActiveEditor().getSite()).getPane();EditorSashContainer editorSashContainer = null;ILayoutContainer rootLayoutContainer = layoutPart.get Container();if (rootLayoutContainer instanceof LayoutPart) {
ILayoutContainer editorSashLayoutContainer = ((Layout Part) rootLayoutContainer).getContainer();if (editorSashLayoutContainer instanceof EditorSashCo ntainer) {
editorSashContainer = ((EditorSashContainer) editorS ashLayoutContainer);}
}
PartStack newPart = createStack(editorSashContainer);editorSashContainer.stack(currentEditorPartPane, ne wPart);if (rootLayoutContainer instanceof LayoutPart) {
ILayoutContainer cont = ((LayoutPart) rootLayoutConta iner).getContainer();
if (cont instanceof PartSashContainer) {// "Split" the editor area by adding the new part((PartSashContainer) cont).add(newPart);
}}
}return null;
}// Suite dans le prochain transparent ...
}
CreateSplitEditorHandler.javadu projet SplitEditorExample
69Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Diviser un éditeur
� Exemple (suite) : Diviser programmatiquement la zone de
l’éditeur
public class CreateSplitEditorHandler extends Abstra ctHandler {
...
private PartStack createStack(EditorSashContainer edi torSashContainer) {WorkbenchPage workPage = (WorkbenchPage)PlatformUI.ge tWorkbench().getActiveWorkbenchWindow().getActivePa ge();EditorStack newWorkbook = EditorStack.newEditorWorkbo ok(editorSashContainer, workbenchPage);return newWorkbook;
}}
CreateSplitEditorHandler.javadu projet SplitEditorExample
Une grande partie des APIs utilisées sont définies comme
Internal
70Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Ecouteurs (Part Listeners)
� Les modifications opérées sur un éditeur (activation, visibilité
ou l’ouverture) peuvent être écoutées (principe identique
pour les vues)
� L’activation et la création des éditeurs sont écoutables 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
71Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Ecouteurs (Part Listeners)
� IPartListener2 fournit les méthodes suivantes pour les
réponses aux événements sur un éditeur
� 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
� L’écoute de certaines modifications propres aux éditeurs n’est
pas pris en compte : show/hide, instances multiples, division
d’un éditeur, …
72Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Ecouteurs (Part Listeners)
� Exemple : Ecouter les changements d’un EditorPartpublic class LifeCycleEditor extends EditorPart {
public void createPartControl(Composite parent) {...IWorkbenchPage activePage = PlatformUI. getWorkbench().getActiveWorkbenchWindow().getActivePage();activePage.addPartListener(new IPartListener2() {
@Overridepublic void partActivated(IWorkbenchPartReference par tRef) {
IWorkbenchPart part = partRef.getPart(false);if (LifeCycleEditor.this == part) {
System. out.println(".partActivated()");}
}@Overridepublic void partBroughtToTop(IWorkbenchPartReference partRef) {
IWorkbenchPart part = partRef.getPart(false);if (LifeCycleEditor.this == part) {
System. out.println(".partBroughtToTop()");}
}@Overridepublic void partClosed(IWorkbenchPartReference partRe f) {
IWorkbenchPart part = partRef.getPart(false);if (LifeCycleEditor.this == part) {
System. out.println(".partClosed()");}
}...
}}
}
LifeCycleEditor.javadu projet EditorExample
73Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et les commandes
� Lors de l’activation d’un éditeur il est possible de rendre
accessible des actions spécifiques à ce contexte
� Si l’éditeur n’est plus actif, les actions spécifiques sont
automatiquement cachées
� Exemple : ouverture d’un éditeur de texte
� Rendre accessible des actions comme copier/coller/couper …
� Deux solutions sont à envisager
� Utilisation des restrictions via les commandes (afficher une commande
selon si un éditeur est actif ou pas)
� Utilisation d’un objet IEditorActionBarContributor (à renseigner lors de
la définition de l’extension d’un éditeur)
� Dans la suite, nous utiliserons la seconde solution basée sur
l’utilisation de commandes
74Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et les commandes
� L’interface IEditorActionBarContributor permet d’ajouter des
actions dans un menu, une barre d’outils et la barre d’états
� void contributeToMenu(IMenuManager mmanager) : pour contribuer à
l’enrichissement de la barre de menu
� void contributeToStatusLine(IStatusLineManager smanager) : pour
contribuer à l’enrichissement de la barre d’états
� void contributeToToolBar(IToolBarManager tmanager) : pour
contribuer à l’enrichissement de la barre d’outils
� Dans les trois cas, possibilité d’ajouter des éléments de type
IContributionItem (CommandContributionItem)
75Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et les commandes
� Exemple : Contribuer au menu, à la barre d’outils et à la
barre d’états
Lors de l’activation de l’éditeur, des actions sont disponibles dans la barre d’outils (1), la barre d’état (2) et le menu File (3)
1
2
3
76Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et les commandes
� Exemple (suite) : Contribuer au menu, à la barre d’outils et
à la barre d’états
plugin.xml du projet EditorActionBarContributor
Objet de type EditorWithCommandActionBarContributor
77Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et les commandes
� Exemple (suite) : Contribuer au menu, à la barre d’outils et
à la barre d’états public class EditorWithCommandActionBarContributor e xtends EditorActionBarContributor {
public void contributeToMenu(IMenuManager menuManage r) {super.contributeToMenu(menuManager);CommandContributionItemParameter commandParameter = n ew CommandContributionItemParameter(
PlatformUI.getWorkbench(), "contributionitem","eclipse.workbench.editorexample.SimpleCommandId",CommandContributionItem.STYLE_PUSH);
IContributionItem ref = new CommandContributionItem( commandParameter);
IMenuManager menu = new MenuManager("Simple Editor");menuManager.prependToGroup(IWorkbenchActionConstant s.MB_ADDITIONS, menu);menuManager.findMenuUsingPath("File").add(ref);
}
public void contributeToStatusLine(IStatusLineManag er statusLineManager) {CommandContributionItemParameter commandParameter = n ew CommandContributionItemParameter(
PlatformUI.getWorkbench(), "contributionitem","eclipse.workbench.editoractionbarcontributorexampl e.samplecommandid",CommandContributionItem.STYLE_PUSH);
IContributionItem ref = new CommandContributionItem( commandParameter);statusLineManager.add(ref);
}
public void contributeToToolBar(IToolBarManager tool BarManager) {CommandContributionItemParameter commandParameter = n ew CommandContributionItemParameter(
PlatformUI.getWorkbench(), "contributionitem","eclipse.workbench.editoractionbarcontributorexampl e.samplecommandid",CommandContributionItem.STYLE_PUSH);
IContributionItem ref = new CommandContributionItem( commandParameter);toolBarManager.add(ref);
}}
EditorWithCommandActionBarContributor.javadu projet EditorActionBarContributor
78Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Généralités
� La plateforme Eclipse s’appuie sur le Workspace pour
stocker les fichiers qu’il manipule
� Le Workspace est un répertoire hiérarchique physique qui
contient une collection de ressources
� Projets, répertoires et fichiers
� Le Workspace sert également à stocker les paramètres des
plugins (répertoire .metadata)
� Paramètres définis par les préférences de l’utilisateur
� Agencement de l’espace de travail (perspectives, projets ouverts, …)
� Pourquoi discuter du Workspace ici ?
� L’éditeur manipulent essentiellement des ressources
� Besoin de notifications sur les changements des ressources
79Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Généralités
� Structure d’un Workspace Eclipse
Répertoire contenant des informations liées aux plugins
Ressources de type projet
Fichier .log utilisépour stocker les
messagesInformations liées
aux plugins
Ressources de type dossier et fichier
80Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Généralités
� Exemple : Localiser l’emplacement du Workspace
public class WorkspaceViewPart extends ViewPart {
public void createPartControl(Composite parent) {...Button location = new Button(parent, SWT.FLAT);location.setText("Workspace location ...");location.addSelectionListener(new SelectionAdapter() {
@Overridepublic void widgetSelected(SelectionEvent e) {
Location instanceLoc = Platform.getInstanceLocation( );
System.out.println(instanceLoc.getURL().toString()) ;}
});...
}}
WorkspaceViewPart.javadu projet WorkspaceExample
81Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Généralités
� Exemple : Forcer la sélection du Workspace au démarrage
d’une application Eclipse
Avec l’option -data @noDefault, la plateforme Eclipse demandera àchaque démarrage l’emplacement
du Workspace
WorkspaceExampleConfiguration.launchdu projet WorkspaceExample
82Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource
� La plateforme Eclipse fournit des APIs pour la création, la
navigation et la manipulation de ressources dans un
Workspace
� Le plugin org.eclipse.core.resources fournit ces APIs
(dépendance obligatoire)
� Des méta-données sont associées aux ressources
� Properties (session et persistent)
� Preferences
� Content types
� Linked resources (attaché un fichier à un projet qui n’est pas localisé
dans le Workspace)
� Markers (task, problem, text, bookmark)
83Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource
� Cartes des principales interfaces concernant les ressources
IResource
getName()
getParent()
getWorkspace()
getFullPath()
…
IContainer
members()
exists(IPath)
…
IProject
open(int, IProgressMonitor)
create(IProgressMonitor)
close(IProgressMonitor)
…
IFolder
getFile(String)
create(boolean, boolean, IProgressMonitor)
createLink(URI, int, IProgressMonitor)
delete(boolean, boolean, IProgressMonitor)
…
IWorkspaceRoot
getProjects()
getProject(String)
delete(boolean, boolean, IProgressMonitor)
…
IWorkspace
addResourceChangeListener(IResourceChangeListener)
build(int, IProgressMonitor)
isAutoBuilding()
getRoot()
…
IFile
create(InputStream, int, IProgressMonitor)
createLink(URI, int, IProgressMonitor)
delete(boolean, boolean, IProgressMonitor)
…
IPath
toFile()
…
Dépendance
Héritage
84Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Resource / IWorkspaceRoot
� Le Workspace est défini par l’interface IWorkspace et il n’y
a qu’un seul workspace par application Eclipse
� Pour récupérer le workspace de l’application Eclipse en cours
� IWorkspace permet l’écoute des changements sur les res-
sources d’un workspace (détaillée plus tard)
� Il permet également de récupérer un objet IWorkspaceRoot
autorisant l’accès à l’ensemble des projets
� Principales méthodes de IWorkspaceRoot
� IProject getProject(String) : récupère un projet par son nom
� IProject[] getProjects() : récupère tous les projets
IWorkspace current = ResourcesPlugin.getWorkspace();
IWorkspaceRoot currentRoot = ResourcesPlugin.getWorks pace().getRoot();
85Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Resource / IWorkspaceRoot
� Exemple : Lister l’ensemble des projets d’un Workspacepublic class WorkspaceViewPart extends ViewPart {
public void createPartControl(Composite parent) {...Button projects = new Button(parent, SWT.FLAT);projects.setText("Workspace location ...");projects.addSelectionListener(new SelectionAdapter() {
@Overridepublic void widgetSelected(SelectionEvent e) {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace() .getRoot();final IProject[] projects = root.getProjects();for (IProject iProject : projects) {
System.out.println(iProject.getName());}
}});...
}}
WorkspaceViewPart.javadu projet WorkspaceExample
86Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / IProject
� L’interface IProject définit le concept de projet
� Principales caractéristiques d’un projet Eclipse
� Un projet est un conteneur et contient des dossiers et des fichiers
� Un projet peut construire des ressources
� Un projet peut avoir des références vers d’autres projets
� Un projet peut avoir une ou plusieurs natures (voir plus tard)
� Un projet contient des méta-données (IProjectDescription)
� Différentes méthodes …
� void create(IProgressMonitor) : crée du projet
� void open(IProgessMonitor) : ouvre un projet
� IProjectDescription getDescription() : récupère les méta-datas
� IFolder getFolder(String) : retourne un dossier
� IFile getFile(String) : retourne un fichier
� + méthodes fournies par IContainer
87Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / IProject
� Exemple : Manipulation de ressource IProjectpublic class WorkspaceViewPart extends ViewPart {
public void createPartControl(Composite parent) {...Button createProject = new Button(parent, SWT.FLAT);createProject.setText("Create new Project ...");createProject.addSelectionListener(new SelectionAdap ter() {
public void widgetSelected(SelectionEvent e) {IWorkspaceRoot root = ResourcesPlugin.getWorkspace() .getRoot();final IProject project4 = root.getProject("Project 4" );try {
project4.create(null);project4.open(null);
final IProjectDescription description = project4.get Description();description.setComment("This is a simple project");final IProject project1 = root.getProject("Project 1" );final IProject project2 = root.getProject("Project 2" );
IProject[] tabProjects = {project1, project2};description.setReferencedProjects(tabProjects);
project4.setDescription(description, null);} catch (CoreException e1) {
e1.printStackTrace();}
}});...
}}
WorkspaceViewPart.javadu projet WorkspaceExample
88Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / IProject
� Les informations décrit dans IProjectDescription sont
stockées dans le fichier .project
<?xml version="1.0" encoding="UTF-8"?><projectDescription>
<name>Project 4</name>
<comment>This is a simple project</comment>
<projects><project>Project 1</project><project>Project 2</project>
</projects>
<buildSpec></buildSpec>
<natures></natures>
</projectDescription>
Nom du projet
Commentaire du projet
Liste des projets référencés
Liste des Builders
Liste des Natures Fichier .project du répertoire Project 4
89Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / IFolder
� L’interface IFolder décrit un dossier localisé dans un projet
� Un objet IFolder est un conteneur et contient des fichiers et des dossiers
� Différentes méthodes …
� void create(boolean, boolean, IProgressMonitor) : création du dossier
� IFile getFile(String) : retourne un fichier
� IFolder getFolder(String) : retour un dossier
� + méthodes fournies par IContainer
� L’interface IFile décrit un fichier
� void create(InputStream, boolean, IProgressMonitor) : création du fichier
� InputStream getContents() : retourne le contenu
� IPath getFullPath() : retourne le chemin
� + méthodes fournis par IResource
90Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / IFolder
� Exemple : Manipulation de ressources IFolder et IFilepublic class WorkspaceViewPart extends ViewPart {
public void createPartControl(Composite parent) {...Button createFolder = new Button(parent, SWT.FLAT);createFolder.setText("Create new Folder and File ... ");createFolder.addSelectionListener(new SelectionAdapt er() {
public void widgetSelected(SelectionEvent e) {IWorkspaceRoot root = ResourcesPlugin.getWorkspace() .getRoot();final IProject project4 = root.getProject("Project 4" );
try {final IFolder folderA = project4.getFolder("Folder A" );folderA.create(true, true, null);
IFile fileA = project4.getFile("File A.txt");fileA.create(new ByteArrayInputStream("HelloWorld fro m File A".getBytes()), true, null);
IFile fileB = folderA.getFile("File B.txt");fileB.create(new ByteArrayInputStream("HelloWorld fro m File B".getBytes()), true, null);
System.out.println(fileA.getFullPath());
} catch (CoreException e1) {e1.printStackTrace();
}}
}); ...}
}
WorkspaceViewPart.javadu projet WorkspaceExample
91Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Properties
� Les propriétés (Properties) sont utilisées pour attacher des
informations (méta-données) aux ressources
� Tous les objets de type IResource sont concernés (IProject,
IFolder, IFile et IWorkspaceRoot)
� Quand une ressource est supprimée, ses propriétés sont
effacées également
� Deux types de propriétés sont à distinguer
� Propriétés de session
� Propriétés persistantes
� L’API de manipulation est fournie par l’interface IResource
92Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Properties
� Propriétés de session
� Permet de sauvegarder des informations dans un couple clé / valeur
� Les valeurs peuvent être des objets
� Les propriétés sont maintenues en mémoire
� Les propriétés sont supprimées quand une ressource est supprimée
ou quand un projet ou un workspace est fermé
� Map IResource#getSessionProperties() : propriétés en session
� Propriétés de persistances
� Sauvegarde les informations physiquement sur le disque
� Les valeurs sont obligatoirement des chaînes de caractères
� Les chaînes de caractères sont prévues pour être courtes
� Les propriétés sont maintenues même au redémarrage de la
plateforme
� Map IResource#getPersistentProperties() : propriétés persistantes
93Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Properties
� Exemple : Manipulation des propriétés de session
public class PropertiesViewPart extends ViewPart {
public void createPartControl(Composite parent) {...Button saveSessionPropertiesButton = new Button(pare nt, SWT.FLAT);saveSessionPropertiesButton.setText("Save Session Pr operties ...");saveSessionPropertiesButton.addSelectionListener(ne w SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {IWorkspaceRoot root = ResourcesPlugin.getWorkspace() .getRoot();
final IProject project5 = root.getProject(projectNam e);
try {if (!project5.exists()) {
project5.create(null);project5.open(null);
}project5.setSessionProperty(new QualifiedName("sess ion_test", "en"), "test");
} catch (Exception e1) {e1.printStackTrace();
}}
});...
}}
PropertiesViewPart.javadu projet WorkspaceExample
Enregistrement d’une propriété« session_test » dans la session d’un projet
Si le projet est fermé, workspacerechargé ou application redémarrée, la
propriété est perdue
94Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Properties
� Exemple (suite) : Manipulation des propriétés de session
public class WorkspaceViewPart extends ViewPart {
public void createPartControl(Composite parent) {...Button loadSessionPropertiesButton = new Button(pare nt, SWT.FLAT);loadSessionPropertiesButton.setText("Load Session Pr operties ...");loadSessionPropertiesButton.addSelectionListener(ne w SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {IWorkspaceRoot root = ResourcesPlugin.getWorkspace() .getRoot();final IProject project5 = root.getProject(projectNam e);
try {final Map sessionProperties = project5.getSessionPro perties();System.out.println(sessionProperties.get(new Qualifi edName("session_test", "en")));
} catch (CoreException e1) {e1.printStackTrace();
}}
});...
}}
PropertiesViewPart.javadu projet WorkspaceExample
Chargement de la propriété« session_test »
95Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Properties
� Exemple : Manipulation des propriétés persistances
public class PropertiesViewPart extends ViewPart {
public void createPartControl(Composite parent) {...Button savePersistentPropertiesButton = new Button(p arent, SWT.FLAT);savePersistentPropertiesButton.setText("Save Persist ence Properties ...");savePersistentPropertiesButton.addSelectionListener (new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {IWorkspaceRoot root = ResourcesPlugin.getWorkspace() .getRoot();final IProject project5 = root.getProject(projectNam e);
try {if (!project5.exists()) {
project5.create(null);}
project5.setPersistentProperty(new QualifiedName("p ersistent_test", "en"), "test");} catch (CoreException e1) {
e1.printStackTrace();}
}});
}}
PropertiesViewPart.javadu projet WorkspaceExample
Enregistrement d’une propriété« persistent_test » dans un projet en
mode persistant
Si le projet est fermé, workspacerechargé ou application redémarrée, la
propriété reste présente
96Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Properties
� Exemple (suite) : Manipulation des propriétés persistances
public class PropertiesViewPart extends ViewPart {
public void createPartControl(Composite parent) {...Button loadPersistentPropertiesButton = new Button(p arent, SWT.FLAT);loadPersistentPropertiesButton.setText("Load Persist ence Properties ...");loadPersistentPropertiesButton.addSelectionListener (new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {IWorkspaceRoot root = ResourcesPlugin.getWorkspace() .getRoot();final IProject project5 = root.getProject(projectNam e);
try {final Map persistentProperties = project5.getPersist entProperties();System.out.println(persistentProperties.get(new Qual ifiedName("persistent_test", "en")));
} catch (CoreException e1) {e1.printStackTrace();
}}
});}
}
PropertiesViewPart.javadu projet WorkspaceExample
Chargement de la propriété« persistent_test »
97Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Markers
� Les markers sont un mécanisme permettant d’annoter une ressource
� Les markers peuvent s’appliquer autant sur les projets que les dossiers et les fichiers
� La plateforme Eclipse définit cinq types de markers
� Marker : annotation de base
� Task : annotation de type tâche
� Problem : annotation de type problème
� Text : annotation de type texte
� Bookmark : annotation de type favori
� Possibilité de définir ses propres markers en utilisant le point d’extension org.eclipse.core.resources.markers
� Les types de markers sont hiérarchiques et des niveaux d’héritage peuvent être définis
98Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Markers
Markers de type Problem avec deux niveaux de sévérité : Error et Warning
� Exemple : Des Markers de types Problem et Task
Markers de type Task
99Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Markers
� Un marker est défini par l’interface IMarker
� La création d’un marker est réalisé à partir d’un objet de
type IResource
� Opérations basiques (méthodes de IResource)
� IMarker createMarker(String) : création d’un marker à partir d’un
identifiant (Task, Bookmark, …)
� void deleteMarkers(String t, boolean, int) : supprime tous les markers
définis par le type t
� Principales méthodes de IMarker
� void delete() : supprimer un marker
� Une série setAttribute(String, boolean || int || Object) : permettant
d’affecter des valeurs à des attributs prédéfinis
100Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Markers
� L’interface IMarker définit un ensemble d’attributs et de
valeurs d’attributs pour les types de marker prédéfinis
� SEVERITY : niveau de sévérité (#SEVERITY_ERROR,
#SEVERITY_WARNING, #SEVERITY_INFO)
� MESSAGE : description du marker (nom d’une tâche)
� LOCATION : information pour distinguer deux markers
� PRIORITY : niveau de priorité (#PRIORITY_HIGH,
#PRIORITY_NORMAL, #PRIORITY_LOW)
� DONE : marker est considéré terminé
� CHAR_START et CHAR_END : intervalle impacté
� LINE_NUMBER : numéro de line impacté
� USER_EDITABLE : modification autorisé ou pas
101Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Markers
� Exemple : Création d’une annotation de type Task
Les tâches sont visibles dans la vue Tasks
Depuis l’éditeur, une annotation précise qu’une tâche est associée à la ligne 2
Tâche annotée àune ressource de
type fichier
102Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Markers
� Exemple (suite) : Création d’une annotation de type Taskpublic class MarkersViewPart extends ViewPart {
public void createPartControl(Composite parent) {...Button createTasks = new Button(parent, SWT.FLAT);createTasks.setText("Create Tasks ...");createTasks.addSelectionListener(new SelectionAdapte r() {
public void widgetSelected(SelectionEvent e) {IWorkspaceRoot root = ResourcesPlugin.getWorkspace() .getRoot();final IProject projectMarkers= root.getProject("Proj ect Markers");try {
if (!projectMarkers.exists()) {projectMarkers.create(null);projectMarkers.open(null);
}final IFile file = projectMarkers.getFile("file");if (!file.exists()) {
file.create(new ByteArrayInputStream("HelloWorld\nThis is a text for Markers example".getBytes()), IR esource.NONE, null);
}
IMarker createTaskMarker = file.createMarker(IMarker. TASK);createTaskMarker.setAttribute(IMarker.MESSAGE, "Sam ple Task message");createTaskMarker.setAttribute(IMarker.PRIORITY, IMa rker.PRIORITY_LOW);createTaskMarker.setAttribute(IMarker.USER_EDITABLE , false);createTaskMarker.setAttribute(IMarker.LINE_NUMBER, 2);
} catch (Exception e1) {e1.printStackTrace();
}}
});}
}
MarkersViewPart.javadu projet WorkspaceExample
103Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Markers
� Exemple : Création d’une annotation de type Problem
Les problèmes sont visibles dans la vue Problems
Depuis l’éditeur, une annotation précise que des problèmes sont associés à la ligne 2
Problèmes annotés à une ressource de
type fichier
104Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Markers
� Exemple (suite) : Création d’une annotation de type Problem
public class MarkersViewPart extends ViewPart {
public void createPartControl(Composite parent) {...Button createProblems = new Button(parent, SWT.FLAT) ;createProblems.createTasks.setText("Create Tasks ... ");createProblems.addSelectionListener(new SelectionAda pter() {
public void widgetSelected(SelectionEvent e) {...try {
IMarker createErrorProblemMarker = file.createMarker( IMarker.PROBLEM);createErrorProblemMarker.setAttribute(IMarker.MESSA GE, "Sample Error Problem message");createErrorProblemMarker.setAttribute(IMarker.SEVER ITY, IMarker.SEVERITY_ERROR);createErrorProblemMarker.setAttribute(IMarker.PRIOR ITY, IMarker.PRIORITY_LOW);createErrorProblemMarker.setAttribute(IMarker.LINE_ NUMBER, 2);
IMarker createWarningProblemMarker = file.createMarke r(IMarker.PROBLEM);createWarningProblemMarker.setAttribute(IMarker.MES SAGE, "Sample Warning Problem message");createWarningProblemMarker.setAttribute(IMarker.SEV ERITY, IMarker.SEVERITY_WARNING);createWarningProblemMarker.setAttribute(IMarker.PRI ORITY, IMarker.PRIORITY_HIGH);createWarningProblemMarker.setAttribute(IMarker.LIN E_NUMBER, 2);
} catch (Exception e1) {e1.printStackTrace();
}}
});}
}
MarkersViewPart.javadu projet WorkspaceExample
105Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Markers
� Exemple : Création d’une annotation de type BookmarkDepuis l’éditeur, une annotation précise qu’un
favori est associé à la ligne 2
Les favoris sont visibles dans la vue Bookmarks
106Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Resource / Markers
public class MarkersViewPart extends ViewPart {
public void createPartControl(Composite parent) {...Button createBookmarks = new Button(parent, SWT.FLAT );createBookmarks.createTasks.setText("Create Tasks .. .");createBookmarks.addSelectionListener(new SelectionAd apter() {
public void widgetSelected(SelectionEvent e) {...try {
IMarker createErrorProblemMarker = file.createMarker( IMarker.BOOKMARK);createErrorProblemMarker.setAttribute(IMarker.MESSA GE, "Sample Bookmark message");createErrorProblemMarker.setAttribute(IMarker.LINE_ NUMBER, 2);
} catch (Exception e1) {e1.printStackTrace();
}}
});}
}
MarkersViewPart.javadu projet WorkspaceExample
� Exemple (suite) : Création d’une annotation de type
Bookmark
107Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Builder
� Un Builder (constructeur) est un objet qui manipule les
ressources d’un projet pour produire d’autres ressources
� Cette opération s’appelle un Build ou une construction
� La plateforme définit deux types de construction
� Une construction complète (full build) : manipule toutes les ressources
même si aucune modification n’a été apportée sur ces ressources
� Une construction incrémentale (incremental build) : s’appuie sur les
précédentes constructions pour traiter les ressources modifiées
� Les constructions incrémentales s’appuient sur des objets de
type IResourceDelta pour distinguer les changements d’une
ressource
� Le nettoyage d’un projet (Clean) force un builder à procéder
à une construction complète
108Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Builder
� Une construction (complète ou incrémentale) se déclenche
� De manière automatique (si l’option Build Automatically est activée)
à chaque modification opérée sur le workspace
� A la demande explicite du développeur (Build Project, Build All)
� Lors du démarrage d’un builder des artefacts peuvent être
générés
� Des ressources (projet, dossier ou des fichiers)
� Des markers (tâches, problèmes, …)
� Une ressource générée est appelée ressource dérivée
� Une construction est encapsulée dans un processus
extérieur de manière à
� éviter le blocage
� assurer l’annulation de la construction
109Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Builder / Exemple JDT
� Le projet JDT (Java Development Tool) utilise un builder
pour compiler les classes Java d’un projet
� Construction complète via JDT
� Toutes les classes Java (ressources) sont compilées
� Les fichiers .class (ressources dérivées) sont stockés dans le réper-
toire bin
� Les problèmes de compilation sont ajoutées comme des markers de
type Problem
� Construction incrémentale via JDT
� Seules les classes modifiées sont recompilées (utilisation des
IResourceDelta)
� Mise à jour de la liste des markers de type Problem
110Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Builder
� Un builder peut être déclenché explicitement via les
méthodes suivantes
� IProject#build(…) : demande un démarrage d’une construction avec
possibilité de choisir son builder (voir paramètres)
� IWorkspace#build(…) : demande un démarrage d’une construction
de tous les projets du workspace
� Les commandes utilisées dans le Workbench permettent
d’appeler directement ces méthodes
� Lors de l’appel de ces méthodes, des builders sont déclen-
chés. Si aucun builder n’a été défini aucune construction ne
sera réalisée
111Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Builder / Définir son Builder
� Création d’une extension à org.eclipse.core.resources.builders
Utilisation du point d’extension org.eclipse.core.resources.builders
Template existant pour les constructeurs
112Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Builder / Définir son Builder
� Edition des attributs de l’extension builders
Préciser l’identifiant de l’extension de manière à manipuler le builder par la suite
plugin.xmldu projet BuilderExample
113Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Builder / Définir son Builder
� Edition des attributs de l’extension builders (suite)Précise si le constructeur est associé à
une nature (voir plus tard)
Si à vraie, déclenche une construction incrémentale même s’il
n’y a aucun changementplugin.xmldu projet BuilderExample
114Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Builder / Définir son Builder
� Création de la classe du builder
Définition de la classe où sera codée le traitement du builder
plugin.xmldu projet BuilderExample
Classe de type IncrementalProjectBuilder
115Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Builder / Définir son Builder
� Associer des paramètres au builder
Deux paramètres sont associés au builder
plugin.xmldu projet BuilderExample
116Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Builder / Définir son Builder
� Classe du builder personnaliséepublic class CustomIncrementalProjectBuilder extends IncrementalProjectBuilder {
protected IProject[] build(int kind, Map args, IProg ressMonitor monitor) throws CoreException {if (kind == IncrementalProjectBuilder.FULL_BUILD) {
fullBuild(monitor);} else {
IResourceDelta delta = getDelta(getProject());if (delta == null) {
fullBuild(monitor);} else {
incrementalBuild(delta, monitor);}
}return null;
}
protected void fullBuild(final IProgressMonitor monit or) throws CoreException {try {
final IFolder folder = this.getProject().getFolder(" My Bin");if (!folder.exists()) {
folder.create(true, true, null);}
getProject().accept(new MyBuildVisitor());} catch (CoreException e) {}
}
protected void incrementalBuild(IResourceDelta delta , IProgressMonitor monitor) throws CoreException {delta.accept(new MyBuildDeltaVisitor());
}...
CustomIncrementalProjectBuilder.javadu projet BuilderExample
Selon le type de builderdes traitements
particuliers sont réalisés
Au niveau du full build un répertoire My Bin est créé
Un Visiteur est utilisé pour parcourir chaque ressource de la
construction et réaliser les opérations adéquates
117Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Builder / Définir son Builder
� Classe du builder personnalisée (suite)
public class CustomIncrementalProjectBuilder extends IncrementalProjectBuilder {
class MyBuildVisitor implements IResourceVisitor {public boolean visit(IResource res) {
System.out.println("Full " + res.getName());return true;
}}
class MyBuildDeltaVisitor implements IResourceDeltaV isitor {public boolean visit(IResourceDelta res) {
System.out.println("Incremental " + res.getKind() + " " + res.getResource().getName());return true;
}}
protected void clean(IProgressMonitor monitor) throw s CoreException {final IFolder folder = this.getProject().getFolder(" My Bin");if (folder.exists()) {
folder.delete(true, null);}
}}
CustomIncrementalProjectBuilder.javadu projet BuilderExample
Ce visiteur donne accès àchaque IResource « balayée »
par le full build
Ce visiteur donne accès à chaque IResourceDelta « balayée » par
l’incremental build
La catégorie permet de savoir quelle modification a été apportée à la ressource (voir constante dans IResourceDelta)
L’opération de nettoyage efface le répertoire créé dans le full build
118Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Builder / Définir son Builder
� Associer un builder personnalisé à un projet
public class BuilderViewPart extends ViewPart {
public void createPartControl(Composite parent) {parent.setLayout(new GridLayout());
Button createTasks = new Button(parent, SWT.FLAT);createTasks.setText("Associate Builder ...");createTasks.addSelectionListener(new SelectionAdapte r() {
public void widgetSelected(SelectionEvent e) {IWorkspaceRoot root = ResourcesPlugin.getWorkspace() .getRoot();
final IProject projectBuilder = root.getProject("Proj ect Builder");
try {if (!projectBuilder.exists()) {
projectBuilder.create(null);projectBuilder.open(null);
}
final IFile file = projectBuilder.getFile("file 1");if (!file.exists()) {
file.create(new ByteArrayInputStream("HelloWorld\n Th is is text for Builder examples".getBytes()), IResource.NONE, null);
}
...
BuilderViewPart.javadu projet BuilderExample
Création d’un projet et d’un fichier
119Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Builder / Définir son Builder
� Associer un builder personnalisé à un projet (suite)
public class BuilderViewPart extends ViewPart {
public void createPartControl(Composite parent) {...
final String BUILDER_ID = "eclipse.workbench.Builde rExample.samplebuilderid";
IProjectDescription desc = projectBuilder.getDescript ion();ICommand[] commands = desc.getBuildSpec();
// Add builder to projectICommand command = desc.newCommand();command.setBuilderName(BUILDER_ID);ICommand[] newCommands = new ICommand[commands.lengt h + 1];
// Add it before other builders.System.arraycopy(commands, 0, newCommands, 1, comma nds.length);newCommands[0] = command;desc.setBuildSpec(newCommands);projectBuilder.setDescription(desc, null);
} catch (Exception e1) {e1.printStackTrace();
}}
});}
}
BuilderViewPart.javadu projet BuilderExample
Identifiant du builder = identifiant plugin + identifiant extension du builder
120Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Builder / Définir son Builder
� Associer un builder personnalisé à un projet (suite)
Un dossier a été ajoutélors du full build
Toutes les ressources sont « visitées »
121Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Builder / Définir son Builder
� Associer un builder personnalisé à un projet (suite)
Le contenu du fichier file1a été mis à jour
Deux ressources ont étémodifiées
122Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Builder / Définir son Builder
� Associer un builder personnalisé à un projet (suite)
Le fichier file1 a été déplacé
Des ressources ont été modifiées, ajoutée (nouveau file 1) et supprimée (ancien file 1)
123Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Nature
� Associer un builder à un projet doit être réalisé une seule
fois, habituellement quand le projet est créé
� La plateforme Eclipse préconise d’associer un builder à un
projet en passant par la notion de nature
� De manière plus générale une nature est utilisée également
pour créer une association entre un projet et des plugins
� En ajoutant une nature à un projet, vous précisez que des
plugins sont configurés à utiliser ce projet
� Ce mécanisme de nature peut être ainsi utilisé pour ajouter
un comportement spécifique à des projets
124Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Nature / Exemple JDT
� Le projet JDT (Java Development Tool) utilise une nature
pour définir des comportements spécifiques pour les projets
Java
� Fonctionnalités de la nature Java
� Tous les plugins JDT sont ainsi associés aux projets Java
� Un classpath a été configuré
� Un builder propre au langage Java est défini
� Les icônes des ressources contenant du Java sont modifiés pour les
distinguer des autres ressources
� Des actions sur les différents menus peuvent être visibles ou
masquées
125Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Nature / Définir sa nature
� Création d’une extension à org.eclipse.core.resources.natures
Utilisation du point d’extension org.eclipse.core.resources.natures
126Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Nature / Définir sa nature
� Edition des attributs de l’extension nature
Préciser l’identifiant de l’extension de manière à manipuler le builder par la suite
plugin.xmldu projet NatureExample
127Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Nature / Définir sa nature
� Associer une nature à un projet
public class NatureViewPart extends ViewPart {public void createPartControl(Composite parent) {
parent.setLayout(new GridLayout());
Button createNature = new Button(parent, SWT.FLAT);createNature.setText("Associate Nature (add Builder by code ...");createNature.addSelectionListener(new SelectionAdapt er() {
public void widgetSelected(SelectionEvent e) {IWorkspaceRoot root = ResourcesPlugin.getWorkspace() .getRoot();final IProject projectNature = root.getProject("Proje ct Nature");
try {if (!projectNature.exists()) {
projectNature.create(null);projectNature.open(null);
}
final IFile file = projectNature.getFile("file 1");if (!file.exists()) {
file.create(new ByteArrayInputStream("HelloWorld\n Th is is text for Nature examples".getBytes()), IResource.NONE, null);
}...
}}
NatureViewPart.javadu projet NatureExample
Création d’un projet et d’un fichier
128Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Nature / Définir sa nature
� Associer une nature à un projet (suite)
public class NatureViewPart extends ViewPart {
public void createPartControl(Composite parent) {...
IProjectDescription description = projectNature.getD escription();String[] natures = description.getNatureIds();String[] newNatures = new String[natures.length + 1];System.arraycopy(natures, 0, newNatures, 0, natures .length);newNatures[natures.length] = "eclipse.workbench.Nat ureExample.samplenatureid";
description.setNatureIds(newNatures);projectNature.setDescription(description, null);
} catch (Exception e1) {e1.printStackTrace();
}}
});}
}
NatureViewPart.javadu projet NatureExample
Identifiant de la nature = identifiant plugin + identifiant extension de la nature
129Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Nature / Définir sa nature
� Création de la classe de la natureDéfinition de la classe où sera codé le traitement de la configuration de la nature vis-à-vis des projets
plugin.xmldu projet NatureExample
Classe de type IProjectNature
130Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Nature / Définir sa nature
� Un objet de type IProjectNature fournit des méthodes pour
l’installation et la désinstallation d’une nature
� void configure() : configure une nature pour un projet
� void unconfigure() : dé-configure une nature
� IProject getProject() : retourne le projet associé à la nature
� void setProject(IProject project) : modifie le projet associé à la nature
� Que faire dans configure/unconfigure ?
� Installation/désinstallation d’un builder
� Création/suppression d’attributs supplémentaires
� Plusieurs projets peuvent être associés à un même type de
nature (IProjectNature)
131Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Nature / Définir sa nature
� Exemple : Associer un builder à une naturepublic class CustomProjectNature implements IProject Nature {
private IProject current;
public void configure() throws CoreException {final String BUILDER_ID = "eclipse.workbench.Builde rExample.samplebuilderid";IProjectDescription desc = current.getDescription();ICommand[] commands = desc.getBuildSpec();
// Add builder to projectICommand command = desc.newCommand();command.setBuilderName(BUILDER_ID);ICommand[] newCommands = new ICommand[commands.lengt h + 1];
// Add it before other builders.System.arraycopy(commands, 0, newCommands, 1, comma nds.length);newCommands[0] = command;desc.setBuildSpec(newCommands);current.setDescription(desc, null);
}
public void deconfigure() throws CoreException {// Code permettant la suppression du builder ...
}
public IProject getProject() {return current;
}
public void setProject(IProject project) {this.current = project;
}}
CustomProjectNature.javadu projet NatureExample
IProjectDescription sert àpréciser les natures à utiliser
sur un projet
132Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comWorkspace : Nature / Définir sa nature
� Exemple : Définir l’icône d’un projet en fonction de la nature
plugin.xmldu projet NatureExample
Création de l’extension org.eclipse.ui.ide.projectNatureImages
Préciser l’identifiant de la naturepuis l’image à afficher
Nécessite que le plugin org.eclipse.ui.ide soit ajouté
comme dépendance
133Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Nature / Contraintes
� Des natures définies sur un projet peuvent être activées
sous certaines conditions (suivant des contraintes)
� Deux types de contraintes sont disponibles
� one-of-nature : spécifie qu’il ne peut y avoir qu’une seule nature pour
un projet
� requires-nature : spécifie qu’une nature dépend d’une autre nature et
ne peut être ajoutée à un projet que si l’autre nature est associée
également au projet
� Exemple via la contrainte requires-nature
� Un plugin ou outils ne peut être associé aux projets dont la nature
JDT est associée
� Les contraintes sont définies directement au niveau des
extensions des natures
134Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Nature / Contraintes
� Exemple : Définir une contrainte requires-nature
plugin.xmldu projet NatureExample
Identifiant de la nature requise (Ici il s’agit de la nature pour
gérer les projets Java)
Ajout d’un élément de type requires-nature à la définition
d’un nature
135Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Nature / Contraintes
� Exemple (suite) : Définir une contrainte requires-nature
public class NatureViewPart extends ViewPart {public void createPartControl(Composite parent) {
parent.setLayout(new GridLayout());
Button createRequiresNature = new Button(parent, SWT .FLAT);createRequiresNature.setText("Associate Nature (add Builder by code ...");createRequiresNature.addSelectionListener(new Select ionAdapter() {
public void widgetSelected(SelectionEvent e) {IWorkspaceRoot root = ResourcesPlugin.getWorkspace() .getRoot();final IProject projectNature = root.getProject("Proje ct Requires Nature");
try {if (!projectNature.exists()) {
projectNature.create(null);projectNature.open(null);
}
final IFile file = projectNature.getFile("file 1");if (!file.exists()) {
file.create(new ByteArrayInputStream("HelloWorld\n Th is is text for Nature examples".getBytes()), IResource.NONE, null);
}...
}}
NatureViewPart.javadu projet NatureExample
136Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Workspace : Nature / Contraintes
public class NatureViewPart extends ViewPart {
public void createPartControl(Composite parent) {...
IProjectDescription description = projectNature.getD escription();String[] natures = description.getNatureIds();String[] newNatures = new String[natures.length + 1];System.arraycopy(natures, 0, newNatures, 0, natures .length);newNatures[natures.length] = "eclipse.workbench.Nat ureExample.samplerequiresnaturesid";IStatus status = ResourcesPlugin.getWorkspace().vali dateNatureSet(newNatures);
if (status.getCode() == IStatus.OK) {description.setNatureIds(newNatures);projectNature.setDescription(description, null);
} else {System.out.println("Cannot enable this nature, natur e is required.");
}} catch (Exception e1) {
e1.printStackTrace();}
}});
}}
� Exemple (suite) : Définir une contrainte requires-nature
NatureViewPart.javadu projet NatureExample
Vérifie si les natures sont valides avant de les imposer aux projets
Comme la nature Java n’est pas associée au projet, une erreur
est retournée
137Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte
� Dans la suite, nous allons étudier en détail un éditeur qui
manipule du texte via la classe TextEditor
� Nous allons montrer comment enrichir un éditeur de texte
en ajoutant
� une coloration syntaxique
� un assistant de contenu (content assist)
� utilisation de patron
� vérification lexicale (spell checking)
� plan du contenu (outline)
� hiérarchiser du texte (folding)
� Par ailleurs, nous allons capitaliser la plupart des éléments
étudiés précédemment pour développer un exemple complet
138Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : exemple
� Définition d’un éditeur pour la sauvegarde de mot de passe
Les mots clés sont en gras La vue Outline est utilisée pour visualiser le contenu de l’éditeur
Utilisation de l’assistant de contenu pour insérer des mots clés et des templates
139Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : TextEditor par extension
� Définir un extension basée sur le point d’extension
org.eclipse.ui.editors
� Définir les attributs de l’extension
� Implémenter une classe qui hérite de TextEditor
� Fournir une icône pour dissocier l’éditeur
� Connecter le menu et la barre de menu à l’implémentation par défaut
� TextEditorActionContributor
� Ajouter les dépendances suivantes dans Require-Bundle
� org.eclipse.jface.text
� org.eclipse.ui.workbench.texteditor
� org.eclipse.ui.editors
140Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : hiérarchie du TextEditor
� Classe AbstractTextEditor
� Chercher / Remplacer, navigateur hypertexte
� Classe StatusTextEditor
� Afficher une barre d’état
� Classe AbstractDecoratedTextEditor
� Numéro de lignes, change ruler, overview ruler, surbrillance de la sélection, …
� Classe TextEditor
� L’éditeur de texte utilisé par défaut
� Toutes ces classes sont définies dans la plateforme Eclipse
via les packages org.eclipse.ui.editors…
� Nous verrons par la suite des APIs issues de la boîte à outils
JFace
141Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : SourceViewerConfiguration
� La configuration de l’affichage d’un éditeur de texte passe
par l’utilisation d’un objet de type SourceViewerConfiguration
� Coloration syntaxique
� Formatage
� Complétion automatique, …
� La classe SourceViewConfiguration réalise que très peu de
traitement, il faut passer par TextSourceViewerConfiguration
� Pour associer un SourceViewerConfiguration à un éditeur de
type texte
� setSourceViewerConfiguration(SourceViewerConfiguration s) : appeler cette méthode à la création de l’éditeur
� Au cours des fonctionnalités de notre éditeur nous découv-
rirons certaines méthodes de SourceViewerConfiguration
142Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : SourceViewerConfiguration
� Exemple : Associer un SourceViewerConfiguration à un
éditeur de texte
public class PassMemEditorPart extends AbstractDecor atedTextEditor {public PassMemEditorPart() {
super();
this.setSourceViewerConfiguration(new PassMemSourceViewerConfiguration(getSharedColor s(), getPreferenceStore()));
}}
Un SourceViewerConfigurationne s’utilise que pour les éditeurs
de type texte
Associe un SourceViewerConfiguration avec
l’éditeur
PassMemEditorPart.javades projets PassMemEditorStep…
143Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Coloration Syntaxique
� La coloration syntaxique permet de mettre en forme des
éléments du contenu d’un texte
� Caractère, mot, phrase, paragraphe, …
� Possibilité de modifier les caractéristiques suivantes
� Couleur de fond
� Couleur de texte
� Style du texte (italique, gras, police, taille, …)
� Exemple
144Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Coloration Syntaxique
� La coloration syntaxique est mise en place en utilisant un
objet de type IPresentationReconciler
� Un IPresentationReconciler permet de mettre à jour la mise
en forme du document lors de la saisie d’un texte
� Un objet PresentationReconciler s’appuie sur deux objets
� Damager : détermine quelle portion du texte à été modifiée et qui
doit être mise à jour (IPresentationDamager)
� Repairer : permet de savoir les styles à appliquer sur la portion de
texte qui a été modifiée (IPresentationRepairer)
� La classe DefaultDamagerRepairer implémente les interfaces
de Damager et Repairer (majorité des cas)
� Petite explication …
145Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Coloration Syntaxique
� L’objet IPresentationReconciler coordonne le Damager et le
Repairer
� Le Damager indique au IPresentationReconciler qu’une
portion du texte a été modifiée
� La portion du texte est transférée au Repairer pour que des
styles y soient appliqués
� L’utilisation de la classe DefaultDamagerRepairer traite à la
fois les demandes de Damager et les besoins de Repairer
� Le SourceViewerConfiguration fournit la méthode suivante
� IPresentationReconciler getPresentationReconciler() : retourne un
IPresentationReconciler pour un éditeur de texte donné
146Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Coloration Syntaxique
IPresentationReconciler
install(…)
getDamager(…)
getRepairer(…)
� Cartes des classes concernant un PresentationReconciler
IPresentationDamager
getDamageRegion(…)IPresentationRepairer
createPresentation(…)
Dépendance
Héritage
PresentationReconciler
setDamager(…)
setRepairer(…)
DefaultDamageRepairer
…
ITokenScanner
nextToken(…) Etudiée dans la suite
147Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Coloration Syntaxique
� Exemple : Définir un IPresentationReconciler dans un
SourceViewerConfigurationpublic class PassMemSourceViewerConfiguration extend s TextSourceViewerConfiguration {
private ISharedTextColors refSharedTextColors;
public PassMemSourceViewerConfiguration(ISharedText Colors pSharedTextColors,IPreferenceStore preferenceStore) {
super(preferenceStore);
this.refSharedTextColors = pSharedTextColors;}
public IPresentationReconciler getPresentationReconc iler(ISourceViewer sourceViewer) {
DefaultDamagerRepairer commentDamagerRepairer= new D efaultDamagerRepairer(getRuleBasedScanner());
PresentationReconciler reconciler= new PresentationR econciler();reconciler.setDamager(commentDamagerRepairer, IDocu ment.DEFAULT_CONTENT_TYPE);reconciler.setRepairer(commentDamagerRepairer, IDoc ument.DEFAULT_CONTENT_TYPE);
return reconciler;}
... // La suite dans les prochains transparents}
PassMemSourceViewerConfiguration.javadu projet PassMemEditorStep1
Scanner étudiépar la suite
148Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Coloration Syntaxique
� Un DefaultDamagerRepairer s’appuie sur un scanner
(ITokenScanner) pour déterminer les styles à appliquer
� Un objet ITokenScanner décompose un texte sur des
intervalles donnés et retourne des Tokens
� Un token contient le style à appliquer sur la portion du texte
� Pour déterminer quel token doit être retourné, l’objet
ITokenScanner s’appuie sur des règles Rules
� Résumé
� Un objet ITokenScanner est associé à un ensemble de Rules
� Chaque règle est associée à un Token
� Si la règle est respectée, le Token est retourné
149Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Coloration Syntaxique
� Cartes des classes concernant Scanner et Rules
IToken
getData()
Token ITokenScanner
nextToken()
getTokenOffset()
getTokenLength()
ICharacterScanner
read()
unread()
IRule
evaluate()
RuleBasedScanner
setRules()
setDefaultReturnToken()
RuleBasedPartitionScanner
setRules()
IPredicatRule
getSuccessToken()
WhitespaceRule
NumberRule
WordRule
SingleLineRule
MultiLineRule
WordPatternRule
IWordDetector
isWordStart()
isWordPart()
IWhitespaceDetector
isWhitespace()
Dépendance
Héritage
150Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Coloration Syntaxique
� Pour chaque règle (voir dans la suite) définie, un Token est
retourné
� Un Token est défini par l’interface IToken et une implémen-
tation par défaut est fournie par Token
� Un objet Token contient un type et un objet
� Différentes valeurs de types (indéfini, espace, fin de fichier
ou autre)
� L’objet contenu peut de type arbitraire
� String : pour donner des valeurs de partitions (voir plus tard)
� TextAttribute(Color for, Color back, int style, Font font) : défini le
style d’un texte
151Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Coloration Syntaxique
� Exemple : Construction d’objets de type Token
public class PassMemSourceViewerConfiguration extend s TextSourceViewerConfiguration {
private ITokenScanner getRuleBasedScanner() {Token tokenDefault = new Token(new TextAttribute(
refSharedTextColors.getColor(new RGB(0, 0, 255)), nu ll, SWT.ITALIC | SWT.BOLD));Token keywordToken = new Token(new TextAttribute(
refSharedTextColors.getColor(new RGB(0, 0, 0)), null , SWT.BOLD));Token tokenComment1 = new Token(new TextAttribute(
refSharedTextColors.getColor(new RGB(192, 192, 192)) , refSharedTextColors.getColor(new RGB(20, 20, 20)), S WT.ITALIC));
Token tokenComment2 = new Token(new TextAttribute(refSharedTextColors.getColor(new RGB(140, 140, 140)) , refharedTextColors.getColor(new RGB(200, 200, 200)), SWT.ITALIC));
...}
}
PassMemSourceViewerConfiguration.javadu projet PassMemEditorStep1
Plusieurs Token ont été définis
152Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Coloration Syntaxique / WordRule
� Dans la plupart des cas, la mise en place de la coloration
syntaxique consiste à lister un ensemble de mots clés
� L’objet WordRule est utilisé dans les cas suivants
� Colorer des mots complets
� Colorer des mots qui débutent par un caractère donné
� Un objet WordRule est construit à partir
� IWordDetector : vérifie les caractères valides en début de mot et les
caractères faisant parti d’un mot (détailler dans la suite)
� Un Token par défaut utilisé par les mots non reconnus
� Un objet WordRule permet d’ajouter des mots clés via
� void addWord(String word, Token currentToken) : ajoute un mot et
un Token qui doit être retourné si le mot est découvert
153Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Coloration Syntaxique / WordRule
� L’objet IWordDetector permet de vérifier les caractères
valides en début de mot et tout au long du mot à l’aide des
méthodes
� boolean isWordStart(char c) : true s’il s’agit d’un caractère valide en
début de mot
� boolean isWordPart(char c) : true s’il s’agit d’un caractère valide en
cours de mot
� A chaque saisi d’un caractère WordRule demande à son
objet IWordDetector si le mot en cours est valide
� Si le caractère de début est découvert deux tokens peuvent
être retournés
� Le Token par défaut, puisque le mot n’est pas encore identifié
� Le Token associé au mot clé
154Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Coloration Syntaxique / WordRule
� Exemple : Définition de règles à partir de WordRule
public class PassMemSourceViewerConfiguration extend s TextSourceViewerConfiguration {
private static final class WordDetector implements I WordDetector {public boolean isWordPart(char c) {
return Character.isLetter(c);}
public boolean isWordStart(char c) {return c == '@';
}}
private ITokenScanner getRuleBasedScanner() {...
// Keywords.String[] keywords = {"@entry", "@login", "@password ", "@url", "@note", "@creationDate", "@expirationDa te"};
WordRule keywordRule= new WordRule(new WordDetector() , tokenDefault);
for(String current : keywords) {keywordRule.addWord(current, keywordToken);
}
...}
}
PassMemSourceViewerConfiguration.javadu projet PassMemEditorStep1
Utilisation du Tokenpar défaut
La liste des mots clés àdécouvrir
Un mot clé contient uniquement des lettres et commence par @
155Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Coloration Syntaxique / WordRule
� Exemple (suite) : Définition de règles à partir de WordRule
Les mots clés ont étédécouverts
Mot clé en cours d’être découvert (utilisation du Token
par défaut)
Ce mot n’a pas été découvert
156Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Col. Synt. / (Single|Multi)LineRule
� La règle SingleLineRule définit une règle qui est satisfaite
� Débute avec une chaîne de caractères donnée
� Se termine avec une chaîne de caractères donnée
� Se termine avec la ligne
� Un caractère d’échappement est autorisé pour exprimer que
la ligne suivante est considérée comme le prolongement de
la ligne en cours
� Constructeur de SingleLineRule
� SingleLineRule(String startSeq, String endSeq, IToken tok, char esc)
� EndOfLineRule est une variante de SingleLineRule àl’exception que la règle se termine avec la ligne
� MultiLineRule propose les mêmes fonctionnalités que SingleLineRule sur plusieurs lignes
157Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Col. Synt. / (Single|Multi)LineRule
� Exemple : Définition de règles à partir de SingleLineRule et
MultiLineRulepublic class PassMemSourceViewerConfiguration extend s TextSourceViewerConfiguration {
private ITokenScanner getRuleBasedScanner() {...
// Comment.EndOfLineRule commentRule1 = new EndOfLineRule("//", tokenComment,'c');MultiLineRule commentRule2 = new MultiLineRule("/*", "*/", tokenComment, (char)0, true);...
}}
PassMemSourceViewerConfiguration.javadu projet PassMemEditorStep1
Les commentaires sont identifiés
158Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Scanner
� Un Scanner s’appuie sur les règles pour déterminer quel
Token doit être retourné
� Un Scanner est défini par l’interface ITokenScanner
� La classe RuleBasedScanner est une implémentation par
défaut et permet de retourner des règles
� void setRules(IRule[] rules) : permet d’ajouter une liste de règles
� Dans la suite nous utiliserons un scanner pour gérer les
partitions via la classe RuleBasedPartitionScanner
159Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Scanner
� Exemple : Mise en place d’un scanner
public class PassMemSourceViewerConfiguration extend s TextSourceViewerConfiguration {
private ITokenScanner getRuleBasedScanner() {...
RuleBasedScanner passMemScanner= new RuleBasedScanne r();
// Keywords.String[] keywords = {"@entry", "@login", "@password ", "@url", "@note", "@creationDate", "@expirationDa te"};
WordRule keywordRule= new WordRule(new WordDetector() , tokenDefault);
for(String current : keywords) {keywordRule.addWord(current, keywordToken);
}
// Comment.EndOfLineRule commentRule1 = new EndOfLineRule("//", tokenComment1,'c');MultiLineRule commentRule2 = new MultiLineRule("/*", "*/", tokenComment2, (char)0, true);
IRule[] rules= {keywordRule, commentRule1, commentR ule2};passMemScanner.setRules(rules);
return passMemScanner;}
}
PassMemSourceViewerConfiguration.javadu projet PassMemEditorStep1
Trois règles ont été définies et associées au scanner
160Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Modèle de texte
� Un texte est défini par un modèle de présentation IDocument
et est affiché via un ITextViewer
� Un modèle de présentation est associé à un type de fichier
(défini par IEditorInput) par un objet IDocumentProvider
� Un IDocumentProvider effectue donc la relation entre un
objet IEditorInput et un objet IDocumentProvider
� Responsabilités d’un IDocumentProvider
� Création du modèle d’annotation IAnnotationModel (markers, …)
� Création et gestion du modèle de présentation IDocument
� …
161Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Modèle de texte
� Exemple : Associer un IDocumentProvider par programme
public class PassMemEditorPart extends AbstractDecor atedTextEditor {public PassMemEditorPart() {
super();
this.setSourceViewerConfiguration(new PassMemSourceViewerConfiguration(getSharedColor s(), getPreferenceStore()));
this.setDocumentProvider(new PassDocumentProvider()) ;}
}
PassMemEditorPart.javadu projet PassMemEditorStep2
Possibilité également d’associer un IDocumentProvider par déclaration. Deux solutions différentes ne sert à
rien de les combiner
162Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Modèle de texte
� Exemple : Associer un IDocumentProvider par extension
plugin.xmldu projet PassMemEditorStep2
Pour tous les fichiers dont l’extension est .pass le IDocumentProvider est associé au
modèle de présentation
163Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Modèle de texte
� Cartes des classes concernant le modèle de présentation
IDocument
get()
getLength()
getLine…()
getDocumentPartitioner()
getLine…()
addDocumentListener()
AbstractDocument
getStore()
getTracker()
Dépendance
Héritage
IDocumentExtension3
getPartition()
getContentType()
IDocumentPartitioner
connect()
getPartition()
getContentType()
Document
IDocumentListener
documentAboutToBeChanged()
documentChanged()
Position
getOffset()
getLength()
isDeleted()
IDocumentProvider
getAnnotationModel(Object element)
getDocument(Object element)
connect(Object element)
IAnnotationModel
addAnnotation(Annotation, Position)
getAnnotationIterator()
IEditorInput
Modèle de Présentation
Modèle du domaine
164Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Partition
� Les partitions (décrites par ITypedRegion) permettent de
diviser un document en plusieurs régions
� Chaque région est associée à un type de contenu
� Un partitionneur (décrit par IDocumentPartitioner) est
responsable de la division du document en plusieurs régions
� L’avantage des partitions est de pouvoir découper le
document selon les différents langages exploités
� Exemple d’un fichier Java
� Code Java
� Commentaire
� Annotation, …
165Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Partition
� Le partitionnement assure une mise à jour permanente de
chaque partition lorsque le texte est modifié
� Le IDocumentProvider assure que le partitionnement est
installé
� void setupDocument(Object ele, IDocument doc) : méthode à utiliser
pour configurer le partitionnement
� Le SourceViewerConfiguration a besoin de connaître le
partitionnement et les types de contenu définis
� String getConfiguredDocumentPartitioning(ISourceViewer sv) :
retourne le partitionnement pour cette configuration
� String[] getConfiguredContentTypes(ISourceViewer sv) : retourne les
types de contenu définis dans le partitionnement
166Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Partition
� Exemple : Ajouter un partitionnement
Type par défaut
Type commentaire
Deux types de contenu sont utilisés un type par défaut et un type
commentaire
12
1
2
1
2
167Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Partition
� Exemple (suite) : Ajouter un partitionnement public class PassDocumentProvider extends FileDocume ntProvider {
public static final String PASS_PARTITIONING = "ecl ipse.workbench.passmemeditor.passpartitioning";
public static final String PASS_CODE = IDocument.DE FAULT_CONTENT_TYPE;public static final String PASS_COMMENT= "PASS_COMM ENT";
private static final String[] CONTENT_TYPES= {PASS_CODE,PASS_COMMENT
};
protected void setupDocument(Object element, IDocume nt document) {if (document instanceof IDocumentExtension3) {
IDocumentExtension3 ext = (IDocumentExtension3)docu ment;
IDocumentPartitioner partitioner = createPassPartitio ner();ext.setDocumentPartitioner(PASS_PARTITIONING, parti tioner);partitioner.connect(document);
}}
private IDocumentPartitioner createPassPartitioner() {EndOfLineRule commentRule1 = new EndOfLineRule("//", new Token(PASS_COMMENT),'c');MultiLineRule commentRule2 = new MultiLineRule("/*", "*/", new Token(PASS_COMMENT), (char)0, true);
IPredicateRule[] rules= { commentRule1, commentRule 2 };
RuleBasedPartitionScanner scanner= new RuleBasedPart itionScanner();scanner.setPredicateRules(rules);
return new FastPartitioner(scanner, CONTENT_TYPES);}
}
PassDocumentProvider.javadu projet PassMemEditorStep2
Identifiant du partitionnement
Associer au document le partitionneur
Connecter le partitionneurau document
Utilisation d’un scanneur spécifique pour les partitions
168Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Partition
� Exemple (suite) : Ajouter un partitionnement
public class PassMemSourceViewerConfiguration extend s TextSourceViewerConfiguration {
public String getConfiguredDocumentPartitioning(ISo urceViewer sourceViewer) {return PassDocumentProvider.PASS_PARTITIONING;
}
public String[] getConfiguredContentTypes(ISourceVi ewer sourceViewer) {return new String[] { PassDocumentProvider.PASS_COD E, PassDocumentProvider.PASS_COMMENT };
}
public IPresentationReconciler getPresentationReconc iler(ISourceViewer sourceViewer) {PresentationReconciler reconciler = new Presentation Reconciler();reconciler.setDocumentPartitioning(getConfiguredDoc umentPartitioning(sourceViewer));
// Partition for other.DefaultDamagerRepairer defaultDamagerRepairer = new D efaultDamagerRepairer(getDefaultRuleBasedScanner()) ;
reconciler.setDamager(defaultDamagerRepairer, PassD ocumentProvider.PASS_CODE);reconciler.setRepairer(defaultDamagerRepairer, Pass DocumentProvider.PASS_CODE);
// Partition for Comment.DefaultDamagerRepairer commentDamagerRepairer = new D efaultDamagerRepairer(getCommentRuleBasedScanner()) ;
reconciler.setDamager(commentDamagerRepairer, PassD ocumentProvider.PASS_COMMENT);reconciler.setRepairer(commentDamagerRepairer, Pass DocumentProvider.PASS_COMMENT);
return reconciler;}
... // Suite dans le prochain transparent}
PassMemSourceViewerConfiguration.javadu projet PassMemEditorStep2
Utilisation de deux scanneurs distinctes
169Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Partition
� Exemple (suite) : Ajouter un partitionnement
public class PassMemSourceViewerConfiguration extend s TextSourceViewerConfiguration {
private ITokenScanner getCommentRuleBasedScanner() {Token tokenComment2 = new Token(new TextAttribute(re fSharedTextColors
.getColor(new RGB(140, 140, 140)), null, SWT.ITALIC) );
RuleBasedScanner commentScanner = new RuleBasedScanne r();commentScanner.setDefaultReturnToken(tokenComment2) ;return commentScanner;
}
private ITokenScanner getDefaultRuleBasedScanner() {Token tokenDefault = new Token(new TextAttribute(refS haredTextColors
.getColor(new RGB(0, 0, 255)), null, SWT.ITALIC | SW T.BOLD));Token keywordToken = new Token(new TextAttribute(refS haredTextColors
.getColor(new RGB(0, 0, 0)), null, SWT.BOLD));
RuleBasedScanner passMemScanner = new RuleBasedScanne r();
// Keywords.String[] keywords = { "@entry", "@login", "@passwor d", "@url", "@note",
"@creationDate", "@expirationDate" };WordRule keywordRule = new WordRule(new WordDetector() , tokenDefault);
for (String current : keywords) {keywordRule.addWord(current, keywordToken);
}
IRule[] rules = { keywordRule };passMemScanner.setRules(rules);
return passMemScanner;}
}
Utilisation des règles définies pour le type PASS_COMMENT
Principe déjà évoqué sans l’utilisation de partitionnement
PassMemSourceViewerConfiguration.javadu projet PassMemEditorStep2
170Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� L’assistant de contenu (Content Assist) permet de fournir
une aide contextuelle à l’utilisateur
� Selon ce contexte (texte en sélection, fraction de mot, …)
l’assistant peut proposer des solutions adaptées
� Fournir des patrons de texte (voir plus tard)
� Compléter un mot qui était en cours de saisie
� Enrichir une portion de texte sélectionné
� …
� L’aide contextuelle est disponible via la combinaison de
touche Ctrl + Espace ou en fonction d’un certain délai
d’attente
171Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� Exemple : Intégration d’un assistant de contenu
Complétion de mots clés (àdéfinir l’algorithme qui liste les propositions de la complétion)
Pour chaque mot clésélectionné, une information
peut être donnée
L’assistant de contenu est ouvert
172Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� L’objet SourceViewerConfiguration est utilisé pour déclarer
l’assistant de contenu
� IContentAssistant getContentAssistant(ISourceViewer p) : définit
l’objet IContentAssistant employé pour activer l’assistant de contenu
� Un objet IContentAssistant est utilisé pour configurer
l’assistant de contenu
� Pour chaque type de contenu un objet IContentAssistProcessor doit
être défini
� Paramètres liés à l’affichage (couleur, délai d’apparition, …)
� Des écouteurs liés au déroulement de l’assistant (début, fin, sélection
de l’élément proposé par l’assistant)
173Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� Exemple (suite) : Intégration d’un assistant de contenu
public class PassMemSourceViewerConfiguration extend s TextSourceViewerConfiguration {...public IContentAssistant getContentAssistant(final IS ourceViewer sourceViewer) {
ContentAssistant assistant= new ContentAssistant();assistant.setDocumentPartitioning(getConfiguredDocu mentPartitioning(sourceViewer));
assistant.setContentAssistProcessor(new HippiePropos alProcessor(), PassDocumentProvider.PASS_COMMENT);
PassMemCompletionProcessor processor = new PassMemCo mpletionProcessor();assistant.setContentAssistProcessor(processor, Pass DocumentProvider.PASS_CODE);assistant.setContentAssistProcessor(processor,IDocu ment.DEFAULT_CONTENT_TYPE);
// Paramètres du ContentAssistant étudiés plus tard
return assistant;}
}
PassMemSourceViewerConfiguration.javadu projet PassMemEditorStep3
Un IContentAssistProcessor prédéfini dont le fonctionnement est d’identifier des mots qui
existent déjà dans les éditeurs ouverts
Défini notre propre IContentAssistProcessor(voir dans la suite)
174Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� Pour que l’assistant de contenu puisse démarrer lors de
l’utilisation du raccourci CTRL + Espace il faut créer une
action de type ContentAssistAction
� Exemple : activer l’assistant de contenu via CTRL + Espace
public class PassMemEditorPart extends AbstractDecor atedTextEditor {public PassMemEditorPart() {
super();
this.setSourceViewerConfiguration(new PassMemSourceViewerConfiguration(getSharedColor s(), getPreferenceStore()));
this.setDocumentProvider(new PassDocumentProvider()) ;
}
protected void createActions() {super.createActions();
ContentAssistAction action= new ContentAssistAction( PassMemEditorMessages.getBundle(), "contentAssist." , this);action.setActionDefinitionId(ITextEditorActionDefin itionIds.CONTENT_ASSIST_PROPOSALS);setAction("ContentAssist", action);
}}
PassMemEditorPart.javadu projet PassMemEditorStep3
175Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� Exemple : Ajouter les actions d’assistant de contenu dans le
menu principalpublic class PassMemEditorActionContributor extends TextEditorActionContributor {
private RetargetTextEditorAction fContentAssist;
public PassMemEditorActionContributor() {fContentAssist = new RetargetTextEditorAction(PassMe mEditorMessages.getBundle(), "contentAssist."); fContentAssist.setActionDefinitionId(ITextEditorAct ionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
}
public void contributeToMenu(IMenuManager menu) {super.contributeToMenu(menu);
IMenuManager editMenu = menu.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT );
if (editMenu != null) {editMenu.appendToGroup(IWorkbenchActionConstants.MB _ADDITIONS,
fContentAssist);}
}
public void setActiveEditor(IEditorPart part) {super.setActiveEditor(part);if (part instanceof ITextEditor) {
fContentAssist.setAction(getAction((ITextEditor) pa rt, "ContentAssist"));}
}}
PassMemEditorActionContributor.javadu projet PassMemEditorStep3
176Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� Un objet IContentAsssistProcessor fournit un mécanisme
pour gérer la complétion de texte (ICompletionProposal)
� Différentes méthodes pour la gérer cette complétion
� ICompletionProposal[] computeCompletionProposals(ITextViewer
viewer, int offset) : pour définir les propositions de complétion
� char[] getCompletionProposalAutoActivationCharacters() : les
caractères qui déclenchent la complétion
� Dans la méthode computeCompletionProposals, il faut fournir
un algorithme qui établie une liste de propositions suivant le
contexte courant
� @e fournira les propositions @entry et @expirationDate
177Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� Exemple (suite) : Intégration d’un assistant de contenu
public class PassMemCompletionProcessor implements I ContentAssistProcessor {
public char[] getCompletionProposalAutoActivationCh aracters() {return new char[] {'@'};
}
public ICompletionProposal[] computeCompletionPropo sals(ITextViewer viewer, int offset) {IDocument document = viewer.getDocument();int currOffset = offset - 1;
String currWord = "";try {
char currChar;while (currOffset > 0 && !Character.isWhitespace(cur rChar = document.getChar(currOffset))) {
currWord = currChar + currWord;currOffset--;
}
List<String> currentSuggests = buildSuggests(currWor d);ICompletionProposal[] proposals = null;if (currentSuggests.size() > 0) {
proposals = buildProposals(currentSuggests, currWor d, offset - currWord.length());}return proposals;
} catch (BadLocationException e) {e.printStackTrace();return null;
}}
PassMemCompletionProcessor.javadu projet PassMemEditorStep3
Extrait à partir du mot courant la liste des propositions
Identifie le mot en cours de saisie
Construit à partir des propositions des objets ICompletionProposal
Le caractère @ qui permet de déclencher l’assistant de contenu
178Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� Exemple (suite) : Intégration d’un assistant de contenu
public class PassMemCompletionProcessor implements I ContentAssistProcessor {
private List<String> buildSuggests(String word) {List<String> current = new ArrayList<String>();for (int i = 0 ; i < PassMemSourceViewerConfiguratio n.KEYWORDS.length ; i++) {
if (PassMemSourceViewerConfiguration.KEYWORDS[i].st artsWith(word)) {current.add(PassMemSourceViewerConfiguration.KEYWOR DS[i]);
}}return current;
}
private ICompletionProposal[] buildProposals(List<S tring> suggestions, String replacedWord, int offset) {ICompletionProposal[] proposals = new ICompletionPr oposal[suggestions.size()];int index = 0;for (Iterator<String> i = suggestions.iterator(); i .hasNext();) {
String currSuggestion = (String) i.next();IContextInformation contextInfo = new ContextInformat ion(null, currSuggestion);proposals[index] = new CompletionProposal(currSugge stion, offset,
replacedWord.length(), currSuggestion.length(), null, currSuggestion, contextInfo,currSuggestion);
index++;}return proposals;
}...
}
PassMemCompletionProcessor.javadu projet PassMemEditorStep3
Retourne une information contextuelle par rapport à la
proposition en cours de sélection
179Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� Pour afficher l’information contextuelle (partie droite) il faut
configurer l’objet IContentAssistant de cette façon
� Optionnellement si vous souhaitez paramétrer l’affichage des
informations contextuelles
� Redéfinir la méthode getInformationControlCreator() qui indiquera la
présentation à utiliser
� Fournir un IInformationPresenter qui précisera comment afficher les
informations contextuelles
assistant.setInformationControlCreator(getInformati onControlCreator(sourceViewer));
public IInformationControlCreator getInformationCont rolCreator(ISourceViewer sourceViewer) {return new IInformationControlCreator() {
public IInformationControl createInformationControl( Shell parent) {return new DefaultInformationControl(parent, presen ter);
}};
}
180Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� Exemple : Modifier l’apparence de l’information contextuellepublic class PassMemSourceViewerConfiguration extend s TextSourceViewerConfiguration {
private DefaultInformationControl.IInformationPrese nter presenter;
public PassMemSourceViewerConfiguration(ISharedText Colors pSharedTextColors, IPreferenceStore preference Store) {super(preferenceStore);this.refSharedTextColors = pSharedTextColors;
presenter = new DefaultInformationControl.IInformat ionPresenter() {public String updatePresentation(Display display, St ring infoText,
TextPresentation presentation, int maxWidth, int maxHe ight) {StyleRange range = new StyleRange(0, 1, null, refSha redTextColors.getColor(new
RGB(220,220,220)), SWT.BOLD | SWT.ITALIC);presentation.addStyleRange(range);return infoText;
}};
}
public IContentAssistant getContentAssistant(final IS ourceViewer sourceViewer) {...assistant.setInformationControlCreator(getInformati onControlCreator(sourceViewer));
}
public IInformationControlCreator getInformationCont rolCreator(ISourceViewer sourceViewer) {return new IInformationControlCreator() {
public IInformationControl createInformationControl( Shell parent) {return new DefaultInformationControl(parent, presen ter);
}};
}...
}
PassMemSourceViewerConfiguration.javadu projet PassMemEditorStep3
Le premier caractère est un gras et sa couleur de fond est modifiée
181Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� Un objet IContentAsssistProcessor fournit également un
traitement pour afficher de l’information contextuelle
� L’information peut être affichée à différents cas
� A la suite d’un caractère donné (principe étudié précédemment)
� Une fois une proposition de complétion insérée dans le document
� Différentes méthodes liées à la gestion de l’information
� IContextInformation[] computeContextInformation(ITextViewer
viewer, int offset) : pour définir les informations susceptibles d’être
affichées
� char[] getContextInformationAutoActivationCharacters() : les
caractères qui déclenchent l’affichage des informations
� IContextInformationValidator getContextInformationValidator() :
défini un objet qui établie si une information doit être affichée ou pas
à la suite de la complétion
1
2
182Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� Exemple : Afficher de l’information contextuelle à la suite
d’un caractère donné
public class PassMemCompletionProcessor implements I ContentAssistProcessor {
public char[] getContextInformationAutoActivationCh aracters() {return new char[] {'?'};
}
public IContextInformation[] computeContextInformat ion(ITextViewer viewer, int offset) {ContextInformation[] contextInfos = new ContextInfor mation[PassMemSourceViewerConfiguration.KEYWORDS.le ngth];
for (int i = 0; i < contextInfos.length; i++) {contextInfos[i] = new ContextInformation(null, Pass MemSourceViewerConfiguration.KEYWORDS[i]);
}
return contextInfos;}
...}
PassMemCompletionProcessor.javadu projet PassMemEditorStep3
Affichage de l’information à la
suite du caractère -
183Editors - M. Baron - Page
keul
keul
.blo
gspo
t.comEditeur et le texte : Assistant de contenu
� Exemple : Afficher de l’information contextuelle une fois une
proposition de complétion insérée dans le documentpublic class PassMemCompletionProcessor implements I ContentAssistProcessor {
...
private ICompletionProposal[] buildProposals(List<S tring> suggestions, String replacedWord, int offset) {...for (Iterator<String> i = suggestions.iterator(); i .hasNext();) {
...IContextInformation contextInfo = new ContextInformat ion(null, currSuggestion);...
}return proposals;
}
public IContextInformation[] computeContextInformat ion(ITextViewer viewer, int offset) {ContextInformation[] contextInfos = new ContextInfor mation[PassMemSourceViewerConfiguration.KEYWORDS.le ngth];
for (int i = 0; i < contextInfos.length; i++) {contextInfos[i] = new ContextInformation(null, Pass MemSourceViewerConfiguration.KEYWORDS[i]);
}
return contextInfos;}
public IContextInformationValidator getContextInform ationValidator() {return new ContextInformationValidator(this);
}}
Le validator compare que l’information utilisée par la complétion est disponible
dans computeContextInformation
PassMemCompletionProcessor.javadu projet PassMemEditorStep3
184Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
� Un template permet à partir de l’assistant de contenu
d’insérer un squelette de texte
� Le contenu du texte inséré peut être complété
par des propositions de valeurs de mots
� Un template s’utilise suivant un contexte
� Une boucle while ne peut être insérée que dans du code Java
� La définition d’un template est réalisée soit
� au travers du point d’extension org.eclipse.ui.editors.template
� programmatiquement via Template et TemplateContexteType
� Privilégier la solution via extension permet
� de s’assurer d’une meilleure portabilité du code
� d’enrichir les templates existants
185Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
� Processus d’utilisation des templates depuis l’assistant de
contenu
� En fonction de la position sur
le document, identification du type
de contexte (ContextType)
� En fonction de l’identification de contexte,
récupération des templates
disponibles (TemplateStore)
� Proposition des templates à l’utilisateur
� Insertion du template dans le document
� Proposition des valeurs pour les différentes
variables (TemplateContexte)
Editeur et le texte : Template
1
2
3
4
5
186Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
� Exemple : Définir un template par extension
Création d’une extension àpartir du point d’extension
org.eclipse.ui.editors.templates
187Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
� Exemple (suite) : Définir un template par extension
plugin.xmldu projet PassMemEditorStep4
Définir un élément template
contextTypeId permet de préciser l’identifiant du contexte (définir plus tard)
188Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
� Exemple (suite) : Définir un template par extension
plugin.xmldu projet PassMemEditorStep4
Définition de l’identifiant contextTypeId en utilisant une classe prédéfinie de la plateforme
189Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
� Exemple (suite) : Définir un template par extension
plugin.xmldu projet PassMemEditorStep4
Pour le template proposé est défini le texte àinsérer. Les textes ${…} désignent des variables
190Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
� Exemple (suite) : Définir un template par extension
plugin.xmldu projet PassMemEditorStep4
Pour la variable entry ces valeurs seront déterminés par un objet de type
TemplateVariableResolver
L’élément resolver nomméentryValues permet d’obtenir la liste des valeurs à proposer pour
la variable entry
191Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
� Les classes de type TemplateVariableResolver permettent
d’énumérer les valeurs possibles pour une variable
� Ces valeurs sont proposées après l’insertion du template
dans le document courant
� Pour retourner ces valeurs possibilité de redéfinir certaines
méthodes
� String[] resolveAll(TemplateContext context) : un ensemble de
valeurs à proposer
� String resolve(TemplateContext context) : une seule valeur à
proposer
� Un objet de type TemplateContext donne accès à l’ensemble
des variables et aux valeurs associées
192Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
� Exemple (suite) : Définir un template par extension
public class TemplateEntryVariableResolver extends T emplateVariableResolver {
protected String[] resolveAll(TemplateContext contex t) {return new String[] {"twitter", "gmail"};
}}
TemplateEntryVariableResolver.javadu projet PassMemEditorStep4
193Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
� La classe TemplateCompletionProcessor est un objet
IContentAssistProcessor dédié à la gestion de l’insertion de
template via l’assistant de contenu
� Différentes méthodes qui permettent de respecter le
processus d’insertion de template
� TemplateContextType getContextType(ITextViewer viewer, IRegion
region) : retourne le type de contexte en fonction de la position sur le
document
� Template[] getTemplates(String contextTypeId) : retourne une liste
de templates en fonction de l’identifiant de type de contexte
� Image getImage(Template template) : retourne une image associé à
un template
194Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
� Exemple : Intégrer un template défini par extension dans un
assistant de contenu
public class PassMemTemplateProcessor extends Templa teCompletionProcessor {
protected TemplateContextType getContextType(ITextVi ewer viewer,IRegion region) {
return Activator.getDefault().getContextTypeRegistr y().getContextType(Activator.PASS_MEM_TEMPLATE_CONT EXT);}
protected Image getImage(Template template) {return Activator.getImage("template");
}
protected Template[] getTemplates(String contextType Id) {ContributionTemplateStore templateStore= Activator.g etDefault().getTemplateStore();
return templateStore.getTemplates(contextTypeId);}
}
PassMemTemplateProcessor.java du projet PassMemEditorStep4
195Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
public class Activator extends AbstractUIPlugin {private ContributionTemplateStore fTemplateStore;private ContributionContextTypeRegistry fRegistry;
public static final String PASS_MEM_TEMPLATE_CONTEX T= "eclipse.workbench.passmemeditorstep4.templateco ntextid";
private static final String TEMPLATES_PREFERENCE_KE Y= "templates";
public ContributionTemplateStore getTemplateStore() {if (fTemplateStore == null) {
fTemplateStore= new ContributionTemplateStore(getCo ntextTypeRegistry(), getPreferenceStore(), TEMPLATES_PREFERENCE_KEY);
try {fTemplateStore.load();
} catch (IOException x) {x.printStackTrace();
}}return fTemplateStore;
}
public ContributionContextTypeRegistry getContextTyp eRegistry() {if (fRegistry == null) {
fRegistry= new ContributionContextTypeRegistry();fRegistry.addContextType(PASS_MEM_TEMPLATE_CONTEXT) ;
}return fRegistry;
}...
}
� Exemple (suite) : Intégrer un template défini par extension
dans un assistant de contenu
Activator.java du projet PassMemEditorStep4
196Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
� Exemple : Combiner une intégration d’un template défini par
extension et une proposition de mots cléspublic class PassMemTemplateProcessorBis extends Tem plateCompletionProcessor {
public ICompletionProposal[] computeCompletionPropo sals(ITextViewer viewer, int offset) {final ICompletionProposal[] computeCompletionPropos als = super.computeCompletionProposals(viewer, offse t);
IDocument document = viewer.getDocument();int currOffset = offset - 1;String currWord = "";try {
char currChar;while (currOffset > 0 && !Character.isWhitespace(cur rChar = document.getChar(currOffset))) {
currWord = currChar + currWord;currOffset--;
}
List<String> currentSuggests = buildSuggests(currWor d);ICompletionProposal[] proposals = null;if (currentSuggests.size() > 0) {
proposals = buildProposals(currentSuggests, currWor d, offset - currWord.length());}
ICompletionProposal[] copyOf = Arrays.copyOf(compute CompletionProposals,computeCompletionProposals.length + proposals.length );
for (int i = 0 ; i < proposals.length ; i++) {copyOf[i+computeCompletionProposals.length] = propo sals[i];
}return copyOf;
} catch (BadLocationException e) {return null;
}}}
PassMemTemplateProcessorBis.javadu projet PassMemEditorStep4
Récupère les objets ICompletionProposalliés aux templates
197Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Template
� Exemple : Intégrer un template défini programmatiquement
dans un assistant de contenupublic class PassMemTemplateProcessorBisBis implemen ts IContentAssistProcessor {
private static final String CONTEXT_ID= "eclipse.wo rkbench.passmemeditorstep4.templatecontextid"; private TemplateContextType fContextType= new Templa teContextType(
CONTEXT_ID, "Default Template Context");
private Template fTemplate= new Template("PassTemplate", // name"This Template inserts all keywords", // descriptio nCONTEXT_ID,"@entry\n${entry}\n@login\n@password\n@url\n@note\n @creationDate\n@expirationDate", // patternfalse);
public ICompletionProposal[] computeCompletionPropo sals(ITextViewer viewer, int offset) {...final ICompletionProposal[] tabTemplates = new IComp letionProposal[1];TemplateContext context= new DocumentTemplateContext (fContextType, document, offset, 0);Region region= new Region(offset, 0);TemplateProposal proposal= new TemplateProposal(fTem plate, context, region, Activator.getImage("templat e"));tabTemplates[0] = proposal;...
final ICompletionProposal[] copyOf = Arrays.copyOf(t abTemplates, tabTemplates.length + proposals.length) ;
for (int i = 0 ; i < proposals.length ; i++) {copyOf[i+tabTemplates.length] = proposals[i];
}
return copyOf;} catch (BadLocationException e) {
e.printStackTrace();return null;
}}...
}
PassMemTemplateProcessorBisBis.javadu projet PassMemEditorStep4
198Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Mise à jour
� Lors de la modification du document d’un éditeur il peut être
intéressant
� D’identifier des erreurs (orthographiques) et de les ajouter dans le
modèle d’annotation
� De construire un modèle (utilisé pour l’affichage dans Outline)
� L’écoute des changements ne peut être réalisé dans le
Thread-UI car la mise à jour est trop couteuse
� Le Reconciler fournit un Thread pour ce type de tâche
� Traitement déclenché quand l’utilisateur a fini de saisir du texte
� Interruptible quand l’utilisateur re-saisit du texte
� Autorise la synchonisation
� Implémentation par défaut : MonoReconciler
� La stratégie de traitement est définit dans IReconcilingStrategy
199Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Mise à jour
� Un objet IReconcilingStrategy est utilisé pour définir les
traitements de mise à jour d’un document
� Différentes méthodes à implémenter
� void setDocument(IDocument document) : pour connaître le
document sur lequel la stratégie s’applique
� void reconcile(IRegion partition) : déclenché à chaque modification
du document et permet de connaître la région impactée
� Dans la méthode reconcile, différents traitements peuvent
être réalisés
� Utilisation d’un moteur de vérification orthographique (Spelling
Checking) et création d’annotation SpellingAnnotation
� Utilisation d’un parser pour identifier les éléments saisis dans le texte
puis utiliser le résultat du parser pour l’affichage dans Outline
200Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Outline
� Exemple : Création d’une vue Outline personnalisée
Le contenu de l’éditeur est analysé puis affiché dans la vue Outline
La vue Outline affiche une liste d’éléments. Un élément sélectionnépermet de mettre en surbrillance la
portion sur l’éditeur
201Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Outline
� Exemple (suite) : Création d’une vue Outline personnalisée
public class PassMemSourceViewerConfiguration extend s TextSourceViewerConfiguration {
public PassMemSourceViewerConfiguration(ISharedText Colors pSharedTextColors, IPreferenceStore preference Store, PassMemEditorPart pEditor) {
super(preferenceStore);this.refSharedTextColors = pSharedTextColors;this.refEditor = pEditor;
}
public IReconciler getReconciler(ISourceViewer source Viewer) {IReconcilingStrategy strategy = new PassMemReconcile Strategy(sourceViewer, refEditor);return new MonoReconciler(strategy, false);
}
...}
PassMemSourceViewerConfiguration.javadu projet PassMemEditorStep5
202Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Outline
� Exemple (suite) : Création d’une vue Outline personnalisée
public class PassMemReconcileStrategy implements IRe concilingStrategy, IReconcilingStrategyExtension {
private IDocument fDocument;
private final PassMemEditorPart fEditor;
public PassMemReconcileStrategy(ISourceViewer pSourc eViewer, PassMemEditorPart refEditorPart) {fEditor = refEditorPart;
}
public void reconcile(IRegion partition) {PassMemModel value = new PassMemParser().parse(fDocu ment);this.fEditor.setPassMemModel(value);
}
public void reconcile(DirtyRegion dirtyRegion, IRegi on subRegion) {}
public void setDocument(IDocument document) {fDocument = document;
}
public void initialReconcile() {reconcile(new Region(0, fDocument.getLength()));
}
public void setProgressMonitor(IProgressMonitor moni tor) { }
}
PassMemReconcileStrategy.java du projet PassMemEditorStep5
Utilisation d’un parser qui analyse le document de
l’éditeur
203Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Outline
� Exemple (suite) : Création d’une vue Outline personnaliséepublic final class PassMemParser {
private IDocument fDocument;private int fLine;private int fLineCount;
public PassMemModel parse(IDocument document) {try {
fDocument= document;fLine= 0;fLineCount= fDocument.getNumberOfLines();return parsePassMem();
} catch (BadLocationException e) {return null;
}}
private PassMemModel parsePassMem() throws BadLocati onException {PassMemModel refModel = new PassMemModel();while (fLine < fLineCount) {
IRegion region= fDocument.getLineInformation(fLine);String text= fDocument.get(region.getOffset(), regi on.getLength());
for (int i = 0 ; i < PassMemSourceViewerConfiguratio n.KEYWORDS.length ; i++) {if (text.startsWith(PassMemSourceViewerConfiguratio n.KEYWORDS[i])) {
refModel.addKeywordPosition(buildKeywordPosition(te xt, PassMemSourceViewerConfiguration.KEYWORDS[i], regio n.getOffset(), refModel));
}}fLine++;
}return refModel;
}
private KeywordPosition buildKeywordPosition(String t ext, String keyword, int offset, PassMemModel pModel) {KeywordPosition refKeywordPosition = new KeywordPosit ion(keyword, offset, text.length());return refKeywordPosition;
}}
PassMemParser.java du projet PassMemEditorStep5
A chaque découverte d’un mot clé, ajout dans un
modèle
204Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Outline
� Exemple (suite) : Création d’une vue Outline personnaliséepublic class PassMemModel {
private List<KeywordPosition> keywordPositions;
public PassMemModel() {keywordPositions = new ArrayList<KeywordPosition>();
}
public void addKeywordPosition(KeywordPosition curre nt) {this.keywordPositions.add(current);
}
public List<KeywordPosition> getKeywordPositions() {return this.keywordPositions;
}}
public class KeywordPosition {private String key;private int offset;private int length;
public KeywordPosition(String key, int offset, int len gth) {this.key = key;this.offset = offset;this.length = length;
}
public String getKey() {return key;
}
public int getOffSetPosition() {return offset;
}
public int getLength() {return length;
}}
PassMemModel.java du projet PassMemEditorStep5
KeywordPosition.java du projet PassMemEditorStep5
205Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : Outline
� Exemple (suite) : Création d’une vue Outline personnaliséepublic class PassMemEditorPart extends AbstractDecor atedTextEditor {
private PassMemOutlinePage fOutlinePage;private PassMemModel fPassMemModel;...public Object getAdapter(Class required) {
if (IContentOutlinePage.class.equals(required)) {if (fOutlinePage == null)
createOutlinePage();return fOutlinePage;
}return super.getAdapter(required);
}
private void createOutlinePage() {fOutlinePage = new PassMemOutlinePage(this);fOutlinePage.addSelectionChangedListener(new ISelect ionChangedListener() {
public void selectionChanged(SelectionChangedEvent e vent) {ISelection selection= event.getSelection();if (selection instanceof IStructuredSelection) {
IStructuredSelection ss= (IStructuredSelection) sele ction;Object element= ss.getFirstElement();if (element instanceof KeywordPosition) {
KeywordPosition re= (KeywordPosition) element;selectAndReveal(re.getOffSetPosition(), re.getLengt h());
}}
}});
}
public void setPassMemModel(PassMemModel passMemMode l) {fPassMemModel = passMemModel;if (fOutlinePage != null)
fOutlinePage.updatePassMemModel(passMemModel);}public PassMemModel getPassMemModel() {
return fPassMemModel;}
}
PassMemEditorPart.java du projet PassMemEditorStep5
206Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Editeur et le texte : il reste …
� De nombreuses améliorations peuvent encore être apportées
à un composant TextEditor
� Folding : plier / déplier une zone de texte
� Spell Checking : vérification orthographique en exploitant un moteur
de vérification et un dictionnaire de mots
� Hyperlinks : ajouter des liens hypertextes dans du texte
Des informations complémentaires sur la mise en place de ces
améliorations peuvent être trouvées
www.eclipse.org/eclipse/platform-text/development/dev.html
207Editors - M. Baron - Page
keul
keul
.blo
gspo
t.com
Bilan
� Ce support de cours a exploré les différentes APIs de la
plateforme Eclipse pour la mise en place d’éditeur
� Deux types d’éditeurs sont à distinguer
� Ceux qui fournissent un composant TextEditor pour la manipulation de texte
� Ceux qui fournissent des IHMs formulaires qui facilitent l’édition des éditeurs à base de texte (complémentaires aux premiers)
� Les éditeurs permettent donc de manipuler des DSL (Domain
Specific Language)
� Des projets du domaine de la modélisation tentent de faire
abstraction de l’apprentissage des APIs et focalisent essentiellement sur la modélisation (Xtext)
� Dans le chapitre lié à la modélisation, nous reviendrons sur
ces technologies
Recommended