Marcadores de recursos

Los conectores pueden definir extensiones de archivos especiales y contribuir con editores que proporcionan características de edición específicas para dichos archivos.  Durante la edición (o construcción) de un recurso, el conector debe codificar recursos para notificar los problemas u otra información al usuario. El mecanismo de marcador de recursos se utiliza para gestionar este tipo de información.

Un marcador es como una nota adhesiva pegada junto a un recurso. En el marcador puede anotar información sobre un problema (por ejemplo, ubicación, gravedad) o una tarea que se ha de realizar.  O anotar una ubicación para un marcador como un favorito. 

Los usuarios pueden ir a la ubicación marcada dentro de un recurso. La UI de entorno de trabajo soporta la presentación de favoritos, puntos de interrupción, tareas y problemas en un lado del editor.  Estos marcadores también pueden mostrarse como elementos de vistas como, por ejemplo, la vista de tareas o de favoritos.

La API de recursos de la plataforma define métodos para crear marcadores, establecer valores de marcadores y ampliar la plataforma con nuevos tipos de marcadores. Mientras la plataforma gestiona marcadores, los conectores controlan su creación, sustitución y sus valores de atributos.

Los marcadores están pensados para ser objetos pequeños y ligeros. En un solo proyecto puede haber un gran número de marcadores.  Por ejemplo, el compilador Java utiliza un marcador para identificar cada problema que encuentra en el código fuente.

La plataforma elimina marcadores asociados a recursos que se han suprimido; en cambio, los conectores tienen que eliminar sus marcadores inservibles cuando ya no se aplican a un recurso que aún existe.

Operaciones con marcadores

Manipular un marcador es parecido a manipular un recurso.  Los marcadores son objetos de manejador.  Puede obtener un manejador de marcador de un recurso, pero no sabrá si existe realmente hasta que utilice el protocolo exists() o intente manipularlo.  Una vez haya determinado que un marcador existe, puede encontrar el recurso al que pertenece y consultar sus identificadores o atributos específicos que pueda tener asignados.

Los marcadores son propiedad de la plataforma, que los gestiona; asimismo, se encarga de hacer que sean persistentes y notificar a los escuchadores si se añaden, suprimen o modifican.  Los conectores son responsables de crear cualquier marcador necesario, cambiar sus atributos y eliminarlos cuando ya no se necesitan.

Crear marcadores

Los marcadores no se crean directamente mediante un constructor. Se crean utilizando un método de fábrica (IResource.createMarker()) en el recurso asociado.

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

Para crear un marcador de ámbito global (que no esté asociado con ningún recurso específico), puede utilizar la raíz de área de trabajo (IWorkspace.getRoot()) como el recurso.

Suprimir marcadores

El código para suprimir un marcador es directo.

try {
    marker.delete();
} catch (CoreException e) {
    // Algo ha ido mal
}

Cuando se suprime un marcador, su objeto de marcador (manejador) deja de ser "útil." Los conectores deben utilizar el protocolo IMarker.exists() para asegurarse de que un objeto de marcador sigue siendo válido.

Los marcadores pueden suprimirse por lotes pidiendo a un recurso que suprima sus marcadores. Este método resulta satisfactorio para suprimir muchos marcadores a la vez o si las referencias o identificadores de marcadores concretos no están disponibles.

int depth = IResource.DEPTH_INFINITE;
try {
    resource.deleteMarkers(IMarker.PROBLEM, true, depth);
} catch (CoreException e) {
    // algo ha ido mal
}

Al suprimir un grupo de marcadores, especifica un tipo de marcador que suprimir, como IMarker.PROBLEM, o null para suprimir todos los marcadores. Este segundo argumento indica si desea suprimir marcadores de subtipo.  (Más adelante, cuando se hable sobre cómo definir nuevos tipos de marcadores, se hará referencia a los subtipos).   El argumento depth controla el alcance de la supresión. 

También puede suprimir marcadores utilizando deleteMarkers(IMarker []).

Atributos de marcador

Respecto a un marcador determinado puede preguntar cuál es su recurso asociado, su identificador (único en relación a ese recurso) y su tipo. También puede acceder a información adicional mediante atributos genéricos.

Cada tipo de marcador tiene un conjunto de atributos específico; dichos atributos los define el creador del tipo de marcador utilizando convenios de denominación.  La interfaz IMarker define un conjunto de constantes que contienen los nombres de atributos estándar (y algunos de los valores esperados) para los tipos de marcadores de la plataforma. El método siguiente manipula atributos utilizando las constantes de la plataforma.

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) {
        // Tiene que saber cómo actuar en caso de que el recurso no exista
    }

