0
回答
如何为 Editor 开发 Eclipse Outline 视图
科大讯飞通用文字识别100000次/天免费使用。立即申请   

在基于 Eclipse 插件的应用中,我们时常能够看到 Outline 视图的身影,它是 Eclipse 框架提供的一个内建视图,能够将编辑器 (Editor) 中的内容以结构化大纲或者缩略图的方式展于给用户。例如,Java Development Tool (JDT) 中的方法和属性大纲,GMF Editor 的 Diagram 的缩略图。由于应用的需求及展示的内容不同,开发者需要为编辑定制属于自己的 Outline 视图。本文将对 Eclipse Outline 视图页面接口进行介绍说明,并以实例的方式帮助读者为 Editor 开发 Outline 视图页面。

Eclipse Outline 视图介绍

在 Eclipse 框架中,每个编辑器和 Outline 视图间有种特殊的关系。当编辑器打开时,Outline 视图会被关联到编辑器,如果编辑器为 Outline 视图提供了一个模型,该模型就会在 Outline 视图中显示,无论编辑器是否处于活动状态,Outline 视图可以用来浏览内容,或者是在更高抽象层上与编辑器的内容进行交互。

使用过 Java Development Tool (JDT) 的程序员,对 Outline 视图不会陌生。例如,当我们打开在编辑器中打开一个 java 类文件,Outline 视图中就会显示类中的成员变量,函数等(如下图所示)。当在 Outline 视图中选中某个元素时,该元素在 Java 编辑中所对应的模型元素也将被高亮选中,如图 1 所示。


图 1. JDT Java Editor 对应的 Outline 视图
图 1. JDT Java Editor 对应的 Outline 视图

同时,随着当前编辑器的变化,Outline 视图中的工具栏与上下文菜单将随之发生变化,以便于对编辑器内容进行操作。当编辑器中的数据太多而无法在有限的屏幕范围内显示时,或者当编辑器的内容为非 结构化时 ( 如文本,图 ),Outline 视图能够有效地提供一个结构化的模型,并以概念角度来帮助用户操作定位、编辑器中内容元素。


图 2. Outline 视图的工具栏及上下文菜单
图 2. Outline 视图的工具栏及上下文菜单

Outline View 接口说明

Outline 视图是 Eclipse 框架提供的默认视图之一,其实现类 ContentOutline 定义于 org.eclipse.ui.views 中,继承 PageBookView,并实现 ISelectionProvider,ISelectionChangedListener 接口,其视图 id 为 org.eclipse.ui.views.ContentOutline。只由 Eclipse 工作台窗口负责实例化,用户不能继承或者实例化该类,那么如何将用户开发的 Editor 关联到 Outline 视图呢,这就要能过 Adapters 模式。当编辑器被激活时,Outline 视图会试图通过 IAdaptable 的 getAdapter() 方法从编辑器中获得一个 ContentOutlinePage,当编辑器能够返回该 page 时,该 page 被添加到 Outline 视图中,否则,Outline 视图将会展示默认的空闲页面。


清单 1. View 的定义
				
 <plugin> 
   
     <extension 
         point="org.eclipse.ui.views"> 
      <view 
            name="%Views.PropertySheet"
            icon="$nl$/icons/full/eview16/prop_ps.gif"
            category="org.eclipse.ui"
            class="org.eclipse.ui.views.properties.PropertySheet"
            id="org.eclipse.ui.views.PropertySheet"> 
      </view> 
      <view 
            name="%Views.ContentOutline"
            icon="$nl$/icons/full/eview16/outline_co.gif"
            category="org.eclipse.ui"
            class="org.eclipse.ui.views.contentoutline.ContentOutline"
            id="org.eclipse.ui.views.ContentOutline"> 
      </view> 
   </extension> 
   
 </plugin> 

 protected PageRec doCreatePage(IWorkbenchPart part) { 
    // Try to get an outline page. 
    Object obj = ViewsPlugin.getAdapter(part, IContentOutlinePage.class, false); 
    if (obj instanceof IContentOutlinePage) { 
        IContentOutlinePage page = (IContentOutlinePage) obj; 
        if (page instanceof IPageBookViewPage) { 
            initPage((IPageBookViewPage) page); 
        } 
        page.createControl(getPageBook()); 
        return new PageRec(part, page); 
    } 
    // There is no content outline 
    return null; 
 } 

编辑器所提供的每个 Outline page 都必须实现 org.eclipse.ui.views.contentoutline.IContentLinePage 接口,该接口继承 IPage 和 ISelectionProvider 接口,其常用到的的方法的介绍如下:

org.eclipse.ui.part. IPage:

  • public void createControl(Composite parent): 用于创建 Content outline page 中的 UI,该方法由 Eclipse workbench 调用。
  • public void setActionBars(IActionBars actionBars):在视图中为 page 定制工具栏,当 page 被设定为 visible 时,工具栏将随之变成可见。
  • public void setFocus():用于设置 page 中的焦点。

org.eclipse.jface.viewers.ISelectionProvider:

  • public void addSelectionChangedListener(ISelectionChangedListener listener): 为 content outline page 添加 SeletionChangeListener, 用于监听 page 中的选择焦点变化事件。
  • public ISelection getSelection():获得当前被选中的元素。
  • public void removeSelectionChangedListener( ISelectionChangedListener listener): 将注册在 content outline page 上的监听器移除。
  • public void setSelection(ISelection selection):设置所选中的元素。

定制 Outline 视图开发实例

本节将通过实现一个简单的 XML 文档编辑器及其 Outline Page 来说明如何为 Editor 开发其 Outline 视图。图 3 展示了实例完成时的效果,图片左侧为一个简单的 XML 文本编辑器,右侧的 Outline 视图将文档的 XML 结点以树型的方式展现出来。


图 3. XML Editor 及 Outline 视图
图 3. XML Editor 及 Outline 视图

第一步,构建 XML 文档编辑器。XML 文档用来存储、传送及携带数据信息,不用来表现及展现数据。因此在本文的例子中的,我们将 XML 文档编辑器视为一个文本编辑器,通过继承 org.eclipse.ui.editors.text.TextEditor 来实现我们自己的 XML 编辑器。同时我们通过 org.eclipse.core.contenttype.contentTypes 扩展点为 xml 文件绑定为我们自定义的一种内容类型,并将其绑定到我们的新建的编辑器上,当打开后缀为 .xml 的文件时,该编辑器将会被初始化。


清单 2. Editor 扩展点定义
				
 <plugin> 

   <extension 
         point="org.eclipse.ui.editors"> 
      <editor 
            class="cn.com.hf.outline.editor.XMLEditor"
            default="true"
            extensions="xml"
            id="cn.com.hf.outline.XMLEditor"
            name="XMLEditor"> 
         <contentTypeBinding 
               contentTypeId="cn.com.hf.outline.xmlfile"> 
         </contentTypeBinding> 
      </editor> 

   </extension> 
   <extension 
         point="org.eclipse.core.contenttype.contentTypes"> 
      <content-type 
            id="cn.com.hf.outline.xmlfile"
            name="XMLFile"
            priority="high"> 
      </content-type> 
      <file-association 
            content-type="cn.com.hf.outline.xmlfile"
            file-extensions="xml"> 
      </file-association> 
   </extension> 

 </plugin> 

第二步,我们该为 Editor 构建 Content Outline Page,用于在 Outline 视图中展于 Editor 中的内容元素。作为 Outline Page,我们需要实现 IContentOutlinePage 接口。我们可以将 XML 文档中的数据构造成一个树型的结构。因此,我们采用 TreeViewer 作为我们 Outline Page 中的主要的 UI 元素。Eclipse 框架为我们提供了一个默认的包含树状视图的 ContentOutlinePage,该类为抽象类,我们通过继承该类来实现我们需要的大纲视图页面。


清单 3. XMLOutlinePage.java
				
 public class XMLOutlinePage extends ContentOutlinePage{ 
    @Override 
    public void createControl(Composite parent) { 
        super.createControl(parent); 
        this.getTreeViewer().setLabelProvider(new XMLOutlineLabelProvider()); 
        this.getTreeViewer().setContentProvider(new XMLOutlineContentProvider()); 
    } 
 } 

