定义自己的Common Navigator

来源:互联网 发布:西安seo外包公司 编辑:程序博客网 时间:2024/06/05 17:28

http://liugang594.iteye.com/blog/153413

所谓的Navigator,可以简单的理解为Eclipse中的资源导航视图,例如:

 


Project Explorer视图

 

 

Project Explorer视图


这一系列,我们就要来实现一个类似的Navigator视图。

 

一、 定义Navigator

在开始之前,我们先了解一下做Navigator需要的扩展点:

1.     org.eclipse.ui.navigator.viewer

这个扩展点就是用来定义整个Navigator用的。例如:Navigator绑定到哪个View上;它的Content是什么;它的actions是什么;它怎么支持拖动的,等等。

这个扩展点的实质是将一些内容组合到一起来决定这个Navigator的,所以它本身几乎是不需要写代码的。

2.     org.eclipse.ui.navigator.navigatorContent

上一个扩展点,我们讲它需要有content的提供、action的提供者等等。这个扩展点就是用来提供这个用的。

当然,除了上面两个扩展点,我们也说是我们的Navigator需要绑定到一个view上,所以也需要一个org.eclipse.ui.views扩展点,因为这个扩展点比较通用,这里就不具体说了。

Navigator部分的API帮助,可以到以下包去找:org.eclipse.ui.navigator。所以显然你需要把这个插件包添加到依赖项里。

 

我们在做的时候也可以参照已有的实现:

 


图一

图一中,红色部分就是对应需要用到的两个扩展点,蓝色部分就是对应的定义了这个扩展点的插件。我们可以参考它们相应的实现来了解更多的应用方面的知识。

 

好。下面我们就来开始我们自己的Navigator。首先我们需要有一个插件工程。这个就不说了。首先我们定义一个org.eclipse.ui.views的扩展声明,如下:

   <extension        point="org.eclipse.ui.views">     <category           id="com.tibco.cdc.liugang.navigator.category"           name="Common Navigator">     </category>     <view            allowMultiple="false"            category="com.tibco.cdc.liugang.navigator.category"            class="org.eclipse.ui.navigator.CommonNavigator"            icon="icons/alt_window_16.gif"            id="com.tibco.cdc.liugang.navigator.view"            name="Sample Navigator">     </view>  </extension> 

这里需要注意的是:

class需要设定为“org.eclipse.ui.navigator.CommonNavigator”,当然你也可以定义自己的实现。一般来说都没有必要。

现在我们已经可以运行,看到一个view了:

 


图二

Ok,一个view就定义完了,下面就是我们要关注的两个扩展点的实现了。这一节,我们先讲第一个扩展点org.eclipse.ui.navigator.viewer,后两节会讲到另一个扩展点:org.eclipse.ui.navigator.navigatorContent

所以我们再定义一个org.eclipse.ui.navigator.viewer扩展声明。在继续之前我们先看一下下图:

 


图三

其中:viewerActionBinding对应于action的支持,例如选择某个对象,显示一个什么的右键菜单;viewerContentBinding对应于内容提供,就是在这navigator上显示什么内容;viewer对应的就是这个navigator要显示在哪个view上。

这一节里,我们将利用已经有的定义来充实这个扩展点。具体哪些内容可以填充,请到图一的各个实现里去找就可以了。这里我参照resources的实现(后面我们会讲到自定义实现),如下:

   <extension        point="org.eclipse.ui.navigator.viewer">     <viewer           viewerId="com.tibco.cdc.liugang.navigator.view">     </viewer>     <viewerActionBinding           viewerId="com.tibco.cdc.liugang.navigator.view">        <includes>           <actionExtension                 pattern="org.eclipse.ui.navigator.resources.*">           </actionExtension>        </includes>     </viewerActionBinding>     <viewerContentBinding           viewerId="com.tibco.cdc.liugang.navigator.view">        <includes>           <contentExtension                 pattern="org.eclipse.ui.navigator.resourceContent">           </contentExtension>        </includes>     </viewerContentBinding>  </extension> 