Los atributos se mantienen de manera genérica como pares de nombre/valor, en los que el nombre es una serie y el valor puede ser cualquiera de los tipos de valor soportados (booleano, entero y serie). La limitación de los tipos de valor permite a la plataforma hacer que los marcadores sean persistentes de manera rápida y simple.

Consultar marcadores

Se puede consultar un recurso para saber cuáles son sus marcadores y los marcadores de sus hijos. Por ejemplo, si se consulta el directorio raíz del área de trabajo en todo su alcance se tendrán en cuenta todos los marcadores del área de trabajo.

IMarker[] problems = null;
int depth = IResource.DEPTH_INFINITE;
try {
    problems = resource.findMarkers(IMarker.PROBLEM, true, depth);
} catch (CoreException e) {
    // algo ha ido mal
}

El resultado devuelto por findMarkers depende de los argumentos que se hayan pasado.  En el segmento anterior, se han buscado todos los marcadores cuyo tipo es PROBLEM y que aparecen en el recurso y todos sus descendientes directos e indirectos. 

Si se pasa null como el tipo de marcador, obtendrá todos los tipos de marcadores asociados con el recurso. El segundo argumento especifica si desea ver los hijos del recurso.  El argumento depth controla el alcance de la búsqueda cuando ve los hijos de los recursos. El alcance puede ser DEPTH_ZERO (sólo el recurso proporcionado), DEPTH_ONE (el recurso y todos sus hijos directos) o DEPTH_INFINITE (el recurso y todos sus descendientes directos e indirectos).

Persistencia de marcador

Los marcadores estándar de la plataforma (tarea, problema y favorito) sonpersistentes. Estos significa que su estado se guarda cuando se concluye y se inicia el entorno de trabajo.

Los nuevos tipos de marcadores declarados por los conectores no son persistentes a menos que se declaren como tales.

Ampliar la plataforma con nuevos tipos de marcadores

Los conectores pueden declarar sus propios tipos de marcadores mediante el punto de extensión org.eclipse.core.resources.markers. Los tipos de marcadores estándar para problemas, tareas y favoritos los declara la plataforma en la marcación del conector 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"/>
</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>

Los nuevos tipos de marcadores se derivan de los existentes mediante herencia múltiple. Los nuevos tipos de marcadores heredan todos los atributos de sus supertipos y añaden todos los atributos nuevos definidos en la declaración. También heredan transitivamente atributos del los supertipos a sus supertipos. La siguiente marcación define un nuevo tipo de marcador en un conectorcom.example.markers hipotético.

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

Tenga en cuenta que org.eclipse.core.resources.problemmarker es realmente uno de los tipos predefinidos (aka IMarker.PROBLEM). 

El único aspecto de un supertipo de marcador que no se hereda es su distintivo de persistencia.  El valor por omisión para la persistencia es false (falso), por lo que cualquier tipo de marcador que deba ser persistente tiene que especificar <persistent value="true"/>.

Después de declarar el nuevo tipo de marcador en el archivo de manifiesto del conector, puede crear instancias del tipo del marcador com.example.markers.myproblem y establecer u obtener libremente el atributo myAttribute.

Declarar nuevos atributos le permite asociar datos con marcadores que piensa utilizar en otro lugar (en vistas y editores). No es necesario que los marcadores de un tipo concreto tengan valores para todos los atributos declarados. Las declaraciones de atributos tienden más a resolver problemas de convenio de denominación (por lo que comúnmente se utiliza "message" para hacer referencia a la descripción de un marcador) que a restringir el contenido.

public IMarker createMyMarker(IResource resource) {
    try {
        IMarker marker = resource.createMarker("com.example.markers.myproblem");
        marker.setAttribute("myAttribute", "MYVALUE");
        return marker;
    } catch (CoreException e) {
        // Tiene que saber cómo actuar en los casos en que el valor de atributo es rechazado
    }
}

Puede consultar sus propios tipos de marcadores de la misma manera que consulta los tipos de marcadores de la plataforma.  El método siguiente busca todos los mymarkers asociados con el recurso de destino proporcionado y con todos sus descendientes. Tenga en cuenta que también se buscarán todos los myproblems ya que se ha pasado true (verdadero) para el argumento includeSubtypes.

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