Index: trunk/src/org/openstreetmap/josm/gui/dialogs/ChangesetDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/ChangesetDialog.java	(revision 18714)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/ChangesetDialog.java	(revision 18715)
@@ -10,7 +10,7 @@
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
+import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
-import java.awt.event.KeyEvent;
 import java.util.Arrays;
 import java.util.Collection;
@@ -22,5 +22,4 @@
 import java.util.stream.Collectors;
 
-import javax.swing.AbstractAction;
 import javax.swing.Action;
 import javax.swing.DefaultListSelectionModel;
@@ -35,4 +34,5 @@
 import javax.swing.event.ListSelectionListener;
 
+import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.actions.OpenBrowserAction;
 import org.openstreetmap.josm.actions.downloadtasks.ChangesetHeaderDownloadTask;
@@ -60,9 +60,8 @@
 import org.openstreetmap.josm.io.OnlineResource;
 import org.openstreetmap.josm.spi.preferences.Config;
-import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.OpenBrowser;
+import org.openstreetmap.josm.tools.Shortcut;
 import org.openstreetmap.josm.tools.bugreport.BugReportExceptionHandler;
-import org.openstreetmap.josm.tools.Shortcut;
 
 /**
@@ -297,13 +296,20 @@
      * Selects objects for the currently selected changesets.
      */
