0

I tried to apply memento pattern to include undo/redo functions in my tex editor app. Let's say it is simplified version :). So far, I haven't figured out how to save and then restore the exact text input from the keyboard. I mean, I have to link the state attribute with the textarea in my code, plus some other modifications. I tried to stuck the whole code in three classes, Main, Editor, Memento like below Any hints? Thank you

public class Main {
    public static void main(String[] args) {
        
        Editor viewEditor = new Editor();
        viewEditor.setVisible(true);

        //Storing changes in ArrayList
        List<Memento> mementoList = new ArrayList<Memento>();
        
        viewEditor.setState(" first and only state :)");
        mementoList.add(viewEditor.saveStatetoMemento());
    
        viewEditor.getStatefromMemento(mementoList.get(0));
       

    }

}

public class Editor extends JFrame {

    String state;

    public void setState(String state) {
        this.state = state;
    }
    public String getState(String state) {
        return state;
    }
    public Memento saveStatetoMemento() {
        System.out.println("Saving state to Memento in Editor.java ");
        return new Memento(state);
    }

    public void getStatefromMemento(Memento memento) {
        state = memento.getState();
        System.out.println("State restored from memento" + state);
    }
    //Using UndoManager for handling undo/redo/ operations 
    private UndoManager um = new UndoManager();

    public Editor() {
        initUI();
    }

    public final void initUI() {
        //Panel
        JPanel panel = new JPanel();
        //Text Field
        final JTextArea textArea = new JTextArea("");
        textArea.getDocument().addUndoableEditListener(new UndoableEditListener() {
            public void undoableEditHappened(UndoableEditEvent e) {
                um.addEdit(e.getEdit());
            
         state = textArea.getText();
            }
        });
        textArea.setPreferredSize(new Dimension(550, 600));
        textArea.setLineWrap(true);
        textArea.setFont(new Font("Arial", Font.PLAIN, 20));
        textArea.setEditable(true);

        // Addind text field to panel
        panel.add(textArea);

        // Adding panel to JFrame
        add(panel);
        pack();

        // Menubar
        JMenuBar menubar = new JMenuBar();
        // Menu Brudnopis
        JMenu brudnopis = new JMenu("Brudnopis");
        brudnopis.setMnemonic(KeyEvent.VK_B);
        // Menu Items: Zakoncz
        JMenuItem eMenuItemZakoncz = new JMenuItem("Zakoncz");
        eMenuItemZakoncz.setMnemonic(KeyEvent.VK_K);
        eMenuItemZakoncz.setToolTipText("Zakoncz program");
        // Adding action for the item: "Zakoncz"
        eMenuItemZakoncz.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                System.exit(0);
            }
        });

        //Menu Edit Item
        JMenu edit = new JMenu("Edycja");
        edit.setMnemonic(KeyEvent.VK_H);
        //Menu items: undo and redo
        JMenuItem undo = new JMenuItem("Undo");
        undo.setMnemonic(KeyEvent.VK_Z);
        undo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK));
        //undo.setAction(a);
        undo.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                if (um.canUndo()) {
                    um.undo();
                }
            }
        });

        JMenuItem redo = new JMenuItem("Redo");
        redo.setMnemonic(KeyEvent.VK_Y);
        redo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, ActionEvent.CTRL_MASK));
        redo.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                if (um.canRedo()) {
                    um.redo();
                }
            }
        });

        //Adding 'brudnopis' to menubar
        menubar.add(brudnopis);
        menubar.add(edit);
        setJMenuBar(menubar);

        //Dodanie opcji do paska menu
        brudnopis.add(eMenuItemZakoncz);
        edit.add(undo);
        edit.add(redo);

        setTitle("Brudnopis");
        setSize(600, 700);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
}




public class Memento {

private final String state;

public Memento(String state) {
this.state = state;
    }

public String getState() {
    return state;
}

 }

Wojciech
  • 3
  • 3

1 Answers1

0

You need to attach an event handler to when the TextArea's state changes. Currently you only store its state when the program starts. The exact way you do this is a design decision to make - if you experiment with existing text editors you will see that they generally do something different than store state on every keystroke.

You have defined an ArrayList to store states. A stack is a more suitable structure to use for the Memento pattern. If you are supporting Redo, then you need a Redo stack as well.

I don't know if you are attempting this as an academic exercise or for a product. If it is the latter, then it would seem more efficient to just find an existing Java text control that already has a mature undo/redo feature.

Peter Dongan
  • 1,762
  • 12
  • 17