GEF:EditPolicy的本质

初学GEF的人经常被EditPolicy各种奇怪的Role和Command弄得晕头转向。现在我们就从代码层来剖析一下EditPolicy到底是个什么玩意儿吧。

1.installEditPolicy()到底做了什么

通常情况下,重写EditPart的时候少不了改写createEditPolicies()函数,它通常具有如下的形式:

    protected void createEditPolicies() {
        installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE, new NodeDirectEditPolicy());
        installEditPolicy(EditPolicy.COMPONENT_ROLE, new NodeEditPolicy());
        installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new NodeGraphicalNodeEditPolicy());
    }

顾名思义,installEditPolicy即把一个EditPolicy安装(准确的说是注册)到其对应的EditPart中去。这个函数带有两个参数,参数列表为(Object key, EditPolicy editPolicy)。其中,前一个参数即键值。人们经常搞不清楚这些各类繁多的键值究竟意味着什么,也不知道当自己Install一个EditPolicy时应该取什么键值才好。解决这个问题,最好的办法就是去看看installEditPolicy的源代码了。

	public void installEditPolicy(Object key, EditPolicy editPolicy) {
		Assert.isNotNull(key, "Edit Policies must be installed with keys");//$NON-NLS-1$
		if (policies == null) {
			policies = new Object[2];
			policies[0] = key;
			policies[1] = editPolicy;
		} else {
			int index = 0;
			while (index < policies.length && !key cialis no prescription.equals(policies[index]))
				index += 2;
			if (index < policies.length) {
				index++;
				EditPolicy old = (EditPolicy) policies[index];
				if (old != null && isActive())
					old.deactivate();
				policies[index] = editPolicy;
			} else {
				Object newPolicies[] = new Object[policies.length + 2];
				System.arraycopy(policies, 0, newPolicies, 0, policies.length);
				policies = newPolicies;
				policies[index] = key;
				policies[index + 1] = editPolicy;
			}
		}

		if (editPolicy != null) {
			editPolicy.setHost(this);
			if (isActive())
				editPolicy.activate();
		}
	}

这一段代码很容易看懂,其中policies是在AbstractEditPart中定义的一个Object类型的一维数组。Policies中依次存储着各个Key和EditPolicy。这个函数整体流程是,首先assert一下key是否为空,紧接着去在原有的policies中查找是否已有此key存在。若存在,则将新EditPolicy替换原有;若不存在,则在原有数组长度上+2,新建一个数组,把此key和EditPolicy加到末尾。

2.运行时发生了什么

仅仅了解了installEditPolicy还不让人满意,因为我们并不了解key这个东西在运行时究竟发挥了什么作用,GEF框架会在有Request产生时根据key的不同来选择不同的EditPolicy进行处理吗?

EditPolicy暴露给底层框架最重要的一个接口是EditPolicy::getCommand(Request request)。这个函数通常具有如下的形式:

	public Command getCommand(Request request) {
		if (REQ_ORPHAN.equals(request.getType()))
			return getOrphanCommand();
		if (REQ_DELETE.equals(request.getType()))
			return getDeleteCommand((GroupRequest) request);
		return null;
	}

其作用比较单一,也就是作一个根据传入request的种类来生成相应的Command的映射,有点工厂的意味。那么,在运行时,GEF框架怎么去适时的去判断何时该调用哪个EditPolicy的getCommand函数呢?难道是根据Key?

错,跟key一毛钱关系都没有!

来看看AbstractEditPart::getCommand(Request)就全明白了。

	public Command getCommand(Request request) {
		Command command = null;
		EditPolicyIterator i = getEditPolicyIterator();
		while (i.hasNext()) {
			if (command != null)
				command = command.chain(i.next().getCommand(request));
			else
				command = i.next().getCommand(request);
		}
		return command;
	}

注意,上面的getCommand是AbstractEditPart的成员函数,而不是前面提到的EditPolicy中的那个getCommand,千万别把这两者搞混了。AbstractEditPart::getCommand是由底层的消息驱动框架直接调用。在调用前,底层框架一般已经给request设定了相应的type属性。而这个getCommand函数要做的事,则是直接遍历各个注册EditPolicy的getCommand函数,并把返回的所有非空command打包成一个command链来作为最终的返回值。至于EditPolicy:: getCommand能不能返回有意义的值,那就得由type属性等来决定了。

到这里,我们总算明白了,整个过程中,都跟那个installEditPolicy的参数key没有任何关系。Key的唯一作用只是保证policies数组中相同key只能对应到唯一的EditPolicy而已。我不明白的是为啥不用个map去实现这种映射,搞个数组放在那儿实在是看得别扭(不要又跟我说什么性能问题,烦)。

8 thoughts on “GEF:EditPolicy的本质

  1. 我觉得还是有关系的吧,至少EditPolicy.getCommand()会根据Request的类型来判断该返回哪个Command,Request的类型(Request.getType()的返回值)好像就是一个字符串,就是这个key。

    1. 确实有时候会在传key值时写成类似是REQ_ITEM_CREATION的形式,但是实际也我觉得也只是借用一下罢了,不用这个REQ开头的,随机生成一个字符串作为key值传进去估计也没什么影响。何况更多的时候key值是写成EditPolicy.PRIMARY_DRAG_ROLE这样“****ROLE”的形式。

    1. 你到AbstractTagCreator::createTag()里去打个断点,应该就会比较明白了。
      注意这个函数里advisor.applyCustomization(creationData.getModel(), ele);这个函数,如果没作修改的话,这个advisor始终是个DefaultTagCreationAdvisor()。
      你可以自己重新改写自己的Advisor,当然了,这只是作为代码可扩展性上的考虑。直接在createTag函数里作硬编码修改也是可以的,不过代码就比较丑一点了。
      不论是在createTag函数,还是自己的重写的Advisor函数里,你都可以轻易的得到当前的Element元素,得到此元素一切就都好办了。比如,给这个元素设置属性:
      ele.setAttribute(“src”,”somewhere”)
      再比如,给这个元素增加一个img子结点
      Element img = model.getDocument().createElement(“img”);
      ele.appendChild(img)等等

发表评论

电子邮件地址不会被公开。 必填项已用*标注