大纲页面中的树型控件所展现的为 XML 文档的数据结点,我们为 TreeViewer 提供 ContentProvider 和 LabelProvider,用于遍历结点元素和显示结点的名称。


清单 4. XMLOutlineContentProvider 和 XMLOutlineLabelProvider
				
 public class XMLOutlineContentProvider implements ITreeContentProvider { 

    @Override 
    public Object[] getElements(Object inputElement) { 
        Element root = (Element)inputElement; 
        return root.getChildren().toArray(); 
    } 

    @Override 
    public Object[] getChildren(Object parentElement) { 
        Element parent = (Element)parentElement; 
        return parent.getChildren().toArray(); 
    } 

    @Override 
    public Object getParent(Object element) { 
        return ((Element)element).getParent(); 
    } 

    @Override 
    public boolean hasChildren(Object element) { 
        return ((Element)element).getChildren().size() > 0; 
    } 

 } 

 public class XMLOutlineLabelProvider implements ILabelProvider { 

    @Override 
    public Image getImage(Object element) { 
        // TODO Auto-generated method stub 
        return null; 
    } 

    @Override 
    public String getText(Object element) { 
        return ((Element)element).getAttributeValue("name"); 
    } 

 } 

第三步,将我们的 XML 编辑器与实现的大纲页面关联起来,如下表所示,在 getAdapter() 方法中,当传入的参数为 IContentOutlinePage 时,说明 Outline 视图向 Editor 查询大纲页面,当函数的返回不为空时,大纲视图将会把页面展现出来。


清单 5. XMLEditor getAdapter 接口
				
 public class XMLEditor extends TextEditor{ 

    @Override 
    public Object getAdapter(Class adapter) { 
        if (adapter == IContentOutlinePage.class) { 
            Element root = this.getRootElement(); 
            if (root != null) { 
                XMLOutlinePage page = new XMLOutlinePage(root); 
                this.addListenerObject(page); 
                return page; 
            } 
        } 
        return super.getAdapter(adapter); 
    } 

 } 

我们的编辑器是以文本的方式显示 XML 内容,因此我们需要将文本解析成 XML 文档元素,才能将其显示在大纲的树型结点上。在本文的例子中,我们使用 JDOM 类库来解析 XML 文档,我们提供的源代码中包含了该类库,读者也可以通过其官方网站进行下载。


清单 6. XML Editor 的实现
				
 public class XMLEditor extends TextEditor{ 

    public Element getRootElement(){ 
        try { 
            IDocument doc = this.getDocumentProvider().getDocument( 
                this.getEditorInput()); 
            String text = doc.get(); 
            SAXBuilder builder = new SAXBuilder(); 
            Reader in = new StringReader(text); 
            if (builder != null) { 
                Document document = builder.build(in); 
                Element root = document.getRootElement(); 
                return root; 
            } 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
        return null; 
    } 

 } 

 public class XMLOutlinePage extends ContentOutlinePage 

    public XMLOutlinePage (Element root){ 
        this.root = root; 
    } 

    @Override 
    public void createControl(Composite parent) { 
        super.createControl(parent); 
        this.getTreeViewer().setLabelProvider(new XMLOutlineLabelProvider()); 
        this.getTreeViewer().setContentProvider(new XMLOutlineContentProvider()); 
        this.getTreeViewer().setInput(root); 
    } 
 } 

第四步,为 XML 编辑器注册监听器。当 Editor 的文本发生变化时,Editor 会产生一个属性名为 IEditorPart.PROP_DIRTY 的事件,表明内容被修改,此时,注册在该属性上的监听器就会被调用。我们将 Outline 页面实现为 IEditorPart.PROP_DIRTY 类型的监听器,当文本内容变化时,页面上树型结点也将发生相应的变化。