-    class SelectObjectsAction extends AbstractAction implements ListSelectionListener, ItemListener {
+    class SelectObjectsAction extends JosmAction implements ListSelectionListener, ItemListener {
 
         SelectObjectsAction() {
-            putValue(NAME, tr("Select"));
-            putValue(SHORT_DESCRIPTION, tr("Select all objects assigned to the currently selected changesets"));
-            new ImageProvider("dialogs", "select").getResource().attachImageIcon(this, true);
-            updateEnabledState();
-        }
-
+            super(tr("Select"), "dialogs/select", tr("Select all objects assigned to the currently selected changesets"),
+                    Shortcut.registerShortcut("changeset:select:objects",
+                            tr("Changesets: Select all objects assigned to the currently selected changesets"),
+                            KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
+            updateEnabledState();
+        }
+
+        /**
+         * Select objects based off of the changeset id
+         * @param ds The dataset to select objects from
+         * @param ids The ids to select
+         */
         public void selectObjectsByChangesetIds(DataSet ds, Set<Integer> ids) {
             if (ds == null || ids == null)
@@ -328,4 +334,5 @@
         }
 
+        @Override
         protected void updateEnabledState() {
             setEnabled(getCurrentChangesetList().getSelectedIndices().length > 0);
@@ -348,9 +355,11 @@
      *
      */
-    class ReadChangesetsAction extends AbstractAction implements ListSelectionListener, ItemListener {
+    class ReadChangesetsAction extends JosmAction implements ListSelectionListener, ItemListener {
         ReadChangesetsAction() {
-            putValue(NAME, tr("Download"));
-            putValue(SHORT_DESCRIPTION, tr("Download information about the selected changesets from the OSM server"));
-            new ImageProvider("download").getResource().attachImageIcon(this, true);
+            super(tr("Download"), "download", tr("Download information about the selected changesets from the OSM server"),
+                    Shortcut.registerShortcut("changeset:download:information",
+                            tr("Changesets: Download information about the selected changeset from the OSM server"),
+                            KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
             updateEnabledState();
         }
@@ -366,4 +375,5 @@
         }
 
+        @Override
         protected void updateEnabledState() {
             setEnabled(getCurrentChangesetList().getSelectedIndices().length > 0 && !NetworkManager.isOffline(OnlineResource.OSM_API));
@@ -385,9 +395,10 @@
      *
      */
-    class CloseOpenChangesetsAction extends AbstractAction implements ListSelectionListener, ItemListener {
+    class CloseOpenChangesetsAction extends JosmAction implements ListSelectionListener, ItemListener {
         CloseOpenChangesetsAction() {
-            putValue(NAME, tr("Close open changesets"));
-            putValue(SHORT_DESCRIPTION, tr("Close the selected open changesets"));
-            new ImageProvider("closechangeset").getResource().attachImageIcon(this, true);
+            super(tr("Close open changesets"), "closechangeset", tr("Close the selected open changesets"),
+                    Shortcut.registerShortcut("changeset:close",
+                            tr("Changesets: Close the selected open changesets"), KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
             updateEnabledState();
         }
@@ -401,4 +412,5 @@
         }
 
+        @Override
         protected void updateEnabledState() {
             setEnabled(getCurrentChangesetListModel().hasSelectedOpenChangesets());
@@ -420,9 +432,10 @@
      *
      */
-    class ShowChangesetInfoAction extends AbstractAction implements ListSelectionListener, ItemListener {
+    class ShowChangesetInfoAction extends JosmAction implements ListSelectionListener, ItemListener {
         ShowChangesetInfoAction() {
-            putValue(NAME, tr("Show info"));
-            putValue(SHORT_DESCRIPTION, tr("Open a web page for each selected changeset"));
-            new ImageProvider("help/internet").getResource().attachImageIcon(this, true);
+            super(tr("Show info"), "help/internet", tr("Open a web page for each selected changeset"),
+                    Shortcut.registerShortcut("changeset:info",
+                            tr("Changesets: Open a web page for each selected changeset"), KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
             updateEnabledState();
         }
@@ -441,4 +454,5 @@
         }
 
+        @Override
         protected void updateEnabledState() {
             setEnabled(getCurrentChangesetList().getSelectedIndices().length > 0);
@@ -460,9 +474,11 @@
      *
      */
-    class LaunchChangesetManagerAction extends AbstractAction {
+    class LaunchChangesetManagerAction extends JosmAction {
         LaunchChangesetManagerAction() {
-            putValue(NAME, tr("Details"));
-            putValue(SHORT_DESCRIPTION, tr("Opens the Changeset Manager window for the selected changesets"));
-            new ImageProvider("dialogs/changeset", "changesetmanager").getResource().attachImageIcon(this, true);
+            super(tr("Details"), "dialogs/changeset/changesetmanager", tr("Opens the Changeset Manager window for the selected changesets"),
+                    Shortcut.registerShortcut("changeset:launch:manager",
+                            tr("Changesets: Opens the Changeset Manager window for the selected changesets"),
+                            KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
         }
 
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java	(revision 18714)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/CommandStackDialog.java	(revision 18715)
@@ -17,5 +17,4 @@
 import java.util.Set;
 
-import javax.swing.AbstractAction;
 import javax.swing.Box;
 import javax.swing.JComponent;
@@ -39,4 +38,5 @@
 import org.openstreetmap.josm.actions.AutoScaleAction;
 import org.openstreetmap.josm.actions.AutoScaleAction.AutoScaleMode;
+import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.command.PseudoCommand;
@@ -54,5 +54,4 @@
 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
 import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.InputMapUtils;
 import org.openstreetmap.josm.tools.Shortcut;
@@ -411,5 +410,5 @@
      * Action that selects the objects that take part in a command.
      */
-    public class SelectAction extends AbstractAction implements IEnabledStateUpdating {
+    public class SelectAction extends JosmAction implements IEnabledStateUpdating {
 
         /**
@@ -417,7 +416,32 @@
          */
         public SelectAction() {
-            putValue(NAME, tr("Select"));
-            putValue(SHORT_DESCRIPTION, tr("Selects the objects that take part in this command (unless currently deleted)"));
-            new ImageProvider("dialogs", "select").getResource().attachImageIcon(this, true);
+            this(tr("Select"), "dialogs/select", tr("Selects the objects that take part in this command (unless currently deleted)"),
+                    Shortcut.registerShortcut("command:stack:select", tr("Command Stack: Select"), KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, null, false);
+        }
+
+        /**
+         * Constructs a new {@code SelectAction} that calls
+         * {@link JosmAction#JosmAction(String, String, String, Shortcut, boolean, String, boolean)}
+         *
+         * The new super for all CommandStack actions.
+         *
+         * Use this super constructor to setup your action.
+         *
+         * @param name the action's text as displayed on the menu (if it is added to a menu)
+         * @param iconName the filename of the icon to use
+         * @param tooltip  a longer description of the action that will be displayed in the tooltip. Please note
+         *           that html is not supported for menu actions on some platforms.
+         * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always
+         *            do want a shortcut, remember you can always register it with group=none, so you
+         *            won't be assigned a shortcut unless the user configures one. If you pass null here,
+         *            the user CANNOT configure a shortcut for your action.
+         * @param registerInToolbar register this action for the toolbar preferences?
+         * @param toolbarId identifier for the toolbar preferences. The iconName is used, if this parameter is null
+         * @param installAdapters false, if you don't want to install layer changed and selection changed adapters
+         */
+        protected SelectAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean registerInToolbar,
+                               String toolbarId, boolean installAdapters) {
+            super(name, iconName, tooltip, shortcut, registerInToolbar, toolbarId, installAdapters);
         }
 
@@ -465,8 +489,8 @@
          */
         public SelectAndZoomAction() {
-            putValue(NAME, tr("Select and zoom"));
-            putValue(SHORT_DESCRIPTION,
-                    tr("Selects the objects that take part in this command (unless currently deleted), then and zooms to it"));
-            new ImageProvider("dialogs/autoscale", "selection").getResource().attachImageIcon(this, true);
+            super(tr("Select and zoom"), "dialogs/autoscale/selection",
+                    tr("Selects the objects that take part in this command (unless currently deleted), then and zooms to it"),
+                    Shortcut.registerShortcut("command:stack:select_and_zoom", tr("Command Stack: Select and zoom"),
+                            KeyEvent.VK_UNDEFINED, Shortcut.NONE), false, null, false);
         }
 
@@ -489,5 +513,5 @@
      * Action to undo or redo all commands up to (and including) the seleced item.
      */
-    protected class UndoRedoAction extends AbstractAction implements IEnabledStateUpdating {
+    protected class UndoRedoAction extends JosmAction implements IEnabledStateUpdating {
         private final UndoRedoType type;
         private final JTree tree;
@@ -498,15 +522,18 @@
          */
         public UndoRedoAction(UndoRedoType type) {
+            // This is really annoying. JEP 8300786 might fix this.
+            super(UndoRedoType.UNDO == type ? tr("Undo") : tr("Redo"),
+                    UndoRedoType.UNDO == type ? "undo" : "redo",
+                    UndoRedoType.UNDO == type ? tr("Undo the selected and all later commands")
+                            : tr("Redo the selected and all earlier commands"),
+                    UndoRedoType.UNDO == type
+                            ? Shortcut.registerShortcut("command:stack:undo", tr("Command Stack: Undo"), KeyEvent.VK_UNDEFINED, Shortcut.NONE)
+                            : Shortcut.registerShortcut("command:stack:redo", tr("Command Stack: Redo"), KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
             this.type = type;
             if (UndoRedoType.UNDO == type) {
                 tree = undoTree;
-                putValue(NAME, tr("Undo"));
-                putValue(SHORT_DESCRIPTION, tr("Undo the selected and all later commands"));
-                new ImageProvider("undo").getResource().attachImageIcon(this, true);
             } else {
                 tree = redoTree;
-                putValue(NAME, tr("Redo"));
-                putValue(SHORT_DESCRIPTION, tr("Redo the selected and all earlier commands"));
-                new ImageProvider("redo").getResource().attachImageIcon(this, true);
             }
         }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/FilterDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/FilterDialog.java	(revision 18714)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/FilterDialog.java	(revision 18715)
@@ -27,4 +27,5 @@
 import javax.swing.table.TableModel;
 
+import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.actions.mapmode.MapMode;
 import org.openstreetmap.josm.actions.search.SearchAction;
@@ -52,5 +53,4 @@
 import org.openstreetmap.josm.gui.util.TableHelper;
 import org.openstreetmap.josm.gui.widgets.DisableShortcutsOnFocusGainedTextField;
-import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.InputMapUtils;
 import org.openstreetmap.josm.tools.Shortcut;
@@ -119,10 +119,8 @@
     };
 
-    private abstract class FilterAction extends AbstractAction implements IEnabledStateUpdating {
-
-        FilterAction(String name, String description, String icon) {
-            putValue(NAME, name);
-            putValue(SHORT_DESCRIPTION, description);
-            new ImageProvider("dialogs", icon).getResource().attachImageIcon(this, true);
+    private abstract class FilterAction extends JosmAction implements IEnabledStateUpdating {
+
+        FilterAction(String name, String description, String icon, Shortcut shortcut) {
+            super(name, "dialogs/" + icon, description, shortcut, false, false);
         }
 
@@ -135,5 +133,6 @@
     private class AddAction extends FilterAction {
         AddAction() {
-            super(tr("Add"), tr("Add filter."), /* ICON(dialogs/) */ "add");
+            super(tr("Add"), tr("Add filter."), /* ICON(dialogs/) */ "add",
+                    Shortcut.registerShortcut("filter:add", tr("Filter: Add"), KeyEvent.VK_UNDEFINED, Shortcut.NONE));
         }
 
@@ -154,5 +153,6 @@
     private class EditAction extends FilterAction {
         EditAction() {
-            super(tr("Edit"), tr("Edit filter."), /* ICON(dialogs/) */ "edit");
+            super(tr("Edit"), tr("Edit filter."), /* ICON(dialogs/) */ "edit",
+                    Shortcut.registerShortcut("filter:edit", tr("Filter: Edit"), KeyEvent.VK_UNDEFINED, Shortcut.NONE));
         }
 
@@ -171,5 +171,6 @@
     private class DeleteAction extends FilterAction {
         DeleteAction() {
-            super(tr("Delete"), tr("Delete filter."), /* ICON(dialogs/) */ "delete");
+            super(tr("Delete"), tr("Delete filter."), /* ICON(dialogs/) */ "delete",
+                    Shortcut.registerShortcut("filter:delete", tr("Filter: Delete"), KeyEvent.VK_UNDEFINED, Shortcut.NONE));
         }
 
@@ -182,5 +183,6 @@
     private class MoveUpAction extends FilterAction {
         MoveUpAction() {
-            super(tr("Up"), tr("Move filter up."), /* ICON(dialogs/) */ "up");
+            super(tr("Up"), tr("Move filter up."), /* ICON(dialogs/) */ "up",
+                    Shortcut.registerShortcut("filter:up", tr("Filter: Move up"), KeyEvent.VK_UNDEFINED, Shortcut.NONE));
         }
 
@@ -198,5 +200,6 @@
     private class MoveDownAction extends FilterAction {
         MoveDownAction() {
-            super(tr("Down"), tr("Move filter down."), /* ICON(dialogs/) */ "down");
+            super(tr("Down"), tr("Move filter down."), /* ICON(dialogs/) */ "down",
+                    Shortcut.registerShortcut("filter:down", tr("Filter: Move down"), KeyEvent.VK_UNDEFINED, Shortcut.NONE));
         }
 
@@ -214,5 +217,6 @@
     private class SortAction extends FilterAction {
         SortAction() {
-            super(tr("Sort"), tr("Sort filters."), /* ICON(dialogs/) */ "sort");
+            super(tr("Sort"), tr("Sort filters."), /* ICON(dialogs/) */ "sort",
+                    Shortcut.registerShortcut("filter:sort", tr("Filter: Sort"), KeyEvent.VK_UNDEFINED, Shortcut.NONE));
         }
 
@@ -230,5 +234,6 @@
     private class ReverseAction extends FilterAction {
         ReverseAction() {
-            super(tr("Reverse"), tr("Reverse the filters order."), /* ICON(dialogs/) */ "reverse");
+            super(tr("Reverse"), tr("Reverse the filters order."), /* ICON(dialogs/) */ "reverse",
+                    Shortcut.registerShortcut("filter:reverse", tr("Filter: Reverse"), KeyEvent.VK_UNDEFINED, Shortcut.NONE));
         }
 
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/MapPaintDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/MapPaintDialog.java	(revision 18714)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/MapPaintDialog.java	(revision 18715)
@@ -311,15 +311,16 @@
     }
 
-    protected class OnOffAction extends AbstractAction implements ListSelectionListener {
+    protected class OnOffAction extends JosmAction implements ListSelectionListener {
         /**
          * Constructs a new {@code OnOffAction}.
          */
         public OnOffAction() {
-            putValue(NAME, tr("On/Off"));
-            putValue(SHORT_DESCRIPTION, tr("Turn selected styles on or off"));
-            new ImageProvider("apply").getResource().attachImageIcon(this, true);
+            super(tr("On/Off"), "apply", tr("Turn selected styles on or off"),
+                    Shortcut.registerShortcut("map:paint:style:on_off", tr("Filter: Add"), KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
             updateEnabledState();
         }
 
+        @Override
         protected void updateEnabledState() {
             setEnabled(!cbWireframe.isSelected() && tblStyles.getSelectedRowCount() > 0);
@@ -342,5 +343,5 @@
      * The action to move down the currently selected entries in the list.
      */
-    protected class MoveUpDownAction extends AbstractAction implements ListSelectionListener {
+    protected class MoveUpDownAction extends JosmAction implements ListSelectionListener {
 
         private final int increment;
@@ -351,11 +352,16 @@
          */
         public MoveUpDownAction(boolean isDown) {
+            super(isDown ? tr("Down") : tr("Up"), "dialogs/" + (isDown ? "down" : "up"),
+                    isDown ? tr("Move the selected entry one row down.") : tr("Move the selected entry one row up."),
+                    isDown ? Shortcut.registerShortcut("map:paint:style:down", tr("Map Paint Styles: Move selected entry down"),
+                            KeyEvent.VK_UNDEFINED, Shortcut.NONE)
+                    : Shortcut.registerShortcut("map:paint:style:up", tr("Map Paint Styles: Move selected entry up"),
+                            KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
             increment = isDown ? 1 : -1;
-            putValue(NAME, isDown ? tr("Down") : tr("Up"));
-            new ImageProvider("dialogs", isDown ? "down" : "up").getResource().attachImageIcon(this, true);
-            putValue(SHORT_DESCRIPTION, isDown ? tr("Move the selected entry one row down.") : tr("Move the selected entry one row up."));
             updateEnabledState();
         }
 
+        @Override
         public void updateEnabledState() {
             int[] sel = tblStyles.getSelectedRows();
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/NotesDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/NotesDialog.java	(revision 18714)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/NotesDialog.java	(revision 18715)
@@ -19,6 +19,6 @@
 import java.util.function.Predicate;
 import java.util.regex.Pattern;
-
-import javax.swing.AbstractAction;
+import java.util.stream.Collectors;
+
 import javax.swing.AbstractListModel;
 import javax.swing.DefaultListCellRenderer;
@@ -35,4 +35,5 @@
 
 import org.openstreetmap.josm.actions.DownloadNotesInViewAction;
+import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.actions.UploadNotesAction;
 import org.openstreetmap.josm.actions.mapmode.AddNoteAction;
@@ -343,5 +344,5 @@
                 filteredData.addAll(data);
             } else {
-                data.stream().filter(filter).forEach(filteredData::add);
+                filteredData.addAll(data.stream().filter(filter).collect(Collectors.toList()));
             }
             fireContentsChanged(this, 0, getSize());
@@ -351,4 +352,8 @@
         }
 
+        /**
+         * Set the note data
+         * @param noteList The notes to show
+         */
         public void setData(Collection<Note> noteList) {
             data.clear();
@@ -357,4 +362,7 @@
         }
 
+        /**
+         * Clear the note data
+         */
         public void clearData() {
             displayList.clearSelection();
@@ -364,5 +372,8 @@
     }
 
-    class AddCommentAction extends AbstractAction {
+    /**
+     * The action to add a new comment to OSM
+     */
+    class AddCommentAction extends JosmAction {
 
         /**
@@ -370,7 +381,7 @@
          */
         AddCommentAction() {
-            putValue(SHORT_DESCRIPTION, tr("Add comment"));
-            putValue(NAME, tr("Comment"));
-            new ImageProvider("dialogs/notes", "note_comment").getResource().attachImageIcon(this, true);
+            super(tr("Comment"), "dialogs/notes/note_comment", tr("Add comment"),
+                    Shortcut.registerShortcut("notes:comment:add", tr("Notes: Add comment"), KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
         }
 
@@ -396,5 +407,8 @@
     }
 
-    class CloseAction extends AbstractAction {
+    /**
+     * Close a note
+     */
+    class CloseAction extends JosmAction {
 
         /**
@@ -402,7 +416,7 @@
          */
         CloseAction() {
-            putValue(SHORT_DESCRIPTION, tr("Close note"));
-            putValue(NAME, tr("Close"));
-            new ImageProvider("dialogs/notes", "note_closed").getResource().attachImageIcon(this, true);
+            super(tr("Close"), "dialogs/notes/note_closed", tr("Close note"),
+                    Shortcut.registerShortcut("notes:comment:close", tr("Notes: Close note"), KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
         }
 
@@ -428,5 +442,8 @@
     }
 
-    class NewAction extends AbstractAction {
+    /**
+     * Create a new note
+     */
+    class NewAction extends JosmAction {
 
         /**
@@ -434,7 +451,7 @@
          */
         NewAction() {
-            putValue(SHORT_DESCRIPTION, tr("Create a new note"));
-            putValue(NAME, tr("Create"));
-            new ImageProvider("dialogs/notes", "note_new").getResource().attachImageIcon(this, true);
+            super(tr("Create"), "dialogs/notes/note_new", tr("Create a new note"),
+                    Shortcut.registerShortcut("notes:comment:new", tr("Notes: New note"), KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
         }
 
@@ -450,5 +467,8 @@
     }
 
-    class ReopenAction extends AbstractAction {
+    /**
+     * Reopen a note
+     */
+    class ReopenAction extends JosmAction {
 
         /**
@@ -456,7 +476,7 @@
          */
         ReopenAction() {
-            putValue(SHORT_DESCRIPTION, tr("Reopen note"));
-            putValue(NAME, tr("Reopen"));
-            new ImageProvider("dialogs/notes", "note_open").getResource().attachImageIcon(this, true);
+            super(tr("Reopen"), "dialogs/notes/note_open", tr("Reopen note"),
+                    Shortcut.registerShortcut("notes:comment:reopen", tr("Notes: Reopen note"), KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
         }
 
@@ -476,5 +496,8 @@
     }
 
-    class SortAction extends AbstractAction {
+    /**
+     * Sort notes
+     */
+    class SortAction extends JosmAction {
 
         /**
@@ -482,7 +505,7 @@
          */
         SortAction() {
-            putValue(SHORT_DESCRIPTION, tr("Sort notes"));
-            putValue(NAME, tr("Sort"));
-            new ImageProvider("dialogs", "sort").getResource().attachImageIcon(this, true);
+            super(tr("Sort"), "dialogs/sort", tr("Sort notes"),
+                    Shortcut.registerShortcut("notes:comment:sort", tr("Notes: Sort notes"), KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
         }
 
@@ -497,9 +520,12 @@
     }
 
-    class OpenInBrowserAction extends AbstractAction {
+    /**
+     * Open the note in a browser
+     */
+    class OpenInBrowserAction extends JosmAction {
         OpenInBrowserAction() {
-            super(tr("Open in browser"));
-            putValue(SHORT_DESCRIPTION, tr("Open the note in an external browser"));
-            new ImageProvider("help", "internet").getResource().attachImageIcon(this, true);
+            super(tr("Open in browser"), "help/internet", tr("Open the note in an external browser"),
+                    Shortcut.registerShortcut("notes:comment:open_in_browser", tr("Notes: Open note in browser"),
+                            KeyEvent.VK_UNDEFINED, Shortcut.NONE), false, false);
         }
 
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java	(revision 18714)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java	(revision 18715)
@@ -19,5 +19,4 @@
 import java.util.stream.IntStream;
 
-import javax.swing.AbstractAction;
 import javax.swing.AbstractListModel;
 import javax.swing.DefaultListSelectionModel;
@@ -36,4 +35,5 @@
 import org.openstreetmap.josm.actions.ExpertToggleAction;
 import org.openstreetmap.josm.actions.HistoryInfoAction;
+import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.actions.relation.AddSelectionToRelations;
 import org.openstreetmap.josm.actions.relation.DeleteRelationsAction;
@@ -89,5 +89,4 @@
 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
 import org.openstreetmap.josm.spi.preferences.Config;
-import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.InputMapUtils;
 import org.openstreetmap.josm.tools.PlatformManager;
@@ -376,12 +375,15 @@
      * The action for creating a new relation.
      */
-    static class NewAction extends AbstractAction implements LayerChangeListener, ActiveLayerChangeListener {
+    static class NewAction extends JosmAction implements LayerChangeListener, ActiveLayerChangeListener {
         NewAction() {
-            putValue(SHORT_DESCRIPTION, tr("Create a new relation"));
-            putValue(NAME, tr("New"));
-            new ImageProvider("dialogs", "add").getResource().attachImageIcon(this, true);
+            super(tr("New"), "dialogs/add", tr("Create a new relation"),
+                    Shortcut.registerShortcut("relation:new", tr("Create a new relation"), KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, false);
             updateEnabledState();
         }
 
+        /**
+         * Make a new relation
+         */
         public void run() {
             RelationEditor.getEditor(MainApplication.getLayerManager().getEditLayer(), null, null).setVisible(true);
@@ -393,4 +395,5 @@
         }
 
+        @Override
         protected void updateEnabledState() {
             setEnabled(MainApplication.getLayerManager().getEditLayer() != null);
@@ -514,5 +517,5 @@
             // extract the removed relations
             Set<Relation> removedRelations = removedPrimitives.stream()
-                    .filter(p -> p instanceof Relation).map(p -> (Relation) p)
+                    .filter(Relation.class::isInstance).map(Relation.class::cast)
                     .collect(Collectors.toSet());
             if (removedRelations.isEmpty())
@@ -598,4 +601,7 @@
         }
 
+        /**
+         * Update the title for the relation list dialog
+         */
         public void updateTitle() {
             if (!relations.isEmpty() && relations.size() != getSize()) {
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java	(revision 18714)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java	(revision 18715)
@@ -30,4 +30,5 @@
 
 import org.openstreetmap.josm.actions.AbstractInfoAction;
+import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.data.osm.DataSelectionListener;
 import org.openstreetmap.josm.data.osm.IPrimitive;
@@ -46,5 +47,4 @@
 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
 import org.openstreetmap.josm.spi.preferences.Config;
-import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.OpenBrowser;
@@ -164,5 +164,8 @@
     }
 
-    class SelectUsersPrimitivesAction extends AbstractAction implements ListSelectionListener {
+    /**
+     * Select the primitives that a user modified <i>last</i>.
+     */
+    class SelectUsersPrimitivesAction extends JosmAction implements ListSelectionListener {
 
         /**
@@ -170,10 +173,13 @@
          */
         SelectUsersPrimitivesAction() {
-            putValue(NAME, tr("Select"));
-            putValue(SHORT_DESCRIPTION, tr("Select objects submitted by this user"));
-            new ImageProvider("dialogs", "select").getResource().attachImageIcon(this, true);
+            super(tr("Select"), "dialogs/select", tr("Select objects submitted by this user"),
+                    Shortcut.registerShortcut("user:select_primitives", tr("User: objects submitted by selected user"),
+                            KeyEvent.VK_UNDEFINED, Shortcut.NONE), false, false);
             updateEnabledState();
         }
 
+        /**
+         * Select the primitives owned by the selected users
+         */
         public void select() {
             int[] indexes = userTable.getSelectedRows();
@@ -188,4 +194,5 @@
         }
 
+        @Override
         protected void updateEnabledState() {
             setEnabled(userTable != null && userTable.getSelectedRowCount() > 0);
@@ -204,8 +211,7 @@
 
         ShowUserInfoAction() {
-            super(false);
-            putValue(NAME, tr("Show info"));
-            putValue(SHORT_DESCRIPTION, tr("Launches a browser with information about the user"));
-            new ImageProvider("help/internet").getResource().attachImageIcon(this, true);
+            super(tr("Show info"), "help/internet", tr("Launches a browser with information about the user"),
+                    Shortcut.registerShortcut("user:open_in_browser", tr("User: Show info in browser"), KeyEvent.VK_UNDEFINED, Shortcut.NONE),
+                    false, null, false);
             updateEnabledState();
         }
@@ -235,5 +241,5 @@
             if (infoObject instanceof User) {
                 User user = (User) infoObject;
-                return Config.getUrls().getBaseUserUrl() + '/' + Utils.encodeUrl(user.getName()).replaceAll("\\+", "%20");
+                return Config.getUrls().getBaseUserUrl() + '/' + Utils.encodeUrl(user.getName()).replace("+", "%20");
             } else {
                 return null;
