nighty

折腾的年华
posts - 37, comments - 143, trackbacks - 0, articles - 0

RssOwl2源码阅读 -- ActionSet

Posted on 2008-08-21 11:29 寒武纪 阅读(1719) 评论(0)  编辑  收藏 所属分类: Eclipse
    ActionSet是Eclipse RCP里面一非常重要的概念,因为菜单、工具栏、上下文菜单、状态栏很多操作都是共享的,所以Action就是用来处理重复出现的东西。至于Eclipse里面定义ActionSet有非常多的技巧,可能无法一一列举,而且使用方法也多种多样。下面介绍的是RssOwl2项目的ui源代码部分的一小块。
   1.  菜单的插入点 -- GroupMarker和Separator的使用
        ApplicationActionBarAdvisor类是定义全局所有Action插入点和入口,查看fillMenuBar(IMenuManager)方法,为了简化,以其中的辅助方法createFileMenu(IMenuManager)为例,讲述一下实现菜单“文件”的内容,先看一下菜单的结构

       像Close,Import...之类的非常简单,看一下它是如何实现New这个子菜单的。首先看一下它的源代码如何定义插入点
     
/* Menu: File */
  
private void createFileMenu(IMenuManager menuBar) {
    MenuManager fileMenu 
= new MenuManager("&File", IWorkbenchActionConstants.M_FILE);
    menuBar.add(fileMenu);

    fileMenu.add(
new GroupMarker(IWorkbenchActionConstants.FILE_START));
    fileMenu.add(
new GroupMarker(IWorkbenchActionConstants.NEW_EXT));
    fileMenu.add(
new Separator());

    fileMenu.add(getAction(ActionFactory.CLOSE.getId()));
    fileMenu.add(getAction(ActionFactory.CLOSE_ALL.getId()));
    fileMenu.add(
new GroupMarker(IWorkbenchActionConstants.CLOSE_EXT));
    fileMenu.add(
new Separator());
    fileMenu.add(getAction(ActionFactory.SAVE_AS.getId()));
    fileMenu.add(
new GroupMarker(IWorkbenchActionConstants.SAVE_EXT));
    fileMenu.add(
new Separator());
    fileMenu.add(getAction(ActionFactory.PRINT.getId()));

    fileMenu.add(
new Separator());
    fileMenu.add(
new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));

    fileMenu.add(fReopenEditors); 
// TODO Consider moving into a "Go" Menu!

    fileMenu.add(
new Separator());
    fileMenu.add(
new GroupMarker(IWorkbenchActionConstants.FILE_END));
    fileMenu.add(
new Separator());

    fileMenu.add(getAction(ActionFactory.QUIT.getId()));
  }
       其中有一行fileMenu.add(new GroupMarker(IWorkbenchActionConstants.NEW_EXT)); 这里是定义一个GroupMarker作为组标记,把子菜单New容纳进来。这个NEW_EXT的值是:new.ext
      现在跳回到plugin.xml去看一下它的ActionSet定义,结构如下:
,点击New(menu),它的path值为:file/new.ext,这个路径就是在createFileMenu方法定义的路径,第一个是“File”本身的ID。也就是把子菜单New(menu)插入到指定的那个GroupMarker,ID为new.ext。然后定义了三个ID分别为bookmark,newsbin,searchmark,的groupmarker和一个folder的separator,这个三ID分别就对应上面actionSet定义的三个action,以其中的Bookmark(action)为例,它的menubarPath为:file/new_sub/bookmark,代表插入到"File"主菜单中定义的new_sub子菜单中,new_sub是New(menu)的ID。因为folder是定义为separator,所以它会有一条分隔线。这只是RssOwl的定义方法,其实以前自己做开发的时候是没有这样定义的,而且把子菜单New也写在方法fillMenuBar中的,菜单把ID都写在里面,ActionSet的配置就没有子菜单出现了,但是这样定义看起来就比较乱。采用这种写法感觉比较简洁。
    2.  Action的实现
       仍以bookmark为例,它的实现类是NewBookMarkAction,实现了IWorkbenchWindowActionDelegate, IObjectActionDelegate二个接口,第一个是ActionSet指定实现接口,第二个是对象操作菜单要求实现的接口(但事实发现没有再定义它的配置,可能是internal版本的原因),也就是说这个Action是多功能,它将会出现在主菜单,工具栏,和局部的右键菜单上。主菜单和工具栏的位置都在ActionSet配置定义了,看看它的右键菜单实现是在哪里的,这个右键是在视图Bookmarks定义的,那么跳转到org.rssowl.ui.internal.views.explorer.BookMarkExplorer类去看看。里面有一个hookContextualMenu()方法,就是定义它的右键菜单的,看一下代码实现:
private void hookContextualMenu() {
    MenuManager manager 
= new MenuManager();

    
/* New Menu */
    MenuManager newMenu 
= new MenuManager("New");
    manager.add(newMenu);

    
/* New BookMark */
    newMenu.add(
new Action("Bookmark"{
      @Override
      
public void run() {
        IStructuredSelection selection 
= (IStructuredSelection) fViewer.getSelection();
        IFolder parent 
= getParent(selection);
        IMark position 
= (IMark) ((selection.getFirstElement() instanceof IMark) ? selection.getFirstElement() : null);
        
new NewBookMarkAction(fViewSite.getShell(), parent, position).run(null);
      }


      @Override
      
public ImageDescriptor getImageDescriptor() {
        
return OwlUI.BOOKMARK;
      }

    }
);

   
//其它定义
}
     原来实现也很简单,只是往MenuManager里面添加一个Action而已,而且run方法就是直接调用定义好的NewBookMarkAction的run方法,但是把选中对象做为参数传进去,因为这个new是涉及当前上下文选择对象的。
    3. 下拉类型的工具按钮定义
    非常常见的Dropdown类型的工具栏按钮可以把功能类型的按钮归为一类,做成一个下拉菜单形式,有默认的按下功能,也有可以选择其它类似功能的下三角形式,样子如下:

    这个dropdown的Action是定义在ActionSet配置里的。style是pulldown类型的,所以实现类NewTypeDropdownAction实现了IWorkbenchWindowPulldownDelegate接口,它的run方法就是定义默认点击不做选择时的事情,这个下拉菜单是实现getMenu(Control parent)方法而来,它定义了如何生成这个菜单,这就用到了最原始的SWT中的MenuItem了,并且为它们添加SelectionListener,方法实现,不用说都知道了,又是New一个先前定义好的NewBookMarkAction类,然后又是调用它的run方法。所以总结一下,Action的重用不一定是这个类的重用,关键是它的run方法的重用,在不同的场景下它的外在表现形式可能会多种多样,但是它的run内容是一致的。像添加这种添加的run大部分时候都是弹出一个对话框,而对话框大都又是Winzard类型的,因为Winzard可以共享放到dialog里面。所以这种复用的思想在Eclipse里面随处可见。
   归结一下,其实这些技巧都是次要的,因为做GUI一个比较痛苦的事情就是经常要写很多重复类似的代码,抽取的不好,可能就变得不伦不类了。怎么利用它的这种思想,把复用的代码都抽取在一起,而阅读起来又比较轻松才是关键。
   知道的就这些,先介绍到这里,下次再谈谈其它新的发现。


刚进场的时候戏就落幕

只有注册用户登录后才能发表评论。


网站导航: