command framework
AdapterFactoryEditingDomain同content and label providers一样,通过ItemProviderAdapterFactory把它的实现delegate给item providers(必须要有IEditingDomainItemProvider接口).而purchaseOrderItemProvider正好也有这个接口,并且其父类ItemProviderAdapter提供了IEditingDomainItemProvider接口的默认实现.AdapterFactoryEditingDomain正是通过delegating to 这些实现了IEditingDomainItemProvider的item provider,才能提供此类服务,说白了就是上层把call委托给下层.
换个角度去理解:
使用command的一般模式(从company中remove department)
Department dep= ...
Company comp = ...
EditingDomain ed = ...
RemoveCommand cmd =
new RemoveCommand(ed,comp,CompanyPackage.eINSTANCE.getCompany_Departments(),dep);
//RemoveCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Object value)
ed.getCommandStack().execute(cmd);
来看看在EMF中的使用:(自动生成的代码)
1.XXXEditor.createContextMenuFor().//监听drop命令
viewer.addDropSupport(dndOperations, transfers, new EditingDomainViewerDropAdapter(editingDomain, viewer));//AdapterFactoryEditingDomain editingDomain
2.EditingDomainViewerDropAdapter.drop().//某触发事件导致调用drop()
source =
extractDragSource(event.data);
Object target =
extractDropTarget(event.item);
command = DragAndDropCommand.create(domain, target, getLocation(event), event.operations, originalOperation, source);//domain就是上面的editingDomain
3.DragAndDropCommand
public static Command create(EditingDomain domain, Object owner, float location, int operations, int
operation, Collection collection)

...
{
return domain.createCommand
(DragAndDropCommand.class, new CommandParameter(owner, new Detail(location, operations, operation), collection));/*domain的具体类型是?由于前面说过AdapterFactoryEditingDomain委派给实现IEditingDomainItemProvider接口的item provider,那么就是YYYItemProvider.*/
}
4.定位domain,由于YYYItemProvider extends ItemProviderAdapter,而正是由ItemProviderAdapter提供了IEditingDomainItemProvider接口的默认实现.那么看ItemProviderAdapter的creatCommand().其中一段代码如下:
[ItemProviderAdapter.createCommand()]
else if (commandClass == DragAndDropCommand.class
)

...
{
DragAndDropCommand.Detail detail = (DragAndDropCommand.Detail)commandParameter.getFeature();
result = createDragAndDropCommand
(domain, commandParameter.getOwner(), detail.location, detail.operations, detail.operation, commandParameter.getCollection());
}
5.ItemProviderAdapter.createDragAndDropCommand()
protected
Command createDragAndDropCommand
(EditingDomain domain, Object owner, float location, int operations, int
operation, Collection collection)

...
{
return new DragAndDropCommand(domain, owner, location, operations, operation, collection);
//返回一个DragAndDropCommand,over.
}
如果想扩充DragAndDropCommand,写一个它的子类DragAndDropCommandEx,override父类的excute().其他需要改动的地方:
1.首先在YYYItemProvider实现createCommand(),不能使用ItemProviderAdapter的默认实现.
判断如果是DragAndDropCommand.class,替换成DragAndDropCommandEx.class.
2.调用YYYItemProvider.createCommand(),返回一个DragAndDropCommandEx对象即可.
更简单的:
1.只在YYYItemProvider实现createDragAndDropCommand以override ItemProviderAdapter.createDragAndDropCommand().这样由继承的相关性质,在ItemProviderAdapter.createCommand()里面调用的createDragAndDropCommand()实际是子类YYYItemProvider的createDragAndDropCommand(当然了前提传递的是子类对象,父类类型).
所以只需在createDragAndDropCommand返回一个DragAndDropCommandEx对象.
Change Notification
首先看个图,便于理解:
1.在Modeling Framwork里面已经提到过,在YYY的set****()方法中有eNotify()来进行Notify的任务.其继承关系是YYYImpl-->EObjectImpl-->BasicEObjectImpl-->BasicNotifierImpl.
[BasicNotifierImpl.Notify()]
Adapter [] adapters =
(Adapter [])eAdapters.data();
for (int i = 0; i < size; ++
i)

