0

I'm trying to undo the setText() method effect in a JEditorPane. Here is my code:

public final class UndoManagerTestForJEditorPane {

private final JEditorPane editor = new JEditorPane();
private final UndoManager undoManager = new UndoManager();

public JComponent makeUI() {
    editor.setContentType("text/html");
    HTMLDocument document = (HTMLDocument) editor.getDocument();
    document.addUndoableEditListener(undoManager);
    editor.setText("Hello");

    JPanel p = new JPanel();
    p.add(new JButton(new AbstractAction("undo") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (undoManager.canUndo()) {
                undoManager.undo();
            }
        }
    }));
    p.add(new JButton(new AbstractAction("redo") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (undoManager.canRedo()) {
                undoManager.redo();
            }
        }
    }));
    p.add(new JButton(new AbstractAction("setText(new Date())") {
        @Override
        public void actionPerformed(ActionEvent e) {
            String str = new Date().toString();
            editor.setText(str);
        }
    }));

    Box box = Box.createVerticalBox();
    box.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    box.add(makePanel("Default", editor));

    JPanel pp = new JPanel(new BorderLayout());
    pp.add(box, BorderLayout.NORTH);
    pp.add(p, BorderLayout.SOUTH);
    return pp;
}

private static JPanel makePanel(String title, JComponent c) {
    JPanel p = new JPanel(new BorderLayout());
    p.setBorder(BorderFactory.createTitledBorder(title));
    p.add(c);
    return p;
}

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            createAndShowGUI();
        }
    });
}

public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new UndoManagerTestForJEditorPane().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
}
}

The default behaviour is done with four steps:

1) Nothing is done, the cursor doesn't even move..

2) The cursor gets down with almost 10 lines under the inserted word..

3) The text get disappeared..

4) the old text appears finally..

So, instead of these steps, could we do it just only with one undo step like in this link for JTextField JTextArea setText() & UndoManager, but with JEditorPane ?

The problem the replace method for JEditorPane does not get executed when setText() is called on JEditorPane...

Please any help ?

Thank you

Community
  • 1
  • 1
michael laudrup
  • 27
  • 3
  • 10
  • Perhaps you should have a look at http://alvinalexander.com/java/java-undo-redo – MadProgrammer Nov 17 '14 at 23:47
  • Thank you for your answer but I'm already using this approach, the problem is exactly when using for example: JEditorPane ed = new JEditorPane(); ed.setText("some text"); when I do undo, the behaviour is as described in the first post. Any help please ? – michael laudrup Nov 18 '14 at 05:40
  • Then you better provide a [runnable example](https://stackoverflow.com/help/mcve) which demonstrates your problem. This will result in less confusion and better responses – MadProgrammer Nov 18 '14 at 05:42
  • I added the code as a demo, thank you so much :) – michael laudrup Nov 18 '14 at 06:06

1 Answers1

1

You could do it with a separate class (can be nested to directly access the necessary GUI elements, if you only have to do your edits with informations from one class) which extends AbstractUndoableEdit. You can save the exact old state that you want to load after one undo operation and the exact new state which you want to reload after a redo operation. You can then set the correct values in the redo and undo methods directly by overriding them in the State class. This could look like this:

public final class UndoManagerTestForJEditorPane {

private final JEditorPane editor = new JEditorPane();
private final UndoManager undoManager = new UndoManager();

public JComponent makeUI() {
    editor.setContentType("text/html");
    HTMLDocument document = (HTMLDocument) editor.getDocument();
    //document.addUndoableEditListener(undoManager);  -> Not used anymore
    editor.setText("Hello");

    JPanel p = new JPanel();
    p.add(new JButton(new AbstractAction("undo") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (undoManager.canUndo()) {
                undoManager.undo();
            }
        }
    }));

    // New class to hold the state and load the correct string
    class State extends AbstractUndoableEdit
    {
        String oldText;
        String newText;

        State(String oldText, String newText)
        {
            this.oldText = oldText;
            this.newText = newText;
        }

        @Override
        public void undo() throws CannotUndoException {
            editor.setText(oldText);
        }

        @Override
        public boolean canUndo() {
            return true;
        }

        @Override
        public void redo() throws CannotRedoException {
            editor.setText(newText);
        }

        @Override
        public boolean canRedo() {
            return true;
        }


    }
    p.add(new JButton(new AbstractAction("redo") {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (undoManager.canRedo()) {
                undoManager.redo();
            }
        }
    }));
    p.add(new JButton(new AbstractAction("setText(new Date())") {
        @Override
        public void actionPerformed(ActionEvent e) {
            String str = new Date().toString();
            // Add a new edit by saving the old string (by calling getText) and the new string 'str'
            undoManager.addEdit(new State(editor.getText(), str));
            editor.setText(str);
        }
    }));



    Box box = Box.createVerticalBox();
    box.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    box.add(makePanel("Default", editor));

    JPanel pp = new JPanel(new BorderLayout());
    pp.add(box, BorderLayout.NORTH);
    pp.add(p, BorderLayout.SOUTH);
    return pp;
}

private static JPanel makePanel(String title, JComponent c) {
    JPanel p = new JPanel(new BorderLayout());
    p.setBorder(BorderFactory.createTitledBorder(title));
    p.add(c);
    return p;
}

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            createAndShowGUI();
        }
    });
}

public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new UndoManagerTestForJEditorPane().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
}
}
BluesSolo
  • 608
  • 9
  • 28
  • Thank you so much for your answer, it works fine but it disabled the listener for the editions that I made before clicking setText. So how should I do to keep trace of the previous editions ? Thank you again – michael laudrup Nov 18 '14 at 17:53
  • No problem, so it works now for you? I'm glad I could help you – BluesSolo Nov 19 '14 at 07:22
  • Yes thank you so much, I have a new problem with JEditorPane, I posted here, thank you again http://stackoverflow.com/questions/27005483/jscrollpane-does-not-scroll-down-to-the-caret-position-because-of-image-in-jedit – michael laudrup Nov 19 '14 at 15:09
  • Great, you're welcome. You should provide some code for your new problem. Otherwise we can't help. – BluesSolo Nov 19 '14 at 15:22
  • Hello, could you take a look on my new post ? Thank you so much – michael laudrup Nov 20 '14 at 13:55
  • Hello, sorry I was busy. It seems that your question was being closed in the meantime. – BluesSolo Nov 25 '14 at 14:25
  • Well, this is the new post because I had problems with that post.. http://stackoverflow.com/questions/27044987/jscrollpane-does-not-update-its-scroll-to-go-down-to-follow-the-caret-position-b – michael laudrup Nov 25 '14 at 16:58
  • Hello, here is a new problem: http://stackoverflow.com/questions/27180459/limit-characters-in-a-jformattedtextfield Could you help me with that please ? Thank you – michael laudrup Nov 28 '14 at 00:44
  • Hello, I can try. Can you accept the answer from this question? Then people will see that this one is solved ;) – BluesSolo Nov 28 '14 at 07:22
  • Done ;) it's not what I wanted but I resolved it in another way.. no problem – michael laudrup Nov 28 '14 at 14:13
  • Could you take a look on the new one http://stackoverflow.com/questions/27180459/limit-characters-in-a-jformattedtextfield ? Thank you – michael laudrup Nov 28 '14 at 16:10