Značkovače prostředků

Víme, že moduly plug-in mohou definovat přípony specializovaných souborů a přidávat editory, které těmto typům souborů zajišťují specializované editační funkce.  V průběhu úprav (nebo sestavení) prostředku bude plug-in možná potřebovat označit prostředky, aby uživatele uvědomil o problémech, či mu sdělil jiné informace. Ke správě tohoto druhu informací se používá mechanizmus značkovačů prostředků.

Značkovač je jako žlutý poznámkový lístek přilepený k prostředku. Na značkovač můžete zaznamenat informace o problému (např. místo, závažnost) nebo o úloze, kterou je třeba provést.  Nebo můžete umístění značkovače prostě zaznamenat jako záložku. 

Uživatelé mohou rychle přeskočit na označené místo v rámci prostředku. Uživatelské rozhraní pracovní plochy podporuje prezentaci záložek, bodů přerušení, úloh a problémů na okraji editoru.  Tyto značkovače lze zobrazit také jako položky v pohledech, například v pohledu úloh nebo záložek.

API prostředků platformy definuje metody pro vytváření značkovačů, nastavení jejich hodnot a rozšiřování platformy novými typy značkovačů. Zatímco platforma značkovače spravuje, jsou to moduly plug-in, které řídí jejich vytváření, odebírání a hodnoty atributů.

Značkovače mají být malými, odlehčenými objekty. V jednom projektu mohou být stovky, ba tisíce značkovačů.  Například kompilátor jazyka Java používá značkovače k označení jednotlivých problémů, které najde ve zdrojovém kódu.

Značkovačů připojených k prostředkům, které byly odstraněny, se zbavuje platforma, ale za odebrání svých zastaralých značkovačů, které již neplatí pro prostředek, jenž dosud existuje, jsou odpovědné moduly plug-in.

Operace se značkovači

Manipulace se značkovačem je podobná jako manipulace s prostředkem. Značkovače jsou objekty popisovačů.  Od prostředku můžete získat popisovač značkovače, ale nevíte, zda značkovač skutečně existuje, dokud nepoužijete protokol exists() nebo se s ní nepokusíte jinak manipulovat.  Jakmile zjistíte, že značkovač existuje, můžete provádět dotazy nad pojmenovanými atributy, které k ní mohou být přiřazeny.

Značkovače jsou vlastněny a spravovány platformou, která se stará o zajištění jejich trvalosti a upozorňování listenerů, když jsou značkovače přidávány, odstraňovány nebo měněny.  Za vytváření všech potřebných značkovačů, změny jejich atributů a jejich odebírání, když již nejsou potřeba, jsou odpovědné moduly plug-in.

Tvorba značkovačů

Značkovače se nevytváří přímo pomocí konstruktoru. Vytváří se pomocí tovární metody (IResource.createMarker()) nad přidruženým prostředkem.

   IMarker marker = file.createMarker(IMarker.TASK);

K vytvoření značkovače, který má globální rozsah (není přiřazen k žádnému konkrétnímu prostředku), můžete jako prostředek využít kořen pracovního prostoru (IWorkspace.getRoot()).

Odstraňování značkovačů

Kód pro odstranění značkovače není nijak komplikovaný.

  try {
      marker.delete();
  } catch (CoreException e) {
      // Někde je problém
   }

Když je značkovač odstraněn, stane se příslušný objekt značkovače (popisovač) "zastaralým". Moduly plug-in by měly používat protokol IMarker.exists(), aby se ujistily, že je objekt značkovače dosud platný.

Značkovače je možné odstraňovat dávkově, když požádáme prostředek, aby odstranil své značkovače. Tato metoda je užitečná při odebírání velkého počtu značkovačů najednou, nebo když nejsou k dispozici ID či odkazy jednotlivých značkovačů.

   int depth = IResource.DEPTH_INFINITE;
  try {
      resource.deleteMarkers(IMarker.PROBLEM, true, depth);
  } catch (CoreException e) {
      // někde je problém
   }

Při odstraňování skupiny značkovačů určíte typ značkovačů, který se má odstranit, jako např. IMarker.PROBLEM, nebo hodnotu null, aby se odstranily všechny značkovače. Druhý argument udává, zda chcete odstranit značkovače podtypů.  (Na podtypy se podíváme za okamžik, až nadefinujeme nové typy značkovačů.)  Argument depth kontroluje hloubku odstraňování. 

Značkovače můžete odstraňovat také pomocí metody IWorkspace.deleteMarkers(IMarker[]).

Atributy značkovačů

Máte-li značkovač, můžete požádat o jeho přidružený prostředek, ID (jedinečný identifikátor ve vztahu k danému prostředku) a typ. Prostřednictvím generických atributů máte přístup i k dalším informacím.

Každý typ značkovačů má specifickou množinu atributů, které jsou definovány tvůrcem daného typu značkovače pomocí pravidel pro pojmenování.  Rozhraní IMarker definuje množinu konstant obsahující standardní názvy atributů (a některé očekávané hodnoty) pro typy značkovačů platformy. Následující metoda manipuluje atributy pomocí konstant platformy.

   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) {
         // Musíte ošetřit případ, kde již značkovač neexistuje      }
   }

