使用CommonNavigator开发资源管理器--基础篇 模型篇

http://java.chinaitlab.com/Eclipse/759601.html

无论在哪一个开发工具中,资源管理器无疑都是使用最频繁的功能之一,因此一个资源器好用与否在很大程度上就决定了一个开发工具的易用程度。我们常用的Eclipse工具中的Java资源管理器就是一个非常优秀的资源管理器,所以在EOS Studio中,我们也照样抄袭它的功能,但是Java的资源管理器做了非常多的功能。如果从头开始做一个相似的资源管理器将是一个非常大的工作量,无论技术风险还是项目时间,都是非常可观的。幸好Eclipse还提供了一个优秀的插件org.eclipse.ui.navigator(以下简称为CNF,即Common Navigator Framework),这个插件提供了完整而且灵活的扩展机制,可以帮助开发人员进行各种相应的类资源管理器功能。其实这个插件在WTP在自己的项目中提供的,最早是用来开发数据库视图的(根源在于RAD6.0,但在WTP中,源代码被大量重写,所以直接就写成WTP),这个插件有足够的实力证明了自己的优秀,随后在Eclipse3.2版本中,它正式成为Eclipse UI层的核心插件之一,默认的Eclipse平台上有一个Project Explorer视图,就是基于它开发的一个资源管理器视图,它允许各种插件提供相应的内容,从而定制适合于各种环境下的资源管理器,下图显示了它的界面和相应的扩展功能。
    
    左面是一个对应的资源管理器,而右面的对话框则显示了当前资源管理器提供的扩展功能,可以方便用户选择各种资源管理视图的处理方式。

Studio在org.eclipse.ui.navigator的基础上开发了资源管理视图,以及相应的功能,因此要扩展和维护Studio的资源管理器,就需要先了解org.eclipse.ui.navigator这个插件,特别是它的扩展机制。

org.eclipse.ui.navigator尽管只提供了以下三个扩展点,却涉及到expression,还有wizard,filter等一堆内容,所以还是比较复杂的。

org.eclipse.ui.navigator.viewer

用来在视图和扩展之间建立关系

org.eclipse.ui.navigator.navigatorContent

用来提供模型,菜单以及过滤器等内容

org.eclipse.ui.navigator.linkHelper

用来支持文件与资源管理器联动

现在先用一个简单的实例方便开发人员上手,以便进一步了解相关的内容。这个实例就是使用现有的资源,无须编写一行代码,仅仅是通过plugin.xml的配置来配置出一个简单的Java资源管理器。

首先,请先通过向导新建一个Eclipse插件项目org.demo.navigator,如下图所示:



    在新建完项目以后,请导入以下插件:

org.eclipse.core.runtime

Eclipse的核心之一

org.eclipse.core.resources

Eclipse的资源模型

org.eclipse.ui

Eclipse的UI框架

org.eclipse.ui.navigator

我们本章要讲的插件

org.eclipse.ui.navigator.resources

一个基于org.eclipse.ui.navigator的插件,提供了ProjectExplorer视图

然后在Eclipse扩展配置的功能页面中,进行了一系列配置以后,可以得到以下的内容,心急的同学可以将该内容复制到plugin.xml文件中,然后运行该插件,即可看到一个简单的Eclipse资源管理器。

<?xml version="1.0" encoding="UTF-8"?>

<?eclipse version="3.2"?>

<plugin>

   <extension

         point="org.eclipse.ui.views">

      <view

            category="org.eclipse.ui"

            class="org.eclipse.ui.navigator.CommonNavigator"

            id="org.demo.navigator.view"

            name="DemoNavigator"/>

   </extension>

   <extension

         point="org.eclipse.ui.navigator.viewer">

      <viewer viewerId="org.demo.navigator.view"/>

      <viewerContentBindingviewerId="org.demo.navigator.view">

         <includes>

            <contentExtension pattern="org.demo.navigator.*"/>

            <actionExtension pattern="org.demo.navigator.*"/>

         </includes>

      </viewerContentBinding>

   </extension>

   <extension

         point="org.eclipse.ui.navigator.navigatorContent">

      <navigatorContent

            contentProvider="org.eclipse.ui.internal.navigator.resources.workbench.ResourceExtensionContentProvider"

            id="org.demo.navigator.content"

            labelProvider="org.eclipse.ui.internal.navigator.resources.workbench.ResourceExtensionLabelProvider"

            name="DemoNavigator">

         <enablement>

            <or>

               <instanceofvalue="org.eclipse.core.resources.IResource"/>

               <adapt type="org.eclipse.core.resources.IProject"/>

            </or>

         </enablement>

      </navigatorContent>

   </extension>

</plugin>


   

    尽管我们并没有写任何一行Java代码,但是却已经提供了一个具有基本功能的资源管理器,由此可以该插件的强大。

现在针对对应的配置图来讲述相应的内容:



    在这个例子,使用了三个扩展点,分别是:org.eclipse.ui.views,org.eclipse.ui.navigator.viewer和org.eclipse.ui.navigator.navigatorContent。

Eclipse插件开发人员对于org.eclipse.ui.views一定不陌生,因为这是Eclipse中最常用的一个扩展点,它用来定义Eclipse的视图,象属性视图,大纲视图都是通过该扩展点来定义的。

org.eclipse.ui.navigator.viewer则是CNF的一个基本扩展点,它提供了将org.eclipse.ui.navigator.navigatorContent与一个CommonNavigator绑定的功能。

   <extension

         point="org.eclipse.ui.navigator.viewer">

      <viewer viewerId="org.demo.navigator.view"/>

      <viewerContentBindingviewerId="org.demo.navigator.view">

         <includes>

            <contentExtension pattern="org.demo.navigator.*"/>

            <actionExtension pattern="org.demo.navigator.*"/>

         </includes>

      </viewerContentBinding>

   </extension>

