Index: /trunk/src/org/openstreetmap/josm/data/osm/FilterModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/FilterModel.java	(revision 18555)
+++ /trunk/src/org/openstreetmap/josm/data/osm/FilterModel.java	(revision 18556)
@@ -7,4 +7,5 @@
 import java.awt.Graphics2D;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -234,4 +235,16 @@
 
     /**
+     * Adds new filters to the filter list.
+     * @param newFilters The new filters
+     * @return true (as specified by {@link Collection#add})
+     * @since 18556
+     */
+    public boolean addFilters(Filter... newFilters) {
+        boolean filtersChanged = filters.addAll(Arrays.asList(newFilters));
+        updateFilterMatcher();
+        return filtersChanged;
+    }
+
+    /**
      * Moves the filters in the given rows by a number of positions.
      * @param delta negative or positive increment
@@ -270,7 +283,27 @@
      * @param rowIndex The index of the filter to remove
      * @return the filter previously at the specified position
+     * @see #removeFilters(int...) for bulk removal
      */
     public Filter removeFilter(int rowIndex) {
         Filter result = filters.remove(rowIndex);
+        updateFilterMatcher();
+        return result;
+    }
+
+    /**
+     * Removes the filters that are displayed in the given rows
+     * @param rowIndexes The indexes of the filters to remove
+     * @return the filters previously at the specified positions
+     * @since 18556
+     */
+    public Collection<Filter> removeFilters(int... rowIndexes) {
+        // Ensure that the indexes are sorted so we can go through them in reverse
+        Arrays.sort(rowIndexes);
+        List<Filter> result = new ArrayList<>(rowIndexes.length);
+        for (int i = rowIndexes.length - 1; i >= 0; i--) {
+            result.add(filters.remove(i));
+        }
+        // Reverse the list so that users can iterate through the filters in the order that they were in the model.
+        Collections.reverse(result);
         updateFilterMatcher();
         return result;
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/FilterDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/FilterDialog.java	(revision 18555)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/FilterDialog.java	(revision 18556)
@@ -176,8 +176,5 @@
         @Override
         public void actionPerformed(ActionEvent e) {
-            int index = filterModel.getSelectionModel().getMinSelectionIndex();
-            if (index >= 0) {
-                filterModel.removeFilter(index);
-            }
+            filterModel.removeFilters(filterModel.getSelectedIndices());
         }
     }
@@ -190,8 +187,5 @@
         @Override
         public void actionPerformed(ActionEvent e) {
-            int index = userTable.convertRowIndexToModel(userTable.getSelectionModel().getMinSelectionIndex());
-            if (index >= 0 && filterModel.moveUp(index)) {
-                filterModel.getSelectionModel().setSelectionInterval(index-1, index-1);
-            }
+            filterModel.moveUp();
         }
 
@@ -209,8 +203,5 @@
         @Override
         public void actionPerformed(ActionEvent e) {
-            int index = userTable.convertRowIndexToModel(userTable.getSelectionModel().getMinSelectionIndex());
-            if (index >= 0 && filterModel.moveDown(index)) {
-                filterModel.getSelectionModel().setSelectionInterval(index+1, index+1);
-            }
+            filterModel.moveDown();
         }
 
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/FilterTableModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/FilterTableModel.java	(revision 18555)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/FilterTableModel.java	(revision 18556)
@@ -6,4 +6,5 @@
 
 import java.awt.Graphics2D;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
