diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableMultiSelectionModel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableMultiSelectionModel.java index 11055c02646..aeb9634fccb 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableMultiSelectionModel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableMultiSelectionModel.java @@ -24,9 +24,11 @@ import com.google.gwt.view.client.SelectionModel; *

* For more details on the update process read the {@link RefreshableSelectionModel} Javadoc and see the methods * {@link RefreshableMultiSelectionModel#refreshSelectionModel(Iterable)} and - * {@link RefreshableMultiSelectionModel#setRowData(int, List)}. + * {@link RefreshableMultiSelectionModel#setRowData(int, List)}.

* - * @author D064976 + * TODO try to factor out the commonalities with RefreshableSingleSelectionModel into a delegate + * + * @author Lukas Furmanek * @param * the type of entries */ @@ -44,10 +46,7 @@ public class RefreshableMultiSelectionModel extends MultiSelectionModel * display on {@link ListDataProvider} */ public RefreshableMultiSelectionModel(EntityIdentityComparator comp, ListDataProvider listDataProvider) { - super(); - this.comp = comp; - this.listDataProvider = listDataProvider; - this.listDataProvider.addDataDisplay(this); + this(/* keyProvider */ null, comp, listDataProvider); } /** @@ -84,7 +83,7 @@ public class RefreshableMultiSelectionModel extends MultiSelectionModel */ @Override public void setSelected(T item, boolean selected) { - if (comp == null || dontcheckSelectionState || item == null || getSelectedSet() == null) { + if (comp == null || dontcheckSelectionState || item == null || getSelectedSet().isEmpty()) { super.setSelected(item, selected); } else { T wasSelectedBefore = null; @@ -97,7 +96,7 @@ public class RefreshableMultiSelectionModel extends MultiSelectionModel } if (wasSelectedBefore != null) { super.setSelected(wasSelectedBefore, false); - isSelected(item); //triggers the deleting of the wasSelectedBefrore element in super class + isSelected(item); // triggers the deleting of the wasSelectedBefrore element in super class super.setSelected(item, selected); } else { super.setSelected(item, selected); @@ -119,31 +118,37 @@ public class RefreshableMultiSelectionModel extends MultiSelectionModel * {@link AbstractSelectionModel#fireEvent(com.google.gwt.event.shared.GwtEvent)}. * * @param newObjects - * the new objects to refresh the {@link RefreshableMultiSelectionModel selectionmodel} + * the new objects to refresh the {@link RefreshableMultiSelectionModel selection model} */ - private void refreshSelectionModel(Iterable newObjects) { - dontcheckSelectionState = true; - final Set selectedSet = getSelectedSet(); - final boolean isEmpty = selectedSet.isEmpty(); - if (!isEmpty) { - clear(); - for (T it : newObjects) { - if (comp == null) { - setSelected(it, selectedSet.contains(it)); - } else { - boolean isSelected = false; - for (T selected : selectedSet) { - isSelected = comp.representSameEntity(selected, it); - if (isSelected) { - setSelected(it, isSelected); - break; + private void refreshSelectionModel(Iterable newObjects) { + if (!dontcheckSelectionState) { // avoid endless recursions + dontcheckSelectionState = true; + try { + final Set selectedSet = getSelectedSet(); // gets the selected set as a non-live copy, so later + // changes to the selection won't change this set anymore + final boolean isEmpty = selectedSet.isEmpty(); + if (!isEmpty) { + clear(); + for (T it : newObjects) { + if (comp == null) { + setSelected(it, selectedSet.contains(it)); + } else { + boolean isSelected = false; + for (T selected : selectedSet) { // FIXME leads to O(n^2) effort which is inacceptable for large tables with all elements selected + isSelected = comp.representSameEntity(selected, it); + if (isSelected) { + setSelected(it, isSelected); + break; + } + } } - } + } + SelectionChangeEvent.fire(this); } + } finally { + dontcheckSelectionState = false; } - SelectionChangeEvent.fire(this); } - dontcheckSelectionState = false; } /** @@ -152,7 +157,7 @@ public class RefreshableMultiSelectionModel extends MultiSelectionModel */ @Override public void setRowData(int start, List values) { - refreshSelectionModel(new ArrayList<>(listDataProvider.getList())); + refreshSelectionModel(listDataProvider.getList()); } @Override diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableSelectionModel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableSelectionModel.java index fb27830ee65..7d8c87d72fc 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableSelectionModel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableSelectionModel.java @@ -8,25 +8,25 @@ import com.google.gwt.view.client.SingleSelectionModel; /** * The {@link RefreshableSelectionModel} unifies the refresh behavior of SelectionModels e.g. of a - * {@link SingleSelectionModel}. This {@link RefreshableSelectionModel selectionmodel} will automatically refresh the - * selection, when there are changes on the {@link ListDataProvider}. Therefore the {@link RefreshableSelectionModel - * selectionmodel} is a listener of the {@link ListDataProvider} and implements the {@link HasData}-interface. + * {@link SingleSelectionModel}. This {@link RefreshableSelectionModel selection model} will automatically refresh the + * selection when there are changes on the {@link ListDataProvider}. Therefore the {@link RefreshableSelectionModel + * selection model} is a listener of the {@link ListDataProvider} and implements the {@link HasData}-interface. *

* All objects from the current selection that {@link EntityIdentityComparator#representSameEntity(Object, Object) * represent the same entity} as a new object from {@link ListDataProvider} will be reselected. All others are - * de-selected. That means a selected object is not contained in {@link ListDataProvider#getList()} wouldn't be selected - * anymore. If an element is reselected the element will be replaced with new version of it. + * de-selected. That means a selected object that is not contained in {@link ListDataProvider#getList()} wouldn't be + * selected anymore. If an element is reselected the element will be replaced with new version of it. *

* If this selection model has no {@link EntityIdentityComparator} set, this method will use the {@link #equals(Object)} * method to compare. *

- * When the selection is refreshed this {@link RefreshableSelectionModel selectionmodel} triggers a + * When the selection is refreshed this {@link RefreshableSelectionModel selection model} triggers a * {@link SelectionChangeEvent.Handler#onSelectionChange(SelectionChangeEvent) onSelectionChangedEvent} using * {@link AbstractSelectionModel#fireEvent(com.google.gwt.event.shared.GwtEvent)}. *

- * When you use this {@link RefreshableSelectionModel selectionmodel} make sure that you don't modify + * When you use this {@link RefreshableSelectionModel selection model} make sure that you don't modify * {@link ListDataProvider} in {@link Handler#onSelectionChange(com.google.gwt.view.client.SelectionChangeEvent) - * onSelectionChange()} (it causes a stackoverflow). + * onSelectionChange()} (it causes a stack overflow). * * @author D064976 */ @@ -36,5 +36,5 @@ public interface RefreshableSelectionModel extends SetSelectionModel, HasD * @return Returns an instance of {@link EntityIdentityComparator}, to compare objects from the type * <T>. */ - public EntityIdentityComparator getEntityIdentityComparator(); + EntityIdentityComparator getEntityIdentityComparator(); } \ No newline at end of file diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableSingleSelectionModel.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableSingleSelectionModel.java index c9c845e8cb9..beb76970ba1 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableSingleSelectionModel.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableSingleSelectionModel.java @@ -21,9 +21,11 @@ import com.google.gwt.view.client.RangeChangeEvent.Handler; *

* For more details on the update process read the {@link RefreshableSelectionModel} Javadoc and see the methods * {@link RefreshableSingleSelectionModel#refreshSelectionModel(Iterable)} and - * {@link RefreshableSingleSelectionModel#setRowData(int, List)}. + * {@link RefreshableSingleSelectionModel#setRowData(int, List)}.

* - * @author D064976 + * TODO try to factor out the commonalities with RefreshableMultiSelectionModel into a delegate + * + * @author Lukas Furmanek * @param * the type of entries */ @@ -108,21 +110,26 @@ public class RefreshableSingleSelectionModel extends SingleSelectionModel * the new objects to refresh the {@link RefreshableSingleSelectionModel selectionmodel} */ private void refreshSelectionModel(Iterable newObjects) { - // avoid a new selection state check in setSelected - dontcheckSelectionState = true; - final T selected = getSelectedObject(); - if (selected != null) { - clear(); - for (final T it : newObjects) { - boolean isEqual = comp == null ? selected.equals(it) : comp.representSameEntity(selected, it); - if (isEqual) { - setSelected(it, true); - break; + if (!dontcheckSelectionState) { // avoid endless recursion + try { + // avoid a new selection state check in setSelected + dontcheckSelectionState = true; + final T selected = getSelectedObject(); + if (selected != null) { + clear(); + for (final T it : newObjects) { + boolean isEqual = comp == null ? selected.equals(it) : comp.representSameEntity(selected, it); + if (isEqual) { + setSelected(it, true); + break; + } + } } + SelectionChangeEvent.fire(this); + } finally { + dontcheckSelectionState = false; } } - SelectionChangeEvent.fire(this); - dontcheckSelectionState = false; } /**