Index: trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 3408)
@@ -519,83 +519,4 @@
     }
 
-    /*------------------------------------------------------
-     * FILTERED / DISABLED HANDLING
-     *-----------------------------------------------------*/
-
-    /**
-     * TODO: can be removed if no longer needed
-     *
-     * Currently, the filter flags are updated directly for the primitives.
-     * On the long run there might be listeners for filter changes,
-     * so the control needs to be moved to this place again.
-     */
-
-    //    public void setDisabled(OsmPrimitive... osm) {
-    //        if (osm.length == 1 && osm[0] == null) {
-    //            setDisabled();
-    //            return;
-    //        }
-    //        clearDisabled(allPrimitives());
-    //        for (OsmPrimitive o : osm)
-    //            if (o != null) {
-    //                o.setDisabled(true);
-    //            }
-    //    }
-    //
-    //    public void setDisabled(Collection<? extends OsmPrimitive> selection) {
-    //        clearDisabled(nodes);
-    //        clearDisabled(ways);
-    //        clearDisabled(relations);
-    //        for (OsmPrimitive osm : selection) {
-    //            osm.setDisabled(true);
-    //        }
-    //    }
-    //
-    //    /**
-    //     * Remove the disabled parameter from every value in the collection.
-    //     * @param list The collection to remove the disabled parameter from.
-    //     */
-    //    private void clearDisabled(Collection<? extends OsmPrimitive> list) {
-    //        for (OsmPrimitive osm : list) {
-    //            osm.setDisabled(false);
-    //        }
-    //    }
-    //
-    //
-    //    public void setFiltered(Collection<? extends OsmPrimitive> selection) {
-    //        clearFiltered(nodes);
-    //        clearFiltered(ways);
-    //        clearFiltered(relations);
-    //        for (OsmPrimitive osm : selection) {
-    //            osm.setFiltered(true);
-    //        }
-    //    }
-    //
-    //    public void setFiltered(OsmPrimitive... osm) {
-    //        if (osm.length == 1 && osm[0] == null) {
-    //            setFiltered();
-    //            return;
-    //        }
-    //        clearFiltered(nodes);
-    //        clearFiltered(ways);
-    //        clearFiltered(relations);
-    //        for (OsmPrimitive o : osm)
-    //            if (o != null) {
-    //                o.setFiltered(true);
-    //            }
-    //    }
-    //
-    //    /**
-    //     * Remove the filtered parameter from every value in the collection.
-    //     * @param list The collection to remove the filtered parameter from.
-    //     */
-    //    private void clearFiltered(Collection<? extends OsmPrimitive> list) {
-    //        if (list == null)
-    //            return;
-    //        for (OsmPrimitive osm : list) {
-    //            osm.setFiltered(false);
-    //        }
-    //    }
-
     @Override public DataSet clone() {
         getReadLock().lock();
Index: trunk/src/org/openstreetmap/josm/gui/conflict/pair/properties/OperationCancelledException.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/conflict/pair/properties/OperationCancelledException.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/conflict/pair/properties/OperationCancelledException.java	(revision 3408)
@@ -6,20 +6,16 @@
     public OperationCancelledException() {
         super();
-        // TODO Auto-generated constructor stub
     }
 
     public OperationCancelledException(String message, Throwable cause) {
         super(message, cause);
-        // TODO Auto-generated constructor stub
     }
 
     public OperationCancelledException(String message) {
         super(message);
-        // TODO Auto-generated constructor stub
     }
 
     public OperationCancelledException(Throwable cause) {
         super(cause);
-        // TODO Auto-generated constructor stub
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 3408)
@@ -26,4 +26,5 @@
 import javax.swing.JLabel;
 import javax.swing.JList;
+import javax.swing.JMenuItem;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
@@ -47,4 +48,5 @@
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.layer.Layer.LayerAction;
 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
@@ -265,5 +267,5 @@
      * The action to delete the currently selected layer
      */
-    public final  class DeleteLayerAction extends AbstractAction implements IEnabledStateUpdating {
+    public final class DeleteLayerAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
         /**
          * Creates a {@see DeleteLayerAction} which will delete the currently
@@ -318,7 +320,27 @@
             setEnabled(! getModel().getSelectedLayers().isEmpty());
         }
-    }
-
-    public final class ShowHideLayerAction extends AbstractAction implements IEnabledStateUpdating {
+
+        @Override
+        public Component createMenuComponent() {
+            return new JMenuItem(this);
+        }
+
+        @Override
+        public boolean supportLayers(List<Layer> layers) {
+            return true;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof DeleteLayerAction;
+        }
+
+        @Override
+        public int hashCode() {
+            return getClass().hashCode();
+        }
+    }
+
+    public final class ShowHideLayerAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
         private  Layer layer;
 
@@ -334,5 +356,4 @@
             CheckParameterUtil.ensureParameterNotNull(layer, "layer");
             this.layer = layer;
-            putValue(NAME, tr("Show/Hide"));
             updateEnabledState();
         }
@@ -347,4 +368,5 @@
             putValue(SHORT_DESCRIPTION, tr("Toggle visible state of the selected layer."));
             putValue("help", HelpUtil.ht("/Dialog/LayerDialog#ShowHideLayer"));
+            putValue(NAME, tr("Show/Hide"));
             updateEnabledState();
         }
@@ -366,4 +388,24 @@
                 setEnabled(true);
             }
+        }
+
+        @Override
+        public Component createMenuComponent() {
+            return new JMenuItem(this);
+        }
+
+        @Override
+        public boolean supportLayers(List<Layer> layers) {
+            return true;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof ShowHideLayerAction;
+        }
+
+        @Override
+        public int hashCode() {
+            return getClass().hashCode();
         }
     }
@@ -576,5 +618,5 @@
             }
             Layer layer = model.getLayer(index);
-            LayerListPopup menu = new LayerListPopup(layerList, layer);
+            LayerListPopup menu = new LayerListPopup(getModel().getSelectedLayers(), layer);
             menu.show(LayerListDialog.this, p.x, p.y-3);
         }
@@ -1064,6 +1106,6 @@
      * @return the action
      */
-    public ShowHideLayerAction createShowHideLayerAction(Layer layer) {
-        return new ShowHideLayerAction(layer);
+    public ShowHideLayerAction createShowHideLayerAction() {
+        return new ShowHideLayerAction();
     }
 
@@ -1075,5 +1117,5 @@
      * @return the action
      */
-    public DeleteLayerAction createDeleteLayerAction(Layer layer) {
+    public DeleteLayerAction createDeleteLayerAction() {
         // the delete layer action doesn't depend on the current layer
         return new DeleteLayerAction();
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListPopup.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListPopup.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListPopup.java	(revision 3408)
@@ -4,9 +4,12 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.Component;
 import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 import javax.swing.AbstractAction;
-import javax.swing.JList;
+import javax.swing.Action;
+import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JPopupMenu;
@@ -14,4 +17,6 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.Layer.LayerAction;
+import org.openstreetmap.josm.gui.layer.Layer.SeparatorLayerAction;
 import org.openstreetmap.josm.tools.ImageProvider;
 
@@ -37,7 +42,45 @@
     }
 
-    public LayerListPopup(final JList layers, final Layer layer) {
-        for (Component c : layer.getMenuEntries()) {
-            add(c);
+    public LayerListPopup(List<Layer> selectedLayers, final Layer layer) {
+
+        List<Action> actions;
+        if (selectedLayers.size() == 1) {
+            actions = Arrays.asList(selectedLayers.get(0).getMenuEntries());
+        } else {
+            // Very simple algorithm - first selected layer has actions order as in getMenuEntries, actions from other layers go to the end
+            actions = new ArrayList<Action>();
+            boolean separatorAdded = true;
+            for (Action a: selectedLayers.get(0).getMenuEntries()) {
+                if (!separatorAdded && a instanceof SeparatorLayerAction) {
+                    separatorAdded = true;
+                    actions.add(a);
+                } else if (a instanceof LayerAction && ((LayerAction)a).supportLayers(selectedLayers)) {
+                    separatorAdded = false;
+                    actions.add(a);
+                }
+            }
+            // This will usually add no action, because if some action support all selected layers then it was probably used also in first layer
+            for (int i=1; i<selectedLayers.size(); i++) {
+                separatorAdded = false;
+                for (Action a: selectedLayers.get(i).getMenuEntries()) {
+                    if (a instanceof LayerAction && ((LayerAction)a).supportLayers(selectedLayers) && !actions.contains(a)) {
+                        if (!separatorAdded) {
+                            separatorAdded = true;
+                            actions.add(SeparatorLayerAction.INSTANCE);
+                        }
+                        actions.add(a);
+                    }
+                }
+            }
+        }
+        if (!actions.isEmpty() && actions.get(actions.size() - 1) instanceof SeparatorLayerAction) {
+            actions.remove(actions.size() - 1);
+        }
+        for (Action a : actions) {
+            if (a instanceof LayerAction) {
+                add (((LayerAction) a).createMenuComponent());
+            } else {
+                add(new JMenuItem(a));
+            }
         }
     }
Index: trunk/src/org/openstreetmap/josm/gui/help/HelpContentReaderException.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/help/HelpContentReaderException.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/help/HelpContentReaderException.java	(revision 3408)
@@ -7,20 +7,16 @@
     public HelpContentReaderException() {
         super();
-        // TODO Auto-generated constructor stub
     }
 
     public HelpContentReaderException(String message, Throwable cause) {
         super(message, cause);
-        // TODO Auto-generated constructor stub
     }
 
     public HelpContentReaderException(String message) {
         super(message);
-        // TODO Auto-generated constructor stub
     }
 
     public HelpContentReaderException(Throwable cause) {
         super(cause);
-        // TODO Auto-generated constructor stub
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/help/MissingHelpContentException.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/help/MissingHelpContentException.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/help/MissingHelpContentException.java	(revision 3408)
@@ -6,20 +6,16 @@
     public MissingHelpContentException() {
         super();
-        // TODO Auto-generated constructor stub
     }
 
     public MissingHelpContentException(String message, Throwable cause) {
         super(message, cause);
-        // TODO Auto-generated constructor stub
     }
 
     public MissingHelpContentException(String message) {
         super(message);
-        // TODO Auto-generated constructor stub
     }
 
     public MissingHelpContentException(Throwable cause) {
         super(cause);
-        // TODO Auto-generated constructor stub
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 3408)
@@ -10,10 +10,8 @@
 import java.awt.BasicStroke;
 import java.awt.Color;
-import java.awt.Component;
 import java.awt.Graphics2D;
 import java.awt.GridBagLayout;
 import java.awt.Point;
 import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.awt.geom.Area;
 import java.awt.geom.Rectangle2D;
@@ -31,4 +29,5 @@
 
 import javax.swing.AbstractAction;
+import javax.swing.Action;
 import javax.swing.Box;
 import javax.swing.ButtonGroup;
@@ -38,9 +37,7 @@
 import javax.swing.JLabel;
 import javax.swing.JList;
-import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JRadioButton;
-import javax.swing.JSeparator;
 import javax.swing.filechooser.FileFilter;
 
@@ -130,246 +127,34 @@
 
     @Override
-    public Component[] getMenuEntries() {
-        JMenuItem line = new JMenuItem(tr("Customize line drawing"), ImageProvider.get("mapmode/addsegment"));
-        line.addActionListener(new ActionListener() {
-            public void actionPerformed(ActionEvent e) {
-                JRadioButton[] r = new JRadioButton[3];
-                r[0] = new JRadioButton(tr("Use global settings."));
-                r[1] = new JRadioButton(tr("Draw lines between points for this layer."));
-                r[2] = new JRadioButton(tr("Do not draw lines between points for this layer."));
-                ButtonGroup group = new ButtonGroup();
-                Box panel = Box.createVerticalBox();
-                for (JRadioButton b : r) {
-                    group.add(b);
-                    panel.add(b);
-                }
-                String propName = "draw.rawgps.lines.layer " + getName();
-                if (Main.pref.hasKey(propName)) {
-                    group.setSelected(r[Main.pref.getBoolean(propName) ? 1 : 2].getModel(), true);
-                } else {
-                    group.setSelected(r[0].getModel(), true);
-                }
-                int answer = JOptionPane.showConfirmDialog(Main.parent, panel,
-                        tr("Select line drawing options"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
-                switch (answer) {
-                case JOptionPane.CANCEL_OPTION:
-                case JOptionPane.CLOSED_OPTION:
-                    return;
-                default:
-                    // continue
-                }
-                if (group.getSelection() == r[0].getModel()) {
-                    Main.pref.put(propName, null);
-                } else {
-                    Main.pref.put(propName, group.getSelection() == r[1].getModel());
-                }
-                Main.map.repaint();
-            }
-        });
-
-        JMenuItem color = new JMenuItem(tr("Customize Color"), ImageProvider.get("colorchooser"));
-        color.putClientProperty("help", "Action/LayerCustomizeColor");
-        color.addActionListener(new ActionListener() {
-            public void actionPerformed(ActionEvent e) {
-                JColorChooser c = new JColorChooser(getColor(getName()));
-                Object[] options = new Object[] { tr("OK"), tr("Cancel"), tr("Default") };
-                int answer = JOptionPane.showOptionDialog(
-                        Main.parent,
-                        c,
-                        tr("Choose a color"),
-                        JOptionPane.OK_CANCEL_OPTION,
-                        JOptionPane.PLAIN_MESSAGE,
-                        null,
-                        options, options[0]
-                );
-                switch (answer) {
-                case 0:
-                    Main.pref.putColor("layer " + getName(), c.getColor());
-                    break;
-                case 1:
-                    return;
-                case 2:
-                    Main.pref.putColor("layer " + getName(), null);
-                    break;
-                }
-                Main.map.repaint();
-            }
-        });
-
-        JMenuItem markersFromNamedTrackpoints = new JMenuItem(tr("Markers From Named Points"), ImageProvider
-                .get("addmarkers"));
-        markersFromNamedTrackpoints.putClientProperty("help", "Action/MarkersFromNamedPoints");
-        markersFromNamedTrackpoints.addActionListener(new ActionListener() {
-            public void actionPerformed(ActionEvent e) {
-                GpxData namedTrackPoints = new GpxData();
-                for (GpxTrack track : data.tracks) {
-                    for (GpxTrackSegment seg : track.getSegments()) {
-                        for (WayPoint point : seg.getWayPoints())
-                            if (point.attr.containsKey("name") || point.attr.containsKey("desc")) {
-                                namedTrackPoints.waypoints.add(point);
-                            }
-                    }
-                }
-
-                MarkerLayer ml = new MarkerLayer(namedTrackPoints, tr("Named Trackpoints from {0}", getName()),
-                        getAssociatedFile(), GpxLayer.this);
-                if (ml.data.size() > 0) {
-                    Main.main.addLayer(ml);
-                }
-            }
-        });
-
-        JMenuItem importAudio = new JMenuItem(tr("Import Audio"), ImageProvider.get("importaudio"));
-        importAudio.putClientProperty("help", "ImportAudio");
-        importAudio.addActionListener(new ActionListener() {
-            private void warnCantImportIntoServerLayer(GpxLayer layer) {
-                String msg = tr("<html>The data in the GPX layer ''{0}'' has been downloaded from the server.<br>"
-                        + "Because its way points do not include a timestamp we cannot correlate them with audio data.</html>",
-                        layer.getName()
-                );
-                HelpAwareOptionPane.showOptionDialog(
-                        Main.parent,
-                        msg,
-                        tr("Import not possible"),
-                        JOptionPane.WARNING_MESSAGE,
-                        ht("/Action/ImportImages#CantImportIntoGpxLayerFromServer")
-                );
-            }
-            public void actionPerformed(ActionEvent e) {
-                if (GpxLayer.this.data.fromServer) {
-                    warnCantImportIntoServerLayer(GpxLayer.this);
-                    return;
-                }
-                String dir = Main.pref.get("markers.lastaudiodirectory");
-                JFileChooser fc = new JFileChooser(dir);
-                fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
-                fc.setAcceptAllFileFilterUsed(false);
-                fc.setFileFilter(new FileFilter() {
-                    @Override
-                    public boolean accept(File f) {
-                        return f.isDirectory() || f.getName().toLowerCase().endsWith(".wav");
-                    }
-
-                    @Override
-                    public String getDescription() {
-                        return tr("Wave Audio files (*.wav)");
-                    }
-                });
-                fc.setMultiSelectionEnabled(true);
-                if (fc.showOpenDialog(Main.parent) == JFileChooser.APPROVE_OPTION) {
-                    if (!fc.getCurrentDirectory().getAbsolutePath().equals(dir)) {
-                        Main.pref.put("markers.lastaudiodirectory", fc.getCurrentDirectory().getAbsolutePath());
-                    }
-
-                    File sel[] = fc.getSelectedFiles();
-                    // sort files in increasing order of timestamp (this is the end time, but so
-                    // long as they don't overlap, that's fine)
-                    if (sel.length > 1) {
-                        Arrays.sort(sel, new Comparator<File>() {
-                            public int compare(File a, File b) {
-                                return a.lastModified() <= b.lastModified() ? -1 : 1;
-                            }
-                        });
-                    }
-
-                    String names = null;
-                    for (int i = 0; i < sel.length; i++) {
-                        if (names == null) {
-                            names = " (";
-                        } else {
-                            names += ", ";
-                        }
-                        names += sel[i].getName();
-                    }
-                    if (names != null) {
-                        names += ")";
-                    } else {
-                        names = "";
-                    }
-                    MarkerLayer ml = new MarkerLayer(new GpxData(), tr("Audio markers from {0}", getName()) + names,
-                            getAssociatedFile(), GpxLayer.this);
-                    double firstStartTime = sel[0].lastModified() / 1000.0 /* ms -> seconds */
-                    - AudioUtil.getCalibratedDuration(sel[0]);
-
-                    Markers m = new Markers();
-                    for (int i = 0; i < sel.length; i++) {
-                        importAudio(sel[i], ml, firstStartTime, m);
-                    }
-                    Main.main.addLayer(ml);
-                    Main.map.repaint();
-                }
-            }
-        });
-
-        JMenuItem tagimage = new JMenuItem(tr("Import images"), ImageProvider.get("dialogs/geoimage"));
-        tagimage.putClientProperty("help", ht("/Action/ImportImages"));
-        tagimage.addActionListener(new ActionListener() {
-
-            private void warnCantImportIntoServerLayer(GpxLayer layer) {
-                String msg = tr("<html>The data in the GPX layer ''{0}'' has been downloaded from the server.<br>"
-                        + "Because its way points do not include a timestamp we cannot correlate them with images.</html>",
-                        layer.getName()
-                );
-                HelpAwareOptionPane.showOptionDialog(
-                        Main.parent,
-                        msg,
-                        tr("Import not possible"),
-                        JOptionPane.WARNING_MESSAGE,
-                        ht("/Action/ImportImages#CantImportIntoGpxLayerFromServer")
-                );
-            }
-
-            public void actionPerformed(ActionEvent e) {
-                if (GpxLayer.this.data.fromServer) {
-                    warnCantImportIntoServerLayer(GpxLayer.this);
-                    return;
-                }
-                String curDir = Main.pref.get("geoimage.lastdirectory", Main.pref.get("lastDirectory"));
-                if (curDir.equals("")) {
-                    curDir = ".";
-                }
-                JFileChooser fc = new JFileChooser(new File(curDir));
-
-                fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
-                fc.setMultiSelectionEnabled(true);
-                fc.setAcceptAllFileFilterUsed(false);
-                JpgImporter importer = new JpgImporter(GpxLayer.this);
-                fc.setFileFilter(importer.filter);
-                fc.showOpenDialog(Main.parent);
-                LinkedList<File> files = new LinkedList<File>();
-                File[] sel = fc.getSelectedFiles();
-                if (sel == null || sel.length == 0)
-                    return;
-                if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) {
-                    Main.pref.put("geoimage.lastdirectory", fc.getCurrentDirectory().getAbsolutePath());
-                }
-                addRecursiveFiles(files, sel);
-                importer.importDataHandleExceptions(files, NullProgressMonitor.INSTANCE);
-            }
-
-            private void addRecursiveFiles(LinkedList<File> files, File[] sel) {
-                for (File f : sel) {
-                    if (f.isDirectory()) {
-                        addRecursiveFiles(files, f.listFiles());
-                    } else if (f.getName().toLowerCase().endsWith(".jpg")) {
-                        files.add(f);
-                    }
-                }
-            }
-        });
-
+    public Action[] getMenuEntries() {
         if (Main.applet)
-            return new Component[] { new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
-                new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)), new JSeparator(), color, line,
-                new JMenuItem(new ConvertToDataLayerAction()), new JSeparator(),
-                new JMenuItem(new RenameLayerAction(getAssociatedFile(), this)), new JSeparator(),
-                new JMenuItem(new LayerListPopup.InfoAction(this)) };
-        return new Component[] { new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
-                new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)), new JSeparator(),
-                new JMenuItem(new LayerSaveAction(this)), new JMenuItem(new LayerSaveAsAction(this)), color, line,
-                tagimage, importAudio, markersFromNamedTrackpoints, new JMenuItem(new ConvertToDataLayerAction()),
-                new JMenuItem(new DownloadAlongTrackAction()), new JSeparator(),
-                new JMenuItem(new RenameLayerAction(getAssociatedFile(), this)), new JSeparator(),
-                new JMenuItem(new LayerListPopup.InfoAction(this)) };
+            return new Action[] {
+                LayerListDialog.getInstance().createShowHideLayerAction(),
+                LayerListDialog.getInstance().createDeleteLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                new CustomizeColor(),
+                new CustomizeLineDrawing(),
+                new ConvertToDataLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                new RenameLayerAction(getAssociatedFile(), this),
+                SeparatorLayerAction.INSTANCE,
+                new LayerListPopup.InfoAction(this) };
+        return new Action[] {
+                LayerListDialog.getInstance().createShowHideLayerAction(),
+                LayerListDialog.getInstance().createDeleteLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                new LayerSaveAction(this),
+                new LayerSaveAsAction(this),
+                new CustomizeColor(),
+                new CustomizeLineDrawing(),
+                new ImportImages(),
+                new ImportAudio(),
+                new MarkersFromNamedPoins(),
+                new ConvertToDataLayerAction(),
+                new DownloadAlongTrackAction(),
+                SeparatorLayerAction.INSTANCE,
+                new RenameLayerAction(getAssociatedFile(), this),
+                SeparatorLayerAction.INSTANCE,
+                new LayerListPopup.InfoAction(this) };
     }
 
@@ -1417,3 +1202,260 @@
         return best;
     }
+
+    private class CustomizeLineDrawing extends AbstractAction {
+
+        CustomizeLineDrawing() {
+            super(tr("Customize line drawing"), ImageProvider.get("mapmode/addsegment"));
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            JRadioButton[] r = new JRadioButton[3];
+            r[0] = new JRadioButton(tr("Use global settings."));
+            r[1] = new JRadioButton(tr("Draw lines between points for this layer."));
+            r[2] = new JRadioButton(tr("Do not draw lines between points for this layer."));
+            ButtonGroup group = new ButtonGroup();
+            Box panel = Box.createVerticalBox();
+            for (JRadioButton b : r) {
+                group.add(b);
+                panel.add(b);
+            }
+            String propName = "draw.rawgps.lines.layer " + getName();
+            if (Main.pref.hasKey(propName)) {
+                group.setSelected(r[Main.pref.getBoolean(propName) ? 1 : 2].getModel(), true);
+            } else {
+                group.setSelected(r[0].getModel(), true);
+            }
+            int answer = JOptionPane.showConfirmDialog(Main.parent, panel,
+                    tr("Select line drawing options"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
+            switch (answer) {
+            case JOptionPane.CANCEL_OPTION:
+            case JOptionPane.CLOSED_OPTION:
+                return;
+            default:
+                // continue
+            }
+            if (group.getSelection() == r[0].getModel()) {
+                Main.pref.put(propName, null);
+            } else {
+                Main.pref.put(propName, group.getSelection() == r[1].getModel());
+            }
+            Main.map.repaint();
+        }
+    }
+
+    private class CustomizeColor extends AbstractAction {
+
+        public CustomizeColor() {
+            super(tr("Customize Color"), ImageProvider.get("colorchooser"));
+            putValue("help", "Action/LayerCustomizeColor");
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            JColorChooser c = new JColorChooser(getColor(getName()));
+            Object[] options = new Object[] { tr("OK"), tr("Cancel"), tr("Default") };
+            int answer = JOptionPane.showOptionDialog(
+                    Main.parent,
+                    c,
+                    tr("Choose a color"),
+                    JOptionPane.OK_CANCEL_OPTION,
+                    JOptionPane.PLAIN_MESSAGE,
+                    null,
+                    options, options[0]
+            );
+            switch (answer) {
+            case 0:
+                Main.pref.putColor("layer " + getName(), c.getColor());
+                break;
+            case 1:
+                return;
+            case 2:
+                Main.pref.putColor("layer " + getName(), null);
+                break;
+            }
+            Main.map.repaint();
+        }
+
+    }
+
+    private class MarkersFromNamedPoins extends AbstractAction {
+
+        public MarkersFromNamedPoins() {
+            super(tr("Markers From Named Points"), ImageProvider.get("addmarkers"));
+            putValue("help", "Action/MarkersFromNamedPoints");
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            GpxData namedTrackPoints = new GpxData();
+            for (GpxTrack track : data.tracks) {
+                for (GpxTrackSegment seg : track.getSegments()) {
+                    for (WayPoint point : seg.getWayPoints())
+                        if (point.attr.containsKey("name") || point.attr.containsKey("desc")) {
+                            namedTrackPoints.waypoints.add(point);
+                        }
+                }
+            }
+
+            MarkerLayer ml = new MarkerLayer(namedTrackPoints, tr("Named Trackpoints from {0}", getName()),
+                    getAssociatedFile(), GpxLayer.this);
+            if (ml.data.size() > 0) {
+                Main.main.addLayer(ml);
+            }
+
+        }
+    }
+
+    private class ImportAudio extends AbstractAction {
+
+        public ImportAudio() {
+            super(tr("Import Audio"), ImageProvider.get("importaudio"));
+            putValue("help", "ImportAudio");
+        }
+
+        private void warnCantImportIntoServerLayer(GpxLayer layer) {
+            String msg = tr("<html>The data in the GPX layer ''{0}'' has been downloaded from the server.<br>"
+                    + "Because its way points do not include a timestamp we cannot correlate them with audio data.</html>",
+                    layer.getName()
+            );
+            HelpAwareOptionPane.showOptionDialog(
+                    Main.parent,
+                    msg,
+                    tr("Import not possible"),
+                    JOptionPane.WARNING_MESSAGE,
+                    ht("/Action/ImportImages#CantImportIntoGpxLayerFromServer")
+            );
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            if (GpxLayer.this.data.fromServer) {
+                warnCantImportIntoServerLayer(GpxLayer.this);
+                return;
+            }
+            String dir = Main.pref.get("markers.lastaudiodirectory");
+            JFileChooser fc = new JFileChooser(dir);
+            fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
+            fc.setAcceptAllFileFilterUsed(false);
+            fc.setFileFilter(new FileFilter() {
+                @Override
+                public boolean accept(File f) {
+                    return f.isDirectory() || f.getName().toLowerCase().endsWith(".wav");
+                }
+
+                @Override
+                public String getDescription() {
+                    return tr("Wave Audio files (*.wav)");
+                }
+            });
+            fc.setMultiSelectionEnabled(true);
+            if (fc.showOpenDialog(Main.parent) == JFileChooser.APPROVE_OPTION) {
+                if (!fc.getCurrentDirectory().getAbsolutePath().equals(dir)) {
+                    Main.pref.put("markers.lastaudiodirectory", fc.getCurrentDirectory().getAbsolutePath());
+                }
+
+                File sel[] = fc.getSelectedFiles();
+                // sort files in increasing order of timestamp (this is the end time, but so
+                // long as they don't overlap, that's fine)
+                if (sel.length > 1) {
+                    Arrays.sort(sel, new Comparator<File>() {
+                        public int compare(File a, File b) {
+                            return a.lastModified() <= b.lastModified() ? -1 : 1;
+                        }
+                    });
+                }
+
+                String names = null;
+                for (int i = 0; i < sel.length; i++) {
+                    if (names == null) {
+                        names = " (";
+                    } else {
+                        names += ", ";
+                    }
+                    names += sel[i].getName();
+                }
+                if (names != null) {
+                    names += ")";
+                } else {
+                    names = "";
+                }
+                MarkerLayer ml = new MarkerLayer(new GpxData(), tr("Audio markers from {0}", getName()) + names,
+                        getAssociatedFile(), GpxLayer.this);
+                double firstStartTime = sel[0].lastModified() / 1000.0 /* ms -> seconds */
+                - AudioUtil.getCalibratedDuration(sel[0]);
+
+                Markers m = new Markers();
+                for (int i = 0; i < sel.length; i++) {
+                    importAudio(sel[i], ml, firstStartTime, m);
+                }
+                Main.main.addLayer(ml);
+                Main.map.repaint();
+            }
+
+        }
+    }
+
+    private class ImportImages extends AbstractAction {
+
+        public ImportImages() {
+            super(tr("Import images"), ImageProvider.get("dialogs/geoimage"));
+            putValue("help", ht("/Action/ImportImages"));
+        }
+
+        private void warnCantImportIntoServerLayer(GpxLayer layer) {
+            String msg = tr("<html>The data in the GPX layer ''{0}'' has been downloaded from the server.<br>"
+                    + "Because its way points do not include a timestamp we cannot correlate them with images.</html>",
+                    layer.getName()
+            );
+            HelpAwareOptionPane.showOptionDialog(
+                    Main.parent,
+                    msg,
+                    tr("Import not possible"),
+                    JOptionPane.WARNING_MESSAGE,
+                    ht("/Action/ImportImages#CantImportIntoGpxLayerFromServer")
+            );
+        }
+
+        private void addRecursiveFiles(LinkedList<File> files, File[] sel) {
+            for (File f : sel) {
+                if (f.isDirectory()) {
+                    addRecursiveFiles(files, f.listFiles());
+                } else if (f.getName().toLowerCase().endsWith(".jpg")) {
+                    files.add(f);
+                }
+            }
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+
+            if (GpxLayer.this.data.fromServer) {
+                warnCantImportIntoServerLayer(GpxLayer.this);
+                return;
+            }
+            String curDir = Main.pref.get("geoimage.lastdirectory", Main.pref.get("lastDirectory"));
+            if (curDir.equals("")) {
+                curDir = ".";
+            }
+            JFileChooser fc = new JFileChooser(new File(curDir));
+
+            fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+            fc.setMultiSelectionEnabled(true);
+            fc.setAcceptAllFileFilterUsed(false);
+            JpgImporter importer = new JpgImporter(GpxLayer.this);
+            fc.setFileFilter(importer.filter);
+            fc.showOpenDialog(Main.parent);
+            LinkedList<File> files = new LinkedList<File>();
+            File[] sel = fc.getSelectedFiles();
+            if (sel == null || sel.length == 0)
+                return;
+            if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) {
+                Main.pref.put("geoimage.lastdirectory", fc.getCurrentDirectory().getAbsolutePath());
+            }
+            addRecursiveFiles(files, sel);
+            importer.importDataHandleExceptions(files, NullProgressMonitor.INSTANCE);
+        }
+
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/Layer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 3408)
@@ -11,7 +11,10 @@
 import java.beans.PropertyChangeSupport;
 import java.io.File;
+import java.util.List;
 
 import javax.swing.AbstractAction;
+import javax.swing.Action;
 import javax.swing.Icon;
+import javax.swing.JSeparator;
 
 import org.openstreetmap.josm.actions.GpxExportAction;
@@ -40,6 +43,33 @@
  */
 abstract public class Layer implements Destroyable, MapViewPaintable {
+
+    public interface LayerAction {
+        boolean supportLayers(List<Layer> layers);
+        Component createMenuComponent();
+    }
+
+    /**
+     * Special class that can be returned by getMenuEntries when JSeparator needs to be created
+     *
+     */
+    public static class SeparatorLayerAction extends AbstractAction implements LayerAction {
+        public static final SeparatorLayerAction INSTANCE = new SeparatorLayerAction();
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public Component createMenuComponent() {
+            return new JSeparator();
+        }
+        @Override
+        public boolean supportLayers(List<Layer> layers) {
+            return false;
+        }
+    }
+
     static public final String VISIBLE_PROP = Layer.class.getName() + ".visible";
     static public final String NAME_PROP = Layer.class.getName() + ".name";
+
 
     /** keeps track of property change listeners */
@@ -112,5 +142,13 @@
     abstract public Object getInfoComponent();
 
-    abstract public Component[] getMenuEntries();
+    /**
+     * Returns list of actions. Action can implement LayerAction interface when it needs to be represented by other
+     * menu component than JMenuItem or when it supports multiple layers. Actions that support multiple layers should also
+     * have correct equals implementation.
+     *
+     * Use SeparatorLayerAction.INSTANCE instead of new JSeparator
+     *
+     */
+    abstract public Action[] getMenuEntries();
 
     /**
Index: trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 3408)
@@ -10,5 +10,4 @@
 import java.awt.AlphaComposite;
 import java.awt.Color;
-import java.awt.Component;
 import java.awt.Composite;
 import java.awt.Graphics2D;
@@ -28,11 +27,10 @@
 
 import javax.swing.AbstractAction;
+import javax.swing.Action;
 import javax.swing.Icon;
 import javax.swing.JLabel;
-import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
-import javax.swing.JSeparator;
 import javax.swing.JTextArea;
 
@@ -440,32 +438,32 @@
     }
 
-    @Override public Component[] getMenuEntries() {
+    @Override public Action[] getMenuEntries() {
         if (Main.applet)
-            return new Component[]{
-                new JMenuItem(LayerListDialog.getInstance().createActivateLayerAction(this)),
-                new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
-                new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)),
-                new JSeparator(),
-                new JMenuItem(LayerListDialog.getInstance().createMergeLayerAction(this)),
-                new JSeparator(),
-                new JMenuItem(new RenameLayerAction(getAssociatedFile(), this)),
-                new JMenuItem(new ConsistencyTestAction()),
-                new JSeparator(),
-                new JMenuItem(new LayerListPopup.InfoAction(this))};
-        return new Component[]{
-                new JMenuItem(LayerListDialog.getInstance().createActivateLayerAction(this)),
-                new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
-                new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)),
-                new JSeparator(),
-                new JMenuItem(LayerListDialog.getInstance().createMergeLayerAction(this)),
-                new JMenuItem(new LayerSaveAction(this)),
-                new JMenuItem(new LayerSaveAsAction(this)),
-                new JMenuItem(new LayerGpxExportAction(this)),
-                new JMenuItem(new ConvertToGpxLayerAction()),
-                new JSeparator(),
-                new JMenuItem(new RenameLayerAction(getAssociatedFile(), this)),
-                new JMenuItem(new ConsistencyTestAction()),
-                new JSeparator(),
-                new JMenuItem(new LayerListPopup.InfoAction(this))};
+            return new Action[]{
+                LayerListDialog.getInstance().createActivateLayerAction(this),
+                LayerListDialog.getInstance().createShowHideLayerAction(),
+                LayerListDialog.getInstance().createDeleteLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                LayerListDialog.getInstance().createMergeLayerAction(this),
+                SeparatorLayerAction.INSTANCE,
+                new RenameLayerAction(getAssociatedFile(), this),
+                new ConsistencyTestAction(),
+                SeparatorLayerAction.INSTANCE,
+                new LayerListPopup.InfoAction(this)};
+        return new Action[]{
+                LayerListDialog.getInstance().createActivateLayerAction(this),
+                LayerListDialog.getInstance().createShowHideLayerAction(),
+                LayerListDialog.getInstance().createDeleteLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                LayerListDialog.getInstance().createMergeLayerAction(this),
+                new LayerSaveAction(this),
+                new LayerSaveAsAction(this),
+                new LayerGpxExportAction(this),
+                new ConvertToGpxLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                new RenameLayerAction(getAssociatedFile(), this),
+                new ConsistencyTestAction(),
+                SeparatorLayerAction.INSTANCE,
+                new LayerListPopup.InfoAction(this)};
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/layer/RawGpsLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/RawGpsLayer.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/layer/RawGpsLayer.java	(revision 3408)
@@ -8,10 +8,8 @@
 
 import java.awt.Color;
-import java.awt.Component;
 import java.awt.Graphics2D;
 import java.awt.GridBagLayout;
 import java.awt.Point;
 import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.io.File;
 import java.util.ArrayList;
@@ -20,4 +18,5 @@
 
 import javax.swing.AbstractAction;
+import javax.swing.Action;
 import javax.swing.Box;
 import javax.swing.ButtonGroup;
@@ -25,9 +24,7 @@
 import javax.swing.JColorChooser;
 import javax.swing.JLabel;
-import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JRadioButton;
-import javax.swing.JSeparator;
 
 import org.openstreetmap.josm.Main;
@@ -196,91 +193,30 @@
     }
 
-    @Override public Component[] getMenuEntries() {
-        JMenuItem line = new JMenuItem(tr("Customize line drawing"), ImageProvider.get("mapmode/addsegment"));
-        line.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                JRadioButton[] r = new JRadioButton[3];
-                r[0] = new JRadioButton(tr("Use global settings."));
-                r[1] = new JRadioButton(tr("Draw lines between points for this layer."));
-                r[2] = new JRadioButton(tr("Do not draw lines between points for this layer."));
-                ButtonGroup group = new ButtonGroup();
-                Box panel = Box.createVerticalBox();
-                for (JRadioButton b : r) {
-                    group.add(b);
-                    panel.add(b);
-                }
-                String propName = "draw.rawgps.lines.layer "+getName();
-                if (Main.pref.hasKey(propName)) {
-                    group.setSelected(r[Main.pref.getBoolean(propName) ? 1:2].getModel(), true);
-                } else {
-                    group.setSelected(r[0].getModel(), true);
-                }
-                int answer = JOptionPane.showConfirmDialog(
-                        Main.parent,
-                        panel,
-                        tr("Select line drawing options"),
-                        JOptionPane.OK_CANCEL_OPTION,
-                        JOptionPane.PLAIN_MESSAGE
-                );
-                if (answer == JOptionPane.CANCEL_OPTION)
-                    return;
-                if (group.getSelection() == r[0].getModel()) {
-                    Main.pref.put(propName, null);
-                } else {
-                    Main.pref.put(propName, group.getSelection() == r[1].getModel());
-                }
-                Main.map.repaint();
-            }
-        });
-
-        JMenuItem color = new JMenuItem(tr("Customize Color"), ImageProvider.get("colorchooser"));
-        color.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                JColorChooser c = new JColorChooser(Main.pref.getColor(marktr("gps point"), "layer "+getName(), Color.gray));
-                Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
-                int answer = JOptionPane.showOptionDialog(
-                        Main.parent,
-                        c,
-                        tr("Choose a color"),
-                        JOptionPane.OK_CANCEL_OPTION,
-                        JOptionPane.PLAIN_MESSAGE, null,options, options[0]);
-                switch (answer) {
-                case 0:
-                    Main.pref.putColor("layer "+getName(), c.getColor());
-                    break;
-                case 1:
-                    return;
-                case 2:
-                    Main.pref.putColor("layer "+getName(), null);
-                    break;
-                }
-                Main.map.repaint();
-            }
-        });
-
+    @Override public Action[] getMenuEntries() {
         if (Main.applet)
-            return new Component[]{
-                new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
-                new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)),
-                new JSeparator(),
-                color,
-                line,
-                new JMenuItem(new ConvertToDataLayerAction()),
-                new JSeparator(),
-                new JMenuItem(new RenameLayerAction(getAssociatedFile(), this)),
-                new JSeparator(),
-                new JMenuItem(new LayerListPopup.InfoAction(this))};
-        return new Component[]{
-                new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)),
-                new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)),
-                new JSeparator(),
-                new JMenuItem(new LayerGpxExportAction(this)),
-                color,
-                line,
-                new JMenuItem(new ConvertToDataLayerAction()),
-                new JSeparator(),
-                new JMenuItem(new RenameLayerAction(getAssociatedFile(), this)),
-                new JSeparator(),
-                new JMenuItem(new LayerListPopup.InfoAction(this))};
+            return new Action[]{
+                LayerListDialog.getInstance().createShowHideLayerAction(),
+                LayerListDialog.getInstance().createDeleteLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                new CustomizeColor(),
+                new CustomizeLineDrawing(),
+                new ConvertToDataLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                new RenameLayerAction(getAssociatedFile(), this),
+                SeparatorLayerAction.INSTANCE,
+                new LayerListPopup.InfoAction(this)};
+        else
+            return new Action[]{
+                LayerListDialog.getInstance().createShowHideLayerAction(),
+                LayerListDialog.getInstance().createDeleteLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                new LayerGpxExportAction(this),
+                new CustomizeColor(),
+                new CustomizeLineDrawing(),
+                new ConvertToDataLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                new RenameLayerAction(getAssociatedFile(), this),
+                SeparatorLayerAction.INSTANCE,
+                new LayerListPopup.InfoAction(this)};
     }
 
@@ -294,3 +230,75 @@
         Main.pref.removePreferenceChangeListener(this);
     }
+
+    private class CustomizeLineDrawing extends AbstractAction {
+
+        public CustomizeLineDrawing() {
+            super(tr("Customize line drawing"), ImageProvider.get("mapmode/addsegment"));
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            JRadioButton[] r = new JRadioButton[3];
+            r[0] = new JRadioButton(tr("Use global settings."));
+            r[1] = new JRadioButton(tr("Draw lines between points for this layer."));
+            r[2] = new JRadioButton(tr("Do not draw lines between points for this layer."));
+            ButtonGroup group = new ButtonGroup();
+            Box panel = Box.createVerticalBox();
+            for (JRadioButton b : r) {
+                group.add(b);
+                panel.add(b);
+            }
+            String propName = "draw.rawgps.lines.layer "+getName();
+            if (Main.pref.hasKey(propName)) {
+                group.setSelected(r[Main.pref.getBoolean(propName) ? 1:2].getModel(), true);
+            } else {
+                group.setSelected(r[0].getModel(), true);
+            }
+            int answer = JOptionPane.showConfirmDialog(
+                    Main.parent,
+                    panel,
+                    tr("Select line drawing options"),
+                    JOptionPane.OK_CANCEL_OPTION,
+                    JOptionPane.PLAIN_MESSAGE
+            );
+            if (answer == JOptionPane.CANCEL_OPTION)
+                return;
+            if (group.getSelection() == r[0].getModel()) {
+                Main.pref.put(propName, null);
+            } else {
+                Main.pref.put(propName, group.getSelection() == r[1].getModel());
+            }
+            Main.map.repaint();
+        }
+    }
+
+    private class CustomizeColor extends AbstractAction {
+
+        public CustomizeColor() {
+            super(tr("Customize Color"), ImageProvider.get("colorchooser"));
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            JColorChooser c = new JColorChooser(Main.pref.getColor(marktr("gps point"), "layer "+getName(), Color.gray));
+            Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
+            int answer = JOptionPane.showOptionDialog(
+                    Main.parent,
+                    c,
+                    tr("Choose a color"),
+                    JOptionPane.OK_CANCEL_OPTION,
+                    JOptionPane.PLAIN_MESSAGE, null,options, options[0]);
+            switch (answer) {
+            case 0:
+                Main.pref.putColor("layer "+getName(), c.getColor());
+                break;
+            case 1:
+                return;
+            case 2:
+                Main.pref.putColor("layer "+getName(), null);
+                break;
+            }
+            Main.map.repaint();
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 3408)
@@ -40,4 +40,5 @@
 import java.util.zip.GZIPInputStream;
 
+import javax.swing.AbstractAction;
 import javax.swing.AbstractListModel;
 import javax.swing.BorderFactory;
@@ -83,5 +84,5 @@
  * Then it correlates the images of the layer with that GPX file.
  */
-public class CorrelateGpxWithImages implements ActionListener {
+public class CorrelateGpxWithImages extends AbstractAction {
 
     private static List<GpxData> loadedGpxData = new ArrayList<GpxData>();
@@ -92,4 +93,5 @@
 
     public CorrelateGpxWithImages(GeoImageLayer layer) {
+        super(tr("Correlate to GPX"), ImageProvider.get("dialogs/geoimage/gpx2img"));
         this.yLayer = layer;
     }
@@ -217,5 +219,5 @@
     }
 
-    /** 
+    /**
      * This action listener is called when the user has a photo of the time of his GPS receiver. It
      * displays the list of photos of the layer, and upon selection displays the selected photo.
@@ -630,5 +632,5 @@
         tfTimezone.addFocusListener(repaintTheMap);
         tfOffset.addFocusListener(repaintTheMap);
-        
+
         tfTimezone.getDocument().addDocumentListener(statusBarUpdater);
         tfOffset.getDocument().addDocumentListener(statusBarUpdater);
@@ -760,5 +762,5 @@
     StatusBarUpdater statusBarUpdater = new StatusBarUpdater(false);
     StatusBarUpdater statusBarUpdaterWithRepaint = new StatusBarUpdater(true);
-    
+
     private class StatusBarUpdater implements  DocumentListener, ItemListener, ActionListener {
         private boolean doRepaint;
@@ -767,5 +769,5 @@
             this.doRepaint = doRepaint;
         }
-        
+
         public void insertUpdate(DocumentEvent ev) {
             updateStatusBar();
@@ -789,5 +791,5 @@
             }
         }
-        
+
         private String statusText() {
             try {
@@ -803,5 +805,5 @@
                 ie.tmp = null;
             }
-            
+
             // Construct a list of images that have a date, and sort them on the date.
             ArrayList<ImageEntry> dateImgLst = getSortedImgList();
@@ -828,5 +830,5 @@
         public void focusGained(FocusEvent e) { // do nothing
         }
-        
+
         public void focusLost(FocusEvent e) {
             yLayer.updateBufferAndRepaint();
@@ -1197,10 +1199,12 @@
         if(prevWpTime == 0 || curWpTime <= prevWpTime) {
             while (true) {
-                if (i < 0)
+                if (i < 0) {
                     break;
+                }
                 final ImageEntry curImg = images.get(i);
                 if (curImg.getExifTime().getTime() > curWpTime
-                    || curImg.getExifTime().getTime() < curWpTime - interval)
-                        break;
+                        || curImg.getExifTime().getTime() < curWpTime - interval) {
+                    break;
+                }
                 if(curImg.tmp.getPos() == null) {
                     curImg.tmp.setPos(curWp.getCoor());
@@ -1218,10 +1222,12 @@
         // previous track point assuming a constant speed in between
         while (true) {
-            if (i < 0)
+            if (i < 0) {
                 break;
+            }
             ImageEntry curImg = images.get(i);
             long imgTime = curImg.getExifTime().getTime();
-            if (imgTime < prevWpTime)
+            if (imgTime < prevWpTime) {
                 break;
+            }
 
             if(curImg.tmp.getPos() == null) {
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 3408)
@@ -11,5 +11,4 @@
 import java.awt.AlphaComposite;
 import java.awt.Color;
-import java.awt.Component;
 import java.awt.Composite;
 import java.awt.Dimension;
@@ -35,9 +34,8 @@
 import java.util.List;
 
+import javax.swing.Action;
 import javax.swing.Icon;
 import javax.swing.JLabel;
-import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
-import javax.swing.JSeparator;
 import javax.swing.SwingConstants;
 
@@ -280,35 +278,26 @@
     }
 
-    public static interface LayerMenuAddition {
-        public Component getComponent(Layer layer);
-    }
-
-    private static List<LayerMenuAddition> menuAdditions = new LinkedList<LayerMenuAddition>();
-    public static void registerMenuAddition(LayerMenuAddition addition) {
+    private static List<Action> menuAdditions = new LinkedList<Action>();
+    public static void registerMenuAddition(Action addition) {
         menuAdditions.add(addition);
     }
 
     @Override
-    public Component[] getMenuEntries() {
-
-        JMenuItem correlateItem = new JMenuItem(tr("Correlate to GPX"), ImageProvider.get("dialogs/geoimage/gpx2img"));
-        correlateItem.addActionListener(new CorrelateGpxWithImages(this));
-
-        List<Component> entries = new ArrayList<Component>();
-        entries.add(new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)));
-        entries.add(new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)));
-        entries.add(new JMenuItem(new RenameLayerAction(null, this)));
-        entries.add(new JSeparator());
-        entries.add(correlateItem);
+    public Action[] getMenuEntries() {
+
+        List<Action> entries = new ArrayList<Action>();
+        entries.add(LayerListDialog.getInstance().createShowHideLayerAction());
+        entries.add(LayerListDialog.getInstance().createDeleteLayerAction());
+        entries.add(new RenameLayerAction(null, this));
+        entries.add(SeparatorLayerAction.INSTANCE);
+        entries.add(new CorrelateGpxWithImages(this));
         if (!menuAdditions.isEmpty()) {
-            entries.add(new JSeparator());
-        }
-        for (LayerMenuAddition addition : menuAdditions) {
-            entries.add(addition.getComponent(this));
-        }
-        entries.add(new JSeparator());
-        entries.add(new JMenuItem(new LayerListPopup.InfoAction(this)));
-
-        return entries.toArray(new Component[0]);
+            entries.add(SeparatorLayerAction.INSTANCE);
+            entries.addAll(menuAdditions);
+        }
+        entries.add(SeparatorLayerAction.INSTANCE);
+        entries.add(new LayerListPopup.InfoAction(this));
+
+        return entries.toArray(new Action[0]);
 
     }
@@ -472,5 +461,5 @@
 
                         double dir = e.getExifImgDir();
-                        // Rotate 90 degrees CCW 
+                        // Rotate 90 degrees CCW
                         double headdir = ( dir < 90 ) ? dir + 270 : dir - 90;
                         double leftdir = ( headdir < 90 ) ? headdir + 270 : headdir - 90;
@@ -522,5 +511,5 @@
         Metadata metadata = null;
         Directory dir = null;
-        
+
         try {
             metadata = JpegMetadataReader.readMetadata(e.getFile());
@@ -531,5 +520,5 @@
             return;
         }
-        
+
         try {
             // longitude
@@ -591,16 +580,14 @@
 
         Rational direction = null;
-        
+
         try {
             direction = dir.getRational(GpsDirectory.TAG_GPS_IMG_DIRECTION);
+            if (direction != null) {
+                e.setExifImgDir(direction.doubleValue());
+            }
         } catch (CompoundException p) {
-            direction = null;
-        } catch (Exception ex) {
-            direction = null;
-        }
-
-        if (direction != null) {
-            e.setExifImgDir(direction.doubleValue());
-        }
+            // Do nothing
+        }
+
 
     }
Index: trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 3408)
@@ -11,5 +11,4 @@
 import java.awt.Point;
 import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
@@ -18,12 +17,12 @@
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 import javax.swing.AbstractAction;
+import javax.swing.Action;
 import javax.swing.Icon;
 import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JColorChooser;
-import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
-import javax.swing.JSeparator;
 import javax.swing.SwingUtilities;
 
@@ -197,105 +196,20 @@
     }
 
-    @Override public Component[] getMenuEntries() {
-        JMenuItem color = new JMenuItem(tr("Customize Color"), ImageProvider.get("colorchooser"));
-        color.putClientProperty("help", "Action/LayerCustomizeColor");
-        color.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                JColorChooser c = new JColorChooser(getColor(getName()));
-                Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
-                int answer = JOptionPane.showOptionDialog(
-                        Main.parent,
-                        c,
-                        tr("Choose a color"),
-                        JOptionPane.OK_CANCEL_OPTION,
-                        JOptionPane.PLAIN_MESSAGE,
-                        null,
-                        options,
-                        options[0]
-                );
-                switch (answer) {
-                case 0:
-                    Main.pref.putColor("layer "+getName(), c.getColor());
-                    break;
-                case 1:
-                    return;
-                case 2:
-                    Main.pref.putColor("layer "+getName(), null);
-                    break;
-                }
-                Main.map.repaint();
-            }
-        });
-
-        JMenuItem syncaudio = new JMenuItem(tr("Synchronize Audio"), ImageProvider.get("audio-sync"));
-        syncaudio.putClientProperty("help", "Action/SynchronizeAudio");
-        syncaudio.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                if (! AudioPlayer.paused()) {
-                    JOptionPane.showMessageDialog(
-                            Main.parent,
-                            tr("You need to pause audio at the moment when you hear your synchronization cue."),
-                            tr("Warning"),
-                            JOptionPane.WARNING_MESSAGE
-                    );
-                    return;
-                }
-                AudioMarker recent = AudioMarker.recentlyPlayedMarker();
-                if (synchronizeAudioMarkers(recent)) {
-                    JOptionPane.showMessageDialog(
-                            Main.parent,
-                            tr("Audio synchronized at point {0}.", recent.text),
-                            tr("Information"),
-                            JOptionPane.INFORMATION_MESSAGE
-                    );
-                } else {
-                    JOptionPane.showMessageDialog(
-                            Main.parent,
-                            tr("Unable to synchronize in layer being played."),
-                            tr("Error"),
-                            JOptionPane.ERROR_MESSAGE
-                    );
-                }
-            }
-        });
-
-        JMenuItem moveaudio = new JMenuItem(tr("Make Audio Marker at Play Head"), ImageProvider.get("addmarkers"));
-        moveaudio.putClientProperty("help", "Action/MakeAudioMarkerAtPlayHead");
-        moveaudio.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                if (! AudioPlayer.paused()) {
-                    JOptionPane.showMessageDialog(
-                            Main.parent,
-                            tr("You need to have paused audio at the point on the track where you want the marker."),
-                            tr("Warning"),
-                            JOptionPane.WARNING_MESSAGE
-                    );
-                    return;
-                }
-                PlayHeadMarker playHeadMarker = Main.map.mapView.playHeadMarker;
-                if (playHeadMarker == null)
-                    return;
-                addAudioMarker(playHeadMarker.time, playHeadMarker.getCoor());
-                Main.map.mapView.repaint();
-            }
-        });
-
-        Collection<Component> components = new ArrayList<Component>();
-        components.add(new JMenuItem(LayerListDialog.getInstance().createShowHideLayerAction(this)));
-        JCheckBoxMenuItem showMarkerTextItem = new JCheckBoxMenuItem(new ShowHideMarkerText(this));
-        showMarkerTextItem.setState(isTextOrIconShown());
-        components.add(showMarkerTextItem);
-        components.add(new JMenuItem(LayerListDialog.getInstance().createDeleteLayerAction(this)));
-        components.add(new JSeparator());
-        components.add(color);
-        components.add(new JSeparator());
-        components.add(syncaudio);
+    @Override public Action[] getMenuEntries() {
+        Collection<Action> components = new ArrayList<Action>();
+        components.add(LayerListDialog.getInstance().createShowHideLayerAction());
+        components.add(new ShowHideMarkerText(this));
+        components.add(LayerListDialog.getInstance().createDeleteLayerAction());
+        components.add(SeparatorLayerAction.INSTANCE);
+        components.add(new CustomizeColor());
+        components.add(SeparatorLayerAction.INSTANCE);
+        components.add(new SynchronizeAudio());
         if (Main.pref.getBoolean("marker.traceaudio", true)) {
-            components.add (moveaudio);
-        }
-        components.add(new JMenuItem(new RenameLayerAction(getAssociatedFile(), this)));
-        components.add(new JSeparator());
-        components.add(new JMenuItem(new LayerListPopup.InfoAction(this)));
-        return components.toArray(new Component[0]);
+            components.add (new MoveAudio());
+        }
+        components.add(new RenameLayerAction(getAssociatedFile(), this));
+        components.add(SeparatorLayerAction.INSTANCE);
+        components.add(new LayerListPopup.InfoAction(this));
+        return components.toArray(new Action[0]);
     }
 
@@ -457,5 +371,5 @@
     }
 
-    public static final class ShowHideMarkerText extends AbstractAction {
+    public static final class ShowHideMarkerText extends AbstractAction implements LayerAction {
         private final MarkerLayer layer;
 
@@ -472,4 +386,116 @@
             Main.map.mapView.repaint();
         }
+
+
+        @Override
+        public Component createMenuComponent() {
+            JCheckBoxMenuItem showMarkerTextItem = new JCheckBoxMenuItem(this);
+            showMarkerTextItem.setState(layer.isTextOrIconShown());
+            return showMarkerTextItem;
+        }
+
+
+        @Override
+        public boolean supportLayers(List<Layer> layers) {
+            return layers.size() == 1 && layers.get(0) instanceof MarkerLayer;
+        }
+    }
+
+    private class CustomizeColor extends AbstractAction {
+
+        public CustomizeColor() {
+            super(tr("Customize Color"), ImageProvider.get("colorchooser"));
+            putValue("help", "Action/LayerCustomizeColor");
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            JColorChooser c = new JColorChooser(getColor(getName()));
+            Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
+            int answer = JOptionPane.showOptionDialog(
+                    Main.parent,
+                    c,
+                    tr("Choose a color"),
+                    JOptionPane.OK_CANCEL_OPTION,
+                    JOptionPane.PLAIN_MESSAGE,
+                    null,
+                    options,
+                    options[0]
+            );
+            switch (answer) {
+            case 0:
+                Main.pref.putColor("layer "+getName(), c.getColor());
+                break;
+            case 1:
+                return;
+            case 2:
+                Main.pref.putColor("layer "+getName(), null);
+                break;
+            }
+            Main.map.repaint();
+        }
+    }
+
+    private class SynchronizeAudio extends AbstractAction {
+
+        public SynchronizeAudio() {
+            super(tr("Synchronize Audio"), ImageProvider.get("audio-sync"));
+            putValue("help", "Action/SynchronizeAudio");
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            if (! AudioPlayer.paused()) {
+                JOptionPane.showMessageDialog(
+                        Main.parent,
+                        tr("You need to pause audio at the moment when you hear your synchronization cue."),
+                        tr("Warning"),
+                        JOptionPane.WARNING_MESSAGE
+                );
+                return;
+            }
+            AudioMarker recent = AudioMarker.recentlyPlayedMarker();
+            if (synchronizeAudioMarkers(recent)) {
+                JOptionPane.showMessageDialog(
+                        Main.parent,
+                        tr("Audio synchronized at point {0}.", recent.text),
+                        tr("Information"),
+                        JOptionPane.INFORMATION_MESSAGE
+                );
+            } else {
+                JOptionPane.showMessageDialog(
+                        Main.parent,
+                        tr("Unable to synchronize in layer being played."),
+                        tr("Error"),
+                        JOptionPane.ERROR_MESSAGE
+                );
+            }
+        }
+    }
+
+    private class MoveAudio extends AbstractAction {
+
+        public MoveAudio() {
+            super(tr("Make Audio Marker at Play Head"), ImageProvider.get("addmarkers"));
+            putValue("help", "Action/MakeAudioMarkerAtPlayHead");
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            if (! AudioPlayer.paused()) {
+                JOptionPane.showMessageDialog(
+                        Main.parent,
+                        tr("You need to have paused audio at the point on the track where you want the marker."),
+                        tr("Warning"),
+                        JOptionPane.WARNING_MESSAGE
+                );
+                return;
+            }
+            PlayHeadMarker playHeadMarker = Main.map.mapView.playHeadMarker;
+            if (playHeadMarker == null)
+                return;
+            addAudioMarker(playHeadMarker.time, playHeadMarker.getCoor());
+            Main.map.mapView.repaint();
+        }
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/oauth/OsmLoginFailedException.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/oauth/OsmLoginFailedException.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/oauth/OsmLoginFailedException.java	(revision 3408)
@@ -6,20 +6,16 @@
     public OsmLoginFailedException() {
         super();
-        // TODO Auto-generated constructor stub
     }
 
     public OsmLoginFailedException(String arg0, Throwable arg1) {
         super(arg0, arg1);
-        // TODO Auto-generated constructor stub
     }
 
     public OsmLoginFailedException(String arg0) {
         super(arg0);
-        // TODO Auto-generated constructor stub
     }
 
     public OsmLoginFailedException(Throwable arg0) {
         super(arg0);
-        // TODO Auto-generated constructor stub
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/progress/NullProgressMonitor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/progress/NullProgressMonitor.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/progress/NullProgressMonitor.java	(revision 3408)
@@ -78,5 +78,4 @@
 
     public int getTicksCount() {
-        // TODO Auto-generated method stub
         return 0;
     }
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetSearchDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetSearchDialog.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetSearchDialog.java	(revision 3408)
@@ -313,5 +313,4 @@
      */
     private void filterPresets(String text) {
-        //TODO search also in keys/values
         //TODO Favorites
         text = text.toLowerCase();
Index: trunk/src/org/openstreetmap/josm/io/GpxReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/GpxReader.java	(revision 3407)
+++ trunk/src/org/openstreetmap/josm/io/GpxReader.java	(revision 3408)
@@ -8,5 +8,4 @@
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Collection;
