java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html
... ...
@@ -6,6 +6,11 @@
6 6
<div id="mainContent">
7 7
<h4 class="articleHeadline" id="sailingAnalyticsHeadline">What's New - Sailing Analytics</h4>
8 8
<div class="innerContent">
9
+ <h5 class="articleSubheadline">April 2026</h5>
10
+ <ul class="bulletList">
11
+ <li>Tables with multi-selection support now have a select/de-select all checkbox in the table header.
12
+ This comes with general improvements in table selection/de-selection handling.</li>
13
+ </ul>
9 14
<h5 class="articleSubheadline">March 2026</h5>
10 15
<ul class="bulletList">
11 16
<li>Maneuver analysis now identifies track segments worth looking at with consistency.
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java
... ...
@@ -16,6 +16,7 @@ import com.google.gwt.core.client.Scheduler.ScheduledCommand;
16 16
import com.google.gwt.event.shared.HandlerRegistration;
17 17
import com.google.gwt.user.cellview.client.AbstractCellTable;
18 18
import com.google.gwt.user.cellview.client.CellTable;
19
+import com.google.gwt.user.cellview.client.Header;
19 20
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
20 21
import com.google.gwt.user.client.Command;
21 22
import com.google.gwt.user.client.Window;
... ...
@@ -390,20 +391,18 @@ public abstract class AbstractLeaderboardConfigPanel extends FormPanel
390 391
391 392
protected abstract void addColumnsToRacesTable(CellTable<RaceColumnDTOAndFleetDTOWithNameBasedEquality> racesTable);
392 393
393
- protected SelectionCheckboxColumn<StrippedLeaderboardDTO> createSortableSelectionCheckboxColumn(
394
+ protected SelectionCheckboxColumn<StrippedLeaderboardDTO> createSelectionCheckboxColumn(
394 395
final FlushableCellTable<StrippedLeaderboardDTO> leaderboardTable,
395 396
AdminConsoleTableResources tableResources,
396 397
ListHandler<StrippedLeaderboardDTO> leaderboardColumnListHandler,
397 398
ListDataProvider<StrippedLeaderboardDTO> listDataProvider) {
398
- SelectionCheckboxColumn<StrippedLeaderboardDTO> selectionCheckboxColumn = new SelectionCheckboxColumn<StrippedLeaderboardDTO>(
399
+ final SelectionCheckboxColumn<StrippedLeaderboardDTO> selectionCheckboxColumn = new SelectionCheckboxColumn<StrippedLeaderboardDTO>(
399 400
tableResources.cellTableStyle().cellTableCheckboxSelected(),
400 401
tableResources.cellTableStyle().cellTableCheckboxDeselected(),
401 402
tableResources.cellTableStyle().cellTableCheckboxColumnCell(),
402
- new NameBasedStrippedLeaderboardDTOEntityIdentityComparator(), listDataProvider, leaderboardTable);
403
- selectionCheckboxColumn.setSortable(true);
404
- leaderboardColumnListHandler.setComparator(selectionCheckboxColumn,
405
- (o1, o2) -> (leaderboardTable.getSelectionModel().isSelected(o1) ? 1 : 0)
406
- - (leaderboardTable.getSelectionModel().isSelected(o2) ? 1 : 0));
403
+ new NameBasedStrippedLeaderboardDTOEntityIdentityComparator(), listDataProvider);
404
+ final Header<Boolean> selectAllHeader = selectionCheckboxColumn.createHeader();
405
+ leaderboardTable.addColumn(selectionCheckboxColumn, selectAllHeader);
407 406
return selectionCheckboxColumn;
408 407
}
409 408
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/BoatPanel.java
... ...
@@ -61,11 +61,6 @@ public class BoatPanel extends SimplePanel implements FilterablePanelProvider<Bo
61 61
allowReloadButton.setEnabled(!refreshableBoatSelectionModel.getSelectedSet().isEmpty());
62 62
final Button addBoatButton = buttonPanel.addCreateAction(stringMessages.add(), this::openAddBoatDialog);
63 63
addBoatButton.ensureDebugId("AddBoatButton");
64
- buttonPanel.addUnsecuredAction(stringMessages.selectAll(), () -> {
65
- for (BoatDTO b : boatTable.getDataProvider().getList()) {
66
- refreshableBoatSelectionModel.setSelected(b, true);
67
- }
68
- });
69 64
mainPanel.add(boatTable);
70 65
}
71 66
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/CompetitorPanel.java
... ...
@@ -84,11 +84,6 @@ public class CompetitorPanel extends SimplePanel implements BusyDisplay, Filtera
84 84
final Button addCompetitorButton = buttonPanel.addCreateAction(stringMessages.add(),
85 85
()->openAddCompetitorDialog(createWithBoatByDefault));
86 86
addCompetitorButton.ensureDebugId("AddCompetitorButton");
87
- buttonPanel.addUnsecuredAction(stringMessages.selectAll(), () -> {
88
- for (CompetitorDTO c : competitorTable.getDataProvider().getList()) {
89
- refreshableCompetitorSelectionModel.setSelected(c, true);
90
- }
91
- });
92 87
buttonPanel.addCreateAction(stringMessages.importCompetitors(), () -> {
93 88
sailingServiceWrite.getCompetitorProviderNames(new AsyncCallback<Iterable<String>>() {
94 89
@Override
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationListComposite.java
... ...
@@ -25,9 +25,10 @@ import com.sap.sse.common.Util;
25 25
import com.sap.sse.gwt.adminconsole.AdminConsoleTableResources;
26 26
import com.sap.sse.gwt.client.ErrorReporter;
27 27
import com.sap.sse.gwt.client.celltable.AbstractSortableTextColumn;
28
-import com.sap.sse.gwt.client.celltable.BaseCelltable;
29 28
import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
29
+import com.sap.sse.gwt.client.celltable.FlushableCellTable;
30 30
import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
31
+import com.sap.sse.gwt.client.celltable.SelectionCheckboxColumn;
31 32
import com.sap.sse.security.shared.HasPermissions;
32 33
import com.sap.sse.security.shared.HasPermissions.DefaultActions;
33 34
import com.sap.sse.security.shared.impl.SecuredSecurityTypes;
... ...
@@ -37,11 +38,12 @@ import com.sap.sse.security.ui.client.component.DefaultActionsImagesBarCell;
37 38
import com.sap.sse.security.ui.client.component.EditOwnershipDialog;
38 39
import com.sap.sse.security.ui.client.component.SecuredDTOOwnerColumn;
39 40
import com.sap.sse.security.ui.client.component.editacl.EditACLDialog;
41
+import com.google.gwt.user.cellview.client.Header;
40 42
41 43
public class DeviceConfigurationListComposite extends Composite {
42 44
protected static AdminConsoleTableResources tableResource = GWT.create(AdminConsoleTableResources.class);
43 45
44
- private final RefreshableMultiSelectionModel<DeviceConfigurationWithSecurityDTO> refreshableConfigurationSelectionModel;
46
+ private RefreshableMultiSelectionModel<DeviceConfigurationWithSecurityDTO> refreshableConfigurationSelectionModel;
45 47
private final CellTable<DeviceConfigurationWithSecurityDTO> configurationTable;
46 48
protected ListDataProvider<DeviceConfigurationWithSecurityDTO> configurationsDataProvider;
47 49
... ...
@@ -66,23 +68,9 @@ public class DeviceConfigurationListComposite extends Composite {
66 68
noConfigurationsLabel.setWordWrap(false);
67 69
panel.add(noConfigurationsLabel);
68 70
configurationsDataProvider = new ListDataProvider<DeviceConfigurationWithSecurityDTO>();
69
- refreshTable();
70 71
configurationTable = createConfigurationTable(userService);
71 72
configurationTable.setVisible(true);
72
- refreshableConfigurationSelectionModel = new RefreshableMultiSelectionModel<>(
73
- new EntityIdentityComparator<DeviceConfigurationWithSecurityDTO>() {
74
- @Override
75
- public boolean representSameEntity(DeviceConfigurationWithSecurityDTO dto1,
76
- DeviceConfigurationWithSecurityDTO dto2) {
77
- return Util.equalsWithNull(dto1.id, dto2.id);
78
- }
79
-
80
- @Override
81
- public int hashCode(DeviceConfigurationWithSecurityDTO t) {
82
- return t.id == null ? 0 : t.id.hashCode();
83
- }
84
- }, configurationsDataProvider);
85
- configurationTable.setSelectionModel(refreshableConfigurationSelectionModel);
73
+ refreshTable();
86 74
panel.add(configurationTable);
87 75
initWidget(mainPanel);
88 76
}
... ...
@@ -117,14 +105,31 @@ public class DeviceConfigurationListComposite extends Composite {
117 105
}
118 106
119 107
private CellTable<DeviceConfigurationWithSecurityDTO> createConfigurationTable(final UserService userService) {
120
- CellTable<DeviceConfigurationWithSecurityDTO> table = new BaseCelltable<DeviceConfigurationWithSecurityDTO>(
121
- /* pageSize */10000, tableResource);
108
+ final FlushableCellTable<DeviceConfigurationWithSecurityDTO> table = new FlushableCellTable<>(10000, tableResource);
122 109
configurationsDataProvider.addDataDisplay(table);
123 110
table.ensureDebugId("DeviceConfigurationList");
124 111
table.setWidth("100%");
125 112
ListHandler<DeviceConfigurationWithSecurityDTO> columnSortHandler = new ListHandler<DeviceConfigurationWithSecurityDTO>(
126 113
configurationsDataProvider.getList());
127 114
table.addColumnSortHandler(columnSortHandler);
115
+ final SelectionCheckboxColumn<DeviceConfigurationWithSecurityDTO> checkColumn = new SelectionCheckboxColumn<DeviceConfigurationWithSecurityDTO>(
116
+ tableResource.cellTableStyle().cellTableCheckboxSelected(),
117
+ tableResource.cellTableStyle().cellTableCheckboxDeselected(),
118
+ tableResource.cellTableStyle().cellTableCheckboxColumnCell(),
119
+ new EntityIdentityComparator<DeviceConfigurationWithSecurityDTO>() {
120
+ @Override
121
+ public boolean representSameEntity(DeviceConfigurationWithSecurityDTO a, DeviceConfigurationWithSecurityDTO b) {
122
+ return Util.equalsWithNull(a.id, b.id);
123
+ }
124
+ @Override
125
+ public int hashCode(DeviceConfigurationWithSecurityDTO t) {
126
+ return t.id == null ? 0 : t.id.hashCode();
127
+ }
128
+ }, configurationsDataProvider);
129
+ final Header<Boolean> selectAllHeader = checkColumn.createHeader();
130
+ table.addColumn(checkColumn, selectAllHeader);
131
+ refreshableConfigurationSelectionModel = checkColumn.getSelectionModel();
132
+ table.setSelectionModel(refreshableConfigurationSelectionModel, checkColumn.getSelectionManager());
128 133
TextColumn<DeviceConfigurationWithSecurityDTO> identifierNameColumn = new TextColumn<DeviceConfigurationWithSecurityDTO>() {
129 134
@Override
130 135
public String getValue(DeviceConfigurationWithSecurityDTO config) {
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java
... ...
@@ -81,6 +81,7 @@ import com.sap.sse.security.ui.client.component.EditOwnershipDialog;
81 81
import com.sap.sse.security.ui.client.component.EditOwnershipDialog.DialogConfig;
82 82
import com.sap.sse.security.ui.client.component.SecuredDTOOwnerColumn;
83 83
import com.sap.sse.security.ui.client.component.editacl.EditACLDialog;
84
+import com.google.gwt.user.cellview.client.Header;
84 85
85 86
/**
86 87
* A composite showing the list of all sailing events
... ...
@@ -229,7 +230,7 @@ public class EventListComposite extends Composite {
229 230
public int hashCode(EventDTO t) {
230 231
return t.id.hashCode();
231 232
}
232
- }, filterTextbox.getAllListDataProvider(),table);
233
+ }, filterTextbox.getAllListDataProvider());
233 234
AnchorCell anchorCell = new AnchorCell();
234 235
ListHandler<EventDTO> listHandler = new ListHandler<EventDTO>(eventListDataProvider.getList());
235 236
final TextColumn<EventDTO> eventUUidColumn = new AbstractSortableTextColumn<EventDTO>(
... ...
@@ -372,7 +373,8 @@ public class EventListComposite extends Composite {
372 373
configureTableColumnSortHandler(listHandler, eventSelectionCheckboxColumn,
373 374
eventNameColumn, venueNameColumn, startEndDateColumn, isPublicColumn, courseAreasColumn,
374 375
leaderboardGroupsColumn, groupColumn, userColumn);
375
- table.addColumn(eventSelectionCheckboxColumn, eventSelectionCheckboxColumn.getHeader());
376
+ final Header<Boolean> selectAllHeader = eventSelectionCheckboxColumn.createHeader();
377
+ table.addColumn(eventSelectionCheckboxColumn, selectAllHeader);
376 378
table.addColumn(eventNameColumn, stringMessages.event());
377 379
table.addColumn(venueNameColumn, stringMessages.venue());
378 380
table.addColumn(startEndDateColumn, stringMessages.from() + "/" + stringMessages.to());
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiDevicesPanel.java
... ...
@@ -24,6 +24,7 @@ import com.google.gwt.text.shared.SafeHtmlRenderer;
24 24
import com.google.gwt.user.cellview.client.AbstractCellTable;
25 25
import com.google.gwt.user.cellview.client.Column;
26 26
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
27
+import com.google.gwt.user.cellview.client.Header;
27 28
import com.google.gwt.user.cellview.client.TextColumn;
28 29
import com.google.gwt.user.client.Window;
29 30
import com.google.gwt.user.client.rpc.AsyncCallback;
... ...
@@ -310,7 +311,7 @@ public class IgtimiDevicesPanel extends FlowPanel implements FilterablePanelProv
310 311
public int hashCode(IgtimiDeviceWithSecurityDTO t) {
311 312
return 7482 ^ (int) t.getId();
312 313
}
313
- }, filterDevicesPanel.getAllListDataProvider(), table);
314
+ }, filterDevicesPanel.getAllListDataProvider());
314 315
final ListHandler<IgtimiDeviceWithSecurityDTO> columnSortHandler = new ListHandler<>(filteredDevices.getList());
315 316
table.addColumnSortHandler(columnSortHandler);
316 317
columnSortHandler.setComparator(devicesSelectionCheckboxColumn, devicesSelectionCheckboxColumn.getComparator());
... ...
@@ -374,8 +375,8 @@ public class IgtimiDevicesPanel extends FlowPanel implements FilterablePanelProv
374 375
.create(userService.getUserManagementWriteService(), type, roleDefinition -> refreshDevices(), stringMessages);
375 376
actionColumn.addAction(DefaultActionsImagesBarCell.ACTION_CHANGE_ACL, DefaultActions.CHANGE_ACL,
376 377
configACL::openDialog);
377
- // add columns to table:
378
- table.addColumn(devicesSelectionCheckboxColumn, devicesSelectionCheckboxColumn.getHeader());
378
+ final Header<Boolean> devicesSelectAllHeader = devicesSelectionCheckboxColumn.createHeader();
379
+ table.addColumn(devicesSelectionCheckboxColumn, devicesSelectAllHeader);
379 380
table.addColumn(deviceIdColumn, stringMessages.id());
380 381
table.addColumn(deviceNameColumn, stringMessages.name());
381 382
table.addColumn(deviceSerialNumberColumn, stringMessages.serialNumber());
... ...
@@ -464,7 +465,7 @@ public class IgtimiDevicesPanel extends FlowPanel implements FilterablePanelProv
464 465
public int hashCode(IgtimiDataAccessWindowWithSecurityDTO t) {
465 466
return 7482 ^ (int) t.getId();
466 467
}
467
- }, filterDataAccessWindowsPanel.getAllListDataProvider(), table);
468
+ }, filterDataAccessWindowsPanel.getAllListDataProvider());
468 469
final ListHandler<IgtimiDataAccessWindowWithSecurityDTO> columnSortHandler = new ListHandler<>(filteredDAWs.getList());
469 470
table.addColumnSortHandler(columnSortHandler);
470 471
columnSortHandler.setComparator(dawsSelectionCheckboxColumn, dawsSelectionCheckboxColumn.getComparator());
... ...
@@ -491,8 +492,8 @@ public class IgtimiDevicesPanel extends FlowPanel implements FilterablePanelProv
491 492
.create(userService.getUserManagementWriteService(), type, roleDefinition -> refreshDataAccessWindows(), stringMessages);
492 493
actionColumn.addAction(DefaultActionsImagesBarCell.ACTION_CHANGE_ACL, DefaultActions.CHANGE_ACL,
493 494
configACL::openDialog);
494
- // add columns to table:
495
- table.addColumn(dawsSelectionCheckboxColumn, dawsSelectionCheckboxColumn.getHeader());
495
+ final Header<Boolean> dawSelectAllHeader = dawsSelectionCheckboxColumn.createHeader();
496
+ table.addColumn(dawsSelectionCheckboxColumn, dawSelectAllHeader);
496 497
table.addColumn(dawIdColumn, stringMessages.id());
497 498
table.addColumn(dawSerialNumberColumn, stringMessages.serialNumber());
498 499
table.addColumn(dawFromColumn, stringMessages.from());
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java
... ...
@@ -181,7 +181,7 @@ public class LeaderboardConfigPanel extends AbstractLeaderboardConfigPanel
181 181
ListDataProvider<StrippedLeaderboardDTO> listDataProvider) {
182 182
ListHandler<StrippedLeaderboardDTO> leaderboardColumnListHandler = new ListHandler<StrippedLeaderboardDTO>(
183 183
filteredLeaderboardList.getList());
184
- SelectionCheckboxColumn<StrippedLeaderboardDTO> selectionCheckboxColumn = createSortableSelectionCheckboxColumn(
184
+ SelectionCheckboxColumn<StrippedLeaderboardDTO> selectionCheckboxColumn = createSelectionCheckboxColumn(
185 185
leaderboardTable, tableResources, leaderboardColumnListHandler, listDataProvider);
186 186
AnchorCell anchorCell = new AnchorCell();
187 187
Column<StrippedLeaderboardDTO, SafeHtml> linkColumn = new Column<StrippedLeaderboardDTO, SafeHtml>(
... ...
@@ -379,7 +379,6 @@ public class LeaderboardConfigPanel extends AbstractLeaderboardConfigPanel
379 379
configACL.openDialog(t);
380 380
}
381 381
});
382
- leaderboardTable.addColumn(selectionCheckboxColumn, selectionCheckboxColumn.getHeader());
383 382
leaderboardTable.addColumn(linkColumn, stringMessages.name());
384 383
leaderboardTable.addColumn(leaderboardDisplayNameColumn, stringMessages.displayName());
385 384
leaderboardTable.addColumn(leaderboardCanBoatsOfCompetitorsChangePerRaceColumn,
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardGroupConfigPanel.java
... ...
@@ -30,6 +30,7 @@ import com.google.gwt.safehtml.shared.UriUtils;
30 30
import com.google.gwt.user.cellview.client.AbstractCellTable;
31 31
import com.google.gwt.user.cellview.client.CellTable.Resources;
32 32
import com.google.gwt.user.cellview.client.Column;
33
+import com.google.gwt.user.cellview.client.Header;
33 34
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
34 35
import com.google.gwt.user.cellview.client.TextColumn;
35 36
import com.google.gwt.user.client.Window;
... ...
@@ -235,7 +236,7 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel
235 236
public int hashCode(StrippedLeaderboardDTO t) {
236 237
return t.getName().hashCode();
237 238
}
238
- }, leaderboardsFilterablePanel.getAllListDataProvider(), leaderboardsTable);
239
+ }, leaderboardsFilterablePanel.getAllListDataProvider());
239 240
refreshableLeaderboardsSelectionModel = leaderboardTableSelectionColumn.getSelectionModel();
240 241
leaderboardsTable.setSelectionModel(refreshableLeaderboardsSelectionModel, leaderboardTableSelectionColumn.getSelectionManager());
241 242
leaderboardsFilterablePanel.getTextBox().ensureDebugId("LeaderboardsFilterTextBox");
... ...
@@ -279,7 +280,8 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel
279 280
};
280 281
leaderboardsTable.setWidth("100%");
281 282
leaderboardsTable.addColumnSortHandler(leaderboardsListHandler);
282
- leaderboardsTable.addColumn(leaderboardTableSelectionColumn, leaderboardTableSelectionColumn.getHeader());
283
+ final Header<Boolean> selectAllHeader = leaderboardTableSelectionColumn.createHeader();
284
+ leaderboardsTable.addColumn(leaderboardTableSelectionColumn, selectAllHeader);
283 285
leaderboardsTable.addColumn(leaderboardsNameColumn, stringMessages.leaderboardName());
284 286
leaderboardsTable.addColumn(leaderboardsRacesColumn, stringMessages.races());
285 287
refreshableLeaderboardsSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
... ...
@@ -383,9 +385,10 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel
383 385
public int hashCode(StrippedLeaderboardDTO t) {
384 386
return t.getName().hashCode();
385 387
}
386
- }, groupDetailsProvider, groupDetailsTable);
388
+ }, groupDetailsProvider);
389
+ final Header<Boolean> groupDetailsSelectAllHeader = groupDetailsTableSelectionColumn.createHeader();
387 390
groupDetailsTable.setWidth("100%");
388
- groupDetailsTable.addColumn(groupDetailsTableSelectionColumn, groupDetailsTableSelectionColumn.getHeader());
391
+ groupDetailsTable.addColumn(groupDetailsTableSelectionColumn, groupDetailsSelectAllHeader);
389 392
groupDetailsTable.addColumn(groupDetailsNameColumn, stringMessages.leaderboardName());
390 393
groupDetailsTable.addColumn(groupDetailsRacesColumn, stringMessages.races());
391 394
refreshableGroupDetailsSelectionModel = groupDetailsTableSelectionColumn.getSelectionModel();
... ...
@@ -593,9 +596,10 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel
593 596
public int hashCode(LeaderboardGroupDTO t) {
594 597
return t.getId().hashCode();
595 598
}
596
- }, groupsFilterablePanel.getAllListDataProvider(), groupsTable);
599
+ }, groupsFilterablePanel.getAllListDataProvider());
600
+ final Header<Boolean> groupsSelectAllHeader = leaderboardTableSelectionColumn.createHeader();
597 601
groupsTable.setWidth("100%");
598
- groupsTable.addColumn(leaderboardTableSelectionColumn, leaderboardTableSelectionColumn.getHeader());
602
+ groupsTable.addColumn(leaderboardTableSelectionColumn, groupsSelectAllHeader);
599 603
groupsTable.addColumn(groupNameColumn, stringMessages.name());
600 604
groupsTable.addColumn(groupDescriptionColumn, stringMessages.description());
601 605
groupsTable.addColumn(groupDisplayNameColumn, stringMessages.displayName());
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/MediaPanel.java
... ...
@@ -122,7 +122,6 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
122 122
add(buttonAndFilterPanel);
123 123
allMediaTracks = new ArrayList<>();
124 124
buttonAndFilterPanel.addUnsecuredAction(stringMessages.refresh(), new Command() {
125
-
126 125
@Override
127 126
public void execute() {
128 127
presenter.getMediaTracksRefresher().reloadAndCallFillAll();
... ...
@@ -138,7 +137,6 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
138 137
@Override
139 138
public void execute() {
140 139
new MultiVideoDialog(sailingServiceWrite, mediaServiceWrite, stringMessages, errorReporter, new Runnable() {
141
-
142 140
@Override
143 141
public void run() {
144 142
presenter.getMediaTracksRefresher().reloadAndCallFillAll();
... ...
@@ -165,11 +163,9 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
165 163
}
166 164
});
167 165
multiURLChange.setEnabled(false);
168
-
169 166
Label lblFilterRaces = new Label(stringMessages.filterMediaByName() + ":");
170 167
lblFilterRaces.setWordWrap(false);
171 168
buttonAndFilterPanel.addUnsecuredWidget(lblFilterRaces);
172
-
173 169
this.filterableMediaTracks = new LabeledAbstractFilterablePanel<MediaTrackWithSecurityDTO>(lblFilterRaces,
174 170
allMediaTracks, mediaTrackListDataProvider, stringMessages) {
175 171
@Override
... ...
@@ -231,17 +227,14 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
231 227
232 228
private void createMediaTracksTable(final UserService userService) {
233 229
// Create a CellTable.
234
-
235 230
// Set a key provider that provides a unique key for each contact. If key is
236 231
// used to identify contacts when fields (such as the name and address)
237 232
// change.
238 233
mediaTracksTable = new BaseCelltable<>(1000, tableResources);
239 234
mediaTracksTable.setWidth("100%");
240
-
241 235
// Attach a column sort handler to the ListDataProvider to sort the list.
242 236
ListHandler<MediaTrackWithSecurityDTO> sortHandler = new ListHandler<>(mediaTrackListDataProvider.getList());
243 237
mediaTracksTable.addColumnSortHandler(sortHandler);
244
-
245 238
// Add a selection model so we can select cells.
246 239
refreshableSelectionModel = new RefreshableMultiSelectionModel<>(
247 240
new EntityIdentityComparator<MediaTrackWithSecurityDTO>() {
... ...
@@ -258,17 +251,17 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
258 251
DefaultSelectionEventManager.createCustomManager(
259 252
new DefaultSelectionEventManager.CheckboxEventTranslator<MediaTrackWithSecurityDTO>() {
260 253
@Override
261
- public boolean clearCurrentSelection(CellPreviewEvent<MediaTrackWithSecurityDTO> event) {
254
+ public boolean clearCurrentSelection(CellPreviewEvent<MediaTrackWithSecurityDTO> event) {
262 255
return !isCheckboxColumn(event.getColumn());
263 256
}
264 257
265 258
@Override
266
- public SelectAction translateSelectionEvent(
259
+ public SelectAction translateSelectionEvent(
267 260
CellPreviewEvent<MediaTrackWithSecurityDTO> event) {
268 261
NativeEvent nativeEvent = event.getNativeEvent();
269 262
if (BrowserEvents.CLICK.equals(nativeEvent.getType())) {
270 263
if (nativeEvent.getCtrlKey()) {
271
- MediaTrackWithSecurityDTO value = event.getValue();
264
+ MediaTrackWithSecurityDTO value = event.getValue();
272 265
refreshableSelectionModel.setSelected(value, !refreshableSelectionModel.isSelected(value));
273 266
return SelectAction.IGNORE;
274 267
}
... ...
@@ -286,7 +279,6 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
286 279
287 280
// Initialize the columns.
288 281
initTableColumns(sortHandler, userService);
289
-
290 282
mediaTrackListDataProvider.addDataDisplay(mediaTracksTable);
291 283
add(mediaTracksTable);
292 284
allMediaTracks.clear();
... ...
@@ -309,7 +301,6 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
309 301
};
310 302
mediaTracksTable.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("<br/>"));
311 303
mediaTracksTable.setColumnWidth(checkColumn, 40, Unit.PX);
312
-
313 304
// db id
314 305
Column<MediaTrackWithSecurityDTO, String> dbIdColumn = new Column<MediaTrackWithSecurityDTO, String>(
315 306
new TextCell()) {
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RegattaListComposite.java
... ...
@@ -19,6 +19,7 @@ import com.google.gwt.safehtml.shared.SafeHtml;
19 19
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
20 20
import com.google.gwt.user.cellview.client.AbstractCellTable;
21 21
import com.google.gwt.user.cellview.client.CellTable;
22
+import com.google.gwt.user.cellview.client.Header;
22 23
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
23 24
import com.google.gwt.user.cellview.client.TextColumn;
24 25
import com.google.gwt.user.client.Window;
... ...
@@ -185,7 +186,7 @@ public class RegattaListComposite extends Composite {
185 186
public int hashCode(RegattaDTO t) {
186 187
return t.getRegattaIdentifier().hashCode();
187 188
}
188
- }, filterablePanelRegattas.getAllListDataProvider(), table);
189
+ }, filterablePanelRegattas.getAllListDataProvider());
189 190
ListHandler<RegattaDTO> columnSortHandler = new ListHandler<RegattaDTO>(regattaListDataProvider.getList());
190 191
table.addColumnSortHandler(columnSortHandler);
191 192
columnSortHandler.setComparator(regattaSelectionCheckboxColumn, regattaSelectionCheckboxColumn.getComparator());
... ...
@@ -304,7 +305,8 @@ public class RegattaListComposite extends Composite {
304 305
stringMessages);
305 306
actionsColumn.addAction(RegattaConfigImagesBarCell.ACTION_CHANGE_ACL, DefaultActions.CHANGE_ACL,
306 307
regattaDTO -> configACL.openDialog(regattaDTO));
307
- table.addColumn(regattaSelectionCheckboxColumn, regattaSelectionCheckboxColumn.getHeader());
308
+ final Header<Boolean> selectAllHeader = regattaSelectionCheckboxColumn.createHeader();
309
+ table.addColumn(regattaSelectionCheckboxColumn, selectAllHeader);
308 310
table.addColumn(regattaNameColumn, stringMessages.regattaName());
309 311
table.addColumn(regattaCanBoatsOfCompetitorsChangePerRaceColumn, stringMessages.canBoatsChange());
310 312
table.addColumn(competitorRegistrationTypeColumn, stringMessages.competitorRegistrationTypeShort());
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SmartphoneTrackingEventManagementPanel.java
... ...
@@ -148,7 +148,7 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
148 148
ListDataProvider<StrippedLeaderboardDTO> listDataProvider) {
149 149
ListHandler<StrippedLeaderboardDTO> leaderboardColumnListHandler = new ListHandler<StrippedLeaderboardDTO>(
150 150
filteredLeaderboardList.getList());
151
- SelectionCheckboxColumn<StrippedLeaderboardDTO> selectionCheckboxColumn = createSortableSelectionCheckboxColumn(
151
+ SelectionCheckboxColumn<StrippedLeaderboardDTO> selectionCheckboxColumn = createSelectionCheckboxColumn(
152 152
leaderboardTable, tableResources, leaderboardColumnListHandler, listDataProvider);
153 153
TextColumn<StrippedLeaderboardDTO> leaderboardNameColumn = new TextColumn<StrippedLeaderboardDTO>() {
154 154
@Override
... ...
@@ -212,7 +212,6 @@ public class SmartphoneTrackingEventManagementPanel extends AbstractLeaderboardC
212 212
configOwnership::openOwnershipDialog);
213 213
leaderboardActionColumn.addAction(DefaultActionsImagesBarCell.ACTION_CHANGE_ACL, DefaultActions.UPDATE,
214 214
configACL::openDialog);
215
- leaderboardTable.addColumn(selectionCheckboxColumn, selectionCheckboxColumn.getHeader());
216 215
leaderboardTable.addColumn(leaderboardNameColumn, stringMessages.name());
217 216
leaderboardTable.addColumn(leaderboardDisplayNameColumn, stringMessages.displayName());
218 217
leaderboardTable.addColumn(leaderboardCanBoatsOfCompetitorsChangePerRaceColumn,
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportListComposite.java
... ...
@@ -14,6 +14,7 @@ import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
14 14
import com.sap.sse.gwt.client.celltable.FlushableCellTable;
15 15
import com.sap.sse.gwt.client.celltable.SelectionCheckboxColumn;
16 16
import com.sap.sse.security.ui.client.UserService;
17
+import com.google.gwt.user.cellview.client.Header;
17 18
18 19
public class StructureImportListComposite extends RegattaListComposite {
19 20
... ...
@@ -57,7 +58,7 @@ public class StructureImportListComposite extends RegattaListComposite {
57 58
public int hashCode(RegattaDTO t) {
58 59
return t.getRegattaIdentifier().hashCode();
59 60
}
60
- }, regattaListDataProvider, table);
61
+ }, regattaListDataProvider);
61 62
62 63
ListHandler<RegattaDTO> columnSortHandler = new ListHandler<RegattaDTO>(regattaListDataProvider.getList());
63 64
table.addColumnSortHandler(columnSortHandler);
... ...
@@ -91,7 +92,8 @@ public class StructureImportListComposite extends RegattaListComposite {
91 92
});
92 93
93 94
columnSortHandler.setComparator(selectionCheckboxColumn, selectionCheckboxColumn.getComparator());
94
- table.addColumn(selectionCheckboxColumn, selectionCheckboxColumn.getHeader());
95
+ final Header<Boolean> selectAllHeader = selectionCheckboxColumn.createHeader();
96
+ table.addColumn(selectionCheckboxColumn, selectAllHeader);
95 97
table.addColumn(regattaNameColumn, stringMessages.regattaName());
96 98
table.addColumn(regattaStructureColumn, stringMessages.series());
97 99
table.setSelectionModel(selectionCheckboxColumn.getSelectionModel(), selectionCheckboxColumn.getSelectionManager());
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingEventManagementPanel.java
... ...
@@ -11,6 +11,7 @@ import com.google.gwt.user.cellview.client.AbstractCellTable;
11 11
import com.google.gwt.user.cellview.client.Column;
12 12
import com.google.gwt.user.cellview.client.ColumnSortEvent.Handler;
13 13
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
14
+import com.google.gwt.user.cellview.client.Header;
14 15
import com.google.gwt.user.cellview.client.TextColumn;
15 16
import com.google.gwt.user.client.rpc.AsyncCallback;
16 17
import com.google.gwt.user.client.ui.Button;
... ...
@@ -234,10 +235,10 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
234 235
return object.regattaName;
235 236
}
236 237
};
237
- SelectionCheckboxColumn<SwissTimingRaceRecordDTO> selectionColumn = new SelectionCheckboxColumn<SwissTimingRaceRecordDTO>(
238
+ SelectionCheckboxColumn<SwissTimingRaceRecordDTO> raceTableSelectionColumn = new SelectionCheckboxColumn<SwissTimingRaceRecordDTO>(
238 239
tableRes.cellTableStyle().cellTableCheckboxSelected(),
239 240
tableRes.cellTableStyle().cellTableCheckboxDeselected(),
240
- tableRes.cellTableStyle().cellTableCheckboxColumnCell(), entityIdentityComparator, raceList, raceTable);
241
+ tableRes.cellTableStyle().cellTableCheckboxColumnCell(), entityIdentityComparator, raceList);
241 242
242 243
TextColumn<SwissTimingRaceRecordDTO> seriesNameColumn = new TextColumn<SwissTimingRaceRecordDTO>() {
243 244
@Override
... ...
@@ -283,7 +284,9 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
283 284
raceStatusColumn.setSortable(true);
284 285
regattaNameColumn.setSortable(true);
285 286
seriesNameColumn.setSortable(true);
286
- raceTable.addColumn(selectionColumn, selectionColumn.getHeader());
287
+ raceTable.setSelectionModel(raceTableSelectionColumn.getSelectionModel(), raceTableSelectionColumn.getSelectionManager());
288
+ final Header<Boolean> selectAllHeader = raceTableSelectionColumn.createHeader();
289
+ raceTable.addColumn(raceTableSelectionColumn, selectAllHeader);
287 290
raceTable.addColumn(regattaNameColumn, stringConstants.regatta());
288 291
raceTable.addColumn(seriesNameColumn, stringConstants.series());
289 292
raceTable.addColumn(raceNameColumn, stringConstants.name());
... ...
@@ -291,7 +294,6 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
291 294
raceTable.addColumn(boatClassColumn, stringConstants.boatClass());
292 295
raceTable.addColumn(genderColumn, stringConstants.gender());
293 296
raceTable.addColumn(raceStartTimeColumn, stringConstants.startTime());
294
- raceTable.setSelectionModel(selectionColumn.getSelectionModel(), selectionColumn.getSelectionManager());
295 297
trackableRacesPanel.add(raceTable);
296 298
raceList.addDataDisplay(raceTable);
297 299
Handler columnSortHandler = getRaceTableColumnSortHandler(raceList.getList(), regattaNameColumn, seriesNameColumn,
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/SwissTimingReplayConnectorPanel.java
... ...
@@ -10,8 +10,8 @@ import com.google.gwt.core.client.GWT;
10 10
import com.google.gwt.event.dom.client.ClickEvent;
11 11
import com.google.gwt.event.dom.client.ClickHandler;
12 12
import com.google.gwt.user.cellview.client.AbstractCellTable;
13
-import com.google.gwt.user.cellview.client.CellTable;
14 13
import com.google.gwt.user.cellview.client.Column;
14
+import com.google.gwt.user.cellview.client.Header;
15 15
import com.google.gwt.user.cellview.client.ColumnSortEvent.Handler;
16 16
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
17 17
import com.google.gwt.user.cellview.client.TextColumn;
... ...
@@ -41,10 +41,10 @@ import com.sap.sse.gwt.adminconsole.AdminConsoleTableResources;
41 41
import com.sap.sse.gwt.adminconsole.FilterablePanelProvider;
42 42
import com.sap.sse.gwt.client.ErrorReporter;
43 43
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
44
-import com.sap.sse.gwt.client.celltable.BaseCelltable;
45 44
import com.sap.sse.gwt.client.celltable.CellTableWithCheckboxResources;
46 45
import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
47
-import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
46
+import com.sap.sse.gwt.client.celltable.FlushableCellTable;
47
+import com.sap.sse.gwt.client.celltable.SelectionCheckboxColumn;
48 48
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
49 49
import com.sap.sse.gwt.client.panels.AbstractFilterablePanel;
50 50
import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel;
... ...
@@ -62,7 +62,7 @@ public class SwissTimingReplayConnectorPanel extends AbstractEventManagementPane
62 62
private final ErrorReporter errorReporter;
63 63
private final LabeledAbstractFilterablePanel<SwissTimingReplayRaceDTO> filterablePanelEvents;
64 64
private final ListDataProvider<SwissTimingReplayRaceDTO> raceList;
65
- private final CellTable<SwissTimingReplayRaceDTO> raceTable;
65
+ private final FlushableCellTable<SwissTimingReplayRaceDTO> raceTable;
66 66
private final List<SwissTimingReplayRaceDTO> availableSwissTimingRaces;
67 67
68 68
private final SwissTimingArchivedConnectionTableWrapper connectionsTable;
... ...
@@ -71,32 +71,25 @@ public class SwissTimingReplayConnectorPanel extends AbstractEventManagementPane
71 71
super(presenter, true, stringMessages);
72 72
this.errorReporter = presenter.getErrorReporter();
73 73
availableSwissTimingRaces = new ArrayList<SwissTimingReplayRaceDTO>();
74
-
75 74
// setup UI
76 75
final VerticalPanel mainPanel = new VerticalPanel();
77 76
this.setWidget(mainPanel);
78 77
mainPanel.setWidth("100%");
79
-
80 78
final CaptionPanel captionPanelConnections = new CaptionPanel(stringMessages.connections());
81 79
mainPanel.add(captionPanelConnections);
82
-
83 80
final VerticalPanel verticalPanel = new VerticalPanel();
84
-
85 81
captionPanelConnections.setContentWidget(verticalPanel);
86 82
captionPanelConnections.setStyleName("bold");
87
-
88 83
// add connections table
89 84
connectionsTable = new SwissTimingArchivedConnectionTableWrapper(presenter.getUserService(), sailingServiceWrite, stringMessages,
90 85
errorReporter, true, tableResources, () -> {
91 86
});
92 87
connectionsTable.refreshConnectionList();
93
-
94 88
// create button UI
95 89
final AccessControlledButtonPanel buttonPanel = createButtonPanel(sailingServiceWrite, presenter.getUserService(), errorReporter,
96 90
stringMessages);
97 91
verticalPanel.add(buttonPanel);
98 92
verticalPanel.add(connectionsTable);
99
-
100 93
// Table
101 94
TextColumn<SwissTimingReplayRaceDTO> regattaNameColumn = new TextColumn<SwissTimingReplayRaceDTO>() {
102 95
@Override
... ...
@@ -121,29 +114,22 @@ public class SwissTimingReplayConnectorPanel extends AbstractEventManagementPane
121 114
public String getValue(SwissTimingReplayRaceDTO object) {
122 115
return object.boat_class;
123 116
}
124
-
125 117
};
126
-
127 118
HorizontalPanel racesSplitPanel = new HorizontalPanel();
128 119
mainPanel.add(racesSplitPanel);
129
-
130 120
CaptionPanel racesCaptionPanel = new CaptionPanel(stringMessages.trackableRaces());
131 121
racesSplitPanel.add(racesCaptionPanel);
132 122
racesCaptionPanel.setWidth("50%");
133
-
134 123
CaptionPanel trackedRacesCaptionPanel = new CaptionPanel(stringMessages.trackedRaces());
135 124
racesSplitPanel.add(trackedRacesCaptionPanel);
136 125
trackedRacesCaptionPanel.setWidth("50%");
137
-
138 126
VerticalPanel racesPanel = new VerticalPanel();
139 127
racesCaptionPanel.setContentWidget(racesPanel);
140 128
racesCaptionPanel.setStyleName("bold");
141
-
142 129
VerticalPanel trackedRacesPanel = new VerticalPanel();
143 130
trackedRacesPanel.setWidth("100%");
144 131
trackedRacesCaptionPanel.setContentWidget(trackedRacesPanel);
145 132
trackedRacesCaptionPanel.setStyleName("bold");
146
-
147 133
// text box for filtering the cell table
148 134
// the regatta selection for a tracked race
149 135
HorizontalPanel regattaPanel = new HorizontalPanel();
... ...
@@ -155,16 +141,12 @@ public class SwissTimingReplayConnectorPanel extends AbstractEventManagementPane
155 141
regattaPanel.add(lblRegattas);
156 142
regattaPanel.add(getAvailableRegattasListBox());
157 143
regattaPanel.setCellVerticalAlignment(getAvailableRegattasListBox(), HasVerticalAlignment.ALIGN_MIDDLE);
158
-
159 144
HorizontalPanel filterPanel = new HorizontalPanel();
160 145
filterPanel.setSpacing(5);
161 146
racesPanel.add(filterPanel);
162
-
163 147
Label lblFilterEvents = new Label(stringMessages.filterRaces()+ ":");
164 148
filterPanel.add(lblFilterEvents);
165 149
filterPanel.setCellVerticalAlignment(lblFilterEvents, HasVerticalAlignment.ALIGN_MIDDLE);
166
-
167
-
168 150
HorizontalPanel racesHorizontalPanel = new HorizontalPanel();
169 151
racesPanel.add(racesHorizontalPanel);
170 152
VerticalPanel trackPanel = new VerticalPanel();
... ...
@@ -173,11 +155,7 @@ public class SwissTimingReplayConnectorPanel extends AbstractEventManagementPane
173 155
raceStartTrackingColumn.setSortable(true);
174 156
boatClassNamesColumn.setSortable(true);
175 157
AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class);
176
- raceTable = new BaseCelltable<SwissTimingReplayRaceDTO>(/* pageSize */10000, tableRes);
177
- raceTable.addColumn(raceNameColumn, stringMessages.race());
178
- raceTable.addColumn(regattaNameColumn, "RSC");
179
- raceTable.addColumn(boatClassNamesColumn, stringMessages.boatClass());
180
- raceTable.addColumn(raceStartTrackingColumn, stringMessages.startTime());
158
+ raceTable = new FlushableCellTable<>(10000, tableRes);
181 159
raceTable.setWidth("300px");
182 160
raceList = new ListDataProvider<SwissTimingReplayRaceDTO>();
183 161
filterablePanelEvents = new LabeledAbstractFilterablePanel<SwissTimingReplayRaceDTO>(lblFilterEvents,
... ...
@@ -194,19 +172,28 @@ public class SwissTimingReplayConnectorPanel extends AbstractEventManagementPane
194 172
return raceTable;
195 173
}
196 174
};
197
- raceTable.setSelectionModel(new RefreshableMultiSelectionModel<SwissTimingReplayRaceDTO>(
175
+ final SelectionCheckboxColumn<SwissTimingReplayRaceDTO> checkColumn = new SelectionCheckboxColumn<SwissTimingReplayRaceDTO>(
176
+ tableRes.cellTableStyle().cellTableCheckboxSelected(),
177
+ tableRes.cellTableStyle().cellTableCheckboxDeselected(),
178
+ tableRes.cellTableStyle().cellTableCheckboxColumnCell(),
198 179
new EntityIdentityComparator<SwissTimingReplayRaceDTO>() {
199 180
@Override
200
- public boolean representSameEntity(SwissTimingReplayRaceDTO dto1, SwissTimingReplayRaceDTO dto2) {
201
- return dto1.race_id.equals(dto2.race_id);
181
+ public boolean representSameEntity(SwissTimingReplayRaceDTO a, SwissTimingReplayRaceDTO b) {
182
+ return a.race_id.equals(b.race_id);
202 183
}
203 184
@Override
204 185
public int hashCode(SwissTimingReplayRaceDTO t) {
205 186
return t.race_id.hashCode();
206 187
}
207
- }, filterablePanelEvents.getAllListDataProvider()) {
208
- });
209
-
188
+ }, filterablePanelEvents.getAllListDataProvider());
189
+ checkColumn.setSortable(false);
190
+ final Header<Boolean> selectAllHeader = checkColumn.createHeader();
191
+ raceTable.setSelectionModel(checkColumn.getSelectionModel(), checkColumn.getSelectionManager());
192
+ raceTable.addColumn(checkColumn, selectAllHeader);
193
+ raceTable.addColumn(raceNameColumn, stringMessages.race());
194
+ raceTable.addColumn(regattaNameColumn, "RSC");
195
+ raceTable.addColumn(boatClassNamesColumn, stringMessages.boatClass());
196
+ raceTable.addColumn(raceStartTrackingColumn, stringMessages.startTime());
210 197
racesHorizontalPanel.add(raceTable);
211 198
racesHorizontalPanel.add(trackPanel);
212 199
raceList.addDataDisplay(raceTable);
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TracTracEventManagementPanel.java
... ...
@@ -5,6 +5,7 @@ import java.util.Comparator;
5 5
import java.util.List;
6 6
import java.util.Set;
7 7
8
+import com.google.gwt.user.cellview.client.Header;
8 9
import com.google.gwt.core.client.GWT;
9 10
import com.google.gwt.event.dom.client.ClickEvent;
10 11
import com.google.gwt.event.dom.client.ClickHandler;
... ...
@@ -332,8 +333,9 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel i
332 333
public int hashCode(TracTracRaceRecordDTO t) {
333 334
return t.id.hashCode();
334 335
}
335
- }, racesFilterablePanel.getAllListDataProvider(), racesTable);
336
- racesTable.addColumn(selectionCheckboxColumn, selectionCheckboxColumn.getHeader());
336
+ }, racesFilterablePanel.getAllListDataProvider());
337
+ final Header<Boolean> selectAllHeader = selectionCheckboxColumn.createHeader();
338
+ racesTable.addColumn(selectionCheckboxColumn, selectAllHeader);
337 339
racesTable.addColumn(regattaNameColumn, stringMessages.event());
338 340
racesTable.addColumn(raceNameColumn, stringMessages.race());
339 341
racesTable.addColumn(boatClassColumn, stringMessages.boatClass());
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/coursecreation/CourseTemplatePanel.java
... ...
@@ -19,10 +19,10 @@ import java.util.stream.Collectors;
19 19
import com.google.gwt.cell.client.TextCell;
20 20
import com.google.gwt.core.client.GWT;
21 21
import com.google.gwt.dom.client.Style.Unit;
22
-import com.google.gwt.safehtml.shared.SafeHtmlUtils;
23 22
import com.google.gwt.user.cellview.client.AbstractCellTable;
24 23
import com.google.gwt.user.cellview.client.Column;
25 24
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
25
+import com.google.gwt.user.cellview.client.Header;
26 26
import com.google.gwt.user.client.Window;
27 27
import com.google.gwt.user.client.rpc.AsyncCallback;
28 28
import com.google.gwt.user.client.ui.FlowPanel;
... ...
@@ -102,12 +102,10 @@ public class CourseTemplatePanel extends FlowPanel implements FilterablePanelPro
102 102
buttonAndFilterPanel.addRemoveAction(stringMessages.remove(), refreshableSelectionModel, true,
103 103
() -> removeCourseTemplates(refreshableSelectionModel.getSelectedSet().stream()
104 104
.map(courseTemplateDTO -> courseTemplateDTO.getUuid()).collect(Collectors.toList())));
105
-
106 105
buttonAndFilterPanel.addUnsecuredWidget(lblFilterRaces);
107 106
buttonAndFilterPanel.addUnsecuredWidget(filterableCourseTemplatePanel);
108 107
filterableCourseTemplatePanel
109 108
.setUpdatePermissionFilterForCheckbox(event -> userService.hasPermission(event, DefaultActions.UPDATE));
110
-
111 109
}
112 110
113 111
private void removeCourseTemplates(Collection<UUID> courseTemplatesUuids) {
... ...
@@ -175,7 +173,6 @@ public class CourseTemplatePanel extends FlowPanel implements FilterablePanelPro
175 173
private void createCourseTemplateTable(final UserService userService) {
176 174
courseTemplateTable = new FlushableCellTable<>(1000, tableResources);
177 175
courseTemplateTable.setWidth("100%");
178
-
179 176
// Attach a column sort handler to the ListDataProvider to sort the list.
180 177
ListHandler<CourseTemplateDTO> sortHandler = new ListHandler<>(courseTemplateListDataProvider.getList());
181 178
courseTemplateTable.addColumnSortHandler(sortHandler);
... ...
@@ -203,9 +200,9 @@ public class CourseTemplatePanel extends FlowPanel implements FilterablePanelPro
203 200
public int hashCode(CourseTemplateDTO t) {
204 201
return t.getUuid().hashCode();
205 202
}
206
- }, filterableCourseTemplatePanel.getAllListDataProvider(), courseTemplateTable);
207
-
208
- courseTemplateTable.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("<br/>"));
203
+ }, filterableCourseTemplatePanel.getAllListDataProvider());
204
+ final Header<Boolean> selectAllHeader = checkColumn.createHeader();
205
+ courseTemplateTable.addColumn(checkColumn, selectAllHeader);
209 206
courseTemplateTable.setColumnWidth(checkColumn, 40, Unit.PX);
210 207
// id
211 208
Column<CourseTemplateDTO, String> idColumn = new Column<CourseTemplateDTO, String>(new TextCell()) {
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/coursecreation/MarkPropertiesPanel.java
... ...
@@ -22,10 +22,10 @@ import com.google.gwt.cell.client.TextCell;
22 22
import com.google.gwt.core.client.GWT;
23 23
import com.google.gwt.dom.client.Style.Unit;
24 24
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
25
-import com.google.gwt.safehtml.shared.SafeHtmlUtils;
26 25
import com.google.gwt.user.cellview.client.AbstractCellTable;
27 26
import com.google.gwt.user.cellview.client.Column;
28 27
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
28
+import com.google.gwt.user.cellview.client.Header;
29 29
import com.google.gwt.user.client.Window;
30 30
import com.google.gwt.user.client.rpc.AsyncCallback;
31 31
import com.google.gwt.user.client.ui.AbstractImagePrototype;
... ...
@@ -183,8 +183,9 @@ public class MarkPropertiesPanel extends FlowPanel implements FilterablePanelPro
183 183
public int hashCode(MarkPropertiesDTO t) {
184 184
return t.getUuid().hashCode();
185 185
}
186
- }, filterableMarkProperties.getAllListDataProvider(), markPropertiesTable);
187
- markPropertiesTable.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("<br/>"));
186
+ }, filterableMarkProperties.getAllListDataProvider());
187
+ final Header<Boolean> selectAllHeader = checkColumn.createHeader();
188
+ markPropertiesTable.addColumn(checkColumn, selectAllHeader);
188 189
markPropertiesTable.setColumnWidth(checkColumn, 40, Unit.PX);
189 190
// id
190 191
Column<MarkPropertiesDTO, String> idColumn = new Column<MarkPropertiesDTO, String>(new TextCell()) {
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/coursecreation/MarkRolePanel.java
... ...
@@ -13,10 +13,10 @@ import com.google.gwt.core.client.GWT;
13 13
import com.google.gwt.dom.client.BrowserEvents;
14 14
import com.google.gwt.dom.client.NativeEvent;
15 15
import com.google.gwt.dom.client.Style.Unit;
16
-import com.google.gwt.safehtml.shared.SafeHtmlUtils;
17 16
import com.google.gwt.user.cellview.client.AbstractCellTable;
18 17
import com.google.gwt.user.cellview.client.Column;
19 18
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
19
+import com.google.gwt.user.cellview.client.Header;
20 20
import com.google.gwt.user.client.Command;
21 21
import com.google.gwt.user.client.rpc.AsyncCallback;
22 22
import com.google.gwt.user.client.ui.FlowPanel;
... ...
@@ -71,7 +71,6 @@ public class MarkRolePanel extends FlowPanel implements FilterablePanelProvider<
71 71
add(buttonAndFilterPanel);
72 72
allMarkRoles = new ArrayList<>();
73 73
buttonAndFilterPanel.addUnsecuredAction(stringMessages.refresh(), new Command() {
74
-
75 74
@Override
76 75
public void execute() {
77 76
loadMarkRoles();
... ...
@@ -187,8 +186,9 @@ public class MarkRolePanel extends FlowPanel implements FilterablePanelProvider<
187 186
public int hashCode(MarkRoleDTO t) {
188 187
return t.getUuid().hashCode();
189 188
}
190
- }, filterableMarkRoles.getAllListDataProvider(), markRolesTable);
191
- markRolesTable.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("<br/>"));
189
+ }, filterableMarkRoles.getAllListDataProvider());
190
+ final Header<Boolean> selectAllHeader = checkColumn.createHeader();
191
+ markRolesTable.addColumn(checkColumn, selectAllHeader);
192 192
markRolesTable.setColumnWidth(checkColumn, 40, Unit.PX);
193 193
// id
194 194
Column<MarkRoleDTO, String> idColumn = new Column<MarkRoleDTO, String>(new TextCell()) {
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/coursecreation/MarkTemplatePanel.java
... ...
@@ -11,10 +11,10 @@ import java.util.List;
11 11
import com.google.gwt.cell.client.TextCell;
12 12
import com.google.gwt.core.client.GWT;
13 13
import com.google.gwt.dom.client.Style.Unit;
14
-import com.google.gwt.safehtml.shared.SafeHtmlUtils;
15 14
import com.google.gwt.user.cellview.client.AbstractCellTable;
16 15
import com.google.gwt.user.cellview.client.Column;
17 16
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
17
+import com.google.gwt.user.cellview.client.Header;
18 18
import com.google.gwt.user.client.Command;
19 19
import com.google.gwt.user.client.rpc.AsyncCallback;
20 20
import com.google.gwt.user.client.ui.FlowPanel;
... ...
@@ -152,8 +152,9 @@ public class MarkTemplatePanel extends FlowPanel implements FilterablePanelProvi
152 152
public int hashCode(MarkTemplateDTO t) {
153 153
return t.getUuid().hashCode();
154 154
}
155
- }, filterableMarkTemplates.getAllListDataProvider(), markTemplateTable);
156
- markTemplateTable.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("<br/>"));
155
+ }, filterableMarkTemplates.getAllListDataProvider());
156
+ Header<Boolean> selectAllHeader = checkColumn.createHeader();
157
+ markTemplateTable.addColumn(checkColumn, selectAllHeader);
157 158
markTemplateTable.setColumnWidth(checkColumn, 40, Unit.PX);
158 159
// id
159 160
Column<MarkTemplateDTO, String> idColumn = new Column<MarkTemplateDTO, String>(new TextCell()) {
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java
... ...
@@ -56,7 +56,6 @@ import com.google.gwt.view.client.CellPreviewEvent;
56 56
import com.google.gwt.view.client.ListDataProvider;
57 57
import com.google.gwt.view.client.SelectionChangeEvent;
58 58
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
59
-import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
60 59
import com.sap.sailing.domain.common.DetailType;
61 60
import com.sap.sailing.domain.common.LeaderboardNameConstants;
62 61
import com.sap.sailing.domain.common.MaxPointsReason;
... ...
@@ -109,6 +108,7 @@ import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
109 108
import com.sap.sse.gwt.client.celltable.AbstractSortableColumnWithMinMax;
110 109
import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
111 110
import com.sap.sse.gwt.client.celltable.FlushableSortedCellTableWithStylableHeaders;
111
+import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
112 112
import com.sap.sse.gwt.client.celltable.SelectionCheckboxColumn;
113 113
import com.sap.sse.gwt.client.celltable.SortedCellTable;
114 114
import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator;
... ...
@@ -2123,7 +2123,7 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
2123 2123
public int hashCode(LeaderboardRowDTO t) {
2124 2124
return t.competitor.getIdAsString().hashCode();
2125 2125
}
2126
- }, getData(), leaderboardTable);
2126
+ }, getData());
2127 2127
// Note: LeaderboardPanel is the ONLY listener that syncs selection state with CompetitorSelectionProvider.
2128 2128
// SelectionCheckboxColumn no longer needs to listen separately.
2129 2129
}
... ...
@@ -2489,8 +2489,7 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
2489 2489
// This causes in consequence potentiallyChangedSettings to not be equal to currentSettings anymore.
2490 2490
// We then apply the new settings to make all new race columns visible.
2491 2491
// TODO check if there is an easier way to get to know if we need to reapply the settings.
2492
- LS potentiallyChangedSettings = overrideDefaultsForNamesOfRaceColumns(currentSettings,
2493
- result);
2492
+ LS potentiallyChangedSettings = overrideDefaultsForNamesOfRaceColumns(currentSettings, result);
2494 2493
// reapply, when this is the first time we received the race columns or if columns have
2495 2494
// changed
2496 2495
if (wasEmptyRaceColumnSelection
... ...
@@ -3129,7 +3128,7 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
3129 3128
if (getLeaderboardTable().getColumnCount() > selectionCheckboxColumnIndex) {
3130 3129
if (showSelectionCheckbox) {
3131 3130
if (getLeaderboardTable().getColumn(selectionCheckboxColumnIndex) != selectionCheckboxColumn) {
3132
- insertColumn(selectionCheckboxColumnIndex, selectionCheckboxColumn);
3131
+ insertSelectionCheckboxColumn(selectionCheckboxColumnIndex);
3133 3132
} // else, the column is needed and is already in place
3134 3133
} else {
3135 3134
if (getLeaderboardTable().getColumn(selectionCheckboxColumnIndex) == selectionCheckboxColumn) {
... ...
@@ -3138,12 +3137,19 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
3138 3137
}
3139 3138
} else {
3140 3139
if (showSelectionCheckbox) {
3141
- insertColumn(selectionCheckboxColumnIndex, selectionCheckboxColumn);
3140
+ insertSelectionCheckboxColumn(selectionCheckboxColumnIndex);
3142 3141
}
3143 3142
}
3144 3143
return indexOfNextColumn;
3145 3144
}
3146 3145
3146
+ private void insertSelectionCheckboxColumn(int beforeIndex) {
3147
+ removeColumnStyles(beforeIndex);
3148
+ getLeaderboardTable().insertColumn(beforeIndex, selectionCheckboxColumn, selectionCheckboxColumn.createHeader(),
3149
+ /* comparator */ null, selectionCheckboxColumn.getPreferredSortingOrder().isAscending());
3150
+ addColumnStyles(beforeIndex);
3151
+ }
3152
+
3147 3153
/**
3148 3154
* @return the 0-based index for the next column
3149 3155
*/
java/com.sap.sailing.www/release_notes_admin.html
... ...
@@ -23,6 +23,11 @@
23 23
<div class="mainContent">
24 24
<h2 class="releaseHeadline">Release Notes - Administration Console</h2>
25 25
<div class="innerContent">
26
+ <h2 class="articleSubheadline">April 2026</h2>
27
+ <ul class="bulletList">
28
+ <li>Tables with multi-selection support now have a select/de-select all checkbox in the table header.
29
+ This comes with general improvements in table selection/de-selection handling.</li>
30
+ </ul>
26 31
<h2 class="articleSubheadline">February 2026</h2>
27 32
<ul class="bulletList">
28 33
<li>Implemented an automated procedure for upgrading the ARCHIVE server. This is now available
java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/RefreshableMultiSelectionModel.java
... ...
@@ -99,7 +99,6 @@ public class RefreshableMultiSelectionModel<T> extends MultiSelectionModelWithSe
99 99
}
100 100
if (wasSelectedBefore != null) {
101 101
super.setSelected(wasSelectedBefore, false);
102
- isSelected(item); // triggers the deleting of the wasSelectedBefore element in super class
103 102
super.setSelected(item, selected);
104 103
} else {
105 104
super.setSelected(item, selected);
java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/SelectionCheckboxColumn.java
... ...
@@ -1,6 +1,7 @@
1 1
package com.sap.sse.gwt.client.celltable;
2 2
3 3
import com.google.gwt.cell.client.Cell.Context;
4
+import com.google.gwt.cell.client.CheckboxCell;
4 5
import com.google.gwt.dom.client.BrowserEvents;
5 6
import com.google.gwt.dom.client.NativeEvent;
6 7
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
... ...
@@ -15,6 +16,7 @@ import com.google.gwt.view.client.DefaultSelectionEventManager.SelectAction;
15 16
import com.google.gwt.view.client.ListDataProvider;
16 17
import com.sap.sse.common.InvertibleComparator;
17 18
import com.sap.sse.common.SortingOrder;
19
+import com.sap.sse.common.Util;
18 20
import com.sap.sse.common.impl.InvertibleComparatorAdapter;
19 21
import com.sap.sse.gwt.client.controls.BetterCheckboxCell;
20 22
... ...
@@ -22,26 +24,37 @@ import com.sap.sse.gwt.client.controls.BetterCheckboxCell;
22 24
* A column to be used in a {@link CellTable} that controls and reflects a table's selection model using stylable
23 25
* "check boxes". To make things work, clients have to also call
24 26
* {@link CellTable#setSelectionModel(com.google.gwt.view.client.SelectionModel, com.google.gwt.view.client.CellPreviewEvent.Handler)}
25
- * with the result of this columns {@link #getSelectionModel} as the first and the result of the
27
+ * with the result of this column's {@link #getSelectionModel()} as the first and the result of the
26 28
* {@link #getSelectionManager()} method as second argument. This will ensure that the event handling and selection
27 29
* updates work properly.
28 30
* <p>
29
- *
30 31
* Clients should use the column's own {@link #getSelectionModel() RefreshableMultiSelectionModel}. This will ensure that
31 32
* the {@link SelectionCheckboxColumn} will be refreshed correctly when the selection changes or the
32 33
* {@link ListDataProvider} has new elements. Clients should also ensure that the {@link Flushable} and the
33 34
* {@link ListDataProvider} are not <code>null</code>; otherwise the {@link RefreshableMultiSelectionModel selection model}
34
- * won�t work correctly. The {@link Flushable} interface is used to ensure that the selection state is displayed
35
+ * won't work correctly. The {@link Flushable} interface is used to ensure that the selection state is displayed
35 36
* correctly by {@link SelectionCheckboxColumn}. To ensure this, the {@link Flushable#flush()} method is called after
36 37
* every selection state change.
37 38
* <p>
38 39
* The column uses the {@link BetterCheckboxCell} cell to implement the display properties. Three CSS styles can be used
39 40
* to parameterize this column: one for the <code>&lt;td&gt;</code> element rendering the cell, and two for the
40 41
* <code>&lt;div&gt;</code> element representing a selected or deselected element.
41
- *
42
+ * <p>
43
+ * Column header: There are two ways to provide a header for this column:
44
+ * <ol>
45
+ * <li>{@link #createHeader()} returns a live select-all/deselect-all {@link Header} backed by a {@link CheckboxCell}.
46
+ * It ticks when all rows are selected and unticks as soon as all rows are deselected. Clicking it selects or deselects
47
+ * all rows in the {@link ListDataProvider}. This header must be passed explicitly to the table's
48
+ * {@code addColumn(Column, Header)} or {@code insertColumn(int, Column, Header, ...)} call — it is not
49
+ * returned by {@link #getHeader()}.</li>
50
+ * <li>{@link #getHeader()} returns a static checkmark (&#x2713;) header. It serves as a fallback default if no
51
+ * select-all behavior is needed, but is not currently used by any caller — {@link #createHeader()} is the
52
+ * preferred choice for all existing usages.</li>
53
+ * </ol>
54
+ *
42 55
* @author Axel Uhl (D043530)
43 56
* @author Lukas Furmanek
44
- *
57
+ *
45 58
* @param <T>
46 59
*/
47 60
public class SelectionCheckboxColumn<T> extends AbstractSortableColumnWithMinMax<T, Boolean> {
... ...
@@ -50,7 +63,6 @@ public class SelectionCheckboxColumn<T> extends AbstractSortableColumnWithMinMax
50 63
private final EventTranslator<T> selectionEventTranslator;
51 64
private final RefreshableMultiSelectionModel<T> selectionModel;
52 65
private final ListDataProvider<T> listDataProvider;
53
- private final Flushable display;
54 66
55 67
/**
56 68
* @param selectedCheckboxCSSClass
... ...
@@ -63,26 +75,67 @@ public class SelectionCheckboxColumn<T> extends AbstractSortableColumnWithMinMax
63 75
* {@link EntityIdentityComparator} to create a {@link RefreshableMultiSelectionModel}
64 76
* @param listDataProvider
65 77
* {@link ListDataProvider} to create a {@link RefreshableMultiSelectionModel}
66
- * @param display
67
- * {@link Flushable} to redraw the selected elements on the display
68 78
*/
69 79
public SelectionCheckboxColumn(String selectedCheckboxCSSClass, String deselectedCheckboxCSSClass,
70 80
String checkboxColumnCellCSSClass, EntityIdentityComparator<T> entityIdentityComparator,
71
- ListDataProvider<T> listDataProvider, Flushable display) {
81
+ ListDataProvider<T> listDataProvider) {
72 82
this(new BetterCheckboxCell(selectedCheckboxCSSClass, deselectedCheckboxCSSClass), checkboxColumnCellCSSClass,
73
- entityIdentityComparator, listDataProvider, display);
83
+ entityIdentityComparator, listDataProvider);
74 84
}
75 85
76 86
private SelectionCheckboxColumn(BetterCheckboxCell checkboxCell, String checkboxColumnCellCSSClass,
77
- EntityIdentityComparator<T> entityIdentityComparator, ListDataProvider<T> listDataProvider,
78
- Flushable display) {
87
+ EntityIdentityComparator<T> entityIdentityComparator, ListDataProvider<T> listDataProvider) {
79 88
super(checkboxCell, SortingOrder.DESCENDING);
80
- this.display = display;
81 89
this.listDataProvider = listDataProvider;
82 90
this.cell = checkboxCell;
83 91
this.checkboxColumnCellCSSClass = checkboxColumnCellCSSClass;
84 92
this.selectionEventTranslator = createSelectionEventTranslator();
85
- this.selectionModel = createSelectionModel(entityIdentityComparator);
93
+ final EntityIdentityComparator<T> entityIdentityComparator1 = entityIdentityComparator;
94
+ this.selectionModel = new RefreshableMultiSelectionModel<T>(entityIdentityComparator1, listDataProvider);
95
+ this.setSortable(false);
96
+ }
97
+
98
+ /**
99
+ * Creates and returns a live select-all/deselect-all {@link Header} for use as this column's header. The returned
100
+ * header displays a {@link CheckboxCell} that is ticked when all rows in the {@link ListDataProvider} are selected,
101
+ * and unticked whenever there is no selection. Clicking the header checkbox selects or
102
+ * deselects all rows accordingly.
103
+ * <p>
104
+ * The returned header must be passed explicitly to the table when adding this column, e.g.:
105
+ * <pre>
106
+ * final Header&lt;Boolean&gt; selectAllHeader = checkboxColumn.createHeader();
107
+ * table.addColumn(checkboxColumn, selectAllHeader);
108
+ * </pre>
109
+ * This method should be called exactly once per column instance, as each call registers a new selection change
110
+ * handler on the underlying selection model.
111
+ *
112
+ * @return a {@link Header} with select-all/deselect-all behavior; distinct from the static checkmark returned by
113
+ * {@link #getHeader()}
114
+ */
115
+ public Header<Boolean> createHeader() {
116
+ final CheckboxCell selectAllCell = new CheckboxCell();
117
+ final Header<Boolean> selectAllHeader = new Header<Boolean>(selectAllCell) {
118
+ @Override
119
+ public Boolean getValue() {
120
+ return false;
121
+ }
122
+ };
123
+ selectAllHeader.setUpdater(value -> {
124
+ for (final T mp : listDataProvider.getList()) {
125
+ if (selectionModel != null) {
126
+ selectionModel.setSelected(mp, value);
127
+ }
128
+ }
129
+ });
130
+ selectionModel.addSelectionChangeHandler(e -> {
131
+ final int selected = Util.size(selectionModel.getSelectedElements());
132
+ if (selected == 0) {
133
+ selectAllCell.setViewData(/* key */ selectAllHeader.getValue(), false);
134
+ } else if (selected == listDataProvider.getList().size()) {
135
+ selectAllCell.setViewData(/* key */ selectAllHeader.getValue(), true);
136
+ }
137
+ });
138
+ return selectAllHeader;
86 139
}
87 140
88 141
/**
... ...
@@ -103,31 +156,6 @@ public class SelectionCheckboxColumn<T> extends AbstractSortableColumnWithMinMax
103 156
}
104 157
105 158
/**
106
- * Clients should use the {@link RefreshableMultiSelectionModel} returned by this method for the {@link CellTable}
107
- * to which they add this column. If they do so, the {@link Flushable#flush()} method will be
108
- * triggered correctly for all selection changes. Otherwise, clients or subclasses are responsible to issue the
109
- * necessary calls to {@link Flushable#flush()} after selection changes.
110
- */
111
- private RefreshableMultiSelectionModel<T> createSelectionModel(final EntityIdentityComparator<T> entityIdentityComparator) {
112
- return new RefreshableMultiSelectionModel<T>(entityIdentityComparator, listDataProvider) {
113
- @Override
114
- public void clear() {
115
- super.clear();
116
- display.flush();
117
- }
118
-
119
- @Override
120
- public void setSelected(T item, boolean selected) {
121
- boolean wasSelected = isSelected(item);
122
- super.setSelected(item, selected);
123
- if (wasSelected != selected) {
124
- display.flush();
125
- }
126
- }
127
- };
128
- }
129
-
130
- /**
131 159
* @return a selection event translator that works nicely with
132 160
* {@link DefaultSelectionEventManager#createCustomManager(EventTranslator)} to ensure that this selection
133 161
* checkbox column does what it is supposed to do. Client may want to obtain the custom event manager
java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/celltable/TableWrapper.java
... ...
@@ -6,6 +6,7 @@ import java.util.function.Function;
6 6
import com.google.gwt.core.client.GWT;
7 7
import com.google.gwt.user.cellview.client.Column;
8 8
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
9
+import com.google.gwt.user.cellview.client.Header;
9 10
import com.google.gwt.user.cellview.client.SimplePager;
10 11
import com.google.gwt.user.cellview.client.TextColumn;
11 12
import com.google.gwt.user.client.ui.IsWidget;
... ...
@@ -236,17 +237,17 @@ public abstract class TableWrapper<T, S extends RefreshableSelectionModel<T>, SM
236 237
selectionCheckboxColumn = new SelectionCheckboxColumn<T>(
237 238
getTableRes().cellTableStyle().cellTableCheckboxSelected(),
238 239
getTableRes().cellTableStyle().cellTableCheckboxDeselected(),
239
- getTableRes().cellTableStyle().cellTableCheckboxColumnCell(), entityIdentityComparator, dataProvider,
240
- table);
240
+ getTableRes().cellTableStyle().cellTableCheckboxColumnCell(), entityIdentityComparator, dataProvider);
241 241
columnSortHandler.setComparator(selectionCheckboxColumn, selectionCheckboxColumn.getComparator());
242 242
@SuppressWarnings("unchecked")
243
- S typedSelectionModel = (S) selectionCheckboxColumn.getSelectionModel();
243
+ final S typedSelectionModel = (S) selectionCheckboxColumn.getSelectionModel();
244 244
selectionModel = typedSelectionModel;
245 245
table.setSelectionModel(selectionModel, selectionCheckboxColumn.getSelectionManager());
246
- table.addColumn(selectionCheckboxColumn, selectionCheckboxColumn.getHeader());
246
+ final Header<Boolean> selectAllHeader = selectionCheckboxColumn.createHeader();
247
+ table.addColumn(selectionCheckboxColumn, selectAllHeader);
247 248
} else {
248 249
@SuppressWarnings("unchecked")
249
- S typedSelectionModel = (S) new RefreshableSingleSelectionModel<T>(entityIdentityComparator, dataProvider);
250
+ final S typedSelectionModel = (S) new RefreshableSingleSelectionModel<T>(entityIdentityComparator, dataProvider);
250 251
selectionModel = typedSelectionModel;
251 252
table.setSelectionModel(selectionModel);
252 253
}
java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/BetterCheckboxCell.java
... ...
@@ -46,12 +46,10 @@ public class BetterCheckboxCell extends AbstractEditableCell<Boolean, Boolean> {
46 46
public void onBrowserEvent(Context context, Element parent, Boolean value, NativeEvent event,
47 47
ValueUpdater<Boolean> valueUpdater) {
48 48
String type = event.getType();
49
-
50 49
boolean enterPressed = BrowserEvents.KEYDOWN.equals(type) && event.getKeyCode() == KeyCodes.KEY_ENTER;
51 50
if (BrowserEvents.CLICK.equals(type) || BrowserEvents.CHANGE.equals(type) || enterPressed) {
52 51
InputElement input = parent.getFirstChild().cast();
53 52
Boolean isChecked = input.isChecked();
54
-
55 53
/*
56 54
* Toggle the value if the enter key was pressed and the cell handles selection or doesn't depend on
57 55
* selection. If the cell depends on selection but doesn't handle selection, then ignore the enter key and
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/RoleDefinitionsPanel.java
... ...
@@ -22,6 +22,7 @@ import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
22 22
import com.google.gwt.user.cellview.client.AbstractCellTable;
23 23
import com.google.gwt.user.cellview.client.Column;
24 24
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
25
+import com.google.gwt.user.cellview.client.Header;
25 26
import com.google.gwt.user.cellview.client.TextColumn;
26 27
import com.google.gwt.user.client.Window;
27 28
import com.google.gwt.user.client.rpc.AsyncCallback;
... ...
@@ -164,7 +165,7 @@ public class RoleDefinitionsPanel extends VerticalPanel {
164 165
private FlushableCellTable<RoleDefinitionDTO> createRoleDefinitionsTable(CellTableWithCheckboxResources tableResources) {
165 166
final FlushableCellTable<RoleDefinitionDTO> table = new FlushableCellTable<>(/* pageSize */ 50, tableResources);
166 167
rolesListDataProvider.addDataDisplay(table);
167
- SelectionCheckboxColumn<RoleDefinitionDTO> roleSelectionCheckboxColumn = new SelectionCheckboxColumn<RoleDefinitionDTO>(
168
+ final SelectionCheckboxColumn<RoleDefinitionDTO> roleSelectionCheckboxColumn = new SelectionCheckboxColumn<RoleDefinitionDTO>(
168 169
tableResources.cellTableStyle().cellTableCheckboxSelected(),
169 170
tableResources.cellTableStyle().cellTableCheckboxDeselected(),
170 171
tableResources.cellTableStyle().cellTableCheckboxColumnCell(), new EntityIdentityComparator<RoleDefinitionDTO>() {
... ...
@@ -176,14 +177,13 @@ public class RoleDefinitionsPanel extends VerticalPanel {
176 177
public int hashCode(RoleDefinitionDTO t) {
177 178
return t.getId().hashCode();
178 179
}
179
- }, filterablePanelRoleDefinitions.getAllListDataProvider(), table);
180
- ListHandler<RoleDefinitionDTO> columnSortHandler = new ListHandler<>(rolesListDataProvider.getList());
180
+ }, filterablePanelRoleDefinitions.getAllListDataProvider());
181
+ final ListHandler<RoleDefinitionDTO> columnSortHandler = new ListHandler<>(rolesListDataProvider.getList());
181 182
table.addColumnSortHandler(columnSortHandler);
182
- columnSortHandler.setComparator(roleSelectionCheckboxColumn, roleSelectionCheckboxColumn.getComparator());
183 183
final TextColumn<RoleDefinitionDTO> roleDefinitionUUidColumn = new AbstractSortableTextColumn<RoleDefinitionDTO>(
184 184
role -> role.getId() == null ? "<null>" : role.getId().toString(), columnSortHandler);
185
- TextColumn<RoleDefinitionDTO> roleDefinitionNameColumn = new AbstractSortableTextColumn<RoleDefinitionDTO>(role->role.getName(), columnSortHandler);
186
- Column<RoleDefinitionDTO, SafeHtml> permissionsColumn = new Column<RoleDefinitionDTO, SafeHtml>(new SafeHtmlCell()) {
185
+ final TextColumn<RoleDefinitionDTO> roleDefinitionNameColumn = new AbstractSortableTextColumn<RoleDefinitionDTO>(role->role.getName(), columnSortHandler);
186
+ final Column<RoleDefinitionDTO, SafeHtml> permissionsColumn = new Column<RoleDefinitionDTO, SafeHtml>(new SafeHtmlCell()) {
187 187
@Override
188 188
public SafeHtml getValue(RoleDefinitionDTO role) {
189 189
SafeHtmlBuilder builder = new SafeHtmlBuilder();
... ...
@@ -204,7 +204,6 @@ public class RoleDefinitionsPanel extends VerticalPanel {
204 204
return new NaturalComparator().compare(r1.getPermissions().toString(), r2.getPermissions().toString());
205 205
}
206 206
});
207
-
208 207
final HasPermissions type = SecuredSecurityTypes.ROLE_DEFINITION;
209 208
final AccessControlledActionsColumn<RoleDefinitionDTO, DefaultActionsImagesBarCell> roleActionColumn = create(
210 209
new DefaultActionsImagesBarCell(stringMessages), userService);
... ...
@@ -222,8 +221,8 @@ public class RoleDefinitionsPanel extends VerticalPanel {
222 221
stringMessages);
223 222
roleActionColumn.addAction(DefaultActionsImagesBarCell.ACTION_CHANGE_ACL, DefaultActions.CHANGE_ACL,
224 223
configACL::openDialog);
225
-
226
- table.addColumn(roleSelectionCheckboxColumn, roleSelectionCheckboxColumn.getHeader());
224
+ final Header<Boolean> selectAllHeader = roleSelectionCheckboxColumn.createHeader();
225
+ table.addColumn(roleSelectionCheckboxColumn, selectAllHeader);
227 226
table.addColumn(roleDefinitionNameColumn, stringMessages.name());
228 227
table.addColumn(permissionsColumn, stringMessages.permissions());
229 228
SecuredDTOOwnerColumn.configureOwnerColumns(table, columnSortHandler, stringMessages);