Index: trunk/src/org/openstreetmap/josm/gui/widgets/JosmTextField.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/widgets/JosmTextField.java	(revision 8000)
+++ trunk/src/org/openstreetmap/josm/gui/widgets/JosmTextField.java	(revision 8002)
@@ -18,5 +18,5 @@
 /**
  * Subclass of {@link JTextField} that:<ul>
- * <li>adds a "native" context menu (undo/cut/copy/paste/select all)</li>
+ * <li>adds a "native" context menu (undo/redo/cut/copy/paste/select all)</li>
  * <li>adds an optional "hint" displayed when no text has been entered</li>
  * <li>disables the global advanced key press detector when focused</li>
Index: trunk/src/org/openstreetmap/josm/gui/widgets/TextContextualPopupMenu.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/widgets/TextContextualPopupMenu.java	(revision 8000)
+++ trunk/src/org/openstreetmap/josm/gui/widgets/TextContextualPopupMenu.java	(revision 8002)
@@ -4,4 +4,5 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.GraphicsEnvironment;
 import java.awt.Toolkit;
 import java.awt.event.ActionEvent;
@@ -20,4 +21,5 @@
 import javax.swing.text.DefaultEditorKit;
 import javax.swing.text.JTextComponent;
+import javax.swing.undo.CannotRedoException;
 import javax.swing.undo.CannotUndoException;
 import javax.swing.undo.UndoManager;
@@ -30,4 +32,5 @@
  * <ul>
  * <li>Undo</li>
+ * <li>Redo</li>
  * <li>Cut</li>
  * <li>Copy</li>
@@ -43,8 +46,20 @@
 
     protected JTextComponent component = null;
-    protected UndoAction undoAction = null;
+    protected final UndoAction undoAction = new UndoAction();
+    protected final RedoAction redoAction = new RedoAction();
+    protected final UndoManager undo = new UndoManager();
+
+    protected final UndoableEditListener undoEditListener = new UndoableEditListener() {
+        @Override
+        public void undoableEditHappened(UndoableEditEvent e) {
+            undo.addEdit(e.getEdit());
+            undoAction.updateUndoState();
+            redoAction.updateRedoState();
+        }
+    };
 
     protected final PropertyChangeListener propertyChangeListener = new PropertyChangeListener() {
-        @Override public void propertyChange(PropertyChangeEvent evt) {
+        @Override
+        public void propertyChange(PropertyChangeEvent evt) {
             if (EDITABLE.equals(evt.getPropertyName())) {
                 removeAll();
@@ -71,8 +86,11 @@
             this.component = component;
             if (component.isEditable()) {
-                undoAction = new UndoAction();
-                component.getDocument().addUndoableEditListener(undoAction);
-                component.getInputMap().put(
-                        KeyStroke.getKeyStroke(KeyEvent.VK_Z, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), undoAction);
+                component.getDocument().addUndoableEditListener(undoEditListener);
+                if (!GraphicsEnvironment.isHeadless()) {
+                    component.getInputMap().put(
+                            KeyStroke.getKeyStroke(KeyEvent.VK_Z, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), undoAction);
+                    component.getInputMap().put(
+                            KeyStroke.getKeyStroke(KeyEvent.VK_Y, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), redoAction);
+                }
             }
             addMenuEntries();
@@ -85,4 +103,5 @@
         if (component.isEditable()) {
             add(new JMenuItem(undoAction));
+            add(new JMenuItem(redoAction));
             addSeparator();
             addMenuEntry(component, tr("Cut"), DefaultEditorKit.cutAction, null);
@@ -106,9 +125,6 @@
             component.removePropertyChangeListener(EDITABLE, propertyChangeListener);
             removeAll();
-            if (undoAction != null) {
-                component.getDocument().removeUndoableEditListener(undoAction);
-                undoAction = null;
-            }
-            this.component = null;
+            component.getDocument().removeUndoableEditListener(undoEditListener);
+            component = null;
         }
         return this;
@@ -164,7 +180,5 @@
     }
 
-    protected static class UndoAction extends AbstractAction implements UndoableEditListener {
-
-        private final UndoManager undoManager = new UndoManager();
+    protected class UndoAction extends AbstractAction {
 
         /**
@@ -177,13 +191,7 @@
 
         @Override
-        public void undoableEditHappened(UndoableEditEvent e) {
-            undoManager.addEdit(e.getEdit());
-            setEnabled(undoManager.canUndo());
-        }
-
-        @Override
         public void actionPerformed(ActionEvent e) {
             try {
-                undoManager.undo();
+                undo.undo();
             } catch (CannotUndoException ex) {
                 if (Main.isTraceEnabled()) {
@@ -191,5 +199,51 @@
                 }
             } finally {
-                setEnabled(undoManager.canUndo());
+                updateUndoState();
+                redoAction.updateRedoState();
+            }
+        }
+
+        public void updateUndoState() {
+            if (undo.canUndo()) {
+                setEnabled(true);
+                putValue(Action.NAME, undo.getUndoPresentationName());
+            } else {
+                setEnabled(false);
+                putValue(Action.NAME, tr("Undo"));
+            }
+        }
+    }
+
+    protected class RedoAction extends AbstractAction {
+
+        /**
+         * Constructs a new {@code RedoAction}.
+         */
+        public RedoAction() {
+            super(tr("Redo"));
+            setEnabled(false);
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            try {
+                undo.redo();
+            } catch (CannotRedoException ex) {
+                if (Main.isTraceEnabled()) {
+                    Main.trace(ex.getMessage());
+                }
+            } finally {
+                updateRedoState();
+                undoAction.updateUndoState();
+            }
+        }
+
+        public void updateRedoState() {
+            if (undo.canRedo()) {
+                setEnabled(true);
+                putValue(Action.NAME, undo.getRedoPresentationName());
+            } else {
+                setEnabled(false);
+                putValue(Action.NAME, tr("Redo"));
             }
         }
