Index: trunk/src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 6670)
@@ -1582,4 +1582,5 @@
                 "validator.TagChecker.useignorefile",          // 01/2014 - can be removed mid-2014. Replaced by validator.TagChecker.source
                 "validator.TagChecker.usespellfile",           // 01/2014 - can be removed mid-2014. Replaced by validator.TagChecker.source
+                "validator.org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker.sources" // 01/2014 - can be removed mid-2014. Replaced by validator.org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker.entries
         };
         for (String key : obsolete) {
Index: trunk/src/org/openstreetmap/josm/data/coor/EastNorth.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/EastNorth.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/data/coor/EastNorth.java	(revision 6670)
@@ -91,7 +91,7 @@
 
     /**
-     * Replies true if east and north are different from Double.NaN and not inifinite
+     * Replies true if east and north are different from Double.NaN and not infinite
      *
-     * @return true if east and north are different from Double.NaN and not inifinite
+     * @return true if east and north are different from Double.NaN and not infinite
      */
     public boolean isValid() {
Index: trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/data/validation/OsmValidator.java	(revision 6670)
@@ -222,4 +222,18 @@
         return new HashMap<String, Test>(allTestsMap);
     }
+    
+    /**
+     * Returns the instance of the given test class.
+     * @param testClass The class of test to retrieve
+     * @return the instance of the given test class, if any, or {@code null}
+     * @since 6670
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Test> T getTest(Class<T> testClass) {
+        if (testClass == null) {
+            return null;
+        }
+        return (T) allTestsMap.get(testClass.getSimpleName());
+    }
 
     private static void applyPrefs(Map<String, Test> tests, boolean beforeUpload) {
@@ -283,5 +297,5 @@
      * @param allTests The tests to initialize
      */
-    public static void initializeTests(Collection<Test> allTests) {
+    public static void initializeTests(Collection<? extends Test> allTests) {
         for (Test test : allTests) {
             try {
Index: trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java	(revision 6670)
@@ -5,10 +5,10 @@
 
 import java.io.BufferedReader;
-import java.io.InputStreamReader;
+import java.io.IOException;
 import java.io.Reader;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
@@ -25,5 +25,4 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Tag;
-import org.openstreetmap.josm.data.preferences.CollectionProperty;
 import org.openstreetmap.josm.data.validation.FixableTestError;
 import org.openstreetmap.josm.data.validation.Severity;
@@ -38,17 +37,14 @@
 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.GeneralSelector;
 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser;
 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.ParseException;
 import org.openstreetmap.josm.gui.preferences.validator.ValidatorPreference;
-import org.openstreetmap.josm.gui.widgets.EditableList;
+import org.openstreetmap.josm.gui.preferences.validator.ValidatorTagCheckerRulesPreference;
 import org.openstreetmap.josm.io.MirroredInputStream;
 import org.openstreetmap.josm.io.UTFInputStreamReader;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
-import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.Predicate;
 import org.openstreetmap.josm.tools.Utils;
-
-import javax.swing.JLabel;
-import javax.swing.JPanel;
 
 /**
@@ -57,4 +53,10 @@
  */
 public class MapCSSTagChecker extends Test.TagTest {
+
+    /**
+     * The preference key for tag checker source entries.
+     * @since 6670
+     */
+    public static final String ENTRIES_PREF_KEY = "validator." + MapCSSTagChecker.class.getName() + ".entries";
 
     /**
@@ -170,4 +172,6 @@
             css.sheet(source);
             assert source.getErrors().isEmpty();
+            // Ignore "meta" rule(s) from external rules of JOSM wiki
+            removeMetaRules(source);
             return new ArrayList<TagCheck>(Utils.transform(source.rules, new Utils.Function<MapCSSRule, TagCheck>() {
                 @Override
@@ -176,4 +180,19 @@
                 }
             }));
+        }
+        
+        private static void removeMetaRules(MapCSSStyleSource source) {
+            for (Iterator<MapCSSRule> it = source.rules.iterator(); it.hasNext(); ) {
+                MapCSSRule x = it.next();
+                if (x.selectors.size() == 1) {
+                    Selector sel = x.selectors.get(0);
+                    if (sel instanceof GeneralSelector) {
+                        GeneralSelector gs = (GeneralSelector) sel;
+                        if ("meta".equals(gs.base) && gs.getConditions().isEmpty()) {
+                            it.remove();
+                        }
+                    }
+                }
+            }
         }
 
@@ -405,53 +424,24 @@
     }
 
-    /**
-     * Adds a new MapCSS config file from the given internal filename.
-     * @param internalConfigFile the filename in data/validator
-     * @throws ParseException if the config file does not match MapCSS syntax
-     */
-    private void addMapCSS(String internalConfigFile) throws ParseException {
-        addMapCSS(new InputStreamReader(getClass().getResourceAsStream("/data/validator/" + internalConfigFile + ".mapcss"), Utils.UTF_8));
-    }
-
     @Override
     public synchronized void initialize() throws Exception {
         checks.clear();
-        addMapCSS("deprecated");
-        addMapCSS("highway");
-        addMapCSS("numeric");
-        addMapCSS("religion");
-        addMapCSS("relation");
-        addMapCSS("combinations");
-        addMapCSS("unnecessary");
-        addMapCSS("wikipedia");
-        addMapCSS("power");
-        addMapCSS("geometry");
-        for (final String i : sourcesProperty.get()) {
+        for (String i : new ValidatorTagCheckerRulesPreference.RulePrefHelper().getActiveUrls()) {
             try {
                 Main.info(tr("Adding {0} to tag checker", i));
-                addMapCSS(new BufferedReader(UTFInputStreamReader.create(new MirroredInputStream(i))));
+                MirroredInputStream s = new MirroredInputStream(i);
+                try {
+                    addMapCSS(new BufferedReader(UTFInputStreamReader.create(s)));
+                } finally {
+                    Utils.close(s);
+                }
+            } catch (IOException ex) {
+                Main.warn(tr("Failed to add {0} to tag checker", i));
+                Main.warn(ex, false);
             } catch (Exception ex) {
-                Main.warn(new RuntimeException(tr("Failed to add {0} to tag checker", i), ex));
-            }
-        }
-    }
-
-    protected EditableList sourcesList;
-    protected final CollectionProperty sourcesProperty = new CollectionProperty(
-            "validator." + this.getClass().getName() + ".sources", Collections.<String>emptyList());
-
-    @Override
-    public void addGui(JPanel testPanel) {
-        super.addGui(testPanel);
-        sourcesList = new EditableList(tr("TagChecker source"));
-        sourcesList.setItems(sourcesProperty.get());
-        testPanel.add(new JLabel(tr("Data sources ({0})", "*.validator.mapcss")), GBC.eol().insets(23, 0, 0, 0));
-        testPanel.add(sourcesList, GBC.eol().fill(GBC.HORIZONTAL).insets(23, 0, 0, 0));
-    }
-
-    @Override
-    public boolean ok() {
-        sourcesProperty.put(sourcesList.getItems());
-        return super.ok();
+                Main.warn(tr("Failed to add {0} to tag checker", i));
+                Main.warn(ex);
+            }
+        }
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 6670)
@@ -42,4 +42,8 @@
     private static ElemStyles styles = new ElemStyles();
 
+    /**
+     * Returns the {@link ElemStyles} instance.
+     * @return the {@code ElemStyles} instance
+     */
     public static ElemStyles getStyles() {
         return styles;
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 6670)
@@ -34,5 +34,5 @@
 
 public class MapCSSStyleSource extends StyleSource {
-    final public List<MapCSSRule> rules;
+    public final List<MapCSSRule> rules;
     private Color backgroundColorOverride;
     private String css = null;
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 6670)
@@ -346,4 +346,7 @@
 
         public List<Condition> getConditions() {
+            if (conds == null) {
+                return Collections.emptyList();
+            }
             return Collections.unmodifiableList(conds);
         }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java	(revision 6670)
@@ -53,4 +53,5 @@
 import org.openstreetmap.josm.gui.preferences.shortcut.ShortcutPreference;
 import org.openstreetmap.josm.gui.preferences.validator.ValidatorPreference;
+import org.openstreetmap.josm.gui.preferences.validator.ValidatorTagCheckerRulesPreference;
 import org.openstreetmap.josm.gui.preferences.validator.ValidatorTestsPreference;
 import org.openstreetmap.josm.plugins.PluginDownloadTask;
@@ -514,4 +515,5 @@
         settingsFactory.add(new ValidatorPreference.Factory());
         settingsFactory.add(new ValidatorTestsPreference.Factory());
+        settingsFactory.add(new ValidatorTagCheckerRulesPreference.Factory());
         settingsFactory.add(new RemoteControlPreference.Factory());
         settingsFactory.add(new ImageryPreference.Factory());
Index: trunk/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java	(revision 6670)
@@ -33,7 +33,9 @@
 import java.util.EventObject;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.regex.Matcher;
@@ -64,4 +66,5 @@
 import javax.swing.event.CellEditorListener;
 import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
@@ -93,5 +96,6 @@
 public abstract class SourceEditor extends JPanel {
 
-    final protected boolean isMapPaint;
+    protected final SourceType sourceType;
+    protected final boolean canEnable;
 
     protected final JTable tblActiveSources;
@@ -99,23 +103,27 @@
     protected final JList lstAvailableSources;
     protected final AvailableSourcesListModel availableSourcesModel;
-    protected final JTable tblIconPaths;
-    protected final IconPathTableModel iconPathsModel;
     protected final String availableSourcesUrl;
     protected final List<SourceProvider> sourceProviders;
 
+    protected JTable tblIconPaths;
+    protected IconPathTableModel iconPathsModel;
+
     protected boolean sourcesInitiallyLoaded;
 
     /**
-     * constructor
-     * @param isMapPaint true for MapPaintPreference subclass, false
-     *  for TaggingPresetPreference subclass
+     * Constructs a new {@code SourceEditor}.
+     * @param sourceType the type of source managed by this editor
      * @param availableSourcesUrl the URL to the list of available sources
      * @param sourceProviders the list of additional source providers, from plugins
+     * @param handleIcons {@code true} if icons may be managed, {@code false} otherwise
      */
-    public SourceEditor(final boolean isMapPaint, final String availableSourcesUrl, final List<SourceProvider> sourceProviders) {
-
-        this.isMapPaint = isMapPaint;
+    public SourceEditor(SourceType sourceType, String availableSourcesUrl, List<SourceProvider> sourceProviders, boolean handleIcons) {
+
+        this.sourceType = sourceType;
+        this.canEnable = sourceType.equals(SourceType.MAP_PAINT_STYLE) || sourceType.equals(SourceType.TAGCHECKER_RULE);
+        
         DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
-        this.lstAvailableSources = new JList(availableSourcesModel = new AvailableSourcesListModel(selectionModel));
+        this.availableSourcesModel = new AvailableSourcesListModel(selectionModel);
+        this.lstAvailableSources = new JList(availableSourcesModel);
         this.lstAvailableSources.setSelectionModel(selectionModel);
         this.lstAvailableSources.setCellRenderer(new SourceEntryListCellRenderer());
@@ -124,5 +132,6 @@
 
         selectionModel = new DefaultListSelectionModel();
-        tblActiveSources = new JTable(activeSourcesModel = new ActiveSourcesModel(selectionModel)) {
+        activeSourcesModel = new ActiveSourcesModel(selectionModel);
+        tblActiveSources = new JTable(activeSourcesModel) {
             // some kind of hack to prevent the table from scrolling slightly to the
             // right when clicking on the text
@@ -140,5 +149,5 @@
         tblActiveSources.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
         SourceEntryTableCellRenderer sourceEntryRenderer = new SourceEntryTableCellRenderer();
-        if (isMapPaint) {
+        if (canEnable) {
             tblActiveSources.getColumnModel().getColumn(0).setMaxWidth(1);
             tblActiveSources.getColumnModel().getColumn(0).setResizable(false);
@@ -153,5 +162,5 @@
             @Override
             public void tableChanged(TableModelEvent e) {
-                TableHelper.adjustColumnWidth(tblActiveSources, isMapPaint ? 1 : 0, 800);
+                TableHelper.adjustColumnWidth(tblActiveSources, canEnable ? 1 : 0, 800);
             }
         });
@@ -168,5 +177,5 @@
                     if (row < 0 || row >= tblActiveSources.getRowCount())
                         return;
-                    if (isMapPaint  && col != 1)
+                    if (canEnable && col != 1)
                         return;
                     editActiveSourceAction.actionPerformed(null);
@@ -182,5 +191,5 @@
         MoveUpDownAction moveUp = null;
         MoveUpDownAction moveDown = null;
-        if (isMapPaint) {
+        if (sourceType.equals(SourceType.MAP_PAINT_STYLE)) {
             moveUp = new MoveUpDownAction(false);
             moveDown = new MoveUpDownAction(true);
@@ -259,5 +268,5 @@
         sideButtonTB.add(removeActiveSourcesAction);
         sideButtonTB.addSeparator(new Dimension(12, 30));
-        if (isMapPaint) {
+        if (sourceType.equals(SourceType.MAP_PAINT_STYLE)) {
             sideButtonTB.add(moveUp);
             sideButtonTB.add(moveDown);
@@ -297,6 +306,13 @@
          **/
 
-        selectionModel = new DefaultListSelectionModel();
-        tblIconPaths = new JTable(iconPathsModel = new IconPathTableModel(selectionModel));
+        if (handleIcons) {
+            buildIcons(gbc);
+        }
+    }
+
+    private void buildIcons(GridBagConstraints gbc) {
+        DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
+        iconPathsModel = new IconPathTableModel(selectionModel);
+        tblIconPaths = new JTable(iconPathsModel);
         tblIconPaths.setSelectionModel(selectionModel);
         tblIconPaths.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
@@ -334,5 +350,6 @@
         gbc.insets = new Insets(0, 11, 0, 0);
 
-        add(sp = new JScrollPane(tblIconPaths), gbc);
+        JScrollPane sp = new JScrollPane(tblIconPaths);
+        add(sp, gbc);
         sp.setColumnHeaderView(null);
 
@@ -485,5 +502,5 @@
         @Override
         public int getColumnCount() {
-            return isMapPaint ? 2 : 1;
+            return canEnable ? 2 : 1;
         }
 
@@ -495,5 +512,5 @@
         @Override
         public Object getValueAt(int rowIndex, int columnIndex) {
-            if (isMapPaint && columnIndex == 0)
+            if (canEnable && columnIndex == 0)
                 return data.get(rowIndex).active;
             else
@@ -503,10 +520,10 @@
         @Override
         public boolean isCellEditable(int rowIndex, int columnIndex) {
-            return isMapPaint && columnIndex == 0;
+            return canEnable && columnIndex == 0;
         }
 
         @Override
         public Class<?> getColumnClass(int column) {
-            if (isMapPaint && column == 0)
+            if (canEnable && column == 0)
                 return Boolean.class;
             else return SourceEntry.class;
@@ -517,5 +534,5 @@
             if (row < 0 || row >= getRowCount() || aValue == null)
                 return;
-            if (isMapPaint && column == 0) {
+            if (canEnable && column == 0) {
                 data.get(row).active = ! data.get(row).active;
             }
@@ -709,5 +726,5 @@
             }
 
-            if (isMapPaint) {
+            if (canEnable) {
                 cbActive = new JCheckBox(tr("active"), e != null ? e.active : true);
                 p.add(cbActive, GBC.eol().insets(15, 0, 5, 0));
@@ -752,8 +769,17 @@
             public void actionPerformed(ActionEvent e) {
                 FileFilter ff;
-                if (isMapPaint) {
+                switch (sourceType) {
+                case MAP_PAINT_STYLE:
                     ff = new ExtensionFileFilter("xml,mapcss,css,zip", "xml", tr("Map paint style file (*.xml, *.mapcss, *.zip)"));
-                } else {
+                    break;
+                case TAGGING_PRESET:
                     ff = new ExtensionFileFilter("xml,zip", "xml", tr("Preset definition file (*.xml, *.zip)"));
+                    break;
+                case TAGCHECKER_RULE:
+                    ff = new ExtensionFileFilter("validator.mapcss,zip", "validator.mapcss", tr("Tag checker rule (*.validator.mapcss, *.zip)"));
+                    break;
+                default:
+                    Main.error("Unsupported source type: "+sourceType);
+                    return;
                 }
                 JFileChooserManager fcm = new JFileChooserManager(true)
@@ -777,5 +803,5 @@
 
         public boolean active() {
-            if (!isMapPaint)
+            if (!canEnable)
                 throw new UnsupportedOperationException();
             return cbActive.isSelected();
@@ -799,5 +825,5 @@
             if (editEntryDialog.getValue() == 1) {
                 boolean active = true;
-                if (isMapPaint) {
+                if (canEnable) {
                     active = editEntryDialog.active();
                 }
@@ -870,5 +896,5 @@
                 }
                 e.url = editEntryDialog.getURL();
-                if (isMapPaint) {
+                if (canEnable) {
                     e.active = editEntryDialog.active();
                 }
@@ -1495,8 +1521,16 @@
         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
+         */
         abstract public Collection<ExtendedSourceEntry> getDefault();
 
@@ -1505,4 +1539,8 @@
         abstract public SourceEntry deserialize(Map<String, String> entryStr);
 
+        /**
+         * Returns the list of sources.
+         * @return The list of sources
+         */
         public List<SourceEntry> get() {
 
@@ -1528,5 +1566,37 @@
             return Main.pref.putListOfStructs(pref, setting);
         }
-    }
-
+
+        /**
+         * Returns the set of active source URLs.
+         * @return The set of active source URLs.
+         */
+        public final Set<String> getActiveUrls() {
+            Set<String> urls = new HashSet<String>();
+            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
+     * @param component The tab component
+     * @since 6670
+     */
+    public final void deferLoading(final DefaultTabPreferenceSetting tab, final Component component) {
+        tab.getTabPane().addChangeListener(
+                new ChangeListener() {
+                    @Override
+                    public void stateChanged(ChangeEvent e) {
+                        if (tab.getTabPane().getSelectedComponent() == component) {
+                            SourceEditor.this.initiallyLoadAvailableSources();
+                        }
+                    }
+                }
+                );
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/preferences/SourceEntry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/SourceEntry.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/SourceEntry.java	(revision 6670)
@@ -50,6 +50,5 @@
 
     /**
-     * active is a boolean flag that can be used to turn the style on or off
-     * at runtime.
+     * active is a boolean flag that can be used to turn the source on or off at runtime.
      */
     public boolean active;
Index: trunk/src/org/openstreetmap/josm/gui/preferences/SourceType.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/SourceType.java	(revision 6670)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/SourceType.java	(revision 6670)
@@ -0,0 +1,15 @@
+// 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 6669)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/map/MapPaintPreference.java	(revision 6670)
@@ -26,4 +26,5 @@
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
 import org.openstreetmap.josm.gui.preferences.SourceEditor;
+import org.openstreetmap.josm.gui.preferences.SourceType;
 import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
 import org.openstreetmap.josm.gui.preferences.SourceEntry;
@@ -41,4 +42,9 @@
     private static final List<SourceProvider> styleSourceProviders = new ArrayList<SourceProvider>();
 
+    /**
+     * Registers a new additional style source provider.
+     * @param provider The style source provider
+     * @return {@code true}, if the provider has been added, {@code false} otherwise
+     */
     public static boolean registerSourceProvider(SourceProvider provider) {
         if (provider != null)
@@ -58,5 +64,5 @@
 
     @Override
-    public void addGui(final PreferenceTabbedPane gui) {
+    public void addGui(PreferenceTabbedPane gui) {
         enableIconDefault = new JCheckBox(tr("Enable built-in icon defaults"),
                 Main.pref.getBoolean("mappaint.icon.enable-defaults", true));
@@ -70,19 +76,7 @@
         panel.add(enableIconDefault, GBC.eol().insets(11,2,5,0));
 
-        gui.getMapPreference().addSubTab(this, tr("Map Paint Styles"), panel);
-
-        // this defers loading of style sources to the first time the tab
-        // with the map paint preferences is selected by the user
-        //
-        gui.getMapPreference().getTabPane().addChangeListener(
-                new ChangeListener() {
-                    @Override
-                    public void stateChanged(ChangeEvent e) {
-                        if (gui.getMapPreference().getTabPane().getSelectedComponent() == panel) {
-                            sources.initiallyLoadAvailableSources();
-                        }
-                    }
-                }
-                );
+        final MapPreference mapPref = gui.getMapPreference();
+        mapPref.addSubTab(this, tr("Map Paint Styles"), panel);
+        sources.deferLoading(mapPref, panel);
     }
 
@@ -92,5 +86,5 @@
 
         public MapPaintSourceEditor() {
-            super(true, Main.JOSM_WEBSITE+"/styles", styleSourceProviders);
+            super(SourceType.MAP_PAINT_STYLE, Main.JOSM_WEBSITE+"/styles", styleSourceProviders, true);
         }
 
@@ -186,4 +180,7 @@
     }
 
+    /**
+     * Helper class for map paint styles preferences.
+     */
     public static class MapPaintPrefHelper extends SourceEditor.SourcePrefHelper {
 
Index: trunk/src/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreference.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreference.java	(revision 6670)
@@ -35,4 +35,5 @@
 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;
@@ -67,4 +68,9 @@
     private JCheckBox sortMenu;
 
+    /**
+     * Registers a new additional preset source provider.
+     * @param provider The preset source provider
+     * @return {@code true}, if the provider has been added, {@code false} otherwise
+     */
     public static final boolean registerSourceProvider(SourceProvider provider) {
         if (provider != null)
@@ -161,5 +167,5 @@
 
     @Override
-    public void addGui(final PreferenceTabbedPane gui) {
+    public void addGui(PreferenceTabbedPane gui) {
         sortMenu = new JCheckBox(tr("Sort presets menu"),
                 Main.pref.getBoolean("taggingpreset.sortmenu", false));
@@ -170,19 +176,7 @@
         sources = new TaggingPresetSourceEditor();
         panel.add(sources, GBC.eol().fill(GBC.BOTH));
-        gui.getMapPreference().addSubTab(this, tr("Tagging Presets"), panel);
-
-        // this defers loading of tagging preset sources to the first time the tab
-        // with the tagging presets is selected by the user
-        //
-        gui.getMapPreference().getTabPane().addChangeListener(
-                new ChangeListener() {
-                    @Override
-                    public void stateChanged(ChangeEvent e) {
-                        if (gui.getMapPreference().getTabPane().getSelectedComponent() == panel) {
-                            sources.initiallyLoadAvailableSources();
-                        }
-                    }
-                }
-                );
+        final MapPreference mapPref = gui.getMapPreference();
+        mapPref.addSubTab(this, tr("Tagging Presets"), panel);
+        sources.deferLoading(mapPref, panel);
         gui.addValidationListener(validationListener);
     }
@@ -193,5 +187,5 @@
 
         public TaggingPresetSourceEditor() {
-            super(false, Main.JOSM_WEBSITE+"/presets", presetSourceProviders);
+            super(SourceType.TAGGING_PRESET, Main.JOSM_WEBSITE+"/presets", presetSourceProviders, true);
         }
 
@@ -274,11 +268,14 @@
     }
 
+    /**
+     * Initializes tagging presets from preferences.
+     */
     public static void readFromPreferences() {
         taggingPresets = TaggingPresetReader.readFromPreferences(false);
     }
 
-        /**
-         * Initialize the tagging presets (load and may display error)
-         */
+    /**
+     * Initialize the tagging presets (load and may display error)
+     */
     public static void initialize() {
         readFromPreferences();
@@ -315,4 +312,7 @@
     }
 
+    /**
+     * Helper class for tagging presets preferences.
+     */
     public static class PresetPrefHelper extends SourceEditor.SourcePrefHelper {
 
Index: trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTagCheckerRulesPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTagCheckerRulesPreference.java	(revision 6670)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTagCheckerRulesPreference.java	(revision 6670)
@@ -0,0 +1,209 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.preferences.validator;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+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 org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.validation.OsmValidator;
+import org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker;
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
+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;
+
+/**
+ * The general validator preferences, allowing to enable/disable tests.
+ * @since 6669
+ */
+public class ValidatorTagCheckerRulesPreference implements SubPreferenceSetting {
+
+    /**
+     * Factory used to create a new {@code ValidatorTagCheckerRulesPreference}.
+     */
+    public static class Factory implements PreferenceSettingFactory {
+        @Override
+        public PreferenceSetting createPreferenceSetting() {
+            return new ValidatorTagCheckerRulesPreference();
+        }
+    }
+
+    private static final List<SourceProvider> ruleSourceProviders = new ArrayList<SourceProvider>();
+
+    /**
+     * Registers a new additional rule source provider.
+     * @param provider The rule source provider
+     * @return {@code true}, if the provider has been added, {@code false} otherwise
+     */
+    public static final boolean registerSourceProvider(SourceProvider provider) {
+        if (provider != null)
+            return ruleSourceProviders.add(provider);
+        return false;
+    }
+    
+    static class TagCheckerRulesSourceEditor extends SourceEditor {
+
+        public TagCheckerRulesSourceEditor() {
+            super(SourceType.TAGCHECKER_RULE, Main.JOSM_WEBSITE+"/rules", ruleSourceProviders, false);
+        }
+
+        @Override
+        public Collection<? extends SourceEntry> getInitialSourcesList() {
+            return RulePrefHelper.INSTANCE.get();
+        }
+
+        @Override
+        public boolean finish() {
+            return RulePrefHelper.INSTANCE.put(activeSourcesModel.getSources());
+        }
+
+        @Override
+        public Collection<ExtendedSourceEntry> getDefault() {
+            return RulePrefHelper.INSTANCE.getDefault();
+        }
+
+        @Override
+        public Collection<String> getInitialIconPathsList() {
+            return null;
+        }
+
+        @Override
+        public String getStr(I18nString ident) {
+            switch (ident) {
+            case AVAILABLE_SOURCES:
+                return tr("Available rules:");
+            case ACTIVE_SOURCES:
+                return tr("Active rules:");
+            case NEW_SOURCE_ENTRY_TOOLTIP:
+                return tr("Add a new rule by entering filename or URL");
+            case NEW_SOURCE_ENTRY:
+                return tr("New rule entry:");
+            case REMOVE_SOURCE_TOOLTIP:
+                return tr("Remove the selected rules from the list of active rules");
+            case EDIT_SOURCE_TOOLTIP:
+                return tr("Edit the filename or URL for the selected active rule");
+            case ACTIVATE_TOOLTIP:
+                return tr("Add the selected available rules to the list of active rules");
+            case RELOAD_ALL_AVAILABLE:
+                return marktr("Reloads the list of available rules from ''{0}''");
+            case LOADING_SOURCES_FROM:
+                return marktr("Loading rule sources from ''{0}''");
+            case FAILED_TO_LOAD_SOURCES_FROM:
+                return marktr("<html>Failed to load the list of rule sources from<br>"
+                        + "''{0}''.<br>"
+                        + "<br>"
+                        + "Details (untranslated):<br>{1}</html>");
+            case FAILED_TO_LOAD_SOURCES_FROM_HELP_TOPIC:
+                return "/Preferences/Rules#FailedToLoadRuleSources";
+            case ILLEGAL_FORMAT_OF_ENTRY:
+                return marktr("Warning: illegal format of entry in rule list ''{0}''. Got ''{1}''");
+            default: throw new AssertionError();
+            }
+        }
+    }
+    
+    /**
+     * Helper class for validator tag checker rules preferences.
+     */
+    public static class RulePrefHelper extends SourceEditor.SourcePrefHelper {
+
+        /**
+         * The unique instance.
+         */
+        public final static 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<ExtendedSourceEntry>();
+            
+            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, "numeric",      tr("Numeric values"),      tr("Checks for wrong numeric values"));
+            addDefault(def, "power",        tr("Power"),               tr("Checks for errors on power infrastructures"));
+            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, "unnecessary",  tr("Unnecessary tags"),    tr("Checks for unnecessary tags"));
+            addDefault(def, "wikipedia",    tr("Wikipedia"),           tr("Checks for wrong wikipedia tags"));
+            
+            return def;
+        }
+        
+        private 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<String, String>();
+            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;
+
+    @Override
+    public void addGui(PreferenceTabbedPane gui) {
+        final ValidatorPreference valPref = gui.getValidatorPreference();
+        sources = new TagCheckerRulesSourceEditor();
+        
+        valPref.addSubTab(this, tr("Tag checker rules"),
+                sources, tr("Choose Tag checker rules to enable"));
+        sources.deferLoading(valPref, sources);
+    }
+
+    @Override
+    public boolean ok() {
+        if (sources.finish()) {
+            // Reload sources
+            MapCSSTagChecker tagChecker = OsmValidator.getTest(MapCSSTagChecker.class);
+            if (tagChecker != null) {
+                OsmValidator.initializeTests(Collections.singleton(tagChecker));
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean isExpert() {
+        return false;
+    }
+
+    @Override
+    public TabPreferenceSetting getTabPreferenceSetting(PreferenceTabbedPane gui) {
+        return gui.getValidatorPreference();
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTestsPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTestsPreference.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/validator/ValidatorTestsPreference.java	(revision 6670)
@@ -7,6 +7,8 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedList;
+import java.util.List;
 
 import javax.swing.BorderFactory;
@@ -18,4 +20,5 @@
 import org.openstreetmap.josm.data.validation.OsmValidator;
 import org.openstreetmap.josm.data.validation.Test;
+import org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker;
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
 import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
@@ -108,5 +111,11 @@
                 testsBeforeUpload.add(name);
         }
-        OsmValidator.initializeTests(allTests);
+        
+        // Initializes all tests but MapCSSTagChecker because it is initialized
+        // later in ValidatorTagCheckerRulesPreference.ok(),
+        // after its list of rules has been saved to preferences
+        List<Test> testsToInitialize = new ArrayList<Test>(allTests);
+        testsToInitialize.remove(OsmValidator.getTest(MapCSSTagChecker.class));
+        OsmValidator.initializeTests(testsToInitialize);
 
         Main.pref.putCollection(ValidatorPreference.PREF_SKIP_TESTS, tests);
Index: trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetReader.java	(revision 6669)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetReader.java	(revision 6670)
@@ -17,4 +17,5 @@
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.Stack;
 
@@ -22,5 +23,4 @@
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.preferences.SourceEntry;
 import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
 import org.openstreetmap.josm.io.MirroredInputStream;
@@ -41,18 +41,17 @@
     private static File zipIcons = null;
     
-    public static List<String> getPresetSources() {
-        LinkedList<String> sources = new LinkedList<String>();
-
-        for (SourceEntry e : (new TaggingPresetPreference.PresetPrefHelper()).get()) {
-            sources.add(e.url);
-        }
-
-        return sources;
-    }
-
     /**
-     * Holds a reference to a chunk of  items/objects.
+     * Returns the set of preset source URLs.
+     * @return The set of preset source URLs.
+     */
+    public static Set<String> getPresetSources() {
+        return new TaggingPresetPreference.PresetPrefHelper().getActiveUrls();
+    }
+
+    /**
+     * Holds a reference to a chunk of items/objects.
      */
     public static class Chunk {
+        /** The chunk id, can be referenced later */
         public String id;
     }
@@ -62,4 +61,5 @@
      */
     public static class Reference {
+        /** Reference matching a chunk id defined earlier **/
         public String ref;
     }