清单 7. 将 XMLOutlinePage 关联到 XMLEditor
				
 public class XMLOutlinePage extends ContentOutlinePage implements IPropertyListener{ 
    @Override 
    public void propertyChanged(Object source, int propId) { 
        if(propId == IEditorPart.PROP_DIRTY){ 
            this.getTreeViewer().setInput(((XMLEditor)source).getRootElement()); 
        } 
    } 
 } 

 public class XMLEditor extends TextEditor { 
    @Override 
    public Object getAdapter(Class adapter) { 
        if (adapter == IContentOutlinePage.class) { 
            Element root = this.getRootElement(); 
            if (root != null) { 
                XMLOutlinePage page = new XMLOutlinePage(root); 
                this.addListenerObject(page); 
                return page; 
            } 
        } 
        return super.getAdapter(adapter); 
    } 
 } 

第五步,为 Outline 视图添加工具栏按钮。大纲页面中的结点元素的按列序列是按照其在 XML 文档中出现的先后顺序排列的,这样用户在查找起来就相当的不方便,因此我们可以在 Outline 视图上添加一个排序按钮,将大纲页面中元素按其名称的字母序进行排列,以方便查找。

首先我们在 XMLOutlinePage 中创建一个内部类 SortAction,其作用是给大纲页面的 TreeViewer 设置排序器,主要代码如下所示。在 valueChange() 方法中,当我们选中排序按钮时,为其添加一个字母序的按排序器,否则排序器默认为空,元素按其在文档中出现的顺序排列。


清单 7. SortAction
				
 private ViewerComparator lexComparator = new ViewerComparator(new LexComparator()); 

 private class SortAction extends Action{ 
 
    public SortAction() { 
        super(); 
        this.setId("cn.com.hf.outline.page.sortAction"); 
        this.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin( 
                "XMLEditorOutline", "icons/alphab_sort_co.gif")); 
        this.setDisabledImageDescriptor(AbstractUIPlugin 
                .imageDescriptorFromPlugin("XMLEditorOutline", 
                        "icons/alphab_sort_co_dl.gif")); 
        this.setEnabled(true); 
        this.valueChange(false); 
    } 

    @Override 
    public void run() { 
        this.valueChange(isChecked()); 
    } 

    private void valueChange(final boolean on) { 
        this.setChecked(on); 
        final TreeViewer viewer = getTreeViewer(); 
        BusyIndicator.showWhile(viewer.getControl().getDisplay(), 
                new Runnable() { 
                    public void run() { 
                        if (on){ 
                            viewer.setComparator(lexComparator); 
                        } else { 
                            viewer.setComparator(null); 
                        } 
                    } 
        }); 
    } 
 } 

接着,我们能过 pageSite 获得 Outline 视图工具栏实例,将 SortAction 添加到工具栏中。pageSite 是大纲页面与外部 UI 元素进行通信的桥梁,当 Outline 页面初始化时,workbench 会初始化 OutlinePage 的 pageSite 属性,此时,通过 pageSite 就可以获得外部的 UI 元素,如上下文菜单按钮,工具栏等,对页面进行定制。


清单 8. 为 OutlinePage 创建 UI 元素
				
 public class XMLOutlinePage extends ContentOutlinePage implements IPropertyListener{ 
    public void createControl(Composite parent) { 
        super.createControl(parent); 
        this.getTreeViewer().setLabelProvider(new XMLOutlineLabelProvider()); 
        this.getTreeViewer().setContentProvider(new XMLOutlineContentProvider()); 
        this.getTreeViewer().setInput(root); 

        bar = this.getSite().getActionBars(); 
        bar.getToolBarManager().add(new SortAction()); 
        bar.updateActionBars(); 
    } 
 } 

总结

本文将对 Eclipse Outline 视图页面接口进行介绍说明,并通过一个简单的 XML 编辑器实例的实现对其实现方法进行说明,定制 Outline 视图页面。通过 Eclipse 框架提供的接口,用户在开发的时候只需通过适配器模式和监听器模式完成两者之前的交互,而不必关心框架对他们是如何进行调用的,从而大大降低了模块间的耦 合性。

下载源码和查看原文: IBM developerWorks

 

举报
IBMdW
发帖于7年前 0回/1K+阅
顶部