Merge branch 'bug3902'

This commit is contained in:
Axel Uhl committed 2016-09-19 17:04:27 +02:00
commit 4c8a0ce269
18 files changed
+199 -76

No files matched your search

@@ -221,8 +221,8 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
public DBCollection getGPSFixCollection() {
DBCollection gpsFixCollection = database.getCollection(CollectionNames.GPS_FIXES.name());
DBObject index = new BasicDBObject();
index.put(FieldNames.DEVICE_ID.name(), null);
index.put(FieldNames.TIME_AS_MILLIS.name(), null);
index.put(FieldNames.DEVICE_ID.name()+"."+FieldNames.DEVICE_TYPE_SPECIFIC_ID.name(), 1);
index.put(FieldNames.GPSFIX.name()+"."+FieldNames.TIME_AS_MILLIS.name(), 1);
gpsFixCollection.createIndex(index);
return gpsFixCollection;
}
@@ -81,7 +81,7 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
return (TypeBasedServiceFinder) serviceFinderFactory.createServiceFinder(FixMongoHandler.class);
}
public <T extends Timed> T loadFix(DBObject object)
private <T extends Timed> T loadFix(DBObject object)
throws TransformationException, NoCorrespondingServiceRegisteredException {
String type = (String) object.get(FieldNames.GPSFIX_TYPE.name());
DBObject fixObject = (DBObject) object.get(FieldNames.GPSFIX.name());
@@ -260,4 +260,24 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
private <FixT extends Timed> FixMongoHandler<FixT> findService(String type) {
return (FixMongoHandler<FixT>) fixServiceFinder.findService(type);
}
@Override
public <FixT extends Timed> Map<DeviceIdentifier, FixT> getLastFix(Iterable<DeviceIdentifier> forDevices)
throws TransformationException, NoCorrespondingServiceRegisteredException {
Map<DeviceIdentifier, FixT> result = new HashMap<>();
for (final DeviceIdentifier deviceIdentifier : forDevices) {
final DBObject deviceQuery = new BasicDBObject(FieldNames.DEVICE_ID.name()+"."+FieldNames.DEVICE_TYPE_SPECIFIC_ID.name(),
deviceIdentifier.getStringRepresentation());
final DBObject orderBy = new BasicDBObject(FieldNames.GPSFIX.name()+"."+FieldNames.TIME_AS_MILLIS.name(), -1);
DBCursor lastFixForDeviceCursor = fixesCollection.find(deviceQuery).sort(orderBy).limit(1);
if (lastFixForDeviceCursor.hasNext()) {
final DBObject lastFixForDeviceDbObject = lastFixForDeviceCursor.next();
final Timed lastFixForDevice = loadFix(lastFixForDeviceDbObject);
@SuppressWarnings("unchecked")
final FixT lastFixForDeviceTyped = (FixT) lastFixForDevice;
result.put(deviceIdentifier, lastFixForDeviceTyped);
}
}
return result;
}
}
@@ -5,6 +5,7 @@ import static org.mockito.Mockito.mock;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
@@ -38,6 +39,7 @@ import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.Timed;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.impl.TimeRangeImpl;
@@ -157,4 +159,34 @@ public class TrackedRaceLoadsFixesTest extends AbstractGPSFixStoreTest {
assertEquals(2, store.getNumberOfFixes(device));
assertEquals(TimeRangeImpl.create(100, 200), store.getTimeRangeCoveredByFixes(device));
}
@Test
public void testFindLatestFixForMapping() throws TransformationException, NoCorrespondingServiceRegisteredException {
store.storeFix(device, createFix(100, 10, 20, 30, 40));
store.storeFix(device, createFix(1100, 10, 20, 30, 40));
store.storeFix(device, createFix(2100, 10, 20, 30, 40));
final Map<DeviceIdentifier, Timed> lastFixes = store.getLastFix(Collections.singleton(device));
assertEquals(1, lastFixes.size());
Timed lastFix = lastFixes.get(device);
assertEquals(2100, lastFix.getTimePoint().asMillis());
store.storeFix(device, createFix(2000, 10, 20, 30, 40));
final Map<DeviceIdentifier, Timed> lastFixes2 = store.getLastFix(Collections.singleton(device));
assertEquals(1, lastFixes2.size());
Timed lastFix2 = lastFixes2.get(device);
assertEquals(2100, lastFix2.getTimePoint().asMillis());
store.storeFix(device, createFix(2200, 10, 20, 30, 40));
final Map<DeviceIdentifier, Timed> lastFixes3 = store.getLastFix(Collections.singleton(device));
assertEquals(1, lastFixes3.size());
Timed lastFix3 = lastFixes3.get(device);
assertEquals(2200, lastFix3.getTimePoint().asMillis());
final DeviceIdentifier device2 = new SmartphoneImeiIdentifier("b");
store.storeFix(device2, createFix(1200, 10, 20, 30, 40));
store.storeFix(device2, createFix(1100, 10, 20, 30, 40));
final Map<DeviceIdentifier, Timed> lastFixes4 = store.getLastFix(Arrays.asList(device, device2));
assertEquals(2, lastFixes4.size());
Timed lastFix4 = lastFixes4.get(device);
assertEquals(2200, lastFix4.getTimePoint().asMillis());
Timed lastFixDevice2 = lastFixes4.get(device2);
assertEquals(1200, lastFixDevice2.getTimePoint().asMillis());
}
}
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.racelog.tracking;
import java.util.Map;
import java.util.function.Consumer;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
@@ -47,4 +48,9 @@ public enum EmptySensorFixStore implements SensorFixStore {
@Override
public <FixT extends Timed> void storeFixes(DeviceIdentifier device, Iterable<FixT> fixes) {
}
@Override
public <FixT extends Timed> Map<DeviceIdentifier, FixT> getLastFix(Iterable<DeviceIdentifier> forDevices) {
return null;
}
}
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.racelog.tracking;
import java.util.Map;
import java.util.function.Consumer;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
@@ -68,4 +69,6 @@ public interface SensorFixStore {
NoCorrespondingServiceRegisteredException;
long getNumberOfFixes(DeviceIdentifier device) throws TransformationException, NoCorrespondingServiceRegisteredException;
<FixT extends Timed> Map<DeviceIdentifier, FixT> getLastFix(Iterable<DeviceIdentifier> forDevices) throws TransformationException, NoCorrespondingServiceRegisteredException;
}
@@ -88,7 +88,7 @@ public abstract class AbstractCompetitorRegistrationsDialog extends DataEntryDia
allCompetitorsTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */
true, /* enablePager */true);
registeredCompetitorsTable = new CompetitorTableWrapper<>(sailingService, stringMessages, errorReporter, /* multiSelection */
true, /* enablePager */true);
true, /* enablePager */false);
allCompetitorsPanel.add(allCompetitorsTable);
registeredCompetitorsPanel.add(registeredCompetitorsTable);
VerticalPanel movePanel = new VerticalPanel();
@@ -35,7 +35,7 @@ import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel;
public class CompetitorTableWrapper<S extends RefreshableSelectionModel<CompetitorDTO>> extends TableWrapper<CompetitorDTO, S> {
private final LabeledAbstractFilterablePanel<CompetitorDTO> filterField;
public CompetitorTableWrapper(SailingServiceAsync sailingService, StringMessages stringMessages,ErrorReporter errorReporter,
public CompetitorTableWrapper(SailingServiceAsync sailingService, StringMessages stringMessages, ErrorReporter errorReporter,
boolean multiSelection, boolean enablePager) {
super(sailingService, stringMessages, errorReporter, multiSelection, enablePager,
new EntityIdentityComparator<CompetitorDTO>() {
@@ -244,7 +244,6 @@ public class CompetitorTableWrapper<S extends RefreshableSelectionModel<Competit
allowUpdate(Collections.singleton(competitor));
}
}
});
mainPanel.insert(filterField, 0);
@@ -1,15 +1,10 @@
package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
@@ -21,28 +16,12 @@ import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
public class DeviceMappingTableWrapper extends TableWrapper<DeviceMappingDTO, RefreshableSingleSelectionModel<DeviceMappingDTO>> {
static interface FilterChangedHandler {
void onFilterChanged(List<DeviceMappingDTO> filteredList);
}
private List<DeviceMappingDTO> allMappings = new ArrayList<>();
private final CheckBox showPingMappingsCb;
private final List<FilterChangedHandler> filterHandlers = new ArrayList<>();
public DeviceMappingTableWrapper(SailingServiceAsync sailingService, final StringMessages stringMessages,
ErrorReporter errorReporter) {
super(sailingService, stringMessages, errorReporter, /* multiSelection */ false, /* enablePager */ true,
/* leaving EntityIdentityComparator null, reducing comparison to equals/hashCode which is well
* defined on DeviceMappingDTO
*/ null);
showPingMappingsCb = new CheckBox(stringMessages.showPingMarkMappings());
showPingMappingsCb.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
filterPingMappings();
}
});
mainPanel.insert(showPingMappingsCb, 0);
table.setWidth("1000px", true);
table.addStyleName("wrap-cols");
ListHandler<DeviceMappingDTO> listHandler = getColumnSortHandler();
@@ -138,37 +117,26 @@ public class DeviceMappingTableWrapper extends TableWrapper<DeviceMappingDTO, Re
});
table.addColumn(toCol, stringMessages.to());
table.addColumnSortHandler(listHandler);
}
private void notifyFilterHandlers() {
for (FilterChangedHandler handler : filterHandlers) {
handler.onFilterChanged(getDataProvider().getList());
}
}
private void filterPingMappings() {
boolean show = showPingMappingsCb.getValue();
getDataProvider().getList().clear();
for (DeviceMappingDTO mapping : allMappings) {
if (show || ! "PING".equals(mapping.deviceIdentifier.deviceType)) {
getDataProvider().getList().add(mapping);
TextColumn<DeviceMappingDTO> lastFixCol = new TextColumn<DeviceMappingDTO>() {
@Override
public String getValue(DeviceMappingDTO mapping) {
return mapping.lastFix==null?"":DateAndTimeFormatterUtil.formatDateAndTime(mapping.lastFix.asDate());
}
}
notifyFilterHandlers();
}
public void refresh(List<DeviceMappingDTO> mappings) {
allMappings = mappings;
filterPingMappings();
};
lastFixCol.setSortable(true);
listHandler.setComparator(lastFixCol, new Comparator<DeviceMappingDTO>() {
@Override
public int compare(DeviceMappingDTO o1, DeviceMappingDTO o2) {
return Util.compareToWithNull(o1.lastFix, o2.lastFix, /* nullIsLess */ false);
}
});
table.addColumn(lastFixCol, stringMessages.lastFix());
table.addColumnSortHandler(listHandler);
}
@Override
public Widget asWidget() {
return mainPanel;
}
public void addFilterChangedHandler(FilterChangedHandler handler) {
filterHandlers.add(handler);
}
}
@@ -23,22 +23,28 @@ import org.moxieapps.gwt.highcharts.client.plotOptions.SeriesPlotOptions;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.CellPreviewEvent;
import com.sap.sailing.gwt.ui.adminconsole.DeviceMappingTableWrapper.FilterChangedHandler;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
import com.sap.sailing.gwt.ui.shared.DeviceMappingDTO;
import com.sap.sailing.gwt.ui.shared.MarkDTO;
import com.sap.sailing.gwt.ui.shared.TypedDeviceMappingDTO;
import com.sap.sse.common.filter.AbstractListFilter;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel;
public class RegattaLogTrackingDeviceMappingsDialog extends DataEntryDialog<Void> {
private static final int HOURS_TO_EXPAND_FOR_OPEN_END = 2;
@@ -55,6 +61,8 @@ public class RegattaLogTrackingDeviceMappingsDialog extends DataEntryDialog<Void
private final StringMessages stringMessages;
private List<DeviceMappingDTO> mappings = new ArrayList<>();
private DeviceMappingTableWrapper deviceMappingTable;
private LabeledAbstractFilterablePanel<DeviceMappingDTO> filterField;
private CheckBox showPingMappingsCb;
private Point[] data;
@@ -101,13 +109,6 @@ public class RegattaLogTrackingDeviceMappingsDialog extends DataEntryDialog<Void
mainPanel.add(buttonPanel);
deviceMappingTable = new DeviceMappingTableWrapper(sailingService, stringMessages, errorReporter);
deviceMappingTable.addFilterChangedHandler(new FilterChangedHandler() {
@Override
public void onFilterChanged(List<DeviceMappingDTO> filteredList) {
mappings = filteredList;
updateChart();
}
});
deviceMappingTable.getTable().addCellPreviewHandler(new CellPreviewEvent.Handler<DeviceMappingDTO>() {
@Override
public void onCellPreview(CellPreviewEvent<DeviceMappingDTO> event) {
@@ -121,8 +122,8 @@ public class RegattaLogTrackingDeviceMappingsDialog extends DataEntryDialog<Void
actionCol.setFieldUpdater(getActionColFieldUpdater());
deviceMappingTable.getTable().addColumn(actionCol, stringMessages.actions());
final HorizontalPanel deviceMappingPannel = new HorizontalPanel();
mainPanel.add(deviceMappingPannel);
final HorizontalPanel deviceMappingPanel = new HorizontalPanel();
mainPanel.add(deviceMappingPanel);
chart = new Chart()
.setType(Series.Type.COLUMN_RANGE)
@@ -166,10 +167,55 @@ public class RegattaLogTrackingDeviceMappingsDialog extends DataEntryDialog<Void
"<b>" + stringMessages.to() + ":</b> " + DateAndTimeFormatterUtil.formatDateAndTime(mapping.to);
}
}));
deviceMappingPanel.add(chart);
filterField = new LabeledAbstractFilterablePanel<DeviceMappingDTO>(
new Label(stringMessages.filterDeviceMappings()),
new ArrayList<DeviceMappingDTO>(), deviceMappingTable.getTable(), deviceMappingTable.getDataProvider()) {
@Override
public Iterable<String> getSearchableStrings(DeviceMappingDTO t) {
List<String> string = new ArrayList<String>();
string.add(t.mappedTo.toString());
string.add(t.deviceIdentifier.deviceType);
string.add(t.deviceIdentifier.deviceId);
return string;
}
@Override
protected AbstractListFilter<DeviceMappingDTO> getFilterer() {
final AbstractListFilter<DeviceMappingDTO> baseFilterer = super.getFilterer();
return new AbstractListFilter<DeviceMappingDTO>() {
@Override
public Iterable<String> getStrings(DeviceMappingDTO t) {
return baseFilterer.getStrings(t);
}
deviceMappingPannel.add(chart);
deviceMappingPannel.add(deviceMappingTable);
@Override
public Iterable<DeviceMappingDTO> applyFilter(Iterable<String> keywords,
Iterable<DeviceMappingDTO> all) {
final List<DeviceMappingDTO> result = new ArrayList<>();
for (final DeviceMappingDTO dm : super.applyFilter(keywords, all)) {
if (showPingMappingsCb.getValue() || !"PING".equals(dm.deviceIdentifier.deviceType)) {
result.add(dm);
}
}
return result;
}
};
}
};
deviceMappingTable.registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider());
final VerticalPanel vp = new VerticalPanel();
deviceMappingPanel.add(vp);
vp.add(filterField);
showPingMappingsCb = new CheckBox(stringMessages.showPingMarkMappings());
showPingMappingsCb.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
filterField.filter();
}
});
vp.insert(showPingMappingsCb, 0);
vp.add(deviceMappingTable);
return mainPanel;
}
@@ -236,7 +282,7 @@ public class RegattaLogTrackingDeviceMappingsDialog extends DataEntryDialog<Void
public void onSuccess(List<DeviceMappingDTO> result) {
mappings = result;
updateChart();
deviceMappingTable.refresh(mappings);
filterField.updateAll(mappings);
}
@Override
@@ -19,6 +19,7 @@ import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
import com.sap.sse.gwt.client.celltable.RefreshableSelectionModel;
import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
import com.sap.sse.gwt.client.panels.AbstractFilterablePanel;
/**
* Implementing classes still have to add the table to the main panel. The table created and wrapped by this object
@@ -26,6 +27,12 @@ import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
* created by this class's constructor by calling {@link #getColumnSortHandler}.
*/
public abstract class TableWrapper<T, S extends RefreshableSelectionModel<T>> implements IsWidget {
/**
* If the {@code enablePager} constructur argument is set to {@code true} then this many entries are shown
* at most on one page, and users will have to flip through the pages one by one.
*/
private static final int PAGING_SIZE = 100;
protected final FlushableCellTable<T> table;
private S selectionModel;
protected ListDataProvider<T> dataProvider;
@@ -67,7 +74,7 @@ public abstract class TableWrapper<T, S extends RefreshableSelectionModel<T>> im
dataProvider.addDataDisplay(table);
mainPanel.add(table);
if (enablePager) {
table.setPageSize(8);
table.setPageSize(PAGING_SIZE);
SimplePager pager = new SimplePager() {
protected String createText() {
HasRows display = getDisplay();
@@ -109,8 +116,11 @@ public abstract class TableWrapper<T, S extends RefreshableSelectionModel<T>> im
}
/**
* This method allows you to change the data base for the {@link RefreshableSelectionModel}. Therefore a new
* {@link ListDataProvider} is needed.
* This method allows you to change the data base for the {@link RefreshableSelectionModel}. This can, e.g., be useful
* if the table wrapped by this object is filtered through an {@link AbstractFilterablePanel} that has an
* {@link AbstractFilterablePanel#getAll() all} data structure of which the table displays only a subset, but selection
* shall be kept across filtering, based on all records available so that removing the filter will restore the previous
* selection again.
*
* @param dataProvider
* {@link ListDataProvider} as data base for the {@link RefreshableSelectionModel}.
@@ -1737,4 +1737,6 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String contentStrategySimulator();
String strategySimulatorReadMore();
String impressum();
String lastFix();
String filterDeviceMappings();
}
@@ -1709,4 +1709,6 @@ i18nDeSolutionsTrainingText=The STG Training Diary supports the daily documentat
strategySimulator=Strategy Simulator
contentStrategySimulator=Choosing the right strategy can provide great competitive advantage during a race. The Strategy Simulator simplifies determining the best sailing strategy for various wind conditions and water currents. Since wind and current can be changed in the simulation right away, the robustness of a strategy can be easily evaluated even for uncertain weather conditions.
strategySimulatorReadMore=Learn More
impressum=Imprint
impressum=Imprint
lastFix=Last fix
filterDeviceMappings=Filter device mappings
@@ -1694,4 +1694,6 @@ i18nDeSolutionsTrainingText=Das STG Trainingstagebuch unterstützt die tägliche
strategySimulator=Strategie-Simulator
contentStrategySimulator=Während eines Rennens hängt viel von der Wahl der richtigen Strategie ab. Der Strategie-Simulator vereinfacht die Ermittlung der besten Segelstrategie für diverse Wind- und Strömungsbedingungen. Da Wind und Strömung sofort in der Simulation geändert werden können, lässt sich die Robustheit einer Strategie selbst für unsichere Wetterbedingungen problemlos bewerten.
strategySimulatorReadMore=Mehr erfahren
impressum=Impressum
impressum=Impressum
lastFix=Letzter Fix
filterDeviceMappings=Gerätezuordnungen filtern
@@ -452,6 +452,7 @@ import com.sap.sse.common.Duration;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TimeRange;
import com.sap.sse.common.Timed;
import com.sap.sse.common.TypeBasedServiceFinder;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
import com.sap.sse.common.Util;
@@ -5399,6 +5400,13 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
private DeviceMappingDTO convertToDeviceMappingDTO(DeviceMapping<?> mapping) throws TransformationException {
final Map<DeviceIdentifier, Timed> lastFixes = getService().getSensorFixStore().getLastFix(Collections.singleton(mapping.getDevice()));
final Timed lastFix;
if (lastFixes != null && lastFixes.containsKey(mapping.getDevice())) {
lastFix = lastFixes.get(mapping.getDevice());
} else {
lastFix = null;
}
String deviceId = serializeDeviceIdentifier(mapping.getDevice());
Date from = mapping.getTimeRange().from() == null || mapping.getTimeRange().from().equals(TimePoint.BeginningOfTime) ?
null : mapping.getTimeRange().from().asDate();
@@ -5428,7 +5436,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
originalRaceLogEventUUIDs.add((UUID) id);
}
return new DeviceMappingDTO(new DeviceIdentifierDTO(mapping.getDevice().getIdentifierType(),
deviceId), from, to, item, originalRaceLogEventUUIDs);
deviceId), from, to, item, originalRaceLogEventUUIDs, lastFix==null?null:lastFix.getTimePoint());
}
private List<AbstractLog<?, ?>> getLogHierarchy(String leaderboardName, String raceColumnName,
@@ -6,6 +6,7 @@ import java.util.UUID;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.sap.sailing.domain.common.racelog.tracking.MappableToDevice;
import com.sap.sse.common.TimePoint;
public class DeviceMappingDTO implements IsSerializable {
public DeviceIdentifierDTO deviceIdentifier;
@@ -13,16 +14,26 @@ public class DeviceMappingDTO implements IsSerializable {
public Date to;
public MappableToDevice mappedTo;
public List<UUID> originalRaceLogEventIds;
public TimePoint lastFix;
protected DeviceMappingDTO() {}
/**
* Produces an instance without a last fix
*/
public DeviceMappingDTO(DeviceIdentifierDTO deviceId, Date from, Date to, MappableToDevice mappedTo,
List<UUID> originalRaceLogEventIds) {
this(deviceId, from, to, mappedTo, originalRaceLogEventIds, /* lastFix */ null);
}
public DeviceMappingDTO(DeviceIdentifierDTO deviceId, Date from, Date to, MappableToDevice mappedTo,
List<UUID> originalRaceLogEventIds, TimePoint lastFix) {
this.deviceIdentifier = deviceId;
this.from = from;
this.to = to;
this.mappedTo = mappedTo;
this.originalRaceLogEventIds = originalRaceLogEventIds;
this.lastFix = lastFix;
}
@Override
@@ -52,6 +52,9 @@
means an open-ended interval, and fixes at or after the start of tracking time point will then
continue to be accepted.
</li>
<li>The device mappings dialog now shows the time point of the last fix received from each mapping
and has a convenient filter text box.
</li>
</ul>
<h2 class="articleSubheadline">July 2016</h2>
@@ -25,7 +25,7 @@ import com.sap.sse.gwt.client.celltable.RefreshableSingleSelectionModel;
* sorting criteria currently active (the sorting is the only reason why the {@link CellTable} actually needs to be
* known to an instance of this class). To be initiated the method {@link #getSearchableStrings(Object)} has to be
* defined, which gets those Strings from a <code>T</code> that should be considered when filtering, e.g. name or
* boatClass. The cell table can be sorted independently from the text box (e.g. after adding new objects) by calling
* boatClass. The cell table can be sorted independently from the text box (e.g., after adding new objects) by calling
* the method {@link #updateAll(Iterable)} which then runs the filter over the new selection.<p>
*
* Note that this panel does <em>not</em> contain the table that it filters. With this, this class's clients are free
@@ -42,7 +42,7 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
protected final ListDataProvider<T> filtered;
protected final TextBox textBox;
private final AbstractListFilter<T> filterer = new AbstractListFilter<T>(){
private final AbstractListFilter<T> filterer = new AbstractListFilter<T>() {
@Override
public Iterable<String> getStrings(T t) {
return getSearchableStrings(t);
@@ -154,7 +154,7 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
public void filter() {
filtered.getList().clear();
Util.addAll(filterer.applyFilter(Arrays.asList(getTextBox().getText().split(" ")), all.getList()),
Util.addAll(getFilterer().applyFilter(Arrays.asList(getTextBox().getText().split(" ")), all.getList()),
filtered.getList());
filtered.refresh();
sort();
@@ -217,4 +217,8 @@ public abstract class AbstractFilterablePanel<T> extends HorizontalPanel {
public void setTable(AbstractCellTable<T> table) {
display = table;
}
protected AbstractListFilter<T> getFilterer() {
return filterer;
}
}
@@ -25,6 +25,13 @@ import com.sap.sse.common.filter.AbstractListFilter;
*/
public abstract class LabeledAbstractFilterablePanel<T> extends AbstractFilterablePanel<T> {
/**
* @param display
* Note: when using this with a cell table obtained through {@link TableWrapper#getTable()}, obtain this
* panel's {@link #getAllListDataProvider()} and pass it to the
* {@link TableWrapper#registerSelectionModelOnNewDataProvider} method so that the selection is preserved
* across setting and removing the filter
*/
public LabeledAbstractFilterablePanel(Label label, Iterable<T> all, CellTable<T> display, final ListDataProvider<T> filtered) {
super(all, display, filtered);
insert(label, 0);