Minor changes to comments, tests and examples

Signed-off-by: Dirk Fauth <dirk.fauth@googlemail.com>

Change-Id: If2fadc8174931fb4c2ea069c4e1c819215bb1702
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/filterrow/combobox/FilterRowComboBoxDataProvider.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/filterrow/combobox/FilterRowComboBoxDataProvider.java
index 62837ef..75369f0 100644
--- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/filterrow/combobox/FilterRowComboBoxDataProvider.java
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/filterrow/combobox/FilterRowComboBoxDataProvider.java
@@ -452,6 +452,11 @@
         // should never reach here. But in case someone fires
         // FilterAppliedEvents programmatically from the body layer stack, we
         // need to guard the execution to avoid exceptions.
+        // Note:
+        // The FilterAppliedEvent is handled in a LayerListener instead of a
+        // dedicated ILayerEventHandler as there can only be one
+        // ILayerEventHandler registered per layer, which could interfere with
+        // user code.
         if (event instanceof FilterAppliedEvent && this.filterCollection != null) {
             // only update the last applied filter column if
             // - the editor is a FilterRowComboBoxCellEditor
diff --git a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_800_Integration/_818_SortableAllFilterPerformanceColumnGroupExample.java b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_800_Integration/_818_SortableAllFilterPerformanceColumnGroupExample.java
index 5699dbe..b5d7051 100644
--- a/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_800_Integration/_818_SortableAllFilterPerformanceColumnGroupExample.java
+++ b/org.eclipse.nebula.widgets.nattable.examples/src/org/eclipse/nebula/widgets/nattable/examples/_800_Integration/_818_SortableAllFilterPerformanceColumnGroupExample.java
@@ -27,6 +27,7 @@
 import org.eclipse.jface.fieldassist.TextContentAdapter;
 import org.eclipse.jface.layout.GridDataFactory;
 import org.eclipse.nebula.widgets.nattable.NatTable;
+import org.eclipse.nebula.widgets.nattable.columnChooser.command.DisplayColumnChooserCommandHandler;
 import org.eclipse.nebula.widgets.nattable.config.AbstractRegistryConfiguration;
 import org.eclipse.nebula.widgets.nattable.config.AbstractUiBindingConfiguration;
 import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes;
@@ -62,6 +63,7 @@
 import org.eclipse.nebula.widgets.nattable.extension.glazedlists.filterrow.ComboBoxFilterRowHeaderComposite;
 import org.eclipse.nebula.widgets.nattable.extension.glazedlists.filterrow.ComboBoxGlazedListsWithExcludeFilterStrategy;
 import org.eclipse.nebula.widgets.nattable.extension.glazedlists.filterrow.FilterRowUtils;
+import org.eclipse.nebula.widgets.nattable.extension.glazedlists.filterrow.GlazedListsFilterRowComboBoxDataProvider;
 import org.eclipse.nebula.widgets.nattable.extension.nebula.richtext.MarkupDisplayConverter;
 import org.eclipse.nebula.widgets.nattable.extension.nebula.richtext.RegexMarkupValue;
 import org.eclipse.nebula.widgets.nattable.extension.nebula.richtext.RichTextCellPainter;
@@ -275,17 +277,8 @@
         // distincts the empty string and null from the collected values. This
         // way null and "" entries in the collection are treated the same way
         // and there is only a single "empty" entry in the dropdown.
-
-        // Note:
-        // The usage of the GlazedListsFilterRowComboBoxDataProvider is not
-        // useful in combination with combobox filters that collect the contents
-        // from the filter list. Sort operations for example are also list
-        // changes that would cause clearing the caches and inserting values in
-        // the background to the list would not be able to determine changes as
-        // the new rows are not part of the previous remembered collection
-        // state.
         FilterRowComboBoxDataProvider<PersonWithAddress> filterRowComboBoxDataProvider =
-                new FilterRowComboBoxDataProvider<>(
+                new GlazedListsFilterRowComboBoxDataProvider<>(
                         bodyLayerStack.getGlazedListsEventLayer(),
                         bodyLayerStack.getSortedList(),
                         columnPropertyAccessor);
@@ -409,6 +402,7 @@
                 return new PopupMenuBuilder(natTable)
                         .withHideColumnMenuItem()
                         .withShowAllColumnsMenuItem()
+                        .withColumnChooserMenuItem()
                         .withCreateColumnGroupMenuItem()
                         .withUngroupColumnsMenuItem()
                         .withAutoResizeSelectedColumnsMenuItem()
@@ -445,6 +439,18 @@
                 filterRowHeaderLayer.getFilterRowDataLayer().getFilterRowDataProvider()));
 
         natTable.addConfiguration(new ScalingUiBindingConfiguration(natTable));
