源于《EMF.Edit Framework Programmgering's Guide》
EMF.Edit里面有几个类比较绕,很容易被搞得晕头转向,所以需要澄清以下:
★AdapterFactoryContentProvider, ItemProviderAdapterFactory和ItemProviderAdapter之间的关系,ItemProviderAdapterFactory用来创建各种Adapter以及将各种notifier跟这些adapter关联起来,AdapterFactoryContentProvider包装了一个ItemProviderAdapterFactory(AdapterFactory),它用来将JFace需要的content provider代理到item content provider上,对content provider各种方法的调用将调用到相应的item content provider上,对org.eclipse.jface.viewers.IStructuredContentProvider的调用将代理到IStructuredItemContentProvider上,对ITreeContentProvider的调用将代理到ITreeItemContentProvider上,而对IPropertySourceProvider的调用将代理到IItemPropertySource,而ItemProviderAdapter是所有ItemProvider的基类,AdapterFactoryLabelProvider和ItemProviderAdapter之间也存在类似的关系
★为了显示model内容,我们需要使用content provider和label provider,而编辑model内容则需要使用到editing domain,AdapterFactoryEditingDomain是一个和AdapterFactoryContentProvider、AdapterFactoryLabelProvider类似的东东
★editing domain主要有两个功能:一个是作为command的factory(所以它的实现类是AdapterFactoryEditingDomain);另一个对EMF Model(ResourceSet,因此提供了getResource()方法)进行管理
★EditingDomain,AdapterFactoryEditingDomain,EditingDomainItemProvider和Command之间的关系,AdapterFactoryEditingDomain实现了EditingDomain接口,AdapterFactoryEditingDomain和AdapterFactoryContentProvider一样,也是用来将EditingDomain的方法代理到EditingDomainItemProvider上去。
从一般的操作说起,比如从一个company对象上删除一个department对象,通常我们的做法是:
但是如果是使用command,则会这样做:
不过这个做法有一个问题,就是不是很通用,因为所有的删除操作基本上都差不多,所以还需要继续抽象,这时就必须引入EditingDomain.
EditingDomain的接口定义如下:
为了创建一个Command对象,我们需要构造一个CommandParameter对象。在createCommand方法里面会调用指定的Command的静态create方法来创建指定的Command对象,通过使用create方法,我们可以对上面的操作做进一步的改写:
通过上面的改写,差不多实现了一个通用的删除操作流程
接下来我们可以看看一个command的创建过程,首先是调用指定command的静态create方法,该方法将调用EditingDomain的createCommand方法,AdapterFactoryEditingDomain作为EditingDomain的实现类,又将command的创建过程代理到EditingDomainItemProvider上,在Itemprovider(实现了EditingDomainItemProvider接口)中,最终使用new创建指定的Command实例
我们可以采用多种方式对command定制,第一种就是复写generated的EditingDomainItemProvider实现类的createCommand方法:
这里的RemoveDepartmentCommand 就是我们自己实现的删除操作。
第二种方式就是复写createRemoveCommand()来实现定制:
通知的处理
在创建AdapterFactoryContentProvider的时候会将其作为一个listener注册到AdapterFactory里面,这个AdapterFactory实现了IChangeNotifier接口,而AdapterFactory在创建每一个ItemProvider的时候又会把自己传递过去,从而使得AdapterFactory成为model的消息分发中心,在AdapterFactoryContentProvider又会记录所有需要接受通知的viewer(也就是为其提供了content provider的viewer)。
当model被改变之后,将触发和该model相关的adapter的notifyChanged()方法(这里面的adapter就包括itemprovider),当然这里还有一个过滤的过程,只把那些跟viewer相关的notification才会发送给viewer。为了将notification继续传递,会使用ViewerNotification这样一个对象来对notifation以及其他的信息进行封装,因此它继承了Notification,除了Notification相关的信息之外,还封装了要更新的viewer的相关元素,IViewerNotification 的定义如下:
对于消息的传递还会进行分类,这个是在notifyChanged这个方法里面做的,如下面的代码:
可以看出,如果是attribute,那么会对label进行更新,如果是reference,那么需要更新content了,否则什么都不做。fireNotifyChanged方法是在ItemProviderAdapter(就是所有ItemProvider的基类)里面定义的,它会把notifaction传给adapter factory,前面我们说过adapter factory是notification的分发器,因此它会将notification发送给所有注册的listener,我们前面也说过AdapterFactory实现IChangeNotifier接口,并作为listener注册到adapter factory中去了,因此在最后会调用adapter factory的fireNotifyChanged方法,当然了adapter factory也会将notification代理别的对象(可能是tree或者table的content/label provider,当然在emf中就是itemprovider了)上去,最后viewer被更新了。
EMF.Edit里面有几个类比较绕,很容易被搞得晕头转向,所以需要澄清以下:
★AdapterFactoryContentProvider, ItemProviderAdapterFactory和ItemProviderAdapter之间的关系,ItemProviderAdapterFactory用来创建各种Adapter以及将各种notifier跟这些adapter关联起来,AdapterFactoryContentProvider包装了一个ItemProviderAdapterFactory(AdapterFactory),它用来将JFace需要的content provider代理到item content provider上,对content provider各种方法的调用将调用到相应的item content provider上,对org.eclipse.jface.viewers.IStructuredContentProvider的调用将代理到IStructuredItemContentProvider上,对ITreeContentProvider的调用将代理到ITreeItemContentProvider上,而对IPropertySourceProvider的调用将代理到IItemPropertySource,而ItemProviderAdapter是所有ItemProvider的基类,AdapterFactoryLabelProvider和ItemProviderAdapter之间也存在类似的关系
★为了显示model内容,我们需要使用content provider和label provider,而编辑model内容则需要使用到editing domain,AdapterFactoryEditingDomain是一个和AdapterFactoryContentProvider、AdapterFactoryLabelProvider类似的东东
★editing domain主要有两个功能:一个是作为command的factory(所以它的实现类是AdapterFactoryEditingDomain);另一个对EMF Model(ResourceSet,因此提供了getResource()方法)进行管理
★EditingDomain,AdapterFactoryEditingDomain,EditingDomainItemProvider和Command之间的关系,AdapterFactoryEditingDomain实现了EditingDomain接口,AdapterFactoryEditingDomain和AdapterFactoryContentProvider一样,也是用来将EditingDomain的方法代理到EditingDomainItemProvider上去。
从一般的操作说起,比如从一个company对象上删除一个department对象,通常我们的做法是:
java 代码
- Department d = ...
- Company c = ...
- c.getDepartments().remove(d);
但是如果是使用command,则会这样做:
java 代码
- Department d = ...
- Company c = ...
- EditingDomain ed = ...
- RemoveCommand cmd =
- new RemoveCommand(ed, c, CompanyPackage.eINSTANCE.getCompany_Departments(), d);
- ed.getCommandStack().execute(cmd);
不过这个做法有一个问题,就是不是很通用,因为所有的删除操作基本上都差不多,所以还需要继续抽象,这时就必须引入EditingDomain.
EditingDomain的接口定义如下:
java 代码
- public interface EditingDomain
- {
- ...
- Command createCommand(Class commandClass, CommandParameter commandParameter);
- ...
- }
为了创建一个Command对象,我们需要构造一个CommandParameter对象。在createCommand方法里面会调用指定的Command的静态create方法来创建指定的Command对象,通过使用create方法,我们可以对上面的操作做进一步的改写:
java 代码
- Department d = ...
- EditingDomain ed = ...
- Command cmd = RemoveCommand.create(ed, d);
- ed.getCommandStack().execute(cmd);
通过上面的改写,差不多实现了一个通用的删除操作流程
接下来我们可以看看一个command的创建过程,首先是调用指定command的静态create方法,该方法将调用EditingDomain的createCommand方法,AdapterFactoryEditingDomain作为EditingDomain的实现类,又将command的创建过程代理到EditingDomainItemProvider上,在Itemprovider(实现了EditingDomainItemProvider接口)中,最终使用new创建指定的Command实例
我们可以采用多种方式对command定制,第一种就是复写generated的EditingDomainItemProvider实现类的createCommand方法:
java 代码
- public class CompanyItemProvider ...
- {
- ...
- public Command createCommand(final Object object, ...)
- {
- if (commandClass == RemoveCommand.class)
- {
- return new RemoveDepartmentCommand(...);
- }
- return super.createCommand(...);
- }
- }
这里的RemoveDepartmentCommand 就是我们自己实现的删除操作。
第二种方式就是复写createRemoveCommand()来实现定制:
java 代码
- protected Command createRemoveCommand(...)
- {
- return new RemoveDepartmentCommand(...);
- }
通知的处理
在创建AdapterFactoryContentProvider的时候会将其作为一个listener注册到AdapterFactory里面,这个AdapterFactory实现了IChangeNotifier接口,而AdapterFactory在创建每一个ItemProvider的时候又会把自己传递过去,从而使得AdapterFactory成为model的消息分发中心,在AdapterFactoryContentProvider又会记录所有需要接受通知的viewer(也就是为其提供了content provider的viewer)。
当model被改变之后,将触发和该model相关的adapter的notifyChanged()方法(这里面的adapter就包括itemprovider),当然这里还有一个过滤的过程,只把那些跟viewer相关的notification才会发送给viewer。为了将notification继续传递,会使用ViewerNotification这样一个对象来对notifation以及其他的信息进行封装,因此它继承了Notification,除了Notification相关的信息之外,还封装了要更新的viewer的相关元素,IViewerNotification 的定义如下:
java 代码
- public interface IViewerNotification extends Notification
- {
- Object getElement();
- boolean isContentRefresh();
- boolean isLabelUpdate();
- }
对于消息的传递还会进行分类,这个是在notifyChanged这个方法里面做的,如下面的代码:
java 代码
- public void notifyChanged(Notification notification)
- {
- ...
- switch (notification.getFeatureID(Company.class))
- {
- case CompanyPackage.COMPANY__NAME:
- //ViewerNotification(Notification decoratedNotification, Object element,
- boolean contentRefresh, boolean labelUpdate)
- fireNotifyChanged(new ViewerNotification(notification, ..., false, true));
- return;
- case CompanyPackage.COMPANY__DEPARTMENT:
- fireNotifyChanged(new ViewerNotification(notification, ..., true, false));
- return;
- }
- super.notifyChanged(notification);
- }
可以看出,如果是attribute,那么会对label进行更新,如果是reference,那么需要更新content了,否则什么都不做。fireNotifyChanged方法是在ItemProviderAdapter(就是所有ItemProvider的基类)里面定义的,它会把notifaction传给adapter factory,前面我们说过adapter factory是notification的分发器,因此它会将notification发送给所有注册的listener,我们前面也说过AdapterFactory实现IChangeNotifier接口,并作为listener注册到adapter factory中去了,因此在最后会调用adapter factory的fireNotifyChanged方法,当然了adapter factory也会将notification代理别的对象(可能是tree或者table的content/label provider,当然在emf中就是itemprovider了)上去,最后viewer被更新了。
安徽新华电脑学校专业职业规划师为你提供更多帮助【在线咨询】