EMF.edit framework(二)

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.
classnew 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(), falsetrue
));
    
return
;
           
case
 PurchasePackage.PURCHASE_ORDER__ITEMS:
    fireNotifyChanged(
new ViewerNotification(notification, notification.getNotifier(), truefalse
));
    
return
;
}

super.notifyChanged(notification);

总共3个case子句,前2个是改变purchaseOrder的两个attribute,后1个是改变子对象Item.看看ViewerNotification的后两个参数.

ViewerNotification(Notification decoratedNotification, Object element, boolean contentRefreshboolean  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

    • SetCommand sets the value of an attribute or reference on an EObject.

    • AddCommand adds one or more objects to a multiplicity-many feature of an EObject.

    • RemoveCommand removes one or more objects from a multiplicity-many feature of an EObject.

    • MoveCommand moves an object within a multiplicity-many feature of an EObject.

    • ReplaceCommand replaces an object in a multiplicity-many feature of an EObject.

    • CopyCommand performs a deep copy of one or more EObjects

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值