Index: /trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java	(revision 14128)
+++ /trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java	(revision 14129)
@@ -300,4 +300,16 @@
             return match((Tagged) osm);
         }
+
+        protected static Pattern compilePattern(String regex, int flags) throws SearchParseError {
+            try {
+                return Pattern.compile(regex, flags);
+            } catch (PatternSyntaxException e) {
+                throw new SearchParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e);
+            } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) {
+                // StringIndexOutOfBoundsException catched because of https://bugs.openjdk.java.net/browse/JI-9044959
+                // See #13870: To remove after we switch to a version of Java which resolves this bug
+                throw new SearchParseError(tr(rxErrorMsgNoPos, regex, e.getMessage()), e);
+            }
+        }
     }
 
@@ -686,22 +698,8 @@
             if (regexSearch) {
                 int searchFlags = regexFlags(caseSensitive);
-
-                try {
-                    this.keyPattern = Pattern.compile(key, searchFlags);
-                } catch (PatternSyntaxException e) {
-                    throw new SearchParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e);
-                } catch (IllegalArgumentException e) {
-                    throw new SearchParseError(tr(rxErrorMsgNoPos, key, e.getMessage()), e);
-                }
-                try {
-                    this.valuePattern = Pattern.compile(value, searchFlags);
-                } catch (PatternSyntaxException e) {
-                    throw new SearchParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e);
-                } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) {
-                    throw new SearchParseError(tr(rxErrorMsgNoPos, value, e.getMessage()), e);
-                }
+                this.keyPattern = compilePattern(key, searchFlags);
+                this.valuePattern = compilePattern(value, searchFlags);
                 this.key = key;
                 this.value = value;
-
             } else {
                 this.key = key;
@@ -966,22 +964,10 @@
 
             if (regexp && !key.isEmpty() && !"*".equals(key)) {
-                try {
-                    keyPattern = Pattern.compile(key, regexFlags(false));
-                } catch (PatternSyntaxException e) {
-                    throw new SearchParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e);
-                } catch (IllegalArgumentException e) {
-                    throw new SearchParseError(tr(rxErrorMsgNoPos, key, e.getMessage()), e);
-                }
+                keyPattern = compilePattern(key, regexFlags(false));
             } else {
                 keyPattern = null;
             }
             if (regexp && !this.value.isEmpty() && !"*".equals(this.value)) {
-                try {
-                    valuePattern = Pattern.compile(this.value, regexFlags(false));
-                } catch (PatternSyntaxException e) {
-                    throw new SearchParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e);
-                } catch (IllegalArgumentException e) {
-                    throw new SearchParseError(tr(rxErrorMsgNoPos, value, e.getMessage()), e);
-                }
+                valuePattern = compilePattern(this.value, regexFlags(false));
             } else {
                 valuePattern = null;
@@ -1098,13 +1084,5 @@
             this.caseSensitive = caseSensitive;
             if (regexSearch) {
-                try {
-                    this.searchRegex = Pattern.compile(s, regexFlags(caseSensitive));
-                } catch (PatternSyntaxException e) {
-                    throw new SearchParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e);
-                } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) {
-                    // StringIndexOutOfBoundsException catched because of https://bugs.openjdk.java.net/browse/JI-9044959
-                    // See #13870: To remove after we switch to a version of Java which resolves this bug
-                    throw new SearchParseError(tr(rxErrorMsgNoPos, s, e.getMessage()), e);
-                }
+                this.searchRegex = compilePattern(s, regexFlags(caseSensitive));
                 this.search = s;
             } else if (caseSensitive) {
Index: /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 14128)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 14129)
@@ -39,8 +39,8 @@
 import org.openstreetmap.josm.gui.io.importexport.GpxImporter;
 import org.openstreetmap.josm.gui.layer.gpx.ChooseTrackVisibilityAction;
-import org.openstreetmap.josm.gui.layer.gpx.ConvertToDataLayerAction;
 import org.openstreetmap.josm.gui.layer.gpx.CustomizeDrawingAction;
 import org.openstreetmap.josm.gui.layer.gpx.DownloadAlongTrackAction;
 import org.openstreetmap.josm.gui.layer.gpx.DownloadWmsAlongTrackAction;
