From 46878a5f5e39bf70e37f83df2563a4c23f38b7ac Mon Sep 17 00:00:00 2001
From: Anna Miroshnik
Date: Mon, 15 Sep 2014 17:11:56 +0400
Subject: Re-adding all rows in Table causes table to loose scroll position
(#14581)
Fix: if to remove (container.removeAllItems()) and then to re-add(container.addAll(..)) the same collection in table container - > scroll position is not loosed now.
The hash code and scroll position of the old container is stored when a new container is added.
If the new container has the same hash code, we restore the scroll position.
The scroll position is not restored if another items added to the container.
Change-Id: I52a22c3c1c7b71f1b3447b9d592ab8fececd67b8
---
server/src/com/vaadin/ui/Table.java | 494 +++++++++++++++++++++---------------
1 file changed, 285 insertions(+), 209 deletions(-)
(limited to 'server/src/com/vaadin/ui')
diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java
index d574ed5ba8..3a1ab82be5 100644
--- a/server/src/com/vaadin/ui/Table.java
+++ b/server/src/com/vaadin/ui/Table.java
@@ -68,7 +68,7 @@ import com.vaadin.shared.ui.table.TableConstants;
* Table is used for representing data or components in a pageable
* and selectable table.
*
- *
+ *
*
* Scalability of the Table is largely dictated by the container. A table does
* not have a limit for the number of items and is just as fast with hundreds of
@@ -76,11 +76,11 @@ import com.vaadin.shared.ui.table.TableConstants;
* scrolling however limits the number of rows to around 500000, depending on
* the browser and the pixel height of rows.
*
- *
+ *
*
* Components in a Table will not have their caption nor icon rendered.
*
- *
+ *
* @author Vaadin Ltd.
* @since 3.0
*/
@@ -421,6 +421,63 @@ public class Table extends AbstractSelect implements Action.Container,
*/
private Object currentPageFirstItemId = null;
+ /*
+ * This class stores the hashcode and scroll position of the previous
+ * container so that the scroll position can be restored if the same
+ * container is removed and then re-added. This resolves #14581.
+ */
+ protected static class ScrollPositionRepairOnReAddAllRowsData implements
+ Serializable {
+
+ private static final long serialVersionUID = 1L;
+ // current page first item index (to repair scroll position)
+ private int itemIndex;
+ /*
+ * hashCode() of container before it was cleared via
+ * container.removeAllItems();
+ */
+ private int containerHashCode;
+
+ public ScrollPositionRepairOnReAddAllRowsData() {
+ itemIndex = -1;
+ containerHashCode = -1;
+ }
+
+ public int getItemId() {
+ return itemIndex;
+ }
+
+ public void setItemId(int itemId) {
+ itemIndex = itemId;
+ }
+
+ public void resetItemId() {
+ itemIndex = -1;
+ }
+
+ public void setContainerData(Container container) {
+ if (container != null) {
+ containerHashCode = container.hashCode();
+ } else {
+ containerHashCode = -1;
+ }
+ }
+
+ public boolean needRepairScrollPosition(Container newContainer) {
+ return (itemIndex != -1) && isTheSameContainer(newContainer);
+ }
+
+ private boolean isTheSameContainer(Container newContainer) {
+ boolean theSame = false;
+ if (newContainer != null) {
+ theSame = (newContainer.hashCode() == containerHashCode);
+ }
+ return theSame;
+ }
+ }
+
+ private final ScrollPositionRepairOnReAddAllRowsData scrollRepairOnReAdding = new ScrollPositionRepairOnReAddAllRowsData();
+
/**
* Index of the first item on the current page.
*/
@@ -583,7 +640,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Creates a new empty table with caption.
- *
+ *
* @param caption
*/
public Table(String caption) {
@@ -593,7 +650,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Creates a new table with caption and connect it to a Container.
- *
+ *
* @param caption
* @param dataSource
*/
@@ -607,11 +664,11 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the array of visible column id:s, including generated columns.
- *
+ *
*
* The columns are show in the order of their appearance in this array.
*
- *
+ *
* @return an array of currently visible propertyIds and generated column
* ids.
*/
@@ -624,11 +681,11 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets the array of visible column property id:s.
- *
+ *
*
* The columns are show in the order of their appearance in this array.
*
- *
+ *
* @param visibleColumns
* the Array of shown property id:s.
*/
@@ -690,7 +747,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the headers of the columns.
- *
+ *
*
* The headers match the property id:s given my the set visible column
* headers. The table must be set in either
@@ -699,7 +756,7 @@ public class Table extends AbstractSelect implements Action.Container,
* headers. In the defaults mode any nulls in the headers array are replaced
* with id.toString().
*
- *
+ *
* @return the Array of column headers.
*/
public String[] getColumnHeaders() {
@@ -717,7 +774,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets the headers of the columns.
- *
+ *
*
* The headers match the property id:s given my the set visible column
* headers. The table must be set in either
@@ -726,7 +783,7 @@ public class Table extends AbstractSelect implements Action.Container,
* headers. In the defaults mode any nulls in the headers array are replaced
* with id.toString() outputs when rendering.
*
- *
+ *
* @param columnHeaders
* the Array of column headers that match the
* {@link #getVisibleColumns()} method.
@@ -750,7 +807,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the icons of the columns.
- *
+ *
*
* The icons in headers match the property id:s given my the set visible
* column headers. The table must be set in either
@@ -758,7 +815,7 @@ public class Table extends AbstractSelect implements Action.Container,
* {@link #COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID} mode to show the headers
* with icons.
*
- *
+ *
* @return the Array of icons that match the {@link #getVisibleColumns()}.
*/
public Resource[] getColumnIcons() {
@@ -777,7 +834,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets the icons of the columns.
- *
+ *
*
* The icons in headers match the property id:s given my the set visible
* column headers. The table must be set in either
@@ -785,7 +842,7 @@ public class Table extends AbstractSelect implements Action.Container,
* {@link #COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID} mode to show the headers
* with icons.
*
- *
+ *
* @param columnIcons
* the Array of icons that match the {@link #getVisibleColumns()}
* .
@@ -809,7 +866,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the array of column alignments.
- *
+ *
*
* The items in the array must match the properties identified by
* {@link #getVisibleColumns()}. The possible values for the alignments
@@ -822,7 +879,7 @@ public class Table extends AbstractSelect implements Action.Container,
* The alignments default to {@link Align#LEFT}: any null values are
* rendered as align lefts.
*
- *
+ *
* @return the Column alignments array.
*/
public Align[] getColumnAlignments() {
@@ -841,7 +898,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets the column alignments.
- *
+ *
*
* The amount of items in the array must match the amount of properties
* identified by {@link #getVisibleColumns()}. The possible values for the
@@ -853,7 +910,7 @@ public class Table extends AbstractSelect implements Action.Container,
*
* The alignments default to {@link Align#LEFT}
*
- *
+ *
* @param columnAlignments
* the Column alignments array.
*/
@@ -882,11 +939,11 @@ public class Table extends AbstractSelect implements Action.Container,
* Sets columns width (in pixels). Theme may not necessary respect very
* small or very big values. Setting width to -1 (default) means that theme
* will make decision of width.
- *
+ *
*
* Column can either have a fixed width or expand ratio. The latter one set
* is used. See @link {@link #setColumnExpandRatio(Object, float)}.
- *
+ *
* @param propertyId
* colunmns property id
* @param width
@@ -920,27 +977,27 @@ public class Table extends AbstractSelect implements Action.Container,
* naturally. Excess space is the space that is not used by columns with
* explicit width (see {@link #setColumnWidth(Object, int)}) or with natural
* width (no width nor expand ratio).
- *
+ *
*
* By default (without expand ratios) the excess space is divided
* proportionally to columns natural widths.
- *
+ *
*
* Only expand ratios of visible columns are used in final calculations.
- *
+ *
*
* Column can either have a fixed width or expand ratio. The latter one set
* is used.
- *
+ *
*
* A column with expand ratio is considered to be minimum width by default
* (if no excess space exists). The minimum width is defined by terminal
* implementation.
- *
+ *
*
* If terminal implementation supports re-sizable columns the column becomes
* fixed width column if users resizes the column.
- *
+ *
* @param propertyId
* columns property id
* @param expandRatio
@@ -969,7 +1026,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the column expand ratio for a columnd. See
* {@link #setColumnExpandRatio(Object, float)}
- *
+ *
* @param propertyId
* columns property id
* @return the expandRatio used to divide excess space for this column
@@ -984,7 +1041,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the pixel width of column
- *
+ *
* @param propertyId
* @return width of column or -1 when value not set
*/
@@ -1003,11 +1060,11 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the page length.
- *
+ *
*
* Setting page length 0 disables paging.
*
- *
+ *
* @return the Length of one page.
*/
public int getPageLength() {
@@ -1016,16 +1073,16 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets the page length.
- *
+ *
*
* Setting page length 0 disables paging. The page length defaults to 15.
*
- *
+ *
*
* If Table has width set ({@link #setWidth(float, int)} ) the client side
* may update the page length automatically the correct value.
*
- *
+ *
* @param pageLength
* the length of one page.
*/
@@ -1039,18 +1096,18 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* This method adjusts a possible caching mechanism of table implementation.
- *
+ *
*
* Table component may fetch and render some rows outside visible area. With
* complex tables (for example containing layouts and components), the
* client side may become unresponsive. Setting the value lower, UI will
* become more responsive. With higher values scrolling in client will hit
* server less frequently.
- *
+ *
*
* The amount of cached rows will be cacheRate multiplied with pageLength (
* {@link #setPageLength(int)} both below and above visible area..
- *
+ *
* @param cacheRate
* a value over 0 (fastest rendering time). Higher value will
* cache more rows on server (smoother scrolling). Default value
@@ -1069,7 +1126,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* @see #setCacheRate(double)
- *
+ *
* @return the current cache rate value
*/
public double getCacheRate() {
@@ -1078,7 +1135,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Getter for property currentPageFirstItem.
- *
+ *
* @return the Value of property currentPageFirstItem.
*/
public Object getCurrentPageFirstItemId() {
@@ -1106,14 +1163,14 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Returns the item ID for the item represented by the index given. Assumes
* that the current container implements {@link Container.Indexed}.
- *
+ *
* See {@link Container.Indexed#getIdByIndex(int)} for more information
* about the exceptions that can be thrown.
- *
+ *
* @param index
* the index for which the item ID should be fetched
* @return the item ID for the given index
- *
+ *
* @throws ClassCastException
* if container does not implement {@link Container.Indexed}
* @throws IndexOutOfBoundsException
@@ -1126,7 +1183,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Setter for property currentPageFirstItemId.
- *
+ *
* @param currentPageFirstItemId
* the New value of property currentPageFirstItemId.
*/
@@ -1183,7 +1240,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the icon Resource for the specified column.
- *
+ *
* @param propertyId
* the propertyId indentifying the column.
* @return the icon for the specified column; null if the column has no icon
@@ -1198,7 +1255,7 @@ public class Table extends AbstractSelect implements Action.Container,
*
* Throws IllegalArgumentException if the specified column is not visible.
*
- *
+ *
* @param propertyId
* the propertyId identifying the column.
* @param icon
@@ -1217,7 +1274,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the header for the specified column.
- *
+ *
* @param propertyId
* the propertyId identifying the column.
* @return the header for the specified column if it has one.
@@ -1238,7 +1295,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets the column header for the specified column;
- *
+ *
* @param propertyId
* the propertyId identifying the column.
* @param header
@@ -1257,7 +1314,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the specified column's alignment.
- *
+ *
* @param propertyId
* the propertyID identifying the column.
* @return the specified column's alignment if it as one; {@link Align#LEFT}
@@ -1270,13 +1327,13 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets the specified column's alignment.
- *
+ *
*
* Throws IllegalArgumentException if the alignment is not one of the
* following: {@link Align#LEFT}, {@link Align#CENTER} or
* {@link Align#RIGHT}
*
- *
+ *
* @param propertyId
* the propertyID identifying the column.
* @param alignment
@@ -1296,7 +1353,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Checks if the specified column is collapsed.
- *
+ *
* @param propertyId
* the propertyID identifying the column.
* @return true if the column is collapsed; false otherwise;
@@ -1308,8 +1365,8 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets whether the specified column is collapsed or not.
- *
- *
+ *
+ *
* @param propertyId
* the propertyID identifying the column.
* @param collapsed
@@ -1338,7 +1395,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Checks if column collapsing is allowed.
- *
+ *
* @return true if columns can be collapsed; false otherwise.
*/
public boolean isColumnCollapsingAllowed() {
@@ -1347,7 +1404,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets whether column collapsing is allowed or not.
- *
+ *
* @param collapsingAllowed
* specifies whether column collapsing is allowed.
*/
@@ -1369,7 +1426,7 @@ public class Table extends AbstractSelect implements Action.Container,
* {@link #setColumnCollapsed(Object, boolean) setColumnCollapsed()}) if
* {@link #isColumnCollapsingAllowed()} is true. By default all columns are
* collapsible.
- *
+ *
* @param propertyId
* the propertyID identifying the column.
* @param collapsible
@@ -1391,7 +1448,7 @@ public class Table extends AbstractSelect implements Action.Container,
* UI or with {@link #setColumnCollapsed(Object, boolean)
* setColumnCollapsed()}) if {@link #isColumnCollapsingAllowed()} is also
* true.
- *
+ *
* @return true if the column can be collapsed; false otherwise.
*/
public boolean isColumnCollapsible(Object propertyId) {
@@ -1400,7 +1457,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Checks if column reordering is allowed.
- *
+ *
* @return true if columns can be reordered; false otherwise.
*/
public boolean isColumnReorderingAllowed() {
@@ -1409,7 +1466,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets whether column reordering is allowed or not.
- *
+ *
* @param columnReorderingAllowed
* specifies whether column reordering is allowed.
*/
@@ -1453,7 +1510,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Getter for property currentPageFirstItem.
- *
+ *
* @return the Value of property currentPageFirstItem.
*/
public int getCurrentPageFirstItemIndex() {
@@ -1576,6 +1633,7 @@ public class Table extends AbstractSelect implements Action.Container,
newIndex = currentPageFirstItemIndex = size - 1;
}
}
+
if (needsPageBufferReset) {
// Assures the visual refresh
refreshRowCache();
@@ -1584,7 +1642,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Setter for property currentPageFirstItem.
- *
+ *
* @param newIndex
* the New value of property currentPageFirstItem.
*/
@@ -1594,11 +1652,11 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Getter for property selectable.
- *
+ *
*
* The table is not selectable by default.
*
- *
+ *
* @return the Value of property selectable.
*/
public boolean isSelectable() {
@@ -1607,11 +1665,11 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Setter for property selectable.
- *
+ *
*
* The table is not selectable by default.
*
- *
+ *
* @param selectable
* the New value of property selectable.
*/
@@ -1624,7 +1682,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Getter for property columnHeaderMode.
- *
+ *
* @return the Value of property columnHeaderMode.
*/
public ColumnHeaderMode getColumnHeaderMode() {
@@ -1633,7 +1691,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Setter for property columnHeaderMode.
- *
+ *
* @param columnHeaderMode
* the New value of property columnHeaderMode.
*/
@@ -1742,7 +1800,7 @@ public class Table extends AbstractSelect implements Action.Container,
* occurred exception is set as the cause of this exception. All occurred
* exceptions can be accessed using {@link #getCauses()}.
*
- *
+ *
*/
public static class CacheUpdateException extends RuntimeException {
private Throwable[] causes;
@@ -1766,7 +1824,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Returns the cause(s) for this exception
- *
+ *
* @return the exception(s) which caused this exception
*/
public Throwable[] getCauses() {
@@ -1822,11 +1880,11 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Requests that the Table should be repainted as soon as possible.
- *
+ *
* Note that a {@code Table} does not necessarily repaint its contents when
* this method has been called. See {@link #refreshRowCache()} for forcing
* an update of the contents.
- *
+ *
* @deprecated As of 7.0, use {@link #markAsDirty()} instead
*/
@@ -1838,7 +1896,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Requests that the Table should be repainted as soon as possible.
- *
+ *
* Note that a {@code Table} does not necessarily repaint its contents when
* this method has been called. See {@link #refreshRowCache()} for forcing
* an update of the contents.
@@ -2125,9 +2183,9 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Render rows with index "firstIndex" to "firstIndex+rows-1" to a new
* buffer.
- *
+ *
* Reuses values from the current page buffer if the rows are found there.
- *
+ *
* @param firstIndex
* @param rows
* @param replaceListeners
@@ -2236,7 +2294,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Update a cache array for a row, register any relevant listeners etc.
- *
+ *
* This is an internal method extracted from
* {@link #getVisibleCellsNoCache(int, int, boolean)} and should be removed
* when the Table is rewritten.
@@ -2454,7 +2512,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Helper method to remove listeners and maintain correct component
* hierarchy. Detaches properties and components if those are no more
* rendered in client.
- *
+ *
* @param oldListenedProperties
* set of properties that where listened in last render
* @param oldVisibleComponents
@@ -2490,12 +2548,12 @@ public class Table extends AbstractSelect implements Action.Container,
* if it is a field, it needs to be detached from its property data source
* in order to allow garbage collection to take care of removing the unused
* component from memory.
- *
+ *
* Override this method and getPropertyValue(Object, Object, Property) with
* custom logic if you need to deal with buffered fields.
- *
+ *
* @see #getPropertyValue(Object, Object, Property)
- *
+ *
* @param oldVisibleComponents
* a set of components that should be unregistered.
*/
@@ -2546,7 +2604,7 @@ public class Table extends AbstractSelect implements Action.Container,
*
* The default value is {@link #ROW_HEADER_MODE_HIDDEN}
*
- *
+ *
* @param mode
* the One of the modes listed above.
*/
@@ -2565,7 +2623,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the row header mode.
- *
+ *
* @return the Row header mode.
* @see #setRowHeaderMode(int)
*/
@@ -2576,7 +2634,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Adds the new row to table and fill the visible cells (except generated
* columns) with given values.
- *
+ *
* @param cells
* the Object array that is used for filling the visible cells
* new row. The types must be settable to visible column property
@@ -2645,7 +2703,7 @@ public class Table extends AbstractSelect implements Action.Container,
*
* Note that calling this method is not cheap so avoid calling it
* unnecessarily.
- *
+ *
* @since 6.7.2
*/
public void refreshRowCache() {
@@ -2666,7 +2724,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Keeps propertyValueConverters if the corresponding id exists in the new
* data source and is of a compatible type.
*
- *
+ *
* @param newDataSource
* the new data source.
*/
@@ -2675,6 +2733,11 @@ public class Table extends AbstractSelect implements Action.Container,
if (newDataSource == null) {
newDataSource = new IndexedContainer();
}
+
+ if (scrollRepairOnReAdding != null) {
+ // this is important if container is set for table after filling
+ scrollRepairOnReAdding.setContainerData(newDataSource);
+ }
Collection