Revision 969a4d94

b/build.xml
77 77
	</target>
78 78

  
79 79
    <target name="uploadToVM" depends="gwt-compile">
80
        <scp todir="chstath@pithos.dev.grnet.gr:/var/www/pithos_web_client" keyfile="/home/chstath/.ssh/id_rsa" passphrase="r0bax45">
80
        <scp todir="chstath@pithos.dev.grnet.gr:/var/www/pithos_web_client" keyfile="/home/chstath/.ssh/chstath@ross.key" passphrase="r0bax45">
81 81
            <fileset dir="${gwt.www.dir}/${gwt.module}"/>
82 82
        </scp>
83 83
    </target>
......
106 106
            <arg value="${gwt.www.dir}"/>
107 107
            <arg value="-noserver"/>
108 108
            <arg value="-startupUrl"/>
109
            <arg value="http://127.0.0.1:8080/client/pithos.html"/>
109
            <arg value="http://127.0.0.1:8080/client"/>
110 110
            <arg value="${gwt.module}"/>
111 111
        </java>
112 112
    </target>
b/src/gr/grnet/pithos/web/Pithos.gwt.xml
40 40
	<inherits name="com.google.gwt.json.JSON"/>
41 41

  
42 42
    <entry-point class='gr.grnet.pithos.web.client.Pithos' />
43
	<stylesheet src='gss.css' />
43
	<stylesheet src='pithos.css' />
44 44

  
45 45
	<source path="client"/>
46 46
</module>
b/src/gr/grnet/pithos/web/client/FileList.java
83 83

  
84 84
	interface TableResources extends CellTable.Resources {
85 85
	    @Override
86
		@Source({CellTable.Style.DEFAULT_CSS, "GssCellTable.css"})
86
		@Source({CellTable.Style.DEFAULT_CSS, "PithosCellTable.css"})
87 87
	    TableStyle cellTableStyle();
88 88
	}
89 89
	
......
331 331

  
332 332
		selectionModel = new MultiSelectionModel<File>(keyProvider);
333 333

  
334
		celltable.setSelectionModel(selectionModel, GSSSelectionEventManager.<File> createDefaultManager());
334
		celltable.setSelectionModel(selectionModel, PithosSelectionEventManager.<File> createDefaultManager());
335 335
//		celltable.setPageSize(Pithos.VISIBLE_FILE_COUNT);
336 336
		
337 337
		sinkEvents(Event.ONCONTEXTMENU);
b/src/gr/grnet/pithos/web/client/FilePropertiesDialog.java
289 289
                    permList.updatePermissionTable();
290 290
                }
291 291
            });
292
            add.addStyleName("button");
292 293
            permButtons.add(add);
293 294
            permButtons.setCellHorizontalAlignment(add, HasHorizontalAlignment.ALIGN_CENTER);
294 295

  
......
300 301
                    permList.updatePermissionTable();
301 302
                }
302 303
            });
304
            addUser.addStyleName("button");
303 305
            permButtons.add(addUser);
304 306
            permButtons.setCellHorizontalAlignment(addUser, HasHorizontalAlignment.ALIGN_CENTER);
305 307

  
b/src/gr/grnet/pithos/web/client/FolderPropertiesDialog.java
175 175
                    dlg.center();
176 176
                }
177 177
            });
178
            add.addStyleName("button");
178 179
            permButtons.add(add);
179 180
            permButtons.setCellHorizontalAlignment(add, HasHorizontalAlignment.ALIGN_CENTER);
180 181

  
......
185 186
                    dlg.center();
186 187
                }
187 188
            });
188
            addUser.getElement().setId("folderPropertiesDialog.button.addUser");
189
            addUser.addStyleName("button");
189 190
            permButtons.add(addUser);
190 191
            permButtons.setCellHorizontalAlignment(addUser, HasHorizontalAlignment.ALIGN_CENTER);
191 192
            permButtons.setSpacing(8);
192
            permButtons.addStyleName("gss-TabPanelBottom");
193 193
            permPanel.add(permButtons);
194 194
        }
195 195

  
/dev/null
1
/*
2
 * Copyright 2011 GRNET S.A. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or
5
 * without modification, are permitted provided that the following
6
 * conditions are met:
7
 *
8
 *   1. Redistributions of source code must retain the above
9
 *      copyright notice, this list of conditions and the following
10
 *      disclaimer.
11
 *
12
 *   2. Redistributions in binary form must reproduce the above
13
 *      copyright notice, this list of conditions and the following
14
 *      disclaimer in the documentation and/or other materials
15
 *      provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
 * POSSIBILITY OF SUCH DAMAGE.
29
 *
30
 * The views and conclusions contained in the software and
31
 * documentation are those of the authors and should not be
32
 * interpreted as representing official policies, either expressed
33
 * or implied, of GRNET S.A.
34
 */
35
package gr.grnet.pithos.web.client;
36

  
37

  
38

  
39
import java.util.ArrayList;
40
import java.util.List;
41

  
42
import com.google.gwt.dom.client.Element;
43
import com.google.gwt.dom.client.InputElement;
44
import com.google.gwt.dom.client.NativeEvent;
45
import com.google.gwt.view.client.CellPreviewEvent;
46
import com.google.gwt.view.client.HasData;
47
import com.google.gwt.view.client.MultiSelectionModel;
48
import com.google.gwt.view.client.Range;
49
import com.google.gwt.view.client.SelectionModel;
50

  
51
/**
52
 * An implementation of {@link com.google.gwt.view.client.CellPreviewEvent.Handler} that adds selection
53
 * support via the spacebar and mouse clicks and handles the control key.
54
 * 
55
 * <p>
56
 * If the {@link HasData} source of the selection event uses a
57
 * {@link MultiSelectionModel}, this manager additionally provides support for
58
 * shift key to select a range of values. For all other {@link SelectionModel}s,
59
 * only the control key is supported.
60
 * </p>
61
 * 
62
 * @param <T> the data type of records in the list
63
 */
