如何在Eclipse3 / Eclipse4混合编辑器(DIEditorPart)中填充undo / redo?

时间:2017-05-18 11:29:00

标签: eclipse scala eclipse-rcp e4

我的应用程序是混合E3 / E4,因为我想使用Eclipse Workbench的一部分,但也为我以后基于纯E4的应用程序做了一些准备工作。

在这个应用程序中,我有一个使用自定义编辑器输入的编辑器(不是基于文件的,而是基于从数据库中提取的数据;当用户保存更改时,它们将被写回数据库)。我的本地内存中数据表示由EMF / Xcore管理,编辑器使用手动设计的GUI,通过EMF编辑数据绑定,即我使用EditingDomain(即基本{{ 1}}使用AdapterFactoryEditingDomain)跟踪所有更改。

要将我的E4编辑器插入E3编辑器,我使用兼容性层,尤其是BasicCommandStack

虽然到目前为止工作正常但我还没有能够撤消/重做工作。

我的代码看起来像这样(我在Scala-IDE中使用Scala):

E3编辑器桥:

DIEditorPart

和“真实”部分:

final class CustomEditorPartE3Bridge extends DIEditorPart(classOf[CustomEditorPart])

那么,我如何提供撤销/重做以便E3的撤销/重做机制启动?我是否必须以某种方式将我的final class CustomEditorPart { @Inject private var _ctx: IEclipseContext = _ private var _view: Option[MyCustomEditorView] = None @Inject private var _dirty: MDirtyable = _ @Inject @Optional private var _dirtyE3: IDirtyProviderService = _ private var doPersist: () => Unit = () => {} @PostConstruct def init(input: IEditorInput): Unit = input match { case i: MyCustomEditorInput => initPart(i) case _ => throw new IllegalStateException("Required a %s but got a %s". format(classOf[MyCustomEditorInput].getName, input.getClass.getName)) } private def initPart(input: MyCustomEditorInput): Unit = { val cc = _ctx.createChild() // Now we need an adapter factory and a respective editing domain // to enable Undo and Redo val adapterFactory = new ModelAdapterFactory // generated with Xcore val cs = new BasicCommandStack val domain = new AdapterFactoryEditingDomain(adapterFactory, cs) // We need the editing domain in the control for Databinding cc.set(classOf[EditingDomain], domain) // Now we setup the view _view = Some(ContextInjectionFactory.make(classOf[MyCustomEditorView], cc)) // And we handle dirtying of our part object csl extends CommandStackListener { def commandStackChanged(eo: EventObject): Unit = { val dirty = cs.isSaveNeeded() if (_dirtyE3 == null) { _dirty.setDirty(dirty) } else { Display.getDefault.asyncExec(() => _dirtyE3.setDirtyState(dirty)) } } } cs.addCommandStackListener(csl) // Finally, we setup our saving routine. doPersist = () => { /* not relevant here */ } } @Focus def setFocus(): Unit = _view.foreach(_.setFocus) @PersistState def persistState(): Unit = {} @Persist def commit(): Unit = doPersist() } 传播回我的E3桥并设置一些动作栏贡献者或者我可以为我注入一些设置撤消/重做的东西吗?

1 个答案:

答案 0 :(得分:0)

我将此作为答案发布,因此我可以将其标记为解决方案。

在摆弄并搜索EHandlerService使用的各种示例后,我想出了这个:

当我使用DIEditorPart时,我可以注入IWorkbenchPart。如果稍后在基于纯E4的应用程序中使用该部件时可能不存在,那么我将其注入@Optional并稍后测试null

所以除了E4方式,我还有以下内容:

  @Inject @Optional private var _workbenchPart: IWorkbenchPart = _

  // In my method
  val cc: IEclipseContext = ...
  val domain: EditingDomain = ...
  cc.set(classOf[EditingDomain], domain)
    if (_workbenchPart != null) {
      val undoAction = ContextInjectionFactory.make(classOf[UndoAction], cc)
      val redoAction = ContextInjectionFactory.make(classOf[RedoAction], cc)
      val site = _workbenchPart.getSite.asInstanceOf[{
        def getActionBars(): org.eclipse.ui.IActionBars
      }]
      val targetActionBars = site.getActionBars
      if (targetActionBars != null) {
        targetActionBars.setGlobalActionHandler(ActionFactory.UNDO.getId, undoAction)
        targetActionBars.setGlobalActionHandler(ActionFactory.REDO.getId, redoAction)
      }
    }

我的UndoActionRedoAction如下所示:

abstract class UndoRedoAction(canExecute: CommandStack => Boolean,
                              execute: CommandStack => Unit) extends Action {

  @Inject private var _domain: EditingDomain = _

  @PostConstruct
  private def init(): Unit = {
    setEnabled(canExecute(_domain.getCommandStack))
    object csl extends CommandStackListener {
      def commandStackChanged(eo: EventObject): Unit = setEnabled(canExecute(_domain.getCommandStack))
    }
    _domain.getCommandStack.addCommandStackListener(csl)
  }

  override final def run(): Unit = execute(_domain.getCommandStack)
}

final class UndoAction extends UndoRedoAction(_.canUndo, _.undo)
final class RedoAction extends UndoRedoAction(_.canRedo, _.redo)

这有点像黑客,但它确实有效。