Bug 581534 - Performance grouping: incorrect group states with freeze

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

Change-Id: I821275b8060fb7f940389e82ba877db1797982e0
diff --git a/org.eclipse.nebula.widgets.nattable.core/META-INF/MANIFEST.MF b/org.eclipse.nebula.widgets.nattable.core/META-INF/MANIFEST.MF
index a68fe83..860069c 100644
--- a/org.eclipse.nebula.widgets.nattable.core/META-INF/MANIFEST.MF
+++ b/org.eclipse.nebula.widgets.nattable.core/META-INF/MANIFEST.MF
@@ -87,6 +87,7 @@
  org.eclipse.nebula.widgets.nattable.group.performance.action;version="2.1.0",
  org.eclipse.nebula.widgets.nattable.group.performance.command;version="2.1.0",
  org.eclipse.nebula.widgets.nattable.group.performance.config;version="2.1.0",
+ org.eclipse.nebula.widgets.nattable.group.performance.event;version="2.1.0",
  org.eclipse.nebula.widgets.nattable.group.performance.gui;version="2.1.0",
  org.eclipse.nebula.widgets.nattable.group.performance.painter;version="2.1.0",
  org.eclipse.nebula.widgets.nattable.hideshow;version="2.1.0",
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/ColumnGroupExpandCollapseLayer.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/ColumnGroupExpandCollapseLayer.java
index e5ea1e8..e42a65e 100644
--- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/ColumnGroupExpandCollapseLayer.java
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/ColumnGroupExpandCollapseLayer.java
@@ -27,9 +27,10 @@
 import org.eclipse.nebula.widgets.nattable.group.performance.command.ColumnGroupCollapseCommand;
 import org.eclipse.nebula.widgets.nattable.group.performance.command.ColumnGroupExpandCommand;
 import org.eclipse.nebula.widgets.nattable.group.performance.command.UpdateColumnGroupCollapseCommand;
+import org.eclipse.nebula.widgets.nattable.group.performance.event.ColumnGroupCollapseEvent;
+import org.eclipse.nebula.widgets.nattable.group.performance.event.ColumnGroupExpandEvent;
 import org.eclipse.nebula.widgets.nattable.hideshow.AbstractColumnHideShowLayer;
 import org.eclipse.nebula.widgets.nattable.hideshow.event.HideColumnPositionsEvent;
-import org.eclipse.nebula.widgets.nattable.hideshow.event.ShowColumnPositionsEvent;
 import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer;
 import org.eclipse.nebula.widgets.nattable.layer.event.VisualRefreshEvent;
 import org.eclipse.nebula.widgets.nattable.util.ArrayUtil;
@@ -72,7 +73,7 @@
 
             if (!shownIndexes.isEmpty()) {
                 invalidateCache();
-                fireLayerEvent(new ShowColumnPositionsEvent(this, getColumnPositionsByIndexes(shownIndexes.toArray())));
+                fireLayerEvent(new ColumnGroupExpandEvent(this, getColumnPositionsByIndexes(shownIndexes.toArray())));
             } else {
                 fireLayerEvent(new VisualRefreshEvent(this));
             }
@@ -107,15 +108,16 @@
                 }
 
                 modifyForVisible(group, columnIndexes);
-                this.hidden.put(group, columnIndexes);
 
                 hiddenPositions.addAll(getColumnPositionsByIndexes(columnIndexes.toArray()));
                 hiddenIndexes.addAll(columnIndexes);
+
+                this.hidden.put(group, columnIndexes);
             }
 
             if (!hiddenPositions.isEmpty()) {
                 invalidateCache();
-                fireLayerEvent(new HideColumnPositionsEvent(this, hiddenPositions.toArray(), hiddenIndexes.toArray()));
+                fireLayerEvent(new ColumnGroupCollapseEvent(this, hiddenPositions.toArray(), hiddenIndexes.toArray()));
             } else {
                 fireLayerEvent(new VisualRefreshEvent(this));
             }
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/ColumnGroupHeaderLayer.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/ColumnGroupHeaderLayer.java
index 7e42480..b3e6674 100644
--- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/ColumnGroupHeaderLayer.java
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/ColumnGroupHeaderLayer.java
@@ -47,6 +47,7 @@
 import org.eclipse.nebula.widgets.nattable.group.performance.command.UpdateColumnGroupCollapseCommand;
 import org.eclipse.nebula.widgets.nattable.group.performance.config.DefaultColumnGroupHeaderLayerConfiguration;
 import org.eclipse.nebula.widgets.nattable.group.performance.config.GroupHeaderConfigLabels;
