Index: trunk/src/org/openstreetmap/josm/actions/ShowStatusReportAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/ShowStatusReportAction.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/actions/ShowStatusReportAction.java	(revision 12649)
@@ -28,10 +28,11 @@
 import org.openstreetmap.josm.data.osm.DatasetConsistencyTest;
 import org.openstreetmap.josm.data.preferences.Setting;
+import org.openstreetmap.josm.data.preferences.sources.MapPaintPrefHelper;
+import org.openstreetmap.josm.data.preferences.sources.PresetPrefHelper;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
+import org.openstreetmap.josm.data.preferences.sources.SourcePrefHelper;
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.MainApplication;
-import org.openstreetmap.josm.gui.preferences.SourceEditor;
-import org.openstreetmap.josm.gui.preferences.map.MapPaintPreference;
-import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
-import org.openstreetmap.josm.gui.preferences.validator.ValidatorTagCheckerRulesPreference;
+import org.openstreetmap.josm.gui.bugreport.DebugTextDisplay;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.io.OsmApi;
@@ -42,5 +43,4 @@
 import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.bugreport.BugReportSender;
-import org.openstreetmap.josm.tools.bugreport.DebugTextDisplay;
 
 /**
@@ -189,7 +189,7 @@
         text.append('\n');
         appendCollection(text, "Plugins", Utils.transform(PluginHandler.getBugReportInformation(), i -> "+ " + i));
-        appendCollection(text, "Tagging presets", getCustomUrls(TaggingPresetPreference.PresetPrefHelper.INSTANCE));
-        appendCollection(text, "Map paint styles", getCustomUrls(MapPaintPreference.MapPaintPrefHelper.INSTANCE));
-        appendCollection(text, "Validator rules", getCustomUrls(ValidatorTagCheckerRulesPreference.RulePrefHelper.INSTANCE));
+        appendCollection(text, "Tagging presets", getCustomUrls(PresetPrefHelper.INSTANCE));
+        appendCollection(text, "Map paint styles", getCustomUrls(MapPaintPrefHelper.INSTANCE));
+        appendCollection(text, "Validator rules", getCustomUrls(ValidatorPrefHelper.INSTANCE));
         appendCollection(text, "Last errors/warnings", Utils.transform(Logging.getLastErrorAndWarnings(), i -> "- " + i));
 
@@ -202,5 +202,5 @@
     }
 
-    private static Collection<String> getCustomUrls(SourceEditor.SourcePrefHelper helper) {
+    private static Collection<String> getCustomUrls(SourcePrefHelper helper) {
         final Set<String> defaultUrls = helper.getDefault().stream()
                 .map(i -> i.url)
Index: trunk/src/org/openstreetmap/josm/actions/ValidateAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/ValidateAction.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/actions/ValidateAction.java	(revision 12649)
@@ -13,4 +13,5 @@
 
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
 import org.openstreetmap.josm.data.validation.OsmValidator;
 import org.openstreetmap.josm.data.validation.Test;
@@ -21,5 +22,4 @@
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
 import org.openstreetmap.josm.gui.layer.ValidatorLayer;
-import org.openstreetmap.josm.gui.preferences.validator.ValidatorPreference;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.io.OsmTransferException;
@@ -170,5 +170,5 @@
             }
             tests = null;
-            if (ValidatorPreference.PREF_USE_IGNORE.get()) {
+            if (ValidatorPrefHelper.PREF_USE_IGNORE.get()) {
                 getProgressMonitor().subTask(tr("Updating ignored errors ..."));
                 for (TestError error : errors) {
Index: trunk/src/org/openstreetmap/josm/actions/upload/ValidateUploadHook.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/upload/ValidateUploadHook.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/actions/upload/ValidateUploadHook.java	(revision 12649)
@@ -16,4 +16,5 @@
 import org.openstreetmap.josm.data.APIDataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
 import org.openstreetmap.josm.data.validation.OsmValidator;
 import org.openstreetmap.josm.data.validation.Severity;
@@ -27,5 +28,4 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.ValidatorLayer;
-import org.openstreetmap.josm.gui.preferences.validator.ValidatorPreference;
 import org.openstreetmap.josm.gui.widgets.HtmlPanel;
 import org.openstreetmap.josm.tools.GBC;
@@ -64,5 +64,5 @@
             test.visit(selection);
             test.endTest();
-            if (ValidatorPreference.PREF_OTHER.get() && ValidatorPreference.PREF_OTHER_UPLOAD.get()) {
+            if (ValidatorPrefHelper.PREF_OTHER.get() && ValidatorPrefHelper.PREF_OTHER_UPLOAD.get()) {
                 errors.addAll(test.getErrors());
             } else {
@@ -86,5 +86,5 @@
             return true;
 
-        if (ValidatorPreference.PREF_USE_IGNORE.get()) {
+        if (ValidatorPrefHelper.PREF_USE_IGNORE.get()) {
             int nume = 0;
             for (TestError error : errors) {
Index: trunk/src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 12649)
@@ -68,7 +68,6 @@
 import org.openstreetmap.josm.data.preferences.Setting;
 import org.openstreetmap.josm.data.preferences.StringSetting;
-import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
-import org.openstreetmap.josm.gui.preferences.validator.ValidatorTagCheckerRulesPreference;
-import org.openstreetmap.josm.gui.preferences.validator.ValidatorTagCheckerRulesPreference.RulePrefHelper;
+import org.openstreetmap.josm.data.preferences.sources.ExtendedSourceEntry;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
 import org.openstreetmap.josm.io.OfflineAccessException;
 import org.openstreetmap.josm.io.OnlineResource;
@@ -1714,5 +1713,5 @@
             List<Map<String, String>> l = new ArrayList<>(((MapListSetting) setting).getValue());
             if (l.stream().noneMatch(x -> x.containsValue(url))) {
-                RulePrefHelper helper = ValidatorTagCheckerRulesPreference.RulePrefHelper.INSTANCE;
+                ValidatorPrefHelper helper = ValidatorPrefHelper.INSTANCE;
                 Optional<ExtendedSourceEntry> val = helper.getDefault().stream().filter(x -> url.equals(x.url)).findFirst();
                 if (val.isPresent()) {
Index: trunk/src/org/openstreetmap/josm/data/preferences/sources/ExtendedSourceEntry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/sources/ExtendedSourceEntry.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/data/preferences/sources/ExtendedSourceEntry.java	(revision 12649)
@@ -0,0 +1,92 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences.sources;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * Source entry with additional metadata.
+ * @since 12649 (extracted from gui.preferences package)
+ */
+public class ExtendedSourceEntry extends SourceEntry implements Comparable<ExtendedSourceEntry> {
+    /** file name used for display */
+    public String simpleFileName;
+    /** version used for display */
+    public String version;
+    /** author name used for display */
+    public String author;
+    /** webpage link used for display */
+    public String link;
+    /** short description used for display */
+    public String description;
+    /** Style type: can only have one value: "xml". Used to filter out old XML styles. For MapCSS styles, the value is not set. */
+    public String styleType;
+    /** minimum JOSM version required to enable this source entry */
+    public Integer minJosmVersion;
+
+    /**
+     * Constructs a new {@code ExtendedSourceEntry}.
+     * @param simpleFileName file name used for display
+     * @param url URL that {@link org.openstreetmap.josm.io.CachedFile} understands
+     */
+    public ExtendedSourceEntry(String simpleFileName, String url) {
+        super(url, null, null, true);
+        this.simpleFileName = simpleFileName;
+    }
+
+    /**
+     * @return string representation for GUI list or menu entry
+     */
+    public String getDisplayName() {
+        return title == null ? simpleFileName : title;
+    }
+
+    private static void appendRow(StringBuilder s, String th, String td) {
+        s.append("<tr><th>").append(th).append("</th><td>").append(Utils.escapeReservedCharactersHTML(td)).append("</td</tr>");
+    }
+
+    /**
+     * Returns a tooltip containing available metadata.
+     * @return a tooltip containing available metadata
+     */
+    public String getTooltip() {
+        StringBuilder s = new StringBuilder();
+        appendRow(s, tr("Short Description:"), getDisplayName());
+        appendRow(s, tr("URL:"), url);
+        if (author != null) {
+            appendRow(s, tr("Author:"), author);
+        }
+        if (link != null) {
+            appendRow(s, tr("Webpage:"), link);
+        }
+        if (description != null) {
+            appendRow(s, tr("Description:"), description);
+        }
+        if (version != null) {
+            appendRow(s, tr("Version:"), version);
+        }
+        if (minJosmVersion != null) {
+            appendRow(s, tr("Minimum JOSM Version:"), Integer.toString(minJosmVersion));
+        }
+        return "<html><style>th{text-align:right}td{width:400px}</style>"
+                + "<table>" + s + "</table></html>";
+    }
+
+    @Override
+    public String toString() {
+        return "<html><b>" + getDisplayName() + "</b>"
+                + (author == null ? "" : " <span color=\"gray\">" + tr("by {0}", author) + "</color>")
+                + "</html>";
+    }
+
+    @Override
+    public int compareTo(ExtendedSourceEntry o) {
+        if (url.startsWith("resource") && !o.url.startsWith("resource"))
+            return -1;
+        if (o.url.startsWith("resource"))
+            return 1;
+        else
+            return getDisplayName().compareToIgnoreCase(o.getDisplayName());
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/preferences/sources/MapPaintPrefHelper.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/sources/MapPaintPrefHelper.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/data/preferences/sources/MapPaintPrefHelper.java	(revision 12649)
@@ -0,0 +1,112 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences.sources;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TreeSet;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * Helper class for map paint styles preferences.
+ * @since 12649 (extracted from gui.preferences package)
+ */
+public class MapPaintPrefHelper extends SourcePrefHelper {
+
+    /**
+     * The unique instance.
+     */
+    public static final MapPaintPrefHelper INSTANCE = new MapPaintPrefHelper();
+
+    /**
+     * Constructs a new {@code MapPaintPrefHelper}.
+     */
+    public MapPaintPrefHelper() {
+        super("mappaint.style.entries");
+    }
+
+    @Override
+    public List<SourceEntry> get() {
+        List<SourceEntry> ls = super.get();
+        if (insertNewDefaults(ls)) {
+            put(ls);
+        }
+        return ls;
+    }
+
+    /**
+     * If the selection of default styles changes in future releases, add
+     * the new entries to the user-configured list. Remember the known URLs,
+     * so an item that was deleted explicitly is not added again.
+     * @param list new defaults
+     * @return {@code true} if a change occurred
+     */
+    private boolean insertNewDefaults(List<SourceEntry> list) {
+        boolean changed = false;
+
+        Collection<String> knownDefaults = new TreeSet<>(Main.pref.getCollection("mappaint.style.known-defaults"));
+
+        Collection<ExtendedSourceEntry> defaults = getDefault();
+        int insertionIdx = 0;
+        for (final SourceEntry def : defaults) {
+            int i = Utils.indexOf(list, se -> Objects.equals(def.url, se.url));
+            if (i == -1 && !knownDefaults.contains(def.url)) {
+                def.active = false;
+                list.add(insertionIdx, def);
+                insertionIdx++;
+                changed = true;
+            } else {
+                if (i >= insertionIdx) {
+                    insertionIdx = i + 1;
+                }
+            }
+            knownDefaults.add(def.url);
+        }
+        Main.pref.putCollection("mappaint.style.known-defaults", knownDefaults);
+
+        // XML style is not bundled anymore
+        list.remove(Utils.find(list, se -> "resource://styles/standard/elemstyles.xml".equals(se.url)));
+
+        return changed;
+    }
+
+    @Override
+    public Collection<ExtendedSourceEntry> getDefault() {
+        ExtendedSourceEntry defJosmMapcss = new ExtendedSourceEntry("elemstyles.mapcss", "resource://styles/standard/elemstyles.mapcss");
+        defJosmMapcss.active = true;
+        defJosmMapcss.name = "standard";
+        defJosmMapcss.title = tr("JOSM default (MapCSS)");
+        defJosmMapcss.description = tr("Internal style to be used as base for runtime switchable overlay styles");
+        ExtendedSourceEntry defPL2 = new ExtendedSourceEntry("potlatch2.mapcss", "resource://styles/standard/potlatch2.mapcss");
+        defPL2.active = false;
+        defPL2.name = "standard";
+        defPL2.title = tr("Potlatch 2");
+        defPL2.description = tr("the main Potlatch 2 style");
+
+        return Arrays.asList(defJosmMapcss, defPL2);
+    }
+
+    @Override
+    public Map<String, String> serialize(SourceEntry entry) {
+        Map<String, String> res = new HashMap<>();
+        res.put("url", entry.url == null ? "" : entry.url);
+        res.put("title", entry.title == null ? "" : entry.title);
+        res.put("active", Boolean.toString(entry.active));
+        if (entry.name != null) {
+            res.put("ptoken", entry.name);
+        }
+        return res;
+    }
+
+    @Override
+    public SourceEntry deserialize(Map<String, String> s) {
+        return new SourceEntry(s.get("url"), s.get("ptoken"), s.get("title"), Boolean.parseBoolean(s.get("active")));
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/preferences/sources/PresetPrefHelper.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/sources/PresetPrefHelper.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/data/preferences/sources/PresetPrefHelper.java	(revision 12649)
@@ -0,0 +1,49 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences.sources;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Helper class for tagging presets preferences.
+ * @since 12649 (extracted from gui.preferences package)
+ */
+public class PresetPrefHelper extends SourcePrefHelper {
+
+    /**
+     * The unique instance.
+     */
+    public static final PresetPrefHelper INSTANCE = new PresetPrefHelper();
+
+    /**
+     * Constructs a new {@code PresetPrefHelper}.
+     */
+    public PresetPrefHelper() {
+        super("taggingpreset.entries");
+    }
+
+    @Override
+    public Collection<ExtendedSourceEntry> getDefault() {
+        ExtendedSourceEntry i = new ExtendedSourceEntry("defaultpresets.xml", "resource://data/defaultpresets.xml");
+        i.title = tr("Internal Preset");
+        i.description = tr("The default preset for JOSM");
+        return Collections.singletonList(i);
+    }
+
+    @Override
+    public Map<String, String> serialize(SourceEntry entry) {
+        Map<String, String> res = new HashMap<>();
+        res.put("url", entry.url);
+        res.put("title", entry.title == null ? "" : entry.title);
+        return res;
+    }
+
+    @Override
+    public SourceEntry deserialize(Map<String, String> s) {
+        return new SourceEntry(s.get("url"), null, s.get("title"), true);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/preferences/sources/SourceEntry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/sources/SourceEntry.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/data/preferences/sources/SourceEntry.java	(revision 12649)
@@ -0,0 +1,206 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences.sources;
+
+import java.io.File;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * A source entry primarily used to save the user's selection of mappaint styles,
+ * but also for preset sources or validator rules.
+ * @since 12649 (moved from gui.preferences package)
+ * @since 3796
+ */
+public class SourceEntry {
+
+    /**
+     *  A URL can be anything that CachedFile understands, i.e.
+     *  a local file, http://, or a file from the current jar
+     */
+    public String url;
+
+    /**
+     * Indicates, that {@link #url} is a zip file and the resource is
+     * inside the zip file.
+     */
+    public boolean isZip;
+
+    /**
+     * If {@link #isZip} is true, denotes the path inside the zip file.
+     */
+    public String zipEntryPath;
+
+    /**
+     *  Name is used as a namespace for color preferences and (currently) only
+     *  one file with a name can be loaded at a time. Additional styles must
+     *  either have the same name as the main style or no name at all.
+     *  If no name is provided, it will be set to the default value "standard".
+     *  The name can also be given in the xml file as attribute for the rules tag.
+     *  (This overrides the name given in the preferences, otherwise both
+     *  methods are equivalent.)
+     */
+    public String name;
+
+    /**
+     * A title that can be used as menu entry.
+     */
+    public String title;
+
+    /**
+     * active is a boolean flag that can be used to turn the source on or off at runtime.
+     */
+    public boolean active;
+
+    /**
+     * Constructs a new {@code SourceEntry}.
+     * @param url URL that {@link org.openstreetmap.josm.io.CachedFile} understands
+     * @param isZip if url is a zip file and the resource is inside the zip file
+     * @param zipEntryPath If {@code isZip} is {@code true}, denotes the path inside the zip file
+     * @param name Source name
+     * @param title title that can be used as menu entry
+     * @param active boolean flag that can be used to turn the source on or off at runtime
+     * @see #url
+     * @see #isZip
+     * @see #zipEntryPath
+     * @see #name
+     * @see #title
+     * @see #active
+     */
+    public SourceEntry(String url, boolean isZip, String zipEntryPath, String name, String title, boolean active) {
+        this.url = url;
+        this.isZip = isZip;
+        this.zipEntryPath = "".equals(zipEntryPath) ? null : zipEntryPath;
+        this.name = "".equals(name) ? null : name;
+        this.title = "".equals(title) ? null : title;
+        this.active = active;
+    }
+
+    /**
+     * Constructs a new {@code SourceEntry}.
+     * @param url URL that {@link org.openstreetmap.josm.io.CachedFile} understands
+     * @param name Source name
+     * @param title title that can be used as menu entry
+     * @param active boolean flag that can be used to turn the source on or off at runtime
+     * @see #url
+     * @see #name
+     * @see #title
+     * @see #active
+     */
+    public SourceEntry(String url, String name, String title, boolean active) {
+        this(url, false, null, name, title, active);
+    }
+
+    /**
+     * Constructs a new {@code SourceEntry}.
+     * @param e existing source entry to copy
+     */
+    public SourceEntry(SourceEntry e) {
+        this.url = e.url;
+        this.isZip = e.isZip;
+        this.zipEntryPath = e.zipEntryPath;
+        this.name = e.name;
+        this.title = e.title;
+        this.active = e.active;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null || getClass() != obj.getClass()) return false;
+        SourceEntry that = (SourceEntry) obj;
+        return isZip == that.isZip &&
+                active == that.active &&
+                Objects.equals(url, that.url) &&
+                Objects.equals(zipEntryPath, that.zipEntryPath) &&
+                Objects.equals(name, that.name) &&
+                Objects.equals(title, that.title);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(url, isZip, zipEntryPath, name, title, active);
+    }
+
+    @Override
+    public String toString() {
+        return title != null ? title : url;
+    }
+
+    /**
+     * String to show in menus and error messages.
+     * @return Usually the shortdescription, but can be the file name
+     * if no shortdescription is available.
+     */
+    public String getDisplayString() {
+        if (title != null)
+            return title;
+        else
+            return getFileNamePart();
+    }
+
+    /**
+     * Extracts file part from url, e.g.:
+     * <code>http://www.test.com/file.xml?format=text --&gt; file.xml</code>
+     * @return The filename part of the URL
+     */
+    public String getFileNamePart() {
+        Pattern p = Pattern.compile("([^/\\\\]*?)([?].*)?$");
+        Matcher m = p.matcher(url);
+        if (m.find()) {
+            return m.group(1);
+        } else {
+            Logging.warn("Unexpected URL format: "+url);
+            return url;
+        }
+    }
+
+    /**
+     * the name / identifier that should be used to save custom color values
+     * and similar stuff to the preference file
+     * @return the identifier; never null. Usually the result is "standard"
+     */
+    public String getPrefName() {
+        return name == null ? "standard" : name;
+    }
+
+    /**
+     * Determines if this source denotes a file on a local filesystem.
+     * @return {@code true} if the source is a local file
+     */
+    public boolean isLocal() {
+        return Utils.isLocalUrl(url);
+    }
+
+    /**
+     * Return the source directory, only for local files.
+     * @return The source directory, or {@code null} if this file isn't local, or does not have a parent
+     * @since 7276
+     */
+    public File getLocalSourceDir() {
+        if (!isLocal())
+            return null;
+        return new File(url).getParentFile();
+    }
+
+    /**
+     * Returns the parent directory of the resource inside the zip file.
+     *
+     * @return the parent directory of the resource inside the zip file,
+     * "." if zipEntryPath is a top level file; null, if zipEntryPath is null
+     */
+    public String getZipEntryDirName() {
+        if (zipEntryPath == null) return null;
+        File file = new File(zipEntryPath);
+        File dir = file.getParentFile();
+        if (dir == null) return ".";
+        String path = dir.getPath();
+        if (!"/".equals(File.separator)) {
+            path = path.replace(File.separator, "/");
+        }
+        return path;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/preferences/sources/SourcePrefHelper.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/sources/SourcePrefHelper.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/data/preferences/sources/SourcePrefHelper.java	(revision 12649)
@@ -0,0 +1,107 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences.sources;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.openstreetmap.josm.Main;
+
+/**
+ * Helper class for specialized extensions preferences.
+ * @since 12649 (extracted from gui.preferences package)
+ */
+public abstract class SourcePrefHelper {
+
+    private final String pref;
+
+    /**
+     * Constructs a new {@code SourcePrefHelper} for the given preference key.
+     * @param pref The preference key
+     */
+    public SourcePrefHelper(String pref) {
+        this.pref = pref;
+    }
+
+    /**
+     * Returns the default sources provided by JOSM core.
+     * @return the default sources provided by JOSM core
+     */
+    public abstract Collection<ExtendedSourceEntry> getDefault();
+
+    /**
+     * Serializes the given source entry as a map.
+     * @param entry source entry to serialize
+     * @return map (key=value)
+     */
+    public abstract Map<String, String> serialize(SourceEntry entry);
+
+    /**
+     * Deserializes the given map as a source entry.
+     * @param entryStr map (key=value)
+     * @return source entry
+     */
+    public abstract SourceEntry deserialize(Map<String, String> entryStr);
+
+    /**
+     * Returns the list of sources.
+     * @return The list of sources
+     */
+    public List<SourceEntry> get() {
+
+        Collection<Map<String, String>> src = Main.pref.getListOfStructs(pref, (Collection<Map<String, String>>) null);
+        if (src == null)
+            return new ArrayList<>(getDefault());
+
+        List<SourceEntry> entries = new ArrayList<>();
+        for (Map<String, String> sourcePref : src) {
+            SourceEntry e = deserialize(new HashMap<>(sourcePref));
+            if (e != null) {
+                entries.add(e);
+            }
+        }
+        return entries;
+    }
+
+    /**
+     * Saves a list of sources to JOSM preferences.
+     * @param entries list of sources
+     * @return {@code true}, if something has changed (i.e. value is different than before)
+     */
+    public boolean put(Collection<? extends SourceEntry> entries) {
+        Collection<Map<String, String>> setting = serializeList(entries);
+        boolean unset = Main.pref.getListOfStructs(pref, (Collection<Map<String, String>>) null) == null;
+        if (unset) {
+            Collection<Map<String, String>> def = serializeList(getDefault());
+            if (setting.equals(def))
+                return false;
+        }
+        return Main.pref.putListOfStructs(pref, setting);
+    }
+
+    private Collection<Map<String, String>> serializeList(Collection<? extends SourceEntry> entries) {
+        Collection<Map<String, String>> setting = new ArrayList<>(entries.size());
+        for (SourceEntry e : entries) {
+            setting.add(serialize(e));
+        }
+        return setting;
+    }
+
+    /**
+     * Returns the set of active source URLs.
+     * @return The set of active source URLs.
+     */
+    public final Set<String> getActiveUrls() {
+        Set<String> urls = new LinkedHashSet<>(); // retain order
+        for (SourceEntry e : get()) {
+            if (e.active) {
+                urls.add(e.url);
+            }
+        }
+        return urls;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/preferences/sources/SourceProvider.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/sources/SourceProvider.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/data/preferences/sources/SourceProvider.java	(revision 12649)
@@ -0,0 +1,20 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences.sources;
+
+import java.util.Collection;
+
+/**
+ * Interface for a class that offers a list of {@link SourceEntry}s.
+ *
+ * Used by plugins to offer additional SourceEntrys to the user.
+ * @since 12649 (moved from gui.preferences package)
+ */
+@FunctionalInterface
+public interface SourceProvider {
+
+    /**
+     * Get the collection of {@link SourceEntry}s.
+     * @return the collection of {@link SourceEntry}s
+     */
+    Collection<SourceEntry> getSources();
+}
Index: trunk/src/org/openstreetmap/josm/data/preferences/sources/SourceType.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/sources/SourceType.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/data/preferences/sources/SourceType.java	(revision 12649)
@@ -0,0 +1,16 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences.sources;
+
+/**
+ * The different types of source entries.
+ * @since 12649 (moved from gui.preferences package)
+ * @since 6670
+ */
+public enum SourceType {
+    /** Entry for a map paint style **/
+    MAP_PAINT_STYLE,
+    /** Entry for a tagging preset **/
+    TAGGING_PRESET,
+    /** Entry for a validator tag checker rule **/
+    TAGCHECKER_RULE
+}
Index: trunk/src/org/openstreetmap/josm/data/preferences/sources/ValidatorPrefHelper.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/sources/ValidatorPrefHelper.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/data/preferences/sources/ValidatorPrefHelper.java	(revision 12649)
@@ -0,0 +1,102 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.preferences.sources;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.openstreetmap.josm.data.preferences.BooleanProperty;
+import org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker;
+
+/**
+ * Helper class for validator tag checker rules preferences.
+ * @since 12649 (extracted from gui.preferences package)
+ */
+public class ValidatorPrefHelper extends SourcePrefHelper {
+
+    /**
+     * The unique instance.
+     */
+    public static final ValidatorPrefHelper INSTANCE = new ValidatorPrefHelper();
+
+    /** The preferences prefix */
+    public static final String PREFIX = "validator";
+
+    /** The preferences key for error layer */
+    public static final BooleanProperty PREF_LAYER = new BooleanProperty(PREFIX + ".layer", true);
+
+    /** The preferences key for enabled tests */
+    public static final String PREF_SKIP_TESTS = PREFIX + ".skip";
+
+    /** The preferences key for enabled tests */
+    public static final BooleanProperty PREF_USE_IGNORE = new BooleanProperty(PREFIX + ".ignore", true);
+
+    /** The preferences key for enabled tests before upload*/
+    public static final String PREF_SKIP_TESTS_BEFORE_UPLOAD = PREFIX + ".skipBeforeUpload";
+
+    /** The preferences key for ignored severity other on upload */
+    public static final BooleanProperty PREF_OTHER_UPLOAD = new BooleanProperty(PREFIX + ".otherUpload", false);
+
+    /** The preferences for ignored severity other */
+    public static final BooleanProperty PREF_OTHER = new BooleanProperty(PREFIX + ".other", false);
+
+    /**
+     * The preferences key for enabling the permanent filtering
+     * of the displayed errors in the tree regarding the current selection
+     */
+    public static final String PREF_FILTER_BY_SELECTION = PREFIX + ".selectionFilter";
+
+    /**
+     * Constructs a new {@code PresetPrefHelper}.
+     */
+    public ValidatorPrefHelper() {
+        super(MapCSSTagChecker.ENTRIES_PREF_KEY);
+    }
+
+    @Override
+    public Collection<ExtendedSourceEntry> getDefault() {
+        List<ExtendedSourceEntry> def = new ArrayList<>();
+
+        // CHECKSTYLE.OFF: SingleSpaceSeparator
+        addDefault(def, "addresses",    tr("Addresses"),           tr("Checks for errors on addresses"));
+        addDefault(def, "combinations", tr("Tag combinations"),    tr("Checks for missing tag or suspicious combinations"));
+        addDefault(def, "deprecated",   tr("Deprecated features"), tr("Checks for deprecated features"));
+        addDefault(def, "geometry",     tr("Geometry"),            tr("Checks for geometry errors"));
+        addDefault(def, "highway",      tr("Highways"),            tr("Checks for errors on highways"));
+        addDefault(def, "multiple",     tr("Multiple values"),     tr("Checks for wrong multiple values"));
+        addDefault(def, "numeric",      tr("Numeric values"),      tr("Checks for wrong numeric values"));
+        addDefault(def, "religion",     tr("Religion"),            tr("Checks for errors on religious objects"));
+        addDefault(def, "relation",     tr("Relations"),           tr("Checks for errors on relations"));
+        addDefault(def, "territories",  tr("Territories"),         tr("Checks for territories-specific features"));
+        addDefault(def, "unnecessary",  tr("Unnecessary tags"),    tr("Checks for unnecessary tags"));
+        addDefault(def, "wikipedia",    tr("Wikipedia"),           tr("Checks for wrong wikipedia tags"));
+        // CHECKSTYLE.ON: SingleSpaceSeparator
+
+        return def;
+    }
+
+    private static void addDefault(List<ExtendedSourceEntry> defaults, String filename, String title, String description) {
+        ExtendedSourceEntry i = new ExtendedSourceEntry(filename+".mapcss", "resource://data/validator/"+filename+".mapcss");
+        i.title = title;
+        i.description = description;
+        defaults.add(i);
+    }
+
+    @Override
+    public Map<String, String> serialize(SourceEntry entry) {
+        Map<String, String> res = new HashMap<>();
+        res.put("url", entry.url);
+        res.put("title", entry.title == null ? "" : entry.title);
+        res.put("active", Boolean.toString(entry.active));
+        return res;
+    }
+
+    @Override
+    public SourceEntry deserialize(Map<String, String> s) {
+        return new SourceEntry(s.get("url"), null, s.get("title"), Boolean.parseBoolean(s.get("active")));
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/preferences/sources/package-info.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/sources/package-info.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/data/preferences/sources/package-info.java	(revision 12649)
@@ -0,0 +1,11 @@
+// License: GPL. For details, see LICENSE file.
+
+/**
+ * Provide classes to manage source of JOSM extensions that can be chosen in user preferences:
+ * <ul>
+ * <li>map paint styles</li>
+ * <li>tagging presets</li>
+ * <li>validator rules</li>
+ * </ul>
+ */
+package org.openstreetmap.josm.data.preferences.sources;
Index: trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java	(revision 12649)
@@ -26,4 +26,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
 import org.openstreetmap.josm.data.validation.tests.Addresses;
 import org.openstreetmap.josm.data.validation.tests.ApiCapabilitiesTest;
@@ -61,5 +62,4 @@
 import org.openstreetmap.josm.gui.layer.ValidatorLayer;
 import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
-import org.openstreetmap.josm.gui.preferences.validator.ValidatorPreference;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Utils;
@@ -185,5 +185,5 @@
     private static void loadIgnoredErrors() {
         ignoredErrors.clear();
-        if (ValidatorPreference.PREF_USE_IGNORE.get()) {
+        if (ValidatorPrefHelper.PREF_USE_IGNORE.get()) {
             Path path = Paths.get(getValidatorDir()).resolve("ignorederrors");
             if (path.toFile().exists()) {
@@ -235,5 +235,5 @@
      */
     public static synchronized void initializeErrorLayer() {
-        if (!ValidatorPreference.PREF_LAYER.get())
+        if (!ValidatorPrefHelper.PREF_LAYER.get())
             return;
         if (errorLayer == null) {
@@ -278,5 +278,5 @@
     private static void applyPrefs(Map<String, Test> tests, boolean beforeUpload) {
         for (String testName : Main.pref.getCollection(beforeUpload
-        ? ValidatorPreference.PREF_SKIP_TESTS_BEFORE_UPLOAD : ValidatorPreference.PREF_SKIP_TESTS)) {
+        ? ValidatorPrefHelper.PREF_SKIP_TESTS_BEFORE_UPLOAD : ValidatorPrefHelper.PREF_SKIP_TESTS)) {
             Test test = tests.get(testName);
             if (test != null) {
Index: trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 12649)
@@ -40,4 +40,6 @@
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.data.preferences.sources.SourceEntry;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
 import org.openstreetmap.josm.data.validation.Severity;
 import org.openstreetmap.josm.data.validation.Test;
@@ -58,7 +60,4 @@
 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser;
 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.ParseException;
-import org.openstreetmap.josm.gui.preferences.SourceEntry;
-import org.openstreetmap.josm.gui.preferences.validator.ValidatorPreference;
-import org.openstreetmap.josm.gui.preferences.validator.ValidatorTagCheckerRulesPreference;
 import org.openstreetmap.josm.io.CachedFile;
 import org.openstreetmap.josm.io.IllegalDataException;
@@ -714,5 +713,5 @@
     @Override
     public void check(OsmPrimitive p) {
-        errors.addAll(getErrorsForPrimitive(p, ValidatorPreference.PREF_OTHER.get()));
+        errors.addAll(getErrorsForPrimitive(p, ValidatorPrefHelper.PREF_OTHER.get()));
     }
 
@@ -748,5 +747,5 @@
     public synchronized void initialize() throws Exception {
         checks.clear();
-        for (SourceEntry source : new ValidatorTagCheckerRulesPreference.RulePrefHelper().get()) {
+        for (SourceEntry source : new ValidatorPrefHelper().get()) {
             if (!source.active) {
                 continue;
Index: trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(revision 12649)
@@ -36,9 +36,9 @@
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
 import org.openstreetmap.josm.data.validation.Severity;
 import org.openstreetmap.josm.data.validation.Test.TagTest;
 import org.openstreetmap.josm.data.validation.TestError;
 import org.openstreetmap.josm.data.validation.util.Entities;
-import org.openstreetmap.josm.gui.preferences.validator.ValidatorPreference;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPreset;
@@ -80,5 +80,5 @@
 
     /** The preferences prefix */
-    protected static final String PREFIX = ValidatorPreference.PREFIX + "." + TagChecker.class.getSimpleName();
+    protected static final String PREFIX = ValidatorPrefHelper.PREFIX + "." + TagChecker.class.getSimpleName();
 
     /**
@@ -293,5 +293,5 @@
             }
             // TODO directionKeys are no longer in OsmPrimitive (search pattern is used instead)
-            for (String a : Main.pref.getCollection(ValidatorPreference.PREFIX + ".knownkeys",
+            for (String a : Main.pref.getCollection(ValidatorPrefHelper.PREFIX + ".knownkeys",
                     Arrays.asList("is_in", "int_ref", "fixme", "population"))) {
                 additionalPresetsValueData.putVoid(a);
Index: trunk/src/org/openstreetmap/josm/data/validation/tests/UnconnectedWays.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/tests/UnconnectedWays.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/data/validation/tests/UnconnectedWays.java	(revision 12649)
@@ -27,4 +27,5 @@
 import org.openstreetmap.josm.data.osm.QuadBuckets;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
 import org.openstreetmap.josm.data.projection.Ellipsoid;
 import org.openstreetmap.josm.data.validation.Severity;
@@ -32,5 +33,4 @@
 import org.openstreetmap.josm.data.validation.TestError;
 import org.openstreetmap.josm.gui.MainApplication;
-import org.openstreetmap.josm.gui.preferences.validator.ValidatorPreference;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.tools.Logging;
@@ -138,5 +138,5 @@
 
     protected static final int UNCONNECTED_WAYS = 1301;
-    protected static final String PREFIX = ValidatorPreference.PREFIX + "." + UnconnectedWays.class.getSimpleName();
+    protected static final String PREFIX = ValidatorPrefHelper.PREFIX + "." + UnconnectedWays.class.getSimpleName();
 
     private Set<MyWaySegment> ways;
Index: trunk/src/org/openstreetmap/josm/gui/bugreport/BugReportDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/bugreport/BugReportDialog.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/gui/bugreport/BugReportDialog.java	(revision 12649)
@@ -0,0 +1,270 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.bugreport;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.Frame;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.UIManager;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.ExpertToggleAction;
+import org.openstreetmap.josm.gui.preferences.plugin.PluginPreference;
+import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
+import org.openstreetmap.josm.gui.widgets.UrlLabel;
+import org.openstreetmap.josm.plugins.PluginDownloadTask;
+import org.openstreetmap.josm.plugins.PluginHandler;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.InputMapUtils;
+import org.openstreetmap.josm.tools.bugreport.BugReport;
+import org.openstreetmap.josm.tools.bugreport.BugReportQueue.SuppressionMode;
+import org.openstreetmap.josm.tools.bugreport.BugReportSender;
+import org.openstreetmap.josm.tools.bugreport.ReportedException;
+
+/**
+ * This is a dialog that can be used to display a bug report.
+ * <p>
+ * It displays the bug to the user and asks the user to submit a bug report.
+ * @author Michael Zangl
+ * @since 10649
+ */
+public class BugReportDialog extends JDialog {
+    private static final int MAX_MESSAGE_SIZE = 500;
+    // This is explicitly not an ExtendedDialog - we still want to be able to display bug reports if there are problems with preferences/..
+    private final JPanel content = new JPanel(new GridBagLayout());
+    private final BugReport report;
+    private final DebugTextDisplay textPanel;
+    private JCheckBox cbSuppressSingle;
+    private JCheckBox cbSuppressAll;
+
+    /**
+     * Create a new dialog.
+     * @param report The report to display the dialog for.
+     */
+    public BugReportDialog(BugReport report) {
+        super(findParent(), tr("You have encountered a bug in JOSM"));
+        this.report = report;
+        textPanel = new DebugTextDisplay(report);
+        setContentPane(content);
+
+        addMessageSection();
+
+        addUpToDateSection();
+        // TODO: Notify user about plugin updates, then remove that notification that is displayed before this dialog is displayed.
+
+        addCreateTicketSection();
+
+        if (ExpertToggleAction.isExpert()) {
+            addDebugTextSection();
+        }
+
+        addIgnoreButton();
+
+        pack();
+        setModal(true);
+        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+
+        InputMapUtils.addEscapeAction(getRootPane(), new AbstractAction() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                closeDialog();
+            }
+        });
+    }
+
+    /**
+     * The message informing the user what happened.
+     */
+    private void addMessageSection() {
+        String message = tr(
+                "An unexpected exception occurred.\n" + "This is always a coding error. If you are running the latest "
+                        + "version of JOSM, please consider being kind and file a bug report.");
+        Icon icon = UIManager.getIcon("OptionPane.errorIcon");
+
+        JPanel panel = new JPanel(new GridBagLayout());
+
+        panel.add(new JLabel(icon), GBC.std().insets(0, 0, 10, 0));
+        JMultilineLabel messageLabel = new JMultilineLabel(message);
+        messageLabel.setMaxWidth(MAX_MESSAGE_SIZE);
+        panel.add(messageLabel, GBC.eol().fill());
+        content.add(panel, GBC.eop().fill(GBC.HORIZONTAL).insets(20, 10, 10, 10));
+    }
+
+    private void addDebugTextSection() {
+        JPanel panel = new JPanel(new GridBagLayout());
+        addBorder(panel, tr("Debug information"));
+        panel.add(textPanel, GBC.eop().fill());
+
+        panel.add(new JLabel(tr("Manually report at:")+' '), GBC.std());
+        panel.add(new UrlLabel(Main.getJOSMWebsite() + "/newticket"), GBC.std().fill(GBC.HORIZONTAL));
+        JButton copy = new JButton("Copy to clipboard");
+        copy.addActionListener(e -> textPanel.copyToClipboard());
+        panel.add(copy, GBC.eol().anchor(GBC.EAST));
+        content.add(panel, GBC.eop().fill());
+    }
+
+    private void addUpToDateSection() {
+        JPanel panel = new JosmUpdatePanel();
+        addBorder(panel, tr("Is JOSM up to date?"));
+        content.add(panel, GBC.eop().fill(GBC.HORIZONTAL));
+    }
+
+    private void addCreateTicketSection() {
+        JPanel panel = new JPanel(new GridBagLayout());
+        addBorder(panel, tr("Send bug report"));
+
+        JMultilineLabel helpText = new JMultilineLabel(
+                tr("If you are running the latest version of JOSM and the plugins, "
+                        + "please file a bug report in our bugtracker.\n"
+                        + "There the error information should already be "
+                        + "filled in for you. Please include information on how to reproduce "
+                        + "the error and try to supply as much detail as possible."));
+        helpText.setMaxWidth(MAX_MESSAGE_SIZE);
+        panel.add(helpText, GBC.eop().fill(GridBagConstraints.HORIZONTAL));
+
+        Component settings = GBC.glue(0, 0);
+        if (ExpertToggleAction.isExpert()) {
+            // The default settings should be fine in most situations.
+            settings = new BugReportSettingsPanel(report);
+        }
+        panel.add(settings);
+
+        JButton sendBugReportButton = new JButton(tr("Report Bug"), ImageProvider.get("bug"));
+        sendBugReportButton.addActionListener(e -> sendBug());
+        panel.add(sendBugReportButton, GBC.eol().insets(0, 0, 0, 0).anchor(GBC.SOUTHEAST));
+        content.add(panel, GBC.eop().fill(GBC.HORIZONTAL));
+    }
+
+    private static void addBorder(JPanel panel, String title) {
+        panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(title), BorderFactory
+                .createEmptyBorder(5, 5, 5, 5)));
+    }
+
+    private void addIgnoreButton() {
+        JPanel panel = new JPanel(new GridBagLayout());
+        cbSuppressSingle = new JCheckBox(tr("Suppress this error for this session."));
+        cbSuppressSingle.setVisible(false);
+        panel.add(cbSuppressSingle, GBC.std(0, 0).fill(GBC.HORIZONTAL));
+        cbSuppressAll = new JCheckBox(tr("Suppress further error dialogs for this session."));
+        cbSuppressAll.setVisible(false);
+        panel.add(cbSuppressAll, GBC.std(0, 1).fill(GBC.HORIZONTAL));
+        JButton ignore = new JButton(tr("Ignore this error."));
+        ignore.addActionListener(e -> closeDialog());
+        panel.add(ignore, GBC.std(1, 0).span(1, 2).anchor(GBC.CENTER));
+        content.add(panel, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 10, 10));
+    }
+
+    /**
+     * Shows or hides the suppress errors button
+     * @param showSuppress <code>true</code> to show the suppress errors checkbox.
+     */
+    public void setShowSuppress(boolean showSuppress) {
+        cbSuppressSingle.setVisible(showSuppress);
+        pack();
+    }
+
+    /**
+     * Shows or hides the suppress all errors button
+     * @param showSuppress <code>true</code> to show the suppress errors checkbox.
+     * @since 10819
+     */
+    public void setShowSuppressAll(boolean showSuppress) {
+        cbSuppressAll.setVisible(showSuppress);
+        pack();
+    }
+
+    /**
+     * Check if the checkbox to suppress further errors was selected
+     * @return <code>true</code> if the user wishes to suppress errors.
+     */
+    public SuppressionMode shouldSuppressFurtherErrors() {
+        if (cbSuppressAll.isSelected()) {
+            return SuppressionMode.ALL;
+        } else if (cbSuppressSingle.isSelected()) {
+            return SuppressionMode.SAME;
+        } else {
+            return SuppressionMode.NONE;
+        }
+    }
+
+    private void closeDialog() {
+        setVisible(false);
+    }
+
+    private void sendBug() {
+        BugReportSender.reportBug(textPanel.getCodeText());
+    }
+
+    /**
+     * A safe way to find a matching parent frame.
+     * @return The parent frame.
+     */
+    private static Frame findParent() {
+        Component current = Main.parent;
+        try {
+            // avoid cycles/invalid hirarchies
+            for (int i = 0; i < 20 && current != null; i++) {
+                if (current instanceof Frame) {
+                    return (Frame) current;
+                }
+                current = current.getParent();
+            }
+        } catch (RuntimeException e) { // NOPMD
+            BugReport.intercept(e).put("current", current).warn();
+        }
+        return null;
+    }
+
+    /**
+     * Show the bug report for a given exception
+     * @param e The exception to display
+     * @param exceptionCounter A counter of how many exceptions have already been worked on
+     * @return The new suppression status
+     * @since 10819
+     */
+    public static SuppressionMode showFor(ReportedException e, int exceptionCounter) {
+        if (e.isOutOfMemory()) {
+            // do not translate the string, as translation may raise an exception
+            JOptionPane.showMessageDialog(Main.parent, "JOSM is out of memory. " +
+                    "Strange things may happen.\nPlease restart JOSM with the -Xmx###M option,\n" +
+                    "where ### is the number of MB assigned to JOSM (e.g. 256).\n" +
+                    "Currently, " + Runtime.getRuntime().maxMemory()/1024/1024 + " MB are available to JOSM.",
+                    "Error",
+                    JOptionPane.ERROR_MESSAGE
+                    );
+            return SuppressionMode.NONE;
+        } else {
+            return GuiHelper.runInEDTAndWaitAndReturn(() -> {
+                PluginDownloadTask downloadTask = PluginHandler.updateOrdisablePluginAfterException(e);
+                if (downloadTask != null) {
+                    // Ask for restart to install new plugin
+                    PluginPreference.notifyDownloadResults(
+                            Main.parent, downloadTask, !downloadTask.getDownloadedPlugins().isEmpty());
+                    return SuppressionMode.NONE;
+                }
+
+                BugReport report = new BugReport(e);
+                BugReportDialog dialog = new BugReportDialog(report);
+                dialog.setShowSuppress(exceptionCounter > 0);
+                dialog.setShowSuppressAll(exceptionCounter > 1);
+                dialog.setVisible(true);
+                return dialog.shouldSuppressFurtherErrors();
+            });
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/bugreport/BugReportSettingsPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/bugreport/BugReportSettingsPanel.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/gui/bugreport/BugReportSettingsPanel.java	(revision 12649)
@@ -0,0 +1,40 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.bugreport;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import javax.swing.BoxLayout;
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+
+import org.openstreetmap.josm.tools.bugreport.BugReport;
+
+/**
+ * This panel displays the settings that can be changed before submitting a bug report to the web page.
+ * @author Michael Zangl
+ * @since 10585
+ */
+public class BugReportSettingsPanel extends JPanel {
+    /**
+     * Creates the new settings panel.
+     * @param report The report this panel should influence.
+     */
+    public BugReportSettingsPanel(BugReport report) {
+        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+
+        JCheckBox statusReport = new JCheckBox(tr("Include the system status report."));
+        statusReport.setSelected(report.isIncludeStatusReport());
+        statusReport.addChangeListener(e -> report.setIncludeStatusReport(statusReport.isSelected()));
+        add(statusReport);
+
+        JCheckBox data = new JCheckBox(tr("Include information about the data you were working on."));
+        data.setSelected(report.isIncludeData());
+        data.addChangeListener(e -> report.setIncludeData(data.isSelected()));
+        add(data);
+
+        JCheckBox allStackTraces = new JCheckBox(tr("Include all stack traces."));
+        allStackTraces.setSelected(report.isIncludeAllStackTraces());
+        allStackTraces.addChangeListener(e -> report.setIncludeAllStackTraces(allStackTraces.isSelected()));
+        add(allStackTraces);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/bugreport/DebugTextDisplay.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/bugreport/DebugTextDisplay.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/gui/bugreport/DebugTextDisplay.java	(revision 12649)
@@ -0,0 +1,82 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.bugreport;
+
+import java.awt.Dimension;
+
+import javax.swing.JScrollPane;
+
+import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
+import org.openstreetmap.josm.gui.widgets.JosmTextArea;
+import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.bugreport.BugReport;
+
+/**
+ * This is a text area that displays the debug text with scroll bars.
+ * @author Michael Zangl
+ * @since 10055
+ */
+public class DebugTextDisplay extends JScrollPane {
+    private static final String CODE_PATTERN = "{{{%n%s%n}}}";
+    private String text;
+    private JosmTextArea textArea;
+
+    /**
+     * Creates a new text area.
+     * @since 10585
+     */
+    private DebugTextDisplay() {
+        textArea = new JosmTextArea();
+        textArea.setCaretPosition(0);
+        textArea.setEditable(false);
+        setViewportView(textArea);
+        setPreferredSize(new Dimension(600, 270));
+    }
+
+    /**
+     * Creates a new text area with an inital text to display
+     * @param textToDisplay The text to display.
+     */
+    public DebugTextDisplay(String textToDisplay) {
+        this();
+        setCodeText(textToDisplay);
+    }
+
+    /**
+     * Creates a new text area that displays the bug report data
+     * @param report The bug report data to display.
+     * @since 10585
+     */
+    public DebugTextDisplay(BugReport report) {
+        this();
+        setCodeText(report.getReportText());
+        report.addChangeListener(e -> setCodeText(report.getReportText()));
+    }
+
+    /**
+     * Sets the text that should be displayed in this view.
+     * @param textToDisplay The text
+     */
+    private void setCodeText(String textToDisplay) {
+        text = Utils.strip(textToDisplay).replaceAll("\r", "");
+        textArea.setText(String.format(CODE_PATTERN, text));
+        textArea.setCaretPosition(0);
+    }
+
+    /**
+     * Copies the debug text to the clipboard. This includes the code tags for trac.
+     * @return <code>true</code> if copy was successful
+     * @since 11102 (typo)
+     */
+    public boolean copyToClipboard() {
+        return ClipboardUtils.copyString(String.format(CODE_PATTERN, text));
+    }
+
+    /**
+     * Gets the text this are displays, without the code tag.
+     * @return The stripped text set by {@link #setCodeText(String)}
+     * @since 10585
+     */
+    public String getCodeText() {
+        return text;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/bugreport/JosmUpdatePanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/bugreport/JosmUpdatePanel.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/gui/bugreport/JosmUpdatePanel.java	(revision 12649)
@@ -0,0 +1,104 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.bugreport;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.io.IOException;
+
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Version;
+import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
+import org.openstreetmap.josm.gui.widgets.UrlLabel;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.WikiReader;
+
+/**
+ * This is a panel that displays the current JOSM version and the ability to update JOSM.
+ * @author Michael Zangl
+ * @since 10649
+ */
+public class JosmUpdatePanel extends JPanel {
+    private final JMultilineLabel testedVersionField;
+    private final int josmVersion;
+
+    /**
+     * Create a new {@link JosmUpdatePanel}
+     */
+    public JosmUpdatePanel() {
+        super(new GridBagLayout());
+        josmVersion = Version.getInstance().getVersion();
+
+        add(new JMultilineLabel(tr("Your current version of JOSM is {0}", josmVersion)), GBC.eol().fill(GBC.HORIZONTAL));
+        testedVersionField = new JMultilineLabel(tr("JOSM is searching for updates..."));
+        add(testedVersionField, GBC.eol().fill(GBC.HORIZONTAL));
+
+        checkCurrentVersion();
+    }
+
+    private void checkCurrentVersion() {
+        new Thread(this::readCurrentVersion, "JOSM version checker").start();
+    }
+
+    private void readCurrentVersion() {
+        int testedVersion = getTestedVersion();
+
+        if (testedVersion < 0) {
+            SwingUtilities.invokeLater(this::displayError);
+        } else if (josmVersion < testedVersion) {
+            SwingUtilities.invokeLater(() -> displayOutOfDate(testedVersion));
+        } else {
+            SwingUtilities.invokeLater(this::displayUpToDate);
+        }
+    }
+
+    private static int getTestedVersion() {
+        try {
+            String testedString = new WikiReader().read(Main.getJOSMWebsite() + "/wiki/TestedVersion?format=txt");
+            return Integer.parseInt(testedString.trim());
+        } catch (NumberFormatException | IOException e) {
+            Logging.log(Logging.LEVEL_WARN, "Unable to detect latest version of JOSM:", e);
+            return -1;
+        }
+    }
+
+    /**
+     * Display that there was an error while checking the current version.
+     */
+    private void displayError() {
+        testedVersionField.setText(tr("An error occured while checking if your JOSM instance is up to date."));
+        showUpdateButton();
+    }
+
+    private void displayUpToDate() {
+        testedVersionField.setText(tr("JOSM is up to date."));
+    }
+
+    private void displayOutOfDate(int testedVersion) {
+        testedVersionField
+                .setText(tr("JOSM is out of date. The current version is {0}. Try updating JOSM.", testedVersion));
+        showUpdateButton();
+    }
+
+    private void showUpdateButton() {
+        add(new JMultilineLabel(tr("Before you file a bug report make sure you have updated to the latest version of JOSM here:")), GBC.eol());
+        add(new UrlLabel(Main.getJOSMWebsite(), 2), GBC.eop().insets(8, 0, 0, 0));
+        JButton updateButton = new JButton(tr("Update JOSM"), ImageProvider.get("download"));
+        updateButton.addActionListener(e -> openJosmUpdateSite());
+        add(updateButton, GBC.eol().anchor(GBC.EAST));
+    }
+
+    private static void openJosmUpdateSite() {
+        try {
+            Main.platform.openUrl(Main.getJOSMWebsite());
+        } catch (IOException ex) {
+            Logging.log(Logging.LEVEL_WARN, "Unable to access JOSM website:", ex);
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/bugreport/package-info.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/bugreport/package-info.java	(revision 12649)
+++ trunk/src/org/openstreetmap/josm/gui/bugreport/package-info.java	(revision 12649)
@@ -0,0 +1,6 @@
+// License: GPL. For details, see LICENSE file.
+
+/**
+ * Provides GUI classes for the bug report system, allowing users to create tickets on issue tracker directly from JOSM.
+ */
+package org.openstreetmap.josm.gui.bugreport;
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/MapPaintDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/MapPaintDialog.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/MapPaintDialog.java	(revision 12649)
@@ -56,4 +56,5 @@
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.actions.PreferencesAction;
+import org.openstreetmap.josm.data.preferences.sources.SourceEntry;
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.MainApplication;
@@ -65,5 +66,4 @@
 import org.openstreetmap.josm.gui.mappaint.StyleSource;
 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
-import org.openstreetmap.josm.gui.preferences.SourceEntry;
 import org.openstreetmap.josm.gui.preferences.map.MapPaintPreference;
 import org.openstreetmap.josm.gui.util.FileFilterAllFiles;
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/ValidatorDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/ValidatorDialog.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/ValidatorDialog.java	(revision 12649)
@@ -40,4 +40,5 @@
 import org.openstreetmap.josm.data.osm.WaySegment;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
 import org.openstreetmap.josm.data.validation.OsmValidator;
 import org.openstreetmap.josm.data.validation.TestError;
@@ -157,5 +158,5 @@
         buttons.add(fixButton);
 
-        if (ValidatorPreference.PREF_USE_IGNORE.get()) {
+        if (ValidatorPrefHelper.PREF_USE_IGNORE.get()) {
             ignoreButton = new SideButton(new AbstractAction() {
                 {
@@ -572,5 +573,5 @@
      */
     public void updateSelection(Collection<? extends OsmPrimitive> newSelection) {
-        if (!Main.pref.getBoolean(ValidatorPreference.PREF_FILTER_BY_SELECTION, false))
+        if (!Main.pref.getBoolean(ValidatorPrefHelper.PREF_FILTER_BY_SELECTION, false))
             return;
         if (newSelection.isEmpty()) {
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/validator/ValidatorTreePanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/validator/ValidatorTreePanel.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/validator/ValidatorTreePanel.java	(revision 12649)
@@ -39,9 +39,9 @@
 import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
 import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
 import org.openstreetmap.josm.data.validation.Severity;
 import org.openstreetmap.josm.data.validation.TestError;
 import org.openstreetmap.josm.data.validation.util.MultipleNameVisitor;
 import org.openstreetmap.josm.gui.MainApplication;
-import org.openstreetmap.josm.gui.preferences.validator.ValidatorPreference;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.tools.AlphanumComparator;
@@ -184,5 +184,5 @@
 
         Predicate<TestError> filterToUse = e -> !e.isIgnored();
-        if (!ValidatorPreference.PREF_OTHER.get()) {
+        if (!ValidatorPrefHelper.PREF_OTHER.get()) {
             filterToUse = filterToUse.and(e -> e.getSeverity() != Severity.OTHER);
         }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 12649)
@@ -22,4 +22,6 @@
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.data.preferences.sources.MapPaintPrefHelper;
+import org.openstreetmap.josm.data.preferences.sources.SourceEntry;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
@@ -30,6 +32,4 @@
 import org.openstreetmap.josm.gui.mappaint.styleelement.NodeElement;
 import org.openstreetmap.josm.gui.mappaint.styleelement.StyleElement;
-import org.openstreetmap.josm.gui.preferences.SourceEntry;
-import org.openstreetmap.josm.gui.preferences.map.MapPaintPreference.MapPaintPrefHelper;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.io.CachedFile;
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/StyleSource.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/StyleSource.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/StyleSource.java	(revision 12649)
@@ -21,6 +21,6 @@
 
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.preferences.sources.SourceEntry;
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference;
-import org.openstreetmap.josm.gui.preferences.SourceEntry;
 import org.openstreetmap.josm.io.CachedFile;
 import org.openstreetmap.josm.tools.ImageOverlay;
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 12649)
@@ -32,4 +32,5 @@
 import org.openstreetmap.josm.data.osm.AbstractPrimitive;
 import org.openstreetmap.josm.data.osm.AbstractPrimitive.KeyValueVisitor;
+import org.openstreetmap.josm.data.preferences.sources.SourceEntry;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -56,5 +57,4 @@
 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.TokenMgrError;
 import org.openstreetmap.josm.gui.mappaint.styleelement.LineElement;
-import org.openstreetmap.josm.gui.preferences.SourceEntry;
 import org.openstreetmap.josm.io.CachedFile;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
Index: trunk/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java	(revision 12649)
@@ -30,9 +30,7 @@
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.regex.Matcher;
@@ -77,4 +75,9 @@
 import org.openstreetmap.josm.actions.ExtensionFileFilter;
 import org.openstreetmap.josm.data.Version;
+import org.openstreetmap.josm.data.preferences.sources.ExtendedSourceEntry;
+import org.openstreetmap.josm.data.preferences.sources.SourceEntry;
+import org.openstreetmap.josm.data.preferences.sources.SourcePrefHelper;
+import org.openstreetmap.josm.data.preferences.sources.SourceProvider;
+import org.openstreetmap.josm.data.preferences.sources.SourceType;
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.HelpAwareOptionPane;
@@ -787,89 +790,4 @@
             }
             selectionModel.setValueIsAdjusting(false);
-        }
-    }
-
-    /**
-     * Source entry with additional metadata.
-     */
-    public static class ExtendedSourceEntry extends SourceEntry implements Comparable<ExtendedSourceEntry> {
-        /** file name used for display */
-        public String simpleFileName;
-        /** version used for display */
-        public String version;
-        /** author name used for display */
-        public String author;
-        /** webpage link used for display */
-        public String link;
-        /** short description used for display */
-        public String description;
-        /** Style type: can only have one value: "xml". Used to filter out old XML styles. For MapCSS styles, the value is not set. */
-        public String styleType;
-        /** minimum JOSM version required to enable this source entry */
-        public Integer minJosmVersion;
-
-        /**
-         * Constructs a new {@code ExtendedSourceEntry}.
-         * @param simpleFileName file name used for display
-         * @param url URL that {@link org.openstreetmap.josm.io.CachedFile} understands
-         */
-        public ExtendedSourceEntry(String simpleFileName, String url) {
-            super(url, null, null, true);
-            this.simpleFileName = simpleFileName;
-        }
-
-        /**
-         * @return string representation for GUI list or menu entry
-         */
-        public String getDisplayName() {
-            return title == null ? simpleFileName : title;
-        }
-
-        private static void appendRow(StringBuilder s, String th, String td) {
-            s.append("<tr><th>").append(th).append("</th><td>").append(Utils.escapeReservedCharactersHTML(td)).append("</td</tr>");
-        }
-
-        /**
-         * Returns a tooltip containing available metadata.
-         * @return a tooltip containing available metadata
-         */
-        public String getTooltip() {
-            StringBuilder s = new StringBuilder();
-            appendRow(s, tr("Short Description:"), getDisplayName());
-            appendRow(s, tr("URL:"), url);
-            if (author != null) {
-                appendRow(s, tr("Author:"), author);
-            }
-            if (link != null) {
-                appendRow(s, tr("Webpage:"), link);
-            }
-            if (description != null) {
-                appendRow(s, tr("Description:"), description);
-            }
-            if (version != null) {
-                appendRow(s, tr("Version:"), version);
-            }
-            if (minJosmVersion != null) {
-                appendRow(s, tr("Minimum JOSM Version:"), Integer.toString(minJosmVersion));
-            }
-            return "<html><style>th{text-align:right}td{width:400px}</style>"
-                    + "<table>" + s + "</table></html>";
-        }
-
-        @Override
-        public String toString() {
-            return "<html><b>" + getDisplayName() + "</b>"
-                    + (author == null ? "" : " <span color=\"gray\">" + tr("by {0}", author) + "</color>")
-                    + "</html>";
-        }
-
-        @Override
-        public int compareTo(ExtendedSourceEntry o) {
-            if (url.startsWith("resource") && !o.url.startsWith("resource"))
-                return -1;
-            if (o.url.startsWith("resource"))
-                return 1;
-            else
-                return getDisplayName().compareToIgnoreCase(o.getDisplayName());
         }
     }
@@ -1766,98 +1684,4 @@
 
     /**
-     * Helper class for specialized extensions preferences.
-     */
-    public abstract static class SourcePrefHelper {
-
-        private final String pref;
-
-        /**
-         * Constructs a new {@code SourcePrefHelper} for the given preference key.
-         * @param pref The preference key
-         */
-        public SourcePrefHelper(String pref) {
-            this.pref = pref;
-        }
-
-        /**
-         * Returns the default sources provided by JOSM core.
-         * @return the default sources provided by JOSM core
-         */
-        public abstract Collection<ExtendedSourceEntry> getDefault();
-
-        /**
-         * Serializes the given source entry as a map.
-         * @param entry source entry to serialize
-         * @return map (key=value)
-         */
-        public abstract Map<String, String> serialize(SourceEntry entry);
-
-        /**
-         * Deserializes the given map as a source entry.
-         * @param entryStr map (key=value)
-         * @return source entry
-         */
-        public abstract SourceEntry deserialize(Map<String, String> entryStr);
-
-        /**
-         * Returns the list of sources.
-         * @return The list of sources
-         */
-        public List<SourceEntry> get() {
-
-            Collection<Map<String, String>> src = Main.pref.getListOfStructs(pref, (Collection<Map<String, String>>) null);
-            if (src == null)
-                return new ArrayList<>(getDefault());
-
-            List<SourceEntry> entries = new ArrayList<>();
-            for (Map<String, String> sourcePref : src) {
-                SourceEntry e = deserialize(new HashMap<>(sourcePref));
-                if (e != null) {
-                    entries.add(e);
-                }
-            }
-            return entries;
-        }
-
-        /**
-         * Saves a list of sources to JOSM preferences.
-         * @param entries list of sources
-         * @return {@code true}, if something has changed (i.e. value is different than before)
-         */
-        public boolean put(Collection<? extends SourceEntry> entries) {
-            Collection<Map<String, String>> setting = serializeList(entries);
-            boolean unset = Main.pref.getListOfStructs(pref, (Collection<Map<String, String>>) null) == null;
-            if (unset) {
-                Collection<Map<String, String>> def = serializeList(getDefault());
-                if (setting.equals(def))
-                    return false;
-            }
-            return Main.pref.putListOfStructs(pref, setting);
-        }
-
-        private Collection<Map<String, String>> serializeList(Collection<? extends SourceEntry> entries) {
-            Collection<Map<String, String>> setting = new ArrayList<>(entries.size());
-            for (SourceEntry e : entries) {
-                setting.add(serialize(e));
-            }
-            return setting;
-        }
-
-        /**
-         * Returns the set of active source URLs.
-         * @return The set of active source URLs.
-         */
-        public final Set<String> getActiveUrls() {
-            Set<String> urls = new LinkedHashSet<>(); // retain order
-            for (SourceEntry e : get()) {
-                if (e.active) {
-                    urls.add(e.url);
-                }
-            }
-            return urls;
-        }
-    }
-
-    /**
      * Defers loading of sources to the first time the adequate tab is selected.
      * @param tab The preferences tab
Index: trunk/src/org/openstreetmap/josm/gui/preferences/SourceEntry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/SourceEntry.java	(revision 12647)
+++ 	(revision )
@@ -1,205 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.preferences;
-
-import java.io.File;
-import java.util.Objects;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.Utils;
-
-/**
- * A source entry primarily used to save the user's selection of mappaint styles,
- * but also for preset sources or validator rules.
- * @since 3796
- */
-public class SourceEntry {
-
-    /**
-     *  A URL can be anything that CachedFile understands, i.e.
-     *  a local file, http://, or a file from the current jar
-     */
-    public String url;
-
-    /**
-     * Indicates, that {@link #url} is a zip file and the resource is
-     * inside the zip file.
-     */
-    public boolean isZip;
-
-    /**
-     * If {@link #isZip} is true, denotes the path inside the zip file.
-     */
-    public String zipEntryPath;
-
-    /**
-     *  Name is used as a namespace for color preferences and (currently) only
-     *  one file with a name can be loaded at a time. Additional styles must
-     *  either have the same name as the main style or no name at all.
-     *  If no name is provided, it will be set to the default value "standard".
-     *  The name can also be given in the xml file as attribute for the rules tag.
-     *  (This overrides the name given in the preferences, otherwise both
-     *  methods are equivalent.)
-     */
-    public String name;
-
-    /**
-     * A title that can be used as menu entry.
-     */
-    public String title;
-
-    /**
-     * active is a boolean flag that can be used to turn the source on or off at runtime.
-     */
-    public boolean active;
-
-    /**
-     * Constructs a new {@code SourceEntry}.
-     * @param url URL that {@link org.openstreetmap.josm.io.CachedFile} understands
-     * @param isZip if url is a zip file and the resource is inside the zip file
-     * @param zipEntryPath If {@code isZip} is {@code true}, denotes the path inside the zip file
-     * @param name Source name
-     * @param title title that can be used as menu entry
-     * @param active boolean flag that can be used to turn the source on or off at runtime
-     * @see #url
-     * @see #isZip
-     * @see #zipEntryPath
-     * @see #name
-     * @see #title
-     * @see #active
-     */
-    public SourceEntry(String url, boolean isZip, String zipEntryPath, String name, String title, boolean active) {
-        this.url = url;
-        this.isZip = isZip;
-        this.zipEntryPath = "".equals(zipEntryPath) ? null : zipEntryPath;
-        this.name = "".equals(name) ? null : name;
-        this.title = "".equals(title) ? null : title;
-        this.active = active;
-    }
-
-    /**
-     * Constructs a new {@code SourceEntry}.
-     * @param url URL that {@link org.openstreetmap.josm.io.CachedFile} understands
-     * @param name Source name
-     * @param title title that can be used as menu entry
-     * @param active boolean flag that can be used to turn the source on or off at runtime
-     * @see #url
-     * @see #name
-     * @see #title
-     * @see #active
-     */
-    public SourceEntry(String url, String name, String title, boolean active) {
-        this(url, false, null, name, title, active);
-    }
-
-    /**
-     * Constructs a new {@code SourceEntry}.
-     * @param e existing source entry to copy
-     */
-    public SourceEntry(SourceEntry e) {
-        this.url = e.url;
-        this.isZip = e.isZip;
-        this.zipEntryPath = e.zipEntryPath;
-        this.name = e.name;
-        this.title = e.title;
-        this.active = e.active;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (obj == null || getClass() != obj.getClass()) return false;
-        SourceEntry that = (SourceEntry) obj;
-        return isZip == that.isZip &&
-                active == that.active &&
-                Objects.equals(url, that.url) &&
-                Objects.equals(zipEntryPath, that.zipEntryPath) &&
-                Objects.equals(name, that.name) &&
-                Objects.equals(title, that.title);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(url, isZip, zipEntryPath, name, title, active);
-    }
-
-    @Override
-    public String toString() {
-        return title != null ? title : url;
-    }
-
-    /**
-     * String to show in menus and error messages.
-     * @return Usually the shortdescription, but can be the file name
-     * if no shortdescription is available.
-     */
-    public String getDisplayString() {
-        if (title != null)
-            return title;
-        else
-            return getFileNamePart();
-    }
-
-    /**
-     * Extracts file part from url, e.g.:
-     * <code>http://www.test.com/file.xml?format=text --&gt; file.xml</code>
-     * @return The filename part of the URL
-     */
-    public String getFileNamePart() {
-        Pattern p = Pattern.compile("([^/\\\\]*?)([?].*)?$");
-        Matcher m = p.matcher(url);
-        if (m.find()) {
-            return m.group(1);
-        } else {
-            Logging.warn("Unexpected URL format: "+url);
-            return url;
-        }
-    }
-
-    /**
-     * the name / identifier that should be used to save custom color values
-     * and similar stuff to the preference file
-     * @return the identifier; never null. Usually the result is "standard"
-     */
-    public String getPrefName() {
-        return name == null ? "standard" : name;
-    }
-
-    /**
-     * Determines if this source denotes a file on a local filesystem.
-     * @return {@code true} if the source is a local file
-     */
-    public boolean isLocal() {
-        return Utils.isLocalUrl(url);
-    }
-
-    /**
-     * Return the source directory, only for local files.
-     * @return The source directory, or {@code null} if this file isn't local, or does not have a parent
-     * @since 7276
-     */
-    public File getLocalSourceDir() {
-        if (!isLocal())
-            return null;
-        return new File(url).getParentFile();
-    }
-
-    /**
-     * Returns the parent directory of the resource inside the zip file.
-     *
-     * @return the parent directory of the resource inside the zip file,
-     * "." if zipEntryPath is a top level file; null, if zipEntryPath is null
-     */
-    public String getZipEntryDirName() {
-        if (zipEntryPath == null) return null;
-        File file = new File(zipEntryPath);
-        File dir = file.getParentFile();
-        if (dir == null) return ".";
-        String path = dir.getPath();
-        if (!"/".equals(File.separator)) {
-            path = path.replace(File.separator, "/");
-        }
-        return path;
-    }
-}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/SourceProvider.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/SourceProvider.java	(revision 12647)
+++ 	(revision )
@@ -1,19 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.preferences;
-
-import java.util.Collection;
-
-/**
- * Interface for a class that offers a list of {@link SourceEntry}s.
- *
- * Used by plugins to offer additional SourceEntrys to the user.
- */
-@FunctionalInterface
-public interface SourceProvider {
-
-    /**
-     * Get the collection of {@link SourceEntry}s.
-     * @return the collection of {@link SourceEntry}s
-     */
-    Collection<SourceEntry> getSources();
-}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/SourceType.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/SourceType.java	(revision 12647)
+++ 	(revision )
@@ -1,15 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.preferences;
-
-/**
- * The different types of source entries.
- * @since 6670
- */
-public enum SourceType {
-    /** Entry for a map paint style **/
-    MAP_PAINT_STYLE,
-    /** Entry for a tagging preset **/
-    TAGGING_PRESET,
-    /** Entry for a validator tag checker rule **/
-    TAGCHECKER_RULE
-}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/map/MapPaintPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/map/MapPaintPreference.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/map/MapPaintPreference.java	(revision 12649)
@@ -7,11 +7,6 @@
 import java.awt.GridBagLayout;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.TreeSet;
 
 import javax.swing.BorderFactory;
@@ -20,4 +15,9 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.preferences.sources.ExtendedSourceEntry;
+import org.openstreetmap.josm.data.preferences.sources.MapPaintPrefHelper;
+import org.openstreetmap.josm.data.preferences.sources.SourceEntry;
+import org.openstreetmap.josm.data.preferences.sources.SourceProvider;
+import org.openstreetmap.josm.data.preferences.sources.SourceType;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
@@ -27,13 +27,8 @@
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
 import org.openstreetmap.josm.gui.preferences.SourceEditor;
-import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
-import org.openstreetmap.josm.gui.preferences.SourceEntry;
-import org.openstreetmap.josm.gui.preferences.SourceProvider;
-import org.openstreetmap.josm.gui.preferences.SourceType;
 import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
 import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.Utils;
 
 /**
@@ -193,100 +188,4 @@
     }
 
-    /**
-     * Helper class for map paint styles preferences.
-     */
-    public static class MapPaintPrefHelper extends SourceEditor.SourcePrefHelper {
-
-        /**
-         * The unique instance.
-         */
-        public static final MapPaintPrefHelper INSTANCE = new MapPaintPrefHelper();
-
-        /**
-         * Constructs a new {@code MapPaintPrefHelper}.
-         */
-        public MapPaintPrefHelper() {
-            super("mappaint.style.entries");
-        }
-
-        @Override
-        public List<SourceEntry> get() {
-            List<SourceEntry> ls = super.get();
-            if (insertNewDefaults(ls)) {
-                put(ls);
-            }
-            return ls;
-        }
-
-        /**
-         * If the selection of default styles changes in future releases, add
-         * the new entries to the user-configured list. Remember the known URLs,
-         * so an item that was deleted explicitly is not added again.
-         * @param list new defaults
-         * @return {@code true} if a change occurred
-         */
-        private boolean insertNewDefaults(List<SourceEntry> list) {
-            boolean changed = false;
-
-            Collection<String> knownDefaults = new TreeSet<>(Main.pref.getCollection("mappaint.style.known-defaults"));
-
-            Collection<ExtendedSourceEntry> defaults = getDefault();
-            int insertionIdx = 0;
-            for (final SourceEntry def : defaults) {
-                int i = Utils.indexOf(list, se -> Objects.equals(def.url, se.url));
-                if (i == -1 && !knownDefaults.contains(def.url)) {
-                    def.active = false;
-                    list.add(insertionIdx, def);
-                    insertionIdx++;
-                    changed = true;
-                } else {
-                    if (i >= insertionIdx) {
-                        insertionIdx = i + 1;
-                    }
-                }
-                knownDefaults.add(def.url);
-            }
-            Main.pref.putCollection("mappaint.style.known-defaults", knownDefaults);
-
-            // XML style is not bundled anymore
-            list.remove(Utils.find(list, se -> "resource://styles/standard/elemstyles.xml".equals(se.url)));
-
-            return changed;
-        }
-
-        @Override
-        public Collection<ExtendedSourceEntry> getDefault() {
-            ExtendedSourceEntry defJosmMapcss = new ExtendedSourceEntry("elemstyles.mapcss", "resource://styles/standard/elemstyles.mapcss");
-            defJosmMapcss.active = true;
-            defJosmMapcss.name = "standard";
-            defJosmMapcss.title = tr("JOSM default (MapCSS)");
-            defJosmMapcss.description = tr("Internal style to be used as base for runtime switchable overlay styles");
-            ExtendedSourceEntry defPL2 = new ExtendedSourceEntry("potlatch2.mapcss", "resource://styles/standard/potlatch2.mapcss");
-            defPL2.active = false;
-            defPL2.name = "standard";
-            defPL2.title = tr("Potlatch 2");
-            defPL2.description = tr("the main Potlatch 2 style");
-
-            return Arrays.asList(defJosmMapcss, defPL2);
-        }
-
-        @Override
-        public Map<String, String> serialize(SourceEntry entry) {
-            Map<String, String> res = new HashMap<>();
-            res.put("url", entry.url == null ? "" : entry.url);
-            res.put("title", entry.title == null ? "" : entry.title);
-            res.put("active", Boolean.toString(entry.active));
-            if (entry.name != null) {
-                res.put("ptoken", entry.name);
-            }
-            return res;
-        }
-
-        @Override
-        public SourceEntry deserialize(Map<String, String> s) {
-            return new SourceEntry(s.get("url"), s.get("ptoken"), s.get("title"), Boolean.parseBoolean(s.get("active")));
-        }
-    }
-
     @Override
     public boolean isExpert() {
Index: trunk/src/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreference.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreference.java	(revision 12649)
@@ -9,8 +9,5 @@
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import javax.swing.BorderFactory;
@@ -21,4 +18,9 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.preferences.sources.ExtendedSourceEntry;
+import org.openstreetmap.josm.data.preferences.sources.PresetPrefHelper;
+import org.openstreetmap.josm.data.preferences.sources.SourceEntry;
+import org.openstreetmap.josm.data.preferences.sources.SourceProvider;
+import org.openstreetmap.josm.data.preferences.sources.SourceType;
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
@@ -27,8 +29,4 @@
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.ValidationListener;
 import org.openstreetmap.josm.gui.preferences.SourceEditor;
-import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
-import org.openstreetmap.josm.gui.preferences.SourceEntry;
-import org.openstreetmap.josm.gui.preferences.SourceProvider;
-import org.openstreetmap.josm.gui.preferences.SourceType;
 import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
 import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
@@ -254,43 +252,4 @@
     }
 
-    /**
-     * Helper class for tagging presets preferences.
-     */
-    public static class PresetPrefHelper extends SourceEditor.SourcePrefHelper {
-
-        /**
-         * The unique instance.
-         */
-        public static final PresetPrefHelper INSTANCE = new PresetPrefHelper();
-
-        /**
-         * Constructs a new {@code PresetPrefHelper}.
-         */
-        public PresetPrefHelper() {
-            super("taggingpreset.entries");
-        }
-
-        @Override
-        public Collection<ExtendedSourceEntry> getDefault() {
-            ExtendedSourceEntry i = new ExtendedSourceEntry("defaultpresets.xml", "resource://data/defaultpresets.xml");
-            i.title = tr("Internal Preset");
-            i.description = tr("The default preset for JOSM");
-            return Collections.singletonList(i);
-        }
-
-        @Override
-        public Map<String, String> serialize(SourceEntry entry) {
-            Map<String, String> res = new HashMap<>();
-            res.put("url", entry.url);
-            res.put("title", entry.title == null ? "" : entry.title);
-            return res;
-        }
-
-        @Override
-        public SourceEntry deserialize(Map<String, String> s) {
-            return new SourceEntry(s.get("url"), null, s.get("title"), true);
-        }
-    }
-
     @Override
     public boolean isExpert() {
Index: trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorPreference.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorPreference.java	(revision 12649)
@@ -6,5 +6,4 @@
 import javax.swing.JTabbedPane;
 
-import org.openstreetmap.josm.data.preferences.BooleanProperty;
 import org.openstreetmap.josm.gui.preferences.DefaultTabPreferenceSetting;
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
@@ -36,31 +35,4 @@
     }
 
-    /** The preferences prefix */
-    public static final String PREFIX = "validator";
-
-    /** The preferences key for error layer */
-    public static final BooleanProperty PREF_LAYER = new BooleanProperty(PREFIX + ".layer", true);
-
-    /** The preferences key for enabled tests */
-    public static final String PREF_SKIP_TESTS = PREFIX + ".skip";
-
-    /** The preferences key for enabled tests */
-    public static final BooleanProperty PREF_USE_IGNORE = new BooleanProperty(PREFIX + ".ignore", true);
-
-    /** The preferences key for enabled tests before upload*/
-    public static final String PREF_SKIP_TESTS_BEFORE_UPLOAD = PREFIX + ".skipBeforeUpload";
-
-    /** The preferences key for ignored severity other on upload */
-    public static final BooleanProperty PREF_OTHER_UPLOAD = new BooleanProperty(PREFIX + ".otherUpload", false);
-
-    /** The preferences for ignored severity other */
-    public static final BooleanProperty PREF_OTHER = new BooleanProperty(PREFIX + ".other", false);
-
-    /**
-     * The preferences key for enabling the permanent filtering
-     * of the displayed errors in the tree regarding the current selection
-     */
-    public static final String PREF_FILTER_BY_SELECTION = PREFIX + ".selectionFilter";
-
     @Override
     public void addGui(PreferenceTabbedPane gui) {
Index: trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTagCheckerRulesPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTagCheckerRulesPreference.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTagCheckerRulesPreference.java	(revision 12649)
@@ -8,9 +8,12 @@
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.preferences.sources.ExtendedSourceEntry;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
+import org.openstreetmap.josm.data.preferences.sources.SourceEntry;
+import org.openstreetmap.josm.data.preferences.sources.SourceProvider;
+import org.openstreetmap.josm.data.preferences.sources.SourceType;
 import org.openstreetmap.josm.data.validation.OsmValidator;
 import org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker;
@@ -19,8 +22,4 @@
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
 import org.openstreetmap.josm.gui.preferences.SourceEditor;
-import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
-import org.openstreetmap.josm.gui.preferences.SourceEntry;
-import org.openstreetmap.josm.gui.preferences.SourceProvider;
-import org.openstreetmap.josm.gui.preferences.SourceType;
 import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
 import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
@@ -64,15 +63,15 @@
         @Override
         public Collection<? extends SourceEntry> getInitialSourcesList() {
-            return RulePrefHelper.INSTANCE.get();
+            return ValidatorPrefHelper.INSTANCE.get();
         }
 
         @Override
         public boolean finish() {
-            return RulePrefHelper.INSTANCE.put(activeSourcesModel.getSources());
+            return ValidatorPrefHelper.INSTANCE.put(activeSourcesModel.getSources());
         }
 
         @Override
         public Collection<ExtendedSourceEntry> getDefault() {
-            return RulePrefHelper.INSTANCE.getDefault();
+            return ValidatorPrefHelper.INSTANCE.getDefault();
         }
 
@@ -123,65 +122,4 @@
     }
 
-    /**
-     * Helper class for validator tag checker rules preferences.
-     */
-    public static class RulePrefHelper extends SourceEditor.SourcePrefHelper {
-
-        /**
-         * The unique instance.
-         */
-        public static final RulePrefHelper INSTANCE = new RulePrefHelper();
-
-        /**
-         * Constructs a new {@code PresetPrefHelper}.
-         */
-        public RulePrefHelper() {
-            super(MapCSSTagChecker.ENTRIES_PREF_KEY);
-        }
-
-        @Override
-        public Collection<ExtendedSourceEntry> getDefault() {
-            List<ExtendedSourceEntry> def = new ArrayList<>();
-
-            // CHECKSTYLE.OFF: SingleSpaceSeparator
-            addDefault(def, "addresses",    tr("Addresses"),           tr("Checks for errors on addresses"));
-            addDefault(def, "combinations", tr("Tag combinations"),    tr("Checks for missing tag or suspicious combinations"));
-            addDefault(def, "deprecated",   tr("Deprecated features"), tr("Checks for deprecated features"));
-            addDefault(def, "geometry",     tr("Geometry"),            tr("Checks for geometry errors"));
-            addDefault(def, "highway",      tr("Highways"),            tr("Checks for errors on highways"));
-            addDefault(def, "multiple",     tr("Multiple values"),     tr("Checks for wrong multiple values"));
-            addDefault(def, "numeric",      tr("Numeric values"),      tr("Checks for wrong numeric values"));
-            addDefault(def, "religion",     tr("Religion"),            tr("Checks for errors on religious objects"));
-            addDefault(def, "relation",     tr("Relations"),           tr("Checks for errors on relations"));
-            addDefault(def, "territories",  tr("Territories"),         tr("Checks for territories-specific features"));
-            addDefault(def, "unnecessary",  tr("Unnecessary tags"),    tr("Checks for unnecessary tags"));
-            addDefault(def, "wikipedia",    tr("Wikipedia"),           tr("Checks for wrong wikipedia tags"));
-            // CHECKSTYLE.ON: SingleSpaceSeparator
-
-            return def;
-        }
-
-        private static void addDefault(List<ExtendedSourceEntry> defaults, String filename, String title, String description) {
-            ExtendedSourceEntry i = new ExtendedSourceEntry(filename+".mapcss", "resource://data/validator/"+filename+".mapcss");
-            i.title = title;
-            i.description = description;
-            defaults.add(i);
-        }
-
-        @Override
-        public Map<String, String> serialize(SourceEntry entry) {
-            Map<String, String> res = new HashMap<>();
-            res.put("url", entry.url);
-            res.put("title", entry.title == null ? "" : entry.title);
-            res.put("active", Boolean.toString(entry.active));
-            return res;
-        }
-
-        @Override
-        public SourceEntry deserialize(Map<String, String> s) {
-            return new SourceEntry(s.get("url"), null, s.get("title"), Boolean.parseBoolean(s.get("active")));
-        }
-    }
-
     private SourceEditor sources;
 
Index: trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTestsPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTestsPreference.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTestsPreference.java	(revision 12649)
@@ -17,4 +17,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
 import org.openstreetmap.josm.data.validation.OsmValidator;
 import org.openstreetmap.josm.data.validation.Test;
@@ -58,18 +59,18 @@
         testPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 
-        prefUseIgnore = new JCheckBox(tr("Use ignore list."), ValidatorPreference.PREF_USE_IGNORE.get());
+        prefUseIgnore = new JCheckBox(tr("Use ignore list."), ValidatorPrefHelper.PREF_USE_IGNORE.get());
         prefUseIgnore.setToolTipText(tr("Use the ignore list to suppress warnings."));
         testPanel.add(prefUseIgnore, GBC.eol());
 
-        prefUseLayer = new JCheckBox(tr("Use error layer."), ValidatorPreference.PREF_LAYER.get());
+        prefUseLayer = new JCheckBox(tr("Use error layer."), ValidatorPrefHelper.PREF_LAYER.get());
         prefUseLayer.setToolTipText(tr("Use the error layer to display problematic elements."));
         testPanel.add(prefUseLayer, GBC.eol());
 
-        prefOther = new JCheckBox(tr("Show informational level."), ValidatorPreference.PREF_OTHER.get());
+        prefOther = new JCheckBox(tr("Show informational level."), ValidatorPrefHelper.PREF_OTHER.get());
         prefOther.setToolTipText(tr("Show the informational tests."));
         testPanel.add(prefOther, GBC.eol());
 
         prefOtherUpload = new JCheckBox(tr("Show informational level on upload."),
-                ValidatorPreference.PREF_OTHER_UPLOAD.get());
+                ValidatorPrefHelper.PREF_OTHER_UPLOAD.get());
         prefOtherUpload.setToolTipText(tr("Show the informational tests in the upload check windows."));
         testPanel.add(prefOtherUpload, GBC.eol());
@@ -115,10 +116,10 @@
         OsmValidator.initializeTests(testsToInitialize);
 
-        Main.pref.putCollection(ValidatorPreference.PREF_SKIP_TESTS, tests);
-        Main.pref.putCollection(ValidatorPreference.PREF_SKIP_TESTS_BEFORE_UPLOAD, testsBeforeUpload);
-        ValidatorPreference.PREF_USE_IGNORE.put(prefUseIgnore.isSelected());
-        ValidatorPreference.PREF_OTHER.put(prefOther.isSelected());
-        ValidatorPreference.PREF_OTHER_UPLOAD.put(prefOtherUpload.isSelected());
-        ValidatorPreference.PREF_LAYER.put(prefUseLayer.isSelected());
+        Main.pref.putCollection(ValidatorPrefHelper.PREF_SKIP_TESTS, tests);
+        Main.pref.putCollection(ValidatorPrefHelper.PREF_SKIP_TESTS_BEFORE_UPLOAD, testsBeforeUpload);
+        ValidatorPrefHelper.PREF_USE_IGNORE.put(prefUseIgnore.isSelected());
+        ValidatorPrefHelper.PREF_OTHER.put(prefOther.isSelected());
+        ValidatorPrefHelper.PREF_OTHER_UPLOAD.put(prefOtherUpload.isSelected());
+        ValidatorPrefHelper.PREF_LAYER.put(prefUseLayer.isSelected());
         return false;
     }
Index: trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReader.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReader.java	(revision 12649)
@@ -25,5 +25,5 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
+import org.openstreetmap.josm.data.preferences.sources.PresetPrefHelper;
 import org.openstreetmap.josm.gui.tagging.presets.items.Check;
 import org.openstreetmap.josm.gui.tagging.presets.items.CheckGroup;
@@ -103,5 +103,5 @@
      */
     public static Set<String> getPresetSources() {
-        return new TaggingPresetPreference.PresetPrefHelper().getActiveUrls();
+        return new PresetPrefHelper().getActiveUrls();
     }
 
Index: trunk/src/org/openstreetmap/josm/io/FileWatcher.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/FileWatcher.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/io/FileWatcher.java	(revision 12649)
@@ -16,4 +16,5 @@
 import java.util.concurrent.Executors;
 
+import org.openstreetmap.josm.data.preferences.sources.SourceEntry;
 import org.openstreetmap.josm.data.validation.OsmValidator;
 import org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker;
@@ -21,5 +22,4 @@
 import org.openstreetmap.josm.gui.mappaint.StyleSource;
 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.ParseException;
-import org.openstreetmap.josm.gui.preferences.SourceEntry;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.Logging;
Index: trunk/src/org/openstreetmap/josm/tools/bugreport/BugReport.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/bugreport/BugReport.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/tools/bugreport/BugReport.java	(revision 12649)
@@ -53,5 +53,5 @@
      * @param e The {@link ReportedException} to use. No more data should be added after creating the report.
      */
-    BugReport(ReportedException e) {
+    public BugReport(ReportedException e) {
         this.exception = e;
         includeAllStackTraces = e.mayHaveConcurrentSource();
Index: trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportDialog.java	(revision 12647)
+++ 	(revision )
@@ -1,267 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.tools.bugreport;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.Component;
-import java.awt.Frame;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.event.ActionEvent;
-
-import javax.swing.AbstractAction;
-import javax.swing.BorderFactory;
-import javax.swing.Icon;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.UIManager;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.ExpertToggleAction;
-import org.openstreetmap.josm.gui.preferences.plugin.PluginPreference;
-import org.openstreetmap.josm.gui.util.GuiHelper;
-import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
-import org.openstreetmap.josm.gui.widgets.UrlLabel;
-import org.openstreetmap.josm.plugins.PluginDownloadTask;
-import org.openstreetmap.josm.plugins.PluginHandler;
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.ImageProvider;
-import org.openstreetmap.josm.tools.InputMapUtils;
-import org.openstreetmap.josm.tools.bugreport.BugReportQueue.SuppressionMode;
-
-/**
- * This is a dialog that can be used to display a bug report.
- * <p>
- * It displays the bug to the user and asks the user to submit a bug report.
- * @author Michael Zangl
- * @since 10649
- */
-public class BugReportDialog extends JDialog {
-    private static final int MAX_MESSAGE_SIZE = 500;
-    // This is explicitly not an ExtendedDialog - we still want to be able to display bug reports if there are problems with preferences/..
-    private final JPanel content = new JPanel(new GridBagLayout());
-    private final BugReport report;
-    private final DebugTextDisplay textPanel;
-    private JCheckBox cbSuppressSingle;
-    private JCheckBox cbSuppressAll;
-
-    /**
-     * Create a new dialog.
-     * @param report The report to display the dialog for.
-     */
-    public BugReportDialog(BugReport report) {
-        super(findParent(), tr("You have encountered a bug in JOSM"));
-        this.report = report;
-        textPanel = new DebugTextDisplay(report);
-        setContentPane(content);
-
-        addMessageSection();
-
-        addUpToDateSection();
-        // TODO: Notify user about plugin updates, then remove that notification that is displayed before this dialog is displayed.
-
-        addCreateTicketSection();
-
-        if (ExpertToggleAction.isExpert()) {
-            addDebugTextSection();
-        }
-
-        addIgnoreButton();
-
-        pack();
-        setModal(true);
-        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
-
-        InputMapUtils.addEscapeAction(getRootPane(), new AbstractAction() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                closeDialog();
-            }
-        });
-    }
-
-    /**
-     * The message informing the user what happened.
-     */
-    private void addMessageSection() {
-        String message = tr(
-                "An unexpected exception occurred.\n" + "This is always a coding error. If you are running the latest "
-                        + "version of JOSM, please consider being kind and file a bug report.");
-        Icon icon = UIManager.getIcon("OptionPane.errorIcon");
-
-        JPanel panel = new JPanel(new GridBagLayout());
-
-        panel.add(new JLabel(icon), GBC.std().insets(0, 0, 10, 0));
-        JMultilineLabel messageLabel = new JMultilineLabel(message);
-        messageLabel.setMaxWidth(MAX_MESSAGE_SIZE);
-        panel.add(messageLabel, GBC.eol().fill());
-        content.add(panel, GBC.eop().fill(GBC.HORIZONTAL).insets(20, 10, 10, 10));
-    }
-
-    private void addDebugTextSection() {
-        JPanel panel = new JPanel(new GridBagLayout());
-        addBorder(panel, tr("Debug information"));
-        panel.add(textPanel, GBC.eop().fill());
-
-        panel.add(new JLabel(tr("Manually report at:")+' '), GBC.std());
-        panel.add(new UrlLabel(Main.getJOSMWebsite() + "/newticket"), GBC.std().fill(GBC.HORIZONTAL));
-        JButton copy = new JButton("Copy to clipboard");
-        copy.addActionListener(e -> textPanel.copyToClipboard());
-        panel.add(copy, GBC.eol().anchor(GBC.EAST));
-        content.add(panel, GBC.eop().fill());
-    }
-
-    private void addUpToDateSection() {
-        JPanel panel = new JosmUpdatePanel();
-        addBorder(panel, tr("Is JOSM up to date?"));
-        content.add(panel, GBC.eop().fill(GBC.HORIZONTAL));
-    }
-
-    private void addCreateTicketSection() {
-        JPanel panel = new JPanel(new GridBagLayout());
-        addBorder(panel, tr("Send bug report"));
-
-        JMultilineLabel helpText = new JMultilineLabel(
-                tr("If you are running the latest version of JOSM and the plugins, "
-                        + "please file a bug report in our bugtracker.\n"
-                        + "There the error information should already be "
-                        + "filled in for you. Please include information on how to reproduce "
-                        + "the error and try to supply as much detail as possible."));
-        helpText.setMaxWidth(MAX_MESSAGE_SIZE);
-        panel.add(helpText, GBC.eop().fill(GridBagConstraints.HORIZONTAL));
-
-        Component settings = GBC.glue(0, 0);
-        if (ExpertToggleAction.isExpert()) {
-            // The default settings should be fine in most situations.
-            settings = new BugReportSettingsPanel(report);
-        }
-        panel.add(settings);
-
-        JButton sendBugReportButton = new JButton(tr("Report Bug"), ImageProvider.get("bug"));
-        sendBugReportButton.addActionListener(e -> sendBug());
-        panel.add(sendBugReportButton, GBC.eol().insets(0, 0, 0, 0).anchor(GBC.SOUTHEAST));
-        content.add(panel, GBC.eop().fill(GBC.HORIZONTAL));
-    }
-
-    private static void addBorder(JPanel panel, String title) {
-        panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(title), BorderFactory
-                .createEmptyBorder(5, 5, 5, 5)));
-    }
-
-    private void addIgnoreButton() {
-        JPanel panel = new JPanel(new GridBagLayout());
-        cbSuppressSingle = new JCheckBox(tr("Suppress this error for this session."));
-        cbSuppressSingle.setVisible(false);
-        panel.add(cbSuppressSingle, GBC.std(0, 0).fill(GBC.HORIZONTAL));
-        cbSuppressAll = new JCheckBox(tr("Suppress further error dialogs for this session."));
-        cbSuppressAll.setVisible(false);
-        panel.add(cbSuppressAll, GBC.std(0, 1).fill(GBC.HORIZONTAL));
-        JButton ignore = new JButton(tr("Ignore this error."));
-        ignore.addActionListener(e -> closeDialog());
-        panel.add(ignore, GBC.std(1, 0).span(1, 2).anchor(GBC.CENTER));
-        content.add(panel, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 0, 10, 10));
-    }
-
-    /**
-     * Shows or hides the suppress errors button
-     * @param showSuppress <code>true</code> to show the suppress errors checkbox.
-     */
-    public void setShowSuppress(boolean showSuppress) {
-        cbSuppressSingle.setVisible(showSuppress);
-        pack();
-    }
-
-    /**
-     * Shows or hides the suppress all errors button
-     * @param showSuppress <code>true</code> to show the suppress errors checkbox.
-     * @since 10819
-     */
-    public void setShowSuppressAll(boolean showSuppress) {
-        cbSuppressAll.setVisible(showSuppress);
-        pack();
-    }
-
-    /**
-     * Check if the checkbox to suppress further errors was selected
-     * @return <code>true</code> if the user wishes to suppress errors.
-     */
-    public SuppressionMode shouldSuppressFurtherErrors() {
-        if (cbSuppressAll.isSelected()) {
-            return SuppressionMode.ALL;
-        } else if (cbSuppressSingle.isSelected()) {
-            return SuppressionMode.SAME;
-        } else {
-            return SuppressionMode.NONE;
-        }
-    }
-
-    private void closeDialog() {
-        setVisible(false);
-    }
-
-    private void sendBug() {
-        BugReportSender.reportBug(textPanel.getCodeText());
-    }
-
-    /**
-     * A safe way to find a matching parent frame.
-     * @return The parent frame.
-     */
-    private static Frame findParent() {
-        Component current = Main.parent;
-        try {
-            // avoid cycles/invalid hirarchies
-            for (int i = 0; i < 20 && current != null; i++) {
-                if (current instanceof Frame) {
-                    return (Frame) current;
-                }
-                current = current.getParent();
-            }
-        } catch (RuntimeException e) { // NOPMD
-            BugReport.intercept(e).put("current", current).warn();
-        }
-        return null;
-    }
-
-    /**
-     * Show the bug report for a given exception
-     * @param e The exception to display
-     * @param exceptionCounter A counter of how many exceptions have already been worked on
-     * @return The new suppression status
-     * @since 10819
-     */
-    public static SuppressionMode showFor(ReportedException e, int exceptionCounter) {
-        if (e.isOutOfMemory()) {
-            // do not translate the string, as translation may raise an exception
-            JOptionPane.showMessageDialog(Main.parent, "JOSM is out of memory. " +
-                    "Strange things may happen.\nPlease restart JOSM with the -Xmx###M option,\n" +
-                    "where ### is the number of MB assigned to JOSM (e.g. 256).\n" +
-                    "Currently, " + Runtime.getRuntime().maxMemory()/1024/1024 + " MB are available to JOSM.",
-                    "Error",
-                    JOptionPane.ERROR_MESSAGE
-                    );
-            return SuppressionMode.NONE;
-        } else {
-            return GuiHelper.runInEDTAndWaitAndReturn(() -> {
-                PluginDownloadTask downloadTask = PluginHandler.updateOrdisablePluginAfterException(e);
-                if (downloadTask != null) {
-                    // Ask for restart to install new plugin
-                    PluginPreference.notifyDownloadResults(
-                            Main.parent, downloadTask, !downloadTask.getDownloadedPlugins().isEmpty());
-                    return SuppressionMode.NONE;
-                }
-
-                BugReport report = new BugReport(e);
-                BugReportDialog dialog = new BugReportDialog(report);
-                dialog.setShowSuppress(exceptionCounter > 0);
-                dialog.setShowSuppressAll(exceptionCounter > 1);
-                dialog.setVisible(true);
-                return dialog.shouldSuppressFurtherErrors();
-            });
-        }
-    }
-}
Index: trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportQueue.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportQueue.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportQueue.java	(revision 12649)
@@ -9,4 +9,5 @@
 import java.util.function.Predicate;
 
+import org.openstreetmap.josm.gui.bugreport.BugReportDialog;
 import org.openstreetmap.josm.tools.Logging;
 
Index: trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportSender.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportSender.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportSender.java	(revision 12649)
@@ -23,4 +23,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.bugreport.DebugTextDisplay;
 import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
 import org.openstreetmap.josm.gui.widgets.UrlLabel;
Index: trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportSettingsPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/bugreport/BugReportSettingsPanel.java	(revision 12647)
+++ 	(revision )
@@ -1,38 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.tools.bugreport;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import javax.swing.BoxLayout;
-import javax.swing.JCheckBox;
-import javax.swing.JPanel;
-
-/**
- * This panel displays the settings that can be changed before submitting a bug report to the web page.
- * @author Michael Zangl
- * @since 10585
- */
-public class BugReportSettingsPanel extends JPanel {
-    /**
-     * Creates the new settings panel.
-     * @param report The report this panel should influence.
-     */
-    public BugReportSettingsPanel(BugReport report) {
-        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
-
-        JCheckBox statusReport = new JCheckBox(tr("Include the system status report."));
-        statusReport.setSelected(report.isIncludeStatusReport());
-        statusReport.addChangeListener(e -> report.setIncludeStatusReport(statusReport.isSelected()));
-        add(statusReport);
-
-        JCheckBox data = new JCheckBox(tr("Include information about the data you were working on."));
-        data.setSelected(report.isIncludeData());
-        data.addChangeListener(e -> report.setIncludeData(data.isSelected()));
-        add(data);
-
-        JCheckBox allStackTraces = new JCheckBox(tr("Include all stack traces."));
-        allStackTraces.setSelected(report.isIncludeAllStackTraces());
-        allStackTraces.addChangeListener(e -> report.setIncludeAllStackTraces(allStackTraces.isSelected()));
-        add(allStackTraces);
-    }
-}
Index: trunk/src/org/openstreetmap/josm/tools/bugreport/DebugTextDisplay.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/bugreport/DebugTextDisplay.java	(revision 12647)
+++ 	(revision )
@@ -1,81 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.tools.bugreport;
-
-import java.awt.Dimension;
-
-import javax.swing.JScrollPane;
-
-import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
-import org.openstreetmap.josm.gui.widgets.JosmTextArea;
-import org.openstreetmap.josm.tools.Utils;
-
-/**
- * This is a text area that displays the debug text with scroll bars.
- * @author Michael Zangl
- * @since 10055
- */
-public class DebugTextDisplay extends JScrollPane {
-    private static final String CODE_PATTERN = "{{{%n%s%n}}}";
-    private String text;
-    private JosmTextArea textArea;
-
-    /**
-     * Creates a new text area.
-     * @since 10585
-     */
-    private DebugTextDisplay() {
-        textArea = new JosmTextArea();
-        textArea.setCaretPosition(0);
-        textArea.setEditable(false);
-        setViewportView(textArea);
-        setPreferredSize(new Dimension(600, 270));
-    }
-
-    /**
-     * Creates a new text area with an inital text to display
-     * @param textToDisplay The text to display.
-     */
-    public DebugTextDisplay(String textToDisplay) {
-        this();
-        setCodeText(textToDisplay);
-    }
-
-    /**
-     * Creates a new text area that displays the bug report data
-     * @param report The bug report data to display.
-     * @since 10585
-     */
-    public DebugTextDisplay(BugReport report) {
-        this();
-        setCodeText(report.getReportText());
-        report.addChangeListener(e -> setCodeText(report.getReportText()));
-    }
-
-    /**
-     * Sets the text that should be displayed in this view.
-     * @param textToDisplay The text
-     */
-    private void setCodeText(String textToDisplay) {
-        text = Utils.strip(textToDisplay).replaceAll("\r", "");
-        textArea.setText(String.format(CODE_PATTERN, text));
-        textArea.setCaretPosition(0);
-    }
-
-    /**
-     * Copies the debug text to the clipboard. This includes the code tags for trac.
-     * @return <code>true</code> if copy was successful
-     * @since 11102 (typo)
-     */
-    public boolean copyToClipboard() {
-        return ClipboardUtils.copyString(String.format(CODE_PATTERN, text));
-    }
-
-    /**
-     * Gets the text this are displays, without the code tag.
-     * @return The stripped text set by {@link #setCodeText(String)}
-     * @since 10585
-     */
-    public String getCodeText() {
-        return text;
-    }
-}
Index: trunk/src/org/openstreetmap/josm/tools/bugreport/JosmUpdatePanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/bugreport/JosmUpdatePanel.java	(revision 12647)
+++ 	(revision )
@@ -1,104 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.tools.bugreport;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.GridBagLayout;
-import java.io.IOException;
-
-import javax.swing.JButton;
-import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Version;
-import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
-import org.openstreetmap.josm.gui.widgets.UrlLabel;
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.ImageProvider;
-import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.WikiReader;
-
-/**
- * This is a panel that displays the current JOSM version and the ability to update JOSM.
- * @author Michael Zangl
- * @since 10649
- */
-public class JosmUpdatePanel extends JPanel {
-    private final JMultilineLabel testedVersionField;
-    private final int josmVersion;
-
-    /**
-     * Create a new {@link JosmUpdatePanel}
-     */
-    public JosmUpdatePanel() {
-        super(new GridBagLayout());
-        josmVersion = Version.getInstance().getVersion();
-
-        add(new JMultilineLabel(tr("Your current version of JOSM is {0}", josmVersion)), GBC.eol().fill(GBC.HORIZONTAL));
-        testedVersionField = new JMultilineLabel(tr("JOSM is searching for updates..."));
-        add(testedVersionField, GBC.eol().fill(GBC.HORIZONTAL));
-
-        checkCurrentVersion();
-    }
-
-    private void checkCurrentVersion() {
-        new Thread(this::readCurrentVersion, "JOSM version checker").start();
-    }
-
-    private void readCurrentVersion() {
-        int testedVersion = getTestedVersion();
-
-        if (testedVersion < 0) {
-            SwingUtilities.invokeLater(this::displayError);
-        } else if (josmVersion < testedVersion) {
-            SwingUtilities.invokeLater(() -> displayOutOfDate(testedVersion));
-        } else {
-            SwingUtilities.invokeLater(this::displayUpToDate);
-        }
-    }
-
-    private static int getTestedVersion() {
-        try {
-            String testedString = new WikiReader().read(Main.getJOSMWebsite() + "/wiki/TestedVersion?format=txt");
-            return Integer.parseInt(testedString.trim());
-        } catch (NumberFormatException | IOException e) {
-            Logging.log(Logging.LEVEL_WARN, "Unable to detect latest version of JOSM:", e);
-            return -1;
-        }
-    }
-
-    /**
-     * Display that there was an error while checking the current version.
-     */
-    private void displayError() {
-        testedVersionField.setText(tr("An error occured while checking if your JOSM instance is up to date."));
-        showUpdateButton();
-    }
-
-    private void displayUpToDate() {
-        testedVersionField.setText(tr("JOSM is up to date."));
-    }
-
-    private void displayOutOfDate(int testedVersion) {
-        testedVersionField
-                .setText(tr("JOSM is out of date. The current version is {0}. Try updating JOSM.", testedVersion));
-        showUpdateButton();
-    }
-
-    private void showUpdateButton() {
-        add(new JMultilineLabel(tr("Before you file a bug report make sure you have updated to the latest version of JOSM here:")), GBC.eol());
-        add(new UrlLabel(Main.getJOSMWebsite(), 2), GBC.eop().insets(8, 0, 0, 0));
-        JButton updateButton = new JButton(tr("Update JOSM"), ImageProvider.get("download"));
-        updateButton.addActionListener(e -> openJosmUpdateSite());
-        add(updateButton, GBC.eol().anchor(GBC.EAST));
-    }
-
-    private static void openJosmUpdateSite() {
-        try {
-            Main.platform.openUrl(Main.getJOSMWebsite());
-        } catch (IOException ex) {
-            Logging.log(Logging.LEVEL_WARN, "Unable to access JOSM website:", ex);
-        }
-    }
-}
Index: trunk/src/org/openstreetmap/josm/tools/bugreport/package-info.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/bugreport/package-info.java	(revision 12647)
+++ trunk/src/org/openstreetmap/josm/tools/bugreport/package-info.java	(revision 12649)
@@ -2,5 +2,5 @@
 
 /**
- * Provides classes for the bug report system, allowing users to create tickets on issue tracker directly from JOSM.
+ * Provides core classes for the bug report system, allowing to save technical information used later in tickets on issue tracker.
  */
 package org.openstreetmap.josm.tools.bugreport;
