From 30850c74c0cacdb71fcf40f23c4432670e2f1b9d Mon Sep 17 00:00:00 2001 From: John Alhroos Date: Tue, 20 Apr 2010 14:40:50 +0000 Subject: [PATCH] Fix for multi page selection #3520 svn changeset:12714/svn branch:6.4 --- .../terminal/gwt/client/ui/VScrollTable.java | 70 +++++++++++++- src/com/vaadin/ui/Table.java | 93 +++++++++++++++++-- 2 files changed, 151 insertions(+), 12 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java index f5dcd07db4..6f8917c37b 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java @@ -127,6 +127,46 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, private final HashSet selectedRowKeys = new HashSet(); + /** + * Represents a select range of rows + */ + private class SelectionRange { + /** + * The starting key of the range + */ + private int startRowKey; + + /** + * The ending key of the range + */ + private int endRowKey; + + /** + * Constuctor. + * + * @param startRowKey + * The range start. Must be less than endRowKey + * @param endRowKey + * The range end. Must be bigger than startRowKey + */ + public SelectionRange(int startRowKey, int endRowKey) { + this.startRowKey = startRowKey; + this.endRowKey = endRowKey; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return startRowKey + "-" + endRowKey; + } + }; + + private final HashSet selectedRowRanges = new HashSet(); + private boolean initializedAndAttached = false; /** @@ -275,6 +315,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, final Set selectedKeys = uidl .getStringArrayVariableAsSet("selected"); selectedRowKeys.clear(); + selectedRowRanges.clear(); for (String string : selectedKeys) { selectedRowKeys.add(string); } @@ -3183,6 +3224,21 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, // might // require changes to "clickEvent" immediateness // also. + if (multiselectmode == MULTISELECT_MODE_DEFAULT) { + Set ranges = new HashSet(); + for (SelectionRange range : selectedRowRanges) { + ranges.add(range.toString()); + } + client + .updateVariable( + paintableId, + "selectedRanges", + ranges + .toArray(new String[selectedRowRanges + .size()]), + false); + } + client .updateVariable( paintableId, @@ -3380,6 +3436,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, * previous selection which was not a deselection */ if (selectedRowKeys.isEmpty() || lastSelectedRowKey < 0) { + // No previous selection found deselectAll(); toggleSelection(true); return; @@ -3403,17 +3460,19 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, // Select the range (not including this row) for (int r = startKey; r <= endKey; r++) { if (r != rowKey) { - selectedRowKeys.add(String.valueOf(r)); VScrollTableRow row = getRenderedRowByKey(String .valueOf(r)); - if (!row.isSelected()) { + if (row != null && !row.isSelected()) { row.toggleSelection(false); } } } - + // Toggle clicked rows selection toggleSelection(false); + + // Add range + selectedRowRanges.add(new SelectionRange(startKey, endKey)); } /* @@ -3515,6 +3574,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } + /** + * Deselects all items + */ public void deselectAll() { final Object[] keys = selectedRowKeys.toArray(); for (int i = 0; i < keys.length; i++) { @@ -3525,7 +3587,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } // still ensure all selects are removed from (not necessary rendered) selectedRowKeys.clear(); - + selectedRowRanges.clear(); } /** diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java index 94e26810fa..234173c2f1 100644 --- a/src/com/vaadin/ui/Table.java +++ b/src/com/vaadin/ui/Table.java @@ -1863,7 +1863,77 @@ public class Table extends AbstractSelect implements Action.Container, resetPageBuffer(); enableContentRefreshing(true); + } + + /** + * Gets items ids from a range of key values + * + * @param startRowKey + * The start key + * @param endRowKey + * The end key + * @return + */ + private Set getItemIdsInRange(int startRowKey, int endRowKey) { + HashSet ids = new HashSet(); + + Object startItemId = itemIdMapper.get(String.valueOf(startRowKey)); + ids.add(startItemId); + + Object endItemId = itemIdMapper.get(String.valueOf(endRowKey)); + ids.add(endItemId); + + Object currentItemId = startItemId; + + Container.Ordered ordered = (Container.Ordered) items; + while (currentItemId != endItemId) { + currentItemId = ordered.nextItemId(currentItemId); + if (currentItemId != null) { + ids.add(currentItemId); + } + } + + return ids; + } + + /** + * Handles selection if selection is a multiselection + * + * @param variables + * The variables + */ + private void handleSelectedItems(Map variables) { + final String[] ka = (String[]) variables.get("selected"); + final String[] ranges = (String[]) variables.get("selectedRanges"); + + // Converts the key-array to id-set + final LinkedList s = new LinkedList(); + for (int i = 0; i < ka.length; i++) { + final Object id = itemIdMapper.get(ka[i]); + if (!isNullSelectionAllowed() + && (id == null || id == getNullSelectionItemId())) { + // skip empty selection if nullselection is not allowed + requestRepaint(); + } else if (id != null && containsId(id)) { + s.add(id); + } + } + if (!isNullSelectionAllowed() && s.size() < 1) { + // empty selection not allowed, keep old value + requestRepaint(); + return; + } + + // Add range items + for (String range : ranges) { + String[] limits = range.split("-"); + int start = Integer.valueOf(limits[0]); + int end = Integer.valueOf(limits[1]); + s.addAll(getItemIdsInRange(start, end)); + } + + setValue(s, true); } /* Component basics */ @@ -1890,6 +1960,18 @@ public class Table extends AbstractSelect implements Action.Container, variables.remove("selected"); } + /* + * The AbstractSelect cannot handle the multiselection properly, instead + * we handle it ourself + */ + else if (isSelectable() && isMultiSelect() + && variables.containsKey("selected") + && multiSelectMode == MultiSelectMode.DEFAULT) { + handleSelectedItems(variables); + variables = new HashMap(variables); + variables.remove("selected"); + } + super.changeVariables(source, variables); // Client might update the pagelength if Table height is fixed @@ -2164,15 +2246,10 @@ public class Table extends AbstractSelect implements Action.Container, // selection support LinkedList selectedKeys = new LinkedList(); - if (isMultiSelect()) { - // only paint selections that are currently visible in the client + if (isMultiSelect()) { HashSet sel = new HashSet((Set) getValue()); - Collection vids = getVisibleItemIds(); - for (Iterator it = vids.iterator(); it.hasNext();) { - Object id = it.next(); - if (sel.contains(id)) { - selectedKeys.add(itemIdMapper.key(id)); - } + for (Object id : sel) { + selectedKeys.add(itemIdMapper.key(id)); } } else { Object value = getValue(); -- 2.39.5