Sabemos que os plug-ins podem definir extensões de ficheiros especializadas e contribuir com editores que proporcionam funções de edição especializadas para estes tipos de ficheiros. No decurso da edição (ou construção) de um recurso, um plug-in poderá precisar de identificar recursos para reportar problemas ou outras informações ao utilizador. O mecanismo de marcador de recursos é utilizado para gerir este tipo de informações.
Um marcador é como um post-it colado a um recurso. No marcador pode gravar-se informações sobre um problema (p.ex., localização, gravidade) ou uma tarefa a desempenhar. Também se pode simplesmente gravar uma localização para um marcador como se fosse para marcar a página de um livro.
Os utilizadores podem avançar rapidamente para a localização marcada dentro de um recurso. A UI da área de trabalho suporta apresentação de marcadores de livros, pontos de quebra, tarefas e problemas na lateral do editor. Estes marcadores também podem ser mostrados como artigos em vistas como, por exemplo, a vista de tarefas ou marcadores de livros.
A API de recursos da plataforma define métodos para criar marcadores, definir valores de marcador e estender a plataforma com novos tipos de marcador. Embora a plataforma se encarregue da gestão dos marcadores, compete aos plug-ins controlar a sua criação, remoção e valores de atributos.
Os marcadores devem ser objectos pequenos e leves. Podem haver centenas, até milhares de marcadores num único projecto. Por exemplo, o compilador Java utiliza um marcador para sinalizar cada problema que encontrar no código fonte.
A plataforma descarta marcadores anexados a recursos que sejam eliminados, mas os plug-ins são responsáveis pela remoção dos seus marcadores desactualizados quando já não se aplicarem a um recurso que ainda exista.
A manipulação de um marcador é semelhante à de um recurso. os marcadores são objectos de pega. Pode obter uma pega de marcador de um recurso, mas só sabe se ele realmente existe quando utilizar o protocolo exists() ou tentar manipulá-lo de outro modo. Uma vez estabelecido que um marcador existe, poderá consultar atributos denominados que lhe possam ter sido atribuídos.
Os marcadores pertencem e são geridos pela plataforma, a qual se encarrega de os tornar persistentes e de notificar os ouvintes à medida que forem adicionados, eliminados ou alterados marcadores. Os plug-ins são responsáveis pela criação de marcadores necessários, alteração de atributos, e remoção deles quando já não forem necessários
Os marcadores não são directamente criados com um construtor. Em contrapartida, são criados com um método de fábrica (IResource.createMarker()) no recurso associado.
IMarker marker = file.createMarker(IMarker.TASK);
Para criar um marcador que tenha âmbito global (não associado a nenhum recurso específico), poderá utilizar a raiz do espaço de trabalho (IWorkspace.getRoot()) como recurso.
O código para eliminar um marcador é muito simples.
try { marker.delete(); } catch (CoreException e) { // Something went wrong }
Quando se elimina um marcador, o seu objecto de marcador (pega) fica "obsoleto". Os plug-ins devem utilizar o protocolo IMarker.exists() para garantir que um objecto de marcador ainda é válido.
Os marcadores podem ser eliminados em lotes pedindo a um recurso que elimine os seus marcadores. Este método é útil na remoção de muitos marcadores de uma vez ou se não estiverem disponíveis referências ou IDs de marcadores individuais.
int depth = IResource.DEPTH_INFINITE; try { resource.deleteMarkers(IMarker.PROBLEM, true, depth); } catch (CoreException e) { // something went wrong }
Ao eliminar um grupo de marcadores, especifica-se um tipo (type) de marcador a eliminar como, por exemplo, IMarker.PROBLEM ou null para os eliminar a todos. O segundo argumento indica se se pretende eliminar marcadores de subtipos. (Veremos os subtipos a seguir quando definirmos novos tipos de marcadores.) O argumento depth controla a profundidade da eliminação.
Também se pode eliminar marcadores com IWorkspace.deleteMarkers(IMarker []).
Com determinado marcador, pode pedir-se o recurso associado, o ID (único relativamente ao recurso) e o tipo. Também se pode aceder a informações adicionais através de atributos genéricos.
Cada tipo de marcador tem um conjunto de atributos específicos que são definidos pelo criador do tipo de marcador mediante convenções de nomenclatura. A interface IMarker define um conjunto de constantes que contém os nomes dos atributos padrão (e alguns dos valores esperados) para os tipos de marcadores da plataforma. O método seguinte manipula atributos com as constantes da plataforma.
IMarker marker = file.createMarker(IMarker.TASK); if (marker.exists()) { try { marker.setAttribute(IMarker.MESSAGE, "Mensagem de marcador exemplo"); marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); } catch (CoreException e) { // You need to handle the case where the marker no longer exists } }
Os atributos são mantidos genericamente como pares nome/valor, em que os nomes são cadeias de caracteres e um valor pode ser qualquer dos tipos de valores suportados (booleano, número inteiro, cadeia de caracteres). A limitação de tipos de valor permite à plataforma tornar os marcadores persistentes rápida e simplesmente.
Os recursos podem ser consultados relativamente aos seus marcadores e aos marcadores dos seus descendentes. Por exemplo, consultar a raiz do espaço de trabalho com profundidade infinita considera todos os marcadores no espaço de trabalho.
IMarker[] problems = null; int depth = IResource.DEPTH_INFINITE; try { problems = resource.findMarkers(IMarker.PROBLEM, true, depth); } catch (CoreException e) { // something went wrong }
O resultado devolvido por findMarkers depende dos argumentos transmitidos. Na porção de código supra, buscamos todos os marcadores do tipo PROBLEM que apareçam no recurso e todos os descendentes directos e indirectos.
Se transmitir null como tipo de marcador, irá obter todos os tipos de marcadores associados ao recurso. O segundo argumento especifica se se pretende ou não buscar nos descendentes do recurso. O argumento depth controla a profundidade da pesquisa quando se busca os descendentes do recurso. A profundidade pode ser DEPTH_ZERO (somente o recurso indicado), DEPTH_ONE (o recurso e todos os descendentes directos) ou DEPTH_INFINITE (o recurso e todos os descendentes directos e indirectos).
Os marcadores padrão da plataforma (tarefa, problema e marcador de livro) são persistentes. Significa isto que o seu estado será guardado ao longo do encerramento e arranque da área de trabalho. Todavia, os marcadores de tipo persistente podem tornar-se selectivamente transitórios definindo o atributo reservado transient como verdadeiro (true).
Os novos tipos de marcadores declarados por plug-ins não são persistentes, salvo se forem declarados como tal.
Os plug-ins podem declarar os seus próprios tipos de marcadores com o ponto de extensão org.eclipse.core.resources.markers. Os tipos de marcadores padrão para problemas, tarefas e marcadores de livros são declarados pela plataforma na marcação do plug-in de recursos.
<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>
Os novos tipos de marcadores derivam dos existentes através de herança múltipla. Os novos tipos de marcadores herdam todos os atributos dos seus supertipos e adicionam novos atributos definidos como parte da declaração. Também herdam transitivamente atributos dos supertipos dos seus supertipos. A marcação seguinte define novo tipo de marcador num plug-in com.example.marcadores hipotético.
<extension id="omeumarcador" point="org.eclipse.core.resources.marcadores" /> <extension id="omeuproblema" point="org.eclipse.core.resources.marcadores"> <super type="org.eclipse.core.resources.marcadorproblema"/> <super type="com.example.marcadores.omeumarcador"/> <attribute name="oMeuAtributo" /> <persistent value="true" /> </extension>
Repare que o tipo org.eclipse.core.resources.marcadorproblema é na verdade um dos tipos predeterminados (ou seja, IMarker.PROBLEM).
O único aspecto de um supertipo de marcador que não é herdado é o sinalizador de persistência. O valor predefinido para persistência é false, de modo que qualquer tipo de marcador que deva ser persistente deve especificar <persistent value="true"/>.
Após declarar o novo tipo de marcador no ficheiro de manifesto de plug-in, pode criar instâncias do tipo de marcador com.exemplo.marcadores.omeuproblema e definir ou obter livremente o atributo oMeuAtributo.
Declarar novos atributos permite associar dados a marcadores que tencione utilizar noutro lugar (em vistas e editores). Os marcadores de determinado tipo não têm de ter valores para todos os atributos declarados. As declarações de atributos são mais para resolver problemas na convenção de nomenclatura (e toda a gente usa "message" para falar da descrição de um marcador) do que para limitar conteúdo.
public IMarker createoMeuMarcador(IResource resource) { try { IMarker marker = resource.createMarker("com.exemplo.marcadores.omeuproblema"); marker.setAttribute("oMeuAtributo", "OMEUVALOR"); return marker; } catch (CoreException e) { // You need to handle the cases where attribute value is rejected } }
Poderá consultar os seus próprios tipos de marcadores da mesma maneira que consulta os tipos de marcadores da plataforma. O método infra detecta todos osmeusmarcadores associados ao recurso destino e todos os descendentes. Repare que isto também irá detectar todos osmeusproblemas dado que é transmitido verdadeiro (true) ao argumento includeSubtypes.
public IMarker[] findosMeusMarcadores(IResource target) { String type = "com.exemplo.marcadores.omeumarcador"; IMarker[] markers = target.findMarkers(type, true, IResource.DEPTH_INFINITE); }