好,我们现在运行看看:

 


图四

OK,我们的view里已经有内容了,而且已经支持了右键菜单了。现在还不支持过滤,如果要支持一个过滤器也是容易的。我们只要加一个content声明就可以了。例如加上:

            <contentExtension                 pattern="org.eclipse.ui.navigator.resources.*">           </contentExtension> 


加上上面声明,我们就支持所有resource的实现。显示如下:

 


图五

看图五中,以“.”开始的资源已经被过滤了。并且我们也支持了一些其他的过滤和内容显示设置。

OK,我们已经初步有了一个自己的Navigator了。下面我们会逐渐的增加更多的内定。

这一节和下一节我们都将来关注另一个扩展点:

org.eclipse.ui.navigator.navigatorContent

首先我们先增加一个扩展声明,然后看看它支持什么东西:


图六

可以看到在这个扩展点下可以定义四个子元素。其中:

     actionProvider:用来定义可以action的。

     commonFilter:定义过滤器

     commonWizard:定义快捷wizard

     navigatorContent:定义内容导航

其中第一和第三个元素通常不需要扩展。而且我发现这两个扩展点几乎没有实现,很奇怪。我们一会可以看到,在navigatorContent元素也有两个同样的扩展,一般都是在这个元素里做扩展。

说了和没说一样,下面就以例子来讲解。

  1. commonFilter

先讲简单的commonFilter,很显然是用来定义过滤的。在第一节里,我们已经给我们的navigator加了resource的过滤。我们再来加一些。例如,我们想有一个过滤掉全部以pda结尾的文件。那我们可以这样实现:

<commonFilter   activeByDefault="false"   description="this used to filter all files whose extensions is  pda"    id="com.tibco.cdc.liugang.navigator.filter.pda"    name="Filter pda files">     <filterExpression>        <and>         <instanceof                    value="org.eclipse.core.resources.IFile">         </instanceof>         <test                    property="org.eclipse.core.resources.extension"                    value="pda">              </test>           </and>    </filterExpression></commonFilter>


这样我们就定义好了一个过滤器。不过我们要使用它的话,需要把它加到我们的navigator上,所以在我们第一节定义的viewer扩展点的contentBindingincludes里加上一句:

      <contentExtension       pattern="com.tibco.cdc.liugang.navigator.filter.pda">     </contentExtension> 


OK,我们已经完成了我们的过滤声明:

 


图七

图七中,当我们选中我们扩展的过滤器后,所有的pda文件都已经消失了。

 

  1. navigatorContent

下面来完成一个navigator content扩展。这个稍微有点复杂。首先我们先完成一个声明。如下

<navigatorContent            activeByDefault="true"            contentProvider="com.tibco.cdc.liugang.navigator.content.XMLTreeContentProvider"            icon="icons/alt_window_16.gif"            id="com.tibco.cdc.liugang.navigator.navigatorContent"            labelProvider="com.tibco.cdc.liugang.navigator.content.XMLLabelProvider"            name="XML Navigator Content"            priority="normal"></navigatorContent>


这里我想做的是:如果是一个xml文件,则显示它的结构。这主要是要完成contentProviderlabelProvider。我们先完成这个。代码就不贴了。可以参考附件!

 

需要注意的是:这里我们是要给xml文件加一个内容导航,因此在contentProvider里传入的有可能是IFile类型。所以我们要注意我们的contentProvider的实现方法。

 

定义完了一个内容以后,并不是会自动被显示的,我们需要给它加一个触发点。这就是要在navigatorContent下增加一个子元素“triggerPoints”,triggerPoints用来指示我们的扩展所感兴趣的内容。实际我们的触发点就是一个xml文件,因此我们可以如下实现:

<triggerPoints>     <and>         <instanceof               value="org.eclipse.core.resources.IFile">         </instanceof>         <test               forcePluginActivation="true"       property="org.eclipse.core.resources.extension"               value="xml">          </test>     </and></triggerPoints> 


