svn changeset:12714/svn branch:6.4tags/6.7.0.beta1
@@ -127,6 +127,46 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, | |||
private final HashSet<String> selectedRowKeys = new HashSet<String>(); | |||
/** | |||
* 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<SelectionRange> selectedRowRanges = new HashSet<SelectionRange>(); | |||
private boolean initializedAndAttached = false; | |||
/** | |||
@@ -275,6 +315,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, | |||
final Set<String> 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<String> ranges = new HashSet<String>(); | |||
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(); | |||
} | |||
/** |
@@ -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<Object> getItemIdsInRange(int startRowKey, int endRowKey) { | |||
HashSet<Object> ids = new HashSet<Object>(); | |||
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<String, Object> 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<String, Object>(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<String> selectedKeys = new LinkedList<String>(); | |||
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(); |