64
public class GSSSelectionEventManager<T> implements
65
    CellPreviewEvent.Handler<T> {
66

  
67
  /**
68
   * Implementation of {@link gr.grnet.pithos.web.client.GSSSelectionEventManager.EventTranslator} that only triggers selection when
69
   * any checkbox is selected.
70
   * 
71
   * @param <T> the data type
72
   */
73
  public static class CheckboxEventTranslator<T> implements EventTranslator<T> {
74

  
75
    /**
76
     * The column index of the checkbox. Other columns are ignored.
77
     */
78
    private final int column;
79

  
80
    /**
81
     * Construct a new {@link gr.grnet.pithos.web.client.GSSSelectionEventManager.CheckboxEventTranslator} that will trigger
82
     * selection when any checkbox in any column is selected.
83
     */
84
    public CheckboxEventTranslator() {
85
      this(-1);
86
    }
87

  
88
    /**
89
     * Construct a new {@link gr.grnet.pithos.web.client.GSSSelectionEventManager.CheckboxEventTranslator} that will trigger
90
     * selection when a checkbox in the specified column is selected.
91
     * 
92
     * @param column the column index, or -1 for all columns
93
     */
94
    public CheckboxEventTranslator(int column) {
95
      this.column = column;
96
    }
97

  
98
    @Override
99
	public boolean clearCurrentSelection(@SuppressWarnings("unused") CellPreviewEvent<T> event) {
100
      return false;
101
    }
102

  
103
    @Override
104
	public SelectAction translateSelectionEvent(CellPreviewEvent<T> event) {
105
      // Handle the event.
106
      NativeEvent nativeEvent = event.getNativeEvent();
107
      if ("click".equals(nativeEvent.getType())) {
108
        // Ignore if the event didn't occur in the correct column.
109
        if (column > -1 && column != event.getColumn()) {
110
          return SelectAction.IGNORE;
111
        }
112

  
113
        // Determine if we clicked on a checkbox.
114
        Element target = nativeEvent.getEventTarget().cast();
115
        if ("input".equals(target.getTagName().toLowerCase())) {
116
          final InputElement input = target.cast();
117
          if ("checkbox".equals(input.getType().toLowerCase())) {
118
            // Synchronize the checkbox with the current selection state.
119
            input.setChecked(event.getDisplay().getSelectionModel().isSelected(
120
                event.getValue()));
121
            return SelectAction.TOGGLE;
122
          }
123
        }
124
        return SelectAction.IGNORE;
125
      }
126

  
127
      // For keyboard events, do the default action.
128
      return SelectAction.DEFAULT;
129
    }
130
  }
131

  
132
  /**
133
   * Translates {@link CellPreviewEvent}s into {@link SelectAction}s.
134
   */
135
  public static interface EventTranslator<T> {
136
    /**
137
     * Check whether a user selection event should clear all currently selected
138
     * values.
139
     * 
140
     * @param event the {@link CellPreviewEvent} to translate
141
     */
142
    boolean clearCurrentSelection(CellPreviewEvent<T> event);
143

  
144
    /**
145
     * Translate the user selection event into a {@link SelectAction}.
146
     * 
147
     * @param event the {@link CellPreviewEvent} to translate
148
     */
149
    SelectAction translateSelectionEvent(CellPreviewEvent<T> event);
150
  }
151

  
152
  /**
153
   * The action that controls how selection is handled.
154
   */
155
  public static enum SelectAction {
156
    DEFAULT, // Perform the default action.
157
    SELECT, // Select the value.
158
    DESELECT, // Deselect the value.
159
    TOGGLE, // Toggle the selected state of the value.
160
    IGNORE; // Ignore the event.
161
  }
162

  
163
  /**
164
   * Construct a new {@link GSSSelectionEventManager} that triggers
165
   * selection when any checkbox in any column is clicked.
166
   * 
167
   * @param <T> the data type of the display
168
   * @return a {@link GSSSelectionEventManager} instance
169
   */
170
  public static <T> GSSSelectionEventManager<T> createCheckboxManager() {
171
    return new GSSSelectionEventManager<T>(new CheckboxEventTranslator<T>());
172
  }
173

  
174
  /**
175
   * Construct a new {@link GSSSelectionEventManager} that triggers
176
   * selection when a checkbox in the specified column is clicked.
177
   * 
178
   * @param <T> the data type of the display
179
   * @param column the column to handle
180
   * @return a {@link GSSSelectionEventManager} instance
181
   */
182
  public static <T> GSSSelectionEventManager<T> createCheckboxManager(
183
      int column) {
184
    return new GSSSelectionEventManager<T>(new CheckboxEventTranslator<T>(
185
        column));
186
  }
187

  
188
  /**
189
   * Create a new {@link GSSSelectionEventManager} using the specified
190
   * {@link EventTranslator} to control which {@link SelectAction} to take for
191
   * each event.
192
   * 
193
   * @param <T> the data type of the display
194
   * @param translator the {@link EventTranslator} to use
195
   * @return a {@link GSSSelectionEventManager} instance
196
   */
197
  public static <T> GSSSelectionEventManager<T> createCustomManager(
198
      EventTranslator<T> translator) {
199
    return new GSSSelectionEventManager<T>(translator);
200
  }
201

  
202
  /**
203
   * Create a new {@link GSSSelectionEventManager} that handles selection
204
   * via user interactions.
205
   * 
206
   * @param <T> the data type of the display
207
   * @return a new {@link GSSSelectionEventManager} instance
208
   */
209
  public static <T> GSSSelectionEventManager<T> createDefaultManager() {
210
    return new GSSSelectionEventManager<T>(null);
211
  }
212

  
213
  /**
214
   * The last {@link HasData} that was handled.
215
   */
216
  private HasData<T> lastDisplay;
217

  
218
  /**
219
   * The last page start.
220
   */
221
  private int lastPageStart;
222

  
223
  /**
224
   * The last selected row index.
225
   */
226
  private int lastSelectedIndex = -1;
227

  
228
  /**
229
   * A boolean indicating that the last shift selection was additive.
230
   */
231
  private boolean shiftAdditive;
232

  
233
  /**
234
   * The last place where the user clicked without holding shift. Multi
235
   * selections that use the shift key are rooted at the anchor.
236
   */
237
  private int shiftAnchor = -1;
238

  
239
  /**
240
   * The {@link EventTranslator} that controls how selection is handled.
241
   */
242
  private final EventTranslator<T> translator;
243

  
244
  /**
245
   * Construct a new {@link GSSSelectionEventManager} using the specified
246
   * {@link EventTranslator} to control which {@link SelectAction} to take for
247
   * each event.
248
   * 
249
   * @param translator the {@link EventTranslator} to use
250
   */
251
  protected GSSSelectionEventManager(EventTranslator<T> translator) {
252
    this.translator = translator;
253
  }
254

  
255
  /**
256
   * Update the selection model based on a user selection event.
257
   * 
258
   * @param selectionModel the selection model to update
259
   * @param row the selected row index relative to the page start
260
   * @param rowValue the selected row value
261
   * @param action the {@link SelectAction} to apply
262
   * @param selectRange true to select the range from the last selected row
263
   * @param clearOthers true to clear the current selection
264
   */
265
  public void doMultiSelection(MultiSelectionModel<? super T> selectionModel,
266
      HasData<T> display, int row, T rowValue, SelectAction action,
267
      boolean selectRange, boolean clearOthers) {
268
    // Determine if we will add or remove selection.
269
    boolean addToSelection = true;
270
    if (action != null) {
271
      switch (action) {
272
        case IGNORE:
273
          // Ignore selection.
274
          return;
275
        case SELECT:
276
          addToSelection = true;
277
          break;
278
        case DESELECT:
279
          addToSelection = false;
280
          break;
281
        case TOGGLE:
282
          addToSelection = !selectionModel.isSelected(rowValue);
283
          break;
284
        case DEFAULT:
285
          break;
286
      }
287
    }
288

  
289
    // Determine which rows will be newly selected.
290
    int pageStart = display.getVisibleRange().getStart();
291
    if (selectRange && pageStart == lastPageStart && lastSelectedIndex > -1
292
        && shiftAnchor > -1 && display == lastDisplay) {
293
      /*
294
       * Get the new shift bounds based on the existing shift anchor and the
295
       * selected row.
296
       */
297
      int start = Math.min(shiftAnchor, row); // Inclusive.
298
      int end = Math.max(shiftAnchor, row); // Inclusive.
299

  
300
      if (lastSelectedIndex < start) {
301
        // Revert previous selection if the user reselects a smaller range.
302
        setRangeSelection(selectionModel, display, new Range(lastSelectedIndex,
303
            start - lastSelectedIndex), !shiftAdditive, false);
304
      } else if (lastSelectedIndex > end) {
305
        // Revert previous selection if the user reselects a smaller range.
306
        setRangeSelection(selectionModel, display, new Range(end + 1,
307
            lastSelectedIndex - end), !shiftAdditive, false);
308
      } else {
309
        // Remember if we are adding or removing rows.
310
        shiftAdditive = addToSelection;
311
      }
312

  
313
      // Update the last selected row, but do not move the shift anchor.
314
      lastSelectedIndex = row;
315

  
316
      // Select the range.
317
      setRangeSelection(selectionModel, display, new Range(start, end - start
318
          + 1), shiftAdditive, clearOthers);
319
    } else {
320
      /*
321
       * If we are not selecting a range, save the last row and set the shift
322
       * anchor.
323
       */
324
      lastDisplay = display;
325
      lastPageStart = pageStart;
326
      lastSelectedIndex = row;
327
      shiftAnchor = row;
328
      selectOne(selectionModel, rowValue, addToSelection, clearOthers);
329
    }
330
  }
331

  
332
  @Override
333
public void onCellPreview(CellPreviewEvent<T> event) {
334
    // Early exit if selection is already handled or we are editing.
335
    if (event.isCellEditing() || event.isSelectionHandled()) {
336
      return;
337
    }
338

  
339
    // Early exit if we do not have a SelectionModel.
340
    HasData<T> display = event.getDisplay();
341
    SelectionModel<? super T> selectionModel = display.getSelectionModel();
342
    if (selectionModel == null) {
343
      return;
344
    }
345

  
346
    // Check for user defined actions.
347
    SelectAction action = (translator == null) ? SelectAction.DEFAULT
348
        : translator.translateSelectionEvent(event);
349

  
350
    // Handle the event based on the SelectionModel type.
351
    if (selectionModel instanceof MultiSelectionModel) {
352
      // Add shift key support for MultiSelectionModel.
353
      handleMultiSelectionEvent(event, action,
354
          (MultiSelectionModel<? super T>) selectionModel);
355
    } else {
356
      // Use the standard handler.
357
      handleSelectionEvent(event, action, selectionModel);
358
    }
359
  }
360

  
361
  /**
362
   * Removes all items from the selection.
363
   * 
364
   * @param selectionModel the {@link MultiSelectionModel} to clear
365
   */
366
  protected void clearSelection(MultiSelectionModel<? super T> selectionModel) {
367
    selectionModel.clear();
368
  }
369

  
370
  /**
371
   * Handle an event that could cause a value to be selected for a
372
   * {@link MultiSelectionModel}. This overloaded method adds support for both
373
   * the control and shift keys. If the shift key is held down, all rows between
374
   * the previous selected row and the current row are selected.
375
   * 
376
   * @param event the {@link CellPreviewEvent} that triggered selection
377
   * @param action the action to handle
378
   * @param selectionModel the {@link SelectionModel} to update
379
   */
380
  protected void handleMultiSelectionEvent(CellPreviewEvent<T> event,
381
      SelectAction action, MultiSelectionModel<? super T> selectionModel) {
382
    NativeEvent nativeEvent = event.getNativeEvent();
383
    String type = nativeEvent.getType();
384
    boolean rightclick = "mousedown".equals(type) && nativeEvent.getButton()==NativeEvent.BUTTON_RIGHT;
385
    SelectAction action1 = action;
386
    if(rightclick){
387
    	boolean shift = nativeEvent.getShiftKey();
388
        boolean ctrlOrMeta = nativeEvent.getCtrlKey() || nativeEvent.getMetaKey();
389
        boolean clearOthers = (translator == null) ? !ctrlOrMeta
390
            : translator.clearCurrentSelection(event);
391
        if (action == null || action == SelectAction.DEFAULT) {
392
          action1 = ctrlOrMeta ? SelectAction.TOGGLE : SelectAction.SELECT;
393
        }
394
        //if the row is selected then do nothing
395
        if(selectionModel.isSelected(event.getValue())){
396
        	return;
397
        }
398
        doMultiSelection(selectionModel, event.getDisplay(), event.getIndex(),
399
            event.getValue(), action1, shift, clearOthers);
400
    }
401
    else if ("click".equals(type)) {
402
      /*
403
       * Update selection on click. Selection is toggled only if the user
404
       * presses the ctrl key. If the user does not press the control key,
405
       * selection is additive.
406
       */
407
      boolean shift = nativeEvent.getShiftKey();
408
      boolean ctrlOrMeta = nativeEvent.getCtrlKey() || nativeEvent.getMetaKey();
409
      boolean clearOthers = (translator == null) ? !ctrlOrMeta
410
          : translator.clearCurrentSelection(event);
411
      if (action == null || action == SelectAction.DEFAULT) {
412
        action1 = ctrlOrMeta ? SelectAction.TOGGLE : SelectAction.SELECT;
413
      }
414
      doMultiSelection(selectionModel, event.getDisplay(), event.getIndex(),
415
          event.getValue(), action1, shift, clearOthers);
416
      if(ctrlOrMeta){
417
    	  event.setCanceled(true);
418
      }
419
    } else if ("keyup".equals(type)) {
420
      int keyCode = nativeEvent.getKeyCode();
421
      if (keyCode == 32) {
422
        /*
423
         * Update selection when the space bar is pressed. The spacebar always
424
         * toggles selection, regardless of whether the control key is pressed.
425
         */
426
        boolean shift = nativeEvent.getShiftKey();
427
        boolean clearOthers = (translator == null) ? false
428
            : translator.clearCurrentSelection(event);
429
        if (action == null || action == SelectAction.DEFAULT) {
430
          action1 = SelectAction.TOGGLE;
431
        }
432
        doMultiSelection(selectionModel, event.getDisplay(), event.getIndex(),
433
            event.getValue(), action1, shift, clearOthers);
434
      }
435
    }
436
  }
437

  
438
  /**
439
   * Handle an event that could cause a value to be selected. This method works
440
   * for any {@link SelectionModel}. Pressing the space bar or ctrl+click will
441
   * toggle the selection state. Clicking selects the row if it is not selected.
442
   * 
443
   * @param event the {@link CellPreviewEvent} that triggered selection
444
   * @param action the action to handle
445
   * @param selectionModel the {@link SelectionModel} to update
446
   */
447
  protected void handleSelectionEvent(CellPreviewEvent<T> event,
448
      SelectAction action, SelectionModel<? super T> selectionModel) {
449
    // Handle selection overrides.
450
    T value = event.getValue();
451
    if (action != null) {
452
      switch (action) {
453
        case IGNORE:
454
          return;
455
        case SELECT:
456
          selectionModel.setSelected(value, true);
457
          return;
458
        case DESELECT:
459
          selectionModel.setSelected(value, false);
460
          return;
461
        case TOGGLE:
462
          selectionModel.setSelected(value, !selectionModel.isSelected(value));
463
          return;
464
		case DEFAULT:
465
			break;
466
      }
467
    }
468

  
469
    // Handle default selection.
470
    NativeEvent nativeEvent = event.getNativeEvent();
471
    String type = nativeEvent.getType();
472
    if ("click".equals(type)) {
473
      if (nativeEvent.getCtrlKey() || nativeEvent.getMetaKey()) {
474
        // Toggle selection on ctrl+click.
475
        selectionModel.setSelected(value, !selectionModel.isSelected(value));
476
      } else {
477
        // Select on click.
478
        selectionModel.setSelected(value, true);
479
      }
480
    } else if ("keyup".equals(type)) {
481
      // Toggle selection on space.
482
      int keyCode = nativeEvent.getKeyCode();
483
      if (keyCode == 32) {
484
        selectionModel.setSelected(value, !selectionModel.isSelected(value));
485
      }
486
    }
487
  }
488

  
489
  /**
490
   * Selects the given item, optionally clearing any prior selection.
491
   * 
492
   * @param selectionModel the {@link MultiSelectionModel} to update
493
   * @param target the item to select
494
   * @param selected true to select, false to deselect
495
   * @param clearOthers true to clear all other selected items
496
   */
497
  protected void selectOne(MultiSelectionModel<? super T> selectionModel,
498
      T target, boolean selected, boolean clearOthers) {
499
    if (clearOthers) {
500
      clearSelection(selectionModel);
501
    }
502
    selectionModel.setSelected(target, selected);
503
  }
504

  
505
  /**
506
   * Select or deselect a range of row indexes, optionally deselecting all other
507
   * values.
508
   * 
509
   * @param selectionModel the {@link MultiSelectionModel} to update
510
   * @param display the {@link HasData} source of the selection event
511
   * @param range the {@link Range} of rows to select or deselect
512
   * @param addToSelection true to select, false to deselect the range
513
   * @param clearOthers true to deselect rows not in the range
514
   */
515
  protected void setRangeSelection(
516
      MultiSelectionModel<? super T> selectionModel, HasData<T> display,
517
      Range range, boolean addToSelection, boolean clearOthers) {
518
    // Get the list of values to select.
519
    List<T> toUpdate = new ArrayList<T>();
520
    int start = range.getStart();
521
    int end = start + range.getLength();
522
    for (int i = start; i < end ; i++) {
523
	     toUpdate.add(display.getVisibleItem(i-display.getVisibleRange().getStart()));
524
	}
525
    // Clear all other values.
526
    if (clearOthers) {
527
      clearSelection(selectionModel);
528
    }
529

  
530
    // Update the state of the values.
531
    for (T value : toUpdate) {
532
      selectionModel.setSelected(value, addToSelection);
533
    }
534
  }
535
}
536

  
/dev/null
1
/*
2
 * Copyright 2010 Google Inc.
3
 * 
4
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5
 * use this file except in compliance with the License. You may obtain a copy of
6
 * the License at
7
 * 
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 * 
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
 * License for the specific language governing permissions and limitations under
14
 * the License.
15
 */