Atributy jsou udržovány genericky jako dvojice názvů a hodnot, kde názvy jsou řetězce a hodnota může být kterýkoli z podporovaných typů hodnot (logická hodnota, celé číslo, řetězec). Omezení typů hodnot umožňuje platformě rychle a jednoduše udržovat trvalé značkovače.

Dotazování nad značkovači

Prostředků se lze dotazovat na jejich značkovače a značkovačů na jejich podřízené prvky. Například dotaz nad kořenem pracovního prostoru s nekonečnou hloubkou zohledňuje všechny značkovače v daném pracovním prostoru.

   IMarker[] problems = null;
   int depth = IResource.DEPTH_INFINITE;
  try {
      problems = resource.findMarkers(IMarker.PROBLEM, true, depth);
  } catch (CoreException e) {
      // někde je problém
   }

Výsledek vrácený metodou findMarkers záleží na předaných argumentech.  Ve výše uvedeném úseku kódu hledáme všechny značkovače typu PROBLEM, které se na prostředku objevují, a všechny jejich přímo i nepřímo podřízené prvky. 

Pokud jako typ značkovače předáte null, dostanete všechny typy značkovačů přidružené k danému prostředku. Druhý argument určuje, zda chcete pracovat i s podřízenými prvky daného prostředku.  Argument depth řídí hloubku vyhledávání, když pracujete i s podřízenými prvky prostředku. Hloubka může být DEPTH_ZERO (pouze daný prostředek), DEPTH_ONE (daný prostředek a všechny jeho přímo podřízené prvky), nebo DEPTH_INFINITE (daný prostředek a všechny jeho přímo i nepřímo podřízené prvky).

Zachování značkovačů

Standardní značkovače platformy (úloha, problém a záložka) jsou trvalé. To znamená, že jejich stav bude při ukončení práce uložen a při spuštění obnoven. Značkovače trvalého typu je však možné selektivně měnit na přechodné nastavením vyhrazeného atributu transient na hodnotu true.

Nové typy značkovačů deklarované v modulech plug-in nejsou trvalé, pokud nejsou jako takové deklarovány.

Rozšiřování platformy pomocí nových typů značkovačů

Moduly plug-in mohou deklarovat vlastní typy značkovačů pomocí bodu rozšíření org.eclipse.core.resources.markers. Standardní typy značkovačů pro problémy, úlohy a záložky jsou deklarované platformou v markupu modulu plug-in prostředků.

   <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>

Nové typy značkovačů jsou odvozené ze stávajících typů s využitím vícenásobné dědičnosti. Nové typy značkovačů zdědí všechny atributy svých supertypů a doplní je o jakékoli nové atributy definované v rámci deklarace. Přechodně zdědí také atributy supertypů svých supertypů. Následující markup definuje nový druh značkovače v hypotetickém modulu plug-in 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>

Všimněte si, že typ org.eclipse.core.resources.problemmarker je ve skutečnosti jedním z předdefinovaných typů (rovněž známo pod pojmem IMarker.PROBLEM). 

Jediný aspekt supertypu značkovače, který se nedědí, je příznak persistence.  Výchozí hodnota příznaku persistence je false, takže jakýkoli typ značkovače, který by měl být trvalý, musí zadat <persistent value="true"/>.

Po deklarování nového typu značkovače ve svém souboru s manifestem modulu plug-in můžete vytvořit instance typu značkovače com.example.markers.myproblem a dle vlastního uvážení nastavit či získat atribut myAttribute.

Deklarování nových atributů vám umožní přiřadit data ke značkovačům, které máte v plánu použít jinde (ve svých pohledech a editorech). Značkovače určitého typu nemusí mít hodnoty pro všechny deklarované atributy. Deklarace atributů slouží spíše k řešení problémů s pravidly pojmenování (takže každý, kdo mluví o popisu značkovače, použije pojem "message" (zpráva)) než k omezení obsahu.

   public IMarker createMyMarker(IResource resource) {
  try {
         IMarker marker = resource.createMarker("com.example.markers.myproblem");
         marker.setAttribute("myAttribute", "MYVALUE");
         return marker;
  } catch (CoreException e) {
         // Musíte ošetřit případy, kde je hodnota atributu odmítnuta
      }
   }

Vlastních typů značkovačů se můžete dotazovat stejně jako se dotazujete typů značkovačů platformy.  Níže uvedená metoda najde všechny značkovače mymarker přidružené k danému cílovému prostředku a všem jeho odvozeným položkám. Všimněte si, že také vyhledá všechny značkovače myproblem, protože pro argument includeSubtypes je předána hodnota true.

   public IMarker[] findMyMarkers(IResource target) {
      String type = "com.example.markers.mymarker";
      IMarker[] markers = target.findMarkers(type, true, IResource.DEPTH_INFINITE);
   }