summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/vaadin/ui/Table.java119
1 files changed, 115 insertions, 4 deletions
diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java
index 5c985d91b7..4bb118dd73 100644
--- a/src/com/vaadin/ui/Table.java
+++ b/src/com/vaadin/ui/Table.java
@@ -1472,8 +1472,85 @@ public class Table extends AbstractSelect implements Action.Container,
requestRepaint();
}
- private Object[][] getVisibleCellsNoCache(int firstIndex, int rows) {
- return getVisibleCellsNoCache(firstIndex, rows, false);
+ private void removeRowsFromCacheAndFillBottom(int firstIndex, int rows) {
+ int totalCachedRows = pageBuffer[CELL_ITEMID].length;
+ int totalRows = size();
+ int cacheIx = firstIndex - pageBufferFirstIndex;
+
+ // Make sure that no components leak.
+ unregisterComponentsAndPropertiesInRows(firstIndex, rows);
+
+ int newCachedRowCount = totalRows < totalCachedRows ? totalRows
+ : totalCachedRows;
+ int firstAppendedRow = newCachedRowCount - rows;
+ Object[][] cells = getVisibleCellsNoCache(firstAppendedRow, rows, false);
+
+ // Create the new cache buffer by copying data from the old one and
+ // appending more rows if applicable.
+ Object[][] newPageBuffer = new Object[pageBuffer.length][newCachedRowCount];
+ for (int ix = 0; ix < newCachedRowCount; ix++) {
+ for (int i = 0; i < pageBuffer.length; i++) {
+ if (ix >= newCachedRowCount - rows) {
+ newPageBuffer[i][ix] = cells[i][ix
+ - (newCachedRowCount - rows)];
+ } else if (ix >= cacheIx) {
+ newPageBuffer[i][ix] = pageBuffer[i][ix + rows];
+ } else {
+ newPageBuffer[i][ix] = pageBuffer[i][ix];
+ }
+ }
+ }
+ pageBuffer = newPageBuffer;
+ }
+
+ private Object[][] getVisibleCellsUpdateCacheRows(int firstIndex, int rows) {
+ Object[][] cells = getVisibleCellsNoCache(firstIndex, rows, false);
+ int cacheIx = firstIndex - pageBufferFirstIndex;
+ // update the new rows in the cache.
+ for (int ix = cacheIx; ix < cacheIx + rows; ix++) {
+ for (int i = 0; i < pageBuffer.length; i++) {
+ pageBuffer[i][ix] = cells[i][ix - cacheIx];
+ }
+ }
+ return cells;
+ }
+
+ private Object[][] getVisibleCellsInsertIntoCache(int firstIndex, int rows) {
+ Object[][] cells = getVisibleCellsNoCache(firstIndex, rows, false);
+ int currentlyCachedRowCount = pageBuffer[CELL_ITEMID].length;
+ int lastCachedRow = currentlyCachedRowCount - rows;
+ int cacheIx = firstIndex - pageBufferFirstIndex;
+
+ // Unregister all components that fall beyond the cache limits after
+ // inserting the new rows.
+ unregisterComponentsAndPropertiesInRows(lastCachedRow + 1,
+ currentlyCachedRowCount - lastCachedRow);
+
+ // Calculate the new cache size
+ int newCachedRowCount = currentlyCachedRowCount;
+ if (currentlyCachedRowCount < pageLength) {
+ newCachedRowCount = currentlyCachedRowCount + rows;
+ if (newCachedRowCount > pageLength) {
+ newCachedRowCount = pageLength;
+ }
+ }
+
+ // Create the new cache buffer and fill it with the data from the old
+ // buffer as well as the inserted rows.
+ Object[][] newPageBuffer = new Object[pageBuffer.length][newCachedRowCount];
+ for (int ix = 0; ix < newCachedRowCount; ix++) {
+ for (int i = 0; i < pageBuffer.length; i++) {
+ if (ix >= cacheIx && ix < cacheIx + rows) {
+ newPageBuffer[i][ix] = cells[i][ix - cacheIx];
+ } else if (ix >= cacheIx + rows) {
+ newPageBuffer[i][ix] = pageBuffer[i][ix - rows];
+ } else {
+ newPageBuffer[i][ix] = pageBuffer[i][ix];
+ }
+ }
+ }
+ pageBuffer = newPageBuffer;
+ return cells;
}
private Object[][] getVisibleCellsNoCache(int firstIndex, int rows,
@@ -1680,6 +1757,39 @@ public class Table extends AbstractSelect implements Action.Container,
}
/**
+ * @param firstIx
+ * @param count
+ */
+ private void unregisterComponentsAndPropertiesInRows(int firstIx, int count) {
+ Object[] colids = getVisibleColumns();
+ if (pageBuffer != null && pageBuffer[CELL_ITEMID].length > 0) {
+ int bufSize = pageBuffer[CELL_ITEMID].length;
+ int ix = firstIx - pageBufferFirstIndex;
+ if (ix < bufSize) {
+ count = count > bufSize - ix ? bufSize - ix : count;
+ for (int i = 0; i < count; i++) {
+ for (int c = 0; c < colids.length; c++) {
+ Object cellVal = pageBuffer[CELL_FIRSTCOL + c][i + ix];
+ if (cellVal instanceof Component
+ && visibleComponents.contains(cellVal)) {
+ visibleComponents.remove(cellVal);
+ unregisterComponent((Component) cellVal);
+ } else {
+ Property p = getContainerProperty(
+ pageBuffer[CELL_ITEMID][i + ix], colids[c]);
+ if (p instanceof ValueChangeNotifier
+ && listenedProperties.contains(p)) {
+ listenedProperties.remove(p);
+ ((ValueChangeNotifier) p).removeListener(this);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
* Helper method to remove listeners and maintain correct component
* hierarchy. Detaches properties and components if those are no more
* rendered in client.
@@ -2410,7 +2520,7 @@ public class Table extends AbstractSelect implements Action.Container,
target.addAttribute("numurows", count);
// Partial row updates bypass the normal caching mechanism.
- Object[][] cells = getVisibleCellsNoCache(firstIx, count);
+ Object[][] cells = getVisibleCellsUpdateCacheRows(firstIx, count);
for (int indexInRowbuffer = 0; indexInRowbuffer < count; indexInRowbuffer++) {
final Object itemId = cells[CELL_ITEMID][indexInRowbuffer];
@@ -2447,7 +2557,7 @@ public class Table extends AbstractSelect implements Action.Container,
if (!shouldHideAddedRows()) {
// Partial row additions bypass the normal caching mechanism.
- Object[][] cells = getVisibleCellsNoCache(firstIx, count);
+ Object[][] cells = getVisibleCellsInsertIntoCache(firstIx, count);
for (int indexInRowbuffer = 0; indexInRowbuffer < count; indexInRowbuffer++) {
final Object itemId = cells[CELL_ITEMID][indexInRowbuffer];
if (shouldHideNullSelectionItem()) {
@@ -2460,6 +2570,7 @@ public class Table extends AbstractSelect implements Action.Container,
indexInRowbuffer, itemId);
}
} else {
+ removeRowsFromCacheAndFillBottom(firstIx, count);
target.addAttribute("hide", true);
}
target.endTag("prows");