16
/* Incremental changes from CellTable.css */ 
17
.cellTableFooter {
18
  padding: 3px 9px;
19
}
20

  
21
.cellTableHeader {
22
    border:none;
23
	font-weight: bold;
24
	cursor: pointer;
25
	color: white;
26
}
27

  
28
.cellTableCell {
29
  padding: 4px 9px;
30
  border-width: 0;
31
}
32

  
33
.cellTableFirstColumn {
34
  padding: 0px;
35
}
36

  
37
.cellTableLastColumn {
38
  padding: 0px;
39
}
40

  
41
.cellTableFirstColumnFooter {
42
  border: 0px;
43
  padding: 0px;
44
}
45

  
46
.cellTableFirstColumnHeader {
47
  border: 0px;
48
  padding: 0px;
49
}
50

  
51
.cellTableLastColumnFooter {
52
  border: 0px;
53
  padding: 0px;
54
}
55

  
56
.cellTableLastColumnHeader {
57
  border: 0px;
58
  padding: 0px;
59
}
60

  
61
.cellTableEvenRow {
62
  cursor: hand;
63
  cursor: pointer;
64
  background: none;
65
}
66

  
67
.cellTableOddRow {
68
  cursor: hand;
69
  cursor: pointer;
70
  background: none;
71
}
72

  
73
.cellTableSelectedRow {
74
  color: #d45500;
75
  height: auto;
76
  overflow: auto;
77
}
78

  
79
.cellTableHoveredRow {
80
    background: none;
81
}
/dev/null
1
/*
2
 * Copyright 2010 Google Inc.
3
 * 
4
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5
 * use this file except in compliance with the License. You may obtain a copy of
6
 * the License at
7
 * 
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 * 
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
 * License for the specific language governing permissions and limitations under
14
 * the License.
15
 */
