root / src / gr / grnet / pithos / web / client / PithosSelectionEventManager.java @ 0c26bcb8
History | View | Annotate | Download (18.9 kB)
1 | a57faaf0 | Christos Stathis | /*
|
---|---|---|---|
2 | cae2a8db | Christos Stathis | * Copyright 2011-2012 GRNET S.A. All rights reserved.
|
3 | 63366925 | Christos Stathis | *
|
4 | 63366925 | Christos Stathis | * Redistribution and use in source and binary forms, with or
|
5 | 63366925 | Christos Stathis | * without modification, are permitted provided that the following
|
6 | 63366925 | Christos Stathis | * conditions are met:
|
7 | 63366925 | Christos Stathis | *
|
8 | 63366925 | Christos Stathis | * 1. Redistributions of source code must retain the above
|
9 | 63366925 | Christos Stathis | * copyright notice, this list of conditions and the following
|
10 | 63366925 | Christos Stathis | * disclaimer.
|
11 | 63366925 | Christos Stathis | *
|
12 | 63366925 | Christos Stathis | * 2. Redistributions in binary form must reproduce the above
|
13 | 63366925 | Christos Stathis | * copyright notice, this list of conditions and the following
|
14 | 63366925 | Christos Stathis | * disclaimer in the documentation and/or other materials
|
15 | 63366925 | Christos Stathis | * provided with the distribution.
|
16 | 63366925 | Christos Stathis | *
|
17 | 63366925 | Christos Stathis | * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
18 | 63366925 | Christos Stathis | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
19 | 63366925 | Christos Stathis | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
20 | 63366925 | Christos Stathis | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
21 | 63366925 | Christos Stathis | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
22 | 63366925 | Christos Stathis | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
23 | 63366925 | Christos Stathis | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
24 | 63366925 | Christos Stathis | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
25 | 63366925 | Christos Stathis | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
26 | 63366925 | Christos Stathis | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
27 | 63366925 | Christos Stathis | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
28 | 63366925 | Christos Stathis | * POSSIBILITY OF SUCH DAMAGE.
|
29 | 63366925 | Christos Stathis | *
|
30 | 63366925 | Christos Stathis | * The views and conclusions contained in the software and
|
31 | 63366925 | Christos Stathis | * documentation are those of the authors and should not be
|
32 | 63366925 | Christos Stathis | * interpreted as representing official policies, either expressed
|
33 | 63366925 | Christos Stathis | * or implied, of GRNET S.A.
|
34 | a57faaf0 | Christos Stathis | */
|
35 | a57faaf0 | Christos Stathis | package gr.grnet.pithos.web.client; |
36 | a57faaf0 | Christos Stathis | |
37 | a57faaf0 | Christos Stathis | |
38 | a57faaf0 | Christos Stathis | |
39 | a57faaf0 | Christos Stathis | import java.util.ArrayList; |
40 | a57faaf0 | Christos Stathis | import java.util.List; |
41 | a57faaf0 | Christos Stathis | |
42 | a57faaf0 | Christos Stathis | import com.google.gwt.dom.client.Element; |
43 | a57faaf0 | Christos Stathis | import com.google.gwt.dom.client.InputElement; |
44 | a57faaf0 | Christos Stathis | import com.google.gwt.dom.client.NativeEvent; |
45 | a57faaf0 | Christos Stathis | import com.google.gwt.view.client.CellPreviewEvent; |
46 | a57faaf0 | Christos Stathis | import com.google.gwt.view.client.HasData; |
47 | a57faaf0 | Christos Stathis | import com.google.gwt.view.client.MultiSelectionModel; |
48 | a57faaf0 | Christos Stathis | import com.google.gwt.view.client.Range; |
49 | a57faaf0 | Christos Stathis | import com.google.gwt.view.client.SelectionModel; |
50 | a57faaf0 | Christos Stathis | |
51 | a57faaf0 | Christos Stathis | /**
|
52 | 7811b9d1 | Christos Stathis | * An implementation of {@link com.google.gwt.view.client.CellPreviewEvent.Handler} that adds selection
|
53 | a57faaf0 | Christos Stathis | * support via the spacebar and mouse clicks and handles the control key.
|
54 | a57faaf0 | Christos Stathis | *
|
55 | a57faaf0 | Christos Stathis | * <p>
|
56 | a57faaf0 | Christos Stathis | * If the {@link HasData} source of the selection event uses a
|
57 | a57faaf0 | Christos Stathis | * {@link MultiSelectionModel}, this manager additionally provides support for
|
58 | a57faaf0 | Christos Stathis | * shift key to select a range of values. For all other {@link SelectionModel}s,
|
59 | a57faaf0 | Christos Stathis | * only the control key is supported.
|
60 | a57faaf0 | Christos Stathis | * </p>
|
61 | a57faaf0 | Christos Stathis | *
|
62 | a57faaf0 | Christos Stathis | * @param <T> the data type of records in the list
|
63 | a57faaf0 | Christos Stathis | */
|
64 | 969a4d94 | Christos Stathis | public class PithosSelectionEventManager<T> implements |
65 | a57faaf0 | Christos Stathis | CellPreviewEvent.Handler<T> { |
66 | a57faaf0 | Christos Stathis | |
67 | a57faaf0 | Christos Stathis | /**
|
68 | 969a4d94 | Christos Stathis | * Implementation of {@link gr.grnet.pithos.web.client.PithosSelectionEventManager.EventTranslator} that only triggers selection when
|
69 | a57faaf0 | Christos Stathis | * any checkbox is selected.
|
70 | a57faaf0 | Christos Stathis | *
|
71 | a57faaf0 | Christos Stathis | * @param <T> the data type
|
72 | a57faaf0 | Christos Stathis | */
|
73 | a57faaf0 | Christos Stathis | public static class CheckboxEventTranslator<T> implements EventTranslator<T> { |
74 | a57faaf0 | Christos Stathis | |
75 | a57faaf0 | Christos Stathis | /**
|
76 | a57faaf0 | Christos Stathis | * The column index of the checkbox. Other columns are ignored.
|
77 | a57faaf0 | Christos Stathis | */
|
78 | a57faaf0 | Christos Stathis | private final int column; |
79 | a57faaf0 | Christos Stathis | |
80 | a57faaf0 | Christos Stathis | /**
|
81 | 969a4d94 | Christos Stathis | * Construct a new {@link gr.grnet.pithos.web.client.PithosSelectionEventManager.CheckboxEventTranslator} that will trigger
|
82 | a57faaf0 | Christos Stathis | * selection when any checkbox in any column is selected.
|
83 | a57faaf0 | Christos Stathis | */
|
84 | a57faaf0 | Christos Stathis | public CheckboxEventTranslator() {
|
85 | a57faaf0 | Christos Stathis | this(-1); |
86 | a57faaf0 | Christos Stathis | } |
87 | a57faaf0 | Christos Stathis | |
88 | a57faaf0 | Christos Stathis | /**
|
89 | 969a4d94 | Christos Stathis | * Construct a new {@link gr.grnet.pithos.web.client.PithosSelectionEventManager.CheckboxEventTranslator} that will trigger
|
90 | a57faaf0 | Christos Stathis | * selection when a checkbox in the specified column is selected.
|
91 | a57faaf0 | Christos Stathis | *
|
92 | a57faaf0 | Christos Stathis | * @param column the column index, or -1 for all columns
|
93 | a57faaf0 | Christos Stathis | */
|
94 | a57faaf0 | Christos Stathis | public CheckboxEventTranslator(int column) { |
95 | a57faaf0 | Christos Stathis | this.column = column;
|
96 | a57faaf0 | Christos Stathis | } |
97 | a57faaf0 | Christos Stathis | |
98 | 7811b9d1 | Christos Stathis | @Override
|
99 | ebead1b5 | Christos Stathis | public boolean clearCurrentSelection(CellPreviewEvent<T> event) { |
100 | a57faaf0 | Christos Stathis | return false; |
101 | a57faaf0 | Christos Stathis | } |
102 | a57faaf0 | Christos Stathis | |
103 | 7811b9d1 | Christos Stathis | @Override
|
104 | 7811b9d1 | Christos Stathis | public SelectAction translateSelectionEvent(CellPreviewEvent<T> event) {
|
105 | a57faaf0 | Christos Stathis | // Handle the event.
|
106 | a57faaf0 | Christos Stathis | NativeEvent nativeEvent = event.getNativeEvent(); |
107 | a57faaf0 | Christos Stathis | if ("click".equals(nativeEvent.getType())) { |
108 | a57faaf0 | Christos Stathis | // Ignore if the event didn't occur in the correct column.
|
109 | a57faaf0 | Christos Stathis | if (column > -1 && column != event.getColumn()) { |
110 | a57faaf0 | Christos Stathis | return SelectAction.IGNORE;
|
111 | a57faaf0 | Christos Stathis | } |
112 | a57faaf0 | Christos Stathis | |
113 | a57faaf0 | Christos Stathis | // Determine if we clicked on a checkbox.
|
114 | a57faaf0 | Christos Stathis | Element target = nativeEvent.getEventTarget().cast();
|
115 | a57faaf0 | Christos Stathis | if ("input".equals(target.getTagName().toLowerCase())) { |
116 | a57faaf0 | Christos Stathis | final InputElement input = target.cast();
|
117 | a57faaf0 | Christos Stathis | if ("checkbox".equals(input.getType().toLowerCase())) { |
118 | a57faaf0 | Christos Stathis | // Synchronize the checkbox with the current selection state.
|
119 | a57faaf0 | Christos Stathis | input.setChecked(event.getDisplay().getSelectionModel().isSelected( |
120 | a57faaf0 | Christos Stathis | event.getValue())); |
121 | a57faaf0 | Christos Stathis | return SelectAction.TOGGLE;
|
122 | a57faaf0 | Christos Stathis | } |
123 | a57faaf0 | Christos Stathis | } |
124 | a57faaf0 | Christos Stathis | return SelectAction.IGNORE;
|
125 | a57faaf0 | Christos Stathis | } |
126 | a57faaf0 | Christos Stathis | |
127 | a57faaf0 | Christos Stathis | // For keyboard events, do the default action.
|
128 | a57faaf0 | Christos Stathis | return SelectAction.DEFAULT;
|
129 | a57faaf0 | Christos Stathis | } |
130 | a57faaf0 | Christos Stathis | } |
131 | a57faaf0 | Christos Stathis | |
132 | a57faaf0 | Christos Stathis | /**
|
133 | a57faaf0 | Christos Stathis | * Translates {@link CellPreviewEvent}s into {@link SelectAction}s.
|
134 | a57faaf0 | Christos Stathis | */
|
135 | a57faaf0 | Christos Stathis | public static interface EventTranslator<T> { |
136 | a57faaf0 | Christos Stathis | /**
|
137 | a57faaf0 | Christos Stathis | * Check whether a user selection event should clear all currently selected
|
138 | a57faaf0 | Christos Stathis | * values.
|
139 | a57faaf0 | Christos Stathis | *
|
140 | a57faaf0 | Christos Stathis | * @param event the {@link CellPreviewEvent} to translate
|
141 | a57faaf0 | Christos Stathis | */
|
142 | a57faaf0 | Christos Stathis | boolean clearCurrentSelection(CellPreviewEvent<T> event);
|
143 | a57faaf0 | Christos Stathis | |
144 | a57faaf0 | Christos Stathis | /**
|
145 | a57faaf0 | Christos Stathis | * Translate the user selection event into a {@link SelectAction}.
|
146 | a57faaf0 | Christos Stathis | *
|
147 | a57faaf0 | Christos Stathis | * @param event the {@link CellPreviewEvent} to translate
|
148 | a57faaf0 | Christos Stathis | */
|
149 | a57faaf0 | Christos Stathis | SelectAction translateSelectionEvent(CellPreviewEvent<T> event); |
150 | a57faaf0 | Christos Stathis | } |
151 | a57faaf0 | Christos Stathis | |
152 | a57faaf0 | Christos Stathis | /**
|
153 | a57faaf0 | Christos Stathis | * The action that controls how selection is handled.
|
154 | a57faaf0 | Christos Stathis | */
|
155 | a57faaf0 | Christos Stathis | public static enum SelectAction { |
156 | a57faaf0 | Christos Stathis | DEFAULT, // Perform the default action.
|
157 | a57faaf0 | Christos Stathis | SELECT, // Select the value.
|
158 | a57faaf0 | Christos Stathis | DESELECT, // Deselect the value.
|
159 | a57faaf0 | Christos Stathis | TOGGLE, // Toggle the selected state of the value.
|
160 | a57faaf0 | Christos Stathis | IGNORE; // Ignore the event.
|
161 | a57faaf0 | Christos Stathis | } |
162 | a57faaf0 | Christos Stathis | |
163 | a57faaf0 | Christos Stathis | /**
|
164 | 969a4d94 | Christos Stathis | * Construct a new {@link PithosSelectionEventManager} that triggers
|
165 | a57faaf0 | Christos Stathis | * selection when any checkbox in any column is clicked.
|
166 | a57faaf0 | Christos Stathis | *
|
167 | a57faaf0 | Christos Stathis | * @param <T> the data type of the display
|
168 | 969a4d94 | Christos Stathis | * @return a {@link PithosSelectionEventManager} instance
|
169 | a57faaf0 | Christos Stathis | */
|
170 | 969a4d94 | Christos Stathis | public static <T> PithosSelectionEventManager<T> createCheckboxManager() { |
171 | 969a4d94 | Christos Stathis | return new PithosSelectionEventManager<T>(new CheckboxEventTranslator<T>()); |
172 | a57faaf0 | Christos Stathis | } |
173 | a57faaf0 | Christos Stathis | |
174 | a57faaf0 | Christos Stathis | /**
|
175 | 969a4d94 | Christos Stathis | * Construct a new {@link PithosSelectionEventManager} that triggers
|
176 | a57faaf0 | Christos Stathis | * selection when a checkbox in the specified column is clicked.
|
177 | a57faaf0 | Christos Stathis | *
|
178 | a57faaf0 | Christos Stathis | * @param <T> the data type of the display
|
179 | a57faaf0 | Christos Stathis | * @param column the column to handle
|
180 | 969a4d94 | Christos Stathis | * @return a {@link PithosSelectionEventManager} instance
|
181 | a57faaf0 | Christos Stathis | */
|
182 | 969a4d94 | Christos Stathis | public static <T> PithosSelectionEventManager<T> createCheckboxManager( |
183 | a57faaf0 | Christos Stathis | int column) {
|
184 | 969a4d94 | Christos Stathis | return new PithosSelectionEventManager<T>(new CheckboxEventTranslator<T>( |
185 | a57faaf0 | Christos Stathis | column)); |
186 | a57faaf0 | Christos Stathis | } |
187 | a57faaf0 | Christos Stathis | |
188 | a57faaf0 | Christos Stathis | /**
|
189 | 969a4d94 | Christos Stathis | * Create a new {@link PithosSelectionEventManager} using the specified
|
190 | a57faaf0 | Christos Stathis | * {@link EventTranslator} to control which {@link SelectAction} to take for
|
191 | a57faaf0 | Christos Stathis | * each event.
|
192 | a57faaf0 | Christos Stathis | *
|
193 | a57faaf0 | Christos Stathis | * @param <T> the data type of the display
|
194 | a57faaf0 | Christos Stathis | * @param translator the {@link EventTranslator} to use
|
195 | 969a4d94 | Christos Stathis | * @return a {@link PithosSelectionEventManager} instance
|
196 | a57faaf0 | Christos Stathis | */
|
197 | 969a4d94 | Christos Stathis | public static <T> PithosSelectionEventManager<T> createCustomManager( |
198 | a57faaf0 | Christos Stathis | EventTranslator<T> translator) { |
199 | 969a4d94 | Christos Stathis | return new PithosSelectionEventManager<T>(translator); |
200 | a57faaf0 | Christos Stathis | } |
201 | a57faaf0 | Christos Stathis | |
202 | a57faaf0 | Christos Stathis | /**
|
203 | 969a4d94 | Christos Stathis | * Create a new {@link PithosSelectionEventManager} that handles selection
|
204 | a57faaf0 | Christos Stathis | * via user interactions.
|
205 | a57faaf0 | Christos Stathis | *
|
206 | a57faaf0 | Christos Stathis | * @param <T> the data type of the display
|
207 | 969a4d94 | Christos Stathis | * @return a new {@link PithosSelectionEventManager} instance
|
208 | a57faaf0 | Christos Stathis | */
|
209 | 969a4d94 | Christos Stathis | public static <T> PithosSelectionEventManager<T> createDefaultManager() { |
210 | 969a4d94 | Christos Stathis | return new PithosSelectionEventManager<T>(null); |
211 | a57faaf0 | Christos Stathis | } |
212 | a57faaf0 | Christos Stathis | |
213 | a57faaf0 | Christos Stathis | /**
|
214 | a57faaf0 | Christos Stathis | * The last {@link HasData} that was handled.
|
215 | a57faaf0 | Christos Stathis | */
|
216 | a57faaf0 | Christos Stathis | private HasData<T> lastDisplay;
|
217 | a57faaf0 | Christos Stathis | |
218 | a57faaf0 | Christos Stathis | /**
|
219 | a57faaf0 | Christos Stathis | * The last page start.
|
220 | a57faaf0 | Christos Stathis | */
|
221 | a57faaf0 | Christos Stathis | private int lastPageStart; |
222 | a57faaf0 | Christos Stathis | |
223 | a57faaf0 | Christos Stathis | /**
|
224 | a57faaf0 | Christos Stathis | * The last selected row index.
|
225 | a57faaf0 | Christos Stathis | */
|
226 | a57faaf0 | Christos Stathis | private int lastSelectedIndex = -1; |
227 | a57faaf0 | Christos Stathis | |
228 | a57faaf0 | Christos Stathis | /**
|
229 | a57faaf0 | Christos Stathis | * A boolean indicating that the last shift selection was additive.
|
230 | a57faaf0 | Christos Stathis | */
|
231 | a57faaf0 | Christos Stathis | private boolean shiftAdditive; |
232 | a57faaf0 | Christos Stathis | |
233 | a57faaf0 | Christos Stathis | /**
|
234 | a57faaf0 | Christos Stathis | * The last place where the user clicked without holding shift. Multi
|
235 | a57faaf0 | Christos Stathis | * selections that use the shift key are rooted at the anchor.
|
236 | a57faaf0 | Christos Stathis | */
|
237 | a57faaf0 | Christos Stathis | private int shiftAnchor = -1; |
238 | a57faaf0 | Christos Stathis | |
239 | a57faaf0 | Christos Stathis | /**
|
240 | a57faaf0 | Christos Stathis | * The {@link EventTranslator} that controls how selection is handled.
|
241 | a57faaf0 | Christos Stathis | */
|
242 | a57faaf0 | Christos Stathis | private final EventTranslator<T> translator; |
243 | a57faaf0 | Christos Stathis | |
244 | a57faaf0 | Christos Stathis | /**
|
245 | 969a4d94 | Christos Stathis | * Construct a new {@link PithosSelectionEventManager} using the specified
|
246 | a57faaf0 | Christos Stathis | * {@link EventTranslator} to control which {@link SelectAction} to take for
|
247 | a57faaf0 | Christos Stathis | * each event.
|
248 | a57faaf0 | Christos Stathis | *
|
249 | a57faaf0 | Christos Stathis | * @param translator the {@link EventTranslator} to use
|
250 | a57faaf0 | Christos Stathis | */
|
251 | 969a4d94 | Christos Stathis | protected PithosSelectionEventManager(EventTranslator<T> translator) {
|
252 | a57faaf0 | Christos Stathis | this.translator = translator;
|
253 | a57faaf0 | Christos Stathis | } |
254 | a57faaf0 | Christos Stathis | |
255 | a57faaf0 | Christos Stathis | /**
|
256 | a57faaf0 | Christos Stathis | * Update the selection model based on a user selection event.
|
257 | a57faaf0 | Christos Stathis | *
|
258 | a57faaf0 | Christos Stathis | * @param selectionModel the selection model to update
|
259 | a57faaf0 | Christos Stathis | * @param row the selected row index relative to the page start
|
260 | a57faaf0 | Christos Stathis | * @param rowValue the selected row value
|
261 | a57faaf0 | Christos Stathis | * @param action the {@link SelectAction} to apply
|
262 | a57faaf0 | Christos Stathis | * @param selectRange true to select the range from the last selected row
|
263 | a57faaf0 | Christos Stathis | * @param clearOthers true to clear the current selection
|
264 | a57faaf0 | Christos Stathis | */
|
265 | a57faaf0 | Christos Stathis | public void doMultiSelection(MultiSelectionModel<? super T> selectionModel, |
266 | a57faaf0 | Christos Stathis | HasData<T> display, int row, T rowValue, SelectAction action,
|
267 | a57faaf0 | Christos Stathis | boolean selectRange, boolean clearOthers) { |
268 | a57faaf0 | Christos Stathis | // Determine if we will add or remove selection.
|
269 | a57faaf0 | Christos Stathis | boolean addToSelection = true; |
270 | a57faaf0 | Christos Stathis | if (action != null) { |
271 | a57faaf0 | Christos Stathis | switch (action) {
|
272 | a57faaf0 | Christos Stathis | case IGNORE:
|
273 | a57faaf0 | Christos Stathis | // Ignore selection.
|
274 | a57faaf0 | Christos Stathis | return;
|
275 | a57faaf0 | Christos Stathis | case SELECT:
|
276 | a57faaf0 | Christos Stathis | addToSelection = true;
|
277 | a57faaf0 | Christos Stathis | break;
|
278 | a57faaf0 | Christos Stathis | case DESELECT:
|
279 | a57faaf0 | Christos Stathis | addToSelection = false;
|
280 | a57faaf0 | Christos Stathis | break;
|
281 | a57faaf0 | Christos Stathis | case TOGGLE:
|
282 | a57faaf0 | Christos Stathis | addToSelection = !selectionModel.isSelected(rowValue); |
283 | a57faaf0 | Christos Stathis | break;
|
284 | 7811b9d1 | Christos Stathis | case DEFAULT:
|
285 | 7811b9d1 | Christos Stathis | break;
|
286 | a57faaf0 | Christos Stathis | } |
287 | a57faaf0 | Christos Stathis | } |
288 | a57faaf0 | Christos Stathis | |
289 | a57faaf0 | Christos Stathis | // Determine which rows will be newly selected.
|
290 | a57faaf0 | Christos Stathis | int pageStart = display.getVisibleRange().getStart();
|
291 | a57faaf0 | Christos Stathis | if (selectRange && pageStart == lastPageStart && lastSelectedIndex > -1 |
292 | a57faaf0 | Christos Stathis | && shiftAnchor > -1 && display == lastDisplay) {
|
293 | a57faaf0 | Christos Stathis | /*
|
294 | a57faaf0 | Christos Stathis | * Get the new shift bounds based on the existing shift anchor and the
|
295 | a57faaf0 | Christos Stathis | * selected row.
|
296 | a57faaf0 | Christos Stathis | */
|
297 | a57faaf0 | Christos Stathis | int start = Math.min(shiftAnchor, row); // Inclusive. |
298 | a57faaf0 | Christos Stathis | int end = Math.max(shiftAnchor, row); // Inclusive. |
299 | a57faaf0 | Christos Stathis | |
300 | a57faaf0 | Christos Stathis | if (lastSelectedIndex < start) {
|
301 | a57faaf0 | Christos Stathis | // Revert previous selection if the user reselects a smaller range.
|
302 | a57faaf0 | Christos Stathis | setRangeSelection(selectionModel, display, new Range(lastSelectedIndex,
|
303 | a57faaf0 | Christos Stathis | start - lastSelectedIndex), !shiftAdditive, false);
|
304 | a57faaf0 | Christos Stathis | } else if (lastSelectedIndex > end) { |
305 | a57faaf0 | Christos Stathis | // Revert previous selection if the user reselects a smaller range.
|
306 | a57faaf0 | Christos Stathis | setRangeSelection(selectionModel, display, new Range(end + 1, |
307 | a57faaf0 | Christos Stathis | lastSelectedIndex - end), !shiftAdditive, false);
|
308 | a57faaf0 | Christos Stathis | } else {
|
309 | a57faaf0 | Christos Stathis | // Remember if we are adding or removing rows.
|
310 | a57faaf0 | Christos Stathis | shiftAdditive = addToSelection; |
311 | a57faaf0 | Christos Stathis | } |
312 | a57faaf0 | Christos Stathis | |
313 | a57faaf0 | Christos Stathis | // Update the last selected row, but do not move the shift anchor.
|
314 | a57faaf0 | Christos Stathis | lastSelectedIndex = row; |
315 | a57faaf0 | Christos Stathis | |
316 | a57faaf0 | Christos Stathis | // Select the range.
|
317 | a57faaf0 | Christos Stathis | setRangeSelection(selectionModel, display, new Range(start, end - start
|
318 | a57faaf0 | Christos Stathis | + 1), shiftAdditive, clearOthers);
|
319 | a57faaf0 | Christos Stathis | } else {
|
320 | a57faaf0 | Christos Stathis | /*
|
321 | a57faaf0 | Christos Stathis | * If we are not selecting a range, save the last row and set the shift
|
322 | a57faaf0 | Christos Stathis | * anchor.
|
323 | a57faaf0 | Christos Stathis | */
|
324 | a57faaf0 | Christos Stathis | lastDisplay = display; |
325 | a57faaf0 | Christos Stathis | lastPageStart = pageStart; |
326 | a57faaf0 | Christos Stathis | lastSelectedIndex = row; |
327 | a57faaf0 | Christos Stathis | shiftAnchor = row; |
328 | a57faaf0 | Christos Stathis | selectOne(selectionModel, rowValue, addToSelection, clearOthers); |
329 | a57faaf0 | Christos Stathis | } |
330 | a57faaf0 | Christos Stathis | } |
331 | a57faaf0 | Christos Stathis | |
332 | 7811b9d1 | Christos Stathis | @Override
|
333 | 7811b9d1 | Christos Stathis | public void onCellPreview(CellPreviewEvent<T> event) { |
334 | a57faaf0 | Christos Stathis | // Early exit if selection is already handled or we are editing.
|
335 | a57faaf0 | Christos Stathis | if (event.isCellEditing() || event.isSelectionHandled()) {
|
336 | a57faaf0 | Christos Stathis | return;
|
337 | a57faaf0 | Christos Stathis | } |
338 | a57faaf0 | Christos Stathis | |
339 | a57faaf0 | Christos Stathis | // Early exit if we do not have a SelectionModel.
|
340 | a57faaf0 | Christos Stathis | HasData<T> display = event.getDisplay(); |
341 | a57faaf0 | Christos Stathis | SelectionModel<? super T> selectionModel = display.getSelectionModel();
|
342 | a57faaf0 | Christos Stathis | if (selectionModel == null) { |
343 | a57faaf0 | Christos Stathis | return;
|
344 | a57faaf0 | Christos Stathis | } |
345 | a57faaf0 | Christos Stathis | |
346 | a57faaf0 | Christos Stathis | // Check for user defined actions.
|
347 | a57faaf0 | Christos Stathis | SelectAction action = (translator == null) ? SelectAction.DEFAULT
|
348 | a57faaf0 | Christos Stathis | : translator.translateSelectionEvent(event); |
349 | a57faaf0 | Christos Stathis | |
350 | a57faaf0 | Christos Stathis | // Handle the event based on the SelectionModel type.
|
351 | a57faaf0 | Christos Stathis | if (selectionModel instanceof MultiSelectionModel) { |
352 | a57faaf0 | Christos Stathis | // Add shift key support for MultiSelectionModel.
|
353 | a57faaf0 | Christos Stathis | handleMultiSelectionEvent(event, action, |
354 | a57faaf0 | Christos Stathis | (MultiSelectionModel<? super T>) selectionModel);
|
355 | a57faaf0 | Christos Stathis | } else {
|
356 | a57faaf0 | Christos Stathis | // Use the standard handler.
|
357 | a57faaf0 | Christos Stathis | handleSelectionEvent(event, action, selectionModel); |
358 | a57faaf0 | Christos Stathis | } |
359 | a57faaf0 | Christos Stathis | } |
360 | a57faaf0 | Christos Stathis | |
361 | a57faaf0 | Christos Stathis | /**
|
362 | a57faaf0 | Christos Stathis | * Removes all items from the selection.
|
363 | a57faaf0 | Christos Stathis | *
|
364 | a57faaf0 | Christos Stathis | * @param selectionModel the {@link MultiSelectionModel} to clear
|
365 | a57faaf0 | Christos Stathis | */
|
366 | a57faaf0 | Christos Stathis | protected void clearSelection(MultiSelectionModel<? super T> selectionModel) { |
367 | a57faaf0 | Christos Stathis | selectionModel.clear(); |
368 | a57faaf0 | Christos Stathis | } |
369 | a57faaf0 | Christos Stathis | |
370 | a57faaf0 | Christos Stathis | /**
|
371 | a57faaf0 | Christos Stathis | * Handle an event that could cause a value to be selected for a
|
372 | a57faaf0 | Christos Stathis | * {@link MultiSelectionModel}. This overloaded method adds support for both
|
373 | a57faaf0 | Christos Stathis | * the control and shift keys. If the shift key is held down, all rows between
|
374 | a57faaf0 | Christos Stathis | * the previous selected row and the current row are selected.
|
375 | a57faaf0 | Christos Stathis | *
|
376 | a57faaf0 | Christos Stathis | * @param event the {@link CellPreviewEvent} that triggered selection
|
377 | a57faaf0 | Christos Stathis | * @param action the action to handle
|
378 | a57faaf0 | Christos Stathis | * @param selectionModel the {@link SelectionModel} to update
|
379 | a57faaf0 | Christos Stathis | */
|
380 | a57faaf0 | Christos Stathis | protected void handleMultiSelectionEvent(CellPreviewEvent<T> event, |
381 | a57faaf0 | Christos Stathis | SelectAction action, MultiSelectionModel<? super T> selectionModel) {
|
382 | a57faaf0 | Christos Stathis | NativeEvent nativeEvent = event.getNativeEvent(); |
383 | a57faaf0 | Christos Stathis | String type = nativeEvent.getType();
|
384 | a57faaf0 | Christos Stathis | boolean rightclick = "mousedown".equals(type) && nativeEvent.getButton()==NativeEvent.BUTTON_RIGHT; |
385 | 7811b9d1 | Christos Stathis | SelectAction action1 = action; |
386 | a57faaf0 | Christos Stathis | if(rightclick){
|
387 | a57faaf0 | Christos Stathis | boolean shift = nativeEvent.getShiftKey();
|
388 | a57faaf0 | Christos Stathis | boolean ctrlOrMeta = nativeEvent.getCtrlKey() || nativeEvent.getMetaKey();
|
389 | a57faaf0 | Christos Stathis | boolean clearOthers = (translator == null) ? !ctrlOrMeta |
390 | a57faaf0 | Christos Stathis | : translator.clearCurrentSelection(event); |
391 | a57faaf0 | Christos Stathis | if (action == null || action == SelectAction.DEFAULT) { |
392 | 7811b9d1 | Christos Stathis | action1 = ctrlOrMeta ? SelectAction.TOGGLE : SelectAction.SELECT; |
393 | a57faaf0 | Christos Stathis | } |
394 | a57faaf0 | Christos Stathis | //if the row is selected then do nothing
|
395 | a57faaf0 | Christos Stathis | if(selectionModel.isSelected(event.getValue())){
|
396 | a57faaf0 | Christos Stathis | return;
|
397 | a57faaf0 | Christos Stathis | } |
398 | a57faaf0 | Christos Stathis | doMultiSelection(selectionModel, event.getDisplay(), event.getIndex(), |
399 | 7811b9d1 | Christos Stathis | event.getValue(), action1, shift, clearOthers); |
400 | a57faaf0 | Christos Stathis | } |
401 | a57faaf0 | Christos Stathis | else if ("click".equals(type)) { |
402 | a57faaf0 | Christos Stathis | /*
|
403 | a57faaf0 | Christos Stathis | * Update selection on click. Selection is toggled only if the user
|
404 | a57faaf0 | Christos Stathis | * presses the ctrl key. If the user does not press the control key,
|
405 | a57faaf0 | Christos Stathis | * selection is additive.
|
406 | a57faaf0 | Christos Stathis | */
|
407 | a57faaf0 | Christos Stathis | boolean shift = nativeEvent.getShiftKey();
|
408 | a57faaf0 | Christos Stathis | boolean ctrlOrMeta = nativeEvent.getCtrlKey() || nativeEvent.getMetaKey();
|
409 | a57faaf0 | Christos Stathis | boolean clearOthers = (translator == null) ? !ctrlOrMeta |
410 | a57faaf0 | Christos Stathis | : translator.clearCurrentSelection(event); |
411 | a57faaf0 | Christos Stathis | if (action == null || action == SelectAction.DEFAULT) { |
412 | 7811b9d1 | Christos Stathis | action1 = ctrlOrMeta ? SelectAction.TOGGLE : SelectAction.SELECT; |
413 | a57faaf0 | Christos Stathis | } |
414 | a57faaf0 | Christos Stathis | doMultiSelection(selectionModel, event.getDisplay(), event.getIndex(), |
415 | 7811b9d1 | Christos Stathis | event.getValue(), action1, shift, clearOthers); |
416 | a57faaf0 | Christos Stathis | if(ctrlOrMeta){
|
417 | a57faaf0 | Christos Stathis | event.setCanceled(true);
|
418 | a57faaf0 | Christos Stathis | } |
419 | a57faaf0 | Christos Stathis | } else if ("keyup".equals(type)) { |
420 | a57faaf0 | Christos Stathis | int keyCode = nativeEvent.getKeyCode();
|
421 | a57faaf0 | Christos Stathis | if (keyCode == 32) { |
422 | a57faaf0 | Christos Stathis | /*
|
423 | a57faaf0 | Christos Stathis | * Update selection when the space bar is pressed. The spacebar always
|
424 | a57faaf0 | Christos Stathis | * toggles selection, regardless of whether the control key is pressed.
|
425 | a57faaf0 | Christos Stathis | */
|
426 | a57faaf0 | Christos Stathis | boolean shift = nativeEvent.getShiftKey();
|
427 | a57faaf0 | Christos Stathis | boolean clearOthers = (translator == null) ? false |
428 | a57faaf0 | Christos Stathis | : translator.clearCurrentSelection(event); |
429 | a57faaf0 | Christos Stathis | if (action == null || action == SelectAction.DEFAULT) { |
430 | 7811b9d1 | Christos Stathis | action1 = SelectAction.TOGGLE; |
431 | a57faaf0 | Christos Stathis | } |
432 | a57faaf0 | Christos Stathis | doMultiSelection(selectionModel, event.getDisplay(), event.getIndex(), |
433 | 7811b9d1 | Christos Stathis | event.getValue(), action1, shift, clearOthers); |
434 | a57faaf0 | Christos Stathis | } |
435 | a57faaf0 | Christos Stathis | } |
436 | a57faaf0 | Christos Stathis | } |
437 | a57faaf0 | Christos Stathis | |
438 | a57faaf0 | Christos Stathis | /**
|
439 | a57faaf0 | Christos Stathis | * Handle an event that could cause a value to be selected. This method works
|
440 | a57faaf0 | Christos Stathis | * for any {@link SelectionModel}. Pressing the space bar or ctrl+click will
|
441 | a57faaf0 | Christos Stathis | * toggle the selection state. Clicking selects the row if it is not selected.
|
442 | a57faaf0 | Christos Stathis | *
|
443 | a57faaf0 | Christos Stathis | * @param event the {@link CellPreviewEvent} that triggered selection
|
444 | a57faaf0 | Christos Stathis | * @param action the action to handle
|
445 | a57faaf0 | Christos Stathis | * @param selectionModel the {@link SelectionModel} to update
|
446 | a57faaf0 | Christos Stathis | */
|
447 | a57faaf0 | Christos Stathis | protected void handleSelectionEvent(CellPreviewEvent<T> event, |
448 | a57faaf0 | Christos Stathis | SelectAction action, SelectionModel<? super T> selectionModel) {
|
449 | a57faaf0 | Christos Stathis | // Handle selection overrides.
|
450 | a57faaf0 | Christos Stathis | T value = event.getValue(); |
451 | a57faaf0 | Christos Stathis | if (action != null) { |
452 | a57faaf0 | Christos Stathis | switch (action) {
|
453 | a57faaf0 | Christos Stathis | case IGNORE:
|
454 | a57faaf0 | Christos Stathis | return;
|
455 | a57faaf0 | Christos Stathis | case SELECT:
|
456 | a57faaf0 | Christos Stathis | selectionModel.setSelected(value, true);
|
457 | a57faaf0 | Christos Stathis | return;
|
458 | a57faaf0 | Christos Stathis | case DESELECT:
|
459 | a57faaf0 | Christos Stathis | selectionModel.setSelected(value, false);
|
460 | a57faaf0 | Christos Stathis | return;
|
461 | a57faaf0 | Christos Stathis | case TOGGLE:
|
462 | a57faaf0 | Christos Stathis | selectionModel.setSelected(value, !selectionModel.isSelected(value)); |
463 | a57faaf0 | Christos Stathis | return;
|
464 | 7811b9d1 | Christos Stathis | case DEFAULT:
|
465 | 7811b9d1 | Christos Stathis | break;
|
466 | a57faaf0 | Christos Stathis | } |
467 | a57faaf0 | Christos Stathis | } |
468 | a57faaf0 | Christos Stathis | |
469 | a57faaf0 | Christos Stathis | // Handle default selection.
|
470 | a57faaf0 | Christos Stathis | NativeEvent nativeEvent = event.getNativeEvent(); |
471 | a57faaf0 | Christos Stathis | String type = nativeEvent.getType();
|
472 | a57faaf0 | Christos Stathis | if ("click".equals(type)) { |
473 | a57faaf0 | Christos Stathis | if (nativeEvent.getCtrlKey() || nativeEvent.getMetaKey()) {
|
474 | a57faaf0 | Christos Stathis | // Toggle selection on ctrl+click.
|
475 | a57faaf0 | Christos Stathis | selectionModel.setSelected(value, !selectionModel.isSelected(value)); |
476 | a57faaf0 | Christos Stathis | } else {
|
477 | a57faaf0 | Christos Stathis | // Select on click.
|
478 | a57faaf0 | Christos Stathis | selectionModel.setSelected(value, true);
|
479 | a57faaf0 | Christos Stathis | } |
480 | a57faaf0 | Christos Stathis | } else if ("keyup".equals(type)) { |
481 | a57faaf0 | Christos Stathis | // Toggle selection on space.
|
482 | a57faaf0 | Christos Stathis | int keyCode = nativeEvent.getKeyCode();
|
483 | a57faaf0 | Christos Stathis | if (keyCode == 32) { |
484 | a57faaf0 | Christos Stathis | selectionModel.setSelected(value, !selectionModel.isSelected(value)); |
485 | a57faaf0 | Christos Stathis | } |
486 | a57faaf0 | Christos Stathis | } |
487 | a57faaf0 | Christos Stathis | } |
488 | a57faaf0 | Christos Stathis | |
489 | a57faaf0 | Christos Stathis | /**
|
490 | a57faaf0 | Christos Stathis | * Selects the given item, optionally clearing any prior selection.
|
491 | a57faaf0 | Christos Stathis | *
|
492 | a57faaf0 | Christos Stathis | * @param selectionModel the {@link MultiSelectionModel} to update
|
493 | a57faaf0 | Christos Stathis | * @param target the item to select
|
494 | a57faaf0 | Christos Stathis | * @param selected true to select, false to deselect
|
495 | a57faaf0 | Christos Stathis | * @param clearOthers true to clear all other selected items
|
496 | a57faaf0 | Christos Stathis | */
|
497 | a57faaf0 | Christos Stathis | protected void selectOne(MultiSelectionModel<? super T> selectionModel, |
498 | a57faaf0 | Christos Stathis | T target, boolean selected, boolean clearOthers) { |
499 | a57faaf0 | Christos Stathis | if (clearOthers) {
|
500 | a57faaf0 | Christos Stathis | clearSelection(selectionModel); |
501 | a57faaf0 | Christos Stathis | } |
502 | a57faaf0 | Christos Stathis | selectionModel.setSelected(target, selected); |
503 | a57faaf0 | Christos Stathis | } |
504 | a57faaf0 | Christos Stathis | |
505 | a57faaf0 | Christos Stathis | /**
|
506 | a57faaf0 | Christos Stathis | * Select or deselect a range of row indexes, optionally deselecting all other
|
507 | a57faaf0 | Christos Stathis | * values.
|
508 | a57faaf0 | Christos Stathis | *
|
509 | a57faaf0 | Christos Stathis | * @param selectionModel the {@link MultiSelectionModel} to update
|
510 | a57faaf0 | Christos Stathis | * @param display the {@link HasData} source of the selection event
|
511 | a57faaf0 | Christos Stathis | * @param range the {@link Range} of rows to select or deselect
|
512 | a57faaf0 | Christos Stathis | * @param addToSelection true to select, false to deselect the range
|
513 | a57faaf0 | Christos Stathis | * @param clearOthers true to deselect rows not in the range
|
514 | a57faaf0 | Christos Stathis | */
|
515 | a57faaf0 | Christos Stathis | protected void setRangeSelection( |
516 | a57faaf0 | Christos Stathis | MultiSelectionModel<? super T> selectionModel, HasData<T> display,
|
517 | a57faaf0 | Christos Stathis | Range range, boolean addToSelection, boolean clearOthers) { |
518 | a57faaf0 | Christos Stathis | // Get the list of values to select.
|
519 | a57faaf0 | Christos Stathis | List<T> toUpdate = new ArrayList<T>(); |
520 | a57faaf0 | Christos Stathis | int start = range.getStart();
|
521 | a57faaf0 | Christos Stathis | int end = start + range.getLength();
|
522 | a57faaf0 | Christos Stathis | for (int i = start; i < end ; i++) { |
523 | a57faaf0 | Christos Stathis | toUpdate.add(display.getVisibleItem(i-display.getVisibleRange().getStart())); |
524 | a57faaf0 | Christos Stathis | } |
525 | a57faaf0 | Christos Stathis | // Clear all other values.
|
526 | a57faaf0 | Christos Stathis | if (clearOthers) {
|
527 | a57faaf0 | Christos Stathis | clearSelection(selectionModel); |
528 | a57faaf0 | Christos Stathis | } |
529 | a57faaf0 | Christos Stathis | |
530 | a57faaf0 | Christos Stathis | // Update the state of the values.
|
531 | a57faaf0 | Christos Stathis | for (T value : toUpdate) {
|
532 | a57faaf0 | Christos Stathis | selectionModel.setSelected(value, addToSelection); |
533 | a57faaf0 | Christos Stathis | } |
534 | a57faaf0 | Christos Stathis | } |
535 | a57faaf0 | Christos Stathis | } |