构建基于通用导航器架构(CNF)的视图 第二部分:增加内容

转自:http://blog.csdn.net/windy444/archive/2007/12/31/2006304.aspx

由windy444翻译,转载请注明

原文名:Building a Common Navigator Framework (CNF) Viewer Part II: Adding Content,作者:MICHAEL ELDER,出处:http://scribbledideas.blogspot.com/(本人从未能打开过,呵呵)。

先上Copyright

The opinions and ideas expressed herin are my own and do not represent the intent, opinion, or official statement of any company or organization.
All postings by me to this site are copyrighted (C) by Michael D. Elder, 2006 and made available under the terms of the Eclipse Public License 1.0 with the constraint that any reuse of the content must contain this copyright statement.

在这篇文章中,我们将学习如何为我们上篇文章定义的例子增加一个简单的内容扩展。为避免陷于过度复杂的内容和标签提供者,我们将关注于一个简单的文件结构模型,简单文本文件*.properties。当完成时,我们的内容扩展将允许在Example viewer展开任意*.properties文件,并在下面正确排列出数据。

首先,让我们看一下,内容扩展在plugin.xml中看起来是怎样的。(译者注:略过一些基本操作,plugin.xml如下:)

该扩展用id "org.eclipse.ui.examples.navigator.propertiesContent"定义了一个内容扩展,显示的名称是"Properties File Contents"。该名称会出现在过滤器对话框的"Available Extensions"标签中。我们马上会去看一下内容和标签提供者的Java代码,但现在只是注意一下,两者都被指定了。只指定其中的一个是不行的。

最后,我们设置一些属性,告诉框架,我们需要怎样的扩展:

activeByDefault 决定扩展是否在缺省配置中被**(如:新工作空间)

icon 决定在用户界面引用该扩展时,显示什么图标

priority 有几种不同的用法。最主要的作用是指定视图中项的相对位置(视图中从上到下排列的分别是最高优先级(highest priority)项到最低优先级(lowest priority)项)。一般的说,“一般级”("normal")或“高级”("high")对于大多数的扩展来说,足够了,两者分别预示着与资源扩展混合在一起(优先级一样的话,则按字母顺序)或恰好放在工程下的资源之上。

在每个<navigatorContent />元素内,我们能指定不同类别的扩展。但在扩展我们的例子之前,我们必须向架构定义,我们的扩展何时被调用。我们必须定义,什么时候视图中树的节点能够提供children,parents,或者标签和图标。我们用Eclipse 核心表达式来做这个工作。

对于内容扩展,这里有两个重要的表达式:<triggerPoints /> 和<possibleChildren />。

<triggerPoints />表达式指定树中哪种类型的节点对我们的扩展感兴趣。当架构找到了匹配<triggerPoints />的节点,我们的扩展会被调用,为该节点提供子元素。我们的扩展并不一定是唯一能有机会为该节点提供子元素的扩展,架构会聚集该节点下所有的子元素(译者注:可以是不同扩展提供的)。

<possibleChildren />表达式指定我们的扩展能为树中哪种类型的节点提供标签或父节点(译者注:注意与triggerPoints 的不同)。若你的场景中必须在视图中支持link with editor,或者 setSelection(),<possibleChildren />表达式必须是完整且正确的。

一旦我们定义了一个扩展,我们必须把它绑定到想要关联的视图上。设定一个<viewerContentBinding />,来指定任何匹配include中模式的扩展,这些扩展对于在<viewerContentBinding />元素中指定的任何viewerId的视图是可见的。可以参考上一篇文章。

既然我们已经设置好了扩展,现在可以来看一下真正处理事务的代码了。

首先,我们需要一个模型。一个属性文件的结构是相当简单的,我们只要用一个模型对象PropertiesTreeData,就能够建模了。这个对象有三个域:name(属性的名称),value(属性的值),container(拥有属性模型的文件)。每一个模型元素,指示属性文件中的一条属性。

在我们的例子中,模型只有当被内容提供者请求时,才被载入。内容提供者被框架用来决定树中每个元素的子元素,或者被用来指定给定元素的父元素(可能有多个)。

我们的示例内容提供者实现了接口org.eclipse.jface.viewers.ITreeContentProvider,用来提供树形结构的信息。通用导航器架构也支持实现org.eclipse.jface.viewers.ITreePathContentProvider接口的内容提供者,但这个超出了本例的范围。

PropertiesContentProvider也提供了我们的扩展需要的其它一些功能,比如监听资源变化和更新模型(以及视图)。在本文中不会涉及,读者可以到本文的源码中了解这个是如何工作的。

现在,我们将关注ITreeContentProvider提供的视图集成方法。

ITreeContentProvider必须实现getElements(Object input),getChildren(Object parent), hasChildren(Object element)getParent(Object element)方法。

getElements()方法被用来查询在视图根目录下有哪些元素。许多实现会直接调用getChildren()来处理,我们在这边也如此。

getChildren()方法接受一个对象(我们这里是*.properties结尾的IFile,或者是由于在<triggerPoints />中描述而必须引入的PropertiesTreeData模型实例)。

在接下来的实现中,我们检查接受的对象是否为org.eclipse.core.resources.IFile,并且是否以*.properties结尾。如果接受的对象满足这些要求,我们检查载入模型的缓存,当未缓存时,尝试载入模型。updateModel()方法将为每个属性创建一个PropertiesTreeData对象,并且在cachedModelMap中缓存所找到的模型。请读者在源码中查看updateModel()方法是如何实现的。

hasChildren()方法被优化了,知道当传入的对象是以*.properties结尾的IFile,就返回true。另一种替换的方法,是在这边载入文件,作一些计算,但这样性能会受损。

如果传入的对象是PropertiesTreeData模型元素,则返回false。因为我们的模型元素没有子元素。(属性没有子元素,但其它模型可能就会有了)。

getParent()方法返回包含PropertiesTreeData项的IFile,若传入其它参数,返回null。通用导航器架构会继续询问其它扩展,直到一个非null的的父元素被找到或者已经遍历了所有扩展。回忆一下,如果元素匹配<possibleChildren />表达式,扩展会被要求为该元素提供父节点。

最后,我们内容扩展的标签提供者,会告诉视图如何为我们的模型元素(PropertiesTreeData)来展现标签和图标。既然我们只关注这些元素,我们不必担心如何为其它元素来提供标签和图标。这些元素将由其它的扩展来展现标签和图标。

PropertiesLabelProvider实现了org.eclipse.jface.viewers.ILabelProvider 和
org.eclipse.ui.navigator.IDescriptionProvider接口。

ILabelProvider是JFace中提供标签和图标的缺省接口要求。

IDescriptionProvider是特定用于通用导航器架构的,用于在Eclipse窗口左下角的状态栏显示文本。

ILabelProvider要求的方法是getText()和 getImage()。我们将让模型标签显示"name= value"的字符串。对于图标,我们使用平台提供的一个共享图标。

标签提供者在下面两种情况下会被访问到:1.自己的扩展定义的元素。2.所有匹配<possibleChildren />的元素。如果图标或标签返回了null,框架会基于<possibleChildren />和视图bindings,继续查找其它扩展(来显示标签和图标)。如果你的扩展希望由其它人来定义标签和图标,则要返回null。

就这些了,最终的视图Example View在属性文件下列出了属性。