16
.cellTreeWidget {
17
  
18
}
19

  
20
.cellTreeEmptyMessage {
21
  padding-left: 16px;
22
  font-style: italic;
23
  background: url(images/cellTreeLoadingBasic.gif) no-repeat;
24
  color: #4085A5;
25
}
26

  
27
.cellTreeItem {
28
  padding-top: 4px;
29
  padding-bottom: 4px;
30
  cursor: hand;
31
  cursor: pointer;
32
  zoom: 1;
33
}
34

  
35
.cellTreeItemImage {
36
  
37
}
38

  
39
.cellTreeItemImageValue {
40
  zoom: 1;
41
}
42

  
43
.cellTreeItemValue {
44
  padding-left: 3px;
45
  padding-right: 3px;
46
  outline: none;
47
}
48

  
49
.cellTreeOpenItem {
50
  
51
}
52

  
53
.cellTreeTopItem {
54
  
55
}
56

  
57
.cellTreeTopItemImage {
58
  
59
}
60

  
61
.cellTreeTopItemImageValue {
62
  
63
}
64

  
65
.cellTreeKeyboardSelectedItem {
66
  outline: none;
67
}
68

  
69
.cellTreeSelectedItem {
70
  color: #d45500;
71
  height: auto;
72
  overflow: visible;
73
}
74

  
75
.cellTreeShowMoreButton {
76
  padding-left: 16px;
77
  outline: none;
78
}
b/src/gr/grnet/pithos/web/client/PithosCellTable.css
1
/*
2
 * Copyright 2010 Google Inc.
3
 * 
4
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5
 * use this file except in compliance with the License. You may obtain a copy of
6
 * the License at
7
 * 
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 * 
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
 * License for the specific language governing permissions and limitations under
14
 * the License.
15
 */
