我们知道插件可以定义专门的文件扩展名并添加为这些文件类型添加特殊编辑功能部件的编辑器。在编辑(或构建)资源的过程中,插件可能需要标记资源以便向用户通知有关问题或其它信息。资源标记机制就是用来管理这种信息的。
标记类似于附着于资源上面的黄色粘贴注释。在标记上,可以记录关于问题(例如,位置和严重性)或者要执行的任务的信息。或者,可以只记录标记的位置,并将它作为书签。
用户可以快速跳至资源中所标记的位置。工作台用户界面支持沿着编辑器的边缘显示书签、断点、任务和问题的表示。这些标记也可以作为视图中的项来显示,例如,任务或书签视图。
平台资源 API 定义用于创建标记、设置标记值和利用新的标记类型来扩展平台的方法。在平台管理标记时,标记的创建、除去和属性值是由插件来控制的。
标记应是小的轻量级对象。在单个项目中可以有成百上千个标记。例如,Java 编译器使用标记来对它在源代码中发现的每个问题作出标志。
平台将抛弃与已删除的资源相连的标记,而在标记不再适用于仍然存在的资源时,插件将负责除去失效的标记。
处理标记与处理资源相似。标记是句柄对象。可以从资源中获得标记句柄,但是在使用 exists() 协议或者试图处理它之前,您并不知道它是否确实存在。一旦确定标记存在,您就可以查询可能已经指定给它的命名属性。
标记由平台拥有和管理,它负责使标记持久,并在添加、删除或更改标记时通知侦听器。插件负责创建任何必需的标记、更改它们的属性,并在不再需要它们时将它们除去。
标记并不是使用构造函数直接创建的。它们是通过对相关联的资源使用工厂方法(IResource.createMarker())来创建的。
IMarker marker = file.createMarker(IMarker.TASK);
要创建具有全局作用域的标记(不与任何特定资源相关联),可以使用工作空间根目录(IWorkspace.getRoot())来作为资源。
用于删除标记的代码是非常简单直接的。
try { marker.delete(); } catch (CoreException e) { // Something went wrong }
如果删除标记,它的标记对象(句柄)就“失效”了。插件应该使用 IMarker.exists() 协议来确保标记对象仍然是有效的。
可以要求资源删除它的标记来成批删除标记。当同时除去许多标记或者如果单独的标记引用或标识不再可用时,此方法就很有用。
int depth = IResource.DEPTH_INFINITE; try { resource.deleteMarkers(IMarker.PROBLEM, true, depth); } catch (CoreException e) { // something went wrong }
当删除一组标记时,指定要删除的标记类型,例如,IMarker.PROBLEM,或者指定 null 来删除所有标记。第二个自变量指示您是否想删除删除子类型标记。(稍后我们定义新标记类型时,将了解子类型)。 depth 自变量控制删除的深度。
还可以使用 IWorkspace.deleteMarkers(IMarker []) 来删除标记。
给定标记,您可以查询它的关联资源、它的标识(相对该资源唯一)及其类型。还可以通过一般属性来访问其它信息。
每种类型的标记都具有由标记类型的创建程序使用命名约定来定义的一组特定属性。IMarker 接口定义一组包含平台标记类型的标准属性名(和一些期望值)的常量。以下方法使用平台常量来处理属性。
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) { // You need to handle the case where the marker no longer exists } }
属性通常是根据名称/值对分类维护的,其中,名称是字符串,而值可以是任何一种受支持的值类型(布尔、整数、字符串)。对值类型的限制允许平台快速而简单地维护标记。
可以查询资源以获取其标记及其子代的标记。例如,查询具有极大深度的工作空间根目录时,可获取工作空间中的所有标记。
IMarker[] problems = null; int depth = IResource.DEPTH_INFINITE; try { problems = resource.findMarkers(IMarker.PROBLEM, true, depth); } catch (CoreException e) { // something went wrong }
findMarkers 返回的结果取决于传送的自变量。在以上代码段中,我们在查找资源上出现的类型为 PROBLEM 的所有标记,以及它的所有直接和间接的子代。
如果传送 null 来作为标记类型,则您将获得与资源相关联的所有标记类型。第二个自变量指定您是否想查看资源的子代。当您查看资源的子代时,depth 自变量控制搜索深度。深度可以是 DEPTH_ZERO(只搜索给定的资源)、DEPTH_ONE(搜索资源及其所有的直接子代)或者 DEPTH_INFINITE(搜索资源及其所有直接和间接子代)。
平台标准标记(任务、问题和书签)是持久。这意味着在关闭和启动工作台这段时间内将保存它们的状态。但是,可以通过将保留的属性 transient 设置为 true 来有选择地使持久类型的标记变成瞬时的。
由插件声明的新标记类型不是持久的,除非它们象这样声明。
插件可以使用 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 实际上是其中一种预定义类型(aka IMarker.PROBLEM)。
标记超类型唯一不是继承的一点就是它的 persistence 标志。persistence 的缺省值为 false,因此,任何应持续存在的标记类型都必须指定 <persistent value="true"/>。
在插件清单文件中声明新标记类型之后,可以创建 com.example.markers.myproblem 标记类型的实例,并自由地设置或获取 myAttribute 属性。
声明新属性允许您将数据与您计划在别处(在视图和编辑器中)使用的标记进行关联。特殊类型的标记不需要具有所有已声明的属性的值。用于解决命名约定问题的属性声明比用于约束内容的属性声明要多 (因此,每个人使用“消息”来谈论标记的描述)。
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 自变量传送了 true。
public IMarker[] findMyMarkers(IResource target) { String type = "com.example.markers.mymarker"; IMarker[] markers = target.findMarkers(type, true, IResource.DEPTH_INFINITE); }