Как известно, модули могут определять специальные расширения файлов и добавлять в систему редакторы, которые будут обеспечивать для этих типов файлов специальные возможности редактирования. В ходе редактирования (или компоновки) ресурса модулю может потребоваться пометить ресурсы для передачи пользователю информации о неполадках или других сведений. Для управления такими данными используется механизм маркеров ресурсов.
Маркер - это своего рода наклейка для ресурса. Маркер может содержать информацию о неполадке, например, расположение, серьезность, или необходимые действия. Также можно записать расположение в виде закладки.
Пользователи могут быстро перейти к отмеченному расположению внутри ресурса. Пользовательский интерфейс рабочей среды поддерживает представление в редакторе закладок, точек прерывания, задач и неполадок. Маркеры тоже можно представить в виде элементов панелей, например, панелей Задачи или Закладки.
API ресурсов платформы определяет методы для создания маркеров, задает значения маркеров и добавляет новые типы маркеров. Маркерами управляет сама платформа, а модули контролируют их создание, удаление и значения атрибутов.
Маркеры представляют собой простые объекты небольшого размера. Один проект может включать сотни и даже тысячи маркеров. Например, компилятор Java использует маркер для присвоения флага каждой неполадке, найденной в исходном коде.
Платформа отбрасывает маркеры, прикрепленные к удаленным ресурсам, однако модули должны удалять устаревшие маркеры, если они уже не относятся к ресурсу, который еще существует.
Операции, которые можно выполнять с маркерами, аналогичны операциям, которые выполняются с ресурсами. Маркеры являются объектами описания. Описатель маркера можно получить из ресурса, однако заранее неизвестно, существует ли он на самом деле, пока к нему не будет применен протокол exists() либо любой другой метод. После того, как вы выяснили, что маркер существует, можно запросить его атрибуты.
Маркерами владеет и управляет платформа, которая сохраняет их постоянство и уведомляет получателей запросов о добавлении, удалении или изменении маркеров. Модули создают все необходимые маркеры, изменяют их атрибуты и удаляют ненужные маркеры.
Для создания маркеров не используется конструктор. Вместо этого применяется метод IResource.createMarker().
IMarker marker = file.createMarker(IMarker.TASK);
Для создания маркера с глобальным контекстом (т.е. не связанного со строго определенным ресурсом), можно использовать корень рабочей области (IWorkspace.getRoot()) в качестве ресурса.
Для удаления маркера используется следующий код:
try { marker.delete(); } catch (CoreException e) { // Исключительная ситуация }
При удалении маркера его объект (описатель) становится "устаревшим." Для проверки его наличия модули должны использовать протокол IMarker.exists().
Маркеры можно удалять группами, отправляя ресурсу запрос на удаление его маркеров. Данный метод применяется, если необходимо удалить сразу группу маркеров либо если отдельные указатели или идентификаторы маркеров недоступны.
int depth = IResource.DEPTH_INFINITE; try { resource.deleteMarkers(IMarker.PROBLEM, true, depth); } catch (CoreException e) { // исключительная ситуация }
При удалении группы маркеров необходимо указать тип маркера, который будет удален, например, IMarker.PROBLEM, или null для удаления всех маркеров. Второй аргумент обозначает, следует ли удалять маркеры производных типов. Производные типы будут рассмотрены в разделе, который описывает определение новых типов маркеров. Аргумент depth определяет глубину удаления.
Кроме того, для удаления маркеров можно использовать метод IWorkspace.deleteMarkers(IMarker []).
Если задан маркер, можно запросить соответствующий ему ресурс, идентификатор (уникальный для данного ресурса) и тип. Для доступа к дополнительной информации используются общие атрибуты.
Каждый тип маркера имеет свой собственный набор атрибутов, которые определяет создатель данного типа маркера, используя соглашения об именах. Интерфейс IMarker определяет набор констант, содержащих стандартные имена атрибутов (и некоторые ожидаемые значения) для типов маркеров. Следующий метод обрабатывает атрибуты с помощью констант платформы.
IMarker marker = file.createMarker(IMarker.TASK); if (marker.exists()) { try { marker.setAttribute(IMarker.MESSAGE, "Сообщение от маркера"); marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); } catch (CoreException e) { // Обработка исключительной ситуации, если маркер уже не существует } }
Обычно обработка атрибутов осуществляется парами имя/значение, где имена являются строками, а значения могут быть трех типов: булевское, целочисленное либо строка. Ограничение типов значений позволяет платформе быстро настраивать маркеры.
Запросы, отправляемые ресурсам, позволяют получить информацию о маркерах данных ресурсов и маркерах вложенных элементов этих ресурсов. Например, запрос неопределенной глубины, отправляемый корневому субъекту рабочей области, находит все маркеры рабочей области.
IMarker[] problems = null; int depth = IResource.DEPTH_INFINITE; try { problems = resource.findMarkers(IMarker.PROBLEM, true, depth); } catch (CoreException e) { // исключительная ситуация }
Результат, который возвращает функция findMarkers, зависит от значений аргументов. Данный фрагмент кода находит все маркеры с типом PROBLEM, а также всех прямых и непрямых их потомков.
Если в качестве типа маркера указано null, будут найдены все типы маркеров, соответствующие данному ресурсу. Второй аргумент определяет, следует ли просматривать вложенные ресурсы. Аргумент depth задает глубину поиска вложенных ресурсов. Он может принимать следующие значения: DEPTH_ZERO (только данный ресурс), DEPTH_ONE (данный ресурс и все его прямые потомки) или DEPTH_INFINITE (данный ресурс и все его прямые и непрямые потомки).
Стандартные маркеры платформы (задача, неполадка и закладка) являются постоянными. Это означает, что их состояние сохраняется при каждом отключении и запуске рабочей среды. Тем не менее маркеры постоянного типа могут выборочно изменить свой тип на временный. Для этого необходимо, чтобы значение зарезервированного атрибута transient равнялось истине.
По умолчанию новые типы маркеров являются временными, если они не объявлены как постоянные.
Модули могут объявлять собственные типы маркеров с помощью точки расширения org.eclipse.core.resources.markers. Стандартные типы маркеров для неполадок, задач и закладок объявляются платформой в коде модуля ресурсов.
<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>
Новые типы маркеров являются производными от уже существующих типов, и для их создания используется множественное наследование. Новые типы маркеров наследуют все атрибуты родительского типа, а также могут иметь новые атрибуты, добавленные в объявлении нового типа. Кроме того, они по цепочке наследуют атрибуты родительских типов их родительских типов. Следующий фрагмент кода определяет новый тип маркера в гипотетическом модуле 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>
Следует отметить, что фактически тип org.eclipse.core.resources.problemmarker - это один из стандартных типов (также называемый IMarker.PROBLEM).
Единственным свойством родительского типа маркера, которое не наследуется, является флаг persistence. По умолчанию этот флаг имеет значение "ложь", поэтому для создания маркера постоянного типа необходимо явно задать <persistent value="true"/>.
После объявления нового типа маркера в файле объявления модуля пользователь может создавать экземпляры типа маркера com.example.markers.myproblem, а также задавать или получать значения атрибута myAttribute.
Объявление новых атрибутов позволяет связывать данные с маркерами, которые планируется использовать в панелях и редакторах. Маркеры некоторых типов необязательно должны иметь значения для всех объявленных атрибутов. Объявления атрибутов скорее предназначены для решения вопросов, связанных с соглашением об именах (чтобы для описания маркера все объекты использовали значения "message"), а не с целью ограничения содержимого.
public IMarker createMyMarker(IResource resource) { try { IMarker marker = resource.createMarker("com.example.markers.myproblem"); marker.setAttribute("myAttribute", "MYVALUE"); return marker; } catch (CoreException e) { // You need to handle the cases where attribute value is rejected } }
Запросы к пользовательским типам маркеров создаются так же, как и к типам маркеров платформы. Следующий метод находит все маркеры mymarkers, связанные с заданным ресурсом и всеми его потомками. Кроме того, будут найдены все неполадки myproblems, так как аргумент includeSubtypes имеет значение "истина".
public IMarker[] findMyMarkers(IResource target) { String type = "com.example.markers.mymarker"; IMarker[] markers = target.findMarkers(type, true, IResource.DEPTH_INFINITE); }