16
/* Incremental changes from CellTable.css */ 
17
.cellTableFooter {
18
  padding: 3px 9px;
19
}
20

  
21
.cellTableHeader {
22
    border:none;
23
	font-weight: bold;
24
	cursor: pointer;
25
	color: white;
26
}
27

  
28
.cellTableCell {
29
  padding: 4px 9px;
30
  border-width: 0;
31
}
32

  
33
.cellTableFirstColumn {
34
  padding: 0px;
35
}
36

  
37
.cellTableLastColumn {
38
  padding: 0px;
39
}
40

  
41
.cellTableFirstColumnFooter {
42
  border: 0px;
43
  padding: 0px;
44
}
45

  
46
.cellTableFirstColumnHeader {
47
  border: 0px;
48
  padding: 0px;
49
}
50

  
51
.cellTableLastColumnFooter {
52
  border: 0px;
53
  padding: 0px;
54
}
55

  
56
.cellTableLastColumnHeader {
57
  border: 0px;
58
  padding: 0px;
59
}
60

  
61
.cellTableEvenRow {
62
  cursor: hand;
63
  cursor: pointer;
64
  background: none;
65
}
66

  
67
.cellTableOddRow {
68
  cursor: hand;
69
  cursor: pointer;
70
  background: none;
71
}
72

  
73
.cellTableSelectedRow {
74
  color: #d45500;
75
  height: auto;
76
  overflow: auto;
77
}
78

  
79
.cellTableHoveredRow {
80
    background: none;
81
}
b/src/gr/grnet/pithos/web/client/PithosCellTreeBasic.css
1
/*
2
 * Copyright 2010 Google Inc.
3
 * 
4
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5
 * use this file except in compliance with the License. You may obtain a copy of
6
 * the License at
7
 * 
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 * 
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
 * License for the specific language governing permissions and limitations under
14
 * the License.
15
 */
16
.cellTreeWidget {
17
  
18
}
19

  
20
.cellTreeEmptyMessage {
21
  padding-left: 16px;
22
  font-style: italic;
23
  background: url(images/cellTreeLoadingBasic.gif) no-repeat;
24
  color: #4085A5;
25
}
26

  
27
.cellTreeItem {
28
  padding-top: 4px;
29
  padding-bottom: 4px;
30
  cursor: hand;
31
  cursor: pointer;
32
  zoom: 1;
33
}
34

  
35
.cellTreeItemImage {
36
  
37
}
38

  
39
.cellTreeItemImageValue {
40
  zoom: 1;
41
}
42

  
43
.cellTreeItemValue {
44
  padding-left: 3px;
45
  padding-right: 3px;
46
  outline: none;
47
}
48

  
49
.cellTreeOpenItem {
50
  
51
}
52

  
53
.cellTreeTopItem {
54
  
55
}
56

  
57
.cellTreeTopItemImage {
58
  
59
}
60

  
61
.cellTreeTopItemImageValue {
62
  
63
}
64

  
65
.cellTreeKeyboardSelectedItem {
66
  outline: none;
67
}
68

  
69
.cellTreeSelectedItem {
70
  color: #d45500;
71
  height: auto;
72
  overflow: visible;
73
}
74

  
75
.cellTreeShowMoreButton {
76
  padding-left: 16px;
77
  outline: none;
78
}
b/src/gr/grnet/pithos/web/client/PithosSelectionEventManager.java
1
/*
2
 * Copyright 2011 GRNET S.A. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or
5
 * without modification, are permitted provided that the following
6
 * conditions are met:
7
 *
8
 *   1. Redistributions of source code must retain the above
9
 *      copyright notice, this list of conditions and the following
10
 *      disclaimer.
11
 *
12
 *   2. Redistributions in binary form must reproduce the above
13
 *      copyright notice, this list of conditions and the following
14
 *      disclaimer in the documentation and/or other materials
15
 *      provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
 * POSSIBILITY OF SUCH DAMAGE.
29
 *
30
 * The views and conclusions contained in the software and
31
 * documentation are those of the authors and should not be
32
 * interpreted as representing official policies, either expressed
33
 * or implied, of GRNET S.A.
34
 */
