diff options
3 files changed, 431 insertions, 209 deletions
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; * <code>Table</code> is used for representing data or components in a pageable * and selectable table. * </p> - * + * * <p> * 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. * </p> - * + * * <p> * Components in a Table will not have their caption nor icon rendered. * </p> - * + * * @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. - * + * * <p> * The columns are show in the order of their appearance in this array. * </p> - * + * * @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. - * + * * <p> * The columns are show in the order of their appearance in this array. * </p> - * + * * @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. - * + * * <p> * 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(). * </p> - * + * * @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. - * + * * <p> * 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. * </p> - * + * * @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. - * + * * <p> * 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. * </p> - * + * * @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. - * + * * <p> * 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. * </p> - * + * * @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. - * + * * <p> * 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. * </p> - * + * * @return the Column alignments array. */ public Align[] getColumnAlignments() { @@ -841,7 +898,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Sets the column alignments. - * + * * <p> * 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, * </ul> * The alignments default to {@link Align#LEFT} * </p> - * + * * @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. - * + * * <p> * 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). - * + * * <p> * By default (without expand ratios) the excess space is divided * proportionally to columns natural widths. - * + * * <p> * Only expand ratios of visible columns are used in final calculations. - * + * * <p> * Column can either have a fixed width or expand ratio. The latter one set * is used. - * + * * <p> * 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. - * + * * <p> * 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. - * + * * <p> * Setting page length 0 disables paging. * </p> - * + * * @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. - * + * * <p> * Setting page length 0 disables paging. The page length defaults to 15. * </p> - * + * * <p> * If Table has width set ({@link #setWidth(float, int)} ) the client side * may update the page length automatically the correct value. * </p> - * + * * @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. - * + * * <p> * 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. - * + * * <p> * 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, * <p> * Throws IllegalArgumentException if the specified column is not visible. * </p> - * + * * @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. - * + * * <p> * Throws IllegalArgumentException if the alignment is not one of the * following: {@link Align#LEFT}, {@link Align#CENTER} or * {@link Align#RIGHT} * </p> - * + * * @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. - * + * * <p> * The table is not selectable by default. * </p> - * + * * @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. - * + * * <p> * The table is not selectable by default. * </p> - * + * * @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()}. * </p> - * + * */ 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, * </ul> * The default value is {@link #ROW_HEADER_MODE_HIDDEN} * </p> - * + * * @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, * <p> * <i>Note that calling this method is not cheap so avoid calling it * unnecessarily.</i> - * + * * @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. * </p> - * + * * @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<Object> generated; if (columnGenerators != null) { generated = columnGenerators.keySet(); @@ -2704,11 +2767,11 @@ 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. * </p> - * + * * @see Table#setContainerDataSource(Container) * @see Table#setVisibleColumns(Object[]) * @see Table#setConverter(Object, Converter<String, ?>) - * + * * @param newDataSource * the new data source. * @param visibleIds @@ -2783,7 +2846,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Checks if class b can be safely assigned to class a. - * + * * @param a * @param b * @return @@ -2797,7 +2860,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Gets items ids from a range of key values - * + * * @param startRowKey * The start key * @param endRowKey @@ -2818,7 +2881,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Handles selection if selection is a multiselection - * + * * @param variables * The variables */ @@ -2897,7 +2960,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Invoked when the value of a variable has changed. - * + * * @see com.vaadin.ui.Select#changeVariables(java.lang.Object, * java.util.Map) */ @@ -3099,7 +3162,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Handles click event - * + * * @param variables */ private void handleClickEvent(Map<String, Object> variables) { @@ -3153,7 +3216,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Handles the column resize event sent by the client. - * + * * @param variables */ private void handleColumnResizeEvent(Map<String, Object> variables) { @@ -3212,7 +3275,7 @@ public class Table extends AbstractSelect implements Action.Container, * Go to mode where content updates are not done. This is due we want to * bypass expensive content for some reason (like when we know we may have * other content changes on their way). - * + * * @return true if content refresh flag was enabled prior this call */ protected boolean disableContentRefreshing() { @@ -3223,7 +3286,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Go to mode where content content refreshing has effect. - * + * * @param refreshContent * true if content refresh needs to be done */ @@ -3423,7 +3486,7 @@ public class Table extends AbstractSelect implements Action.Container, * Subclass and override this to enable partial row updates and additions, * which bypass the normal caching mechanism. This is useful for e.g. * TreeTable. - * + * * @return true if this update is a partial row update, false if not. For * plain Table it is always false. */ @@ -3435,7 +3498,7 @@ public class Table extends AbstractSelect implements Action.Container, * Subclass and override this to enable partial row additions, bypassing the * normal caching mechanism. This is useful for e.g. TreeTable, where * expanding a node should only fetch and add the items inside of that node. - * + * * @return The index of the first added item. For plain Table it is always * 0. */ @@ -3447,7 +3510,7 @@ public class Table extends AbstractSelect implements Action.Container, * Subclass and override this to enable partial row additions, bypassing the * normal caching mechanism. This is useful for e.g. TreeTable, where * expanding a node should only fetch and add the items inside of that node. - * + * * @return the number of rows to be added, starting at the index returned by * {@link #getFirstAddedItemIndex()}. For plain Table it is always * 0. @@ -3460,11 +3523,11 @@ public class Table extends AbstractSelect implements Action.Container, * Subclass and override this to enable removing of rows, bypassing the * normal caching and lazy loading mechanism. This is useful for e.g. * TreeTable, when you need to hide certain rows as a node is collapsed. - * + * * This should return true if the rows pointed to by * {@link #getFirstAddedItemIndex()} and {@link #getAddedRowCount()} should * be hidden instead of added. - * + * * @return whether the rows to add (see {@link #getFirstAddedItemIndex()} * and {@link #getAddedRowCount()}) should be added or hidden. For * plain Table it is always false. @@ -3478,7 +3541,7 @@ public class Table extends AbstractSelect implements Action.Container, * normal caching and lazy loading mechanism. This is useful for updating * the state of certain rows, e.g. in the TreeTable the collapsed state of a * single node is updated using this mechanism. - * + * * @return the index of the first item to be updated. For plain Table it is * always 0. */ @@ -3491,7 +3554,7 @@ public class Table extends AbstractSelect implements Action.Container, * normal caching and lazy loading mechanism. This is useful for updating * the state of certain rows, e.g. in the TreeTable the collapsed state of a * single node is updated using this mechanism. - * + * * @return the number of rows to update, starting at the index returned by * {@link #getFirstUpdatedItemIndex()}. For plain table it is always * 0. @@ -4005,7 +4068,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * A method where extended Table implementations may add their custom * attributes for rows. - * + * * @param target * @param itemId */ @@ -4016,7 +4079,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Gets the cached visible table contents. - * + * * @return the cached visible table contents. */ private Object[][] getVisibleCells() { @@ -4028,11 +4091,11 @@ public class Table extends AbstractSelect implements Action.Container, /** * Gets the value of property. - * + * * By default if the table is editable the fieldFactory is used to create * editors for table cells. Otherwise formatPropertyValue is used to format * the value representation. - * + * * @param rowId * the Id of the row (same as item Id). * @param colId @@ -4064,7 +4127,7 @@ public class Table extends AbstractSelect implements Action.Container, * default behavior is to bind property straight to Field. If * Property.Viewer type property (e.g. PropertyFormatter) is already set for * field, the property is bound to that Property.Viewer. - * + * * @param rowId * @param colId * @param property @@ -4089,7 +4152,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Formats table cell property values. By default the property.toString() * and return a empty string for null properties. - * + * * @param rowId * the Id of the row (same as item Id). * @param colId @@ -4124,7 +4187,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Registers a new action handler for this container - * + * * @see com.vaadin.event.Action.Container#addActionHandler(Action.Handler) */ @@ -4152,7 +4215,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Removes a previously registered action handler for the contents of this * container. - * + * * @see com.vaadin.event.Action.Container#removeActionHandler(Action.Handler) */ @@ -4191,9 +4254,9 @@ public class Table extends AbstractSelect implements Action.Container, /** * Notifies this listener that the Property's value has changed. - * + * * Also listens changes in rendered items to refresh content area. - * + * * @see com.vaadin.data.Property.ValueChangeListener#valueChange(Property.ValueChangeEvent) */ @@ -4224,7 +4287,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Notifies the component that it is connected to an application. - * + * * @see com.vaadin.ui.Component#attach() */ @@ -4237,7 +4300,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Notifies the component that it is detached from the application - * + * * @see com.vaadin.ui.Component#detach() */ @@ -4248,7 +4311,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Removes all Items from the Container. - * + * * @see com.vaadin.data.Container#removeAllItems() */ @@ -4261,7 +4324,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Removes the Item identified by <code>ItemId</code> from the Container. - * + * * @see com.vaadin.data.Container#removeItem(Object) */ @@ -4280,7 +4343,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Removes a Property specified by the given Property ID from the Container. - * + * * @see com.vaadin.data.Container#removeContainerProperty(Object) */ @@ -4302,7 +4365,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Adds a new property to the table and show it as a visible column. - * + * * @param propertyId * the Id of the proprty. * @param type @@ -4337,7 +4400,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Adds a new property to the table and show it as a visible column. - * + * * @param propertyId * the Id of the proprty * @param type @@ -4393,7 +4456,7 @@ public class Table extends AbstractSelect implements Action.Container, * Also note that getVisibleColumns() will return the generated columns, * while getContainerPropertyIds() will not. * </p> - * + * * @param id * the id of the column to be added * @param generatedColumn @@ -4422,7 +4485,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Returns the ColumnGenerator used to generate the given column. - * + * * @param columnId * The id of the generated column * @return The ColumnGenerator used for the given columnId or null. @@ -4434,7 +4497,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Removes a generated column previously added with addGeneratedColumn. - * + * * @param columnId * id of the generated column to remove * @return true if the column could be removed (existed in the Table) @@ -4465,7 +4528,7 @@ public class Table extends AbstractSelect implements Action.Container, * architecture. Using {@link #getCurrentPageFirstItemId()} combined with * {@link #getPageLength()} may produce good enough estimates in some * situations. - * + * * @see com.vaadin.ui.Select#getVisibleItemIds() */ @@ -4489,7 +4552,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Container datasource item set change. Table must flush its buffers on * change. - * + * * @see com.vaadin.data.Container.ItemSetChangeListener#containerItemSetChange(com.vaadin.data.Container.ItemSetChangeEvent) */ @@ -4505,16 +4568,29 @@ public class Table extends AbstractSelect implements Action.Container, // avoid getting invalid keys back (#8584) keyMapperReset = true; + int currentFirstItemIndex = getCurrentPageFirstItemIndex(); + + if (event.getContainer().size() == 0) { + scrollRepairOnReAdding.setItemId(getCurrentPageFirstItemIndex()); + } else { + if (scrollRepairOnReAdding.needRepairScrollPosition(event + .getContainer())) { + currentFirstItemIndex = scrollRepairOnReAdding.getItemId(); + } + scrollRepairOnReAdding.resetItemId(); + scrollRepairOnReAdding.setContainerData(event.getContainer()); + } + // ensure that page still has first item in page, ignore buffer refresh // (forced in this method) - setCurrentPageFirstItemIndex(getCurrentPageFirstItemIndex(), false); + setCurrentPageFirstItemIndex(currentFirstItemIndex, false); refreshRowCache(); } /** * Container datasource property set change. Table must flush its buffers on * change. - * + * * @see com.vaadin.data.Container.PropertySetChangeListener#containerPropertySetChange(com.vaadin.data.Container.PropertySetChangeEvent) */ @@ -4560,7 +4636,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Adding new items is not supported. - * + * * @throws UnsupportedOperationException * if set to true. * @see com.vaadin.ui.Select#setNewItemsAllowed(boolean) @@ -4576,7 +4652,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Gets the ID of the Item following the Item that corresponds to itemId. - * + * * @see com.vaadin.data.Container.Ordered#nextItemId(java.lang.Object) */ @@ -4588,7 +4664,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Gets the ID of the Item preceding the Item that corresponds to the * itemId. - * + * * @see com.vaadin.data.Container.Ordered#prevItemId(java.lang.Object) */ @@ -4599,7 +4675,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Gets the ID of the first Item in the Container. - * + * * @see com.vaadin.data.Container.Ordered#firstItemId() */ @@ -4610,7 +4686,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Gets the ID of the last Item in the Container. - * + * * @see com.vaadin.data.Container.Ordered#lastItemId() */ @@ -4622,7 +4698,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Tests if the Item corresponding to the given Item ID is the first Item in * the Container. - * + * * @see com.vaadin.data.Container.Ordered#isFirstId(java.lang.Object) */ @@ -4634,7 +4710,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Tests if the Item corresponding to the given Item ID is the last Item in * the Container. - * + * * @see com.vaadin.data.Container.Ordered#isLastId(java.lang.Object) */ @@ -4645,7 +4721,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Adds new item after the given item. - * + * * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object) */ @@ -4662,7 +4738,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Adds new item after the given item. - * + * * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object, * java.lang.Object) */ @@ -4680,10 +4756,10 @@ public class Table extends AbstractSelect implements Action.Container, /** * Sets the TableFieldFactory that is used to create editor for table cells. - * + * * The TableFieldFactory is only used if the Table is editable. By default * the DefaultFieldFactory is used. - * + * * @param fieldFactory * the field factory to set. * @see #isEditable @@ -4698,9 +4774,9 @@ public class Table extends AbstractSelect implements Action.Container, /** * Gets the TableFieldFactory that is used to create editor for table cells. - * + * * The FieldFactory is only used if the Table is editable. - * + * * @return TableFieldFactory used to create the Field instances. * @see #isEditable */ @@ -4710,18 +4786,18 @@ public class Table extends AbstractSelect implements Action.Container, /** * Is table editable. - * + * * If table is editable a editor of type Field is created for each table * cell. The assigned FieldFactory is used to create the instances. - * + * * To provide custom editors for table cells create a class implementins the * FieldFactory interface, and assign it to table, and set the editable * property to true. - * + * * @return true if table is editable, false oterwise. * @see Field * @see FieldFactory - * + * */ public boolean isEditable() { return editable; @@ -4729,19 +4805,19 @@ public class Table extends AbstractSelect implements Action.Container, /** * Sets the editable property. - * + * * If table is editable a editor of type Field is created for each table * cell. The assigned FieldFactory is used to create the instances. - * + * * To provide custom editors for table cells create a class implementins the * FieldFactory interface, and assign it to table, and set the editable * property to true. - * + * * @param editable * true if table should be editable by user. * @see Field * @see FieldFactory - * + * */ public void setEditable(boolean editable) { this.editable = editable; @@ -4752,13 +4828,13 @@ public class Table extends AbstractSelect implements Action.Container, /** * Sorts the table. - * + * * @throws UnsupportedOperationException * if the container data source does not implement * Container.Sortable * @see com.vaadin.data.Container.Sortable#sort(java.lang.Object[], * boolean[]) - * + * */ @Override @@ -4790,7 +4866,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Sorts the table by currently selected sorting column. - * + * * @throws UnsupportedOperationException * if the container data source does not implement * Container.Sortable @@ -4810,7 +4886,7 @@ public class Table extends AbstractSelect implements Action.Container, * returns. Disabling sorting causes this method to always return an empty * collection. * </p> - * + * * @see com.vaadin.data.Container.Sortable#getSortableContainerPropertyIds() */ @@ -4826,7 +4902,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Gets the currently sorted column property ID. - * + * * @return the Container property id of the currently sorted column. */ public Object getSortContainerPropertyId() { @@ -4835,7 +4911,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Sets the currently sorted column property id. - * + * * @param propertyId * the Container property id of the currently sorted column. */ @@ -4846,7 +4922,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Internal method to set currently sorted column property id. With doSort * flag actual sorting may be bypassed. - * + * * @param propertyId * @param doSort */ @@ -4867,7 +4943,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Is the table currently sorted in ascending order. - * + * * @return <code>true</code> if ascending, <code>false</code> if descending. */ public boolean isSortAscending() { @@ -4876,7 +4952,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Sets the table in ascending order. - * + * * @param ascending * <code>true</code> if ascending, <code>false</code> if * descending. @@ -4888,7 +4964,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Internal method to set sort ascending. With doSort flag actual sort can * be bypassed. - * + * * @param ascending * @param doSort */ @@ -4906,10 +4982,10 @@ public class Table extends AbstractSelect implements Action.Container, /** * Is sorting disabled altogether. - * + * * True iff no sortable columns are given even in the case where data source * would support this. - * + * * @return True iff sorting is disabled. * @deprecated As of 7.0, use {@link #isSortEnabled()} instead */ @@ -4920,7 +4996,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Checks if sorting is enabled. - * + * * @return true if sorting by the user is allowed, false otherwise */ public boolean isSortEnabled() { @@ -4929,7 +5005,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Disables the sorting by the user altogether. - * + * * @param sortDisabled * True iff sorting is disabled. * @deprecated As of 7.0, use {@link #setSortEnabled(boolean)} instead @@ -4945,7 +5021,7 @@ public class Table extends AbstractSelect implements Action.Container, * Setting this to false disallows sorting by the user. It is still possible * to call {@link #sort()}. * </p> - * + * * @param sortEnabled * true to allow the user to sort the table, false to disallow it */ @@ -4960,14 +5036,14 @@ public class Table extends AbstractSelect implements Action.Container, * Used to create "generated columns"; columns that exist only in the Table, * not in the underlying Container. Implement this interface and pass it to * Table.addGeneratedColumn along with an id for the column to be generated. - * + * */ public interface ColumnGenerator extends Serializable { /** * Called by Table when a cell in a generated column needs to be * generated. - * + * * @param source * the source Table * @param itemId @@ -4985,7 +5061,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Set cell style generator for Table. - * + * * @param cellStyleGenerator * New cell style generator or null to remove generator. */ @@ -4999,7 +5075,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Get the current cell style generator. - * + * */ public CellStyleGenerator getCellStyleGenerator() { return cellStyleGenerator; @@ -5016,7 +5092,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Called by Table when a cell (and row) is painted. - * + * * @param source * the source Table * @param itemId @@ -5079,7 +5155,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Sets the drag start mode of the Table. Drag start mode controls how Table * behaves as a drag source. - * + * * @param newDragMode */ public void setDragMode(TableDragMode newDragMode) { @@ -5098,9 +5174,9 @@ public class Table extends AbstractSelect implements Action.Container, /** * Concrete implementation of {@link DataBoundTransferable} for data * transferred from a table. - * + * * @see {@link DataBoundTransferable}. - * + * * @since 6.3 */ public class TableTransferable extends DataBoundTransferable { @@ -5162,7 +5238,7 @@ public class Table extends AbstractSelect implements Action.Container, * Note, that on some clients the mode may not be respected. E.g. on touch * based devices CTRL/SHIFT base selection method is invalid, so touch based * browsers always use the {@link MultiSelectMode#SIMPLE}. - * + * * @param mode * The select mode of the table */ @@ -5173,7 +5249,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Returns the select mode in which multi-select is used. - * + * * @return The multi select mode */ public MultiSelectMode getMultiSelectMode() { @@ -5185,7 +5261,7 @@ public class Table extends AbstractSelect implements Action.Container, * from server once per drag and drop operation. Developer must override one * method that decides on which rows the currently dragged data can be * dropped. - * + * * <p> * Initially pretty much no data is sent to client. On first required * criterion check (per drag request) the client side data structure is @@ -5302,7 +5378,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Gets the property id of the column which header was pressed - * + * * @return The column propety id */ public Object getPropertyId() { @@ -5336,7 +5412,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Constructor - * + * * @param source * The source of the component * @param propertyId @@ -5352,7 +5428,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Gets the property id of the column which header was pressed - * + * * @return The column propety id */ public Object getPropertyId() { @@ -5368,7 +5444,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Called when a user clicks a header column cell - * + * * @param event * The event which contains information about the column and * the mouse click event @@ -5384,7 +5460,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Called when a user clicks a footer column cell - * + * * @param event * The event which contains information about the column and * the mouse click event @@ -5399,7 +5475,7 @@ public class Table extends AbstractSelect implements Action.Container, * The listener will receive events which contain information about which * column was clicked and some details about the mouse event. * </p> - * + * * @param listener * The handler which should handle the header click events. */ @@ -5420,7 +5496,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Removes a header click listener - * + * * @param listener * The listener to remove. */ @@ -5445,7 +5521,7 @@ public class Table extends AbstractSelect implements Action.Container, * The listener will receive events which contain information about which * column was clicked and some details about the mouse event. * </p> - * + * * @param listener * The handler which should handle the footer click events. */ @@ -5466,7 +5542,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Removes a footer click listener - * + * * @param listener * The listener to remove. */ @@ -5486,7 +5562,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Gets the footer caption beneath the rows - * + * * @param propertyId * The propertyId of the column * * @return The caption of the footer or NULL if not set @@ -5498,10 +5574,10 @@ public class Table extends AbstractSelect implements Action.Container, /** * Sets the column footer caption. The column footer caption is the text * displayed beneath the column if footers have been set visible. - * + * * @param propertyId * The properyId of the column - * + * * @param footer * The caption of the footer */ @@ -5521,7 +5597,7 @@ public class Table extends AbstractSelect implements Action.Container, * The footer can be used to add column related data like sums to the bottom * of the Table using setColumnFooter(Object propertyId, String footer). * </p> - * + * * @param visible * Should the footer be visible */ @@ -5534,7 +5610,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Is the footer currently visible? - * + * * @return Returns true if visible else false */ public boolean isFooterVisible() { @@ -5566,7 +5642,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Constructor - * + * * @param source * The source of the event * @param propertyId @@ -5586,7 +5662,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Get the column property id of the column that was resized. - * + * * @return The column property id */ public Object getPropertyId() { @@ -5595,7 +5671,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Get the width in pixels of the column before the resize event - * + * * @return Width in pixels */ public int getPreviousWidth() { @@ -5604,7 +5680,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Get the width in pixels of the column after the resize event - * + * * @return Width in pixels */ public int getCurrentWidth() { @@ -5619,7 +5695,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * This method is triggered when the column has been resized - * + * * @param event * The event which contains the column property id, the * previous width of the column and the current width of the @@ -5631,7 +5707,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Adds a column resize listener to the Table. A column resize listener is * called when a user resizes a columns width. - * + * * @param listener * The listener to attach to the Table */ @@ -5652,7 +5728,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Removes a column resize listener from the Table. - * + * * @param listener * The listener to remove */ @@ -5689,7 +5765,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Constructor - * + * * @param source * The source of the event */ @@ -5706,7 +5782,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * This method is triggered when the column has been reordered - * + * * @param event */ public void columnReorder(ColumnReorderEvent event); @@ -5715,7 +5791,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Adds a column reorder listener to the Table. A column reorder listener is * called when a user reorders columns. - * + * * @param listener * The listener to attach to the Table */ @@ -5735,7 +5811,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Removes a column reorder listener from the Table. - * + * * @param listener * The listener to remove */ @@ -5756,7 +5832,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Set the item description generator which generates tooltips for cells and * rows in the Table - * + * * @param generator * The generator to use or null to disable */ @@ -5781,7 +5857,7 @@ public class Table extends AbstractSelect implements Action.Container, * Row generators can be used to replace certain items in a table with a * generated string. The generator is called each time the table is * rendered, which means that new strings can be generated each time. - * + * * Row generators can be used for e.g. summary rows or grouping of items. */ public interface RowGenerator extends Serializable { @@ -5807,7 +5883,7 @@ public class Table extends AbstractSelect implements Action.Container, * For custom styling of a generated row you can combine a RowGenerator * with a CellStyleGenerator. * <p> - * + * * @param table * The Table that is being painted * @param itemId @@ -5826,7 +5902,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Creates a new generated row. If only one string is passed in, columns * are automatically spanned. - * + * * @param text */ public GeneratedRow(String... text) { @@ -5861,7 +5937,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * If set to true, all strings passed to {@link #setText(String...)} * will be rendered as HTML. - * + * * @param htmlContentAllowed */ public void setHtmlContentAllowed(boolean htmlContentAllowed) { @@ -5875,7 +5951,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * If set to true, only one string will be rendered, spanning the entire * row. - * + * * @param spanColumns */ public void setSpanColumns(boolean spanColumns) { @@ -5886,7 +5962,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Assigns a row generator to the table. The row generator will be able to * replace rows in the table when it is rendered. - * + * * @param generator * the new row generator */ @@ -5908,7 +5984,7 @@ public class Table extends AbstractSelect implements Action.Container, * The converter is used to format the the data for the given property id * before displaying it in the table. * </p> - * + * * @param propertyId * The propertyId to format using the converter * @param converter @@ -5933,7 +6009,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Checks if there is a converter set explicitly for the given property id. - * + * * @param propertyId * The propertyId to check * @return true if a converter has been set for the property id, false @@ -5945,7 +6021,7 @@ public class Table extends AbstractSelect implements Action.Container, /** * Returns the converter used to format the given propertyId. - * + * * @param propertyId * The propertyId to check * @return The converter used to format the propertyId or null if no diff --git a/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRows.java b/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRows.java new file mode 100644 index 0000000000..d9cbf007df --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRows.java @@ -0,0 +1,73 @@ +package com.vaadin.tests.components.table; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import com.vaadin.data.util.BeanItemContainer; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Table; + +public class TableRepairsScrollPositionOnReAddingAllRows extends AbstractTestUI { + + private static final long serialVersionUID = 1L; + + @Override + protected void setup(VaadinRequest request) { + final BeanItemContainer<TableItem> cont = new BeanItemContainer<TableItem>( + TableItem.class); + final List<TableItem> itemList = new ArrayList<TableItem>(); + + Button button1 = new Button("ReAdd rows"); + button1.setId("button1"); + button1.addClickListener(new ClickListener() { + + @Override + public void buttonClick(com.vaadin.ui.Button.ClickEvent event) { + cont.removeAllItems(); + cont.addAll(itemList); + } + }); + + for (int i = 0; i < 80; i++) { + TableItem ti = new TableItem(); + ti.setName("Name_" + i); + itemList.add(ti); + cont.addBean(ti); + } + + final Table table = new Table(); + table.setPageLength(-1); + table.setContainerDataSource(cont); + table.setSelectable(true); + + getLayout().addComponent(button1); + getLayout().addComponent(table); + } + + public class TableItem implements Serializable { + private static final long serialVersionUID = -745849615488792221L; + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Override + protected Integer getTicketNumber() { + return 14581; + } + + @Override + protected String getTestDescription() { + return "The scroll position should not be changed if removing and re-adding all rows in Table."; + } +} diff --git a/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRowsTest.java b/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRowsTest.java new file mode 100644 index 0000000000..807a80d182 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableRepairsScrollPositionOnReAddingAllRowsTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedCondition; + +import com.vaadin.testbench.commands.TestBenchCommandExecutor; +import com.vaadin.testbench.elements.TableElement; +import com.vaadin.testbench.screenshot.ImageComparison; +import com.vaadin.testbench.screenshot.ReferenceNameGenerator; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TableRepairsScrollPositionOnReAddingAllRowsTest extends + MultiBrowserTest { + + @Test + public void testScrollRepairsAfterReAddingAllRows() + throws InterruptedException { + openTestURL(); + + WebElement buttonReAddRows = findElement(By.id("button1")); + + scrollUp(); + + waitUntilNot(new ExpectedCondition<Boolean>() { + @Override + public Boolean apply(WebDriver input) { + return $(TableElement.class).first().getCell(49, 0) == null; + } + }, 10); + + WebElement row = $(TableElement.class).first().getCell(49, 0); + int rowLocation = row.getLocation().getY(); + + buttonReAddRows.click(); + + row = $(TableElement.class).first().getCell(49, 0); + int newRowLocation = row.getLocation().getY(); + + assertThat( + "Scroll position should be the same as before Re-Adding all rows", + rowLocation == newRowLocation, is(true)); + } + + private void scrollUp() { + WebElement actualElement = getDriver().findElement( + By.className("v-table-body-wrapper")); + JavascriptExecutor js = new TestBenchCommandExecutor(getDriver(), + new ImageComparison(), new ReferenceNameGenerator()); + js.executeScript("arguments[0].scrollTop = " + 1200, actualElement); + } +} |