@@ -21,4 +22,5 @@
 import org.openstreetmap.josm.gui.widgets.OSDLabel;
 import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.Utils;
 
 /**
@@ -134,7 +136,22 @@
      * Adds a new filter to the filter list.
      * @param filter The new filter
+     * @see #addFilters(Filter...) for bulk addition
      */
     public void addFilter(Filter filter) {
         if (model.addFilter(filter)) {
+            savePrefs();
+            updateFilters();
+            int size = model.getFiltersCount();
+            fireTableRowsInserted(size - 1, size - 1);
+        }
+    }
+
+    /**
+     * Adds a new filter to the filter list.
+     * @param filters The new filter
+     * @since 18556
+     */
+    public void addFilters(Filter... filters) {
+        if (model.addFilters(filters)) {
             savePrefs();
             updateFilters();
@@ -166,10 +183,29 @@
      * Removes the filter that is displayed in the given row
      * @param rowIndex The index of the filter to remove
+     * @see #removeFilters(int...)
      */
     public void removeFilter(int rowIndex) {
-        if (model.removeFilter(rowIndex) != null) {
+        this.removeFilters(rowIndex);
+    }
+
+    /**
+     * Removes the filters that is displayed in the given rows
+     * @param rowIndexes The indexes of the filters to remove
+     * @since 18556
+     */
+    public void removeFilters(int... rowIndexes) {
+        // Ensure that the indexes are sorted so we can go through
+        // them in reverse
+        Arrays.sort(rowIndexes);
+        boolean modified = !model.removeFilters(rowIndexes).isEmpty();
+        if (modified) {
             savePrefs();
             updateFilters();
-            fireTableRowsDeleted(rowIndex, rowIndex);
+            int[][] groupedRows = Utils.groupIntegers(rowIndexes);
+            // Reverse to avoid having to deal with offsets in client code
+            for (int i = groupedRows.length - 1; i >= 0; i--) {
+                int[] rows = groupedRows[i];
+                fireTableRowsDeleted(rows[0], rows[1]);
+            }
         }
     }
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java	(revision 18555)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java	(revision 18556)
@@ -308,5 +308,5 @@
         final ListSelectionModel selectionModel = getSelectionModel();
         selectionModel.setValueIsAdjusting(true);
-        for (int[] row : groupRows(selectedRows)) {
+        for (int[] row : Utils.groupIntegers(selectedRows)) {
             if (members.size() > row[0] - offset) {
                 // Remove (inclusive)
@@ -318,32 +318,4 @@
         selectionModel.setValueIsAdjusting(false);
         fireTableDataChanged();
-    }
-
-    /**
-     * Group rows for use in changing selection intervals, to avoid many small calls on large selections
-     * @param rows The rows to group
-     * @return A list of grouped rows, [lower, higher] (inclusive)
-     */
-    private static List<int[]> groupRows(int... rows) {
-        if (rows.length == 0) {
-            return Collections.emptyList();
-        }
-        List<int[]> groups = new ArrayList<>();
-        int[] current = {Integer.MIN_VALUE, Integer.MIN_VALUE};
-        groups.add(current);
-        for (int row : rows) {
-            if (current[0] == Integer.MIN_VALUE) {
-                current[0] = row;
-                current[1] = row;
-                continue;
-            }
-            if (current[1] == row - 1) {
-                current[1] = row;
-            } else {
-                current = new int[] {row, row};
-                groups.add(current);
-            }
-        }
-        return Collections.unmodifiableList(groups);
     }
 
@@ -489,5 +461,5 @@
             final int tIdx = idx;
             // Avoiding many addSelectionInterval calls is critical for performance.
-            for (int[] row : groupRows(IntStream.of(originalSelection).map(i -> i < index ? i : i + tIdx - index).toArray())) {
+            for (int[] row : Utils.groupIntegers(IntStream.of(originalSelection).map(i -> i < index ? i : i + tIdx - index).toArray())) {
                 model.addSelectionInterval(row[0], row[1]);
             }
Index: /trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 18555)
+++ /trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 18556)
@@ -82,4 +82,5 @@
     private static final long MILLIS_OF_HOUR = TimeUnit.HOURS.toMillis(1);
     private static final long MILLIS_OF_DAY = TimeUnit.DAYS.toMillis(1);
+    private static final int[][] EMPTY_INT_INT_ARRAY = new int[0][];
 
     /**
@@ -1340,4 +1341,36 @@
 
         return Math.sqrt(standardDeviation / values.length);
+    }
+
+    /**
+     * Group a list of integers, mostly useful to avoid calling many selection change events
+     * for a logical interval.
+     * <br>
+     * Example: {@code groupIntegers(1, 2, 3, 5, 6, 7, 8, 9)} becomes {@code [[1, 3], [5, 9]]}
+     * @param integers The integers to group
+     * @return The integers grouped into logical blocks, [lower, higher] (inclusive)
+     * @since 18556
+     */
+    public static int[][] groupIntegers(int... integers) {
+        if (integers.length == 0) {
+            return EMPTY_INT_INT_ARRAY;
+        }
+        List<int[]> groups = new ArrayList<>();
+        int[] current = {Integer.MIN_VALUE, Integer.MIN_VALUE};
+        groups.add(current);
+        for (int row : integers) {
+            if (current[0] == Integer.MIN_VALUE) {
+                current[0] = row;
+                current[1] = row;
+                continue;
+            }
+            if (current[1] == row - 1) {
+                current[1] = row;
+            } else {
+                current = new int[] {row, row};
+                groups.add(current);
+            }
+        }
+        return groups.toArray(EMPTY_INT_INT_ARRAY);
     }
 