+
+        // Register column chooser
+        DisplayColumnChooserCommandHandler columnChooserCommandHandler =
+                new DisplayColumnChooserCommandHandler(
+                        bodyLayerStack.getColumnHideShowLayer(),
+                        columnHeaderLayer,
+                        columnHeaderDataLayer,
+                        columnGroupHeaderLayer,
+                        false);
+
+        bodyLayerStack.registerCommandHandler(columnChooserCommandHandler);
+
         natTable.configure();
 
         // The painter instances in a theme configuration are created on demand
@@ -609,6 +615,33 @@
             }
         });
 
+        Button replaceContentButton = new Button(buttonPanel, SWT.PUSH);
+        replaceContentButton.setText("Replace");
+        replaceContentButton.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                Address address1 = new Address();
+                address1.setStreet("Some Street");
+                address1.setHousenumber(42);
+                address1.setPostalCode(12345);
+                address1.setCity("In the clouds");
+                PersonWithAddress ralph = new PersonWithAddress(42, "Ralph",
+                        "Wiggum", Gender.MALE, false, new Date(), address1);
+
+                Address address2 = new Address();
+                address2.setStreet("Evergreen Terrace");
+                address2.setHousenumber(742);
+                address2.setPostalCode(54321);
+                address2.setCity("Springfield");
+                PersonWithAddress lisa = new PersonWithAddress(23, "Lisa",
+                        "Simpson", Gender.FEMALE, false, new Date(), address2);
+
+                bodyLayerStack.getSortedList().clear();
+                bodyLayerStack.getSortedList().add(ralph);
+                bodyLayerStack.getSortedList().add(lisa);
+            }
+        });
+
         return container;
     }
 
@@ -769,6 +802,8 @@
         private final DataLayer bodyDataLayer;
         private final GlazedListsEventLayer<T> glazedListsEventLayer;
 
+        private final ColumnHideShowLayer columnHideShowLayer;
+
         private final SelectionLayer selectionLayer;
 
         public BodyLayerStack(List<T> values, IColumnPropertyAccessor<T> columnPropertyAccessor) {
@@ -793,10 +828,10 @@
                     new GlazedListsEventLayer<>(this.bodyDataLayer, this.filterList);
 
             ColumnReorderLayer reorderLayer = new ColumnReorderLayer(this.glazedListsEventLayer);
-            ColumnHideShowLayer hideShowLayer = new ColumnHideShowLayer(reorderLayer);
+            this.columnHideShowLayer = new ColumnHideShowLayer(reorderLayer);
 
             ColumnGroupExpandCollapseLayer columnGroupExpandCollapseLayer =
-                    new ColumnGroupExpandCollapseLayer(hideShowLayer);
+                    new ColumnGroupExpandCollapseLayer(this.columnHideShowLayer);
 
             this.selectionLayer = new SelectionLayer(columnGroupExpandCollapseLayer);
             ViewportLayer viewportLayer = new ViewportLayer(this.selectionLayer);
@@ -831,6 +866,10 @@
         public GlazedListsEventLayer<T> getGlazedListsEventLayer() {
             return this.glazedListsEventLayer;
         }
+
+        public ColumnHideShowLayer getColumnHideShowLayer() {
+            return this.columnHideShowLayer;
+        }
     }
 
     /**
diff --git a/org.eclipse.nebula.widgets.nattable.extension.glazedlists.test/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/filterrow/MixedComboBoxFilterRowHeaderIntegrationTest.java b/org.eclipse.nebula.widgets.nattable.extension.glazedlists.test/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/filterrow/MixedComboBoxFilterRowHeaderIntegrationTest.java
index 0350ac2..ec56e42 100644
--- a/org.eclipse.nebula.widgets.nattable.extension.glazedlists.test/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/filterrow/MixedComboBoxFilterRowHeaderIntegrationTest.java
+++ b/org.eclipse.nebula.widgets.nattable.extension.glazedlists.test/src/org/eclipse/nebula/widgets/nattable/extension/glazedlists/filterrow/MixedComboBoxFilterRowHeaderIntegrationTest.java
@@ -1392,10 +1392,9 @@
                 "all values selected");
     }
 
-    // the combination of listchanges = true and caching = true will fail
-    // this is because sorting is a list change which causes clearing the cache
     @ParameterizedTest(name = "listchanges={0}, caching={1}")
     @CsvSource({
+            "true, true",
             "true, false",
             "false, true",
             "false, false"