+import org.openstreetmap.josm.gui.layer.gpx.ConvertFromGpxLayerAction;
 import org.openstreetmap.josm.gui.layer.gpx.GpxDrawHelper;
 import org.openstreetmap.josm.gui.layer.gpx.ImportAudioAction;
@@ -225,5 +225,5 @@
                 new ImportAudioAction(this),
                 new MarkersFromNamedPointsAction(this),
-                new ConvertToDataLayerAction.FromGpxLayer(this),
+                new ConvertFromGpxLayerAction(this),
                 new DownloadAlongTrackAction(data),
                 new DownloadWmsAlongTrackAction(data),
Index: /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java	(revision 14129)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java	(revision 14129)
@@ -0,0 +1,279 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.gpx;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map.Entry;
+
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.gpx.GpxConstants;
+import org.openstreetmap.josm.data.gpx.GpxTrack;
+import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.WayPoint;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.ExtendedDialog;
+import org.openstreetmap.josm.gui.layer.GpxLayer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.UncheckedParseException;
+import org.openstreetmap.josm.tools.date.DateUtils;
+
+/**
+ * Converts a {@link GpxLayer} to a {@link OsmDataLayer}.
+ * @since 14129 (extracted from {@link ConvertToDataLayerAction})
+ */
+public class ConvertFromGpxLayerAction extends ConvertToDataLayerAction<GpxLayer> {
+
+    private static final String GPX_SETTING = "gpx.convert-tags";
+    private final DateFormat timeFormatter = DateUtils.getGpxFormat();
+
+    /**
+     * Creates a new {@code FromGpxLayer}.
+     * @param layer the source layer
+     */
+    public ConvertFromGpxLayerAction(GpxLayer layer) {
+        super(layer);
+    }
+
+    @Override
+    public DataSet convert() {
+        final DataSet ds = new DataSet();
+
+        List<String> keys = new ArrayList<>();
+        String convertTags = Config.getPref().get(GPX_SETTING, "ask");
+        boolean check = "list".equals(convertTags) || "ask".equals(convertTags);
+        boolean none = "no".equals(convertTags); // no need to convert tags when no dialog will be shown anyways
+
+        for (GpxTrack trk : layer.data.getTracks()) {
+            for (GpxTrackSegment segment : trk.getSegments()) {
+                List<Node> nodes = new ArrayList<>();
+                for (WayPoint p : segment.getWayPoints()) {
+                    Node n = new Node(p.getCoor());
+                    for (Entry<String, Object> entry : p.attr.entrySet()) {
+                        String key = entry.getKey();
+                        Object obj = p.get(key);
+                        if (check && !keys.contains(key) && (obj instanceof String || obj instanceof Date)) {
+                            keys.add(key);
+                        }
+                        if (obj instanceof String) {
+                            String str = (String) obj;
+                            if (!none) {
+                                // only convert when required
+                                n.put(key, str);
+                            }
+                            if (GpxConstants.PT_TIME.equals(key)) {
+                                // timestamps should always be converted
+                                try {
+                                    n.setTimestamp(DateUtils.fromString(str));
+                                } catch (UncheckedParseException e) {
+                                    Logging.log(Logging.LEVEL_WARN, e);
+                                }
+                            }
+                        } else if (obj instanceof Date && GpxConstants.PT_TIME.equals(key)) {
+                            // timestamps should always be converted
+                            Date date = (Date) obj;
+                            if (!none) { //... but the tag will only be set when required
+                                n.put(key, timeFormatter.format(date));
+                            }
+                            n.setTimestamp(date);
+                        }
+                    }
+                    ds.addPrimitive(n);
+                    nodes.add(n);
+                }
+                Way w = new Way();
+                w.setNodes(nodes);
+                ds.addPrimitive(w);
+            }
+        }
+        //gpx.convert-tags: all, list, *ask, no
+        //gpx.convert-tags.last: *all, list, no
+        //gpx.convert-tags.list.yes
+        //gpx.convert-tags.list.no
+        List<String> listPos = Config.getPref().getList(GPX_SETTING + ".list.yes");
+        List<String> listNeg = Config.getPref().getList(GPX_SETTING + ".list.no");
+        if (check && !keys.isEmpty()) {
+            // Either "list" or "ask" was stored in the settings, so the Nodes have to be filtered after all tags have been processed
+            List<String> allTags = new ArrayList<>(listPos);
+            allTags.addAll(listNeg);
+            if (!allTags.containsAll(keys) || "ask".equals(convertTags)) {
+                // not all keys are in positive/negative list, so we have to ask the user
+                TagConversionDialogResponse res = showTagConversionDialog(keys, listPos, listNeg);
+                if (res.sel == null) {
+                    return null;
+                }
+                listPos = res.listPos;
+
+                if ("no".equals(res.sel)) {
+                    // User just chose not to convert any tags, but that was unknown before the initial conversion
+                    return filterDataSet(ds, null);
+                } else if ("all".equals(res.sel)) {
+                    return ds;
+                }
+            }
+            if (!listPos.containsAll(keys)) {
+                return filterDataSet(ds, listPos);
+            }
+        }
+        return ds;
+    }
+
+    /**
+     * Filters the tags of the given {@link DataSet}
+     * @param ds The {@link DataSet}
+     * @param listPos A {@code List<String>} containing the tags to be kept, can be {@code null} if all tags are to be removed
+     * @return The {@link DataSet}
+     * @since 14103
+     */
+    public DataSet filterDataSet(DataSet ds, List<String> listPos) {
+        Collection<Node> nodes = ds.getNodes();
+        for (Node n : nodes) {
+            for (String key : n.keySet()) {
+                if (listPos == null || !listPos.contains(key)) {
+                    n.put(key, null);
+                }
+            }
+        }
+        return ds;
+    }
+
+    /**
+     * Shows the TagConversionDialog asking the user whether to keep all, some or no tags
+     * @param keys The keys present during the current conversion
+     * @param listPos The keys that were previously selected
+     * @param listNeg The keys that were previously unselected
+     * @return {@link TagConversionDialogResponse} containing the selection
+     */
+    private static TagConversionDialogResponse showTagConversionDialog(List<String> keys, List<String> listPos, List<String> listNeg) {
+        TagConversionDialogResponse res = new TagConversionDialogResponse(listPos, listNeg);
+        String lSel = Config.getPref().get(GPX_SETTING + ".last", "all");
+
+        JPanel p = new JPanel(new GridBagLayout());
+        ButtonGroup r = new ButtonGroup();
+
+        p.add(new JLabel(
+                tr("The GPX layer contains fields that can be converted to OSM tags. How would you like to proceed?")),
+                GBC.eol());
+        JRadioButton rAll = new JRadioButton(tr("Convert all fields"), "all".equals(lSel));
+        r.add(rAll);
+        p.add(rAll, GBC.eol());
+
+        JRadioButton rList = new JRadioButton(tr("Only convert the following fields:"), "list".equals(lSel));
+        r.add(rList);
+        p.add(rList, GBC.eol());
+
+        JPanel q = new JPanel();
+
+        List<JCheckBox> checkList = new ArrayList<>();
+        for (String key : keys) {
+            JCheckBox cTmp = new JCheckBox(key, !listNeg.contains(key));
+            checkList.add(cTmp);
+            q.add(cTmp);
+        }
+
+        q.setBorder(BorderFactory.createEmptyBorder(0, 20, 5, 0));
+        p.add(q, GBC.eol());
+
+        JRadioButton rNone = new JRadioButton(tr("Do not convert any fields"), "no".equals(lSel));
+        r.add(rNone);
+        p.add(rNone, GBC.eol());
+
+        ActionListener enabler = new TagConversionDialogRadioButtonActionListener(checkList, true);
+        ActionListener disabler = new TagConversionDialogRadioButtonActionListener(checkList, false);
+
+        if (!"list".equals(lSel)) {
+            disabler.actionPerformed(null);
+        }
+
+        rAll.addActionListener(disabler);
+        rList.addActionListener(enabler);
+        rNone.addActionListener(disabler);
+
+        ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Options"),
+                tr("Convert"), tr("Convert and remember selection"), tr("Cancel"))
+                .setButtonIcons("exportgpx", "exportgpx", "cancel").setContent(p);
+        int ret = ed.showDialog().getValue();
+
+        if (ret == 1 || ret == 2) {
+            for (JCheckBox cItem : checkList) {
+                String key = cItem.getText();
+                if (cItem.isSelected()) {
+                    if (!res.listPos.contains(key)) {
+                        res.listPos.add(key);
+                    }
+                    res.listNeg.remove(key);
+                } else {
+                    if (!res.listNeg.contains(key)) {
+                        res.listNeg.add(key);
+                    }
+                    res.listPos.remove(key);
+                }
+            }
+            if (rAll.isSelected()) {
+                res.sel = "all";
+            } else if (rNone.isSelected()) {
+                res.sel = "no";
+            }
+            Config.getPref().put(GPX_SETTING + ".last", res.sel);
+            if (ret == 2) {
+                Config.getPref().put(GPX_SETTING, res.sel);
+            } else {
+                Config.getPref().put(GPX_SETTING, "ask");
+            }
+            Config.getPref().putList(GPX_SETTING + ".list.yes", res.listPos);
+            Config.getPref().putList(GPX_SETTING + ".list.no", res.listNeg);
+        } else {
+            res.sel = null;
+        }
+        return res;
+    }
+
+    private static class TagConversionDialogResponse {
+
+        final List<String> listPos;
+        final List<String> listNeg;
+        String sel = "list";
+
+        TagConversionDialogResponse(List<String> p, List<String> n) {
+            listPos = new ArrayList<>(p);
+            listNeg = new ArrayList<>(n);
+        }
+    }
+
+    private static class TagConversionDialogRadioButtonActionListener implements ActionListener {
+
+        private final boolean enable;
+        private final List<JCheckBox> checkList;
+
+        TagConversionDialogRadioButtonActionListener(List<JCheckBox> chks, boolean en) {
+            enable = en;
+            checkList = chks;
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent arg0) {
+            for (JCheckBox ch : checkList) {
+                ch.setEnabled(enable);
+            }
+        }
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromMarkerLayerAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromMarkerLayerAction.java	(revision 14129)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromMarkerLayerAction.java	(revision 14129)
@@ -0,0 +1,59 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.gpx;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Optional;
+
+import org.openstreetmap.josm.data.gpx.GpxConstants;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.layer.markerlayer.Marker;
+import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
+import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.tools.Logging;
+
+/**
+ * Converts a {@link MarkerLayer} to a {@link OsmDataLayer}.
+ * @since 14129 (extracted from {@link ConvertToDataLayerAction})
+ */
+public class ConvertFromMarkerLayerAction extends ConvertToDataLayerAction<MarkerLayer> {
+
+    /**
+     * Converts a {@link MarkerLayer} to a {@link OsmDataLayer}.
+     * @param layer marker layer
+     */
+    public ConvertFromMarkerLayerAction(MarkerLayer layer) {
+        super(layer);
+    }
+
+    @Override
+    public DataSet convert() {
+        final DataSet ds = new DataSet();
+        for (Marker marker : layer.data) {
+            final Node node = new Node(marker.getCoor());
+            final Collection<String> mapping = Config.getPref().getList("gpx.to-osm-mapping", Arrays.asList(
+                    GpxConstants.GPX_NAME, "name",
+                    GpxConstants.GPX_DESC, "description",
+                    GpxConstants.GPX_CMT, "note",
+                    GpxConstants.GPX_SRC, "source",
+                    GpxConstants.PT_SYM, "gpxicon"));
+            if (mapping.size() % 2 == 0) {
+                final Iterator<String> it = mapping.iterator();
+                while (it.hasNext()) {
+                    final String gpxKey = it.next();
+                    final String osmKey = it.next();
+                    Optional.ofNullable(marker.getTemplateValue(gpxKey, false))
+                            .map(String::valueOf)
+                            .ifPresent(s -> node.put(osmKey, s));
+                }
+            } else {
+                Logging.warn("Invalid gpx.to-osm-mapping Einstein setting: expecting even number of entries");
+            }
+            ds.addPrimitive(node);
+        }
+        return ds;
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerAction.java	(revision 14128)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerAction.java	(revision 14129)
@@ -7,48 +7,21 @@
 import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.io.File;
-import java.text.DateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Optional;
 
 import javax.swing.AbstractAction;
-import javax.swing.BorderFactory;
-import javax.swing.ButtonGroup;
-import javax.swing.JCheckBox;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
-import javax.swing.JRadioButton;
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.gpx.GpxConstants;
-import org.openstreetmap.josm.data.gpx.GpxTrack;
-import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
-import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
-import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.MainApplication;
-import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
-import org.openstreetmap.josm.gui.layer.markerlayer.Marker;
-import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
 import org.openstreetmap.josm.gui.widgets.UrlLabel;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
-import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.UncheckedParseException;
-import org.openstreetmap.josm.tools.date.DateUtils;
 
 /**
@@ -69,286 +42,4 @@
         this.layer = layer;
         putValue("help", ht("/Action/ConvertToDataLayer"));
-    }
-
-    /**
-     * Converts a {@link GpxLayer} to a {@link OsmDataLayer}.
-     */
-    public static class FromGpxLayer extends ConvertToDataLayerAction<GpxLayer> {
-
-        private static final String GPX_SETTING = "gpx.convert-tags";
-        private final DateFormat timeFormatter = DateUtils.getGpxFormat();
-
-        /**
-         * Creates a new {@code FromGpxLayer}.
-         * @param layer the source layer
-         */
-        public FromGpxLayer(GpxLayer layer) {
-            super(layer);
-        }
-
-        @Override
-        public DataSet convert() {
-            final DataSet ds = new DataSet();
-
-            List<String> keys = new ArrayList<>();
-            String convertTags = Config.getPref().get(GPX_SETTING, "ask");
-            boolean check = "list".equals(convertTags) || "ask".equals(convertTags);
-            boolean none = "no".equals(convertTags); // no need to convert tags when no dialog will be shown anyways
-
-            for (GpxTrack trk : layer.data.getTracks()) {
-                for (GpxTrackSegment segment : trk.getSegments()) {
-                    List<Node> nodes = new ArrayList<>();
-                    for (WayPoint p : segment.getWayPoints()) {
-                        Node n = new Node(p.getCoor());
-                        for (Entry<String, Object> entry : p.attr.entrySet()) {
-                            String key = entry.getKey();
-                            Object obj = p.get(key);
-                            if (check && !keys.contains(key) && (obj instanceof String || obj instanceof Date)) {
-                                keys.add(key);
-                            }
-                            if (obj instanceof String) {
-                                String str = (String) obj;
-                                if (!none) {
-                                    // only convert when required
-                                    n.put(key, str);
-                                }
-                                if (GpxConstants.PT_TIME.equals(key)) {
-                                    // timestamps should always be converted
-                                    try {
-                                        n.setTimestamp(DateUtils.fromString(str));
-                                    } catch (UncheckedParseException e) {
-                                        Logging.log(Logging.LEVEL_WARN, e);
-                                    }
-                                }
-                            } else if (obj instanceof Date && GpxConstants.PT_TIME.equals(key)) {
-                                // timestamps should always be converted
-                                Date date = (Date) obj;
-                                if (!none) { //... but the tag will only be set when required
-                                    n.put(key, timeFormatter.format(date));
-                                }
-                                n.setTimestamp(date);
-                            }
-                        }
-                        ds.addPrimitive(n);
-                        nodes.add(n);
-                    }
-                    Way w = new Way();
-                    w.setNodes(nodes);
-                    ds.addPrimitive(w);
-                }
-            }
-            //gpx.convert-tags: all, list, *ask, no
-            //gpx.convert-tags.last: *all, list, no
-            //gpx.convert-tags.list.yes
-            //gpx.convert-tags.list.no
-            List<String> listPos = Config.getPref().getList(GPX_SETTING + ".list.yes");
-            List<String> listNeg = Config.getPref().getList(GPX_SETTING + ".list.no");
-            if (check && !keys.isEmpty()) {
-                // Either "list" or "ask" was stored in the settings, so the Nodes have to be filtered after all tags have been processed
-                List<String> allTags = new ArrayList<>(listPos);
-                allTags.addAll(listNeg);
-                if (!allTags.containsAll(keys) || "ask".equals(convertTags)) {
-                    // not all keys are in positive/negative list, so we have to ask the user
-                    TagConversionDialogResponse res = showTagConversionDialog(keys, listPos, listNeg);
-                    if (res.sel == null) {
-                        return null;
-                    }
-                    listPos = res.listPos;
-
-                    if ("no".equals(res.sel)) {
-                        // User just chose not to convert any tags, but that was unknown before the initial conversion
-                        return filterDataSet(ds, null);
-                    } else if ("all".equals(res.sel)) {
-                        return ds;
-                    }
-                }
-                if (!listPos.containsAll(keys)) {
-                    return filterDataSet(ds, listPos);
-                }
-            }
-            return ds;
-        }
-
-        /**
-         * Filters the tags of the given {@link DataSet}
-         * @param ds The {@link DataSet}
-         * @param listPos A {@code List<String>} containing the tags to be kept, can be {@code null} if all tags are to be removed
-         * @return The {@link DataSet}
-         * @since 14103
-         */
-        public DataSet filterDataSet(DataSet ds, List<String> listPos) {
-            Collection<Node> nodes = ds.getNodes();
-            for (Node n : nodes) {
-                for (String key : n.keySet()) {
-                    if (listPos == null || !listPos.contains(key)) {
-                        n.put(key, null);
-                    }
-                }
-            }
-            return ds;
-        }
-
-        /**
-         * Shows the TagConversionDialog asking the user whether to keep all, some or no tags
-         * @param keys The keys present during the current conversion
-         * @param listPos The keys that were previously selected
-         * @param listNeg The keys that were previously unselected
-         * @return {@link TagConversionDialogResponse} containing the selection
-         */
-        private static TagConversionDialogResponse showTagConversionDialog(List<String> keys, List<String> listPos, List<String> listNeg) {
-            TagConversionDialogResponse res = new TagConversionDialogResponse(listPos, listNeg);
-            String lSel = Config.getPref().get(GPX_SETTING + ".last", "all");
-
-            JPanel p = new JPanel(new GridBagLayout());
-            ButtonGroup r = new ButtonGroup();
-
-            p.add(new JLabel(
-                    tr("The GPX layer contains fields that can be converted to OSM tags. How would you like to proceed?")),
-                    GBC.eol());
-            JRadioButton rAll = new JRadioButton(tr("Convert all fields"), "all".equals(lSel));
-            r.add(rAll);
-            p.add(rAll, GBC.eol());
-
-            JRadioButton rList = new JRadioButton(tr("Only convert the following fields:"), "list".equals(lSel));
-            r.add(rList);
-            p.add(rList, GBC.eol());
-
-            JPanel q = new JPanel();
-
-            List<JCheckBox> checkList = new ArrayList<>();
-            for (String key : keys) {
-                JCheckBox cTmp = new JCheckBox(key, !listNeg.contains(key));
-                checkList.add(cTmp);
-                q.add(cTmp);
-            }
-
-            q.setBorder(BorderFactory.createEmptyBorder(0, 20, 5, 0));
-            p.add(q, GBC.eol());
-
-            JRadioButton rNone = new JRadioButton(tr("Do not convert any fields"), "no".equals(lSel));
-            r.add(rNone);
-            p.add(rNone, GBC.eol());
-
-            ActionListener enabler = new TagConversionDialogRadioButtonActionListener(checkList, true);
-            ActionListener disabler = new TagConversionDialogRadioButtonActionListener(checkList, false);
-
-            if (!"list".equals(lSel)) {
-                disabler.actionPerformed(null);
-            }
-
-            rAll.addActionListener(disabler);
-            rList.addActionListener(enabler);
-            rNone.addActionListener(disabler);
-
-            ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Options"),
-                    tr("Convert"), tr("Convert and remember selection"), tr("Cancel"))
-                    .setButtonIcons("exportgpx", "exportgpx", "cancel").setContent(p);
-            int ret = ed.showDialog().getValue();
-
-            if (ret == 1 || ret == 2) {
-                for (JCheckBox cItem : checkList) {
-                    String key = cItem.getText();
-                    if (cItem.isSelected()) {
-                        if (!res.listPos.contains(key)) {
-                            res.listPos.add(key);
-                        }
-                        res.listNeg.remove(key);
-                    } else {
-                        if (!res.listNeg.contains(key)) {
-                            res.listNeg.add(key);
-                        }
-                        res.listPos.remove(key);
-                    }
-                }
-                if (rAll.isSelected()) {
-                    res.sel = "all";
-                } else if (rNone.isSelected()) {
-                    res.sel = "no";
-                }
-                Config.getPref().put(GPX_SETTING + ".last", res.sel);
-                if (ret == 2) {
-                    Config.getPref().put(GPX_SETTING, res.sel);
-                } else {
-                    Config.getPref().put(GPX_SETTING, "ask");
-                }
-                Config.getPref().putList(GPX_SETTING + ".list.yes", res.listPos);
-                Config.getPref().putList(GPX_SETTING + ".list.no", res.listNeg);
-            } else {
-                res.sel = null;
-            }
-            return res;
-        }
-
-        private static class TagConversionDialogResponse {
-
-            final List<String> listPos;
-            final List<String> listNeg;
-            String sel = "list";
-
-            TagConversionDialogResponse(List<String> p, List<String> n) {
-                listPos = new ArrayList<>(p);
-                listNeg = new ArrayList<>(n);
-            }
-        }
-
-        private static class TagConversionDialogRadioButtonActionListener implements ActionListener {
-
-            private final boolean enable;
-            private final List<JCheckBox> checkList;
-
-            TagConversionDialogRadioButtonActionListener(List<JCheckBox> chks, boolean en) {
-                enable = en;
-                checkList = chks;
-            }
-
-            @Override
-            public void actionPerformed(ActionEvent arg0) {
-                for (JCheckBox ch : checkList) {
-                    ch.setEnabled(enable);
-                }
-            }
-        }
-    }
-
-    /**
-     * Converts a {@link MarkerLayer} to a {@link OsmDataLayer}.
-     */
-    public static class FromMarkerLayer extends ConvertToDataLayerAction<MarkerLayer> {
-
-        /**
-         * Converts a {@link MarkerLayer} to a {@link OsmDataLayer}.
-         * @param layer marker layer
-         */
-        public FromMarkerLayer(MarkerLayer layer) {
-            super(layer);
-        }
-
-        @Override
-        public DataSet convert() {
-            final DataSet ds = new DataSet();
-            for (Marker marker : layer.data) {
-                final Node node = new Node(marker.getCoor());
-                final Collection<String> mapping = Config.getPref().getList("gpx.to-osm-mapping", Arrays.asList(
-                        GpxConstants.GPX_NAME, "name",
-                        GpxConstants.GPX_DESC, "description",
-                        GpxConstants.GPX_CMT, "note",
-                        GpxConstants.GPX_SRC, "source",
-                        GpxConstants.PT_SYM, "gpxicon"));
-                if (mapping.size() % 2 == 0) {
-                    final Iterator<String> it = mapping.iterator();
-                    while (it.hasNext()) {
-                        final String gpxKey = it.next();
-                        final String osmKey = it.next();
-                        Optional.ofNullable(marker.getTemplateValue(gpxKey, false))
-                                .map(String::valueOf)
-                                .ifPresent(s -> node.put(osmKey, s));
-                    }
-                } else {
-                    Logging.warn("Invalid gpx.to-osm-mapping Einstein setting: expecting even number of entries");
-                }
-                ds.addPrimitive(node);
-            }
-            return ds;
-        }
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 14128)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 14129)
@@ -49,5 +49,5 @@
 import org.openstreetmap.josm.gui.layer.JumpToMarkerActions.JumpToPreviousMarker;
 import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.gpx.ConvertToDataLayerAction;
+import org.openstreetmap.josm.gui.layer.gpx.ConvertFromMarkerLayerAction;
 import org.openstreetmap.josm.io.audio.AudioPlayer;
 import org.openstreetmap.josm.spi.preferences.Config;
@@ -248,5 +248,5 @@
         components.add(new JumpToNextMarker(this));
         components.add(new JumpToPreviousMarker(this));
-        components.add(new ConvertToDataLayerAction.FromMarkerLayer(this));
+        components.add(new ConvertFromMarkerLayerAction(this));
         components.add(new RenameLayerAction(getAssociatedFile(), this));
         components.add(SeparatorLayerAction.INSTANCE);
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerActionTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerActionTest.java	(revision 14128)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerActionTest.java	(revision 14129)
@@ -40,5 +40,5 @@
         final GpxData data = GpxReaderTest.parseGpxData(TestUtils.getTestDataRoot() + "minimal.gpx");
         final MarkerLayer markers = new MarkerLayer(data, "Markers", data.storageFile, null);
-        final DataSet osm = new ConvertToDataLayerAction.FromMarkerLayer(markers).convert();
+        final DataSet osm = new ConvertFromMarkerLayerAction(markers).convert();
         assertEquals(1, osm.getNodes().size());
         assertEquals(new TagMap("name", "Schranke", "description", "Pfad", "note", "Pfad", "gpxicon", "Toll Booth"),
