I plugin possono definire estensioni file specializzate e fornire editor che offrono funzioni di modifica specializzate per questi tipi di file. Durante la modifica o la creazione di una risorsa, è possibile che un plugin debba codificare le risorse per comunicare problemi o altre informazioni all'utente. Per gestire questo tipo di informazioni viene utilizzato il meccanismo degli indicatori di risorsa.
Un indicatore è come un promemoria adesivo attaccato alla risorsa. Sull'indicatore è possibile registrare informazioni relative a un problema (ad esempio la posizione o la gravità) o ad un'attività da eseguire, nonché registrare semplicemente un percorso come avviene con un segnalibro.
Gli utenti possono passare rapidamente al percorso contrassegnato dall'indicatore all'interno di una risorsa. L'interfaccia utente del workbench supporta la presentazione di segnalibri, punti di interruzione, attività e problemi relativi all'editor. Tali indicatori possono anche essere visualizzati come voci nelle viste, ad esempio in quelle delle attività e dei segnalibri.
L'API delle risorse della piattaforma definisce metodi per la creazione di indicatori, per l'impostazione dei relativi valori e per l'estensione della piattaforma con i nuovi tipi di indicatori. Mentre la piattaforma gestisce gli indicatori, i plugin ne controllano la creazione, la rimozione e i valori degli attributi.
Gli indicatori sono oggetti leggeri e di piccole dimensioni. In un singolo progetto possono essere presenti centinaia, persino migliaia di indicatori. Ad esempio il compilatore Java utilizza un indicatore per contrassegnare ogni problema rilevato nel codice di origine.
La piattaforma eliminerà gli indicatori associati alle risorse che vengono eliminate, ma i plugin sono responsabili della rimozione di indicatori non aggiornati e non più applicabili ad una risorsa ancora esistente.
La gestione di un indicatore è simile alla gestione di una risorsa. Gli indicatori sono oggetti handle. È possibile ottenere un handle di indicatore da una risorsa, ma non è possibile determinare se esiste effettivamente finché non si utilizza il protocollo exists() o non si prova ad utilizzarlo. Dopo averne verificato l'esistenza, è possibile eseguire la query di attributi denominati ad esso assegnati.
Gli indicatori sono di proprietà della piattaforma che li gestisce curandone la persistenza e inviando una notifica ai listener quando essi vengono aggiunti, eliminati o modificati. I plugin sono responsabili della creazione degli indicatori necessari, della modifica dei relativi attributi e della rimozione degli stessi indicatori quando questi non sono più necessari.
Gli indicatori non vengono creati direttamente mediante un costruttore ma utilizzando un metodo factory (IResource.createMarker()) sulla risorsa associata.
IMarker marker = file.createMarker(IMarker.TASK);
Per creare un indicatore di ambito globale (non associato ad alcuna risorsa specifica), è possibile utilizzare come risorsa la directory principale dello spazio di lavoro (IWorkspace.getRoot()).
Il codice per l'eliminazione di un indicatore è piuttosto semplice.
try { marker.delete(); } catch (CoreException e) { // Si è verificato un errore }
Quando un indicatore viene eliminato, il relativo oggetto indicatore (handle) assumerà uno stato "non aggiornato". I plugin devono utilizzare il protocollo IMarker.exists() per verificare la validità di un oggetto indicatore.
Gli indicatori possono essere eliminati in batch richiedendo ad una risorsa di eliminare i propri indicatori. Questo metodo è utile quando si rimuovono contemporaneamente molti indicatori oppure quando i riferimenti o gli id dei singoli indicatori non sono disponibili.
int depth = IResource.DEPTH_INFINITE; try { resource.deleteMarkers(IMarker.PROBLEM, true, depth); } catch (CoreException e) { // si è verificato un errore }
Quando si elimina un gruppo di indicatori, si specifica un tipo di indicatore da eliminare, ad esempio IMarker.PROBLEM o null per eliminare tutti gli indicatori. Il secondo argomento indica se si desidera eliminare gli indicatori di sottotipo. I sottotipi verranno illustrati quando si definiranno i nuovi tipi di indicatori. L'argomento depth controlla la profondità dell'eliminazione.
È anche possibile eliminare gli indicatori utilizzando IWorkspace.deleteMarkers(IMarker []).
Dato un indicatore, l'utente può individuarne la risorsa associata, l'id (univoco e relativo a tale risorsa) e il tipo. È anche possibile accedere ad ulteriori informazioni attraverso attributi generici.
Ogni tipo di indicatore dispone di un insieme specifico di attributi definiti dal creatore del tipo di indicatore utilizzando convenzioni di denominazione. L'interfaccia IMarker definisce un insieme di costanti che contengono i nomi degli attributi standard (ed alcuni dei valori previsti) per i tipi di indicatori della piattaforma. Il metodo seguente agisce sugli attributi utilizzando le costanti della piattaforma.
IMarker marker = file.createMarker(IMarker.TASK); if (marker.exists()) { try { marker.setAttribute(IMarker.MESSAGE, "A sample marker message"); marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); } catch (CoreException e) { // È necessario gestire il caso in cui l'indicatore non esiste più } }
Gli attributi vengono generalmente conservati come coppie nome/valore, in cui i nomi sono costituiti da stringhe e un valore può corrispondere a uno qualsiasi dei tipi di valore supportati (boolean, integer, string). La limitazione sui tipi di valore consente alla piattaforma di conservare in modo rapido e semplice gli indicatori.
È possibile eseguire una query delle risorse per individuare i rispettivi indicatori e gli indicatori dei relativi elementi secondari. Ad esempio, la query con profondità infinita eseguita sulla directory principale dello spazio di lavoro considera tutti gli indicatori presenti nello spazio di lavoro.
IMarker[] problems = null; int depth = IResource.DEPTH_INFINITE; try { problems = resource.findMarkers(IMarker.PROBLEM, true, depth); } catch (CoreException e) { // si è verificato un errore }
Il risultato restituito da findMarkers dipende dagli argomenti passati. Nel frammento di codice precedente, si cercavano tutti gli indicatori di tipo PROBLEM presenti nella risorsa e tutti i relativi discendenti diretti e indiretti.
Se si trasmette null come tipo di indicatore, tutti i tipi di indicatore verranno associati alla risorsa. Il secondo argomento specifica se si desidera esaminare gli elementi secondari della risorsa. L'argomento depth controlla la profondità della ricerca quando si intende esaminare gli elementi secondari della risorsa. La profondità può corrispondere a DEPTH_ZERO (solo la risorsa specificata), DEPTH_ONE (la risorsa e tutti gli elementi secondari diretti) oppure DEPTH_INFINITE (la risorsa e tutti i discendenti diretti e indiretti).
Gli indicatori standard della piattaforma (attività, problema e segnalibro) sono persistenti. Ciò significa che il loro stato verrà salvato agli avvii e alle chiusure del workbench. Tuttavia, è possibile rendere transitori gli indicatori di tipo persistente in modo selettivo impostando l'attributo riservato transient su true.
I nuovi tipi di indicatori dichiarati dai plugin non sono persistenti a meno che non siano dichiarati come tali.
I plugin sono in grado di dichiarare i propri tipi di indicatori utilizzando il punto di estensione org.eclipse.core.resources.markers. I tipi di indicatori standard per problemi, attività e segnalibri, vengono dichiarati dalla piattaforma nel tag del plugin delle risorse.
<extension id="problemmarker" point="org.eclipse.core.resources.markers" name="%problemName"> <super type="org.eclipse.core.resources.marker"/> <persistent value="true"/> <attribute name="severity"/> <attribute name="message"/> <attribute name="location"/> </extension> <extension id="taskmarker" point="org.eclipse.core.resources.markers" name="%taskName"> <super type="org.eclipse.core.resources.marker"/> <persistent value="true"/> <attribute name="priority"/> <attribute name="message"/> <attribute name="done"/> <attribute name="userEditable"/> </extension> <extension id="bookmark" point="org.eclipse.core.resources.markers" name="%bookmarkName"> <super type="org.eclipse.core.resources.marker"/> <persistent value="true"/> <attribute name="message"/> <attribute name="location"/> </extension>
I nuovi tipi di indicatori derivano dagli indicatori esistenti utilizzando varie eredità. I nuovi tipi di indicatori ereditano tutti gli attributi dai rispettivi supertipi e aggiungono qualsiasi nuovo attributo definito come parte della dichiarazione. Inoltre, ereditano attributi anche per transitività dai supertipi dei relativi supertipi. Il codice seguente definisce un nuovo tipo di indicatore in un ipotetico plugin com.example.markers.
<extension id="mymarker" point="org.eclipse.core.resources.markers" /> <extension id="myproblem" point="org.eclipse.core.resources.markers"> <super type="org.eclipse.core.resources.problemmarker"/> <super type="com.example.markers.mymarker"/> <attribute name="myAttribute" /> <persistent value="true" /> </extension>
Notare che il tipo org.eclipse.core.resources.problemmarker è in realtà uno dei tipi predefiniti (aka IMarker.PROBLEM).
Il solo aspetto di un supertipo di indicatore che non viene ereditato è l'indicatore di persistenza. Il valore predefinito per la persistenza è false. Pertanto, tutti i tipi di indicatori che devono essere persistenti devono specificare <persistent value="true"/>.
Dopo aver dichiarato il nuovo tipo di indicatore nel file manifest del plugin, è possibile creare istanze del tipo di indicatore com.example.markers.myproblem e impostare o richiamare liberamente l'attributo myAttribute.
La dichiarazione di nuovi attributi consente all'utente di associare i dati agli indicatori che si decide di utilizzare (nelle viste e negli editor). Gli indicatori di un particolare tipo non devono disporre di valori per tutti gli attributi dichiarati. Le dichiarazioni degli attributi sono maggiori per la risoluzione di problemi relativi alla convenzione di denominazione (quindi tutti utilizzano "messaggio" per riferirsi alla descrizione di un indicatore) che per la limitazione del contenuto.
public IMarker createMyMarker(IResource resource) { try { IMarker marker = resource.createMarker("com.example.markers.myproblem"); marker.setAttribute("myAttribute", "MYVALUE"); return marker; } catch (CoreException e) { // È necessario gestire i casi in cui il valore dell'attributo viene rifiutato } }
È possibile eseguire una query dei tipi di indicatori nello stesso modo in cui si esegua una query dei tipi di indicatori della piattaforma. Il metodo riportato di seguito consente di trovare tutti gli indicatori mymarkers associati alla specifica risorsa di destinazione e tutti i relativi discendenti. Si noti che verranno rilevati anche tutti i myproblems dato che, per l'argomento di includeSubtypes, viene definito un valore true.
public IMarker[] findMyMarkers(IResource target) { String type = "com.example.markers.mymarker"; IMarker[] markers = target.findMarkers(type, true, IResource.DEPTH_INFINITE); }