xiaoxiaoleemin

天道酬勤,小小加油
posts - 19, comments - 12, trackbacks - 0, articles - 0
    上一部分中,我们看到了如何通过content和label provider来显示EMF模型,这一部分介绍如何修改、编辑EMF模型。EMF.Edit支持基于Command的模型编辑方式,可以自动的undo和redo。EMF.Edit的Command Framework可以分为两部分,第一部分是common command framework,其中定义了一些基本的命令接口,实现了例如basic command stack,compound command等,虽然这些命令主要用于EMF.Edit,但是实际上可以独立于EMF.Edit使用;第二部分是EMF.Edit 命令,是指一些专门编辑EObject的命令。
    Common Command Framework
   
Command:所有命令必须要实现的接口。有execute(),undo(),redo(),canExecute(),canUndo(), undo(),redo()等方法,其含义可以从方法名字上看出。另外还有两个可以选择实现的方法,getResult()和getAffectedObjects()。前者是指该命令执行的结果是什么,适合于复合的命令中,一个命令的输出作为另一个命令的输入的情况。比如一个复制命令把复制的内容作为命令的结果返回,那么“复制并粘贴”命令可以有一个复制命令和一个Add命令组成,其中复制命令的输出作为Add命令的输入。后者getAffectedObjects()是指在最近一次的execute(),undo()或者redo()的过程中发生改变的对象。EMF.Edit UI通过在UI上选中这些返回的对象来突出命令执行的结果。
    AbstractCommand:是实现了Command接口中部分方法的一个抽象类,大多数命令的定义可以继承于它。它实现了一个很重要方法canExecute(),不管canExecute方法运行多少次,prepare只运行一次。这样在子类中我们重写prepare而不是canExecute方法,把判断命令是否可执行的逻辑写在prepare里边,当判断需要复杂的计算时,这一设计会很有意义。
public boolean canExecute()
{
    if(!isPrepared)
    {
       isExecutable = prepare();
       isPrepared = true;
     }
    return isExecutable;
}
    CommandStack:在可undo的栈中执行、维护命令的接口,和Command一样拥有execute,undo,redo等方法,另外还得维护其中的命令。canUndo 和canRedo分别返回栈中是否有可以undo和redo的命令。
    BasicCommandStack:CommandStack接口的基本实现类。它的功能比较强大,可以直接用在基于EMF.Edit的编辑器中。
    CompoundCommand:包含了多个基本命令的复合命令。它的execute方法会执行它所包含的所有方法,canExecute只有在所有的命令都可以执行的时候才返回true。appendAndExecute()方法可以把一个命令加入进去并且立即执行;unWrap方法,如果只包含一个命令,那么返回这个命令,否则返回compoundCommand本身。

    EMF.Edit Framework
   
专门用于修改、编辑EObject的命令,如:
    SetCommand:修改EObject的属性或者引用。
    AddCommand:为EObject的多重性为*的feature添加一个或者多个对象。
    RemoveCommand:从EObject的多重性为*的feature中删除一个或者多个对象。
    MoveCommand:在EObject的多重性为*的feature中移动某个对象的位置,构造函数要给出新的位置序号
    ReplaceCommand:把EObjecct的多重性为*的feature中的某个对象替换掉。
    CopyCommand:对一个或者多个EObject对象进行深层拷贝。
    上述的命令除了CopyCommand都是原子命令,而CopyCommand是由CreateCopyCommand和InitializeCopyCommand组合而成的,分别创建和初始化一个浅拷贝的对象。除了上述几个基本命令外, EMF还有一些由几个命令组成的复合命令,如:
    CreateChildCommand = AddCommand + SetCommand;
    CutToClipboardCommand = RemoveCommand + 在剪切板上保存被删除的对象;
    PasteFromClipboardCommand =  CopyCommand + AddCommand ;
    DragAndDropCommand = CopyCommand + RemoveCommand + AddCommand;
   
    AbstractOverrideableCommand:是AbstractCommand的子类,大多数命令直接继承于它。它实现了OverriableCommand接口,其中针对于Command接口中的每个方法都定义了do***方法。AbstractOverridableCommand的execute方法如下:
public final void execute{
    if(overrideCommand != null)
       overrideCommand.execute();
    else
       doExecute();
}
    子类直接复写doExecute()方法而不是execute.

    CommandParameter:EMF.Edit的命令是通过EditingDomain的方法createCommand(Class commandClass,CommandParamter paramter)来创建的,可见要通过这种方法创建命令必须先构造CommandParamter(owner,feature,value等属性)。另外,每一个命令都有静态的create方法,比如SetCommand.create(editingDomain, object, feature, value),其实它本质上的实现还是先用这几个参数构造CommandParamter,然后再调用EditingDomain的createCommand方法。

    EditingDomain
   
类似于通过content和label provider来管理模型的视图,EMF.Edit通过editing domain来管理在编辑器中对模型进行的基于命令的修改。editing domain主要有三个功能:创建命令;管理命令栈;为EMF 资源的访问提供方便。

    创建命令:
    先看一个具体的例子,假设我们要从订单中删除某个订单项,可以直接通过RemoveCommand的create静态方法来实现:
Command cmd = RemoveCommand.create(editingDomain, purchaseOrder, poPackage.getPurchaseOrder_Items, item);
或者
Command cmd = RemoveCommand.create(editingDomain, item);
    其中第二个方法没有提供owner和feature两个参数,editing domain负责补充它们。下面看一下EditingDomain的实现类AdapterFactoryEditingDomain创建命令的方法,它把创建命令的任务分发到相应的item provider:
public Command createCommand(Class commandClass, CommandParamter parameter){
    Object owner = paramter.getOwner();
    IEditingDomainItemProvider adapter = (IEditingDomainItemProvider)adapterFactory.adapt(owner, IEditingDomainItemProvider.class);
    return adapter.createCommand(owner, this, commandClass, parameter);

    维护命令栈:
    命令栈在EMF编辑器中是很有用的,它可以跟踪模型的所有变化,助于实现编辑器的Save,Undo,Redo.事实上,所有的命令都是在editing domain中创建,在command stack中执行。editing domain是创建命令的工厂,因此它也适合维护command stack。在修改模型的任何地方,我们都可以取得editing domain,比如在编辑器的Action中,可以直接从编辑器中取得; 在Property descriptor中,可以通过resource set取得。
   
    访问Resource Set:
    AdapterFactoryEditingDomain创建了一种特殊的ResourceSet(实现了IEditingDomainProvider接口),因此这个resource set可以访问editingDomain。EditingDomain与ResourceSet,Resource,Object之间的可访问关系如下图所示:

    如下的API可以实现对象间的互相访问:
    AdapterFactoryEditingDomain#getCommandStack();
    AdapterFactoryEditingDomain#getResourceSet();
    ResourceSet#getResource(URI,boolean);
    Resource#getResourceSet()/getContents();
    EObject#eResource();

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


网站导航: