论坛首页 Java企业应用论坛

基于EMF.EDIT实现GEF编辑器属性页

浏览 2694 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-11-29   最后修改:2009-11-29

GEF配合EMF是很常用的eclipse可视化应用的解决方案,用EMF的好处就是可以根据uml,schema等生成应用模型代码,并且emf生成的模型代码包含模型的监听机制,省去了很多代码量。同样EMF.EDIT框架包含了模型的content,label provider和property source的支持,应用可以方便使用使用,你可以看到EMF.EDIT框架为每个模型生成了命名形式为 ****ProviderAdapter的类,继承自ItemProviderAdapter,又实现了诸如IEditingDomainItemProvider, IStructuredItemContentProvider, ITreeItemContentProvider, IItemLabelProvider, IItemPropertySource的接口,看出来了吧,这个了还是干了很多事儿的。今天主要讨论如何利用EMF.EDIT提供的对模型property source的支持,实现gef编辑器属性页(又省了N多代码啊,实现属性页支持一般要实现自己的IPropertySource和IPropertyDescriptor,很多代码啊)。先看一下实现后的样子,使用了eclipse tabbed property page:

Category tab:

A to Z tab:

咋实现的呢?由于俺也有2年多没摸gef/emf了,于是乎想起了当年作为入门学习的八进制同学的blog(http://www.cnblogs.com/bjzhanghao)借鉴了关于利用emf实现属性页的那篇文章,有兴趣的可以看一下。但是使用EMF.EDIT实现属性也还是有点问题。主要有:

1. 没有实现属性分类的可配置化,只能a-z的排列

2. 由于emf属性页改变模型使用emf自己的command框架,和gef的command框架不同,这就造成emf属性页修改模型后,undo有点问题。这个问题八进制也提过,不过现在我看了一下,似乎没当时那么严重了,gef/emf也在发展,dirty可以显示,就是undo完了值有问题。一会儿详细说明原因和解决办法。

下面就谈谈俺如何解决上面这两个问题的,不知道各位大侠有否更好的解决方法,希望指教点化。

先说第2点吧,导致undo问题的原因是在ItemPropertyDescriptor中的setPropertyValue(Object object, Object value)方法,第二个参数value不是真正要改变的值,而是PropertyValueWrapper对象,这个要归功于ItemPropertyDescriptor中的getPropertyValue方法把原本的属性值包装成了PropertyValueWrapper对象,于是乎SetValueCommand中保存的需要undo的属性值是PropertyValueWrapper类型,于是乎在undo是调用setPropertyValue就会出错。

解决办法很简单,实现自己的ItemPropertyDescriptor覆盖setPropertyValue方法:

public class KulItemPropertyDescriptor extends ItemPropertyDescriptor {

	public KulItemPropertyDescriptor(AdapterFactory adapterFactory,
		      ResourceLocator resourceLocator,
		      String displayName,
		      String description,
		      EStructuralFeature feature, 
		      boolean isSettable,
		      boolean multiLine,
		      boolean sortChoices,
		      Object staticImage,
		      String category,
		      String [] filterFlags) {
		super(adapterFactory, resourceLocator, displayName, description, feature, isSettable, multiLine, sortChoices, staticImage, category, filterFlags);
		
	}
	@Override
	public void setPropertyValue(Object object, Object value) {
		Object validValue = null;
		if(value instanceof PropertyValueWrapper) {
			validValue = ((PropertyValueWrapper) value).getEditableValue(null);
		} else {
			validValue = value;
		}
		super.setPropertyValue(object, validValue);
	}
}
 

要使用自己的ItemPropertyDescriptor,需要做的就是实现自己ItemProviderAdapter,让所有**PropertyAdapter继承它,参考代码:

 

public class CustomItemProviderAdapter extends ItemProviderAdapter {

	public CustomItemProviderAdapter(AdapterFactory adapterFactory) {
		super(adapterFactory);
		
	}
	protected ItemPropertyDescriptor createItemPropertyDescriptor(
		    AdapterFactory adapterFactory,
		    ResourceLocator resourceLocator,
		    String displayName,
		    String description,
		    EStructuralFeature feature,
		    boolean isSettable,
		    boolean multiLine,
		    boolean sortChoices,
		    Object staticImage,
		    String category,
		    String[] filterFlags) {
		
		    return new KulItemPropertyDescriptor(
		      adapterFactory,
		      resourceLocator,
		      displayName,
		      description,
		      feature,
		      isSettable,
		      multiLine,
		      sortChoices,
		      staticImage,
		      category,
		      filterFlags);
		  }
}
 

 

好,现在第2个问题解决了,第一个问题其实也好解决。应为EMF.EDIT生成的代码,默认每个属性的category是null,可以看一下**ProviderAdapter中的创建PropertyDescriptor的方法,要给属性赋予一个category于是乎实现自己的PropertySource在覆盖createPropertyDescriptor方法,返回自己的IPropertyDescriptor,在自己的IPropertyDescriptor中重写getCategory方法就ok了,参考代码:

private class KulPropertySource extends PropertySource {
		private PropertyHolderType propertyHolder = null;

		public KulPropertySource(Object object,
				IItemPropertySource itemPropertySource) {
			super(object, itemPropertySource);
			propertyHolder = PropertyConfigLoader.getInstance()
					.getPropertyHolder(((EObject) object).eClass().getName());
		}

		public IPropertyDescriptor[] getPropertyDescriptors() {
			Collection<IPropertyDescriptor> result = new ArrayList<IPropertyDescriptor>();
			List<IItemPropertyDescriptor> itemPropertyDescriptors = itemPropertySource
					.getPropertyDescriptors(object);
			if (itemPropertyDescriptors != null) {
				for (IItemPropertyDescriptor itemPropertyDescriptor : itemPropertyDescriptors) {
					result.add(createPropertyDescriptor(itemPropertyDescriptor));
				}
			}

			return result.toArray(new IPropertyDescriptor[result.size()]);
		}
		
		protected IPropertyDescriptor createPropertyDescriptor(
				IItemPropertyDescriptor itemPropertyDescriptor) {
			return new PropertyDescriptor(object, itemPropertyDescriptor) {
				public String getCategory() {
					CategoryType ct = PropertyConfigLoader.getInstance()
							.getCategory(propertyHolder,itemPropertyDescriptor.getDisplayName(object));
					if(ct != null) {
						return ct.getId();
					}
					return "Other";
				}
				
			};
		}

	}

这个KulPropertySource类是啥?怎么用?其实这个就是你自己的IPropertySourceProvider中getPropertySource要返回的PropertySource对象。那IPropertySourceProvider又是啥?这个就是UndoablePropertySheetEntry.setPropertySourceProvider()方法要传入的参数,UndoablePropertySheetEntry是啥?就是PropertySheetPage.setRootEntry()要传入的参数,PropertySheetPage是啥?你因该了解吧。

 

  • 大小: 6.6 KB
  • 大小: 7.6 KB
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics