Sabemos que los conectores pueden definir extensiones de archivos especializadas y aportar editores que proporcionen características de edición especializadas para estos tipos de archivos. Durante la edición (o construcción) de un recurso, puede ser que el conector tenga que marcar los recursos para que comuniquen los problemas u otro tipo de información al usuario.El mecanismo de marcador de recursos se utiliza para gestionar este tipo de información.
El marcador es como una nota adhesiva pegada en un recurso. En el marcador puede anotar información sobre un problema (por ejemplo, la ubicación, la gravedad) o una tarea que deba realizarse. O puede simplemente anotar una ubicación de un marcador para que se añada como favorito.
Los usuarios pueden ir directamente a la ubicación marcada dentro de un recurso. La UI del entorno de trabajo da soporte a la presentación de favoritos, puntos de interrupción, tareas y problemas en un lado del editor. Estos marcadores también se pueden mostrar como elementos en vistas como las 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. Si bien es la plataforma la que gestiona los marcadores, los conectores son los que controlan su creación, su eliminación y los valores de sus atributos.
Los marcadores están pensados para ser objetos pequeños y ligeros. En un solo proyecto puede haber cientos e incluso miles de marcadores. Por ejemplo, el compilador Java utiliza un marcador para señalar cada problema que encuentra en el código fuente.
La plataforma desechará los marcadores pegados a los recursos que se han suprimido; en cambio, los conectores son los que se encargan de eliminar sus marcadores obsoletos cuando hayan dejado de ser válidos para un recurso que todavía existe.
Los marcadores se manipulan de forma parecida a los recursos. Los marcadores son objetos de tipo handle. Puede obtener el handle de un marcador a partir de un recurso, pero no sabrá si realmente existe mientras no utilice el protocolo exists() o mientras no intente manipularlo de alguna otra manera. Una vez establecida la existencia de un marcador, podrá consultar los atributos con nombre que estén asignados a él.
Los marcadores son propiedad de la plataforma, que además los gestiona y se encarga de hacer que sean persistentes y de informar a los escuchas cuando se añaden, suprimen o cambian marcadores. Los conectores son los que se encargan de crear los marcadores necesarios, de cambiar sus atributos y de eliminarlos cuando hayan dejado de ser necesarios.
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 a ningún recurso específico), puede utilizar el directorio raíz del área de trabajo (IWorkspace.getRoot()) como recurso.
El código para suprimir un marcador es muy sencillo.
try { marker.delete(); } catch (CoreException e) { // Algo no ha funcionado }
Cuando se suprime un marcador, su objeto marcador (handle) pasa a ser "obsoleto". Los conectores deben utilizar el protocolo IMarker.exists() para asegurarse de que un objeto marcador sigue siendo válido.
Los marcadores pueden suprimirse por lotes pidiendo a un recurso que suprima sus marcadores. Este método resulta de utilidad cuando se eliminan muchos marcadores de una sola vez o si las referencias o los ID de los marcadores individuales no están disponibles.
int depth = IResource.DEPTH_INFINITE; try { resource.deleteMarkers(IMarker.PROBLEM, true, depth); } catch (CoreException e) { // Algo no ha funcionado }
Al suprimir un grupo de marcadores, especificará un atributo type de marcador que deba suprimirse (por ejemplo, IMarker.PROBLEM) o el valor null para suprimir todos los marcadores. El segundo argumento indica si desea suprimir marcadores de subtipo. (Más adelante, al definir nuevos tipos de marcadores, veremos los subtipos). El argumento depth controla la profundidad de la supresión.
Los marcadores también se pueden suprimir con el método IWorkspace.deleteMarkers(IMarker []).
Dado un marcador, puede consultar cuál es su recurso asociado, su ID (exclusivo y relativo a ese recurso) y su tipo. También puede acceder a información adicional por medio de los atributos genéricos.
Cada tipo de marcador tiene un conjunto específico de atributos definidos por el creador del tipo de marcador según los 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) de los tipos de marcadores de la plataforma. El método siguiente manipula los atributos utilizando las constantes de la plataforma.
IMarker marker = file.createMarker(IMarker.TASK); if (marker.exists()) { try { marker.setAttribute(IMarker.MESSAGE, "Un mensaje de marcador de ejemplo"); marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); } catch (CoreException e) { // Hay que manejar el caso en que el marcador haya dejado de existir } }
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, serie). La limitación impuesta en los tipos de valores permite a la plataforma hacer que los marcadores sean persistentes de manera rápida y simple.
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 con una profundidad infinita, 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 no ha funcionado }
El resultado devuelto por findMarkers depende de los argumentos que se hayan pasado. En el fragmento de código anterior, se han buscado todos los marcadores de tipo PROBLEM que aparecen en el recurso y en todos sus descendientes directos e indirectos.
Si pasa el valor null como tipo de marcador, obtendrá todos los tipos de marcadores asociados al recurso. El segundo argumento especifica si desea ver los hijos del recurso. El argumento depth controla la profundidad de la búsqueda cuando ve los hijos del recurso.La profundidad puede tener los valores DEPTH_ZERO (solo el recurso dado), DEPTH_ONE (el recurso y todos sus hijos directos) o DEPTH_INFINITE (el recurso y todos sus descendientes directos e indirectos).
Los marcadores estándar de la plataforma (de tareas, problemas y favoritos) son persistentes. Esto significa que su estado se guarda cuando se concluye y se inicia el entorno de trabajo. Sin embargo, los marcadores de tipo persistente pueden convertirse en transitorios de forma selectiva estableciendo el atributo reservado transient en true.
Los tipos de marcadores nuevos declarados por los conectores no son persistentes, a menos que se declaren como tales.
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 de problemas, tareas y favoritos los declara la plataforma en los códigos XML 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"/> <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>
Los tipos de marcadores nuevos se derivan de los existentes mediante la herencia múltiple. Los tipos de marcadores nuevos heredan todos los atributos de sus supertipos y añaden los atributos nuevos que se hayan definido como parte de la declaración. También heredan transitivamente los atributos de los supertipos de sus supertipos. Los siguientes códigos XML definen un tipo de marcador nuevo en un conector com.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 el tipo de marcador org.eclipse.core.resources.problemmarker es en realidad uno de los tipos predefinidos (conocido como IMarker.PROBLEM).
El único aspecto de un supertipo de marcador que no se hereda es su distintivo de persistencia. El valor por omisión de 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.
La declaración de atributos nuevos le permite asociar datos a los marcadores que piensa utilizar en otro lugar (en sus vistas y editores). No es necesario que los marcadores de un tipo concreto tengan valores para todos los atributos declarados. Las declaraciones de los atributos están destinadas más a resolver los 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) { // Hay que manejar los casos en que se rechace el valor del atributo } }
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 al recurso destino proporcionado y a todos sus descendientes. Tenga en cuenta que también se buscarán todos los myproblems, porque 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); }