其实意思就是:如果选择的是一个文件,并且文件扩展名为“xml”,则触发我们的内容导航。好了,这样就完成了我们的xml文件的内容导航,最后不要忘了把它加到我们的Navigatorviewer声明里去,如下在viewerContentBindingincludes下加上:

 

      <contentExtension           pattern="com.tibco.cdc.liugang.navigator.navigatorContent">      </contentExtension> 
 

现在我们的图如下:

 


图八

 

补充:

一个完整的内容导航,我们除了要显示它之外,还需要有一个监听机制,就是eclipse已经实现的resourceChangeListener。这样当外部有修改时,我们的内容也能显示正确。

OK,我们已经有了一个初步可运行的Navigator了,现在它看起来已经比较丰富了。不过我们在xml文件下的任意结点上点右键时,都没有菜单显示。另外假如我们有一个新的wizard,我们也想像javapackage explorer视图一样显示在new菜单的那一层。那我们应该怎么做呢?这一节就来介绍这部分的实现。

 

实际上,从上面的介绍里,很多人可能都已经知道了怎么完成这些事情。不过这里还是写一个完整的介绍过程。

 

先说一下我们的目标:在IResource对象的new菜单里,加上java project wizard。在xml文件的node上,加一个菜单用来显示它的所有属性。

 

首先我们完成第一件事。

 

增加快捷Wizard

第二节中,我们提到过,在org.eclipse.ui.navigator.navigatorContent扩展点的navigatorContent里也有两个子扩展:commonWizardactionProvider

这里要加一个wizard的快捷方式,就是需要扩展这个commonWizard。所以在上面我们扩展的navigatorContent里,我们再声明子扩展:commonWizard。如下:

         <commonWizard               type="new"               wizardId="org.eclipse.jdt.ui.wizards.JavaProjectWizard">           <enablement>              <instanceof                    value="org.eclipse.core.resources.IResource">              </instanceof>           </enablement>        </commonWizard> 

 

有三种类型的wizard,这里我们选择new;然后就是指定wizardId,这里我们指定为java project wizardID;最后就是定义出现在条件,这里定义的条件就是如果选择的对象为IResource对象,则出现。

最后我们的图如下:


图九

 

显然你可以很简易的推到其他两种类型wizard的快捷定义。

 

增加自定义菜单

现在看我们的XML下的那些结点,点右键时没有菜单显示。这里我们就给他们加一个显示值的菜单。

要实现自定义菜单,我们就需要扩展和上面的commonWizard在同一级的actionProvider。先看一下我们的声明:

        <actionProvider              class="com.tibco.cdc.liugang.navigator.actions.LiugangCommonActionProvider"              id="com.tibco.cdc.liugang.navigator.navigatorContent.actions">            <enablement>              <instanceof                     value="org.w3c.dom.Node">              </instanceof>           </enablement>        </actionProvider> 


 

这里有五个属性定义,不过我们需要关心的只有上面两个:class用来定义实现类;id唯一标识这个actionProvider。然后我们加了一个可用的约束条件:选择的对象需要是一个Node实例。

 

定义完actionProvider之后,我们就要注册这个actionProvider了。在我们的viewer扩展的viewerActionBindingincludes下面加一句就行了:

 <actionExtension             pattern="com.tibco.cdc.liugang.navigator.navigatorContent.actions"></actionExtension>
 

好,接下来我们先完成实现类,如下:

public class LiugangCommonActionProviderextends CommonActionProvider {  private ActionpropertyAction;  private ICommonViewerSiteviewSite;  public LiugangCommonActionProvider() {  }  @Override  public void init(ICommonActionExtensionSite site) {         super.init(site);         viewSite = site.getViewSite();         propertyAction =new Action("Show Property") {               @Override               publicvoid run() {                      IStructuredSelection selection = (IStructuredSelection) viewSite                                   .getSelectionProvider().getSelection();                      Object firstElement = selection.getFirstElement();                      if (firstElement instanceof Node) {                            Node selectedNode = (Node) firstElement;                            MessageDialog.openInformation(viewSite.getShell(),                                          "Property", getAllAttributes(selectedNode));                      }               }         };  }  @Override  public void fillContextMenu(IMenuManager menu) {         menu.add(propertyAction);  }  private String getAllAttributes(Node node) {         NamedNodeMap attributes = node.getAttributes();         String content ="<";         for (int i = 0; i < attributes.getLength(); i++) {               Node item = attributes.item(i);               content += item.getNodeName() +"=" + item.getNodeValue() + " ";         }         content +=">";         return content;  }} 


看起来像是我们已经完成了所有的过程。不过如果此时我们在node上点右键的话,并不出现右键菜单。为什么呢?

 

这里我们需要提到另一个扩展元素:possibleChildren。它和triggerPoints在同一层。

这个扩展元素指出我们的内容扩展中的哪些结点类型可以指供labelparent。如果你要实现editor link或者是想使得setSelection()方法可用,则必须提供这个扩展元素的声明。

 

这里,对应于我们点右键菜单,显然我们应该使得setSelection()方法可用,这样才能知道我们在资源树上选择了哪个node结点,最后传到我们的actionProvider的实现。完成我们的右键菜单。这里我们可以如下声明:

         <possibleChildren>           <or>              <instanceof                    value="org.w3c.dom.Node">              </instanceof>           </or>        </possibleChildren> 


最后效果如下:

 


图十

package com.tibco.cdc.liugang.navigator.content;import org.eclipse.jface.viewers.ILabelProvider;import org.eclipse.jface.viewers.LabelProvider;import org.eclipse.swt.graphics.Image;import org.eclipse.ui.navigator.IDescriptionProvider;import org.w3c.dom.Node;import com.tibco.cdc.liugang.navigator.Activator;public class XMLLabelProvider extends LabelProvider implements ILabelProvider,IDescriptionProvider {@Overridepublic Image getImage(Object element) {if(element instanceof Node){return Activator.getImageDescriptor("icons/alt_window_16.gif").createImage();}return super.getImage(element);}@Overridepublic String getText(Object element) {if(element instanceof Node){return ((Node)element).getNodeName();}return super.getText(element);}public String getDescription(Object anElement) {return "This is a test for navigator content!";}}


package com.tibco.cdc.liugang.navigator.content;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.List;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import org.eclipse.core.resources.IFile;import org.eclipse.jface.viewers.ITreeContentProvider;import org.eclipse.jface.viewers.Viewer;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.xml.sax.SAXException;public  class XMLTreeContentProvider implements ITreeContentProvider {public Object[] getChildren(Object parentElement) {if(parentElement instanceof IFile){return getElements(parentElement);}else if(parentElement instanceof Node){NodeList childNodes = ((Node)parentElement).getChildNodes();List<Node> children = new ArrayList<Node>();for(int i=0;i<childNodes.getLength();i++){Node item = childNodes.item(i);if(item.getNodeType()!=Node.TEXT_NODE){children.add(item);}}return children.toArray();}return null;}public Object getParent(Object element) {if(element instanceof Node){return ((Node)element).getParentNode();}return null;}public boolean hasChildren(Object element) {//if(element instanceof Node){//return ((Node)element).getChildNodes().getLength()==0?false:true;//}return true;}public Object[] getElements(Object inputElement) {if (inputElement instanceof IFile) {try {InputStream is = ((IFile) inputElement).getContents();Element element = parseXML(is);is.close();return new Object[] { element };} catch (Exception e) {return null;}}return null;}private Element parseXML(InputStream is)throws ParserConfigurationException, SAXException, IOException {DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();Document document = db.parse(is);Element documentElement = document.getDocumentElement();return documentElement;}public void dispose() {}public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}}



原创粉丝点击