+import org.eclipse.nebula.widgets.nattable.group.performance.event.ColumnGroupCollapseEvent;
 import org.eclipse.nebula.widgets.nattable.group.performance.painter.ColumnGroupHeaderGridLineCellLayerPainter;
 import org.eclipse.nebula.widgets.nattable.layer.AbstractLayerTransform;
 import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
@@ -875,7 +876,9 @@
             int level = getLevelForRowPosition(rowPosition);
             Group group = getGroupByPosition(level, columnPosition);
             if (group != null) {
-                int start = convertColumnPositionUpwards(getPositionLayer().getColumnPositionByIndex(group.getVisibleStartIndex()));
+                int start = this.compositeFreezeLayer == null
+                        ? convertColumnPositionUpwards(getPositionLayer().getColumnPositionByIndex(group.getVisibleStartIndex()))
+                        : this.compositeFreezeLayer.getColumnPositionByIndex(group.getVisibleStartIndex());
 
                 // check if there is a level above that does not have a group
                 int row = rowPosition;
@@ -930,7 +933,9 @@
                 }
 
                 if (subGroup != null) {
-                    int start = convertColumnPositionUpwards(getPositionLayer().getColumnPositionByIndex(subGroup.getVisibleStartIndex()));
+                    int start = this.compositeFreezeLayer == null
+                            ? convertColumnPositionUpwards(getPositionLayer().getColumnPositionByIndex(subGroup.getVisibleStartIndex()))
+                            : this.compositeFreezeLayer.getColumnPositionByIndex(subGroup.getVisibleStartIndex());
                     int columnSpan = getColumnSpan(subGroup);
 
                     // if the header should be shown always, e.g. because of
@@ -2334,8 +2339,9 @@
                         // check. reason is that the ranges are modified to be
                         // always in a valid range, and that could cause a loss
                         // of hidden positions on conversion
-                        if (event instanceof ColumnStructuralChangeEvent
-                                && ((ColumnStructuralChangeEvent) event).getColumnIndexes().length > deletedPositions.length) {
+                        if ((event instanceof ColumnGroupCollapseEvent)
+                                || (event instanceof ColumnStructuralChangeEvent
+                                        && ((ColumnStructuralChangeEvent) event).getColumnIndexes().length > deletedPositions.length)) {
                             // this triggers a consistency check
                             handleDeleteDiffs(new int[0]);
                         } else {
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/RowGroupExpandCollapseLayer.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/RowGroupExpandCollapseLayer.java
index 196a53e..f632d8f 100644
--- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/RowGroupExpandCollapseLayer.java
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/RowGroupExpandCollapseLayer.java
@@ -28,9 +28,10 @@
 import org.eclipse.nebula.widgets.nattable.group.performance.command.RowGroupCollapseCommand;
 import org.eclipse.nebula.widgets.nattable.group.performance.command.RowGroupExpandCommand;
 import org.eclipse.nebula.widgets.nattable.group.performance.command.UpdateRowGroupCollapseCommand;
+import org.eclipse.nebula.widgets.nattable.group.performance.event.RowGroupCollapseEvent;
+import org.eclipse.nebula.widgets.nattable.group.performance.event.RowGroupExpandEvent;
 import org.eclipse.nebula.widgets.nattable.hideshow.AbstractRowHideShowLayer;
 import org.eclipse.nebula.widgets.nattable.hideshow.event.HideRowPositionsEvent;
-import org.eclipse.nebula.widgets.nattable.hideshow.event.ShowRowPositionsEvent;
 import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer;
 import org.eclipse.nebula.widgets.nattable.layer.event.VisualRefreshEvent;
 import org.eclipse.nebula.widgets.nattable.util.ArrayUtil;
@@ -73,7 +74,7 @@
 
             if (!shownIndexes.isEmpty()) {
                 invalidateCache();
-                fireLayerEvent(new ShowRowPositionsEvent(this, getRowPositionsByIndexes(shownIndexes.toArray())));
+                fireLayerEvent(new RowGroupExpandEvent(this, getRowPositionsByIndexes(shownIndexes.toArray())));
             } else {
                 fireLayerEvent(new VisualRefreshEvent(this));
             }
@@ -108,15 +109,16 @@
                 }
 
                 modifyForVisible(group, rowIndexes);
-                this.hidden.put(group, rowIndexes);
 
                 hiddenPositions.addAll(getRowPositionsByIndexes(rowIndexes.toArray()));
                 hiddenIndexes.addAll(rowIndexes);
+
+                this.hidden.put(group, rowIndexes);
             }
 
             if (!hiddenPositions.isEmpty()) {
                 invalidateCache();
-                fireLayerEvent(new HideRowPositionsEvent(this, hiddenPositions.toArray(), hiddenIndexes.toArray()));
+                fireLayerEvent(new RowGroupCollapseEvent(this, hiddenPositions.toArray(), hiddenIndexes.toArray()));
             } else {
                 fireLayerEvent(new VisualRefreshEvent(this));
             }
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/RowGroupHeaderLayer.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/RowGroupHeaderLayer.java
index 660c470..09bd6a1 100644
--- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/RowGroupHeaderLayer.java
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/RowGroupHeaderLayer.java
@@ -47,6 +47,7 @@
 import org.eclipse.nebula.widgets.nattable.group.performance.command.UpdateRowGroupCollapseCommand;
 import org.eclipse.nebula.widgets.nattable.group.performance.config.DefaultRowGroupHeaderLayerConfiguration;
 import org.eclipse.nebula.widgets.nattable.group.performance.config.GroupHeaderConfigLabels;
+import org.eclipse.nebula.widgets.nattable.group.performance.event.RowGroupCollapseEvent;
 import org.eclipse.nebula.widgets.nattable.group.performance.painter.RowGroupHeaderGridLineCellLayerPainter;
 import org.eclipse.nebula.widgets.nattable.layer.AbstractLayerTransform;
 import org.eclipse.nebula.widgets.nattable.layer.ILayer;
@@ -868,7 +869,9 @@
             int level = getLevelForColumnPosition(columnPosition);
             Group group = getGroupByPosition(level, rowPosition);
             if (group != null) {
-                int start = convertRowPositionUpwards(getPositionLayer().getRowPositionByIndex(group.getVisibleStartIndex()));
+                int start = this.compositeFreezeLayer == null
+                        ? convertRowPositionUpwards(getPositionLayer().getRowPositionByIndex(group.getVisibleStartIndex()))
+                        : this.compositeFreezeLayer.getRowPositionByIndex(group.getVisibleStartIndex());
 
                 // check if there is a level above that does not have a group
                 int column = columnPosition;
@@ -923,7 +926,9 @@
                 }
 
                 if (subGroup != null) {
-                    int start = convertRowPositionUpwards(getPositionLayer().getRowPositionByIndex(subGroup.getVisibleStartIndex()));
+                    int start = this.compositeFreezeLayer == null
+                            ? convertRowPositionUpwards(getPositionLayer().getRowPositionByIndex(subGroup.getVisibleStartIndex()))
+                            : this.compositeFreezeLayer.getRowPositionByIndex(subGroup.getVisibleStartIndex());
                     int rowSpan = getRowSpan(subGroup);
 
                     // if the header should be shown always, e.g. because of
@@ -2325,8 +2330,9 @@
                         // check. reason is that the ranges are modified to be
                         // always in a valid range, and that could cause a loss
                         // of hidden positions on conversion
-                        if (event instanceof RowStructuralChangeEvent
-                                && ((RowStructuralChangeEvent) event).getRowIndexes().length > deletedPositions.length) {
+                        if ((event instanceof RowGroupCollapseEvent)
+                                || (event instanceof RowStructuralChangeEvent
+                                        && ((RowStructuralChangeEvent) event).getRowIndexes().length > deletedPositions.length)) {
                             // this triggers a consistency check
                             handleDeleteDiffs(new int[0]);
                         } else {
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/event/ColumnGroupCollapseEvent.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/event/ColumnGroupCollapseEvent.java
new file mode 100644
index 0000000..2b20741
--- /dev/null
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/event/ColumnGroupCollapseEvent.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Original authors and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Original authors and others - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.nebula.widgets.nattable.group.performance.event;
+
+import java.util.Collection;
+
+import org.eclipse.nebula.widgets.nattable.hideshow.event.HideColumnPositionsEvent;
+import org.eclipse.nebula.widgets.nattable.layer.ILayer;
+
+/**
+ * Specialization of the {@link HideColumnPositionsEvent}. Mainly used to inform
+ * about hidden columns but avoid handling it in the ColumnGroupHeaderLayer.
+ *
+ * @since 2.1
+ */
+public class ColumnGroupCollapseEvent extends HideColumnPositionsEvent {
+
+    /**
+     * Creates a new ColumnGroupCollapseEvent based on the given information.
+     *
+     * @param layer
+     *            The ILayer to which the given column positions match.
+     * @param columnPositions
+     *            The positions of the columns that have changed.
+     */
+    public ColumnGroupCollapseEvent(ILayer layer, Collection<Integer> columnPositions) {
+        super(layer, columnPositions);
+    }
+
+    /**
+     * Creates a new ColumnGroupCollapseEvent based on the given information.
+     *
+     * @param layer
+     *            The ILayer to which the given column positions match.
+     * @param columnPositions
+     *            The positions of the columns that have changed.
+     */
+    public ColumnGroupCollapseEvent(ILayer layer, int... columnPositions) {
+        super(layer, columnPositions);
+    }
+
+    /**
+     * Creates a new ColumnGroupCollapseEvent based on the given information.
+     *
+     * @param layer
+     *            The ILayer to which the given column positions match.
+     * @param columnPositions
+     *            The positions of the columns that have changed.
+     * @param columnIndexes
+     *            The indexes of the columns that have changed.
+     */
+    public ColumnGroupCollapseEvent(ILayer layer, Collection<Integer> columnPositions, Collection<Integer> columnIndexes) {
+        super(layer, columnPositions, columnIndexes);
+    }
+
+    /**
+     * Creates a new ColumnGroupCollapseEvent based on the given information.
+     *
+     * @param layer
+     *            The ILayer to which the given column positions match.
+     * @param columnPositions
+     *            The positions of the columns that have changed.
+     * @param columnIndexes
+     *            The indexes of the columns that have changed.
+     */
+    public ColumnGroupCollapseEvent(ILayer layer, int[] columnPositions, int[] columnIndexes) {
+        super(layer, columnPositions, columnIndexes);
+    }
+
+    /**
+     * Clone constructor.
+     *
+     * @param event
+     *            The event to clone.
+     */
+    protected ColumnGroupCollapseEvent(ColumnGroupCollapseEvent event) {
+        super(event);
+    }
+
+    @Override
+    public ColumnGroupCollapseEvent cloneEvent() {
+        return new ColumnGroupCollapseEvent(this);
+    }
+
+}
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/event/ColumnGroupExpandEvent.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/event/ColumnGroupExpandEvent.java
new file mode 100644
index 0000000..eaaceca
--- /dev/null
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/event/ColumnGroupExpandEvent.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Original authors and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Original authors and others - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.nebula.widgets.nattable.group.performance.event;
+
+import java.util.Collection;
+
+import org.eclipse.nebula.widgets.nattable.hideshow.event.ShowColumnPositionsEvent;
+import org.eclipse.nebula.widgets.nattable.layer.ILayer;
+import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer;
+
+/**
+ * Specialization of the {@link ShowColumnPositionsEvent}. Mainly used to inform
+ * about showed columns but avoid handling it in the ColumnGroupHeaderLayer.
+ *
+ * @since 2.1
+ */
+public class ColumnGroupExpandEvent extends ShowColumnPositionsEvent {
+
+    /**
+     * Constructor.
+     *
+     * @param layer
+     *            The layer to which the given column positions match.
+     * @param columnPositions
+     *            The column positions that are made visible again.
+     */
+    public ColumnGroupExpandEvent(IUniqueIndexLayer layer, Collection<Integer> columnPositions) {
+        super(layer, columnPositions);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param layer
+     *            The layer to which the given column positions match.
+     * @param columnPositions
+     *            The column positions that are made visible again.
+     */
+    public ColumnGroupExpandEvent(ILayer layer, int... columnPositions) {
+        super(layer, columnPositions);
+    }
+
+    /**
+     * Clone constructor.
+     *
+     * @param event
+     *            The {@link ColumnGroupExpandEvent} to clone.
+     */
+    public ColumnGroupExpandEvent(ShowColumnPositionsEvent event) {
+        super(event);
+    }
+
+}
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/event/RowGroupCollapseEvent.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/event/RowGroupCollapseEvent.java
new file mode 100644
index 0000000..9f88797
--- /dev/null
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/event/RowGroupCollapseEvent.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Original authors and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Original authors and others - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.nebula.widgets.nattable.group.performance.event;
+
+import java.util.Collection;
+
+import org.eclipse.nebula.widgets.nattable.hideshow.event.HideRowPositionsEvent;
+import org.eclipse.nebula.widgets.nattable.layer.ILayer;
+
+/**
+ * Specialization of the {@link HideRowPositionsEvent}. Mainly used to inform
+ * about hidden rows but avoid handling it in the RowGroupHeaderLayer.
+ *
+ * @since 2.1
+ */
+public class RowGroupCollapseEvent extends HideRowPositionsEvent {
+
+    /**
+     * Creates a new RowGroupCollapseEvent based on the given information.
+     *
+     * @param layer
+     *            The ILayer to which the given row positions match.
+     * @param rowPositions
+     *            The positions of the rows that have changed.
+     */
+    public RowGroupCollapseEvent(ILayer layer, Collection<Integer> rowPositions) {
+        super(layer, rowPositions);
+    }
+
+    /**
+     * Creates a new RowGroupCollapseEvent based on the given information.
+     *
+     * @param layer
+     *            The ILayer to which the given row positions match.
+     * @param rowPositions
+     *            The positions of the rows that have changed.
+     */
+    public RowGroupCollapseEvent(ILayer layer, int... rowPositions) {
+        super(layer, rowPositions);
+    }
+
+    /**
+     * Creates a new RowGroupCollapseEvent based on the given information.
+     *
+     * @param layer
+     *            The ILayer to which the given row positions match.
+     * @param rowPositions
+     *            The positions of the rows that have changed.
+     * @param rowIndexes
+     *            The indexes of the rows that have changed.
+     */
+    public RowGroupCollapseEvent(ILayer layer, Collection<Integer> rowPositions, Collection<Integer> rowIndexes) {
+        super(layer, rowPositions, rowIndexes);
+    }
+
+    /**
+     * Creates a new RowGroupCollapseEvent based on the given information.
+     *
+     * @param layer
+     *            The ILayer to which the given row positions match.
+     * @param rowPositions
+     *            The positions of the rows that have changed.
+     * @param rowIndexes
+     *            The indexes of the rows that have changed.
+     */
+    public RowGroupCollapseEvent(ILayer layer, int[] rowPositions, int[] rowIndexes) {
+        super(layer, rowPositions, rowIndexes);
+    }
+
+    /**
+     * Clone constructor.
+     *
+     * @param event
+     *            The event to clone.
+     */
+    protected RowGroupCollapseEvent(RowGroupCollapseEvent event) {
+        super(event);
+    }
+
+}
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/event/RowGroupExpandEvent.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/event/RowGroupExpandEvent.java
new file mode 100644
index 0000000..fba9b6b
--- /dev/null
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/group/performance/event/RowGroupExpandEvent.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Original authors and others.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Original authors and others - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.nebula.widgets.nattable.group.performance.event;
+
+import java.util.Collection;
+
+import org.eclipse.nebula.widgets.nattable.hideshow.event.ShowRowPositionsEvent;
+import org.eclipse.nebula.widgets.nattable.layer.ILayer;
+
+/**
+ * Specialization of the {@link ShowRowPositionsEvent}. Mainly used to inform
+ * about showed rows but avoid handling it in the RowGroupHeaderLayer.
+ *
+ * @since 2.1
+ */
+public class RowGroupExpandEvent extends ShowRowPositionsEvent {
+
+    /**
+     * Constructor.
+     *
+     * @param layer
+     *            The layer to which the given row positions match.
+     * @param rowPositions
+     *            The row positions that are made visible again.
+     */
+    public RowGroupExpandEvent(ILayer layer, Collection<Integer> rowPositions) {
+        super(layer, rowPositions);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param layer
+     *            The layer to which the given row positions match.
+     * @param rowPositions
+     *            The row positions that are made visible again.
+     */
+    public RowGroupExpandEvent(ILayer layer, int... rowPositions) {
+        super(layer, rowPositions);
+    }
+
+    /**
+     * Clone constructor.
+     *
+     * @param event
+     *            The {@link RowGroupExpandEvent} to clone.
+     */
+    protected RowGroupExpandEvent(RowGroupExpandEvent event) {
+        super(event);
+    }
+
+}