定义自己的Common Navigator

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扩展点的contentBinding的includes里加上一句:

      <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文件,则显示它的结构。这主要是要完成contentProvider和labelProvider。我们先完成这个。代码就不贴了。可以参考附件!

 

需要注意的是:这里我们是要给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文件的内容导航,最后不要忘了把它加到我们的Navigator的viewer声明里去,如下在viewerContentBinding的includes下加上:

 

      <contentExtension

           pattern="com.tibco.cdc.liugang.navigator.navigatorContent">

      </contentExtension> 
 

现在我们的图如下:

 


图八

 

补充:

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

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

 

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

 

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

 

首先我们完成第一件事。

 

增加快捷Wizard

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

这里要加一个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 wizard的ID;最后就是定义出现在条件,这里定义的条件就是如果选择的对象为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在同一层。

这个扩展元素指出我们的内容扩展中的哪些结点类型可以指供label和parent。如果你要实现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 {

	@Override
	public Image getImage(Object element) {
		if(element instanceof Node){
			return Activator.getImageDescriptor("icons/alt_window_16.gif").createImage();
		}
		return super.getImage(element);
	}
	
	@Override
	public 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) {

	}

}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值