在Eclipse插件开发中, 实现标准的Search功能

来源:互联网 发布:淘宝怎么一件代发 编辑:程序博客网 时间:2024/05/16 20:29
 ------------------------------------------------------------
        在Eclipse插件开发中, 实现标准和Search功能

------------------------------------------------------------

1 说明

  使用过eclispe进行开发的Developer,估计都对其中的方便而强大的查找功能留下过不错的影像吧. 漂亮的界面, 强大的查找功能, 丰富的查找结果, 人性化的结果展示, 以及方便的定位等等. 呵呵, 如果你的应用程序中要查找并显示结果给用户, 那做的和标准的eclipse一样, 那一定很爽吧. 下面就对在实现的过程中的一点体会分享给大家.

  感谢pingpangsong写的文章, 在我茫然不知如何入手的时候, 给了启发. 文章地址:
  http://pingpangsong.javaeye.com/blog/42925
 
2 需要扩展的Extention

  org.eclipse.search.searchPages
  扩展,实现查找的查找条件输入页面

  org.eclipse.search.searchResultSorts
  扩展,实现查找结果的排序

  org.eclipse.search.searchResultViewPages
  扩展,实现查找结果在标准SearchView中展示

 
3 原理剖析

  3.1 接口介绍

  在一个标准的查找功能中, 至少我们要实现如下一些类或接口
  ISearchQuery.java
  ISearchResult.java
  ISearchResultPage.java
 
  Match.java

  Action.java

  NewSearchUI.java

  前三个接口是Eclipse查找框架的接口, 搭建了一个数据流程, 将数据的查找, 传递, 展示结合起来. 用户所要用的就是实现这些接口,并将生成合适的数据. 其它的事Eclipse帮助我们完成.

  第3个Match.java是查找结果的表示, 所有查找的结果将以一个个Match的形式存储到SearchResult中. 在这些Match中Eclipse提供了一些公用的方法如定位信息等.

  第4个Action.java很明显就是查找的启动入口了, 用户实现它,在合适的时机将触发动作, 完成查找并展示结果.

  第5个NewSearchUI.java是Eclipse的标准查找界面类, 提供了方法用于启动查找, 打开(或激活)查找视图等. 通常这个类在Action中使用(或在条件输入页面的OK Button被触发后使用, 以启动查找.

  3.2 数据流程介绍

  下面介绍一下整个查找过程的数据流程, 以帮助比我更菜的人更好的理解Search框架.

  一个查找通常以一个Action触发开始, 在Action.run()中, 实现对查找条件的判断等, 并生成SearchQuery对象(继承自ISearchQuery). 然后使用NewSearchUI.activateSearchResultView(), 激活SearchView, 这个时候在那个标准和SearchView就已经出现在工作台最前面了. 然后用户调用NewSearchUI.runQuery(query); 函数来为我们的SearchView生成要展示的数据.

  下面的事基本都交给框架来完成, 我们只要实现必要的接口函数就OK了. 在上面使用NewSearchUI的runQuery()后, 系统会开始一个线程在后台(或前面)运行我们的ISearchQuery.run()函数, 以完成查找匹配数据的过程. 所以自己的SearchQuery要函数自ISearchQuery函数, 并在run方法中实现自己的查找结果的形成.

  查找结果必需存储在一个叫ISearchResult的类型中. 这个类事实上没有其它的大作用, 就是将用户查找的结果起个头封闭一下, 同时给查找结果在界面上展示时的标题,图标等进行一下设置. 无论用户的查找结果是层次的树壮结构还是扁平的表结果的, 都需要自己实现相应的表示结构. 在框架中对于每一个查找结果项的表示也必须从Match继承, Match提供了部分接口方法, 可以使框架方便的进行定位, 当然用户可以实现自己的定位. 对于每一个Match项, 用户可以实现自己的类, 从而体现自己查找结果的层次关系. 在SearchQuery中, 查找到结果,并将这些结果按一定的方式组织起来, 最后存放到SearchResult中.
  有了查找结果后就要显示了. 这时候我们写的SearchResultPage就要起作用了. 框架会自动的初始化它, 并根据构造参数在Page中使用TreeView或TableView来显示查找结果. Page要显示的数据SearcuResult这时候会由框架自动传递到Page中来. 为了正确且漂亮的显示数据, 通常我们还会提供自己的ContentProvider和LabelProvider.

  上面基本就中一个标准的Search的数据流程. 下面具体的介绍一下各个接口类及函数的作用.

4 详细解析

  4.1 ISearchQuery

  此接口有如下几个方法.
  IStatus run(IProgressMonitor monitor);
  String getLabel();
  boolean canRerun();
  boolean canRunInBackground();
  ISearchResult getSearchResult();

  其中getLabel(), canRerun(), canRunInBackground()顾名思义, 很简单的. 剩下的getSearchResult()是提供给框架使用, 来获取查找结果SearchResult的. 最为重要的一个就是run()函数, 用户重载这个函数,在其中实现查找结果的生成. 如

  IStatus run(IProgressMonitor monitor)
  {
       queryResult = getQueryResult();

      monitor.beginTask("Search Something", 1000);
      // do something
      // queryResult.addMatch(xxxx);
      monitor.worked(100);

      // do something
      // queryResult.addMatch(xxxx);
      monitor.done();
  }

 
  4.2 ISearchResult

  此接口中的方法都很简单, 看名称就可以知道是干什么用的了.
  ISearchQuery getQuery();
  这个函数返回的即是生成了本Result的那个SearchQuery. 这样Query和Result就形成了一个环, 知道任何一个就可以获取到对方.

  4.3 ISearchResultPage

  通常我们不直接从此类继承, 而是从AbstractTextSearchViewPage类继承, 因为对于大多数查找来说, AbstractTextSearchViewPage基类已经将SearchResultPage封闭的很好了, 我们只要重载其中的部分函数, 实现我们自有的特色就OK了, 没必要从头再实现一个View. 对于AbstractTextSearchViewPage来说, 继承后有如下几个函数可能人重写:

  protected void configureTreeViewer(TreeViewer viewer) 配置我们风格的TreeViewer
  protected void configureTableViewer(TableViewer viewer) 配置我们风格的TableViewer
  protected void showMatch(Match match, int currentOffset, int currentLength, boolean activate) 重载此方法, 实现自己的匹配项的定位.

  4.4 显示
 
  一个好的View显示当然是非常重要的, 由于我们的SearchResultViewer使用了TableViewer或TreeViewer, 所以有必要为其配置ContentProvider和 LabelProvider. 分别从ITreeContentProvider和 ILabelProvider继承. 需要注意的一点就是传入ITreeContentProvider.getElements( Object inputElement)中的InputElement就是我们在Query中生成的SearchResult, 根据这个SearchResult就可以得到其中存储的有层次(或无层次)的Match

  4.5 匹配项

  匹配项从Match继承. 每个查找匹配结果都要封闭到一个Match中. 如我们的查找结果有层次,那可以实现这样一个Match

  public class MyMatch extends Match
  {
      private MyMatch parent;

      private List children;
     
      // some functions
  }

 
5 备注:

  最后, 完成了所有的类后, 千万别忘记了在plugin.xml中向系统注册(扩展eclipse扩展点)实现的类:-)