如何在 Eclipse FormEditor 中实现撤消/重做功能?

2022-01-16 00:00:00 xml eclipse-plugin java eclipse

我正在开发一个多页表单编辑器来在 Eclipse 中编辑/创建自定义 XML 文件.

I am developing a multipage Form Editor to edit/create a customized XML file in Eclipse.

  1. 实现类是 MyXMLFormEditor,它扩展了 FormEditor.

  1. Implementation class is MyXMLFormEditor which extends FormEditor.

FormEditor 的每一页都扩展了 FormPage(即 MyXMLFormPage 扩展了 FormPage).

Each page of FormEditor extends FormPage (i.e. MyXMLFormPage extends FormPage).

在 FormEditor 和实际 XML 文件之间,我正在维护 JDOM 模型.

Between FormEditor and actual XML file I am maintaining JDOM model.

我还实现了脏标志处理.因此,用户在表单编辑器中的输入会保存到 JDOM 中,直到用户按下保存按钮.当用户按下保存按钮时,JDOM 被写入/序列化为 XML 文件.

Also I implemented dirty flag handling. So user’s inputs into form editor gets saved into JDOM till the time user presses Save button. When user presses save button JDOM is written/serialized into XML file.

在具有上述功能的编辑器中,我想实现如下撤消/重做功能:

In an editor with above functionality I would like to implement undo/redo functionality as follow:

  • 当编辑器变脏时(用户将某些内容更改为表单编辑器但未保存)撤消操作应将表单编辑器和 JDOM 中的更改恢复到其原始状态(即编辑器未变脏时的状态)和重做操作应该再次将更改带回 FormEditor 以及 JDOM,并且编辑器应该变脏.

以下是我的代码片段:

MyXMLFormEditor.java

MyXMLFormEditor.java

public class MyXMLFormEditor extends FormEditor {

    MyXMLFormEditor(){
                                super();                                
                                }

                @Override
                protected FormToolkit createToolkit(Display display) {
                                // Create a toolkit that shares colors between editors.
                                return new FormToolkit(Activator.getDefault().getFormColors(display));
                }

                @Override
                public void init(IEditorSite site, IEditorInput editorInput) {
                                setSite(site);
                                mSite = site;
                                setInput(editorInput);
                                try {
                                                super.init(site, editorInput);
                                } catch (PartInitException e1) {
                                                e1.printStackTrace();
                                }
                                if (!(editorInput instanceof IFileEditorInput))
                                                try {
                                                                throw new PartInitException("Invalid Input: Must be IFileEditorInput");
                                                                } catch (PartInitException e) {
                                                                                e.printStackTrace();
                                                                }
                                setPartName(fileName);
                }
                public void setUpProgFile(IEditorSite site, IEditorInput editorInput){                       
                                IFileEditorInput fileInput = ((IFileEditorInput) editorInput);

                                //create document builder and prepare JDom model for xml file.
                }


                @Override
                protected void addPages() {
                                try {
                                                //add 'Main' page
                                                objMyXMLFormPage = new MyXMLFormPage (this, "FirstPage","Main");
                                                //set rootNode of MyXMLFormPage 
                                                objMyXMLFormPage.rootNode = getRootNode();
                                                objMyXMLFormPage.filePath = filePath;
                                                objMyXMLFormPage.document = document;
                                                addPage(objMyXMLFormPage);

                                } catch (PartInitException e) {
                                                e.printStackTrace();
                                }
                }

                @Override
                public void doSave(IProgressMonitor monitor) {
                                System.out.println("MyXMLFormEditor: doSave");

                                //logic to write jdom contents into xml file.
                                objMyXMLFormPage.setDirty(false);
                }

                @Override
                public void doSaveAs() {
                                System.out.println("MyXMLFormEditor: doSaveAs");
                }
                @Override
                public boolean isSaveAsAllowed() {
                                System.out.println("MyXMLFormEditor: isSaveAsAllowed");
                                return true;
                }

}

MyXMLFormPage .java

MyXMLFormPage .java

public class MyXMLFormPage  extends FormPage{

                //private members declaration.

                public MyXMLFormPage (MyXMLFormEditor editor,String title, String id) {
                                // initialize the editor and set its title and name.
                                super(editor,title,id );
                                }

                @Override
                public void createFormContent(IManagedForm managedForm) {
                    // Set page title
                                super.createFormContent(managedForm);

                                FormToolkit mMyXMLFormPage Toolkit = managedForm.getToolkit();

                                //Logic to creat UI and populating its contents from JDom

                }


                private void makeEditorDirty() {
                                updateJdom =  true;       
                                setDirty(true);                                                   
                }

                private void updateJDom() {
                                if(updateJdom){
                                                System.out.println("*** Jdom updated ***");
                                                updateJdom = false;
                                }
                }

                @Override
                public boolean isDirty() {
                                return isDirtyFlag;
                }

                protected void setDirty(boolean value) {
                                isDirtyFlag = value;
                                dirtyStateChanged();
                }

                public void dirtyStateChanged() {
                                getEditor().editorDirtyStateChanged();

                }

                @Override
                public boolean isSaveAsAllowed() {
                                System.out.println("MyXMLFormPage .isSaveAsAllowed");
                      return false;
                   }

                @Override
                public void doSave(IProgressMonitor monitor) {
                                System.out.println("MyXMLFormPage .doSave");
                }

}

谁能向我提供有关如何在 FormEditor 中实现撤消/重做功能的指针/示例?如果该方法利用 Eclipse PDE 或工作台的现有撤消/重做框架会很好.

Can anyone provide me pointer/samples on how to implement undo/redo functionality into FormEditor? It would be good if the approach make use of existing undo/redo framework of Eclipse PDE or workbench.

推荐答案

您需要阅读以下资源.这看起来像是额外的工作,但相信我,你的工作会轻松很多,而且这些文章并不长.

You need to read the following resources. It may seem like extra work but believe me your job will be a lot easier and these articles aren't really long.

  • 可撤消的操作
  • 撤消和IDE工作台
  • 撤消示例

您需要执行的基本步骤是:

The basic steps you need to perform are:

1) 在编辑器中为撤消/重做操作添加操作处理程序

1) Add action handlers for undo/redo operations in your editor

@Override
public void init(IEditorSite site, IEditorInput editorInput) {
    ...

    UndoRedoActionGroup historyActionGroup = new UndoRedoActionGroup(editorSite, myUndoContext, true);
    historyActionGroup.fillActionBars(editorSite.getActionBars());
}

如果您在思考什么是 myUndoContext,您将通过阅读第一篇文章了解这一点.

If you are thinking what is myUndoContext, you will know this from reading the first article.

2) 创建自己的 IUndoableOperation 实现用户可以对您的数据进行的不同类型的修改.如果它只依赖于 XPath->"new value" 或 id->"new value" 之类的东西,它可能是处理所有修改的单个操作.或者,您可以有一系列不同的操作来修改每种类型的数据模型.由你决定.

2) Create your own IUndoableOperation implementations for different types of modifications that the user can make on your data. It could be a single operation that handles all your modifications if it only depends on something like XPath->"new value", or id->"new value". Or you could have a range of different operations for modifying each type of your data model. Its up to you.

3)仅通过您创建的操作对您的数据进行每一次修改

3) Make each and every modification to your data only through the operations you created

MyDataModifyingOperation op = new MyDataModifyingOperation(xpath, newValue, oldValue);
op.addContext(myUndoContext);
IStatus status = OperationHistoryFactory.getOperationHistory().execute(operation, null, null);

一旦你得到了基本的东西,你将需要看看其他一些高级的东西,比如在数据模型上添加某种变化监听机制,以便在撤消/重做修改数据时,你可以更新 UI.同样在大多数情况下,最好在执行操作时记录 UI 选择状态,以便在撤消或后续重做时可以将选择恢复到已修改的元素,以便用户在 Ctrl+z/Ctrl 时立即识别更改的内容+y 被按下.

Once you get the basic stuff working you will need to look at some other advanced stuff, like adding some kind of change listening mechanism on the data model so that when undo/redo modify the data, you can update the UI. Also in most cases it is desirable that when you perform an operation you record UI selection state, so that on undo or subsequent redos you can restore selection to the element that was modified so that the user immediately recognizes what changed when Ctrl+z/Ctrl+y was pressed.

相关文章