xiaoxiaoleemin

天道酬勤,小小加油
posts - 19, comments - 12, trackbacks - 0, articles - 0
    本书的第二章介绍了EMF产生的Model部分的代码,你可以使用EMF Edit Framework来为model构建功能强大的视图和编辑器。在EMF为你生成的编辑器里,可以编辑(复制,粘贴,拖拽等)、显示model,还可以无限的redo/undo。如果这个编辑器不能完全满足你的需求,你可以在此基础上做一些修改,肯定比从头开始写节约时间。
    Eclipse通过JFace中的一些Viewer来显示结构化的数据,这些Viewer不直接从model中获取要显示的数据,而是通过ContentProvider和LabelProvider来取得要显示的内容、文本以及图标等信息。不同的Viewer需要不同的ContentProvider和LabelProvider:
   
 Viewer ContentProvider LabelProvider
 ListViewer
IStructureContentProvider 
ILabelProvider
 TreeViewer ITreeContentProvider
ILabelProvider
 TableViewer IStructureContentProvider
ITableLabelProvider
    其中ILabelProvider有getText(Object)和getImage(Object)两个方法,ITableLabelProvider有getColumnText(Object, int)和getColumnImage(Object,int)两个方法,它们之间没有继承关系。IStructureContentProvider有getElements(Object)方法,返回一个Object数组,而ITreeContentProvider是其子类,另有自己的方法getChildren(Object),getParent(Object)和hasChildren(Objecct)三个方法。
    EMF Edit是把Eclipse UI Framework(JFace)和EMF Framework连接起来的桥梁,包括两部分,其中org.eclipse.emf.edit是与UI无关的部分,org.eclipse.emf.edit.ui是与UI有关的部分。前一部分主要包括ItemProvider和Commmand。
    1.Item Providers
   
item provider,这个名字来源于它为模型中各个可编辑的"items"(对象)"provides"功能。它通常是EMF Adapters,但是也可以不是。They are used to adapt model objects so the model object can provide all of the interfaces that it needs to be viewed and edited.
    item provider主要有四个功能:作为content和label provider; 为EMF对象提供property source; 担当Command Factory; 将EMF模型的变化通知发送给Viewer。每个item provider可以实现上述全部功能或者部分功能,通常情况下,item provider通过继承EMF Edit的基类ItemProviderAdapter来实现全部的功能。下面分别介绍这四个功能各自需要哪些方法的支持:
   
    (1)Content and label item providers
    EMF.Edit分别通过AdapterFactoryContentProvider和AdapterFactcoryLabelProvider来提供content provider和label provider的功能,这两个类的构造函数都需要一个adapter factory(EMF生成的edit部分代码中的**ItemProviderAdapterFactory,负责为特定的类型创建或者定位adapter),它们的很多方法都通过分发到相应的Item Provider来实现。比如getChildren()的实现如下:
  public boolean hasChildren(Object object)
  {
    
// Get the adapter from the factory.
    ITreeItemContentProvider treeItemContentProvider = 
      (ITreeItemContentProvider)adapterFactory.adapt(object, ITreeItemContentProviderClass);

    
// Either delegate the call or return nothing.
    return 
      treeItemContentProvider 
!= null  && 
        treeItemContentProvider.hasChildren(object);
  }
    EMF.Edit为模型中的每个类生成一个**ItemProvider类,负责为UI的显示提供具体的实现。每个类在默认情况下都实现了5个接口,其中的三个IStructuredItemContentProvider(为ListViewer和TableViewer提供contentProvider), ITreeItemContentProvider(为TreeViewer提供contentProvider),IItemLabelProvider(为TreeViewer和ListViewer提供labelProvider)是支持这一功能的.
    如果我们要用TableViewer显示订单(模型中对应PurchaseOrder类),那么应该修改PurchaseOrderItemProvider,使它实现ITableItemLabelProvider,同时实现方法getColumnText和getColumnImage。还要在为该模型生成的POItemProviderAdapterFactory类的构造函数中添加对ITableItemLabelProvider的支持:
...
supportedTypes.add(ITableItemLabelProvider.
class);
   
    (2)Item Property Source
    当打开PropertySheet时,AdapterFactoryContentProvider还是通过adapterFactory找到相应的实现了IItemPropertySource接口的item Provider。EMF.Edit中的PropertySource类实现了这一接口,因此AdapterFactoryContentProvider返回PropertySource的一个新创建的实例(作为被选中的item provider的wrapper)给PropertySheet,PropertySource把很多方法的实现分发给了itemPropertySource。其代码如下:
public IPropertySource getPropertySource(Object object)
  {
    
if (object instanceof IPropertySource)
    {
      
return (IPropertySource)object;
    }
    
else
    {
      IItemPropertySource itemPropertySource 
=
        (IItemPropertySource)
          (object 
instanceof EObject && ((EObject)object).eClass() == null ?
            
null :
            adapterFactory.adapt(object, IItemPropertySourceClass));
  
      
return 
        itemPropertySource 
!= null ?  createPropertySource(object, itemPropertySource) : null;
    }
  }

  
protected IPropertySource createPropertySource(Object object, IItemPropertySource itemPropertySource)
  {
    
return new PropertySource(object, itemPropertySource);
  }
    自动生成的**ItemProvider实现的5个接口中的IItemPropertySource就是支持这一功能的, 其中getPropertyDescriptors()方法返回的列表决定了PropertySheet中显示的内容列表。
   
    (3)Command Factory
    EMF.Edit提供了修改EMF对象(可以undo)的整套机制,并且提供了一些通用的命令。自动生成的**ItemProvider实现的5个接口中还没提到的IEditingDomainItemProvider就是支持这一功能的。EMF.Edit的Command Framework需要EditngDomain接口,其中类AdapterFactoryEditingDomain如同前面提到的AdapterFactoryContentProvider和AdapterFactoryLabelProvider,它负责把相应的方法(比如getChildren(),getParent()等)分发给实现了IEditingDomainItemProvider的Item Provider。
   
    (4)Change Notification
    当**ItemProvider所adapt的对象状态发生变化时,**ItemProvider会收到Notification,其NotifyChanged()会被调用。ItemProvider作为Observer负责过滤不相关的事件,然后把相关的事件传递给模型的central change notifier,通常是实现了IChangeNotifier接口的**ItemProviderAdapterFactory。
    当我们在PropertySheet中修改Item(订单项,在模型中对应Item类)的名字时,首先ItemPropertyDescriptor的setPropertyValue()方法被调用,它会通过SetCommand修改名字或者直接调用Item的eSet(),总之这两种方法都会调用到ItemImpl的setName()方法,该方法中判断是否需要发送通知,如果需要,则向所有监听item对象的adapter发送通知(即调用它们的notifyChanged()方法),这些adapter包括ItemItemProvide,它的notifyChanged()方法调用POItemProviderAdapterFactory(IChangeNotifier类型)的fireNotifyChanged()方法,然后再调用所有注册的listener的fireNotifyChanged()。这些listener可能是PropertySheet,Outline视图中的TreeViewer等,收到通知后,更新视图以反映model的变化。当有事件发生需要通知JFace的Viewer时,真正的listener并不是viewer本身,而是它的content provider。

    EMF.Edit的另一部分重要内容Command Framework留到下一部分介绍。


只有注册用户登录后才能发表评论。


网站导航: