Index: trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryProvidersPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryProvidersPanel.java	(revision 15115)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryProvidersPanel.java	(revision 15116)
@@ -59,4 +59,5 @@
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
 import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.gui.widgets.FilterField;
 import org.openstreetmap.josm.gui.widgets.HtmlPanel;
 import org.openstreetmap.josm.gui.widgets.JosmEditorPane;
@@ -78,4 +79,6 @@
     /** The table of default providers **/
     public final JTable defaultTable;
+    /** The filter of default providers **/
+    private final FilterField defaultFilter;
     /** The selection listener synchronizing map display with table of default providers **/
     private final transient DefListSelectionListener defaultTableListener;
@@ -159,5 +162,6 @@
             JLabel label = (JLabel) super.getTableCellRendererComponent(
                     table, mapper.apply(obj), isSelected, hasFocus, row, column);
-            GuiHelper.setBackgroundReadable(label, UIManager.getColor("Table.background"));
+            GuiHelper.setBackgroundReadable(label,
+                    isSelected ? UIManager.getColor("Table.selectionBackground") : UIManager.getColor("Table.background"));
             if (obj != null) {
                 label.setToolTipText(tooltip.apply(obj));
@@ -225,4 +229,6 @@
         defaultModel = new ImageryDefaultLayerTableModel();
         defaultTable = new JTable(defaultModel);
+        defaultTable.setAutoCreateRowSorter(true);
+        defaultFilter = new FilterField().filter(defaultTable, defaultModel);
 
         defaultModel.addTableModelListener(e -> activeTable.repaint());
@@ -251,7 +257,10 @@
 
         // Add default item list
+        JPanel defaultPane = new JPanel(new GridBagLayout());
         JScrollPane scrolldef = new JScrollPane(defaultTable);
         scrolldef.setPreferredSize(new Dimension(200, 200));
-        add(scrolldef, GBC.std().insets(0, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(1.0, 0.6).insets(5, 0, 0, 0));
+        defaultPane.add(defaultFilter, GBC.eol().insets(0, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL));
+        defaultPane.add(scrolldef, GBC.eol().insets(0, 0, 0, 0).fill(GridBagConstraints.BOTH));
+        add(defaultPane, GBC.std().fill(GridBagConstraints.BOTH).weight(1.0, 0.6).insets(5, 0, 0, 0));
 
         // Add default item map
@@ -268,5 +277,5 @@
         defaultMap.setZoomControlsVisible(false);
         defaultMap.setMinimumSize(new Dimension(100, 200));
-        add(defaultMap, GBC.std().insets(5, 5, 0, 0).fill(GridBagConstraints.BOTH).weight(0.33, 0.6).insets(5, 0, 0, 0));
+        add(defaultMap, GBC.std().fill(GridBagConstraints.BOTH).weight(0.33, 0.6).insets(5, 0, 0, 0));
 
         defaultTableListener = new DefListSelectionListener();
@@ -341,5 +350,5 @@
                 // Only process complete (final) selection events
                 for (int i = e.getFirstIndex(); i <= e.getLastIndex(); i++) {
-                    updateBoundsAndShapes(i);
+                    updateBoundsAndShapes(defaultTable.convertRowIndexToModel(i));
                 }
                 // If needed, adjust map to show all map rectangles and polygons
@@ -351,10 +360,15 @@
         }
 
+        /**
+         * update bounds and shapes for a new entry
+         * @param i model index
+         */
         private void updateBoundsAndShapes(int i) {
             ImageryBounds bounds = defaultModel.getRow(i).getBounds();
             if (bounds != null) {
+                int viewIndex = defaultTable.convertRowIndexToView(i);
                 List<Shape> shapes = bounds.getShapes();
                 if (shapes != null && !shapes.isEmpty()) {
-                    if (defaultTable.getSelectionModel().isSelectedIndex(i)) {
+                    if (defaultTable.getSelectionModel().isSelectedIndex(viewIndex)) {
                         if (!mapPolygons.containsKey(i)) {
                             List<MapPolygon> list = new ArrayList<>();
@@ -376,5 +390,5 @@
                     // Only display bounds when no polygons (shapes) are defined for this provider
                 } else {
-                    if (defaultTable.getSelectionModel().isSelectedIndex(i)) {
+                    if (defaultTable.getSelectionModel().isSelectedIndex(viewIndex)) {
                         if (!mapRectangles.containsKey(i)) {
                             // Add new map rectangle
Index: trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreference.java	(revision 15115)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreference.java	(revision 15116)
@@ -40,6 +40,4 @@
 import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
 
 import org.openstreetmap.josm.actions.ExpertToggleAction;
@@ -56,6 +54,6 @@
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.PreferencePanel;
 import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.gui.widgets.FilterField;
 import org.openstreetmap.josm.gui.widgets.JosmTextField;
-import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
 import org.openstreetmap.josm.plugins.PluginDownloadTask;
 import org.openstreetmap.josm.plugins.PluginInformation;
@@ -192,9 +190,9 @@
         gc.gridx = 1;
         gc.weightx = 1.0;
-        tfFilter = new JosmTextField();
+        tfFilter = new FilterField().filter(expr -> {
+            model.filterDisplayedPlugins(expr);
+            pnlPluginPreferences.refreshView();
+        });
         pnl.add(tfFilter, gc);
-        tfFilter.setToolTipText(tr("Enter a search expression"));
-        SelectAllOnFocusGainedDecorator.decorate(tfFilter);
-        tfFilter.getDocument().addDocumentListener(new SearchFieldAdapter());
         return pnl;
     }
@@ -565,33 +563,4 @@
     }
 
-    /**
-     * Applies the current filter condition in the filter text field to the model.
-     */
-    class SearchFieldAdapter implements DocumentListener {
-        private void filter() {
-            String expr = tfFilter.getText().trim();
-            if (expr.isEmpty()) {
-                expr = null;
-            }
-            model.filterDisplayedPlugins(expr);
-            pnlPluginPreferences.refreshView();
-        }
-
-        @Override
-        public void changedUpdate(DocumentEvent evt) {
-            filter();
-        }
-
-        @Override
-        public void insertUpdate(DocumentEvent evt) {
-            filter();
-        }
-
-        @Override
-        public void removeUpdate(DocumentEvent evt) {
-            filter();
-        }
-    }
-
     private static class PluginConfigurationSitesPanel extends JPanel {
 
Index: trunk/src/org/openstreetmap/josm/gui/preferences/shortcut/PrefJPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/preferences/shortcut/PrefJPanel.java	(revision 15115)
+++ trunk/src/org/openstreetmap/josm/gui/preferences/shortcut/PrefJPanel.java	(revision 15116)
@@ -16,9 +16,7 @@
 import java.awt.im.InputContext;
 import java.lang.reflect.Field;
-import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.regex.PatternSyntaxException;
 
 import javax.swing.AbstractAction;
@@ -33,9 +31,6 @@
 import javax.swing.KeyStroke;
 import javax.swing.ListSelectionModel;
-import javax.swing.RowFilter;
 import javax.swing.SwingConstants;
 import javax.swing.UIManager;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
@@ -43,12 +38,9 @@
 import javax.swing.table.DefaultTableCellRenderer;
 import javax.swing.table.TableColumnModel;
-import javax.swing.table.TableModel;
-import javax.swing.table.TableRowSorter;
 
 import org.openstreetmap.josm.data.preferences.NamedColorProperty;
 import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.gui.widgets.FilterField;
 import org.openstreetmap.josm.gui.widgets.JosmComboBox;
-import org.openstreetmap.josm.gui.widgets.JosmTextField;
-import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
 import org.openstreetmap.josm.tools.KeyboardUtils;
 import org.openstreetmap.josm.tools.Logging;
@@ -89,10 +81,10 @@
 
     private final JTable shortcutTable = new JTable();
-
-    private final JosmTextField filterField = new JosmTextField();
+    private final FilterField filterField;
 
     /** Creates new form prefJPanel */
     public PrefJPanel() {
         this.model = new ScListModel();
+        this.filterField = new FilterField();
         initComponents();
     }
@@ -207,4 +199,5 @@
         shortcutTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
         shortcutTable.setAutoCreateRowSorter(true);
+        filterField.filter(shortcutTable, model);
         TableColumnModel mod = shortcutTable.getColumnModel();
         mod.getColumn(0).setCellRenderer(new ShortcutTableCellRenderer(true));
@@ -268,7 +261,4 @@
         gc.weightx = 1.0;
         pnl.add(filterField, gc);
-        filterField.setToolTipText(tr("Enter a search expression"));
-        SelectAllOnFocusGainedDecorator.decorate(filterField);
-        filterField.getDocument().addDocumentListener(new FilterFieldAdapter());
         pnl.setMaximumSize(new Dimension(300, 10));
         return pnl;
@@ -372,45 +362,3 @@
         }
     }
-
-    class FilterFieldAdapter implements DocumentListener {
-        private void filter() {
-            String expr = filterField.getText().trim();
-            if (expr.isEmpty()) {
-                expr = null;
-            }
-            try {
-                final TableRowSorter<? extends TableModel> sorter =
-                    (TableRowSorter<? extends TableModel>) shortcutTable.getRowSorter();
-                if (expr == null) {
-                    sorter.setRowFilter(null);
-                } else {
-                    expr = expr.replace("+", "\\+");
-                    // split search string on whitespace, do case-insensitive AND search
-                    List<RowFilter<Object, Object>> andFilters = new ArrayList<>();
-                    for (String word : expr.split("\\s+")) {
-                        andFilters.add(RowFilter.regexFilter("(?i)" + word));
-                    }
-                    sorter.setRowFilter(RowFilter.andFilter(andFilters));
-                }
-                model.fireTableDataChanged();
-            } catch (PatternSyntaxException | ClassCastException ex) {
-                Logging.warn(ex);
-            }
-        }
-
-        @Override
-        public void changedUpdate(DocumentEvent e) {
-            filter();
-        }
-
-        @Override
-        public void insertUpdate(DocumentEvent e) {
-            filter();
-        }
-
-        @Override
-        public void removeUpdate(DocumentEvent e) {
-            filter();
-        }
-    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/widgets/FilterField.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/widgets/FilterField.java	(revision 15116)
+++ trunk/src/org/openstreetmap/josm/gui/widgets/FilterField.java	(revision 15116)
@@ -0,0 +1,127 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.widgets;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.PatternSyntaxException;
+
+import javax.swing.JTable;
+import javax.swing.RowFilter;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableRowSorter;
+
+import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.Utils;
+
+/**
+ * Text field allowing to filter contents.
+ * @since 15116
+ */
+public class FilterField extends JosmTextField {
+
+    /**
+     * Constructs a new {@code TableFilterField}.
+     */
+    public FilterField() {
+        setToolTipText(tr("Enter a search expression"));
+        SelectAllOnFocusGainedDecorator.decorate(this);
+    }
+
+    /**
+     * Defines the filter behaviour.
+     */
+    @FunctionalInterface
+    public interface FilterBehaviour {
+        /**
+         * Filters a component according to the given filter expression.
+         * @param expr filter expression
+         */
+        void filter(String expr);
+    }
+
+    /**
+     * Enables filtering of given table/model.
+     * @param table table to filter
+     * @param model table model
+     * @return {@code this} for easy chaining
+     */
+    public FilterField filter(JTable table, AbstractTableModel model) {
+        return filter(new TableFilterBehaviour(table, model));
+    }
+
+    /**
+     * Enables generic filtering.
+     * @param behaviour filter behaviour
+     * @return {@code this} for easy chaining
+     */
+    public FilterField filter(FilterBehaviour behaviour) {
+        getDocument().addDocumentListener(new FilterFieldAdapter(behaviour));
+        return this;
+    }
+
+    private static class TableFilterBehaviour implements FilterBehaviour {
+        private final JTable table;
+        private final AbstractTableModel model;
+
+        TableFilterBehaviour(JTable table, AbstractTableModel model) {
+            this.table = Objects.requireNonNull(table, "table");
+            this.model = Objects.requireNonNull(model, "model");
+            Objects.requireNonNull(table.getRowSorter(), "table.rowSorter");
+        }
+
+        @Override
+        public void filter(String expr) {
+            try {
+                final TableRowSorter<? extends TableModel> sorter =
+                    (TableRowSorter<? extends TableModel>) table.getRowSorter();
+                if (expr == null || expr.isEmpty()) {
+                    sorter.setRowFilter(null);
+                } else {
+                    expr = expr.replace("+", "\\+");
+                    // split search string on whitespace, do case-insensitive AND search
+                    List<RowFilter<Object, Object>> andFilters = new ArrayList<>();
+                    for (String word : expr.split("\\s+")) {
+                        andFilters.add(RowFilter.regexFilter("(?i)" + word));
+                    }
+                    sorter.setRowFilter(RowFilter.andFilter(andFilters));
+                }
+                model.fireTableDataChanged();
+            } catch (PatternSyntaxException | ClassCastException ex) {
+                Logging.warn(ex);
+            }
+        }
+    }
+
+    private class FilterFieldAdapter implements DocumentListener {
+        private final FilterBehaviour behaviour;
+
+        FilterFieldAdapter(FilterBehaviour behaviour) {
+            this.behaviour = Objects.requireNonNull(behaviour);
+        }
+
+        private void filter() {
+            behaviour.filter(Utils.strip(getText()));
+        }
+
+        @Override
+        public void changedUpdate(DocumentEvent e) {
+            filter();
+        }
+
+        @Override
+        public void insertUpdate(DocumentEvent e) {
+            filter();
+        }
+
+        @Override
+        public void removeUpdate(DocumentEvent e) {
+            filter();
+        }
+    }
+}
