Eclipse 3.X的selection机制

本文详细介绍了Eclipse中WorkBench、WorkBenchWindow、WorkBenchPage等核心概念及其相互之间的关系,并深入探讨了Eclipse中Selection机制的工作原理,包括如何通过监听器实现选择变化的响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 要想搞清楚Eclipse的selection机制,首先要对Eclipse的WorkBench和它的结构有一个清晰的认识。

下面是我画的一张图,原图在这里:http://www.eclipse.org/articles/Article-UI-Workbench/workbench.html

一般来说WorkBench有一个WorkBenchWindow,一个WorkBenchWindow有一个WorkBenchPage,一个WorkBenchPage有一个

EditManager,ViewFactory和多个Perspective,ViewFactory是通过引用计数来管理ViewReference的,只有引用计数为0时,对应的View才会被dispose掉。

2. 什么是part

WorkBenchPage中的所有Editor和View是part. 见下图:

ViewReference和EditorReference都继承自WorkbenchPartReference,WorkbenchPartReference有对应的WorkbenchPart和PartPane;

因为Eclipse是lazy初始化的,所有有时WorkbenchPartReference中的WorkbenchPart是空;

PartPane是用来管理给part绘制界面组件的;

PartPane通过给control添加SWT.Activate事件来更新page的active part;

org.eclipse.ui.internal.PartPane的handleEvent方法:

    public void handleEvent(Event event) {
        if (event.type == SWT.Activate) {
            if (inLayout) {
                requestActivation();
            }
        }
    }

处理Activate事件时,导致setActivePart被调用,来更新activeProvider和它们的listener;

org.eclipse.ui.internal.AbstractSelectionService的setActivePart方法:

    /**
     * Sets the current-active part (or null if none)
     * 
     * @since 3.1 
     *
     * @param newPart the new active part (or null if none)
     */
    public void setActivePart(IWorkbenchPart newPart) {
        // Optimize.
        if (newPart == activePart) {
			return;
		}
        
        ISelectionProvider selectionProvider = null;
        
        if (newPart != null) {
            selectionProvider = newPart.getSite().getSelectionProvider();
            
            if (selectionProvider == null) {
                newPart = null;
            }
        }
        
        if (newPart == activePart) {
			return;
		}
        
        if (activePart != null) {
            if (activeProvider != null) {//清除旧的SP中的listener
                activeProvider.removeSelectionChangedListener(selListener);
                if (activeProvider instanceof IPostSelectionProvider) {
					((IPostSelectionProvider) activeProvider)
                            .removePostSelectionChangedListener(postSelListener);
				} else {
					activeProvider
                            .removeSelectionChangedListener(postSelListener);
				}
                activeProvider = null;
            }
            activePart = null;
        }

        activePart = newPart;
        
        if (newPart != null) {
            activeProvider = selectionProvider;
            // Fire an event if there's an active provider
            activeProvider.addSelectionChangedListener(selListener); //将listener加入新的SP
            ISelection sel = activeProvider.getSelection();
            fireSelection(newPart, sel);
            if (activeProvider instanceof IPostSelectionProvider) {
				((IPostSelectionProvider) activeProvider)
                        .addPostSelectionChangedListener(postSelListener);
			} else { //这里的逻辑是不是有问题,如果对应的SP不是IPostSelectionProvider类型,将postSelListener加入SP?
				activeProvider.addSelectionChangedListener(postSelListener);
			}
            firePostSelection(newPart, sel);
        } else {
            fireSelection(null, null);
            firePostSelection(null, null);
        }
    }

selListener和postSelListener的定义如下:

    /**
     * The JFace selection listener to hook on the active part's selection provider.
     */
    private ISelectionChangedListener selListener = new ISelectionChangedListener() {
        public void selectionChanged(SelectionChangedEvent event) {
            fireSelection(activePart, event.getSelection());
        }
    };
    
    /**
     * The JFace post selection listener to hook on the active part's selection provider.
     */
    private ISelectionChangedListener postSelListener = new ISelectionChangedListener() {
        public void selectionChanged(SelectionChangedEvent event) {
            firePostSelection(activePart, event.getSelection());
        }
    };
   

3. WorkBenchWindow和WorkBenchPage的关系,见下图:

上面已经说过,一个WorkBenchWindow一般有一个WorkBenchPage。

从上图可以看出:

WorkBenchWindow通过busyOpenPage来创建WorkBenchPage;

WorkBenchWindow和WorkBenchPage有自己的SelectionService,但是它们都是继承自org.eclipse.ui.internal.AbstractSelectionService的;

WorkBenchWindow的WWinPartService通过给WorkBenchPage的ParService添加或者删除WWinListener,来和响应Part相关的事件;

WorkBenchWindow的SelectionService叫做WindowSelectionService;

WorkBenchPage的SelectionService叫做PageSelectionService;

SlectionService有多应全局的ListenerList(listeners)和每个part的ListenerList(PagePartSelectionTracker)

4. selection是如何工作的,加下图:

简单的说,当你在且画Editor或者Viewer的时候,WorkbenchPage会通过setActivePart方法,将selListener和postSelListener从老的SP中移除;

然后加入到新的SP中去,然后当SP中有selection改变的时候,SP会通知所有的listener。


5. WorkbenchWindow和WorkbenchPage的SelectionService不一样,那么如何给它们追加listener呢?

    getSite().getWorkbenchWindow().getSelectionService().addSelectionListener(l); 给Window的SelectionService追加listener
    getSite().getPage().addSelectionListener(l); 给Page的SelectionService追加listener


6.  PropertyView是如何响应Selection改变的

org.eclipse.ui.views.properties.PropertySheet通过

    public void init(IViewSite site) throws PartInitException {
           site.getPage().addPostSelectionListener(this);
           super.init(site);
    }
将机制注册到Page的selection完成队列中,如果有selection改变完成的话,Page会通知PropertySheet来更新自己的。


Note:

1. 加下图,分别是Window和Page的SelectionService中listener个数,可以看到它们两个的个数分别是70和1,

Windows:

Page:

2. 每个Part都要对应的PartSite

3. 每个Part都有可能对应一个SelectionTracker

4. 在PartPane中来处理SWT.Activate事件,来更新Page中的SP

5. 有两个SelectionService,一个是Page的,一个是Window的

6. 不要混淆Page和Window的SelectionService

7. setSelectionProvider只能在createPartControl()被调用,之后的调用不会生效;因为没有时机给page去更新SP

8. 如果你的Part有不同的SP,你可能需要在自己写的SP中进行以下trick的处理,可以参见这里:

www.eclipse.org/articles/Article-WorkbenchSelections/SelectionProviderIntermediate.java


参考:

http://www.eclipse.org/articles/Article-WorkbenchSelections/article.html
http://www.eclipse.org/articles/Article-UI-Workbench/workbench.html

http://wiki.eclipse.org/FAQ_Pages,_parts,_sites,_windows:_What_is_all_this_stuff%3F



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值