Construction d'éditeurs avec la plateforme Eclipse

6 751 vues

Publié le

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

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

Aucun téléchargement
Vues
Nombre de vues
6 751
Sur SlideShare
0
Issues des intégrations
0
Intégrations
1 138
Actions
Partages
0
Téléchargements
366
Commentaires
0
J’aime
2
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Construction d'éditeurs avec la plateforme Eclipse

  1. 1. Développement de clients riches : Plateforme Eclipse Mickaël BARON - 2010 mailto:baron.mickael@gmail.com ou mailto:baron@ensma.fr @mickaelbaron Chapitre 3 : Conception de plug-ins Workbench : Editors
  2. 2. 2Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Creative Commons Contrat Paternité Partage des Conditions Initiales à l'Identique 2.0 France http://creativecommons.org/licenses/by-sa/2.0/fr Licence
  3. 3. 3Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron † 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
  4. 4. 4Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workbench 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
  5. 5. 5Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  6. 6. 6Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  7. 7. 7Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  8. 8. 8Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  9. 9. 9Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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, …)
  10. 10. 10Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Gé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
  11. 11. 11Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Gé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
  12. 12. 12Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  13. 13. 13Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Généralités : Carte des classes de l’éditeur † Principales interfaces et classes pour la gestion des éditeurs IWorkbenchPage 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
  14. 14. 14Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  15. 15. 15Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  16. 16. 16Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  17. 17. 17Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  18. 18. 18Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  19. 19. 19Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 »
  20. 20. 20Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 !!!!
  21. 21. 21Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  22. 22. 22Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Construction d’un éditeur externe par extension † Exemple (suite) : Création d’un éditeur externe via launcher public class SimpleEditorEditorLauncher implements IEditorLauncher { public void open(IPath file) { final Program findProgram = Program.findProgram("txt"); boolean result = findProgram.execute(file.toFile().getAbsolutePath()); System.out.println("External Editor has been launched ? : " + 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
  23. 23. 23Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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)
  24. 24. 24Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  25. 25. 25Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 ?
  26. 26. 26Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  27. 27. 27Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  28. 28. 28Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  29. 29. 29Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  30. 30. 30Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  31. 31. 31Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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.getWorkbench().getEditorRegistry(); L’interface IEditorRegistry est détaillée dans la suite
  32. 32. 32Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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)
  33. 33. 33Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  34. 34. 34Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Registre des éditeurs † Exemple (suite) : Modifier et accéder à l’éditeur par défaut public class LauncherEditorCommandHandler extends AbstractHandler { public Object execute(ExecutionEvent event) throws ExecutionException { final IEditorRegistry editorRegistry = PlatformUI.getWorkbench().getEditorRegistry(); IEditorDescriptor defaultEditor = editorRegistry.getDefaultEditor("*.html"); if (defaultEditor != null) { System.out.println(defaultEditor.getLabel()); } editorRegistry.setDefaultEditor("*.html","eclipse.workbench.EditorExample.SimpleExternalEditorWithLauncherId"); defaultEditor = editorRegistry.getDefaultEditor("*.html"); if (defaultEditor != null) { System.out.println(defaultEditor.getLabel()); } return null; } } LauncherEditorCommandHandler.java du 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
  35. 35. 35Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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)
  36. 36. 36Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Registre des éditeurs † Exemple : Interroger le registre des éditeurs public class EditorRegistryCommandHandler extends AbstractHandler { @Override public Object execute(ExecutionEvent event) throws ExecutionException { final IEditorRegistry editorRegistry = PlatformUI.getWorkbench().getEditorRegistry(); final IEditorDescriptor[] editors = editorRegistry.getEditors("*.txt"); for (IEditorDescriptor iEditorDescriptor : editors) { System.out.println(iEditorDescriptor.getLabel()); } return null; } } EditorRegistryCommandHandler.java du Projet EditorExample Récupère les éditeurs associés à ce type d’extension Deux éditeurs sont disponibles
  37. 37. 37Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie † Un objet IWorkbenchPage permet de gérer le cycle de vie des instances d’une classe 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
  38. 38. 38Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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)
  39. 39. 39Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  40. 40. 40Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie : openEditor … † Exemple : Ouvrir un éditeur pour un fichier présent dans le Workspace public class OpenEditorCommandHandler extends AbstractHandler { @Override public Object execute(ExecutionEvent event) throws ExecutionException { final IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); ISelectionService selService = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService(); final ISelection selection = selService.getSelection(); if (selection instanceof TreeSelection) { TreeSelection currentFile = (TreeSelection)selection; final IFile firstElement = (IFile)currentFile.getFirstElement(); IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(firstElement.getName()); try { activePage.openEditor(new FileEditorInput(firstElement), 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
  41. 41. 41Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 …
  42. 42. 42Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie : openEditor … † Exemple : Ouvrir un éditeur pour un fichier non présent dans le Workspace (solution 1) public class OpenExternalEditorCommandHandler extends AbstractHandler { public Object execute(ExecutionEvent event) throws ExecutionException { try { IWorkspace ws = ResourcesPlugin.getWorkspace(); IProject project = ws.getRoot().getProject("SimpleEditor"); if (!project.exists()) project.create(null); if (!project.isOpen()) project.open(null); final IWorkbenchWindow activeWorkbenchWindow = PlatformUI.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.getActivePage(); if (page != null) IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(file.getName()); page.openEditor(new FileEditorInput(file), desc.getId()); } catch(Exception e) { e.printStackTrace(); } return null; } } OpenExternalEditorCommandHandler.java du 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
  43. 43. 43Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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.log dans le répertoire du workspace
  44. 44. 44Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie : openEditor … † Exemple : Ouvrir un éditeur pour un fichier non présent dans le Workspace (solution 2) public class OpenExternalEditorWithEFSCommandHandler extends AbstractHandler { public Object execute(ExecutionEvent event) throws ExecutionException { final IWorkbenchWindow activeWorkbenchWindow = PlatformUI.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().getStore(URI.create(name)); if (!fileStore.fetchInfo().isDirectory() && fileStore.fetchInfo().exists()) { IWorkbenchPage page= activeWorkbenchWindow.getActivePage(); try { IDE.openEditorOnFileStore(page, fileStore); } catch (PartInitException e) { e.printStackTrace(); } } return null; } } OpenExternalEditorWithEFCCommandHandler.java du 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
  45. 45. 45Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  46. 46. 46Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie : openEditor … † Exemple (suite) : Ouvrir un éditeur pour un contenu qui n’est pas un fichier public class OpenEditorWithNoFileCommandHandler extends 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.java du projet EditorExample
  47. 47. 47Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie : openEditor … † Exemple (suite) : Ouvrir un éditeur pour un contenu qui n’est pas un fichier public class OpenEditorWithNoFileCommandHandler extends 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 null; } } ... // Suite dans le prochain transparent OpenEditorWithNoFileCommandHandler.java du projet EditorExample
  48. 48. 48Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie : openEditor … † Exemple (suite) : Ouvrir un éditeur pour un contenu qui n’est pas un fichier public class OpenEditorWithNoFileCommandHandler extends AbstractHandler { public Object execute(ExecutionEvent event) throws ExecutionException { IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); 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.DefaultTextEditor"); } catch (PartInitException e) { e.printStackTrace(); } } return null; } OpenEditorWithNoFileCommandHandler.java du projet EditorExample Contenu à afficher Définition d’un IEditorInput dédié à la gestion d’une chaîne de caractères Ouverture de l’éditeur qui gère l’édition et l’affichage du texte
  49. 49. 49Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie : openEditor … † Exemple : Ouvrir plusieurs instances d’un même éditeur Plusieurs instances d’un même éditeur
  50. 50. 50Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie : openEditor … † Exemple (suite) : Ouvrir plusieurs instances d’un même éditeur public class OpenSeveralEditorInstances extends AbstractHandler { public Object execute(ExecutionEvent event) throws ExecutionException { final IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); ISelectionService selService = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService(); final ISelection selection = selService.getSelection(); if (selection instanceof TreeSelection) { TreeSelection currentFile = (TreeSelection)selection; final IFile firstElement = (IFile)currentFile.getFirstElement(); IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(firstElement.getName()); try { activePage.openEditor( new FileEditorInput(firstElement), desc.getId(), true, IWorkbenchPage.MATCH_NONE); } catch (PartInitException e) { e.printStackTrace(); } } return null; } } OpenSeveralEditorInstances.java du projet EditorExample Précise qu’il n’y a pas de comparaison entre les instances d’éditeur
  51. 51. 51Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  52. 52. 52Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  53. 53. 53Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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é
  54. 54. 54Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle 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
  55. 55. 55Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  56. 56. 56Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  57. 57. 57Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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)
  58. 58. 58Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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é
  59. 59. 59Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie : show et hide † Exemple : Cacher et ouvrir un éditeur public class HideEditorCommandHandler extends AbstractHandler { public Object execute(ExecutionEvent event) throws ExecutionException { final IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); final IWorkbenchPartReference reference = activePage.getReference(activePage.getActiveEditor()); if (reference instanceof IEditorReference) { activePage.hideEditor((IEditorReference)reference); Activator.getDefault().getHiddenEditors().add((IEditorReference)reference); } return null; } } HideEditorCommandHandler.java du 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
  60. 60. 60Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Cycle de vie : show et hide † Exemple (suite) : Cacher et ouvrir un éditeur public class ShowEditorCommandHandler extends AbstractHandler { public Object execute(ExecutionEvent event) throws ExecutionException { final IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); final List<IEditorReference> hiddenEditors = Activator.getDefault().getHiddenEditors(); if (!hiddenEditors.isEmpty()) { activePage.showEditor(hiddenEditors.get(0)); hiddenEditors.remove(0); } return null; } } ShowEditorCommandHandler.java du projet EditorExample public class ShowAllHiddenEditorsHandler extends AbstractHandler { public Object execute(ExecutionEvent event) throws ExecutionException { final IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); WorkbenchPage activeWorkbencPage = (WorkbenchPage)activePage; final List<IEditorReference> hiddenEditors = Activator.getDefault().getHiddenEditors(); hiddenEditors.clear(); activeWorkbencPage.resetHiddenEditors(); return null; } } ShowAllHiddenEditorsHandler.java du 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
  61. 61. 61Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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, …)
  62. 62. 62Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  63. 63. 63Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  64. 64. 64Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron MultiPageEditorPart † Exemple (suite) : Un éditeur multiple avec trois pages public class MultiPageEditor extends MultiPageEditorPart implements IResourceChangeListener { public MultiPageEditor() { super(); ResourcesPlugin.getWorkspace().addResourceChangeListener(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 creating 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.java du 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
  65. 65. 65Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron MultiPageEditorPart † Exemple (suite) : Un éditeur multiple avec trois pages public class MultiPageEditor extends MultiPageEditorPart 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 IResourceChangeEvent event) { if(event.getType() == IResourceChangeEvent.PRE_CLOSE){ Display.getDefault().asyncExec(new Runnable(){ public void run(){ IWorkbenchPage[] pages = getSite().getWorkbenchWindow().getPages(); for (int i = 0; i<pages.length; i++){ if(((FileEditorInput)editor.getEditorInput()).getFile() .getProject().equals(event.getResource())) { IEditorPart editorPart = pages[i].findEditor(editor.getEditorInput()); pages[i].closeEditor(editorPart,true); } } } }); } } public void dispose() { ResourcesPlugin.getWorkspace().removeResourceChangeListener(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.java du projet MultiPageEditorExample
  66. 66. 66Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  67. 67. 67Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  68. 68. 68Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Diviser un éditeur † Exemple (suite) : Diviser programmatiquement la zone de l’éditeur public class CreateSplitEditorHandler extends AbstractHandler { public Object execute(ExecutionEvent event) throws ExecutionException { IWorkbenchPage workbenchPage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); IWorkbenchPart part = workbenchPage.getActivePart(); PartPane partPane = ((PartSite) part.getSite()).getPane(); LayoutPart layoutPart = partPane.getPart(); IEditorReference[] editorReferences = workbenchPage.getEditorReferences(); if (editorReferences.length > 1) { PartPane currentEditorPartPane = ((PartSite) workbenchPage.getActiveEditor().getSite()).getPane(); EditorSashContainer editorSashContainer = null; ILayoutContainer rootLayoutContainer = layoutPart.getContainer(); if (rootLayoutContainer instanceof LayoutPart) { ILayoutContainer editorSashLayoutContainer = ((LayoutPart) rootLayoutContainer).getContainer(); if (editorSashLayoutContainer instanceof EditorSashContainer) { editorSashContainer = ((EditorSashContainer) editorSashLayoutContainer); } } PartStack newPart = createStack(editorSashContainer); editorSashContainer.stack(currentEditorPartPane, newPart); if (rootLayoutContainer instanceof LayoutPart) { ILayoutContainer cont = ((LayoutPart) rootLayoutContainer).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.java du projet SplitEditorExample
  69. 69. 69Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Diviser un éditeur † Exemple (suite) : Diviser programmatiquement la zone de l’éditeur public class CreateSplitEditorHandler extends AbstractHandler { ... private PartStack createStack(EditorSashContainer editorSashContainer) { WorkbenchPage workPage = (WorkbenchPage)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); EditorStack newWorkbook = EditorStack.newEditorWorkbook(editorSashContainer, workbenchPage); return newWorkbook; } } CreateSplitEditorHandler.java du projet SplitEditorExample Une grande partie des APIs utilisées sont définies comme Internal
  70. 70. 70Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  71. 71. 71Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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, …
  72. 72. 72Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Ecouteurs (Part Listeners) † Exemple : Ecouter les changements d’un EditorPart public class LifeCycleEditor extends EditorPart { public void createPartControl(Composite parent) { ... IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); activePage.addPartListener(new IPartListener2() { @Override public void partActivated(IWorkbenchPartReference partRef) { IWorkbenchPart part = partRef.getPart(false); if (LifeCycleEditor.this == part) { System.out.println(".partActivated()"); } } @Override public void partBroughtToTop(IWorkbenchPartReference partRef) { IWorkbenchPart part = partRef.getPart(false); if (LifeCycleEditor.this == part) { System.out.println(".partBroughtToTop()"); } } @Override public void partClosed(IWorkbenchPartReference partRef) { IWorkbenchPart part = partRef.getPart(false); if (LifeCycleEditor.this == part) { System.out.println(".partClosed()"); } } ... } } } LifeCycleEditor.java du projet EditorExample
  73. 73. 73Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  74. 74. 74Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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)
  75. 75. 75Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  76. 76. 76Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  77. 77. 77Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Editeur et les commandes † Exemple (suite) : Contribuer au menu, à la barre d’outils et à la barre d’états public class EditorWithCommandActionBarContributor extends EditorActionBarContributor { public void contributeToMenu(IMenuManager menuManager) { super.contributeToMenu(menuManager); CommandContributionItemParameter commandParameter = new CommandContributionItemParameter( PlatformUI.getWorkbench(), "contributionitem", "eclipse.workbench.editorexample.SimpleCommandId", CommandContributionItem.STYLE_PUSH); IContributionItem ref = new CommandContributionItem(commandParameter); IMenuManager menu = new MenuManager("Simple Editor"); menuManager.prependToGroup(IWorkbenchActionConstants.MB_ADDITIONS, menu); menuManager.findMenuUsingPath("File").add(ref); } public void contributeToStatusLine(IStatusLineManager statusLineManager) { CommandContributionItemParameter commandParameter = new CommandContributionItemParameter( PlatformUI.getWorkbench(), "contributionitem", "eclipse.workbench.editoractionbarcontributorexample.samplecommandid", CommandContributionItem.STYLE_PUSH); IContributionItem ref = new CommandContributionItem(commandParameter); statusLineManager.add(ref); } public void contributeToToolBar(IToolBarManager toolBarManager) { CommandContributionItemParameter commandParameter = new CommandContributionItemParameter( PlatformUI.getWorkbench(), "contributionitem", "eclipse.workbench.editoractionbarcontributorexample.samplecommandid", CommandContributionItem.STYLE_PUSH); IContributionItem ref = new CommandContributionItem(commandParameter); toolBarManager.add(ref); } } EditorWithCommandActionBarContributor.java du projet EditorActionBarContributor
  78. 78. 78Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  79. 79. 79Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 messages Informations liées aux plugins Ressources de type dossier et fichier
  80. 80. 80Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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() { @Override public void widgetSelected(SelectionEvent e) { Location instanceLoc = Platform.getInstanceLocation(); System.out.println(instanceLoc.getURL().toString()); } }); ... } } WorkspaceViewPart.java du projet WorkspaceExample
  81. 81. 81Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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.launch du projet WorkspaceExample
  82. 82. 82Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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)
  83. 83. 83Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  84. 84. 84Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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.getWorkspace().getRoot();
  85. 85. 85Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Resource / IWorkspaceRoot † Exemple : Lister l’ensemble des projets d’un Workspace public class WorkspaceViewPart extends ViewPart { public void createPartControl(Composite parent) { ... Button projects = new Button(parent, SWT.FLAT); projects.setText("Workspace location ..."); projects.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); final IProject[] projects = root.getProjects(); for (IProject iProject : projects) { System.out.println(iProject.getName()); } } }); ... } } WorkspaceViewPart.java du projet WorkspaceExample
  86. 86. 86Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  87. 87. 87Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Resource / IProject † Exemple : Manipulation de ressource IProject public class WorkspaceViewPart extends ViewPart { public void createPartControl(Composite parent) { ... Button createProject = new Button(parent, SWT.FLAT); createProject.setText("Create new Project ..."); createProject.addSelectionListener(new SelectionAdapter() { 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.getDescription(); 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.java du projet WorkspaceExample
  88. 88. 88Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  89. 89. 89Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  90. 90. 90Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Resource / IFolder † Exemple : Manipulation de ressources IFolder et IFile public 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 SelectionAdapter() { 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 from File A".getBytes()), true, null); IFile fileB = folderA.getFile("File B.txt"); fileB.create(new ByteArrayInputStream("HelloWorld from File B".getBytes()), true, null); System.out.println(fileA.getFullPath()); } catch (CoreException e1) { e1.printStackTrace(); } } }); ... } } WorkspaceViewPart.java du projet WorkspaceExample
  91. 91. 91Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  92. 92. 92Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  93. 93. 93Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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(parent, SWT.FLAT); saveSessionPropertiesButton.setText("Save Session Properties ..."); saveSessionPropertiesButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); final IProject project5 = root.getProject(projectName); try { if (!project5.exists()) { project5.create(null); project5.open(null); } project5.setSessionProperty(new QualifiedName("session_test", "en"), "test"); } catch (Exception e1) { e1.printStackTrace(); } } }); ... } } PropertiesViewPart.java du projet WorkspaceExample Enregistrement d’une propriété « session_test » dans la session d’un projet Si le projet est fermé, workspace rechargé ou application redémarrée, la propriété est perdue
  94. 94. 94Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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(parent, SWT.FLAT); loadSessionPropertiesButton.setText("Load Session Properties ..."); loadSessionPropertiesButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); final IProject project5 = root.getProject(projectName); try { final Map sessionProperties = project5.getSessionProperties(); System.out.println(sessionProperties.get(new QualifiedName("session_test", "en"))); } catch (CoreException e1) { e1.printStackTrace(); } } }); ... } } PropertiesViewPart.java du projet WorkspaceExample Chargement de la propriété « session_test »
  95. 95. 95Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Resource / Properties † Exemple : Manipulation des propriétés persistances public class PropertiesViewPart extends ViewPart { public void createPartControl(Composite parent) { ... Button savePersistentPropertiesButton = new Button(parent, SWT.FLAT); savePersistentPropertiesButton.setText("Save Persistence Properties ..."); savePersistentPropertiesButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); final IProject project5 = root.getProject(projectName); try { if (!project5.exists()) { project5.create(null); } project5.setPersistentProperty(new QualifiedName("persistent_test", "en"), "test"); } catch (CoreException e1) { e1.printStackTrace(); } } }); } } PropertiesViewPart.java du projet WorkspaceExample Enregistrement d’une propriété « persistent_test » dans un projet en mode persistant Si le projet est fermé, workspace rechargé ou application redémarrée, la propriété reste présente
  96. 96. 96Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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(parent, SWT.FLAT); loadPersistentPropertiesButton.setText("Load Persistence Properties ..."); loadPersistentPropertiesButton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); final IProject project5 = root.getProject(projectName); try { final Map persistentProperties = project5.getPersistentProperties(); System.out.println(persistentProperties.get(new QualifiedName("persistent_test", "en"))); } catch (CoreException e1) { e1.printStackTrace(); } } }); } } PropertiesViewPart.java du projet WorkspaceExample Chargement de la propriété « persistent_test »
  97. 97. 97Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  98. 98. 98Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  99. 99. 99Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  100. 100. 100Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  101. 101. 101Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  102. 102. 102Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Resource / Markers † Exemple (suite) : Création d’une annotation de type Task public class MarkersViewPart extends ViewPart { public void createPartControl(Composite parent) { ... Button createTasks = new Button(parent, SWT.FLAT); createTasks.setText("Create Tasks ..."); createTasks.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); final IProject projectMarkers= root.getProject("Project Markers"); try { if (!projectMarkers.exists()) { projectMarkers.create(null); projectMarkers.open(null); } final IFile file = projectMarkers.getFile("file"); if (!file.exists()) { file.create(new ByteArrayInputStream("HelloWorldn This is a text for Markers example".getBytes()), IResource.NONE, null); } IMarker createTaskMarker = file.createMarker(IMarker.TASK); createTaskMarker.setAttribute(IMarker.MESSAGE, "Sample Task message"); createTaskMarker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_LOW); createTaskMarker.setAttribute(IMarker.USER_EDITABLE, false); createTaskMarker.setAttribute(IMarker.LINE_NUMBER, 2); } catch (Exception e1) { e1.printStackTrace(); } } }); } } MarkersViewPart.java du projet WorkspaceExample
  103. 103. 103Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  104. 104. 104Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 SelectionAdapter() { public void widgetSelected(SelectionEvent e) { ... try { IMarker createErrorProblemMarker = file.createMarker(IMarker.PROBLEM); createErrorProblemMarker.setAttribute(IMarker.MESSAGE, "Sample Error Problem message"); createErrorProblemMarker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); createErrorProblemMarker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_LOW); createErrorProblemMarker.setAttribute(IMarker.LINE_NUMBER, 2); IMarker createWarningProblemMarker = file.createMarker(IMarker.PROBLEM); createWarningProblemMarker.setAttribute(IMarker.MESSAGE, "Sample Warning Problem message"); createWarningProblemMarker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING); createWarningProblemMarker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); createWarningProblemMarker.setAttribute(IMarker.LINE_NUMBER, 2); } catch (Exception e1) { e1.printStackTrace(); } } }); } } MarkersViewPart.java du projet WorkspaceExample
  105. 105. 105Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Resource / Markers † Exemple : Création d’une annotation de type Bookmark Depuis l’éditeur, une annotation précise qu’un favori est associé à la ligne 2 Les favoris sont visibles dans la vue Bookmarks
  106. 106. 106Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 SelectionAdapter() { public void widgetSelected(SelectionEvent e) { ... try { IMarker createErrorProblemMarker = file.createMarker(IMarker.BOOKMARK); createErrorProblemMarker.setAttribute(IMarker.MESSAGE, "Sample Bookmark message"); createErrorProblemMarker.setAttribute(IMarker.LINE_NUMBER, 2); } catch (Exception e1) { e1.printStackTrace(); } } }); } } MarkersViewPart.java du projet WorkspaceExample † Exemple (suite) : Création d’une annotation de type Bookmark
  107. 107. 107Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  108. 108. 108Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  109. 109. 109Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  110. 110. 110Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  111. 111. 111Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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
  112. 112. 112Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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.xml du projet BuilderExample
  113. 113. 113Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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.xml du projet BuilderExample
  114. 114. 114Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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.xml du projet BuilderExample Classe de type IncrementalProjectBuilder
  115. 115. 115Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Builder / Définir son Builder † Associer des paramètres au builder Deux paramètres sont associés au builder plugin.xml du projet BuilderExample
  116. 116. 116Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Builder / Définir son Builder † Classe du builder personnalisée public class CustomIncrementalProjectBuilder extends IncrementalProjectBuilder { protected IProject[] build(int kind, Map args, IProgressMonitor 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 monitor) 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.java du projet BuilderExample Selon le type de builder des 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
  117. 117. 117Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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 IResourceDeltaVisitor { public boolean visit(IResourceDelta res) { System.out.println("Incremental " + res.getKind() + " " + res.getResource().getName()); return true; } } protected void clean(IProgressMonitor monitor) throws CoreException { final IFolder folder = this.getProject().getFolder("My Bin"); if (folder.exists()) { folder.delete(true, null); } } } CustomIncrementalProjectBuilder.java du 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
  118. 118. 118Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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 SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); final IProject projectBuilder = root.getProject("Project 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("HelloWorldn This is text for Builder examples".getBytes()), IResource.NONE, null); } ... BuilderViewPart.java du projet BuilderExample Création d’un projet et d’un fichier
  119. 119. 119Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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.BuilderExample.samplebuilderid"; IProjectDescription desc = projectBuilder.getDescription(); ICommand[] commands = desc.getBuildSpec(); // Add builder to project ICommand command = desc.newCommand(); command.setBuilderName(BUILDER_ID); ICommand[] newCommands = new ICommand[commands.length + 1]; // Add it before other builders. System.arraycopy(commands, 0, newCommands, 1, commands.length); newCommands[0] = command; desc.setBuildSpec(newCommands); projectBuilder.setDescription(desc, null); } catch (Exception e1) { e1.printStackTrace(); } } }); } } BuilderViewPart.java du projet BuilderExample Identifiant du builder = identifiant plugin + identifiant extension du builder
  120. 120. 120Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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 »
  121. 121. 121Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Builder / Définir son Builder † Associer un builder personnalisé à un projet (suite) Le contenu du fichier file1 a été mis à jour Deux ressources ont été modifiées
  122. 122. 122Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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)
  123. 123. 123Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  124. 124. 124Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  125. 125. 125Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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
  126. 126. 126Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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.xml du projet NatureExample
  127. 127. 127Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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 SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); final IProject projectNature = root.getProject("Project 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("HelloWorldn This is text for Nature examples".getBytes()), IResource.NONE, null); } ... } } NatureViewPart.java du projet NatureExample Création d’un projet et d’un fichier
  128. 128. 128Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Nature / Définir sa nature † Associer une nature à un projet (suite) public class NatureViewPart extends ViewPart { public void createPartControl(Composite parent) { ... IProjectDescription description = projectNature.getDescription(); String[] natures = description.getNatureIds(); String[] newNatures = new String[natures.length + 1]; System.arraycopy(natures, 0, newNatures, 0, natures.length); newNatures[natures.length] = "eclipse.workbench.NatureExample.samplenatureid"; description.setNatureIds(newNatures); projectNature.setDescription(description, null); } catch (Exception e1) { e1.printStackTrace(); } } }); } } NatureViewPart.java du projet NatureExample Identifiant de la nature = identifiant plugin + identifiant extension de la nature
  129. 129. 129Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Nature / Définir sa nature † Création de la classe de la nature Définition de la classe où sera codé le traitement de la configuration de la nature vis-à-vis des projets plugin.xml du projet NatureExample Classe de type IProjectNature
  130. 130. 130Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : 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)
  131. 131. 131Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Nature / Définir sa nature † Exemple : Associer un builder à une nature public class CustomProjectNature implements IProjectNature { private IProject current; public void configure() throws CoreException { final String BUILDER_ID = "eclipse.workbench.BuilderExample.samplebuilderid"; IProjectDescription desc = current.getDescription(); ICommand[] commands = desc.getBuildSpec(); // Add builder to project ICommand command = desc.newCommand(); command.setBuilderName(BUILDER_ID); ICommand[] newCommands = new ICommand[commands.length + 1]; // Add it before other builders. System.arraycopy(commands, 0, newCommands, 1, commands.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.java du projet NatureExample IProjectDescription sert à préciser les natures à utiliser sur un projet
  132. 132. 132Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Nature / Définir sa nature † Exemple : Définir l’icône d’un projet en fonction de la nature plugin.xml du projet NatureExample Création de l’extension org.eclipse.ui.ide.projectNatureImages Préciser l’identifiant de la nature puis l’image à afficher Nécessite que le plugin org.eclipse.ui.ide soit ajouté comme dépendance
  133. 133. 133Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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
  134. 134. 134Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron Workspace : Nature / Contraintes † Exemple : Définir une contrainte requires-nature plugin.xml du 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
  135. 135. 135Editors - M. Baron - Page keulkeul.blogspot.com@mickaelbaron 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 SelectionAdapter() { public void widgetSelected(SelectionEvent e) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); final IProject projectNature = root.getProject("Project 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("HelloWorldn This is text for Nature examples".getBytes()), IResource.NONE, null); } ... } } NatureViewPart.java du projet NatureExample

×