Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement undo/redo functionality into Eclipse FormEditor?

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

  1. Implementation class is MyXMLFormEditor which extends FormEditor.

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

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

  4. 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:

  • When editor is dirty (user changed something into form editor and it is not saved) undo operation should revert back the changes in form editor as well as JDOM to its original state (i.e. the state when editor was non-dirty) and redo operation should again bring back the changes into FormEditor as well as JDOM and editor should become dirty.

Following is my code snippet:

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

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");
                }

}

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.

like image 458
BSalunke Avatar asked Oct 05 '22 11:10

BSalunke


1 Answers

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.

  • Undoable operations
  • Undo and IDE Workbench
  • Undo Example

The basic steps you need to perform are:

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());
}

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

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) 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);

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.

like image 76
Waqas Ilyas Avatar answered Oct 10 '22 03:10

Waqas Ilyas