...
{
adapters[i].notifyChanged(notification);//给list中每个注册了的adapter发送notification.
}
2.再看YYYItemProvider.notifyChanged()(这里是purchaseOrderItemProvider)

switch (notification.getFeatureID(PurchaseOrder.class)) ...
{
case PurchasePackage.PURCHASE_ORDER__TO_SHIP:
case PurchasePackage.PURCHASE_ORDER__TO_BILL:
fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false, true));
return;
case PurchasePackage.PURCHASE_ORDER__ITEMS:
fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
return;
}
super.notifyChanged(notification);
总共3个case子句,前2个是改变purchaseOrder的两个attribute,后1个是改变子对象Item.看看ViewerNotification的后两个参数.
ViewerNotification(Notification decoratedNotification, Object element, boolean contentRefresh, boolean
labelUpdate)
说明前两个case导致label update,后一个case导致content refresh.
3.而这个fireNotifyChanged是调用父类ItemProviderAdapter的,用来把notification转交给adapter factory(YYYItemProviderAdapterFactory),再由factory发给各个listener.
[ItemProviderAdapter.fireNotifyChanged()]
if (adapterFactory instanceof
IChangeNotifier)

...
{
IChangeNotifier changeNotifier = (IChangeNotifier)adapterFactory;
changeNotifier.fireNotifyChanged(notification);
}
adapterFactory就是YYYItemProviderAdapterFactory.
跟踪如下:
在YYYItemProvider(父类就是ItemProviderAdapter)构造函数里调用了super(adapterFactory),而XXXAdapterFacotry调用了子类(XXXItemProviderAdapterFactory).createPurchaseOrderAdapter,createPurchaseOrderAdapter里面调用了new PurchaseOrderItemProvider(this).那么这个this也就是后来一直传递的adapterFactory,亦即XXXItemProviderAdapterFactory.
4.[YYYItemProviderAdapterFactory.fireNotifyChanged()]
changeNotifier.fireNotifyChanged(notification);

if (parentAdapterFactory != null) ...
{
parentAdapterFactory.fireNotifyChanged(notification);
}
注意到XXXItemProviderAdapterFactory).adapterFatory维持了一张自己的notifier list(changeNotifier)(生成的代码中这个似乎为null,难道没用?比如在set***引发的事件当中,这个list是空),把notification传递给这个list中的每一个notifier,让他们再进一步notify 它们自己的listerner.
对于parentAdapterFatory(ComposedAdapterFactory类型),如果非空,那么把notification传递过去.再传递notification下去(比如传给AdapterFactoryContentProvider-->viewer结束)
补充:
1.在XXXEditor的constructor中:
List factories = new ArrayList();
factories.add(new ResourceItemProviderAdapterFactory());
factories.add(new PurchaseItemProviderAdapterFactory());
factories.add(new ReflectiveItemProviderAdapterFactory());
adapterFactory = new ComposedAdapterFactory(factories);
.....
editingDomain = new AdapterFactoryEditingDomain(adapterFactory, commandStack, new HashMap());
将editingDomain注册几个能被delegate的adapter Factory.
在XXXEditor.createModel()中
editingDomain.getResourceSet().eAdapters().add(problemIndicationAdapter);
editingDomain是AdapterFactoryEditingDomain类型,getResourceSet()返回一个ResourceSet接口类型的对象,ResourceSet继承了Notifier接口,editingDomain.getResourceSet().eAdapters()得到一个ResourceSet(notifier)的adapters(监听这个notifier的),并再加一个adapter--problemIndicationAdapter.
2. 在EMF.EDIT中包含的一些常用command
-