这段代码表示所有名称符合"org.demo.navigator.*"的org.eclipse.ui.navigator.navigatorContent都可作为资源管理器的树模型扩展。

最后一个扩展点org.eclipse.ui.navigator.navigatorContent的配置则是CNF框架中最为复杂的一个点,在例子中,则只采用了最简单的配置信息。

   <extension

         point="org.eclipse.ui.navigator.navigatorContent">

      <navigatorContent

            contentProvider="org.eclipse.ui.internal.navigator.resources.workbench.ResourceExtensionContentProvider"

            id="org.demo.navigator.content"

            labelProvider="org.eclipse.ui.internal.navigator.resources.workbench.ResourceExtensionLabelProvider"

            name="DemoNavigator">

         <enablement>

            <or>

               <instanceofvalue="org.eclipse.core.resources.IResource"/>

               <adapt type="org.eclipse.core.resources.IProject"/>

            </or>

         </enablement>

      </navigatorContent>

   </extension>

每一个org.eclipse.ui.navigator.navigatorContent扩展点都有相应的contentProvider和labelProvider属性,用来定制树模型以及相应的显示功能。而enablement则表示,在何种情况下,才会调用激活这个指定的扩展功能。enablement则采用了org.eclipse.core.expression中定义的扩展点,支持各种复杂的表达式,方便开发人员定义各种条件。

在基础篇中,已经通过例子初步说明了,如何基于CNF制作一个简单的资源管理器,但很多开发人员并不理解,树上的结点是如何得到的,这就涉及到CNF的模型。在详述CNF的模型之前,需要先对Tree所使用的模型进行描述。

    对于早期习惯C/S开发的程序员来说,对于SWT中的Tree并不陌生,可以通过相应的TreeItem来创建子结点,但是这并不是一种好的设计和使用方式,它大大的增加了模型与UI之间的耦合度,所以在Swing中,使用了TreeNode来描述树模型,而Eclipse则通过JFace提供了ITreeContentProvider接口来描述树模型。这两种方式有异曲同工之处,大家可以看一下这两个接口,就会发现两者非常之雷同,最大的区别在于前者通过userObject持有真实的数据,而后者则是由TreeItem的getData来持有,在使用的时候,才会由相应的TreeViewer传给ITreeContentProvider,从结构来说,后者是一个纯粹的控制类,而TreeNode则是更灵活一些,可以作为一个控制类,也可以作为一个模型体,所以相对而言,TreeNode更加灵活一些,但从本质上而言,两者并无区别。

    表面上看来,一个TreeViewer将会拥有一个ITreeContentProvider用来取得树状的数据模型,进而呈现出来,但CNF中的树却更加灵活,在基础篇中,展现的图中,却表示可以通过扩展点org.eclipse.ui.navigator.navigatorContent来添加新的结点,而且这些与资源并没有本质的关系,它可以与一个具体的文件或者目录资源绑定,也可以与多个具体的文件或者目录绑定,还可以是一个与文件或者目录无关的模型。那么现在来看一下CNF到底做了哪些事情,使得它的模型扩展如此容易呢?

    首先启动Eclipse32.,然后创建一个新的工作区,再将CNF相关的代码以插件的形式导入到这个工作区中,开始我们的分析过程。

    讲到这里,要提到Eclipse提供的一个接口IWorkbenchAdapter和IWorkbenchAdapter2,这两个接口是有一点点怪的,因为从设计的角度来看,它将模型与展现层混合在一起,违反常见的设计准则,但从另一个角度来讲,它可以减少用户扩展的内容,有利于用户开发。由此可见设计准则并不是一成不变的,很多时候,它也要在易用性和合理性方面做出适当的妥协。这一点也可以在我们自己的设计中加以考虑,设计并不是要偏向哪一个方向,恰恰相反,设计是要在多者之间,如易用性,稳定性,合理性之间取得一个平衡点,而不是在各方面都做到完美。

    另外ITreeContentProvider有一个方法getParent(Object parent),它是用来为一个指定结点找到相应的父亲结点,从而便于查找和定位,而这个方法却被很多人所忽视,开发人员经常会习惯性的直接返回null,而且也不会出现什么错误,但这个方法其实却是一个非常有用的方法,开发人员在使用Java资源管理器的时候,有一个经常使用的功能就是LinkWithEditor,这个功能经常是用来在资源管理器上定位当前打开的文件,这个功能如此之重要,以至于CNF专门为此定义了一个org.eclipse.ui.navigator.linkHelper来支持该功能。所以请根据实际情况,来实现这个方法,否则就无法正确的实现相应的功能。

    以上对TreeViewer的模型进行了简单的介绍和分析,接下来就看一下CNF是如何处理树模型从而获得如此高的灵活性。

    CNF很好的利用了代理模式,它自身并没有提供模型的能力,所以它将提供模型的能力仍然交给外部扩展点提供的类,它会根据当前要处理的结点,以及每个扩展点的表达式,来找出能够处理当前结点的ITreeContentProvider实例,然后再将这些实例返回的子结点放入相应的Set中,最终以数组的方式返回给TreeViewer,从表面上来看,可能很难理解正常情况下,每个TreeViewer只有一个ITreeContentProvider的模型接口,如何能够从多个实例中取得模型呢?就是由NavigatorContentServiceContentProvider这个代理类完成模型的组合功能。

    因此只要提供自己的ITreeContentProvidre实现,然后通过扩展点挂入,即可将各种真实或者虚拟的模型挂入系统。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值