4545@ JsModule ("./src/vcf-selection-grid.js" )
4646@ JsModule ("./src/selection-grid.js" )
4747public class SelectionGrid <T > extends Grid <T > {
48+
49+ private Integer selectRangeOnlyFromIndex = null ;
50+ private Set <T > selectRangeOnlySelection = new HashSet <T >();
4851
4952 /**
5053 * @see Grid#Grid()
@@ -163,18 +166,41 @@ private String getColumnInternalId(Column<T> column) {
163166 private void selectRange (int fromIndex , int toIndex ) {
164167 GridSelectionModel <T > model = getSelectionModel ();
165168 if (model instanceof GridMultiSelectionModel ) {
166- DataCommunicator <T > dataCommunicator = super .getDataCommunicator ();
167- Method fetchFromProvider ;
168- try {
169- fetchFromProvider = DataCommunicator .class .getDeclaredMethod ("fetchFromProvider" , int .class , int .class );
170- fetchFromProvider .setAccessible (true );
171- asMultiSelect ().select (((Stream <T >) fetchFromProvider .invoke (dataCommunicator , Math .min (fromIndex , toIndex ), Math .max (fromIndex ,
172- toIndex ) - Math .min (fromIndex , toIndex ) + 1 )).collect (Collectors .toList ()));
173- } catch (Exception ignored ) {
174- ignored .printStackTrace ();
175- }
169+ this .getUI ().ifPresent (ui ->ui .beforeClientResponse (this , (ctx )->{
170+ Set <T > newSelectedItems = obtainNewSelectedItems (fromIndex , toIndex );
171+ asMultiSelect ().select (newSelectedItems );
172+ }));
176173 }
177174 }
175+
176+ @ SuppressWarnings ("unchecked" )
177+ private Set <T > obtainNewSelectedItems (int fromIndex , int toIndex ) {
178+ DataCommunicator <T > dataCommunicator = super .getDataCommunicator ();
179+ Set <T > newSelectedItems = new HashSet <>();
180+ int from = Math .min (fromIndex , toIndex );
181+ int to = Math .max (fromIndex , toIndex ) + 1 ;
182+ int pageSize = dataCommunicator .getPageSize ();
183+ if (to - from < (pageSize * 2 ) - 3 ) {
184+ // if the range to be retrieved is smaller than 2 pages
185+ // ask the dataCommunicator to retrieve the items so the cache is used
186+ for (int i = from ; i < to ; i ++) {
187+ newSelectedItems .add (dataCommunicator .getItem (i ));
188+ }
189+ } else {
190+ // if the range to be retrieved is bigger then use the fetchFromProvider method
191+ // that load the items in pages reducing the amount of queries to the backend
192+ Method fetchFromProvider ;
193+ try {
194+ fetchFromProvider = DataCommunicator .class .getDeclaredMethod ("fetchFromProvider" , int .class , int .class );
195+ fetchFromProvider .setAccessible (true );
196+ newSelectedItems .addAll (((Stream <T >) fetchFromProvider .invoke (dataCommunicator , from , to - from + 1 )).collect (Collectors .toList ()));
197+ } catch (Exception ignored ) {
198+ ignored .printStackTrace ();
199+ }
200+ }
201+ return newSelectedItems ;
202+ }
203+
178204
179205 /**
180206 * Select the range and deselect the other items
@@ -183,19 +209,58 @@ private void selectRange(int fromIndex, int toIndex) {
183209 * @param toIndex
184210 */
185211 @ ClientCallable
186- private void selectRangeOnly (int fromIndex , int toIndex ) {
187- GridSelectionModel <T > model = getSelectionModel ();
188- if (model instanceof GridMultiSelectionModel ) {
189- int from = Math .min (fromIndex , toIndex );
190- int to = Math .max (fromIndex , toIndex );
191- fetchFromProvider (from , to - from + 1 ).ifPresent (stream -> {
192- Set <T > newSelectedItems = stream .collect (Collectors .toSet ());
193- HashSet <T > oldSelectedItems = new HashSet <>(getSelectedItems ());
194- oldSelectedItems .removeAll (newSelectedItems );
195- asMultiSelect ().updateSelection (newSelectedItems , oldSelectedItems );
196- });
197- }
198- }
212+ private void selectRangeOnly (int fromIndex , int toIndex ) {
213+ int start = fromIndex < toIndex ? fromIndex : toIndex ;
214+ int end = fromIndex < toIndex ? toIndex : fromIndex ;
215+ GridSelectionModel <T > model = getSelectionModel ();
216+ if (model instanceof GridMultiSelectionModel ) {
217+
218+ Set <T > newSelectedItems = new HashSet <T >();
219+
220+ int calculatedFromIndex = start ;
221+
222+ // selectRangeOnlySelection will keep the items already selected so there's no unnecessary
223+ // call to backend done
224+ if (!selectRangeOnlySelection .isEmpty ()) {
225+ int firstKey = selectRangeOnlyFromIndex ;
226+ int lastKey = firstKey + selectRangeOnlySelection .size () - 1 ;
227+
228+ // recalculate from index so already selected items are not re-selected and no
229+ // unnecessary call to backend is done
230+ if (start == firstKey && end > lastKey ) {
231+ calculatedFromIndex = lastKey ;
232+ newSelectedItems .addAll (selectRangeOnlySelection );
233+ }
234+ }
235+
236+ final int calculatedFromIndexFinal = calculatedFromIndex ;
237+ this .getUI ().ifPresent (ui ->ui .beforeClientResponse (this , (ctx )->{
238+ newSelectedItems .addAll (obtainNewSelectedItems (calculatedFromIndexFinal , end ));
239+ HashSet <T > oldSelectedItems = new HashSet <>(getSelectedItems ());
240+ oldSelectedItems .removeAll (newSelectedItems );
241+ asMultiSelect ().updateSelection (newSelectedItems , oldSelectedItems );
242+ }));
243+
244+ // update selectRangeOnlySelection with new selected items
245+ selectRangeOnlySelection = new HashSet <T >(getSelectedItems ());
246+ selectRangeOnlyFromIndex = fromIndex ;
247+ }
248+ }
249+
250+ /**
251+ * Select the range on click and makes sure selectRangeOnlySelection is cleared.
252+ *
253+ * @param fromIndex
254+ * @param toIndex
255+ */
256+ @ ClientCallable
257+ private void selectRangeOnlyOnClick (int fromIndex , int toIndex ) {
258+ selectRangeOnlySelection .clear ();
259+ selectRangeOnlyFromIndex = null ;
260+ this .getUI ().ifPresent (ui ->ui .beforeClientResponse (this , (ctx )->{
261+ this .selectRangeOnly (fromIndex , toIndex );
262+ }));
263+ }
199264
200265 private Optional <Stream <T >> fetchFromProvider (int offset , int limit ) {
201266 DataCommunicator <T > dataCommunicator = super .getDataCommunicator ();
0 commit comments