35
package gr.grnet.pithos.web.client;
36

  
37

  
38

  
39
import java.util.ArrayList;
40
import java.util.List;
41

  
42
import com.google.gwt.dom.client.Element;
43
import com.google.gwt.dom.client.InputElement;
44
import com.google.gwt.dom.client.NativeEvent;
45
import com.google.gwt.view.client.CellPreviewEvent;
46
import com.google.gwt.view.client.HasData;
47
import com.google.gwt.view.client.MultiSelectionModel;
48
import com.google.gwt.view.client.Range;
49
import com.google.gwt.view.client.SelectionModel;
50

  
51
/**
52
 * An implementation of {@link com.google.gwt.view.client.CellPreviewEvent.Handler} that adds selection
53
 * support via the spacebar and mouse clicks and handles the control key.
54
 * 
55
 * <p>
56
 * If the {@link HasData} source of the selection event uses a
57
 * {@link MultiSelectionModel}, this manager additionally provides support for
58
 * shift key to select a range of values. For all other {@link SelectionModel}s,
59
 * only the control key is supported.
60
 * </p>
61
 * 
62
 * @param <T> the data type of records in the list
63
 */
64
public class PithosSelectionEventManager<T> implements
65
    CellPreviewEvent.Handler<T> {
66

  
67
  /**
68
   * Implementation of {@link gr.grnet.pithos.web.client.PithosSelectionEventManager.EventTranslator} that only triggers selection when
69
   * any checkbox is selected.
70
   * 
71
   * @param <T> the data type
72
   */
73
  public static class CheckboxEventTranslator<T> implements EventTranslator<T> {
74

  
75
    /**
76
     * The column index of the checkbox. Other columns are ignored.
77
     */
78
    private final int column;
79

  
80
    /**
81
     * Construct a new {@link gr.grnet.pithos.web.client.PithosSelectionEventManager.CheckboxEventTranslator} that will trigger
82
     * selection when any checkbox in any column is selected.
83
     */
84
    public CheckboxEventTranslator() {
85
      this(-1);
86
    }
87

  
88
    /**
89
     * Construct a new {@link gr.grnet.pithos.web.client.PithosSelectionEventManager.CheckboxEventTranslator} that will trigger
90
     * selection when a checkbox in the specified column is selected.
91
     * 
92
     * @param column the column index, or -1 for all columns
93
     */
94
    public CheckboxEventTranslator(int column) {
95
      this.column = column;
96
    }
97

  
98
    @Override
99
	public boolean clearCurrentSelection(@SuppressWarnings("unused") CellPreviewEvent<T> event) {
100
      return false;
101
    }
102

  
103
    @Override
104
	public SelectAction translateSelectionEvent(CellPreviewEvent<T> event) {
105
      // Handle the event.
106
      NativeEvent nativeEvent = event.getNativeEvent();
107
      if ("click".equals(nativeEvent.getType())) {
108
        // Ignore if the event didn't occur in the correct column.
109
        if (column > -1 && column != event.getColumn()) {
110
          return SelectAction.IGNORE;
111
        }
112

  
113
        // Determine if we clicked on a checkbox.
114
        Element target = nativeEvent.getEventTarget().cast();
115
        if ("input".equals(target.getTagName().toLowerCase())) {
116
          final InputElement input = target.cast();
117
          if ("checkbox".equals(input.getType().toLowerCase())) {
118
            // Synchronize the checkbox with the current selection state.
119
            input.setChecked(event.getDisplay().getSelectionModel().isSelected(
120
                event.getValue()));
121
            return SelectAction.TOGGLE;
122
          }
123
        }
124
        return SelectAction.IGNORE;
125
      }
126

  
127
      // For keyboard events, do the default action.
128
      return SelectAction.DEFAULT;
129
    }
130
  }
131

  
132
  /**
133
   * Translates {@link CellPreviewEvent}s into {@link SelectAction}s.
134
   */
135
  public static interface EventTranslator<T> {
136
    /**
137
     * Check whether a user selection event should clear all currently selected
138
     * values.
139
     * 
140
     * @param event the {@link CellPreviewEvent} to translate
141
     */
142
    boolean clearCurrentSelection(CellPreviewEvent<T> event);
143

  
144
    /**
145
     * Translate the user selection event into a {@link SelectAction}.
146
     * 
147
     * @param event the {@link CellPreviewEvent} to translate
148
     */
149
    SelectAction translateSelectionEvent(CellPreviewEvent<T> event);
150
  }
151

  
152
  /**
153
   * The action that controls how selection is handled.
154
   */
155
  public static enum SelectAction {
156
    DEFAULT, // Perform the default action.
157
    SELECT, // Select the value.
158
    DESELECT, // Deselect the value.
159
    TOGGLE, // Toggle the selected state of the value.
160
    IGNORE; // Ignore the event.
161
  }
162

  
163
  /**
164
   * Construct a new {@link PithosSelectionEventManager} that triggers
165
   * selection when any checkbox in any column is clicked.
166
   * 
167
   * @param <T> the data type of the display
168
   * @return a {@link PithosSelectionEventManager} instance
169
   */
170
  public static <T> PithosSelectionEventManager<T> createCheckboxManager() {
171
    return new PithosSelectionEventManager<T>(new CheckboxEventTranslator<T>());
172
  }
173

  
174
  /**
175
   * Construct a new {@link PithosSelectionEventManager} that triggers
176
   * selection when a checkbox in the specified column is clicked.
177
   * 
178
   * @param <T> the data type of the display
179
   * @param column the column to handle
180
   * @return a {@link PithosSelectionEventManager} instance
181
   */
182
  public static <T> PithosSelectionEventManager<T> createCheckboxManager(
183
      int column) {
184
    return new PithosSelectionEventManager<T>(new CheckboxEventTranslator<T>(
185
        column));
186
  }
187

  
188
  /**
189
   * Create a new {@link PithosSelectionEventManager} using the specified
190
   * {@link EventTranslator} to control which {@link SelectAction} to take for
191
   * each event.
192
   * 
193
   * @param <T> the data type of the display
194
   * @param translator the {@link EventTranslator} to use
195
   * @return a {@link PithosSelectionEventManager} instance
196
   */
197
  public static <T> PithosSelectionEventManager<T> createCustomManager(
198
      EventTranslator<T> translator) {
199
    return new PithosSelectionEventManager<T>(translator);
200
  }
201

  
202
  /**
203
   * Create a new {@link PithosSelectionEventManager} that handles selection
204
   * via user interactions.
205
   * 
206
   * @param <T> the data type of the display
207
   * @return a new {@link PithosSelectionEventManager} instance
208
   */
209
  public static <T> PithosSelectionEventManager<T> createDefaultManager() {
210
    return new PithosSelectionEventManager<T>(null);
211
  }
212

  
213
  /**
214
   * The last {@link HasData} that was handled.
215
   */
216
  private HasData<T> lastDisplay;
217

  
218
  /**
219
   * The last page start.
220
   */
221
  private int lastPageStart;
222

  
223
  /**
224
   * The last selected row index.
225
   */
226
  private int lastSelectedIndex = -1;
227

  
228
  /**
229
   * A boolean indicating that the last shift selection was additive.
230
   */
231
  private boolean shiftAdditive;
232

  
233
  /**
234
   * The last place where the user clicked without holding shift. Multi
235
   * selections that use the shift key are rooted at the anchor.
236
   */
237
  private int shiftAnchor = -1;
238

  
239
  /**
240
   * The {@link EventTranslator} that controls how selection is handled.
241
   */
242
  private final EventTranslator<T> translator;
243

  
244
  /**
245
   * Construct a new {@link PithosSelectionEventManager} using the specified
246
   * {@link EventTranslator} to control which {@link SelectAction} to take for
247
   * each event.
248
   * 
249
   * @param translator the {@link EventTranslator} to use
250
   */
251
  protected PithosSelectionEventManager(EventTranslator<T> translator) {
252
    this.translator = translator;
253
  }
254

  
255
  /**
256
   * Update the selection model based on a user selection event.
257
   * 
258
   * @param selectionModel the selection model to update
259
   * @param row the selected row index relative to the page start
260
   * @param rowValue the selected row value
261
   * @param action the {@link SelectAction} to apply
262
   * @param selectRange true to select the range from the last selected row
263
   * @param clearOthers true to clear the current selection
264
   */
265
  public void doMultiSelection(MultiSelectionModel<? super T> selectionModel,
266
      HasData<T> display, int row, T rowValue, SelectAction action,
267
      boolean selectRange, boolean clearOthers) {
268
    // Determine if we will add or remove selection.
269
    boolean addToSelection = true;
270
    if (action != null) {
271
      switch (action) {
272
        case IGNORE:
273
          // Ignore selection.
274
          return;
275
        case SELECT:
276
          addToSelection = true;
277
          break;
278
        case DESELECT:
279
          addToSelection = false;
280
          break;
281
        case TOGGLE:
282
          addToSelection = !selectionModel.isSelected(rowValue);
283
          break;
284
        case DEFAULT:
285
          break;
286
      }
287
    }
288

  
289
    // Determine which rows will be newly selected.
290
    int pageStart = display.getVisibleRange().getStart();
291
    if (selectRange && pageStart == lastPageStart && lastSelectedIndex > -1
292
        && shiftAnchor > -1 && display == lastDisplay) {
293
      /*
294
       * Get the new shift bounds based on the existing shift anchor and the
295
       * selected row.
296
       */
297
      int start = Math.min(shiftAnchor, row); // Inclusive.
298
      int end = Math.max(shiftAnchor, row); // Inclusive.
299

  
300
      if (lastSelectedIndex < start) {
301
        // Revert previous selection if the user reselects a smaller range.
302
        setRangeSelection(selectionModel, display, new Range(lastSelectedIndex,
303
            start - lastSelectedIndex), !shiftAdditive, false);
304
      } else if (lastSelectedIndex > end) {
305
        // Revert previous selection if the user reselects a smaller range.
306
        setRangeSelection(selectionModel, display, new Range(end + 1,
307
            lastSelectedIndex - end), !shiftAdditive, false);
308
      } else {
309
        // Remember if we are adding or removing rows.
310
        shiftAdditive = addToSelection;
311
      }
312

  
313
      // Update the last selected row, but do not move the shift anchor.
314
      lastSelectedIndex = row;
315

  
316
      // Select the range.
317
      setRangeSelection(selectionModel, display, new Range(start, end - start
318
          + 1), shiftAdditive, clearOthers);
319
    } else {
320
      /*
321
       * If we are not selecting a range, save the last row and set the shift
322
       * anchor.
323
       */
324
      lastDisplay = display;
325
      lastPageStart = pageStart;
326
      lastSelectedIndex = row;
327
      shiftAnchor = row;
328
      selectOne(selectionModel, rowValue, addToSelection, clearOthers);
329
    }
330
  }
331

  
332
  @Override
333
public void onCellPreview(CellPreviewEvent<T> event) {
334
    // Early exit if selection is already handled or we are editing.
335
    if (event.isCellEditing() || event.isSelectionHandled()) {
336
      return;
337
    }
338

  
339
    // Early exit if we do not have a SelectionModel.
340
    HasData<T> display = event.getDisplay();
341
    SelectionModel<? super T> selectionModel = display.getSelectionModel();
342
    if (selectionModel == null) {
343
      return;
344
    }
345

  
346
    // Check for user defined actions.
347
    SelectAction action = (translator == null) ? SelectAction.DEFAULT
348
        : translator.translateSelectionEvent(event);
349

  
350
    // Handle the event based on the SelectionModel type.
351
    if (selectionModel instanceof MultiSelectionModel) {
352
      // Add shift key support for MultiSelectionModel.
353
      handleMultiSelectionEvent(event, action,
354
          (MultiSelectionModel<? super T>) selectionModel);
355
    } else {
356
      // Use the standard handler.
357
      handleSelectionEvent(event, action, selectionModel);
358
    }
359
  }
360

  
361
  /**
362
   * Removes all items from the selection.
363
   * 
364
   * @param selectionModel the {@link MultiSelectionModel} to clear
365
   */
366
  protected void clearSelection(MultiSelectionModel<? super T> selectionModel) {
367
    selectionModel.clear();
368
  }
369

  
370
  /**
371
   * Handle an event that could cause a value to be selected for a
372
   * {@link MultiSelectionModel}. This overloaded method adds support for both
373
   * the control and shift keys. If the shift key is held down, all rows between
374
   * the previous selected row and the current row are selected.
375
   * 
376
   * @param event the {@link CellPreviewEvent} that triggered selection
377
   * @param action the action to handle
378
   * @param selectionModel the {@link SelectionModel} to update
379
   */
380
  protected void handleMultiSelectionEvent(CellPreviewEvent<T> event,
381
      SelectAction action, MultiSelectionModel<? super T> selectionModel) {
382
    NativeEvent nativeEvent = event.getNativeEvent();
383
    String type = nativeEvent.getType();
384
    boolean rightclick = "mousedown".equals(type) && nativeEvent.getButton()==NativeEvent.BUTTON_RIGHT;
385
    SelectAction action1 = action;
386
    if(rightclick){
387
    	boolean shift = nativeEvent.getShiftKey();
388
        boolean ctrlOrMeta = nativeEvent.getCtrlKey() || nativeEvent.getMetaKey();
389
        boolean clearOthers = (translator == null) ? !ctrlOrMeta
390
            : translator.clearCurrentSelection(event);
391
        if (action == null || action == SelectAction.DEFAULT) {
392
          action1 = ctrlOrMeta ? SelectAction.TOGGLE : SelectAction.SELECT;
393
        }
394
        //if the row is selected then do nothing
395
        if(selectionModel.isSelected(event.getValue())){
396
        	return;
397
        }
398
        doMultiSelection(selectionModel, event.getDisplay(), event.getIndex(),
399
            event.getValue(), action1, shift, clearOthers);
400
    }
401
    else if ("click".equals(type)) {
402
      /*
403
       * Update selection on click. Selection is toggled only if the user
404
       * presses the ctrl key. If the user does not press the control key,
405
       * selection is additive.
406
       */
407
      boolean shift = nativeEvent.getShiftKey();
408
      boolean ctrlOrMeta = nativeEvent.getCtrlKey() || nativeEvent.getMetaKey();
409
      boolean clearOthers = (translator == null) ? !ctrlOrMeta
410
          : translator.clearCurrentSelection(event);
411
      if (action == null || action == SelectAction.DEFAULT) {
412
        action1 = ctrlOrMeta ? SelectAction.TOGGLE : SelectAction.SELECT;
413
      }
414
      doMultiSelection(selectionModel, event.getDisplay(), event.getIndex(),
415
          event.getValue(), action1, shift, clearOthers);
416
      if(ctrlOrMeta){
417
    	  event.setCanceled(true);
418
      }
419
    } else if ("keyup".equals(type)) {
420
      int keyCode = nativeEvent.getKeyCode();
421
      if (keyCode == 32) {
422
        /*
423
         * Update selection when the space bar is pressed. The spacebar always
424
         * toggles selection, regardless of whether the control key is pressed.
425
         */
426
        boolean shift = nativeEvent.getShiftKey();
427
        boolean clearOthers = (translator == null) ? false
428
            : translator.clearCurrentSelection(event);
429
        if (action == null || action == SelectAction.DEFAULT) {
430
          action1 = SelectAction.TOGGLE;
431
        }
432
        doMultiSelection(selectionModel, event.getDisplay(), event.getIndex(),
433
            event.getValue(), action1, shift, clearOthers);
434
      }
435
    }
436
  }
437

  
438
  /**
439
   * Handle an event that could cause a value to be selected. This method works
440
   * for any {@link SelectionModel}. Pressing the space bar or ctrl+click will
441
   * toggle the selection state. Clicking selects the row if it is not selected.
442
   * 
443
   * @param event the {@link CellPreviewEvent} that triggered selection
444
   * @param action the action to handle
445
   * @param selectionModel the {@link SelectionModel} to update
446
   */
447
  protected void handleSelectionEvent(CellPreviewEvent<T> event,
448
      SelectAction action, SelectionModel<? super T> selectionModel) {
449
    // Handle selection overrides.
450
    T value = event.getValue();
451
    if (action != null) {
452
      switch (action) {
453
        case IGNORE:
454
          return;
455
        case SELECT:
456
          selectionModel.setSelected(value, true);
457
          return;
458
        case DESELECT:
459
          selectionModel.setSelected(value, false);
460
          return;
461
        case TOGGLE:
462
          selectionModel.setSelected(value, !selectionModel.isSelected(value));
463
          return;
464
		case DEFAULT:
465
			break;
466
      }
467
    }
468

  
469
    // Handle default selection.
470
    NativeEvent nativeEvent = event.getNativeEvent();
471
    String type = nativeEvent.getType();
472
    if ("click".equals(type)) {
473
      if (nativeEvent.getCtrlKey() || nativeEvent.getMetaKey()) {
474
        // Toggle selection on ctrl+click.
475
        selectionModel.setSelected(value, !selectionModel.isSelected(value));
476
      } else {
477
        // Select on click.
478
        selectionModel.setSelected(value, true);
479
      }
480
    } else if ("keyup".equals(type)) {
481
      // Toggle selection on space.
482
      int keyCode = nativeEvent.getKeyCode();
483
      if (keyCode == 32) {
484
        selectionModel.setSelected(value, !selectionModel.isSelected(value));
485
      }
486
    }
487
  }
488

  
489
  /**
490
   * Selects the given item, optionally clearing any prior selection.
491
   * 
492
   * @param selectionModel the {@link MultiSelectionModel} to update
493
   * @param target the item to select
494
   * @param selected true to select, false to deselect
495
   * @param clearOthers true to clear all other selected items
496
   */
497
  protected void selectOne(MultiSelectionModel<? super T> selectionModel,
498
      T target, boolean selected, boolean clearOthers) {
499
    if (clearOthers) {
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff