Merge branch 'master' into bug4207

This commit is contained in:
Axel Uhl committed 2017-07-10 13:31:36 +02:00
commit 49e655d76f
279 files changed
+6149 -2862

No files matched your search

@@ -9,6 +9,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;
import java.util.logging.Level;
@@ -89,28 +90,43 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
DBObject fixObject = (DBObject) object.get(FieldNames.GPSFIX.name());
return this.<T> findService(type).transformBack(fixObject);
}
@Override
public <FixT extends Timed> boolean loadOldestFix(Consumer<FixT> consumer, DeviceIdentifier device, TimeRange timeRangeToLoad) throws NoCorrespondingServiceRegisteredException, TransformationException {
return loadFixes(consumer, device, timeRangeToLoad.from(), timeRangeToLoad.to(), false, cursor -> cursor.sort(new BasicDBObject(FieldNames.TIME_AS_MILLIS.name(), /* ascending */ 1)).limit(1));
return loadFixes(consumer, device, timeRangeToLoad.from(), timeRangeToLoad.to(), false, () -> false, (d) -> {
}, cursor -> cursor.sort(new BasicDBObject(FieldNames.TIME_AS_MILLIS.name(), /* ascending */ 1)).limit(1));
}
@Override
public <FixT extends Timed> boolean loadYoungestFix(Consumer<FixT> consumer, DeviceIdentifier device, TimeRange timeRangeToLoad) throws NoCorrespondingServiceRegisteredException, TransformationException {
return loadFixes(consumer, device, timeRangeToLoad.from(), timeRangeToLoad.to(), false, cursor -> cursor.sort(new BasicDBObject(FieldNames.TIME_AS_MILLIS.name(), /* descending */ -1)).limit(1));
return loadFixes(consumer, device, timeRangeToLoad.from(), timeRangeToLoad.to(), false, () -> false, (d) -> {
}, cursor -> cursor.sort(new BasicDBObject(FieldNames.TIME_AS_MILLIS.name(), /* descending */ -1)).limit(1));
}
@Override
public <FixT extends Timed> void loadFixes(Consumer<FixT> consumer, DeviceIdentifier device, TimePoint from,
TimePoint to, boolean inclusive) throws NoCorrespondingServiceRegisteredException, TransformationException {
loadFixes(consumer, device, from, to, inclusive, UnaryOperator.identity());
loadFixes(consumer, device, from, to, inclusive, () -> false, (d) -> {
});
}
@Override
public <FixT extends Timed> void loadFixes(Consumer<FixT> consumer, DeviceIdentifier device, TimePoint from,
TimePoint to, boolean inclusive, BooleanSupplier isPreemptiveStopped, Consumer<Double> progressConsumer)
throws NoCorrespondingServiceRegisteredException, TransformationException {
loadFixes(consumer, device, from, to, inclusive, isPreemptiveStopped, progressConsumer,
UnaryOperator.identity());
}
private <FixT extends Timed> boolean loadFixes(Consumer<FixT> consumer, DeviceIdentifier device, TimePoint from,
TimePoint to, boolean inclusive, UnaryOperator<DBCursor> dbCursorCallback) throws NoCorrespondingServiceRegisteredException, TransformationException {
TimePoint to, boolean inclusive, BooleanSupplier isPreemptiveStopped, Consumer<Double> progressConsumer,
UnaryOperator<DBCursor> dbCursorCallback)
throws NoCorrespondingServiceRegisteredException, TransformationException {
progressConsumer.accept(0d);
final TimePoint loadFixesFrom = from == null ? TimePoint.BeginningOfTime : from;
final TimePoint loadFixesTo = to == null ? TimePoint.EndOfTime : to;
Object dbDeviceId = storeDeviceId(deviceServiceFinder, device);
final QueryBuilder queryBuilder = QueryBuilder.start(FieldNames.DEVICE_ID.name()).is(dbDeviceId)
.and(FieldNames.TIME_AS_MILLIS.name());
@@ -118,12 +134,26 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
queryBuilder.greaterThanEquals(loadFixesFrom.asMillis()).and(FieldNames.TIME_AS_MILLIS.name())
.lessThanEquals(loadFixesTo.asMillis());
} else {
queryBuilder.greaterThanEquals(loadFixesFrom.asMillis()).and(FieldNames.TIME_AS_MILLIS.name()).lessThan(loadFixesTo.asMillis());
queryBuilder.greaterThanEquals(loadFixesFrom.asMillis()).and(FieldNames.TIME_AS_MILLIS.name())
.lessThan(loadFixesTo.asMillis());
}
DBObject query = queryBuilder.get();
DBCursor result = dbCursorCallback.apply(fixesCollection.find(query));
boolean fixLoaded = false;
double max = result.size();
// update roughly every percent, but at not more often than every 100th entry
int reportIncrement = (int) Math.max(max / 100, 100);
int current = 0;
for (DBObject fixObject : result) {
current++;
if (current % reportIncrement == 0) {
progressConsumer.accept(current / max);
if (isPreemptiveStopped.getAsBoolean()) {
logger.log(Level.WARNING, "Exiting because of preemtive stop requested " + fixObject);
return fixLoaded;
}
}
try {
@SuppressWarnings("unchecked")
FixT fix = (FixT) loadFix(fixObject);
@@ -137,6 +167,8 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
"Unexpected fix type (" + type + ") encountered when trying to load track for " + device);
}
}
progressConsumer.accept(1d);
return fixLoaded;
}
@@ -150,7 +182,7 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
final Object dbDeviceId = storeDeviceId(deviceServiceFinder, device);
final int nrOfTotalFixes = Util.size(fixes);
final ArrayList<DBObject> dbFixes = new ArrayList<>(nrOfTotalFixes);
TimePoint newFrom = null;
TimePoint newTo = null;
for (FixT fix : fixes) {
@@ -173,14 +205,14 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
final BasicDBObject updateOperation = new BasicDBObject();
final BasicDBObject newMetadata = new BasicDBObject();
newMetadata.put(FieldNames.DEVICE_ID.name(), dbDeviceId);
TimeRange oldTimeRange = getTimeRangeCoveredByFixes(device);
if (oldTimeRange != null) {
newFrom = oldTimeRange.from().before(newFrom) ? oldTimeRange.from() : newFrom;
newTo = oldTimeRange.to().after(newTo) ? oldTimeRange.to() : newTo;
}
final TimeRange newTimeRange = new TimeRangeImpl(newFrom, newTo);
storeTimeRange(newTimeRange, newMetadata, FieldNames.TIMERANGE);
updateOperation.append("$set", newMetadata);
updateOperation.append("$inc", new BasicDBObject(FieldNames.NUM_FIXES.name(), nrOfTotalFixes));
@@ -221,7 +253,7 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
public void removeListener(FixReceivedListener<? extends Timed> listener) {
LockUtil.executeWithWriteLock(listenersLock, () -> Util.removeFromAllValueSets(listeners, listener));
}
@Override
public void removeListener(FixReceivedListener<? extends Timed> listener, DeviceIdentifier device) {
LockUtil.executeWithWriteLock(listenersLock, () -> Util.removeFromValueSet(listeners, device, listener));
@@ -264,12 +296,13 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
/**
* Try to find a service implementing specified type of objects interface using the {@link #fixServiceFinder}.
* <p>
* To support an additional fix type, an implementation of {@link FixMongoHandler} is required, which specifies how to
* transform a fix forth to and back from database. This implementation needs to be
* registered during OSGi bundle activator startup, providing respective type mapping properties.
* To support an additional fix type, an implementation of {@link FixMongoHandler} is required, which specifies how
* to transform a fix forth to and back from database. This implementation needs to be registered during OSGi bundle
* activator startup, providing respective type mapping properties.
* </p>
*
* @param type type object to find service for
* @param type
* type object to find service for
* @return the registered {@link FixMongoHandler} implementation
*
* @see TypeBasedServiceFinder#findService(String)
@@ -282,11 +315,13 @@ public class MongoSensorFixStoreImpl implements MongoSensorFixStore {
@Override
public <FixT extends Timed> Map<DeviceIdentifier, FixT> getLastFix(Iterable<DeviceIdentifier> forDevices)
throws TransformationException, NoCorrespondingServiceRegisteredException {
Map<DeviceIdentifier, FixT> result = new HashMap<>();
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(),
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);
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();
@@ -5,6 +5,7 @@ import static org.junit.Assert.assertEquals;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import org.junit.After;
import org.junit.Before;
@@ -30,10 +31,13 @@ import com.sap.sailing.domain.racelog.tracking.SensorFixStore;
import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServiceFinderFactory;
import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
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;
import junit.framework.Assert;
public class SensorFixStoreTest {
private static final long FIX_TIMESTAMP = 110;
private static final long FIX_TIMESTAMP2 = 120;
@@ -88,32 +92,82 @@ public class SensorFixStoreTest {
newStore();
assertEquals(1, store.getNumberOfFixes(device));
}
@Test
public void testFixDataIsPreservedOnStore() throws Exception {
DoubleVectorFix fix = addBravoFix(device, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
verifySingleFix(fix, 100, 200, device, true);
}
@Test
public void testProgressSingle() throws Exception {
testProgress(1);
}
@Test
public void testFew() throws Exception {
testProgress(80);
}
@Test
public void testLittle() throws Exception {
testProgress(109);
}
@Test
public void testProgressMay() throws Exception {
testProgress(2000);
}
private void testProgress(int fixes) throws NoCorrespondingServiceRegisteredException, TransformationException {
for (int i = 0; i < fixes; i++) {
addBravoFix(device, FIX_TIMESTAMP + 1, FIX_RIDE_HEIGHT);
}
List<Double> progressData = new ArrayList<>();
store.loadFixes((fix) -> {
}, device, new MillisecondsTimePoint(FIX_TIMESTAMP - 1), new MillisecondsTimePoint(FIX_TIMESTAMP + fixes + 1),
true, () -> false, new Consumer<Double>() {
@Override
public void accept(Double progress) {
progressData.add(progress);
}
});
// validate monotone rising
// validate between 0 and 1 (inclusive)
Double last = 0.0;
for (Double progress : progressData) {
Assert.assertTrue(progress <= 1);
Assert.assertTrue(progress >= 0);
Assert.assertTrue(progress >= last);
last = progress;
}
//validate that 0-100 updates do exist
Assert.assertFalse(progressData.isEmpty());
Assert.assertTrue(progressData.size() <= 100);
}
@Test
public void testFixWithinExclusiveBoundsIsLoaded() throws Exception {
DoubleVectorFix fix = addBravoFix(device, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
verifySingleFix(fix, FIX_TIMESTAMP - 1, FIX_TIMESTAMP + 1, device, false);
}
@Test
public void testFixOnInclusiveLowerBoundIsLoaded() throws Exception {
DoubleVectorFix fix = addBravoFix(device, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
verifySingleFix(fix, FIX_TIMESTAMP, FIX_TIMESTAMP + 1, device, true);
}
@Test
public void testFixOnInclusiveUpperBoundIsLoaded() throws Exception {
DoubleVectorFix fix = addBravoFix(device, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
verifySingleFix(fix, FIX_TIMESTAMP-1, FIX_TIMESTAMP, device, true);
verifySingleFix(fix, FIX_TIMESTAMP - 1, FIX_TIMESTAMP, device, true);
}
@Test
public void testFixesOnExclusiveEndBoundsArentLoaded() throws Exception {
DoubleVectorFix fix = addBravoFix(device, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
@@ -136,16 +190,16 @@ public class SensorFixStoreTest {
addBravoFix(device, FIX_TIMESTAMP + 5, FIX_RIDE_HEIGHT2);
verifyOldestFix(oldestFix, FIX_TIMESTAMP, FIX_TIMESTAMP2, device);
}
@Test
public void testSingleListenerIsNotified() throws Exception {
FixReceivedListener<DoubleVectorFix> listener = mockFixReceivedListener();
store.addListener(listener, device);
DoubleVectorFix doubleVectorFix = addBravoFix(device, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
Mockito.verify(listener, Mockito.times(1)).fixReceived(device, doubleVectorFix);
}
@Test
public void testMultipleListenersForSameDeviceAreNotified() throws Exception {
FixReceivedListener<DoubleVectorFix> listener1 = mockFixReceivedListener();
@@ -153,20 +207,20 @@ public class SensorFixStoreTest {
store.addListener(listener1, device);
store.addListener(listener2, device);
DoubleVectorFix doubleVectorFix = addBravoFix(device, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
Mockito.verify(listener1, Mockito.times(1)).fixReceived(device, doubleVectorFix);
Mockito.verify(listener2, Mockito.times(1)).fixReceived(device, doubleVectorFix);
}
@Test
public void testListenerForNonMatchingDeviceIsNotNotified() throws Exception {
FixReceivedListener<DoubleVectorFix> listener = mockFixReceivedListener();
store.addListener(listener, device);
addBravoFix(device2, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
Mockito.verifyZeroInteractions(listener);
}
@Test
public void testOnlyListenerForMatchingDeviceIsNotified() throws Exception {
FixReceivedListener<DoubleVectorFix> listener1 = mockFixReceivedListener();
@@ -174,23 +228,23 @@ public class SensorFixStoreTest {
store.addListener(listener1, device);
store.addListener(listener2, device2);
DoubleVectorFix doubleVectorFix = addBravoFix(device, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
Mockito.verify(listener1, Mockito.times(1)).fixReceived(device, doubleVectorFix);
Mockito.verifyZeroInteractions(listener2);
}
@Test
public void testListenerForMatchingDeviceIsNotifiedMultipleTimes() throws Exception {
FixReceivedListener<DoubleVectorFix> listener = mockFixReceivedListener();
store.addListener(listener, device);
DoubleVectorFix doubleVectorFix1 = addBravoFix(device, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
DoubleVectorFix doubleVectorFix2 = addBravoFix(device, FIX_TIMESTAMP2, FIX_RIDE_HEIGHT2);
Mockito.verify(listener, Mockito.times(1)).fixReceived(device, doubleVectorFix1);
Mockito.verify(listener, Mockito.times(1)).fixReceived(device, doubleVectorFix2);
Mockito.verifyNoMoreInteractions(listener);
}
@Test
public void testAfterRemoveListenerIsNotNotified() throws Exception {
FixReceivedListener<DoubleVectorFix> listener = mockFixReceivedListener();
@@ -199,7 +253,7 @@ public class SensorFixStoreTest {
addBravoFix(device, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
Mockito.verifyZeroInteractions(listener);
}
@Test
public void testAfterRemoveForDeviceListenerIsNotNotified() throws Exception {
FixReceivedListener<DoubleVectorFix> listener = mockFixReceivedListener();
@@ -208,7 +262,7 @@ public class SensorFixStoreTest {
addBravoFix(device, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
Mockito.verifyZeroInteractions(listener);
}
@Test
public void testAfterRemoveForNonMatchingDeviceListenerIsNotified() throws Exception {
FixReceivedListener<DoubleVectorFix> listener = mockFixReceivedListener();
@@ -217,7 +271,7 @@ public class SensorFixStoreTest {
DoubleVectorFix doubleVectorFix = addBravoFix(device, FIX_TIMESTAMP, FIX_RIDE_HEIGHT);
Mockito.verify(listener, Mockito.times(1)).fixReceived(device, doubleVectorFix);
}
@Test
public void testListenerForMultipleDevicesIsNotifiedMultipleTimes() throws Exception {
FixReceivedListener<DoubleVectorFix> listener = mockFixReceivedListener();
@@ -229,7 +283,7 @@ public class SensorFixStoreTest {
Mockito.verify(listener, Mockito.times(1)).fixReceived(device2, doubleVectorFix2);
Mockito.verifyNoMoreInteractions(listener);
}
@Test
public void testAfterRemoveListenerForMultipleDevicesIsNotNotified() throws Exception {
FixReceivedListener<DoubleVectorFix> listener = mockFixReceivedListener();
@@ -240,7 +294,7 @@ public class SensorFixStoreTest {
addBravoFix(device2, FIX_TIMESTAMP2, FIX_RIDE_HEIGHT2);
Mockito.verifyZeroInteractions(listener);
}
@Test
public void testAfterRemoveListenerForOneDevicesIsNotifiedForOtherDevice() throws Exception {
FixReceivedListener<DoubleVectorFix> listener = mockFixReceivedListener();
@@ -252,7 +306,7 @@ public class SensorFixStoreTest {
Mockito.verify(listener, Mockito.times(1)).fixReceived(device2, doubleVectorFix2);
Mockito.verifyNoMoreInteractions(listener);
}
@Test
public void testAfterRemoveListenerOtherListenerIsNotified() throws Exception {
FixReceivedListener<DoubleVectorFix> listener1 = mockFixReceivedListener();
@@ -265,7 +319,7 @@ public class SensorFixStoreTest {
Mockito.verifyNoMoreInteractions(listener2);
Mockito.verifyZeroInteractions(listener1);
}
@Test
public void testAfterRemoveForDeviceListenerOtherListenerIsNotified() throws Exception {
FixReceivedListener<DoubleVectorFix> listener1 = mockFixReceivedListener();
@@ -278,7 +332,7 @@ public class SensorFixStoreTest {
Mockito.verifyNoMoreInteractions(listener2);
Mockito.verifyZeroInteractions(listener1);
}
@SuppressWarnings("unchecked")
private FixReceivedListener<DoubleVectorFix> mockFixReceivedListener() {
FixReceivedListener<DoubleVectorFix> listener = Mockito.mock(FixReceivedListener.class);
@@ -2,11 +2,14 @@ package com.sap.sailing.domain.racelogtracking.impl.fixtracker;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -273,10 +276,11 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
* special handling.
*/
private void loadFixesForNewlyCoveredTimeRanges(WithID item,
Map<RegattaLogDeviceMappingEvent<WithID>, MultiTimeRange> newlyCoveredTimeRanges) {
Map<RegattaLogDeviceMappingEvent<WithID>, MultiTimeRange> newlyCoveredTimeRanges,
Consumer<Double> progressConsumer, BooleanSupplier stopCallback) {
if (trackedRace.getStartOfTracking() != null) {
TimeRange trackingTimeRange = getTrackingTimeRange();
loadFixesInTrackingTimeRange(newlyCoveredTimeRanges, trackingTimeRange);
loadFixesInTrackingTimeRange(newlyCoveredTimeRanges, trackingTimeRange, progressConsumer, stopCallback);
if (item instanceof Mark) {
Mark mark = (Mark) item;
DynamicGPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(mark);
@@ -300,19 +304,42 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
*/
private void loadFixesInTrackingTimeRange(
Map<RegattaLogDeviceMappingEvent<WithID>, MultiTimeRange> newlyCoveredTimeRanges,
TimeRange trackingTimeRange) {
newlyCoveredTimeRanges.forEach((event, timeRange) -> {
loadFixesForMultiTimeRange(timeRange.intersection(trackingTimeRange), event);
});
TimeRange trackingTimeRange, Consumer<Double> progressConsumer, BooleanSupplier stopCallback) {
final MultiJobProgressUpdater progressUpdater = new MultiJobProgressUpdater(newlyCoveredTimeRanges.size());
int currentJobNr = 0;
for (Entry<RegattaLogDeviceMappingEvent<WithID>, MultiTimeRange> e : newlyCoveredTimeRanges.entrySet()) {
final int jobNr = currentJobNr;
MultiTimeRange timeRange = e.getValue();
RegattaLogDeviceMappingEvent<WithID> event = e.getKey();
loadFixesForMultiTimeRange(timeRange.intersection(trackingTimeRange), event, p -> {
progressUpdater.updateProgress(jobNr, p);
progressConsumer.accept(progressUpdater.getProgress());
}, stopCallback);
currentJobNr++;
}
}
/**
* Loads fixes for the parts of the given {@link MultiTimeRange} using the given mapping event.
*/
private void loadFixesForMultiTimeRange(MultiTimeRange effectiveRangeToLoad,
RegattaLogDeviceMappingEvent<WithID> event) {
RegattaLogDeviceMappingEvent<WithID> event, Consumer<Double> progressConsumer, BooleanSupplier stopCallback) {
if (!effectiveRangeToLoad.isEmpty()) {
effectiveRangeToLoad.forEach(timeRange -> loadFixes(timeRange, event));
int currentJobNr = 0;
final int nrOfJobs = Util.size(effectiveRangeToLoad);
final MultiJobProgressUpdater progressUpdater = new MultiJobProgressUpdater(nrOfJobs);
for (TimeRange timeRange : effectiveRangeToLoad) {
final int jobNr = currentJobNr;
loadFixes(timeRange, event, p -> {
progressUpdater.updateProgress(jobNr, p);
progressConsumer.accept(progressUpdater.getProgress());
}, stopCallback);
currentJobNr++;
}
}
}
@@ -333,7 +360,8 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
/**
* Loads the fixes in the specified {@link TimeRange} using a visitor of the given mapping event.
*/
private void loadFixes(TimeRange timeRangeToLoad, RegattaLogDeviceMappingEvent<? extends WithID> mappingEvent) {
private void loadFixes(TimeRange timeRangeToLoad, RegattaLogDeviceMappingEvent<? extends WithID> mappingEvent,
final Consumer<Double> progressConsumer, final BooleanSupplier stopCallback) {
if (timeRangeToLoad != null && !preemptiveStopRequested.get()) {
mappingEvent.accept(new MappingEventVisitor() {
@Override
@@ -347,7 +375,8 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
// competitor retrieved from the mapping event does not have a track in trackedRace
try {
sensorFixStore.<DoubleVectorFix> loadFixes(fix -> mapper.addFix(track, fix), event.getDevice(),
timeRangeToLoad.from(), timeRangeToLoad.to(), /* toIsInclusive */ false);
timeRangeToLoad.from(), timeRangeToLoad.to(), /* toIsInclusive */ false,
stopCallback, progressConsumer);
} catch (NoCorrespondingServiceRegisteredException | TransformationException e) {
logger.log(Level.WARNING, "Could not load track for competitor: " + event.getMappedTo()
+ "; device: " + event.getDevice());
@@ -364,7 +393,8 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
// competitor retrieved from the mapping event does not have a track in trackedRace
try {
sensorFixStore.<GPSFixMoving> loadFixes(fix -> track.add(fix, true), event.getDevice(),
timeRangeToLoad.from(), timeRangeToLoad.to(), /* toIsInclusive */ false);
timeRangeToLoad.from(), timeRangeToLoad.to(), /* toIsInclusive */ false,
stopCallback, progressConsumer);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not load competitor track " + event.getMappedTo() + "; device "
+ event.getDevice());
@@ -377,7 +407,8 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
DynamicGPSFixTrack<Mark, GPSFix> track = trackedRace.getOrCreateTrack(event.getMappedTo());
try {
sensorFixStore.<GPSFix> loadFixes(fix -> track.add(fix, true), event.getDevice(),
timeRangeToLoad.from(), timeRangeToLoad.to(), /* toIsInclusive */ false);
timeRangeToLoad.from(), timeRangeToLoad.to(), /* toIsInclusive */ false,
stopCallback, progressConsumer);
} catch (TransformationException | NoCorrespondingServiceRegisteredException e) {
logger.log(Level.WARNING, "Could not load mark track " + event.getMappedTo());
}
@@ -524,8 +555,8 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
double progressSum = 0.0;
boolean allFinished = true;
for (AbstractLoadingJob loadingJob : loadingJobs) {
allFinished &= loadingJob.finished;
progressSum += loadingJob.progress;
allFinished &= loadingJob.isFinished();
progressSum += loadingJob.getProgress();
}
if (allFinished) {
loadingJobs.clear();
@@ -563,7 +594,7 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
public boolean isStopRequested() {
return stopRequested.get();
}
private class FixLoaderDeviceMappings extends RegattaLogDeviceMappings<WithID> {
public FixLoaderDeviceMappings(Iterable<RegattaLog> initialRegattaLogs, String raceNameForLock) {
super(initialRegattaLogs, raceNameForLock);
@@ -593,26 +624,60 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
* Subclasses are intended to be run using an executor.
*/
private abstract class AbstractLoadingJob implements Runnable {
double progress = 0;
boolean finished = false;
volatile double currentProgress = 0d;
volatile boolean isFinished = false;
@Override
public final void run() {
progress = 0.5;
updateStatusAndProgressWithErrorHandling();
try {
load();
load(this::updateProgress, preemptiveStopRequested::get);
} finally {
progress = 1.0;
finished = true;
updateStatusAndProgressWithErrorHandling();
isFinished = true;
updateProgress(1d);
}
}
protected abstract void load();
private void updateProgress(double newProgress) {
currentProgress = newProgress;
updateStatusAndProgressWithErrorHandling();
}
public boolean isFinished() {
return isFinished;
}
public double getProgress() {
return currentProgress;
}
protected abstract void load(Consumer<Double> progressConsumer, BooleanSupplier stopCallback);
}
public class MultiJobProgressUpdater {
volatile double[] currentProgress = new double[1];
public MultiJobProgressUpdater(int nrOfJobs) {
super();
currentProgress = new double[nrOfJobs];
}
void updateProgress(int jobNr, double progress) {
if (jobNr >= 0 && jobNr < currentProgress.length) {
currentProgress[jobNr] = progress;
}
}
public double getProgress() {
double progress = 0d;
for (int i = 0; i < currentProgress.length; i++) {
progress += currentProgress[i] / currentProgress.length;
}
return progress;
}
}
/**
* Loads fixes for an item's mappings in a defined tracking {@link TimeRange}. This is used when the tracking
* {@link TimeRange} is extended. No better fixes for {@link Mark} are being loaded because if available, these must
@@ -631,8 +696,8 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
}
@Override
protected void load() {
loadFixesInTrackingTimeRange(newlyCoveredTimeRanges, trackingTimeRange);
protected void load(Consumer<Double> progressConsumer, BooleanSupplier stopCallback) {
loadFixesInTrackingTimeRange(newlyCoveredTimeRanges, trackingTimeRange, progressConsumer, stopCallback);
}
}
@@ -652,8 +717,8 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
}
@Override
protected void load() {
loadFixesForNewlyCoveredTimeRanges(item, newlyCoveredTimeRanges);
protected void load(Consumer<Double> progressConsumer, BooleanSupplier stopCallback) {
loadFixesForNewlyCoveredTimeRanges(item, newlyCoveredTimeRanges, progressConsumer, stopCallback);
}
}
}
@@ -13,30 +13,12 @@ public class ConfirmedFinishPositioningListFinder extends RaceLogAnalyzer<Compet
@Override
protected CompetitorResults performAnalysis() {
return performAnalysis(/* eventToIgnore */ null);
}
private CompetitorResults performAnalysis(RaceLogFinishPositioningConfirmedEvent eventToIgnore) {
for (RaceLogEvent event : getPassEventsDescending()) {
if (event != eventToIgnore && event instanceof RaceLogFinishPositioningConfirmedEvent) {
if (event instanceof RaceLogFinishPositioningConfirmedEvent) {
RaceLogFinishPositioningConfirmedEvent finishPositioningEvent = (RaceLogFinishPositioningConfirmedEvent) event;
return finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons();
}
}
return null;
}
/**
* Same as {@link #analyze()}, only that if {@code event} is found in the log then it is ignored for this
* analysis. This way, the method returns a result as it would have been without {@code event} in the
* {@link RaceLog}. This can be useful, e.g., to determine the result prior to the last update.
*/
public CompetitorResults analyzeIgnoring(RaceLogFinishPositioningConfirmedEvent event) {
log.lockForRead();
try {
return performAnalysis(event);
} finally {
log.unlockAfterRead();
}
}
}
@@ -32,8 +32,8 @@ public interface SettableScoreCorrection extends ScoreCorrection {
void uncorrectScore(Competitor competitor, RaceColumn raceColumn);
/**
* @return <code>null</code> if not set for the competitor, e.g., because no correction was made or an explicit
* {@link MaxPointsReason} was provided for the competitor.
* @return <code>null</code> if not set for the competitor, e.g., because no correction was made or only a
* {@link MaxPointsReason} but no explicit score was provided for the competitor.
*/
Double getExplicitScoreCorrection(Competitor competitor, RaceColumn raceColumn);
@@ -1,6 +1,8 @@
package com.sap.sailing.domain.racelog.impl;
import java.util.List;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.tracking.analyzing.impl.RegattaLogDeviceCompetitorMappingFinder;
@@ -21,10 +23,10 @@ import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
/**
* At the moment, the timerange covered by the fixes for a device, and the number of
* fixes for a device are stored in a metadata collection. Should be changed, see bug 1982.
* At the moment, the timerange covered by the fixes for a device, and the number of fixes for a device are stored in a
* metadata collection. Should be changed, see bug 1982.
*
* @author Fredrik Teschke
*
*/
public class GPSFixStoreImpl implements GPSFixStore {
private final SensorFixStore sensorFixStore;
@@ -34,31 +36,44 @@ public class GPSFixStoreImpl implements GPSFixStore {
}
private <FixT extends GPSFix> void loadTrack(DynamicGPSFixTrack<?, FixT> track, DeviceIdentifier device,
TimePoint from, TimePoint to, boolean toIsInclusive) throws NoCorrespondingServiceRegisteredException,
TransformationException {
sensorFixStore.<FixT>loadFixes(fix->track.add(fix, /* replace */ true), device, from, to, toIsInclusive);
TimePoint from, TimePoint to, boolean toIsInclusive)
throws NoCorrespondingServiceRegisteredException, TransformationException {
loadTrack(track, device, from, to, toIsInclusive, () -> {
return false;
}, (c) -> {
});
}
private <FixT extends GPSFix> void loadTrack(DynamicGPSFixTrack<?, FixT> track, DeviceIdentifier device,
TimePoint from, TimePoint to, boolean toIsInclusive, BooleanSupplier isPreemptiveStopped,
Consumer<Double> progress)
throws NoCorrespondingServiceRegisteredException, TransformationException {
sensorFixStore.<FixT> loadFixes(fix -> track.add(fix, /* replace */ true), device, from, to, toIsInclusive,
isPreemptiveStopped, progress);
}
@Override
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, RegattaLog log, Competitor competitor)
throws NoCorrespondingServiceRegisteredException, TransformationException{
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, RegattaLog log,
Competitor competitor) throws NoCorrespondingServiceRegisteredException, TransformationException {
List<DeviceMappingWithRegattaLogEvent<Competitor>> mappings = new RegattaLogDeviceCompetitorMappingFinder(log)
.analyze().get(competitor);
if (mappings != null) {
for (DeviceMapping<Competitor> mapping : mappings) {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), false /*toIsInclusive*/);
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(),
false /* toIsInclusive */);
}
}
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RegattaLog log, Mark mark)
throws NoCorrespondingServiceRegisteredException, TransformationException{
throws NoCorrespondingServiceRegisteredException, TransformationException {
List<DeviceMappingWithRegattaLogEvent<Mark>> mappings = new RegattaLogDeviceMarkMappingFinder(log).analyze()
.get(mark);
if (mappings != null) {
for (DeviceMapping<Mark> mapping : mappings) {
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), false /*toIsInclusive*/);
loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(),
false /* toIsInclusive */);
}
}
}
@@ -67,17 +82,39 @@ public class GPSFixStoreImpl implements GPSFixStore {
public void storeFix(DeviceIdentifier device, GPSFix fix) {
sensorFixStore.storeFix(device, fix);
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RegattaLog log, Mark mark,
TimePoint start, TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException {
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track,
DeviceMapping<Competitor> mapping, TimePoint start, TimePoint end, BooleanSupplier isPreemptiveStopped,
Consumer<Double> progressReporter)
throws TransformationException, NoCorrespondingServiceRegisteredException {
// loadTrack(track, mapping.getDevice(), mapping.getTimeRange().from(), mapping.getTimeRange().to(), true
// /*inclusive*/);
final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from());
final TimePoint to = Util.getEarliestOfTimePoints(end, mapping.getTimeRange().to());
loadTrack(track, mapping.getDevice(), from, to, true /* inclusive */, isPreemptiveStopped, progressReporter);
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, DeviceMapping<Mark> mapping, TimePoint start,
TimePoint end, BooleanSupplier isPreemptiveStopped, Consumer<Double> progressReport)
throws TransformationException, NoCorrespondingServiceRegisteredException {
final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from());
final TimePoint to = Util.getEarliestOfTimePoints(end, mapping.getTimeRange().to());
loadTrack(track, mapping.getDevice(), from, to, true /* inclusive */, isPreemptiveStopped, progressReport);
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RegattaLog log, Mark mark, TimePoint start,
TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException {
List<DeviceMappingWithRegattaLogEvent<Mark>> mappings = new RegattaLogDeviceMarkMappingFinder(log).analyze()
.get(mark);
if (mappings != null) {
for (DeviceMapping<Mark> mapping : mappings) {
final TimePoint from = Util.getLatestOfTimePoints(start, mapping.getTimeRange().from());
final TimePoint to = Util.getEarliestOfTimePoints(end, mapping.getTimeRange().to());
loadTrack(track, mapping.getDevice(), from, to, false /*toIsInclusive*/);
loadTrack(track, mapping.getDevice(), from, to, false /* toIsInclusive */);
}
}
}
@@ -1,5 +1,8 @@
package com.sap.sailing.domain.racelog.tracking;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Mark;
@@ -7,6 +10,7 @@ import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
@@ -32,4 +36,19 @@ public enum EmptyGPSFixStore implements GPSFixStore {
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RegattaLog log, Mark mark,
TimePoint start, TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException {
}
@Override
public void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track,
DeviceMapping<Competitor> mapping, TimePoint start, TimePoint end, BooleanSupplier isPreemptiveStopped,
Consumer<Double> progressReporter)
throws TransformationException, NoCorrespondingServiceRegisteredException {
}
@Override
public void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, DeviceMapping<Mark> mapping, TimePoint start,
TimePoint end, BooleanSupplier isPreemptiveStopped, Consumer<Double> progressReporter)
throws TransformationException, NoCorrespondingServiceRegisteredException {
}
}
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.racelog.tracking;
import java.util.Map;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
@@ -41,6 +42,13 @@ public enum EmptySensorFixStore implements SensorFixStore {
TransformationException {
}
@Override
public <FixT extends Timed> void loadFixes(Consumer<FixT> consumer, DeviceIdentifier deviceIdentifier,
TimePoint start, TimePoint end, boolean inclusive, BooleanSupplier isPreemptiveStopped,
Consumer<Double> progressReporter)
throws NoCorrespondingServiceRegisteredException, TransformationException {
}
@Override
public <FixT extends Timed> void storeFix(DeviceIdentifier device, FixT fix) {
}
@@ -1,5 +1,8 @@
package com.sap.sailing.domain.racelog.tracking;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceCompetitorMappingEvent;
import com.sap.sailing.domain.abstractlog.regatta.events.RegattaLogDeviceMarkMappingEvent;
@@ -9,6 +12,7 @@ import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
import com.sap.sailing.domain.common.tracking.GPSFix;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.racelogtracking.DeviceIdentifier;
import com.sap.sailing.domain.racelogtracking.DeviceMapping;
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
@@ -41,5 +45,17 @@ public interface GPSFixStore {
void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, RegattaLog log, Mark mark, TimePoint start,
TimePoint end) throws TransformationException, NoCorrespondingServiceRegisteredException;
void loadCompetitorTrack(DynamicGPSFixTrack<Competitor, GPSFixMoving> track, DeviceMapping<Competitor> mapping,
TimePoint start, TimePoint end, BooleanSupplier isPreemptiveStopped, Consumer<Double> progressReporter)
throws TransformationException, NoCorrespondingServiceRegisteredException;
/**
* Load all fixes that correspond to the {@code mapping}.
*/
void loadMarkTrack(DynamicGPSFixTrack<Mark, GPSFix> track, DeviceMapping<Mark> mapping, TimePoint start,
TimePoint end, BooleanSupplier isPreemptiveStopped, Consumer<Double> progressReport)
throws TransformationException,
NoCorrespondingServiceRegisteredException;
void storeFix(DeviceIdentifier device, GPSFix fix) throws TransformationException, NoCorrespondingServiceRegisteredException;
}
@@ -1,6 +1,7 @@
package com.sap.sailing.domain.racelog.tracking;
import java.util.Map;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import com.sap.sailing.domain.common.racelog.tracking.TransformationException;
@@ -37,6 +38,22 @@ public interface SensorFixStore {
<FixT extends Timed> void loadFixes(Consumer<FixT> consumer, DeviceIdentifier deviceIdentifier, TimePoint start, TimePoint end,
boolean toIsInclusive) throws NoCorrespondingServiceRegisteredException,
TransformationException;
/**
* Loads fixes for a device in a given time range.
*
* @param consumer will be called for each loaded fix. Must not be <code>null</code>.
* @param deviceIdentifier the device to load the fixes for. Must not be <code>null</code>.
* @param start the lower bound of the time range to load. If <code>null</code>, fixes are loaded from {@link TimePoint#BeginningOfTime}.
* @param end the upper bound of the time range to load. If <code>null</code>, fixes are loaded to {@link TimePoint#EndOfTime}.
* @param inclusive true if fixes exactly at the bounds of the time range should be loaded, false otherwise.
* @param progressReporter not allowed to be null, can be used to get reports of the approximate loading progress
*/
<FixT extends Timed> void loadFixes(Consumer<FixT> consumer, DeviceIdentifier deviceIdentifier, TimePoint start,
TimePoint end, boolean inclusive, BooleanSupplier isPreemptiveStopped,
Consumer<Double> progressReporter)
throws NoCorrespondingServiceRegisteredException,
TransformationException;
/**
* Saves a single fix for the given device and informs all registered listeners about the new fix.
@@ -58,12 +58,12 @@ public class AutoplayPerspectiveLifecycle extends AbstractPerspectiveLifecycle<A
}
@Override
protected AutoplayPerspectiveOwnSettings extractOwnGlobalSettings(AutoplayPerspectiveOwnSettings settings) {
protected AutoplayPerspectiveOwnSettings extractOwnUserSettings(AutoplayPerspectiveOwnSettings settings) {
return settings;
}
@Override
protected AutoplayPerspectiveOwnSettings extractOwnContextSettings(AutoplayPerspectiveOwnSettings settings) {
protected AutoplayPerspectiveOwnSettings extractOwnDocumentSettings(AutoplayPerspectiveOwnSettings settings) {
return settings;
}
@@ -9,7 +9,7 @@ import com.sap.sailing.gwt.common.client.FullscreenUtil;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.shared.components.AbstractCompositeComponent;
import com.sap.sse.gwt.client.shared.components.Component;
import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
import com.sap.sse.gwt.client.shared.settings.ComponentContext;
import com.sap.sse.security.ui.client.UserService;
public class SAPHeaderComponent extends AbstractCompositeComponent<SAPHeaderComponentSettings> {
@@ -56,7 +56,7 @@ public class SAPHeaderComponent extends AbstractCompositeComponent<SAPHeaderComp
}
@Override
public SAPHeaderComponentSettingsDialogComponent getSettingsDialogComponent() {
public SAPHeaderComponentSettingsDialogComponent getSettingsDialogComponent(SAPHeaderComponentSettings settings) {
return componentLifecycle.getSettingsDialogComponent(settings);
}
@@ -40,12 +40,12 @@ public class SAPHeaderComponentLifecycle implements ComponentLifecycle<SAPHeader
}
@Override
public SAPHeaderComponentSettings extractGlobalSettings(SAPHeaderComponentSettings settings) {
public SAPHeaderComponentSettings extractUserSettings(SAPHeaderComponentSettings settings) {
return createDefaultSettings();
}
@Override
public SAPHeaderComponentSettings extractContextSpecificSettings(SAPHeaderComponentSettings settings) {
public SAPHeaderComponentSettings extractDocumentSettings(SAPHeaderComponentSettings settings) {
return createDefaultSettings();
}
}
@@ -29,9 +29,9 @@ import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.shared.components.Component;
import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent;
import com.sap.sse.gwt.client.shared.perspective.AbstractPerspectiveComposite;
import com.sap.sse.gwt.client.shared.perspective.ComponentContextWithSettingsStorage;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
import com.sap.sse.security.ui.client.UserService;
import com.sap.sse.security.ui.settings.ComponentContextWithSettingsStorage;
/**
* A perspective managing a header with a single leaderboard filling the rest of the screen.
@@ -64,13 +64,13 @@ public class LeaderboardWithHeaderPerspectiveLifecycle extends AbstractPerspecti
}
@Override
protected LeaderboardWithHeaderPerspectiveSettings extractOwnGlobalSettings(
protected LeaderboardWithHeaderPerspectiveSettings extractOwnUserSettings(
LeaderboardWithHeaderPerspectiveSettings settings) {
return settings;
}
@Override
protected LeaderboardWithHeaderPerspectiveSettings extractOwnContextSettings(
protected LeaderboardWithHeaderPerspectiveSettings extractOwnDocumentSettings(
LeaderboardWithHeaderPerspectiveSettings settings) {
return settings;
}
@@ -3,7 +3,6 @@ package com.sap.sailing.gwt.common.theme.component.celltable;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.CellTable.Style;
/**
* {@link ClientBundle} with avoids the standard {@link CellTable} styles.
@@ -11,9 +10,12 @@ import com.google.gwt.user.cellview.client.CellTable.Style;
public interface CleanCellTableResources extends CellTable.Resources {
public static final CleanCellTableResources INSTANCE = GWT.create(CleanCellTableResources.class);
public interface CleanCellTableStyle extends CellTable.Style {
}
@Override
@Source("CleanCellTable.css")
public Style cellTableStyle();
public CleanCellTableStyle cellTableStyle();
}
@@ -0,0 +1,68 @@
.cellTableWidget {
font-size: 1rem;
border: 1px solid #dedede;
border-radius: .333333333333333em;
border-spacing: 0;
border-collapse: separate;
overflow: hidden;
background-color: #f2f2f2;
}
.cellTableWidget>thead>tr {
color: #666;
background-color: #dfdfdf;
border-bottom: 1px solid #dedede;
text-transform: uppercase;
font-weight: 600;
border-radius: .333333333333333em 0 0 .333333333333333em;
}
.cellTableWidget>thead>tr>th {
padding: .666666666666667em .666666666666667em .666666666666667em 1.333333333333333em;
text-align: left;
}
.cellTableCell {
text-align: left;
vertical-align: baseline;
border-bottom: 1px solid #dfdfdf;
white-space: nowrap;
padding: 1.4em .666666666666667em .733333333333333em 1.333333333333333em;
}
.buttonCell {
text-align: right;
vertical-align: middle;
padding-left: 0;
padding-right: .666666666666667em;
padding-top: .666666666666667em;
}
.buttonCell>div>button {
font-size: 1rem;
color: #fff;
font-weight: 700;
background: #008fcc;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -moz-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
-webkit-box-flex: 0;
-webkit-flex: 0;
-moz-box-flex: 0;
-ms-flex: 0;
flex: 0;
text-align: center;
-webkit-box-align: center;
-webkit-align-items: center;
-moz-box-align: center;
-ms-flex-align: center;
align-items: center;
height: 2.666666666666667em;
padding: 0 1em 0 1em;
border-radius: .2em;
position: relative;
border: none;
}
@@ -0,0 +1,22 @@
package com.sap.sailing.gwt.common.theme.component.celltable;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.user.cellview.client.CellTable;
/**
* {@link ClientBundle} with avoids the standard {@link CellTable} styles.
*/
public interface DesignedCellTableResources extends CellTable.Resources {
public static final DesignedCellTableResources INSTANCE = GWT.create(DesignedCellTableResources.class);
public interface DesignedCellTableStyle extends CellTable.Style {
String buttonCell();
}
@Override
@Source({"CleanCellTable.css", "DesignedCellTable.css"})
public DesignedCellTableStyle cellTableStyle();
}
@@ -30,10 +30,6 @@ public class SearchResultItem extends AbstractSearchResultItem {
this.navigator = navigator;
this.item = item;
init(uiBinder.createAndBindUi(this), item);
SearchResultEventInfoDTO event = item.getEvents().iterator().next();
String eventId = String.valueOf(event.getId()), leaderboardName = item.getLeaderboardName(), baseUrl = item.getBaseUrl();
PlaceNavigation<?> regattaNavigation = navigator.getRegattaNavigation(eventId, leaderboardName, baseUrl, item.isOnRemoteServer());
regattaNavigation.configureAnchorElement(resultTitleUi);
}
@Override
@@ -41,10 +37,16 @@ public class SearchResultItem extends AbstractSearchResultItem {
return resultTitleUi;
}
@Override
protected void configureRegattaNavigation(String eventId, String leaderboardName, String baseUrl, boolean isOnRemoteServer) {
navigator.getRegattaNavigation(eventId, leaderboardName, baseUrl, item.isOnRemoteServer()).configureAnchorElement(resultTitleUi);
}
@Override
protected void addEventInfo(SearchResultEventInfoDTO event) {
eventInfoContainerUi.appendChild(new SearchResultItemEventInfo(
navigator, event, item.getBaseUrl(), item.isOnRemoteServer()).getElement());
String eventId = String.valueOf(event.getId());
PlaceNavigation<?> eventNavigation = navigator.getEventNavigation(eventId, item.getBaseUrl(), item.isOnRemoteServer());
eventInfoContainerUi.appendChild(new SearchResultItemEventInfo(event, eventNavigation).getElement());
}
}
@@ -7,7 +7,6 @@ import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.sap.sailing.gwt.home.communication.search.SearchResultEventInfoDTO;
import com.sap.sailing.gwt.home.desktop.app.DesktopPlacesNavigator;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.home.shared.partials.searchresult.AbstractSearchResultItemEventInfo;
@@ -22,12 +21,8 @@ public class SearchResultItemEventInfo extends AbstractSearchResultItemEventInfo
@UiField SpanElement eventVenueUi;
@UiField SpanElement eventDateUi;
SearchResultItemEventInfo(DesktopPlacesNavigator navigator, SearchResultEventInfoDTO event, String baseUrl,
boolean isOnRemoteServer) {
init(uiBinder.createAndBindUi(this), event);
String eventId = String.valueOf(event.getId());
PlaceNavigation<?> eventNavigation = navigator.getEventNavigation(eventId, baseUrl, isOnRemoteServer);
eventNavigation.configureAnchorElement(eventNameUi);
SearchResultItemEventInfo(SearchResultEventInfoDTO event, PlaceNavigation<?> navigation) {
init(uiBinder.createAndBindUi(this), event, navigation);
}
@Override
@@ -44,4 +39,9 @@ public class SearchResultItemEventInfo extends AbstractSearchResultItemEventInfo
protected Element getEventDateUi() {
return eventDateUi;
}
@Override
protected AnchorElement getNavigationUi() {
return eventNameUi;
}
}
@@ -9,7 +9,6 @@ import com.google.gwt.place.shared.Place;
import com.google.gwt.safehtml.shared.SafeUri;
import com.google.gwt.safehtml.shared.UriUtils;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.gwt.common.client.controls.tabbar.TabView;
import com.sap.sailing.gwt.home.communication.SailingDispatchSystem;
@@ -149,28 +148,20 @@ public abstract class AbstractEventActivity<PLACE extends AbstractEventPlace> ex
@Override
public String getRaceViewerURL(SimpleRaceMetadataDTO raceMetadata, String mode) {
RaceIdentifier raceIdentifier = raceMetadata.getRegattaAndRaceIdentifier();
RaceboardContextDefinition raceboardContext = new RaceboardContextDefinition(raceIdentifier.getRegattaName(),
raceIdentifier.getRaceName(), raceMetadata.getLeaderboardName(), raceMetadata.getLeaderboardGroupName(),
null, mode);
RaceBoardPerspectiveOwnSettings perspectiveOwnSettings = RaceBoardPerspectiveOwnSettings
.createDefaultWithCanReplayDuringLiveRaces(true);
;
HashMap<String, Settings> innerSettings = new HashMap<>();
innerSettings.put(RaceMapLifecycle.ID, RaceMapSettings.getDefaultWithShowMapControls(true));
PerspectiveCompositeSettings<RaceBoardPerspectiveOwnSettings> settings = new PerspectiveCompositeSettings<>(
perspectiveOwnSettings, innerSettings);
return EntryPointWithSettingsLinkFactory.createRaceBoardLink(raceboardContext, settings);
return getRaceViewerURL(raceMetadata.getLeaderboardName(), raceMetadata.getLeaderboardGroupName(),
raceMetadata.getRegattaAndRaceIdentifier(), mode);
}
@Override
public String getRaceViewerURL(String leaderboardName, String leaderboardGroupName, RegattaAndRaceIdentifier raceIdentifier) {
return getRaceViewerURL(leaderboardName, leaderboardGroupName, raceIdentifier, null);
}
private String getRaceViewerURL(String leaderboardName, String leaderboardGroupName, RegattaAndRaceIdentifier raceIdentifier, String mode) {
RaceboardContextDefinition raceboardContext = new RaceboardContextDefinition(raceIdentifier.getRegattaName(),
raceIdentifier.getRaceName(), leaderboardName, leaderboardGroupName, null, null);
RaceBoardPerspectiveOwnSettings perspectiveOwnSettings = RaceBoardPerspectiveOwnSettings
.createDefaultWithCanReplayDuringLiveRaces(true);
;
raceIdentifier.getRaceName(), leaderboardName, leaderboardGroupName, UUID.fromString(ctx.getEventId()), mode);
RaceBoardPerspectiveOwnSettings perspectiveOwnSettings = new RaceBoardPerspectiveOwnSettings();
HashMap<String, Settings> innerSettings = new HashMap<>();
innerSettings.put(RaceMapLifecycle.ID, RaceMapSettings.getDefaultWithShowMapControls(true));
PerspectiveCompositeSettings<RaceBoardPerspectiveOwnSettings> settings = new PerspectiveCompositeSettings<>(
@@ -16,7 +16,7 @@ import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.shared.components.Component;
import com.sap.sse.gwt.client.shared.components.SettingsDialog;
import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
import com.sap.sse.gwt.client.shared.settings.ComponentContext;
/**
* A class managing analytical data on the regatta level (like leaderboard, regatta rank, etc.)
@@ -7,20 +7,18 @@ import com.sap.sailing.gwt.home.desktop.places.Consumer;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardPanelLifecycle;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardSettings;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardUrlSettings;
import com.sap.sailing.gwt.settings.client.utils.StorageDefinitionIdFactory;
import com.sap.sailing.gwt.settings.client.utils.StoredSettingsLocationFactory;
import com.sap.sailing.gwt.ui.client.LeaderboardUpdateListener;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
import com.sap.sse.gwt.client.mutationobserver.ElementSizeMutationObserver;
import com.sap.sse.gwt.client.mutationobserver.ElementSizeMutationObserver.DomMutationCallback;
import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
import com.sap.sse.gwt.client.shared.perspective.ComponentContextWithSettingsStorage;
import com.sap.sse.gwt.client.shared.perspective.DefaultOnSettingsLoadedCallback;
import com.sap.sse.gwt.client.shared.perspective.SettingsStorageManager;
import com.sap.sse.gwt.client.shared.settings.ComponentContext;
import com.sap.sse.gwt.client.shared.settings.DefaultOnSettingsLoadedCallback;
import com.sap.sse.gwt.shared.GwtHttpRequestUtils;
import com.sap.sse.security.ui.client.UserService;
import com.sap.sse.security.ui.settings.PlaceBasedUserSettingsStorageManager;
import com.sap.sse.security.ui.settings.StorageDefinitionId;
import com.sap.sse.security.ui.settings.PlaceBasedComponentContextWithSettingsStorage;
import com.sap.sse.security.ui.settings.StoredSettingsLocation;
/**
* An abstract regatta tabView with some shared functions between the leaderboard tab and competitors chart tab
@@ -41,7 +39,7 @@ public abstract class SharedLeaderboardRegattaTabView<T extends AbstractEventReg
final ComponentContext<LeaderboardSettings> componentContext = createLeaderboardComponentContext(leaderboardName, userService,
placeToken);
componentContext.initInitialSettings(new DefaultOnSettingsLoadedCallback<LeaderboardSettings>() {
componentContext.getInitialSettings(new DefaultOnSettingsLoadedCallback<LeaderboardSettings>() {
@Override
public void onSuccess(LeaderboardSettings leaderboardSettings) {
final LeaderboardPanel leaderboardPanel = regattaAnalyticsManager.createLeaderboardPanel(null, componentContext, //
@@ -82,13 +80,11 @@ public abstract class SharedLeaderboardRegattaTabView<T extends AbstractEventReg
protected ComponentContext<LeaderboardSettings> createLeaderboardComponentContext(String leaderboardName, UserService userService,
String placeToken) {
final LeaderboardPanelLifecycle lifeCycle = new LeaderboardPanelLifecycle(null, StringMessages.INSTANCE);
final StorageDefinitionId storageDefinitionId = StorageDefinitionIdFactory.createStorageDefinitionIdForEventRegattaLeaderboard(leaderboardName);
final SettingsStorageManager<LeaderboardSettings> settingsStorageManager = new PlaceBasedUserSettingsStorageManager<>(
userService, storageDefinitionId, placeToken);
final LeaderboardPanelLifecycle lifecycle = new LeaderboardPanelLifecycle(null, StringMessages.INSTANCE);
final StoredSettingsLocation storageDefinition = StoredSettingsLocationFactory.createStoredSettingsLocatorForEventRegattaLeaderboard(leaderboardName);
final ComponentContext<LeaderboardSettings> componentContext = new ComponentContextWithSettingsStorage<>(
lifeCycle, settingsStorageManager);
final ComponentContext<LeaderboardSettings> componentContext = new PlaceBasedComponentContextWithSettingsStorage<>(
lifecycle, userService, storageDefinition, placeToken);
return componentContext;
}
}
@@ -33,7 +33,7 @@ import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardSettings;
import com.sap.sailing.gwt.ui.client.LeaderboardUpdateProvider;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
import com.sap.sse.gwt.client.shared.perspective.DefaultOnSettingsLoadedCallback;
import com.sap.sse.gwt.client.shared.settings.DefaultOnSettingsLoadedCallback;
import com.sap.sse.gwt.dispatch.shared.commands.CollectionResult;
/**
@@ -88,8 +88,7 @@ public class RegattaLeaderboardTabView extends SharedLeaderboardRegattaTabView<R
if (regattaId != null && !regattaId.isEmpty()) {
String leaderboardName = regattaId;
RegattaAnalyticsDataManager regattaAnalyticsManager = currentPresenter.getCtx().getRegattaAnalyticsManager();
LeaderboardPanel leaderboardPanel = regattaAnalyticsManager.getLeaderboardPanel();
LeaderboardPanel leaderboardPanel = regattaAnalyticsManager.getLeaderboardPanel();
final Consumer<LeaderboardPanel> leaderboardConsumer = new Consumer<LeaderboardPanel>() {
@Override
public void consume(LeaderboardPanel leaderboardPanel) {
@@ -113,18 +112,18 @@ public class RegattaLeaderboardTabView extends SharedLeaderboardRegattaTabView<R
}
regattaAnalyticsManager.hideCompetitorChart();
contentArea.setWidget(RegattaLeaderboardTabView.this);
if (leaderboardPanel.getLeaderboard() != null) {
if(leaderboardPanel.getLeaderboard() != null) {
leaderboard.updatedLeaderboard(leaderboardPanel.getLeaderboard());
}
}
};
if (leaderboardPanel == null) {
if(leaderboardPanel == null) {
createSharedLeaderboardPanel(leaderboardName, regattaAnalyticsManager,
currentPresenter.getUserService(), /* FIXME placeToken */ null, leaderboardConsumer);
} else if ( /* FIXME placeToken not empty */ false) {
} else if( /*FIXME placeToken not empty */ false) {
createLeaderboardComponentContext(leaderboardName, currentPresenter.getUserService(),
/* FIXME placeToken */ null)
.initInitialSettings(new DefaultOnSettingsLoadedCallback<LeaderboardSettings>() {
.getInitialSettings(new DefaultOnSettingsLoadedCallback<LeaderboardSettings>() {
@Override
public void onSuccess(LeaderboardSettings settings) {
leaderboardPanel.updateSettings(settings);
@@ -134,7 +133,6 @@ public class RegattaLeaderboardTabView extends SharedLeaderboardRegattaTabView<R
} else {
leaderboardConsumer.consume(leaderboardPanel);
}
} else {
contentArea.setWidget(new Label("No leaderboard specified, cannot proceed to leaderboardpage"));
new com.google.gwt.user.client.Timer() {
@@ -25,7 +25,7 @@ import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.shared.components.Component;
import com.sap.sse.gwt.client.shared.components.SettingsDialog;
import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
import com.sap.sse.gwt.client.shared.settings.ComponentContext;
/**
* A viewer for an overall series leaderboard. Additionally the viewer can render a chart for the series leaderboard and
@@ -7,18 +7,16 @@ import com.sap.sailing.gwt.home.desktop.places.Consumer;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardPanelLifecycle;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardSettings;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardUrlSettings;
import com.sap.sailing.gwt.settings.client.utils.StorageDefinitionIdFactory;
import com.sap.sailing.gwt.settings.client.utils.StoredSettingsLocationFactory;
import com.sap.sailing.gwt.ui.client.LeaderboardUpdateListener;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
import com.sap.sse.gwt.client.shared.perspective.ComponentContextWithSettingsStorage;
import com.sap.sse.gwt.client.shared.perspective.DefaultOnSettingsLoadedCallback;
import com.sap.sse.gwt.client.shared.perspective.SettingsStorageManager;
import com.sap.sse.gwt.client.shared.settings.ComponentContext;
import com.sap.sse.gwt.client.shared.settings.DefaultOnSettingsLoadedCallback;
import com.sap.sse.gwt.shared.GwtHttpRequestUtils;
import com.sap.sse.security.ui.client.UserService;
import com.sap.sse.security.ui.settings.PlaceBasedUserSettingsStorageManager;
import com.sap.sse.security.ui.settings.StorageDefinitionId;
import com.sap.sse.security.ui.settings.PlaceBasedComponentContextWithSettingsStorage;
import com.sap.sse.security.ui.settings.StoredSettingsLocation;
/**
* An abstract series tabView with some shared functions between the overall leaderboard tab and competitors chart tab
@@ -39,7 +37,7 @@ public abstract class SharedLeaderboardEventSeriesTabView<T extends AbstractSeri
final ComponentContext<LeaderboardSettings> componentContext = createLeaderboardComponentContext(leaderboardName, userService,
placeToken);
componentContext.initInitialSettings(new DefaultOnSettingsLoadedCallback<LeaderboardSettings>() {
componentContext.getInitialSettings(new DefaultOnSettingsLoadedCallback<LeaderboardSettings>() {
@Override
public void onSuccess(LeaderboardSettings leaderboardSettings) {
LeaderboardPanel leaderboardPanel = eventSeriesAnalyticsManager.createOverallLeaderboardPanel(null,
@@ -64,13 +62,11 @@ public abstract class SharedLeaderboardEventSeriesTabView<T extends AbstractSeri
protected ComponentContext<LeaderboardSettings> createLeaderboardComponentContext(String leaderboardName, UserService userService,
String placeToken) {
final LeaderboardPanelLifecycle lifeCycle = new LeaderboardPanelLifecycle(null, StringMessages.INSTANCE);
final StorageDefinitionId storageDefinitionId = StorageDefinitionIdFactory.createStorageDefinitionIdForSeriesOverallLeaderboard(leaderboardName);
final SettingsStorageManager<LeaderboardSettings> settingsStorageManager = new PlaceBasedUserSettingsStorageManager<>(
userService, storageDefinitionId, placeToken);
final LeaderboardPanelLifecycle lifecycle = new LeaderboardPanelLifecycle(null, StringMessages.INSTANCE);
final StoredSettingsLocation storageDefinition = StoredSettingsLocationFactory.createStoredSettingsLocatorForSeriesOverallLeaderboard(leaderboardName);
final ComponentContext<LeaderboardSettings> componentContext = new ComponentContextWithSettingsStorage<>(
lifeCycle, settingsStorageManager);
final ComponentContext<LeaderboardSettings> componentContext = new PlaceBasedComponentContextWithSettingsStorage<>(
lifecycle, userService, storageDefinition, placeToken);
return componentContext;
}
}
@@ -22,18 +22,16 @@ import com.sap.sailing.gwt.home.desktop.places.fakeseries.SeriesView;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardSettings;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardUrlSettings;
import com.sap.sailing.gwt.settings.client.leaderboard.MultiLeaderboardPanelLifecycle;
import com.sap.sailing.gwt.settings.client.utils.StorageDefinitionIdFactory;
import com.sap.sailing.gwt.settings.client.utils.StoredSettingsLocationFactory;
import com.sap.sailing.gwt.ui.client.LeaderboardUpdateListener;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.leaderboard.MultiLeaderboardProxyPanel;
import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
import com.sap.sse.gwt.client.shared.perspective.ComponentContextWithSettingsStorage;
import com.sap.sse.gwt.client.shared.perspective.DefaultOnSettingsLoadedCallback;
import com.sap.sse.gwt.client.shared.perspective.SettingsStorageManager;
import com.sap.sse.gwt.client.shared.settings.ComponentContext;
import com.sap.sse.gwt.client.shared.settings.DefaultOnSettingsLoadedCallback;
import com.sap.sse.gwt.shared.GwtHttpRequestUtils;
import com.sap.sse.security.ui.client.UserService;
import com.sap.sse.security.ui.settings.PlaceBasedUserSettingsStorageManager;
import com.sap.sse.security.ui.settings.StorageDefinitionId;
import com.sap.sse.security.ui.settings.PlaceBasedComponentContextWithSettingsStorage;
import com.sap.sse.security.ui.settings.StoredSettingsLocation;
public class EventSeriesLeaderboardsTabView extends Composite implements SeriesTabView<EventSeriesLeaderboardsPlace>,
LeaderboardUpdateListener {
@@ -77,7 +75,7 @@ public class EventSeriesLeaderboardsTabView extends Composite implements SeriesT
final boolean autoExpandLastRaceColumn = GwtHttpRequestUtils.getBooleanParameter(LeaderboardUrlSettings.PARAM_AUTO_EXPAND_LAST_RACE_COLUMN, false);
final ComponentContext<LeaderboardSettings> componentContext = createLeaderboardComponentContext(leaderboardName, currentPresenter.getUserService(), /*FIXME placeToken */ null);
componentContext.initInitialSettings(new DefaultOnSettingsLoadedCallback<LeaderboardSettings>() {
componentContext.getInitialSettings(new DefaultOnSettingsLoadedCallback<LeaderboardSettings>() {
@Override
public void onSuccess(LeaderboardSettings settings) {
MultiLeaderboardProxyPanel leaderboardPanel = regattaAnalyticsManager.createMultiLeaderboardPanel(null, componentContext,
@@ -129,12 +127,10 @@ public class EventSeriesLeaderboardsTabView extends Composite implements SeriesT
private ComponentContext<LeaderboardSettings> createLeaderboardComponentContext(String leaderboardName, UserService userService,
String placeToken) {
final MultiLeaderboardPanelLifecycle lifecycle = new MultiLeaderboardPanelLifecycle(null, StringMessages.INSTANCE);
final StorageDefinitionId storageDefinitionId = StorageDefinitionIdFactory.createStorageDefinitionIdForSeriesRegattaLeaderboards(leaderboardName);
final SettingsStorageManager<LeaderboardSettings> settingsStorageManager = new PlaceBasedUserSettingsStorageManager<>(
userService, storageDefinitionId, placeToken);
final StoredSettingsLocation storageDefinition = StoredSettingsLocationFactory.createStoredSettingsLocatorForSeriesRegattaLeaderboards(leaderboardName);
final ComponentContext<LeaderboardSettings> componentContext = new ComponentContextWithSettingsStorage<>(
lifecycle, settingsStorageManager);
final ComponentContext<LeaderboardSettings> componentContext = new PlaceBasedComponentContextWithSettingsStorage<>(
lifecycle, userService, storageDefinition, placeToken);
return componentContext;
}
@@ -18,7 +18,7 @@ import com.sap.sailing.gwt.home.desktop.places.fakeseries.SeriesView;
import com.sap.sailing.gwt.home.desktop.places.fakeseries.SharedLeaderboardEventSeriesTabView;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardSettings;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
import com.sap.sse.gwt.client.shared.perspective.DefaultOnSettingsLoadedCallback;
import com.sap.sse.gwt.client.shared.settings.DefaultOnSettingsLoadedCallback;
/**
* Created by pgtaboada on 25.11.14.
@@ -78,7 +78,7 @@ public class EventSeriesOverallLeaderboardTabView extends SharedLeaderboardEvent
if(leaderboardPanel == null) {
createSharedLeaderboardPanel(leaderboardName, eventSeriesAnalyticsManager, currentPresenter.getUserService(), /*FIXME placeToken */ null, leaderboardConsumer);
} else if( /*FIXME placeToken not empty */ false) {
createLeaderboardComponentContext(leaderboardName, currentPresenter.getUserService(), /*FIXME placeToken */ null).initInitialSettings(new DefaultOnSettingsLoadedCallback<LeaderboardSettings>() {
createLeaderboardComponentContext(leaderboardName, currentPresenter.getUserService(), /*FIXME placeToken */ null).getInitialSettings(new DefaultOnSettingsLoadedCallback<LeaderboardSettings>() {
@Override
public void onSuccess(LeaderboardSettings settings) {
leaderboardPanel.updateSettings(settings);
@@ -47,6 +47,9 @@
<c:tabcontent title="{i18n.favoritesAndNotifications}">
<s:preferencestab.UserProfilePreferencesTabView ui:field="preferencesTabUi" />
</c:tabcontent>
<c:tabcontent title="{i18n.settings}">
<s:settingstab.UserProfileSettingsTabView ui:field="settingsTabUi" />
</c:tabcontent>
</c:TabPanel>
</g:HTMLPanel>
</ui:UiBinder>
@@ -4,6 +4,7 @@ import com.sap.sailing.gwt.home.shared.app.ClientFactoryWithDispatch;
import com.sap.sailing.gwt.ui.client.SailingClientFactory;
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
import com.sap.sse.security.ui.authentication.WithAuthenticationManager;
import com.sap.sse.security.ui.authentication.WithUserService;
public interface UserProfileClientFactory extends ClientFactoryWithDispatch, SailingClientFactory, ErrorAndBusyClientFactory, WithAuthenticationManager {
public interface UserProfileClientFactory extends ClientFactoryWithDispatch, SailingClientFactory, ErrorAndBusyClientFactory, WithAuthenticationManager, WithUserService {
}
@@ -0,0 +1,55 @@
package com.sap.sailing.gwt.home.desktop.places.user.profile.settingstab;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsEntry;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
public class SettingsEntryDialog extends DataEntryDialog<UserSettingsEntry> {
private final FlowPanel fp;
public SettingsEntryDialog(UserSettingsEntry entry, Runnable deleteCallback) {
super(StringMessages.INSTANCE.settings(), StringMessages.INSTANCE.settingsForId(entry.getKey()), StringMessages.INSTANCE.remove(), StringMessages.INSTANCE.cancel(), null, false, new DialogCallback<UserSettingsEntry>() {
@Override
public void ok(UserSettingsEntry editedObject) {
deleteCallback.run();
}
@Override
public void cancel() {
}
});
fp = new FlowPanel();
final String userProfileSettings = entry.getProfileData();
boolean hasUserData = (userProfileSettings != null && !userProfileSettings.isEmpty());
final String localSettings = entry.getLocalData();
TextArea textArea = createTextArea(hasUserData ? userProfileSettings : localSettings);
textArea.setReadOnly(true);
fp.add(textArea);
}
public TextArea createTextArea(final String initialValue) {
final TextArea textArea = super.createTextArea(initialValue);
textArea.getElement().getStyle().setWidth(25, Unit.EM);
textArea.getElement().getStyle().setHeight(15, Unit.EM);
return textArea;
}
@Override
protected Widget getAdditionalWidget() {
return fp;
}
@Override
protected UserSettingsEntry getResult() {
return null;
}
}
@@ -0,0 +1,41 @@
package com.sap.sailing.gwt.home.desktop.places.user.profile.settingstab;
import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileClientFactory;
import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsPresenter;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsView;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
public class UserProfileSettingsPresenter implements UserProfileSettingsView.Presenter {
private final UserProfileSettingsView view;
private final UserProfileView.Presenter userProfilePresenter;
private final UserSettingsView.Presenter userSettingsPresenter;
public UserProfileSettingsPresenter(final UserProfileSettingsView view,
final UserProfileView.Presenter userProfilePresenter) {
this.view = view;
this.userProfilePresenter = userProfilePresenter;
this.userSettingsPresenter = new UserSettingsPresenter<UserProfileClientFactory>(
userProfilePresenter.getClientFactory());
view.setPresenter(this);
}
@Override
public UserSettingsView.Presenter getUserSettingsPresenter() {
return userSettingsPresenter;
}
@Override
public void setAuthenticationContext(AuthenticationContext authenticationContext) {
view.getDecorator().setAuthenticationContext(authenticationContext);
if (authenticationContext.isLoggedIn()) {
userSettingsPresenter.loadData();
}
}
@Override
public void doTriggerLoginForm() {
userProfilePresenter.doTriggerLoginForm();
}
}
@@ -0,0 +1,51 @@
package com.sap.sailing.gwt.home.desktop.places.user.profile.settingstab;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.Composite;
import com.sap.sailing.gwt.common.client.controls.tabbar.TabView;
import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileTabView;
import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView;
import com.sap.sailing.gwt.home.shared.ExperimentalFeatures;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserProfileSettingsPlace;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
public class UserProfileSettingsTabView extends Composite implements UserProfileTabView<UserProfileSettingsPlace> {
private UserProfileSettingsView.Presenter currentPresenter;
private UserProfileSettingsView view;
@Override
public Class<UserProfileSettingsPlace> getPlaceClassForActivation() {
return UserProfileSettingsPlace.class;
}
@Override
public TabView.State getState() {
return ExperimentalFeatures.SHOW_MY_SETTINGS_IN_USER_PROFILE ? TabView.State.VISIBLE : TabView.State.INVISIBLE;
}
@Override
public void start(UserProfileSettingsPlace myPlace, AcceptsOneWidget contentArea) {
contentArea.setWidget(view);
}
@Override
public void setAuthenticationContext(AuthenticationContext authenticationContext) {
currentPresenter.setAuthenticationContext(authenticationContext);
}
@Override
public void stop() {
}
@Override
public UserProfileSettingsPlace placeToFire() {
return new UserProfileSettingsPlace();
}
@Override
public void setPresenter(UserProfileView.Presenter currentPresenter) {
view = new UserProfileSettingsViewImpl();
this.currentPresenter = new UserProfileSettingsPresenter(view, currentPresenter);
}
}
@@ -0,0 +1,17 @@
package com.sap.sailing.gwt.home.desktop.places.user.profile.settingstab;
import com.google.gwt.user.client.ui.IsWidget;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsView;
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter;
public interface UserProfileSettingsView extends IsWidget {
void setPresenter(Presenter presenter);
NeedsAuthenticationContext getDecorator();
public interface Presenter extends NotLoggedInPresenter, NeedsAuthenticationContext {
UserSettingsView.Presenter getUserSettingsPresenter();
}
}
@@ -0,0 +1,33 @@
package com.sap.sailing.gwt.home.desktop.places.user.profile.settingstab;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop;
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
public class UserProfileSettingsViewImpl extends Composite implements UserProfileSettingsView {
interface MyBinder extends UiBinder<Widget, UserProfileSettingsViewImpl> {
}
private static MyBinder uiBinder = GWT.create(MyBinder.class);
@UiField(provided = true) AuthorizedContentDecoratorDesktop decoratorUi;
@UiField(provided = true) UserSettings userSettingsUi;
@Override
public void setPresenter(Presenter presenter) {
decoratorUi = new AuthorizedContentDecoratorDesktop(presenter);
userSettingsUi = new UserSettings(presenter.getUserSettingsPresenter());
initWidget(uiBinder.createAndBindUi(this));
}
@Override
public NeedsAuthenticationContext getDecorator() {
return decoratorUi;
}
}
@@ -0,0 +1,11 @@
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:um="urn:import:com.sap.sailing.gwt.home.shared.usermanagement.decorator"
xmlns:us="urn:import:com.sap.sailing.gwt.home.desktop.places.user.profile.settingstab">
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<um:AuthorizedContentDecoratorDesktop ui:field="decoratorUi">
<um:content>
<us:UserSettings ui:field="userSettingsUi"/>
</um:content>
</um:AuthorizedContentDecoratorDesktop>
</ui:UiBinder>
@@ -0,0 +1,127 @@
package com.sap.sailing.gwt.home.desktop.places.user.profile.settingstab;
import java.util.List;
import com.google.gwt.cell.client.ButtonCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.domain.common.impl.InvertibleComparatorAdapter;
import com.sap.sailing.gwt.common.theme.component.celltable.DesignedCellTableResources;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsEntry;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsView;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.leaderboard.SortedCellTable;
import com.sap.sse.common.Util.Function;
import com.sap.sse.common.util.NaturalComparator;
/**
* Implementation of {@link UserSettingsView} where users can change their preferred selections and notifications.
*/
public class UserSettings extends Composite implements UserSettingsView {
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
interface MyUiBinder extends UiBinder<Widget, UserSettings> {
}
@UiField
DivElement notificationsTextUi;
@UiField
DivElement tableWrapper;
@UiField(provided = true)
final SortedCellTable<UserSettingsEntry> userSettingsTable = new SortedCellTable<>(0,
DesignedCellTableResources.INSTANCE);
private final Column<UserSettingsEntry, String> keyColumn = new Column<UserSettingsEntry, String>(new TextCell()) {
@Override
public String getValue(UserSettingsEntry entry) {
return entry.getKeyWithoutContext();
}
};
private final Column<UserSettingsEntry, String> documentSettingsIdColumn = new Column<UserSettingsEntry, String>(
new TextCell()) {
@Override
public String getValue(UserSettingsEntry entry) {
return entry.getDocumentSettingsId();
}
};
private final Column<UserSettingsEntry, String> deleteColumn = new Column<UserSettingsEntry, String>(
new ButtonCell()) {
@Override
public String getValue(UserSettingsEntry entry) {
return StringMessages.INSTANCE.remove();
}
};
private final Column<UserSettingsEntry, String> showColumn = new Column<UserSettingsEntry, String>(
new ButtonCell()) {
@Override
public String getValue(UserSettingsEntry entry) {
return StringMessages.INSTANCE.show();
}
};
public UserSettings(UserSettingsView.Presenter presenter) {
initWidget(uiBinder.createAndBindUi(this));
deleteColumn.setFieldUpdater(new FieldUpdater<UserSettingsEntry, String>() {
@Override
public void update(int index, UserSettingsEntry object, String value) {
presenter.remove(object);
}
});
showColumn.setFieldUpdater(new FieldUpdater<UserSettingsEntry, String>() {
@Override
public void update(int index, UserSettingsEntry object, String value) {
new SettingsEntryDialog(object, () -> presenter.remove(object)).show();
}
});
userSettingsTable.addColumn(keyColumn, StringMessages.INSTANCE.settingsId(),
new StringComparator(UserSettingsEntry::getKeyWithoutContext), true);
userSettingsTable.addColumn(documentSettingsIdColumn, StringMessages.INSTANCE.documentSettingsId(),
new StringComparator(UserSettingsEntry::getDocumentSettingsId), true);
showColumn.setCellStyleNames(DesignedCellTableResources.INSTANCE.cellTableStyle().buttonCell());
userSettingsTable.addColumn(showColumn, "", null, false);
deleteColumn.setCellStyleNames(DesignedCellTableResources.INSTANCE.cellTableStyle().buttonCell());
userSettingsTable.addColumn(deleteColumn, "", null, false);
presenter.setView(this);
}
@Override
public void setEntries(List<UserSettingsEntry> entries) {
if (entries.isEmpty()) {
notificationsTextUi.setInnerText(StringMessages.INSTANCE.noDataFound());
tableWrapper.getStyle().setDisplay(Display.NONE);
} else {
notificationsTextUi.setInnerText(StringMessages.INSTANCE.userProfileSettingsTabDescription());
tableWrapper.getStyle().clearDisplay();
userSettingsTable.setPageSize(entries.size());
userSettingsTable.setList(entries);
}
}
private static final class StringComparator extends InvertibleComparatorAdapter<UserSettingsEntry> {
private final NaturalComparator innerComnparator = new NaturalComparator();
private final Function<UserSettingsEntry, String> valueExtractor;
public StringComparator(Function<UserSettingsEntry, String> valueExtractor) {
this.valueExtractor = valueExtractor;
}
@Override
public int compare(UserSettingsEntry o1, UserSettingsEntry o2) {
final String s1 = valueExtractor.get(o1);
final String s2 = valueExtractor.get(o2);
return innerComnparator.compare(s1, s2);
}
}
}
@@ -0,0 +1,20 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:um="urn:import:com.sap.sailing.gwt.home.shared.usermanagement.decorator"
xmlns:ms="urn:import:com.sap.sailing.gwt.home.shared.partials.multiselection" xmlns:c="urn:import:com.google.gwt.user.cellview.client">
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:style>
.table {
width: 100%;
}
</ui:style>
<g:HTMLPanel addStyleNames="{res.mediaCss.grid} {res.mainCss.spacermarginbottommediumsmall}">
<div ui:field="notificationsTextUi" class="{res.mediaCss.column} {res.mediaCss.medium12} {res.mainCss.spacermargintopsmall} {res.mainCss.spacermarginbottomsmall}">
<ui:text from="{i18n.userNotificationsOnlyIfMailAddressIsVerified}" />
</div>
<div ui:field="tableWrapper" class="{res.mediaCss.column} {res.mediaCss.small12} {res.mainCss.spacermargintopmediumsmall}">
<c:CellTable ui:field="userSettingsTable" addStyleNames="{style.table}" />
</div>
</g:HTMLPanel>
</ui:UiBinder>
@@ -17,6 +17,14 @@
for the competitor is cleared, the rank is set to 0 and the penalty is
set to "NONE" then the competitor will remain in the list, and this
"empty" result will be sent to the server, clearing any previous score
</li>
<li>When entering and publishing partial results, updates will only be applied
for those competitors for which a result has been entered. In particular,
when operating with multiple devices on the same course area and in case
the devices haven't synchronized their states yet this will make sure that
partial results entered on one device will not unnecessarily remove changes
applied on another device.
</li>
corrections that were sent to the server. This is the only way to
"reset" an erroneous score correction entirely from the app, because
swiping and thus removing the competitor from the list would leave the
@@ -4,8 +4,24 @@
<div id="mainContent">
<h4 class="articleHeadline">What's New - SAP Sailing Analytics</h4>
<div class="innerContent">
<h5 class="articleSubheadline">May 2017</h5>
<h5 class="articleSubheadline">June 2017</h5>
<ul class="bulletList">
<li>Several improvements were implemented regarding user settings:
<ul>
<li>Document settings are saved as delta to the user defaults instead of the delta to the system defaults.
In cases where a setting has the value 'A' as system default and 'B' as user default, it's now possible to set it back to 'A' for a document.
Settings stored before this change will continue to work with the old overwriting semantic.</li>
<li>Collection based settings are now stored as delta to the default set of values. This means that removals and additions are being recorded instead of all values of a setting.
Having value 'A' as system default and adding 'B' for the user default and 'C' for one document will select values 'A', 'B' and 'C' for the document.</li>
<li>Settings dialogs now have a 'reset to default' button. When pressing this button, user defaults as well as the current document settings are being reset to the system defaults.
In addition, the settings dialog is updated to show the system defaults. Those defaults will only take effect for the current view when pressing ok.</li>
<li>User settings can now also be saved for <code>/gwt/RaceBoard.html</code>. Be aware that different modes have distinct settings so that defaults defined for one mode do not have any effect on other modes.</li>
<li>On the user profile page you can now find a list of all stored settings. You can show the technical settings data and remove specific setting entries.</li>
</ul>
</li>
</ul>
<h5 class="articleSubheadline">May 2017</h5>
<ul class="bulletList">
<li>It's now possible to show nationality flags in addition to competitor images in leaderboards if both are available.
If no competitor images are available, this won't have any effect.
@@ -15,20 +31,22 @@
<h5 class="articleSubheadline">April 2017</h5>
<ul class="bulletList">
<li>Several pages are now enabled to save user settings. In settings dialogs there is a "Make default"
button in the lower-left corner which is displayed when saving of settings is enabled. A click on that
button causes the system to use the new settings as default values for the same page for any other context opened, e.g. another event.
A click on OK button causes the system to store current settings for the current context and restore the same settings
when the user opens the page with the same context again unless there are specific parameters given by the URL. Settings saved this way are
stored locally in the browser's local storage and in the user profile if you are logged in.
Some settings are only valid in a specific context (e.g. the selected race columns to show are stored for a specific leaderboard only).
This feature required changing several URL parameters, which means that previously saved bookmarks might work slightly different.
Affected pages:
<li>Several pages are now enabled to save user settings with the following specifics:
<ul>
<li>In settings dialogs there is a "Make default" button in the lower-left corner which is displayed when saving of settings is enabled. A click on that
button causes the system to use the new settings as default values for the same page. This is independent of a race, event or leaderboard to be shown.</li>
<li>A click on OK button causes the system to store the settings as document settings. Document settings are only used for the same event, leaderboard or race.
When the page is opened for e.g. the same race, the settings used last time are loaded.</li>
<li>Settings saved this way are stored locally in the browser's local storage and in the user profile if you are logged in.</li>
<li>Settings can be overwritten by URL parameters.</li>
</ul>
The following pages are now enabled to provide user settings:
<ul>
<li><code>/gwt/Leaderboard.html</code></li>
<li><code>/gwt/RegattaOverview.html</code></li>
<li>Leaderboards embedded in <code>/gwt/Home.html</code></li>
</ul>
</ul>
This feature required changing several URL parameters, which means that previously saved bookmarks might work slightly different.
</li>
<li>The maneuver loss calculation for penalty circles has been improved. Previously, the end of the
penalty circle maneuver was considered to be at the last of the two adjacent tack/gybe maneuvers.
@@ -29,6 +29,7 @@ import com.sap.sse.gwt.client.mvp.ErrorView;
import com.sap.sse.security.ui.authentication.AuthenticationManager;
import com.sap.sse.security.ui.authentication.AuthenticationManagerImpl;
import com.sap.sse.security.ui.authentication.WithAuthenticationManager;
import com.sap.sse.security.ui.authentication.WithUserService;
import com.sap.sse.security.ui.client.SecureClientFactoryImpl;
import com.sap.sse.security.ui.client.i18n.StringMessages;
@@ -40,7 +41,7 @@ import com.sap.sse.security.ui.client.i18n.StringMessages;
public class MobileApplicationClientFactory extends
SecureClientFactoryImpl<ApplicationTopLevelView<ResettableNavigationPathDisplay>> implements
ErrorAndBusyClientFactory, SearchResultClientFactory, ConfirmationClientFactory, PasswordResetClientFactory,
WithAuthenticationManager {
WithAuthenticationManager, WithUserService {
private final MobilePlacesNavigator navigator;
private final SailingDispatchSystem dispatch = new SailingDispatchSystemImpl();
private final AuthenticationManager authenticationManager;
@@ -49,26 +49,42 @@
border-bottom: 1px solid #ccc;
}
.searchresult_item {
padding: 1.333333333333333em 1em;
padding: 0;
border-bottom: 1px solid #ccc;
}
.searchresult_item_link,
.searchresult_item_link:visited,
.searchresult_item_link:after {
position: relative;
display: block;
padding: 1em;
text-decoration: none !important;
}
.searchresult_item_headline {
font-size: 1.066666666666667em;
font-weight: 700;
margin-right: 2em;
font-weight: bold;
margin-right: 2rem;
}
.searchresult_item_event {
font-size: 0.866666666666667em;
color: #0a0a0a;
margin-right: 2em;
}
.searchresult_item_event_link {
color: #0a0a0a;
font-size: 1.066666666666667em;
font-weight: bold;
color: #bcbcbc;
margin-right: 2rem;
}
.searchresult_item_event_link,
.searchresult_item_event_link:visited,
.searchresult_item_event_link:active {
font-size: 93.3333333333%;
position: relative;
display: block;
color: #0a0a0a;
padding: 0.5em 1em 0.5em 3em;
border-top: 1px solid #ebebeb;
text-decoration: none !important;
}
.searchresult_item_event_info {
font-size: 0.866666666666667em;
margin-right: 2rem;
}
.searchresult_item_event_separator:after {
content: "|";
@@ -76,13 +92,14 @@
color: #ccc;
}
.searchresult_item_arrow {
font-size: 1rem;
background: url("images/home/arrow-down-grey.png");
background-size: contain;
display: block;
width: 1.333333333333333em;
height: 1.333333333333333em;
top: 50%;
right: 1em;
right: 0.666666666666667em;
position: absolute;
-webkit-transform: translateY(-50%) rotate(-90deg);
-moz-transform: translateY(-50%) rotate(-90deg);
@@ -16,21 +16,19 @@ public class SearchResultItem extends AbstractSearchResultItem {
private static SearchResultItemUiBinder uiBinder = GWT.create(SearchResultItemUiBinder.class);
interface SearchResultItemUiBinder extends UiBinder<AnchorElement, SearchResultItem> {
interface SearchResultItemUiBinder extends UiBinder<DivElement, SearchResultItem> {
}
@UiField DivElement resultTitleUi;
@UiField DivElement eventInfoContainerUi;
private final AnchorElement anchorUi;
@UiField AnchorElement anchorUi;
private final MobilePlacesNavigator navigator;
private final SearchResultDTO item;
SearchResultItem(MobilePlacesNavigator navigator, SearchResultDTO item) {
this.navigator = navigator;
init(anchorUi = uiBinder.createAndBindUi(this), item);
SearchResultEventInfoDTO event = item.getEvents().iterator().next();
String eventId = String.valueOf(event.getId()), leaderboardName = item.getLeaderboardName(), baseUrl = item.getBaseUrl();
PlaceNavigation<?> regattaNavigation = navigator.getRegattaNavigation(eventId, leaderboardName, baseUrl, item.isOnRemoteServer());
regattaNavigation.configureAnchorElement(anchorUi);
this.item = item;
init(uiBinder.createAndBindUi(this), item);
}
@Override
@@ -38,10 +36,16 @@ public class SearchResultItem extends AbstractSearchResultItem {
return resultTitleUi;
}
@Override
protected void configureRegattaNavigation(String eventId, String leaderboardName, String baseUrl, boolean isOnRemoteServer) {
navigator.getRegattaNavigation(eventId, leaderboardName, baseUrl, item.isOnRemoteServer()).configureAnchorElement(anchorUi);
}
@Override
protected void addEventInfo(SearchResultEventInfoDTO event) {
if (eventInfoContainerUi.hasChildNodes()) return; // TODO: Temporary add only one event on mobile
eventInfoContainerUi.appendChild(new SearchResultItemEventInfo(navigator, event).getElement());
String eventId = String.valueOf(event.getId());
PlaceNavigation<?> eventNavigation = navigator.getEventNavigation(eventId, item.getBaseUrl(), item.isOnRemoteServer());
eventInfoContainerUi.appendChild(new SearchResultItemEventInfo(event, eventNavigation).getElement());
}
}
@@ -4,9 +4,11 @@
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.home.mobile.partials.searchresult.SearchResultResources" />
<a class="{local_res.css.searchresult_item} {res.mediaCss.small12} {res.mediaCss.columns}">
<div class="{local_res.css.searchresult_item_headline}" ui:field="resultTitleUi"> </div>
<div class="{local_res.css.searchresult_item} {res.mediaCss.small12} {res.mediaCss.columns}">
<a class="{local_res.css.searchresult_item_link}" ui:field="anchorUi" >
<div class="{local_res.css.searchresult_item_headline}" ui:field="resultTitleUi"> </div>
<div class="{local_res.css.searchresult_item_arrow}"></div>
</a>
<div ui:field="eventInfoContainerUi"></div>
<div class="{local_res.css.searchresult_item_arrow}"></div>
</a>
</div>
</ui:UiBinder>
@@ -1,28 +1,30 @@
package com.sap.sailing.gwt.home.mobile.partials.searchresult;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.AnchorElement;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.sap.sailing.gwt.home.communication.search.SearchResultEventInfoDTO;
import com.sap.sailing.gwt.home.mobile.app.MobilePlacesNavigator;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.home.shared.partials.searchresult.AbstractSearchResultItemEventInfo;
public class SearchResultItemEventInfo extends AbstractSearchResultItemEventInfo {
private static SearchResultItemEventInfoUiBinder uiBinder = GWT.create(SearchResultItemEventInfoUiBinder.class);
interface SearchResultItemEventInfoUiBinder extends UiBinder<Element, SearchResultItemEventInfo> {
interface SearchResultItemEventInfoUiBinder extends UiBinder<AnchorElement, SearchResultItemEventInfo> {
}
@UiField DivElement eventNameUi;
@UiField SpanElement eventVenueUi;
@UiField SpanElement eventDateUi;
private final AnchorElement anchorUi;
SearchResultItemEventInfo(MobilePlacesNavigator navigator, SearchResultEventInfoDTO event) {
init(uiBinder.createAndBindUi(this), event);
SearchResultItemEventInfo(SearchResultEventInfoDTO event, PlaceNavigation<?> navigation) {
init(anchorUi = uiBinder.createAndBindUi(this), event, navigation);
}
@Override
@@ -39,5 +41,10 @@ public class SearchResultItemEventInfo extends AbstractSearchResultItemEventInfo
protected Element getEventDateUi() {
return eventDateUi;
}
@Override
protected AnchorElement getNavigationUi() {
return anchorUi;
}
}
@@ -4,11 +4,12 @@
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.home.mobile.partials.searchresult.SearchResultResources" />
<div class="{local_res.css.searchresult_item_event}">
<div class="{local_res.css.searchresult_item_event_link}" ui:field="eventNameUi"></div>
<div>
<a class="{local_res.css.searchresult_item_event_link}">
<div class="{local_res.css.searchresult_item_event}" ui:field="eventNameUi"></div>
<div class="{local_res.css.searchresult_item_event_info}">
<span class="{local_res.css.searchresult_item_event_separator}" ui:field="eventVenueUi"></span>
<span ui:field="eventDateUi"></span>
</div>
</div>
<div class="{local_res.css.searchresult_item_arrow}"></div>
</a>
</ui:UiBinder>
@@ -20,8 +20,10 @@ public interface SearchResultResources extends ClientBundle {
String searchresult_header_form_button();
String searchresult_amount();
String searchresult_item();
String searchresult_item_link();
String searchresult_item_headline();
String searchresult_item_event();
String searchresult_item_event_info();
String searchresult_item_event_link();
String searchresult_item_event_separator();
String searchresult_item_arrow();
@@ -63,6 +63,9 @@
font-size: 0.866666666666667em;
color: #0a0a0a;
}
.sectionheader_item, .sectionheader_item_title, .sectionheader_item_subtitle {
max-width: 100%;
}
.sectionheader_item_infotext {
display: inline-block;
vertical-align: middle;
@@ -112,9 +115,8 @@ img.sectionheader_item_arrow.accordion.collapsed {
background: url("images/mobile/filter.svg") 100% no-repeat transparent;
background-size: 1.333333333333333em;
}
.sectionheader_item_adjust_title {
margin-left: 4em;
margin-right: 2.5em;
.sectionheader_item_adjust_title_left {
padding-left: 4em;
position: absolute;
top: 50%;
-webkit-transform: translateY(-50%);
@@ -122,6 +124,9 @@ img.sectionheader_item_arrow.accordion.collapsed {
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
.sectionheader_item_adjust_title > h2 {
.sectionheader_item_adjust_title_left > h2 {
display: inline;
}
.sectionheader_item_adjust_title_right {
padding-right: 2.5em;
}
@@ -1,25 +0,0 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:s="urn:import:com.sap.sailing.gwt.home.client.shared" xmlns:mp="urn:import:com.sap.sailing.gwt.home.mobile.partials">
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.home.mobile.partials.sectionHeader.SectionHeaderResources" />
<g:HTMLPanel>
<div class="{res.mediaCss.grid}">
<a href="#" title="TODO">
<!-- IF isStandalone ADD class 'section-header--stand-alone' -->
<div class="{local_res.css.sectionheader} {res.mediaCss.small12} {res.mediaCss.columns} {local_res.css.sectionheaderstandalone}">
<!-- IF END -->
<mp:sectionHeader.SectionHeaderContent />
</div>
</a>
</div>
<div class="{res.mediaCss.grid}">
<!-- IF isStandalone ADD class 'section-header--stand-alone' -->
<div class="{local_res.css.sectionheader} {res.mediaCss.small12} {res.mediaCss.columns} {local_res.css.sectionheaderstandalone}">
<!-- IF END -->
<mp:sectionHeader.SectionHeaderContent />
</div>
</div>
</g:HTMLPanel>
</ui:UiBinder>
@@ -10,8 +10,6 @@ import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.SimplePanel;
@@ -75,7 +73,8 @@ public class SectionHeaderContent extends Composite {
public void setImageUrl(String imageUrl) {
imageUi.getStyle().clearDisplay();
imageUi.getStyle().setBackgroundImage("url(" + imageUrl + ")");
titleAndLabelContainerUi.addClassName(SectionHeaderResources.INSTANCE.css().sectionheader_item_adjust_title());
titleAndLabelContainerUi
.addClassName(SectionHeaderResources.INSTANCE.css().sectionheader_item_adjust_title_left());
}
public void setInfoText(String infoText) {
@@ -97,23 +96,31 @@ public class SectionHeaderContent extends Composite {
});
actionArrowUi.setSrc("images/mobile/arrow-down-grey.png");
actionArrowUi.addClassName(SectionHeaderResources.INSTANCE.css().accordion());
titleAndLabelContainerUi
.addClassName(SectionHeaderResources.INSTANCE.css().sectionheader_item_adjust_title_right());
actionArrowUi.getStyle().clearDisplay();
headerRightUi.getStyle().clearDisplay();
}
public void setClickAction(final PlaceNavigation<?> placeNavigation) {
placeNavigation.configureAnchorElement(headerMainUi);
this.adjustedActionStyles();
titleAndLabelContainerUi
.addClassName(SectionHeaderResources.INSTANCE.css().sectionheader_item_adjust_title_right());
headerRightUi.getStyle().clearDisplay();
actionArrowUi.getStyle().clearDisplay();
}
public void setClickAction(final String url) {
headerMainUi.setHref(url);
DOM.setEventListener(headerMainUi, new EventListener() {
@Override
public void onBrowserEvent(Event event) {
}
DOM.setEventListener(headerMainUi, event -> {
});
this.adjustedActionStyles();
}
private void adjustedActionStyles() {
titleAndLabelContainerUi
.addClassName(SectionHeaderResources.INSTANCE.css().sectionheader_item_adjust_title_right());
headerRightUi.getStyle().clearDisplay();
actionArrowUi.getStyle().clearDisplay();
}
@@ -23,7 +23,8 @@ public interface SectionHeaderResources extends ClientBundle {
String sectionheader_item_subtitle();
String sectionheader_item_infotext();
String sectionheader_item_arrow();
String sectionheader_item_adjust_title();
String sectionheader_item_adjust_title_left();
String sectionheader_item_adjust_title_right();
String sectionheader_item_select();
String accordion();
String collapsed();
@@ -261,13 +261,12 @@ public abstract class AbstractEventActivity<PLACE extends AbstractEventPlace> ex
RaceboardContextDefinition raceboardContext = new RaceboardContextDefinition(raceIdentifier.getRegattaName(),
raceIdentifier.getRaceName(), leaderboardName, leaderboardGroupName,
UUID.fromString(getCtx().getEventId()), mode);
RaceBoardPerspectiveOwnSettings perspectiveOwnSettings = RaceBoardPerspectiveOwnSettings
.createDefaultWithCanReplayDuringLiveRaces(true);
RaceBoardPerspectiveOwnSettings perspectiveOwnSettings = new RaceBoardPerspectiveOwnSettings();
HashMap<String, Settings> innerSettings = new HashMap<>();
innerSettings.put(RaceMapLifecycle.ID, RaceMapSettings.getDefaultWithShowMapControls(true));
PerspectiveCompositeSettings<RaceBoardPerspectiveOwnSettings> settings = new PerspectiveCompositeSettings<>(
perspectiveOwnSettings, innerSettings);
return EntryPointWithSettingsLinkFactory.createRaceBoardLink(raceboardContext, settings);
}
@@ -28,4 +28,9 @@ public abstract class AbstractUserProfileActivity extends AbstractActivity imple
return clientFactory.getNavigator().getUserPreferencesNavigation();
}
@Override
public PlaceNavigation<? extends AbstractUserProfilePlace> getUserSettingsNavigation() {
return clientFactory.getNavigator().getUserSettingsNavigation();
}
}
@@ -9,6 +9,7 @@ import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.common.client.SharedResources;
import com.sap.sailing.gwt.home.mobile.partials.quickfinder.Quickfinder;
import com.sap.sailing.gwt.home.shared.ExperimentalFeatures;
import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorMobile;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
@@ -42,6 +43,9 @@ public class AbstractUserProfileView extends Composite implements UserProfileVie
this.layout.quickfinderUi.addPlaceholderItem(i18n.profileQuickfinder());
this.layout.quickfinderUi.addItem(i18n.details(), presenter.getUserProfileNavigation());
this.layout.quickfinderUi.addItem(i18n.favoritesAndNotifications(), presenter.getUserPreferencesNavigation());
if(ExperimentalFeatures.SHOW_MY_SETTINGS_IN_USER_PROFILE) {
this.layout.quickfinderUi.addItem(i18n.settings(), presenter.getUserSettingsNavigation());
}
}
protected final void setViewContent(IsWidget content) {
@@ -4,8 +4,10 @@ import com.google.gwt.core.client.GWT;
import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory;
import com.sap.sailing.gwt.home.mobile.places.user.profile.details.UserProfileDetailsActivity;
import com.sap.sailing.gwt.home.mobile.places.user.profile.preferences.UserProfilePreferencesActivity;
import com.sap.sailing.gwt.home.mobile.places.user.profile.settings.UserProfileSettingsActivity;
import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace;
import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.UserProfilePreferencesPlace;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserProfileSettingsPlace;
import com.sap.sse.gwt.client.mvp.AbstractActivityProxy;
public class UserProfileActivityProxy extends AbstractActivityProxy {
@@ -26,6 +28,8 @@ public class UserProfileActivityProxy extends AbstractActivityProxy {
if (currentPlace instanceof UserProfilePreferencesPlace) {
UserProfilePreferencesPlace userProfilePrefsPlace = (UserProfilePreferencesPlace) currentPlace;
super.onSuccess(new UserProfilePreferencesActivity(userProfilePrefsPlace, clientFactory));
} else if(currentPlace instanceof UserProfileSettingsPlace) {
super.onSuccess(new UserProfileSettingsActivity((UserProfileSettingsPlace) currentPlace, clientFactory));
} else {
super.onSuccess(new UserProfileDetailsActivity(currentPlace, clientFactory));
}
@@ -11,5 +11,6 @@ public interface UserProfileViewBase extends IsWidget, NeedsAuthenticationContex
public interface Presenter extends NotLoggedInPresenter {
PlaceNavigation<? extends AbstractUserProfilePlace> getUserProfileNavigation();
PlaceNavigation<? extends AbstractUserProfilePlace> getUserPreferencesNavigation();
PlaceNavigation<? extends AbstractUserProfilePlace> getUserSettingsNavigation();
}
}
@@ -0,0 +1,44 @@
package com.sap.sailing.gwt.home.mobile.places.user.profile.settings;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory;
import com.sap.sailing.gwt.home.mobile.places.user.profile.AbstractUserProfileActivity;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserProfileSettingsPlace;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsPresenter;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsView;
import com.sap.sse.security.ui.authentication.AuthenticationContextEvent;
public class UserProfileSettingsActivity extends AbstractUserProfileActivity implements UserProfileSettingsView.Presenter {
private final UserSettingsView.Presenter userSettingsPresenter;
private final UserProfileSettingsView currentView;
public UserProfileSettingsActivity(UserProfileSettingsPlace place,
MobileApplicationClientFactory clientFactory) {
super(clientFactory);
this.userSettingsPresenter = new UserSettingsPresenter<MobileApplicationClientFactory>(clientFactory);
this.currentView = new UserProfileSettingsViewImpl(this);
}
@Override
public void start(final AcceptsOneWidget panel, final EventBus eventBus) {
panel.setWidget(currentView);
currentView.setAuthenticationContext(clientFactory.getAuthenticationManager().getAuthenticationContext());
eventBus.addHandler(AuthenticationContextEvent.TYPE, new AuthenticationContextEvent.Handler() {
@Override
public void onUserChangeEvent(AuthenticationContextEvent event) {
currentView.setAuthenticationContext(event.getCtx());
}
});
if (clientFactory.getAuthenticationManager().getAuthenticationContext().isLoggedIn()) {
userSettingsPresenter.loadData();
}
}
@Override
public UserSettingsView.Presenter getUserSettingsPresenter() {
return userSettingsPresenter;
}
}
@@ -0,0 +1,12 @@
package com.sap.sailing.gwt.home.mobile.places.user.profile.settings;
import com.sap.sailing.gwt.home.mobile.places.user.profile.UserProfileViewBase;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsView;
public interface UserProfileSettingsView extends UserProfileViewBase {
public interface Presenter extends UserProfileViewBase.Presenter {
UserSettingsView.Presenter getUserSettingsPresenter();
}
}
@@ -0,0 +1,16 @@
package com.sap.sailing.gwt.home.mobile.places.user.profile.settings;
import com.sap.sailing.gwt.home.mobile.places.user.profile.AbstractUserProfileView;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsView;
public class UserProfileSettingsViewImpl extends AbstractUserProfileView implements UserProfileSettingsView {
private final UserSettingsView userPreferencesView;
public UserProfileSettingsViewImpl(UserProfileSettingsView.Presenter presenter) {
super(presenter);
this.userPreferencesView = new UserSettings(presenter.getUserSettingsPresenter());
this.setViewContent(userPreferencesView);
}
}
@@ -0,0 +1,46 @@
package com.sap.sailing.gwt.home.mobile.places.user.profile.settings;
import java.util.List;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsEntry;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsView;
import com.sap.sailing.gwt.ui.client.StringMessages;
/**
* Implementation of {@link UserSettingsView} where users can change their preferred selections and notifications.
*/
public class UserSettings extends Composite implements UserSettingsView {
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
interface MyUiBinder extends UiBinder<Widget, UserSettings> {
}
@UiField
DivElement notificationsTextUi;
@UiField
FlowPanel settingsContainerUi;
private final Presenter presenter;
public UserSettings(UserSettingsView.Presenter presenter) {
this.presenter = presenter;
initWidget(uiBinder.createAndBindUi(this));
presenter.setView(this);
}
@Override
public void setEntries(List<UserSettingsEntry> entries) {
notificationsTextUi.setInnerText(entries.isEmpty() ? StringMessages.INSTANCE.noDataFound()
: StringMessages.INSTANCE.userProfileSettingsTabDescription());
settingsContainerUi.clear();
entries.forEach(entry -> settingsContainerUi.add(new UserSettingsItem(entry, () -> presenter.remove(entry))));
}
}
@@ -0,0 +1,11 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<g:HTMLPanel addStyleNames="{res.mediaCss.grid} {res.mainCss.spacermarginbottommediumsmall}">
<div ui:field="notificationsTextUi" class="{res.mediaCss.column} {res.mediaCss.small12} {res.mainCss.spacermargintopsmall} {res.mainCss.spacermarginbottomsmall}">
<ui:text from="{i18n.userNotificationsOnlyIfMailAddressIsVerified}" />
</div>
<g:FlowPanel ui:field="settingsContainerUi" addStyleNames="{res.mediaCss.column} {res.mediaCss.small12}" />
</g:HTMLPanel>
</ui:UiBinder>
@@ -0,0 +1,49 @@
package com.sap.sailing.gwt.home.mobile.places.user.profile.settings;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.sap.sailing.gwt.home.mobile.partials.section.MobileSection;
import com.sap.sailing.gwt.home.mobile.partials.sectionHeader.SectionHeaderContent;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserSettingsEntry;
public class UserSettingsItem extends Composite {
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
interface MyUiBinder extends UiBinder<MobileSection, UserSettingsItem> {
}
@UiField SectionHeaderContent sectionHeaderUi;
@UiField HTMLPanel contentContainerUi;
@UiField DivElement settingsDataUi;
private final Runnable deleteCallback;
public UserSettingsItem(UserSettingsEntry userSettingsEntry, Runnable deleteCallback) {
this.deleteCallback = deleteCallback;
MobileSection mobileSection = uiBinder.createAndBindUi(this);
mobileSection.setEdgeToEdgeContent(true);
initWidget(mobileSection);
sectionHeaderUi.setSectionTitle(userSettingsEntry.getKeyWithoutContext());
sectionHeaderUi.setSubtitle(userSettingsEntry.getDocumentSettingsId());
final String userProfileSettings = userSettingsEntry.getProfileData();
boolean hasUserData = (userProfileSettings != null && !userProfileSettings.isEmpty());
final String localSettings = userSettingsEntry.getLocalData();
settingsDataUi.setInnerText(hasUserData ? userProfileSettings : localSettings);
sectionHeaderUi.initCollapsibility(contentContainerUi.getElement(), false);
}
@UiHandler("deleteControlUi")
void onRemoveControlClicked(ClickEvent event) {
this.deleteCallback.run();
}
}
@@ -0,0 +1,30 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:ms="urn:import:com.sap.sailing.gwt.home.mobile.partials.section"
xmlns:sh="urn:import:com.sap.sailing.gwt.home.mobile.partials.sectionHeader">
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:style>
.wordwrapping {
word-wrap: break-word;
}
.content {
padding: .333333333333333em;
}
.deleteControl {
width: 100%;
}
</ui:style>
<ms:MobileSection addStyleNames="{style.wordwrapping}">
<ms:header>
<sh:SectionHeaderContent ui:field="sectionHeaderUi"/>
</ms:header>
<ms:content>
<g:HTMLPanel ui:field="contentContainerUi" addStyleNames="{style.content}">
<div ui:field="settingsDataUi" class="{res.mainCss.spacermarginbottomsmall}"></div>
<g:Button ui:field="deleteControlUi" text="{i18n.delete}"
addStyleNames="{res.mainCss.button} {res.mainCss.buttonprimary} {style.deleteControl}" />
</g:HTMLPanel>
</ms:content>
</ms:MobileSection>
</ui:UiBinder>
@@ -13,4 +13,8 @@ public class ExperimentalFeatures {
* Provide buttons for user management login via social services like facebook or google.
*/
public static final boolean SHOW_SOCIAL_LOGINS_FOR_USER_MANAGEMENT = false;
/**
* Provide a tab "settings" in the user profile page.
*/
public static final boolean SHOW_MY_SETTINGS_IN_USER_PROFILE = true;
}
@@ -38,6 +38,7 @@ import com.sap.sailing.gwt.home.shared.places.user.passwordreset.PasswordResetPl
import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfileDefaultPlace;
import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfileDetailsPlace;
import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.UserProfilePreferencesPlace;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserProfileSettingsPlace;
@WithTokenizers({ AboutUsPlace.Tokenizer.class, ContactPlace.Tokenizer.class, EventPlace.Tokenizer.class,
EventsPlace.Tokenizer.class, SolutionsPlace.Tokenizer.class, WhatsNewPlace.Tokenizer.class,
@@ -72,6 +73,7 @@ import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.UserProfi
UserProfileDefaultPlace.Tokenizer.class,
UserProfileDetailsPlace.Tokenizer.class,
UserProfilePreferencesPlace.Tokenizer.class,
UserProfileSettingsPlace.Tokenizer.class,
AuthenticationPlace.Tokenizer.class,
ConfirmationPlace.Tokenizer.class,
PasswordResetPlace.Tokenizer.class,
@@ -21,6 +21,7 @@ import com.sap.sailing.gwt.home.shared.places.user.passwordreset.PasswordResetPl
import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace;
import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfileDefaultPlace;
import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.UserProfilePreferencesPlace;
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserProfileSettingsPlace;
public class HomePlacesNavigator extends AbstractPlaceNavigator {
@@ -103,4 +104,8 @@ public class HomePlacesNavigator extends AbstractPlaceNavigator {
public PlaceNavigation<? extends AbstractUserProfilePlace> getUserPreferencesNavigation() {
return createLocalPlaceNavigation(new UserProfilePreferencesPlace());
}
public PlaceNavigation<? extends AbstractUserProfilePlace> getUserSettingsNavigation() {
return createLocalPlaceNavigation(new UserProfileSettingsPlace());
}
}
@@ -10,11 +10,16 @@ public abstract class AbstractSearchResultItem extends Widget {
protected final void init(Element element, SearchResultDTO item) {
setElement(element);
getResultTitleUi().setInnerText(item.getDisplayName());
String eventId = String.valueOf(item.getEvents().iterator().next().getId());
configureRegattaNavigation(eventId, item.getLeaderboardName(), item.getBaseUrl(), item.isOnRemoteServer());
for (SearchResultEventInfoDTO event : item.getEvents()) {
addEventInfo(event);
}
}
protected abstract void configureRegattaNavigation(String eventId,
String leaderboardName, String baseUrl, boolean isOnRemoteServer);
protected abstract Element getResultTitleUi();
protected abstract void addEventInfo(SearchResultEventInfoDTO event);
@@ -2,19 +2,22 @@ package com.sap.sailing.gwt.home.shared.partials.searchresult;
import static com.sap.sailing.gwt.home.shared.utils.EventDatesFormatterUtil.formatDateRangeWithYear;
import com.google.gwt.dom.client.AnchorElement;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.ui.UIObject;
import com.sap.sailing.gwt.home.communication.search.SearchResultEventInfoDTO;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
public abstract class AbstractSearchResultItemEventInfo extends UIObject {
protected final void init(Element element, SearchResultEventInfoDTO event) {
protected final void init(Element element, SearchResultEventInfoDTO event, PlaceNavigation<?> navigation) {
setElement(element);
getEventNameUi().setInnerText(event.getName());
getEventVenueUi().setInnerText(event.getVenueName());
if (event.getStartDate() != null && event.getEndDate() != null) {
getEventDateUi().setInnerText(formatDateRangeWithYear(event.getStartDate(), event.getEndDate()));
}
navigation.configureAnchorElement(getNavigationUi());
}
protected abstract Element getEventNameUi();
@@ -22,5 +25,7 @@ public abstract class AbstractSearchResultItemEventInfo extends UIObject {
protected abstract Element getEventVenueUi();
protected abstract Element getEventDateUi();
protected abstract AnchorElement getNavigationUi();
}
@@ -26,6 +26,7 @@ public class PlaceTokenPrefixes {
public static final String UserProfileDefault = "/user/profile/";
public static final String UserProfileDetails = "/user/profile/details/";
public static final String UserProfilePreferences = "/user/profile/preferences/";
public static final String UserProfileSettings = "/user/profile/settings/";
public static final String UserConfirmation = "/user/confirmation/";
public static final String UserPasswordReset = "/user/passwordreset/";
public static final String UserAuthentication = "/user/auth/";
@@ -0,0 +1,18 @@
package com.sap.sailing.gwt.home.shared.places.user.profile.settings;
import com.google.gwt.place.shared.Prefix;
import com.sap.sailing.gwt.home.shared.app.HasMobileVersion;
import com.sap.sailing.gwt.home.shared.places.PlaceTokenPrefixes;
import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace;
public class UserProfileSettingsPlace extends AbstractUserProfilePlace implements HasMobileVersion {
@Prefix(PlaceTokenPrefixes.UserProfileSettings)
public static class Tokenizer extends AbstractUserProfilePlace.Tokenizer<UserProfileSettingsPlace> {
@Override
protected UserProfileSettingsPlace getRealPlace() {
return new UserProfileSettingsPlace();
}
}
}
@@ -0,0 +1,47 @@
package com.sap.sailing.gwt.home.shared.places.user.profile.settings;
import com.sap.sse.security.ui.settings.StoredSettingsLocation;
public class UserSettingsEntry {
private final String key;
private final String keyWithoutContext;
private final String documentSettingsId;
private final String profileData;
private final String localData;
public UserSettingsEntry(String key, String profileData, String localData) {
super();
final int separatorIndex = key.indexOf(StoredSettingsLocation.DOCUMENT_SETTINGS_SUFFIX_SEPARATOR);
if(separatorIndex > 0) {
keyWithoutContext = key.substring(0, separatorIndex);
documentSettingsId = key.substring(separatorIndex + 1);
} else {
keyWithoutContext = key;
documentSettingsId = null;
}
this.key = key;
this.profileData = profileData;
this.localData = localData;
}
public String getKey() {
return key;
}
public String getProfileData() {
return profileData;
}
public String getLocalData() {
return localData;
}
public String getDocumentSettingsId() {
return documentSettingsId;
}
public String getKeyWithoutContext() {
return keyWithoutContext;
}
}
@@ -0,0 +1,101 @@
package com.sap.sailing.gwt.home.shared.places.user.profile.settings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import com.google.gwt.storage.client.Storage;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.gwt.home.shared.app.ClientFactoryWithDispatch;
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
import com.sap.sailing.gwt.ui.shared.settings.SailingSettingsConstants;
import com.sap.sse.security.ui.authentication.WithAuthenticationManager;
import com.sap.sse.security.ui.authentication.WithUserService;
/**
* @param <C>
* the provided client factory type
*/
public class UserSettingsPresenter<C extends ClientFactoryWithDispatch & ErrorAndBusyClientFactory & WithAuthenticationManager & WithUserService>
implements UserSettingsView.Presenter {
private final C clientFactory;
private UserSettingsView view;
private final List<UserSettingsEntry> currentlyShownEntries = new ArrayList<>();
public UserSettingsPresenter(C clientFactory) {
this.clientFactory = clientFactory;
}
@Override
public void loadData() {
if(clientFactory.getAuthenticationManager().getAuthenticationContext().isLoggedIn()) {
clientFactory.getUserService().getAllPreferences(new AsyncCallback<Map<String,String>>() {
@Override
public void onSuccess(Map<String, String> result) {
loadSettingsFromLocalStorage(result);
}
@Override
public void onFailure(Throwable caught) {
clientFactory.createErrorView("Error while loading user settings!", caught);
}
});
} else {
loadSettingsFromLocalStorage(Collections.emptyMap());
}
}
private void loadSettingsFromLocalStorage(final Map<String, String> userSettings) {
final Map<String, String> localSettings = loadSettingsFromLocalStorage();
final Set<String> allKeys = new TreeSet<>((a, b) -> a.compareTo(b));
allKeys.addAll(userSettings.keySet());
allKeys.addAll(localSettings.keySet());
currentlyShownEntries.clear();
for(String key : allKeys) {
currentlyShownEntries.add(new UserSettingsEntry(key, userSettings.get(key), localSettings.get(key)));
}
view.setEntries(currentlyShownEntries);
}
private Map<String, String> loadSettingsFromLocalStorage() {
final Map<String, String> localSettings;
if(Storage.isLocalStorageSupported()) {
localSettings = new HashMap<String, String>();
Storage localStorage = Storage.getLocalStorageIfSupported();
for(int i = 0; i< localStorage.getLength(); i++) {
String key = localStorage.key(i);
if(key.startsWith(SailingSettingsConstants.USER_SETTINGS_UI)) {
String value = localStorage.getItem(key);
localSettings.put(key, value);
}
}
} else {
localSettings = Collections.emptyMap();
}
return localSettings;
}
@Override
public void remove(UserSettingsEntry entry) {
String storageKey = entry.getKey();
clientFactory.getUserService().unsetPreference(storageKey);
if(Storage.isLocalStorageSupported()) {
Storage localStorage = Storage.getLocalStorageIfSupported();
localStorage.removeItem(storageKey);
}
currentlyShownEntries.remove(entry);
view.setEntries(currentlyShownEntries);
}
@Override
public void setView(UserSettingsView view) {
this.view = view;
}
}
@@ -0,0 +1,29 @@
package com.sap.sailing.gwt.home.shared.places.user.profile.settings;
import java.util.List;
import com.google.gwt.user.client.ui.IsWidget;
import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionDataProvider;
/**
* Interface for the user preferences UI. To support desktop as well as mobile version, an
* {@link #setEdgeToEdge(boolean) edge-to-edge} flag can be provided, in order to meet the respective layout
* requirements.
*/
public interface UserSettingsView extends IsWidget {
void setEntries(List<UserSettingsEntry> entries);
/**
* Presenter interface for the user preferences UI, providing methods to load preferences and to access the required
* {@link SuggestedMultiSelectionDataProvider}s.
*/
public interface Presenter {
void loadData();
void remove(UserSettingsEntry entry);
void setView(UserSettingsView view);
}
}
@@ -1,11 +0,0 @@
package com.sap.sailing.gwt.regattaoverview.client;
import java.util.List;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sailing.gwt.ui.shared.RaceGroupDTO;
public interface EventAndRaceGroupAvailabilityListener {
void onEventUpdated(EventDTO event);
void onRaceGroupsUpdated(List<RaceGroupDTO> raceGroups);
}
@@ -16,11 +16,9 @@ import com.google.gwt.user.client.ui.ScrollPanel;
import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication;
import com.sap.sailing.gwt.common.authentication.SAPSailingHeaderWithAuthentication;
import com.sap.sailing.gwt.common.client.SharedResources;
import com.sap.sailing.gwt.regattaoverview.client.RegattaRaceStatesComponent.EntryHandler;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaOverviewContextDefinition;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings;
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO;
import com.sap.sse.gwt.settings.SettingsToUrlSerializer;
public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint {
@@ -56,30 +54,18 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint {
siteHeader.addWidgetToRightSide(clockLabel);
containerPanel.addNorth(siteHeader, 75);
RegattaOverviewContextDefinition regattaOverviewSettings = serializer
RegattaOverviewContextDefinition regattaOverviewContextDefinition = serializer
.deserializeFromCurrentLocation(new RegattaOverviewContextDefinition());
if (regattaOverviewSettings.getEvent() == null) {
if (regattaOverviewContextDefinition.getEvent() == null) {
Window.alert("Missing parameter");
return;
}
createAndAddDetailPanel();
createAndAddRegattaPanel(regattaOverviewSettings);
createAndAddRegattaPanel(regattaOverviewContextDefinition);
toggleDetailPanel(false);
regattaPanel.setEntryClickedHandler(new EntryHandler() {
@Override
public void onEntryClicked(RegattaOverviewEntryDTO entry) {
detailPanel.show(entry);
toggleDetailPanel(true);
}
@Override
public void onEntryUpdated(RegattaOverviewEntryDTO entry) {
detailPanel.update(entry);
}
});
}
private void toggleDetailPanel(boolean visibile) {
@@ -23,7 +23,7 @@ import com.sap.sailing.gwt.regattaoverview.client.RegattaRaceStatesComponent.Ent
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardSettings;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaOverviewContextDefinition;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings;
import com.sap.sailing.gwt.settings.client.utils.StorageDefinitionIdFactory;
import com.sap.sailing.gwt.settings.client.utils.StoredSettingsLocationFactory;
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
@@ -40,13 +40,12 @@ import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.client.player.Timer.PlayStates;
import com.sap.sse.gwt.client.shared.components.LinkWithSettingsGenerator;
import com.sap.sse.gwt.client.shared.components.SettingsDialog;
import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
import com.sap.sse.gwt.client.shared.perspective.ComponentContextWithSettingsStorage;
import com.sap.sse.gwt.client.shared.perspective.DefaultOnSettingsLoadedCallback;
import com.sap.sse.gwt.client.shared.perspective.SettingsStorageManager;
import com.sap.sse.gwt.client.shared.perspective.IgnoreLocalSettings;
import com.sap.sse.gwt.client.shared.settings.ComponentContext;
import com.sap.sse.gwt.client.shared.settings.DefaultOnSettingsLoadedCallback;
import com.sap.sse.security.ui.client.UserService;
import com.sap.sse.security.ui.settings.StorageDefinitionId;
import com.sap.sse.security.ui.settings.UserSettingsStorageManager;
import com.sap.sse.security.ui.settings.ComponentContextWithSettingsStorage;
import com.sap.sse.security.ui.settings.StoredSettingsLocation;
public class RegattaOverviewPanel extends SimplePanel {
@@ -63,7 +62,6 @@ public class RegattaOverviewPanel extends SimplePanel {
private final RegattaOverviewContextDefinition regattaOverviewContextDefinition;
private EventDTO eventDTO;
private List<RaceGroupDTO> raceGroupDTOs;
private List<EventAndRaceGroupAvailabilityListener> eventRaceGroupListeners;
private boolean showLeaderboard = false;
private RegattaRaceStatesComponent regattaRaceStatesComponent;
@@ -74,12 +72,20 @@ public class RegattaOverviewPanel extends SimplePanel {
private final Anchor startStopUpdatingButton;
private CheckBox leaderboardCheckBox;
private final FlowPanel repeatedInfoLabel = new FlowPanel();
private VerticalPanel mainPanel;
private UserService userService;
private ComponentContext<RegattaRaceStatesSettings> componentContext;
private final RegattaOverviewResources.LocalCss style = RegattaOverviewResources.INSTANCE.css();
private final SharedResources RES = SharedResources.INSTANCE;
private EntryHandler entryClickedHandler = null;
public void setEntryClickedHandler(EntryHandler handler) {
regattaRaceStatesComponent.setEntryClickedHandler(handler);
entryClickedHandler = handler;
if(regattaRaceStatesComponent != null) {
regattaRaceStatesComponent.setEntryClickedHandler(handler);
}
}
public RegattaOverviewPanel(
@@ -97,12 +103,9 @@ public class RegattaOverviewPanel extends SimplePanel {
this.uiUpdateTimer = new Timer(PlayModes.Live, uiUpdateRateInMs);
this.eventDTO = null;
this.raceGroupDTOs = new ArrayList<RaceGroupDTO>();
this.eventRaceGroupListeners = new ArrayList<EventAndRaceGroupAvailabilityListener>();
this.userService = userService;
retrieveEvent();
retrieveRegattaStructure();
VerticalPanel mainPanel = new VerticalPanel();
mainPanel = new VerticalPanel();
setWidget(mainPanel);
mainPanel.setWidth("100%");
mainPanel.addStyleName(style.contentWrapper());
@@ -130,7 +133,7 @@ public class RegattaOverviewPanel extends SimplePanel {
// TODO should we always set ignoreLocalSettings=true when creating links?
new SettingsDialog<RegattaRaceStatesSettings>(regattaRaceStatesComponent, stringMessages,
new LinkWithSettingsGenerator<>(regattaOverviewContextDefinition,
UserSettingsStorageManager.getIgnoreLocalSettings())).show();
IgnoreLocalSettings.getIgnoreLocalSettingsFromCurrentUrl())).show();
}
});
@@ -152,17 +155,67 @@ public class RegattaOverviewPanel extends SimplePanel {
});
final StorageDefinitionId storageDefinitionId = StorageDefinitionIdFactory.createStorageDefinitionIdForRegattaOverview(regattaOverviewContextDefinition);
final RegattaRaceStatesComponentLifecycle lifecycle = new RegattaRaceStatesComponentLifecycle();
final SettingsStorageManager<RegattaRaceStatesSettings> settingsStorageManager = UserSettingsStorageManager
.createSettingsStorageManager(userService, storageDefinitionId);
final ComponentContext<RegattaRaceStatesSettings> componentContext = new ComponentContextWithSettingsStorage<>(
lifecycle, settingsStorageManager);
//FIXME The chained calls from here are independent from each other and should be implemented with Dispatching Framework
sailingService.getEventById(regattaOverviewContextDefinition.getEvent(), false, new MarkedAsyncCallback<EventDTO>(
new AsyncCallback<EventDTO>() {
@Override
public void onFailure(Throwable cause) {
settingsButton.setEnabled(false);
errorReporter.reportError("Error trying to load event with id " + regattaOverviewContextDefinition.getEvent() + " : "
+ cause.getMessage());
continueInitAfterEventRetrieved();
}
@Override
public void onSuccess(EventDTO result) {
setEvent(result);
continueInitAfterEventRetrieved();
}
}));
}
private void continueInitAfterEventRetrieved() {
sailingService.getRegattaStructureForEvent(regattaOverviewContextDefinition.getEvent(), new MarkedAsyncCallback<List<RaceGroupDTO>>(
new AsyncCallback<List<RaceGroupDTO>>() {
@Override
public void onFailure(Throwable cause) {
errorReporter.reportError("Error trying to load regattas for event with id " + regattaOverviewContextDefinition.getEvent() + " : "
+ cause.getMessage());
continueInitAfterRaceGroupsRetrieved();
}
@Override
public void onSuccess(List<RaceGroupDTO> result) {
raceGroupDTOs.clear();
raceGroupDTOs.addAll(result);
continueInitAfterRaceGroupsRetrieved();
}
}));
}
private void continueInitAfterRaceGroupsRetrieved() {
final StoredSettingsLocation storageDefinition = StoredSettingsLocationFactory.createStoredSettingsLocatorForRegattaOverview(regattaOverviewContextDefinition);
final RegattaRaceStatesComponentLifecycle lifecycle = new RegattaRaceStatesComponentLifecycle(eventDTO == null ? null : eventDTO.venue.getCourseAreas(), raceGroupDTOs);
componentContext = new ComponentContextWithSettingsStorage<>(
lifecycle, userService, storageDefinition);
componentContext.getInitialSettings(new DefaultOnSettingsLoadedCallback<RegattaRaceStatesSettings>() {
@Override
public void onSuccess(RegattaRaceStatesSettings defaultSettings) {
continueInitAfterSettingsRetrieved(defaultSettings);
}
});
}
private void continueInitAfterSettingsRetrieved(RegattaRaceStatesSettings defaultSettings) {
regattaRaceStatesComponent = new RegattaRaceStatesComponent(null, componentContext, sailingService, errorReporter,
stringMessages,
regattaOverviewContextDefinition.getEvent(), lifecycle.createDefaultSettings(), uiUpdateTimer);
this.eventRaceGroupListeners.add(regattaRaceStatesComponent);
regattaOverviewContextDefinition.getEvent(), eventDTO, raceGroupDTOs, defaultSettings, uiUpdateTimer);
regattaRaceStatesComponent.setEntryClickedHandler(entryClickedHandler);
regattaRaceStatesComponent.setWidth("100%");
this.serverUpdateTimer.addTimeListener(new TimeListener() {
@@ -223,13 +276,7 @@ public class RegattaOverviewPanel extends SimplePanel {
} else {
leaderboardsTabPanel = null;
}
componentContext.initInitialSettings(new DefaultOnSettingsLoadedCallback<RegattaRaceStatesSettings>() {
@Override
public void onSuccess(RegattaRaceStatesSettings defaultSettings) {
regattaRaceStatesComponent.updateSettings(defaultSettings);
}
});
checkToEnableSettingsButton();
}
private CheckBox addLeaderboardEnablerButton() {
@@ -297,80 +344,15 @@ public class RegattaOverviewPanel extends SimplePanel {
}
}
private void retrieveEvent() {
sailingService.getEventById(regattaOverviewContextDefinition.getEvent(), false, new MarkedAsyncCallback<EventDTO>(
new AsyncCallback<EventDTO>() {
@Override
public void onFailure(Throwable cause) {
settingsButton.setEnabled(false);
errorReporter.reportError("Error trying to load event with id " + regattaOverviewContextDefinition.getEvent() + " : "
+ cause.getMessage());
}
@Override
public void onSuccess(EventDTO result) {
if (result != null) {
setEvent(result);
}
}
}));
}
protected void setEvent(EventDTO event) {
eventDTO = event;
onEventUpdated();
}
private void onEventUpdated() {
fireEvent(new EventDTOLoadedEvent(eventDTO));
for (EventAndRaceGroupAvailabilityListener listener : this.eventRaceGroupListeners) {
listener.onEventUpdated(eventDTO);
}
checkToEnableSettingsButton();
}
private void retrieveRegattaStructure() {
sailingService.getRegattaStructureForEvent(regattaOverviewContextDefinition.getEvent(), new MarkedAsyncCallback<List<RaceGroupDTO>>(
new AsyncCallback<List<RaceGroupDTO>>() {
@Override
public void onFailure(Throwable cause) {
errorReporter.reportError("Error trying to load regattas for event with id " + regattaOverviewContextDefinition.getEvent() + " : "
+ cause.getMessage());
}
@Override
public void onSuccess(List<RaceGroupDTO> result) {
if (result != null) {
setRaceGroups(result);
}
}
}));
}
protected void setRaceGroups(List<RaceGroupDTO> result) {
raceGroupDTOs.clear();
raceGroupDTOs.addAll(result);
onRaceGroupsUpdated();
}
private void onRaceGroupsUpdated() {
for (EventAndRaceGroupAvailabilityListener listener : this.eventRaceGroupListeners) {
listener.onRaceGroupsUpdated(raceGroupDTOs);
}
checkToEnableSettingsButton();
}
private void checkToEnableSettingsButton() {
if (eventDTO != null && raceGroupDTOs.size() > 0) {
settingsButton.setEnabled(true);
}
}
private void setEvent(EventDTO event) {
eventDTO = event;
fireEvent(new EventDTOLoadedEvent(eventDTO));
}
}
@@ -73,16 +73,15 @@ import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.shared.components.AbstractCompositeComponent;
import com.sap.sse.gwt.client.shared.components.Component;
import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent;
import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
import com.sap.sse.gwt.client.shared.settings.ComponentContext;
/**
* This component shows a table displaying the current state of races for a given event. Which races are shown depends
* on the setting {@link RegattaRaceStatesSettings}. Each entry shows what flags are currently displayed, what start
* time the race has and additional information, e.g. for Gate start.
*/
public class RegattaRaceStatesComponent extends AbstractCompositeComponent<RegattaRaceStatesSettings> implements
EventAndRaceGroupAvailabilityListener {
public class RegattaRaceStatesComponent extends AbstractCompositeComponent<RegattaRaceStatesSettings> {
public interface EntryHandler {
void onEntryClicked(RegattaOverviewEntryDTO entry);
@@ -136,22 +135,21 @@ public class RegattaRaceStatesComponent extends AbstractCompositeComponent<Regat
* Whenever this component makes a service call and receives an update on the current server time, the
* timer passed for this argument will be synchronized.
*/
public RegattaRaceStatesComponent(Component<?> parent, ComponentContext<?> context,
public RegattaRaceStatesComponent(Component<?> parent, ComponentContext<?> componentContext,
final SailingServiceAsync sailingService,
ErrorReporter errorReporter,
final StringMessages stringMessages, final UUID eventId, RegattaRaceStatesSettings settings,
final StringMessages stringMessages, UUID eventId, EventDTO eventDTO, List<RaceGroupDTO> raceGroupDTOs, RegattaRaceStatesSettings settings,
Timer timerToSynchronize) {
super(parent, context);
super(parent, componentContext);
this.eventId = eventId;
this.sailingService = sailingService;
this.stringMessages = stringMessages;
this.eventId = eventId;
this.allEntries = new ArrayList<RegattaOverviewEntryDTO>();
this.timerToSynchronize = timerToSynchronize;
this.eventDTO = null;
this.raceGroupDTOs = null;
this.flagInterpreter = new RaceStateFlagsInterpreter(stringMessages);
this.settings = new RegattaRaceStatesSettings();
updateSettings(settings);
mainPanel = new VerticalPanel();
mainPanel.getElement().getStyle().setWidth(100, Unit.PCT);
regattaOverviewDataProvider = new ListDataProvider<RegattaOverviewEntryDTO>();
@@ -160,6 +158,9 @@ public class RegattaRaceStatesComponent extends AbstractCompositeComponent<Regat
mainPanel.add(tableHolder);
initWidget(mainPanel);
getElement().getStyle().setWidth(100, Unit.PCT);
this.eventDTO = eventDTO;
setRaceGroups(raceGroupDTOs);
updateSettings(settings);
}
public void onUpdateServer() {
@@ -346,7 +347,7 @@ public class RegattaRaceStatesComponent extends AbstractCompositeComponent<Regat
}
protected void loadAndUpdateEventLog() {
if (eventId == null || eventDTO == null || raceGroupDTOs == null) {
if (eventDTO == null || raceGroupDTOs == null) {
return;
}
final long clientTimeWhenRequestWasSent = System.currentTimeMillis();
@@ -727,7 +728,7 @@ public class RegattaRaceStatesComponent extends AbstractCompositeComponent<Regat
}
@Override
public SettingsDialogComponent<RegattaRaceStatesSettings> getSettingsDialogComponent() {
public SettingsDialogComponent<RegattaRaceStatesSettings> getSettingsDialogComponent(RegattaRaceStatesSettings settings) {
return new RegattaRaceStatesSettingsDialogComponent(settings, stringMessages,
Collections.unmodifiableList(eventDTO.venue.getCourseAreas()),
Collections.unmodifiableList(raceGroupDTOs));
@@ -775,15 +776,7 @@ public class RegattaRaceStatesComponent extends AbstractCompositeComponent<Regat
return this;
}
@Override
public void onEventUpdated(EventDTO event) {
eventDTO = event;
setDefaultCourseAreas();
refreshTableWithNewSettings();
}
@Override
public void onRaceGroupsUpdated(List<RaceGroupDTO> raceGroups) {
private void setRaceGroups(List<RaceGroupDTO> raceGroups) {
raceGroupDTOs = raceGroups;
GWT.log("onRaceGroupsUpdated");
if (raceGroupDTOs != null) {
@@ -817,8 +810,6 @@ public class RegattaRaceStatesComponent extends AbstractCompositeComponent<Regat
// }
// }
// regattaOverviewTable.redraw();
setDefaultRegattas();
refreshTableWithNewSettings();
}
private DialogBox createCourseViewDialogBox(RaceInfoDTO raceInfoDTO) {
@@ -1,13 +1,24 @@
package com.sap.sailing.gwt.regattaoverview.client;
import java.util.List;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
import com.sap.sailing.gwt.ui.shared.RaceGroupDTO;
import com.sap.sse.gwt.client.shared.components.ComponentLifecycle;
public class RegattaRaceStatesComponentLifecycle implements ComponentLifecycle<RegattaRaceStatesSettings> {
public static final String ID = "rrs";
private List<CourseAreaDTO> courseAreaDTOs;
private List<RaceGroupDTO> raceGroupDTOs;
public RegattaRaceStatesComponentLifecycle(List<CourseAreaDTO> courseAreaDTOs, List<RaceGroupDTO> raceGroupDTOs) {
this.courseAreaDTOs = courseAreaDTOs;
this.raceGroupDTOs = raceGroupDTOs;
}
@Override
public RegattaRaceStatesSettingsDialogComponent getSettingsDialogComponent(RegattaRaceStatesSettings settings) {
// TODO implement if needed
@@ -19,7 +30,14 @@ public class RegattaRaceStatesComponentLifecycle implements ComponentLifecycle<R
@Override
public RegattaRaceStatesSettings createDefaultSettings() {
return new RegattaRaceStatesSettings();
RegattaRaceStatesSettings settings = new RegattaRaceStatesSettings();
if(courseAreaDTOs != null) {
settings.setDefaultCourseAreas(courseAreaDTOs);
}
if(raceGroupDTOs != null) {
settings.setDefaultRegattas(raceGroupDTOs);
}
return settings;
}
@Override
@@ -38,13 +56,13 @@ public class RegattaRaceStatesComponentLifecycle implements ComponentLifecycle<R
}
@Override
public RegattaRaceStatesSettings extractGlobalSettings(RegattaRaceStatesSettings settings) {
public RegattaRaceStatesSettings extractUserSettings(RegattaRaceStatesSettings settings) {
return settings.createInstanceWithSettings(null, null, settings.isShowOnlyRacesOfSameDay(),
settings.isShowOnlyCurrentlyRunningRaces());
}
@Override
public RegattaRaceStatesSettings extractContextSpecificSettings(RegattaRaceStatesSettings settings) {
public RegattaRaceStatesSettings extractDocumentSettings(RegattaRaceStatesSettings settings) {
return settings;
}
}
@@ -25,12 +25,12 @@ public abstract class AbstractLeaderboardPerspectiveLifecycle extends AbstractPe
}
@Override
protected LeaderboardPerspectiveOwnSettings extractOwnGlobalSettings(LeaderboardPerspectiveOwnSettings settings) {
protected LeaderboardPerspectiveOwnSettings extractOwnUserSettings(LeaderboardPerspectiveOwnSettings settings) {
return settings;
}
@Override
protected LeaderboardPerspectiveOwnSettings extractOwnContextSettings(LeaderboardPerspectiveOwnSettings settings) {
protected LeaderboardPerspectiveOwnSettings extractOwnDocumentSettings(LeaderboardPerspectiveOwnSettings settings) {
return settings;
}
@@ -5,6 +5,7 @@ import java.util.List;
import com.sap.sailing.domain.common.dto.AbstractLeaderboardDTO;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.common.settings.generic.support.SettingsUtil;
import com.sap.sse.gwt.client.shared.components.ComponentLifecycle;
public class LeaderboardPanelLifecycle
@@ -27,7 +28,7 @@ public class LeaderboardPanelLifecycle
@Override
public LeaderboardSettings createDefaultSettings() {
return LeaderboardSettingsFactory.getInstance()
.createNewSettingsWithCustomDefaults(new LeaderboardSettings(namesOfRaceColumns));
.createNewDefaultSettingsWithRaceColumns(namesOfRaceColumns);
}
@Override
@@ -46,8 +47,8 @@ public class LeaderboardPanelLifecycle
}
@Override
public LeaderboardSettings extractGlobalSettings(LeaderboardSettings currentLeaderboardSettings) {
LeaderboardSettings defaultLeaderboardSettings = currentLeaderboardSettings.getDefaultSettings();
public LeaderboardSettings extractUserSettings(LeaderboardSettings currentLeaderboardSettings) {
LeaderboardSettings defaultLeaderboardSettings = createDefaultSettings();
LeaderboardSettings globalLeaderboardSettings = new LeaderboardSettings(
currentLeaderboardSettings.getManeuverDetailsToShow(), currentLeaderboardSettings.getLegDetailsToShow(),
currentLeaderboardSettings.getRaceDetailsToShow(), currentLeaderboardSettings.getOverallDetailsToShow(),
@@ -64,13 +65,11 @@ public class LeaderboardPanelLifecycle
currentLeaderboardSettings.isShowCompetitorSailIdColumn(),
currentLeaderboardSettings.isShowCompetitorFullNameColumn(),
currentLeaderboardSettings.isShowCompetitorNationality());
globalLeaderboardSettings = LeaderboardSettingsFactory.getInstance().keepDefaults(currentLeaderboardSettings,
globalLeaderboardSettings);
return globalLeaderboardSettings;
return SettingsUtil.copyValues(globalLeaderboardSettings, defaultLeaderboardSettings);
}
@Override
public LeaderboardSettings extractContextSpecificSettings(LeaderboardSettings leaderboardSettings) {
public LeaderboardSettings extractDocumentSettings(LeaderboardSettings leaderboardSettings) {
return leaderboardSettings;
}
@@ -7,10 +7,6 @@ public class LeaderboardPerspectiveLifecycle extends AbstractLeaderboardPerspect
public static final String ID = "lbh";
public LeaderboardPerspectiveLifecycle(StringMessages stringMessages) {
this(stringMessages, null);
}
public LeaderboardPerspectiveLifecycle(StringMessages stringMessages, AbstractLeaderboardDTO leaderboard) {
super(stringMessages, leaderboard, false);
addLifeCycle(new OverallLeaderboardPanelLifecycle(null, stringMessages));
@@ -5,19 +5,18 @@ import java.util.Collection;
import java.util.List;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.gwt.settings.client.settingtypes.converter.DetailTypeStringToEnumConverter;
import com.sap.sailing.gwt.settings.client.settingtypes.converter.RaceColumnSelectionStrategiesStringToEnumConverter;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardEntryPoint;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
import com.sap.sse.common.Util;
import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings;
import com.sap.sse.common.settings.generic.BooleanSetting;
import com.sap.sse.common.settings.generic.EnumListSetting;
import com.sap.sse.common.settings.generic.EnumSetSetting;
import com.sap.sse.common.settings.generic.EnumSetting;
import com.sap.sse.common.settings.generic.IntegerSetting;
import com.sap.sse.common.settings.generic.LongSetting;
import com.sap.sse.common.settings.generic.StringListSetting;
import com.sap.sse.common.settings.generic.StringSetSetting;
import com.sap.sse.common.settings.generic.StringSetting;
import com.sap.sse.common.settings.util.SettingsDefaultValuesUtils;
/**
* Settings for the {@link LeaderboardPanel} component. If you change here, please also visit
@@ -34,23 +33,23 @@ public class LeaderboardSettings extends AbstractGenericSerializableSettings {
* Only one of {@link #namesOfRaceColumnsToShow} and {@link #namesOfRacesToShow} must be non-<code>null</code>.
* Only valid when the {@link #activeRaceColumnSelectionStrategy} is set to EXPLIZIT
*/
private StringListSetting namesOfRaceColumnsToShow;
private StringSetSetting namesOfRaceColumnsToShow;
/**
* Only one of {@link #namesOfRaceColumnsToShow} and {@link #namesOfRacesToShow} must be non-<code>null</code>.
* Only valid when the {@link #activeRaceColumnSelectionStrategy} is set to EXPLIZIT
*/
private StringListSetting namesOfRacesToShow;
private StringSetSetting namesOfRacesToShow;
/**
* Only valid when the {@link #activeRaceColumnSelectionStrategy} is set to LAST_N
*/
private IntegerSetting numberOfLastRacesToShow;
private EnumListSetting<DetailType> maneuverDetailsToShow;
private EnumListSetting<DetailType> legDetailsToShow;
private EnumListSetting<DetailType> raceDetailsToShow;
private EnumListSetting<DetailType> overallDetailsToShow;
private EnumSetSetting<DetailType> maneuverDetailsToShow;
private EnumSetSetting<DetailType> legDetailsToShow;
private EnumSetSetting<DetailType> raceDetailsToShow;
private EnumSetSetting<DetailType> overallDetailsToShow;
private boolean autoExpandPreSelectedRace = false;
private LongSetting delayBetweenAutoAdvancesInMilliseconds;
private BooleanSetting updateUponPlayStateChange;
@@ -87,27 +86,27 @@ public class LeaderboardSettings extends AbstractGenericSerializableSettings {
@Override
protected void addChildSettings() {
isShowCompetitorNationality = new BooleanSetting("showCompetitorNationality", this, false);
namesOfRaceColumnsToShow = new StringListSetting("namesOfRaceColumnsToShow", this);
namesOfRacesToShow = new StringListSetting("namesOfRacesToShow", this, null);
namesOfRaceColumnsToShow = new StringSetSetting("namesOfRaceColumnsToShow", this);
namesOfRacesToShow = new StringSetSetting("namesOfRacesToShow", this, null);
numberOfLastRacesToShow = new IntegerSetting("numberOfLastRacesToShow", this, null);
List<DetailType> maneuverDetails = new ArrayList<DetailType>();
maneuverDetails.add(DetailType.TACK);
maneuverDetails.add(DetailType.JIBE);
maneuverDetails.add(DetailType.PENALTY_CIRCLE);
maneuverDetailsToShow = new EnumListSetting<>("maneuverDetailsToShow", this, maneuverDetails, new DetailTypeStringToEnumConverter());
maneuverDetailsToShow = new EnumSetSetting<>("maneuverDetailsToShow", this, maneuverDetails, DetailType::valueOf);
List<DetailType> legDetails = new ArrayList<DetailType>();
legDetails.add(DetailType.DISTANCE_TRAVELED);
legDetails.add(DetailType.AVERAGE_SPEED_OVER_GROUND_IN_KNOTS);
legDetails.add(DetailType.RANK_GAIN);
legDetailsToShow = new EnumListSetting<>("legDetailsToShow", this, legDetails, new DetailTypeStringToEnumConverter());
legDetailsToShow = new EnumSetSetting<>("legDetailsToShow", this, legDetails, DetailType::valueOf);
List<DetailType> raceDetails = new ArrayList<DetailType>();
raceDetails.add(DetailType.DISPLAY_LEGS);
raceDetailsToShow = new EnumListSetting<>("raceDetailsToShow", this, raceDetails, new DetailTypeStringToEnumConverter());
raceDetailsToShow = new EnumSetSetting<>("raceDetailsToShow", this, raceDetails, DetailType::valueOf);
List<DetailType> overallDetails = new ArrayList<>();
overallDetails.add(DetailType.REGATTA_RANK);
overallDetailsToShow = new EnumListSetting<>("overallDetailsToShow", this, overallDetails, new DetailTypeStringToEnumConverter());
overallDetailsToShow = new EnumSetSetting<>("overallDetailsToShow", this, overallDetails, DetailType::valueOf);
delayBetweenAutoAdvancesInMilliseconds = new LongSetting("delayBetweenAutoAdvancesInMilliseconds", this, LeaderboardEntryPoint.DEFAULT_REFRESH_INTERVAL_MILLIS);
activeRaceColumnSelectionStrategy = new EnumSetting<>("activeRaceColumnSelectionStrategy", this, RaceColumnSelectionStrategies.EXPLICIT, new RaceColumnSelectionStrategiesStringToEnumConverter());
activeRaceColumnSelectionStrategy = new EnumSetting<>("activeRaceColumnSelectionStrategy", this, RaceColumnSelectionStrategies.EXPLICIT, RaceColumnSelectionStrategies::valueOf);
nameOfRaceToSort = new StringSetting("nameOfRaceToSort", this, null);
updateUponPlayStateChange = new BooleanSetting("updateUponPlayStateChange", this, true);
sortAscending = new BooleanSetting("sortAscending", this, true);
@@ -124,35 +123,11 @@ public class LeaderboardSettings extends AbstractGenericSerializableSettings {
this.namesOfRaceColumnsToShow.setValues(namesOfRaceColumnsToShow);
}
public LeaderboardSettings(Iterable<String> namesOfRaceColumnsToShow, Long delayBetweenAutoAdvancesInMilliseconds) {
this.namesOfRaceColumnsToShow.setValues(namesOfRaceColumnsToShow);
this.delayBetweenAutoAdvancesInMilliseconds.setValue(delayBetweenAutoAdvancesInMilliseconds);
}
public LeaderboardSettings(Long delayBetweenAutoAdvancesInMilliseconds, Integer numberOfLastRacesToShow,
RaceColumnSelectionStrategies activeRaceColumnSelectionStrategy) {
this.delayBetweenAutoAdvancesInMilliseconds.setValue(delayBetweenAutoAdvancesInMilliseconds);
this.numberOfLastRacesToShow.setValue(numberOfLastRacesToShow);
this.activeRaceColumnSelectionStrategy.setValue(activeRaceColumnSelectionStrategy);
}
public LeaderboardSettings(List<String> namesOfRaceColumnsToShow, List<String> namesOfRacesToShow, List<DetailType> overallDetailsToShow,
String nameOfRaceToSort, boolean autoExpandPreSelectedRace,
boolean showCompetitorSailIdColumn, boolean showCompetitorFullNameColumn) {
this.namesOfRaceColumnsToShow.setValues(namesOfRaceColumnsToShow);
this.namesOfRacesToShow.setValues(namesOfRacesToShow);
this.overallDetailsToShow.setValues(overallDetailsToShow);
this.nameOfRaceToSort.setValue(nameOfRaceToSort);
this.autoExpandPreSelectedRace = autoExpandPreSelectedRace;
this.showCompetitorSailIdColumn.setValue(showCompetitorSailIdColumn);
this.showCompetitorFullNameColumn.setValue(showCompetitorFullNameColumn);
}
/**
* @param raceColumnsToShow <code>null</code> means don't modify the list of races shown
*/
public LeaderboardSettings(List<DetailType> maneuverDetailsToShow, List<DetailType> legDetailsToShow,
List<DetailType> raceDetailsToShow, List<DetailType> overallDetailsToShow,
public LeaderboardSettings(Collection<DetailType> maneuverDetailsToShow, Collection<DetailType> legDetailsToShow,
Collection<DetailType> raceDetailsToShow, Collection<DetailType> overallDetailsToShow,
List<String> namesOfRaceColumnsToShow, List<String> namesOfRacesToShow, Integer numberOfLastRacesToShow,
boolean autoExpandPreSelectedRace, Long delayBetweenAutoAdvancesInMilliseconds, String nameOfRaceToSort,
boolean sortAscending, boolean updateUponPlayStateChange, RaceColumnSelectionStrategies activeRaceColumnSelectionStrategy,
@@ -182,32 +157,33 @@ public class LeaderboardSettings extends AbstractGenericSerializableSettings {
this.isShowCompetitorNationality.setValue(isCompetitorNationalityColumnVisible);
}
/**
* A live collection that reflects the current state of the settings of a leaderboard panel
*/
public List<DetailType> getManeuverDetailsToShow() {
return Util.createList(maneuverDetailsToShow.getValues());
public Collection<DetailType> getManeuverDetailsToShow() {
return Util.createSet(maneuverDetailsToShow.getValues());
}
/**
* A live collection that reflects the current state of the settings of a leaderboard panel
*/
public List<DetailType> getLegDetailsToShow() {
return Util.createList(legDetailsToShow.getValues());
public Collection<DetailType> getLegDetailsToShow() {
return Util.createSet(legDetailsToShow.getValues());
}
/**
* A live collection that reflects the current state of the settings of a leaderboard panel
*/
public List<DetailType> getRaceDetailsToShow() {
return Util.createList(raceDetailsToShow.getValues());
public Collection<DetailType> getRaceDetailsToShow() {
return Util.createSet(raceDetailsToShow.getValues());
}
/**
* A live collection that reflects the current state of the settings of a leaderboard panel
*/
public List<DetailType> getOverallDetailsToShow() {
return Util.createList(overallDetailsToShow.getValues());
public Collection<DetailType> getOverallDetailsToShow() {
return Util.createSet(overallDetailsToShow.getValues());
}
/**
@@ -288,83 +264,34 @@ public class LeaderboardSettings extends AbstractGenericSerializableSettings {
return isShowCompetitorNationality.getValue();
}
void overrideDefaultValues(LeaderboardSettings newDefaults) {
autoExpandPreSelectedRace = newDefaults.autoExpandPreSelectedRace;
boolean namesOfRaceColumnsToShowWasDefault = Util.equals(namesOfRaceColumnsToShow.getValues(), namesOfRaceColumnsToShow.getDefaultValues());
namesOfRaceColumnsToShow.setDefaultValues(newDefaults.namesOfRaceColumnsToShow.getValues());
namesOfRacesToShow.setDefaultValues(newDefaults.namesOfRacesToShow.getValues());
if(getNamesOfRaceColumnsToShow() != null && getNamesOfRacesToShow() != null) {
if(namesOfRaceColumnsToShowWasDefault) {
namesOfRaceColumnsToShow.setValues(null);
} else {
namesOfRacesToShow.setValues(null);
}
public LeaderboardSettings overrideDefaultsForNamesOfRaceColumns(List<String> namesOfRaceColumns) {
LeaderboardSettings newSettings = new LeaderboardSettings();
newSettings.legDetailsToShow.setValues(this.getLegDetailsToShow());
newSettings.raceDetailsToShow.setValues(this.getRaceDetailsToShow());
newSettings.overallDetailsToShow.setValues(this.getOverallDetailsToShow());
newSettings.numberOfLastRacesToShow.setValue(this.getNumberOfLastRacesToShow());
newSettings.activeRaceColumnSelectionStrategy.setValue(this.getActiveRaceColumnSelectionStrategy());
newSettings.autoExpandPreSelectedRace = this.isAutoExpandPreSelectedRace();
newSettings.delayBetweenAutoAdvancesInMilliseconds.setValue(this.getDelayBetweenAutoAdvancesInMilliseconds());
newSettings.maneuverDetailsToShow.setValues(this.getManeuverDetailsToShow());
newSettings.nameOfRaceToSort.setValue(this.getNameOfRaceToSort());
newSettings.sortAscending.setValue(this.isSortAscending());
newSettings.updateUponPlayStateChange.setValue(this.isUpdateUponPlayStateChange());
newSettings.showAddedScores.setValue(this.isShowAddedScores());
newSettings.showCompetitorSailIdColumn.setValue(this.isShowCompetitorSailIdColumn());
newSettings.showCompetitorFullNameColumn.setValue(this.isShowCompetitorFullNameColumn());
newSettings.showOverallColumnWithNumberOfRacesCompletedPerCompetitor.setValue(this.isShowOverallColumnWithNumberOfRacesCompletedPerCompetitor());
newSettings.isShowCompetitorNationality.setValue(this.isShowCompetitorNationality());
if(namesOfRaceColumns != null && !namesOfRaceColumns.isEmpty()) {
newSettings.namesOfRacesToShow.setValues(null);
}
numberOfLastRacesToShow.setDefaultValue(newDefaults.numberOfLastRacesToShow.getValue());
maneuverDetailsToShow.setDefaultValues(newDefaults.maneuverDetailsToShow.getValues());
legDetailsToShow.setDefaultValues(newDefaults.legDetailsToShow.getValues());
raceDetailsToShow.setDefaultValues(newDefaults.raceDetailsToShow.getValues());
overallDetailsToShow.setDefaultValues(newDefaults.overallDetailsToShow.getValues());
delayBetweenAutoAdvancesInMilliseconds.setDefaultValue(newDefaults.delayBetweenAutoAdvancesInMilliseconds.getValue());
activeRaceColumnSelectionStrategy.setDefaultValue(newDefaults.activeRaceColumnSelectionStrategy.getValue());
nameOfRaceToSort.setDefaultValue(newDefaults.nameOfRaceToSort.getValue());
updateUponPlayStateChange.setDefaultValue(newDefaults.updateUponPlayStateChange.getValue());
sortAscending.setDefaultValue(newDefaults.sortAscending.getValue());
showAddedScores.setDefaultValue(newDefaults.showAddedScores.getValue());
showCompetitorSailIdColumn.setDefaultValue(newDefaults.showCompetitorSailIdColumn.getValue());
showCompetitorFullNameColumn.setDefaultValue(newDefaults.showCompetitorFullNameColumn.getValue());
showOverallColumnWithNumberOfRacesCompletedPerCompetitor.setDefaultValue(newDefaults.showOverallColumnWithNumberOfRacesCompletedPerCompetitor.getValue());
isShowCompetitorNationality.setDefaultValue(newDefaults.isShowCompetitorNationality.getValue());
newSettings.namesOfRaceColumnsToShow.setValues(this.getNamesOfRaceColumnsToShow());
SettingsDefaultValuesUtils.keepDefaults(this, newSettings);
if(namesOfRaceColumns != null && !namesOfRaceColumns.isEmpty()) {
newSettings.namesOfRacesToShow.setDefaultValues(null);
}
newSettings.namesOfRaceColumnsToShow.setDefaultValues(namesOfRaceColumns);
return newSettings;
}
void setValues(LeaderboardSettings settingsWithCustomValues) {
this.legDetailsToShow.setValues(settingsWithCustomValues.getLegDetailsToShow());
this.raceDetailsToShow.setValues(settingsWithCustomValues.getRaceDetailsToShow());
this.overallDetailsToShow.setValues(settingsWithCustomValues.getOverallDetailsToShow());
this.namesOfRacesToShow.setValues(settingsWithCustomValues.getNamesOfRacesToShow());
this.namesOfRaceColumnsToShow.setValues(settingsWithCustomValues.getNamesOfRaceColumnsToShow());
this.numberOfLastRacesToShow.setValue(settingsWithCustomValues.getNumberOfLastRacesToShow());
this.activeRaceColumnSelectionStrategy.setValue(settingsWithCustomValues.getActiveRaceColumnSelectionStrategy());
this.autoExpandPreSelectedRace = settingsWithCustomValues.isAutoExpandPreSelectedRace();
this.delayBetweenAutoAdvancesInMilliseconds.setValue(settingsWithCustomValues.getDelayBetweenAutoAdvancesInMilliseconds());
this.maneuverDetailsToShow.setValues(settingsWithCustomValues.getManeuverDetailsToShow());
this.nameOfRaceToSort.setValue(settingsWithCustomValues.getNameOfRaceToSort());
this.sortAscending.setValue(settingsWithCustomValues.isSortAscending());
this.updateUponPlayStateChange.setValue(settingsWithCustomValues.isUpdateUponPlayStateChange());
this.showAddedScores.setValue(settingsWithCustomValues.isShowAddedScores());
this.showCompetitorSailIdColumn.setValue(settingsWithCustomValues.isShowCompetitorSailIdColumn());
this.showCompetitorFullNameColumn.setValue(settingsWithCustomValues.isShowCompetitorFullNameColumn());
this.isShowCompetitorNationality.setValue(settingsWithCustomValues.isShowCompetitorNationality());
this.showOverallColumnWithNumberOfRacesCompletedPerCompetitor.setValue(settingsWithCustomValues.isShowOverallColumnWithNumberOfRacesCompletedPerCompetitor());
}
public LeaderboardSettings getDefaultSettings() {
LeaderboardSettings leaderboardSettings = new LeaderboardSettings();
leaderboardSettings.legDetailsToShow.setDefaultValues(legDetailsToShow.getDefaultValues());
leaderboardSettings.raceDetailsToShow.setDefaultValues(raceDetailsToShow.getDefaultValues());
leaderboardSettings.overallDetailsToShow.setDefaultValues(overallDetailsToShow.getDefaultValues());
leaderboardSettings.namesOfRacesToShow.setDefaultValues(namesOfRacesToShow.getDefaultValues());
leaderboardSettings.namesOfRaceColumnsToShow.setDefaultValues(namesOfRaceColumnsToShow.getDefaultValues());
leaderboardSettings.numberOfLastRacesToShow.setDefaultValue(numberOfLastRacesToShow.getDefaultValue());
leaderboardSettings.activeRaceColumnSelectionStrategy.setDefaultValue(activeRaceColumnSelectionStrategy.getDefaultValue());
leaderboardSettings.autoExpandPreSelectedRace = autoExpandPreSelectedRace;
leaderboardSettings.delayBetweenAutoAdvancesInMilliseconds.setDefaultValue(delayBetweenAutoAdvancesInMilliseconds.getDefaultValue());
leaderboardSettings.maneuverDetailsToShow.setDefaultValues(maneuverDetailsToShow.getDefaultValues());
leaderboardSettings.nameOfRaceToSort.setDefaultValue(nameOfRaceToSort.getDefaultValue());
leaderboardSettings.sortAscending.setDefaultValue(sortAscending.getDefaultValue());
leaderboardSettings.updateUponPlayStateChange.setDefaultValue(updateUponPlayStateChange.getDefaultValue());
leaderboardSettings.showAddedScores.setDefaultValue(showAddedScores.getDefaultValue());
leaderboardSettings.showCompetitorSailIdColumn.setDefaultValue(showCompetitorSailIdColumn.getDefaultValue());
leaderboardSettings.showCompetitorFullNameColumn.setDefaultValue(showCompetitorFullNameColumn.getDefaultValue());
leaderboardSettings.showOverallColumnWithNumberOfRacesCompletedPerCompetitor.setDefaultValue(showOverallColumnWithNumberOfRacesCompletedPerCompetitor.getDefaultValue());
leaderboardSettings.isShowCompetitorNationality.setDefaultValue(isShowCompetitorNationality.getDefaultValue());
return leaderboardSettings;
}
public static LeaderboardSettings createDefaultSettings(Collection<String> defaultNamesOfRaceColumnsToShow) {
LeaderboardSettings leaderboardSettings = new LeaderboardSettings();
leaderboardSettings.namesOfRaceColumnsToShow.setDefaultValues(defaultNamesOfRaceColumnsToShow);
return leaderboardSettings;
}
}
@@ -1,6 +1,7 @@
package com.sap.sailing.gwt.settings.client.leaderboard;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -29,6 +30,7 @@ import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
import com.sap.sailing.gwt.ui.leaderboard.LegColumn;
import com.sap.sailing.gwt.ui.leaderboard.ManeuverCountRaceColumn;
import com.sap.sse.common.Util;
import com.sap.sse.common.settings.util.SettingsDefaultValuesUtils;
import com.sap.sse.gwt.client.controls.IntegerBox;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.Validator;
@@ -89,7 +91,7 @@ public class LeaderboardSettingsDialogComponent implements SettingsDialogCompone
meneuverPanel.addStyleName("SettingsDialogComponent");
FlowPanel meneuverContent = new FlowPanel();
meneuverContent.addStyleName("dialogInnerContent");
List<DetailType> currentMeneuverDetailSelection = initialSettings.getManeuverDetailsToShow();
Collection<DetailType> currentMeneuverDetailSelection = initialSettings.getManeuverDetailsToShow();
for (DetailType detailType : ManeuverCountRaceColumn.getAvailableManeuverDetailColumnTypes()) {
CheckBox checkbox = createAndRegisterCheckbox(dialog, detailType,
currentMeneuverDetailSelection.contains(detailType), maneuverDetailCheckboxes);
@@ -131,7 +133,7 @@ public class LeaderboardSettingsDialogComponent implements SettingsDialogCompone
raceDetailDialog.add(dialog.createHeadline(stringMessages.raceDetailsToShow(), true));
raceDetailDialog.addStyleName("SettingsDialogComponent");
int detailCountInCurrentFlowPanel = 0;
List<DetailType> currentRaceDetailSelection = initialSettings.getRaceDetailsToShow();
Collection<DetailType> currentRaceDetailSelection = initialSettings.getRaceDetailsToShow();
FlowPanel raceDetailDialogContent = null;
for (DetailType type : LeaderboardPanel.getAvailableRaceDetailColumnTypes()) {
if (detailCountInCurrentFlowPanel % 8 == 0) {
@@ -161,7 +163,7 @@ public class LeaderboardSettingsDialogComponent implements SettingsDialogCompone
raceStartAnalysisDialog.add(dialog.createHeadline(stringMessages.raceStartAnalysis(), true));
raceStartAnalysisDialog.addStyleName("SettingsDialogComponent");
int detailCountInCurrentFlowPanel = 0;
List<DetailType> currentRaceDetailSelection = initialSettings.getRaceDetailsToShow();
Collection<DetailType> currentRaceDetailSelection = initialSettings.getRaceDetailsToShow();
FlowPanel raceStartAnalysisDialogContent = null;
for (DetailType type : LeaderboardPanel.getAvailableRaceStartAnalysisColumnTypes()) {
if (detailCountInCurrentFlowPanel % 8 == 0) {
@@ -184,7 +186,7 @@ public class LeaderboardSettingsDialogComponent implements SettingsDialogCompone
overallDetailDialog.addStyleName("SettingsDialogComponent overallDetailSettings");
FlowPanel overallDetailDialogContent = new FlowPanel();
overallDetailDialogContent.addStyleName("dialogInnerContent");
List<DetailType> currentOverallDetailSelection = initialSettings.getOverallDetailsToShow();
Collection<DetailType> currentOverallDetailSelection = initialSettings.getOverallDetailsToShow();
for (DetailType type : LeaderboardPanel.getAvailableOverallDetailColumnTypes()) {
CheckBox checkbox = createAndRegisterCheckbox(dialog, type, currentOverallDetailSelection.contains(type),
overallDetailCheckboxes);
@@ -220,7 +222,7 @@ public class LeaderboardSettingsDialogComponent implements SettingsDialogCompone
legDetailsToShow.add(dialog.createHeadline(stringMessages.legDetailsToShow(), true));
legDetailsToShow.addStyleName("SettingsDialogComponent");
FlowPanel legDetailsContent = null;
List<DetailType> currentLegDetailSelection = initialSettings.getLegDetailsToShow();
Collection<DetailType> currentLegDetailSelection = initialSettings.getLegDetailsToShow();
int detailCountInCurrentFlowPanel = 0;
for (DetailType type : LegColumn.getAvailableLegDetailColumnTypes()) {
if (detailCountInCurrentFlowPanel % 8 == 0) {
@@ -402,7 +404,8 @@ public class LeaderboardSettingsDialogComponent implements SettingsDialogCompone
/*showOverallColumnWithNumberOfRacesSailedPerCompetitor*/ showOverallColumnWithNumberOfRacesSailedPerCompetitorCheckBox.getValue().booleanValue(),
showCompetitorSailIdColumnheckBox.getValue(), showCompetitorFullNameColumnCheckBox.getValue(),
isCompetitorNationalityColumnVisible.getValue());
return LeaderboardSettingsFactory.getInstance().keepDefaults(initialSettings, newSettings);
SettingsDefaultValuesUtils.keepDefaults(initialSettings, newSettings);
return newSettings;
}
@Override
@@ -1,14 +1,14 @@
package com.sap.sailing.gwt.settings.client.leaderboard;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collection;
import java.util.List;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardSettings.RaceColumnSelectionStrategies;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
import com.sap.sse.common.Util;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.common.settings.generic.support.SettingsUtil;
import com.sap.sse.common.settings.util.SettingsDefaultValuesUtils;
/**
* A factory class creating leaderboard settings for different contexts (user role, live or replay mode, etc.
@@ -16,201 +16,71 @@ import com.sap.sse.gwt.client.player.Timer.PlayModes;
public class LeaderboardSettingsFactory {
private static LeaderboardSettingsFactory instance;
public synchronized static LeaderboardSettingsFactory getInstance() {
public static LeaderboardSettingsFactory getInstance() {
if (instance == null) {
instance = new LeaderboardSettingsFactory();
}
return instance;
}
/**
* @param nameOfRaceToSort
* if <code>null</code>, don't sort any race column
* @param nameOfRaceColumnToShow
* if <code>null</code>, the settings returned will cause the list of race columns shown to remain
* unchanged during {@link LeaderboardPanel#updateSettings(LeaderboardSettings)}; otherwise, the settings
* will show the single race column identified by this argument
* @param nameOfRaceToShow
* alternatively to <code>nameOfRaceColumnToShow</code>, this argument may be used in case the race name
* is known, but its column name is not. If <code>null</code>, and <code>nameOfRaceColumnToShow</code> is
* also <code>null</code>, no change to the selected race columns will happen while updating the
* leaderboard settings. It is an error to pass non-<code>null</code> values for both,
* <code>nameOfRaceColumnToShow</code> <em>and</em> <code>nameOfRaceToShow</code>, and an
* {@link IllegalArgumentException} will be thrown in this case.
* @param raceColumnSelection
* the settings will be constructed such that the new settings will have the same race columns selected
* as those selected by this argument
* @param showRegattaRank
* if <code>null</code>, the overall detail settings that are responsible for deciding whether or not to
* show the regatta rank are left unchanged; otherwise, a non-<code>null</code> overall details
* collection will be put to the settings and the {@link DetailType#REGATTA_RANK} will be added to the
* overall details if and only if this parameter is <code>true</code>
* @param raceColumnSelectionType
* @param raceColumnSelection
*/
public LeaderboardSettings createNewSettingsForPlayMode(PlayModes playMode, String nameOfRaceToSort, String nameOfRaceColumnToShow,
String nameOfRaceToShow, boolean showRegattaRank, boolean showCompetitorSailIdColumn,
boolean showCompetitorNameColumn, Integer raceColumnSelectionNumber,
RaceColumnSelectionStrategies raceColumnSelectionType) {
if (nameOfRaceColumnToShow != null && nameOfRaceToShow != null) {
throw new IllegalArgumentException("Can identify only one race to show, either by race name or by its column name, but not both");
}
LeaderboardSettings settings = null;
List<String> namesOfRaceColumnsToShow = nameOfRaceColumnToShow == null ? null : Collections.singletonList(nameOfRaceColumnToShow);
List<String> namesOfRacesToShow = nameOfRaceToShow == null ? null : Collections.singletonList(nameOfRaceToShow);
switch (playMode) {
case Live:
List<DetailType> maneuverDetails = new ArrayList<DetailType>();
maneuverDetails.add(DetailType.TACK);
maneuverDetails.add(DetailType.JIBE);
maneuverDetails.add(DetailType.PENALTY_CIRCLE);
List<DetailType> legDetails = new ArrayList<DetailType>();
legDetails.add(DetailType.DISTANCE_TRAVELED);
legDetails.add(DetailType.AVERAGE_SPEED_OVER_GROUND_IN_KNOTS);
legDetails.add(DetailType.ESTIMATED_TIME_TO_NEXT_WAYPOINT_IN_SECONDS);
legDetails.add(DetailType.RANK_GAIN);
List<DetailType> raceDetails = new ArrayList<DetailType>();
raceDetails.add(DetailType.RACE_DISTANCE_TRAVELED);
raceDetails.add(DetailType.RACE_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS);
raceDetails.add(DetailType.RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS);
raceDetails.add(DetailType.NUMBER_OF_MANEUVERS);
raceDetails.add(DetailType.DISPLAY_LEGS);
final List<DetailType> overallDetails = createOverallDetailsForShowRegattaRank(showRegattaRank);
settings = new LeaderboardSettings(maneuverDetails, legDetails, raceDetails, overallDetails,
namesOfRaceColumnsToShow,
namesOfRacesToShow, raceColumnSelectionNumber,
/* set autoExpandPreSelectedRace to true if we look at a single race */ nameOfRaceColumnToShow != null || nameOfRaceToShow != null,
/* refresh interval */ null, /* name of race to sort */ nameOfRaceToSort,
/* ascending */ true, /* updateUponPlayStateChange */ true, raceColumnSelectionType,
/*showAddedScores*/ false, /*showOverallRacesCompleted*/ false,
showCompetitorSailIdColumn, showCompetitorNameColumn, false);
break;
case Replay:
settings = createNewDefaultSettings(namesOfRaceColumnsToShow, namesOfRacesToShow, nameOfRaceToSort, /* autoExpandFirstRace */
nameOfRaceColumnToShow != null, showRegattaRank, showCompetitorSailIdColumn, showCompetitorNameColumn);
break;
}
return settings;
}
/**
* @param showRegattaRank
* Puts overall details
* collection to the settings and adds {@link DetailType#REGATTA_RANK} to the
* overall details if and only if this parameter is <code>true</code>
*/
private List<DetailType> createOverallDetailsForShowRegattaRank(boolean showRegattaRank) {
final List<DetailType> overallDetails = new ArrayList<>();
if (showRegattaRank) {
overallDetails.add(DetailType.REGATTA_RANK);
}
return overallDetails;
}
/**
* @param namesOfRaceColumnsToShow
* if <code>null</code>, create settings which leave the list of races to show unchanged when applied
* using {@link LeaderboardPanel#updateSettings(LeaderboardSettings)}; otherwise, the list of names of
* the race columns (not their races!) that will be shown, so that, e.g., an empty list causes no race
* columns to be shown
* @param namesOfRacesToShow
* alternatively, races to show can also be specified by their race names; if not <code>null</code>,
* <code>namesOfRaceColumnsToShow</code> must be <code>null</code>
* @param showRegattaRank
* if <code>null</code>, the overall detail settings that are responsible for deciding whether or not to
* show the regatta rank are left unchanged; otherwise, a non-<code>null</code> overall details
* collection will be put to the settings and the {@link DetailType#REGATTA_RANK} will be added to the
* overall details if and only if this parameter is <code>true</code>
*/
private LeaderboardSettings createNewDefaultSettings(List<String> namesOfRaceColumnsToShow,
List<String> namesOfRacesToShow, String nameOfRaceToSort, boolean autoExpandPreSelectedRace, Boolean showRegattaRank,
boolean showCompetitorSailIdColumn, boolean showCompetitorFullNameColumn) {
final List<DetailType> overallDetails = createOverallDetailsForShowRegattaRank(showRegattaRank);
return new LeaderboardSettings(namesOfRaceColumnsToShow, namesOfRacesToShow, overallDetails,
nameOfRaceToSort, autoExpandPreSelectedRace,
showCompetitorSailIdColumn, showCompetitorFullNameColumn);
}
public LeaderboardSettings createNewSettingsWithCustomDefaults(LeaderboardSettings customDefaultSettings, LeaderboardSettings settingsWithCustomValues) {
LeaderboardSettings leaderboardSettings = new LeaderboardSettings();
leaderboardSettings.overrideDefaultValues(customDefaultSettings);
leaderboardSettings.setValues(settingsWithCustomValues);
public LeaderboardSettings createNewDefaultSettingsWithRaceColumns(List<String> namesOfRaceColumns) {
LeaderboardSettings leaderboardSettings = new LeaderboardSettings(namesOfRaceColumns);
SettingsUtil.copyDefaultsFromValues(leaderboardSettings, leaderboardSettings);
return leaderboardSettings;
}
public LeaderboardSettings createNewSettingsWithCustomDefaults(LeaderboardSettings customDefaultSettings) {
LeaderboardSettings leaderboardSettings = new LeaderboardSettings();
leaderboardSettings.overrideDefaultValues(customDefaultSettings);
return leaderboardSettings;
public LeaderboardSettings createNewSettingsWithCustomRaceDetails(List<DetailType> raceDetailsToShow) {
LeaderboardSettings defaultSettings = new LeaderboardSettings();
return new LeaderboardSettings(
defaultSettings.getManeuverDetailsToShow(),
defaultSettings.getLegDetailsToShow(),
raceDetailsToShow, defaultSettings.getOverallDetailsToShow(),
Util.cloneListOrNull(defaultSettings.getNamesOfRaceColumnsToShow()),
Util.cloneListOrNull(defaultSettings.getNamesOfRacesToShow()),
defaultSettings.getNumberOfLastRacesToShow(),
defaultSettings.isAutoExpandPreSelectedRace(),
defaultSettings.getDelayBetweenAutoAdvancesInMilliseconds(),
defaultSettings.getNameOfRaceToSort(), defaultSettings.isSortAscending(),
defaultSettings.isUpdateUponPlayStateChange(),
defaultSettings.getActiveRaceColumnSelectionStrategy(),
defaultSettings.isShowAddedScores(),
defaultSettings.isShowOverallColumnWithNumberOfRacesCompletedPerCompetitor(),
defaultSettings.isShowCompetitorSailIdColumn(),
defaultSettings.isShowCompetitorFullNameColumn(),
defaultSettings.isShowCompetitorNationality());
}
public LeaderboardSettings overrideDefaultValuesWithNewDefaults(LeaderboardSettings settingsWithCustomValues, LeaderboardSettings customDefaultSettings) {
LeaderboardSettings leaderboardSettings = new LeaderboardSettings();
leaderboardSettings.setValues(settingsWithCustomValues);
leaderboardSettings.overrideDefaultValues(customDefaultSettings);
return leaderboardSettings;
}
public LeaderboardSettings keepDefaults(LeaderboardSettings previousSettings, LeaderboardSettings newSettings) {
LeaderboardSettings leaderboardSettings = previousSettings.getDefaultSettings();
leaderboardSettings.setValues(newSettings);
return leaderboardSettings;
}
public LeaderboardSettings overrideDefaultValuesForRaceDetails(LeaderboardSettings existingSettings, List<DetailType> newRaceDetailsDefaultValues) {
LeaderboardSettings newSettings = new LeaderboardSettings(
Util.cloneListOrNull(existingSettings.getManeuverDetailsToShow()),
Util.cloneListOrNull(existingSettings.getLegDetailsToShow()),
newRaceDetailsDefaultValues, Util.cloneListOrNull(existingSettings.getOverallDetailsToShow()),
Util.cloneListOrNull(existingSettings.getNamesOfRaceColumnsToShow()),
Util.cloneListOrNull(existingSettings.getNamesOfRacesToShow()),
existingSettings.getNumberOfLastRacesToShow(), /* auto-expand pre-selected race */ true,
existingSettings.getDelayBetweenAutoAdvancesInMilliseconds(),
existingSettings.getNameOfRaceToSort(), existingSettings.isSortAscending(),
existingSettings.isUpdateUponPlayStateChange(),
existingSettings.getActiveRaceColumnSelectionStrategy(),
existingSettings.isShowAddedScores(),
existingSettings.isShowOverallColumnWithNumberOfRacesCompletedPerCompetitor(),
existingSettings.isShowCompetitorSailIdColumn(),
existingSettings.isShowCompetitorFullNameColumn(),
existingSettings.isShowCompetitorNationality());
final LeaderboardSettings existingDefaultSettings = existingSettings.getDefaultSettings();
LeaderboardSettings newDefaultSettings = new LeaderboardSettings(
Util.cloneListOrNull(existingDefaultSettings.getManeuverDetailsToShow()),
Util.cloneListOrNull(existingDefaultSettings.getLegDetailsToShow()),
newRaceDetailsDefaultValues, Util.cloneListOrNull(existingDefaultSettings.getOverallDetailsToShow()),
Util.cloneListOrNull(existingDefaultSettings.getNamesOfRaceColumnsToShow()),
Util.cloneListOrNull(existingDefaultSettings.getNamesOfRacesToShow()),
existingDefaultSettings.getNumberOfLastRacesToShow(), /* auto-expand pre-selected race */ true,
existingDefaultSettings.getDelayBetweenAutoAdvancesInMilliseconds(),
existingDefaultSettings.getNameOfRaceToSort(), existingDefaultSettings.isSortAscending(),
existingDefaultSettings.isUpdateUponPlayStateChange(),
existingDefaultSettings.getActiveRaceColumnSelectionStrategy(),
existingDefaultSettings.isShowAddedScores(),
existingDefaultSettings.isShowOverallColumnWithNumberOfRacesCompletedPerCompetitor(),
existingDefaultSettings.isShowCompetitorSailIdColumn(),
existingDefaultSettings.isShowCompetitorFullNameColumn(),
existingSettings.isShowCompetitorNationality());
newDefaultSettings = LeaderboardSettingsFactory.getInstance().createNewSettingsWithCustomDefaults(newDefaultSettings);
newSettings = LeaderboardSettingsFactory.getInstance().keepDefaults(newDefaultSettings, newSettings);
return newSettings;
public LeaderboardSettings createSettingsWithCustomExpandPreselectedRaceState(LeaderboardSettings settings, boolean expandPreselectedRace) {
return new LeaderboardSettings(
settings.getManeuverDetailsToShow(),
settings.getLegDetailsToShow(),
settings.getRaceDetailsToShow(), settings.getOverallDetailsToShow(),
Util.cloneListOrNull(settings.getNamesOfRaceColumnsToShow()),
Util.cloneListOrNull(settings.getNamesOfRacesToShow()),
settings.getNumberOfLastRacesToShow(), expandPreselectedRace,
settings.getDelayBetweenAutoAdvancesInMilliseconds(),
settings.getNameOfRaceToSort(), settings.isSortAscending(),
settings.isUpdateUponPlayStateChange(),
settings.getActiveRaceColumnSelectionStrategy(),
settings.isShowAddedScores(),
settings.isShowOverallColumnWithNumberOfRacesCompletedPerCompetitor(),
settings.isShowCompetitorSailIdColumn(),
settings.isShowCompetitorFullNameColumn(),
settings.isShowCompetitorNationality());
}
public LeaderboardSettings mergeLeaderboardSettings(LeaderboardSettings settingsWithRaceSelection, LeaderboardSettings settingsWithDetails) {
LeaderboardSettings newSettings = mergeLeaderboardSettingsHelper(settingsWithRaceSelection, settingsWithDetails);
LeaderboardSettings newDefaultSettings = mergeLeaderboardSettingsHelper(settingsWithRaceSelection.getDefaultSettings(), settingsWithDetails.getDefaultSettings());
return keepDefaults(newDefaultSettings, newSettings);
LeaderboardSettings newDefaultSettings = mergeLeaderboardSettingsHelper(SettingsDefaultValuesUtils.getDefaultSettings(new LeaderboardSettings(), settingsWithRaceSelection), SettingsDefaultValuesUtils.getDefaultSettings(new LeaderboardSettings(), settingsWithDetails));
SettingsDefaultValuesUtils.keepDefaults(newDefaultSettings, newSettings);
return newSettings;
}
private LeaderboardSettings mergeLeaderboardSettingsHelper(LeaderboardSettings settingsWithRaceSelection, LeaderboardSettings settingsWithDetails) {
List<DetailType> maneuverDetails = copyDetailTypes(settingsWithDetails.getManeuverDetailsToShow());
List<DetailType> legDetails = copyDetailTypes(settingsWithDetails.getLegDetailsToShow());
List<DetailType> raceDetails = copyDetailTypes(settingsWithDetails.getRaceDetailsToShow());
List<DetailType> overallDetailsToShow = copyDetailTypes(settingsWithDetails.getOverallDetailsToShow());
Collection<DetailType> maneuverDetails = settingsWithDetails.getManeuverDetailsToShow();
Collection<DetailType> legDetails = settingsWithDetails.getLegDetailsToShow();
Collection<DetailType> raceDetails = settingsWithDetails.getRaceDetailsToShow();
Collection<DetailType> overallDetailsToShow = settingsWithDetails.getOverallDetailsToShow();
Long refreshIntervalInMs = settingsWithDetails.getDelayBetweenAutoAdvancesInMilliseconds();
RaceColumnSelectionStrategies strategy = settingsWithRaceSelection.getActiveRaceColumnSelectionStrategy();
@@ -231,14 +101,6 @@ public class LeaderboardSettingsFactory {
settingsWithRaceSelection.isShowCompetitorNationality());
}
private List<DetailType> copyDetailTypes(List<DetailType> detailTypes) {
List<DetailType> result = null;
if(detailTypes != null) {
result = new ArrayList<DetailType>(detailTypes);
}
return result;
}
private List<String> copyRaceNamesList(List<String> raceNames) {
List<String> result = null;
if(raceNames != null) {
@@ -7,13 +7,12 @@ public class MetaLeaderboardPerspectiveLifecycle extends AbstractLeaderboardPers
public static final String ID = "mlbh";
public MetaLeaderboardPerspectiveLifecycle(StringMessages stringMessages) {
this(stringMessages, null);
}
private final MultiLeaderboardPanelLifecycle multiLeaderboardPanelLifecycle;
public MetaLeaderboardPerspectiveLifecycle(StringMessages stringMessages, AbstractLeaderboardDTO leaderboard) {
super(stringMessages, leaderboard, true);
addLifeCycle(new MultiLeaderboardPanelLifecycle(null, stringMessages));
multiLeaderboardPanelLifecycle = new MultiLeaderboardPanelLifecycle(null, stringMessages);
addLifeCycle(multiLeaderboardPanelLifecycle);
}
@Override
@@ -25,4 +24,8 @@ public class MetaLeaderboardPerspectiveLifecycle extends AbstractLeaderboardPers
public String getComponentId() {
return ID;
}
public MultiLeaderboardPanelLifecycle getMultiLeaderboardPanelLifecycle() {
return multiLeaderboardPanelLifecycle;
}
}
@@ -44,13 +44,13 @@ public class MultiCompetitorLeaderboardChartLifecycle implements
}
@Override
public MultiCompetitorLeaderboardChartSettings extractGlobalSettings(
public MultiCompetitorLeaderboardChartSettings extractUserSettings(
MultiCompetitorLeaderboardChartSettings settings) {
return settings;
}
@Override
public MultiCompetitorLeaderboardChartSettings extractContextSpecificSettings(
public MultiCompetitorLeaderboardChartSettings extractDocumentSettings(
MultiCompetitorLeaderboardChartSettings settings) {
return settings;
}
@@ -20,7 +20,7 @@ public class MultiLeaderboardPanelLifecycle extends LeaderboardPanelLifecycle {
}
@Override
public LeaderboardSettings extractContextSpecificSettings(LeaderboardSettings leaderboardSettings) {
public LeaderboardSettings extractDocumentSettings(LeaderboardSettings leaderboardSettings) {
return createDefaultSettings();
}
@@ -1,13 +0,0 @@
package com.sap.sailing.gwt.settings.client.settingtypes.converter;
import com.sap.sailing.domain.common.DetailType;
import com.sap.sse.common.settings.generic.StringToEnumConverter;
public class DetailTypeStringToEnumConverter implements StringToEnumConverter<DetailType> {
@Override
public DetailType fromString(String stringValue) {
return DetailType.valueOf(stringValue);
}
}
@@ -1,13 +0,0 @@
package com.sap.sailing.gwt.settings.client.settingtypes.converter;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings.HelpLineTypes;
import com.sap.sse.common.settings.generic.StringToEnumConverter;
public class HelpLineTypesStringToEnumConverter implements StringToEnumConverter<HelpLineTypes> {
@Override
public HelpLineTypes fromString(String stringValue) {
return HelpLineTypes.valueOf(stringValue);
}
}
@@ -1,13 +0,0 @@
package com.sap.sailing.gwt.settings.client.settingtypes.converter;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sse.common.settings.generic.StringToEnumConverter;
public class ManeuverTypeStringToEnumConverter implements StringToEnumConverter<ManeuverType> {
@Override
public ManeuverType fromString(String stringValue) {
return ManeuverType.valueOf(stringValue);
}
}
@@ -1,13 +0,0 @@
package com.sap.sailing.gwt.settings.client.settingtypes.converter;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardSettings.RaceColumnSelectionStrategies;
import com.sap.sse.common.settings.generic.StringToEnumConverter;
public class RaceColumnSelectionStrategiesStringToEnumConverter implements StringToEnumConverter<RaceColumnSelectionStrategies> {
@Override
public RaceColumnSelectionStrategies fromString(String stringValue) {
return RaceColumnSelectionStrategies.valueOf(stringValue);
}
}
@@ -1,13 +0,0 @@
package com.sap.sailing.gwt.settings.client.settingtypes.converter;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sse.common.settings.generic.StringToEnumConverter;
public class WindSourceTypeStringToEnumConverter implements StringToEnumConverter<WindSourceType> {
@Override
public WindSourceType fromString(String stringValue) {
return WindSourceType.valueOf(stringValue);
}
}
@@ -1,13 +0,0 @@
package com.sap.sailing.gwt.settings.client.settingtypes.converter;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings.ZoomTypes;
import com.sap.sse.common.settings.generic.StringToEnumConverter;
public class ZoomTypesStringToEnumConverter implements StringToEnumConverter<ZoomTypes> {
@Override
public ZoomTypes fromString(String stringValue) {
return ZoomTypes.valueOf(stringValue);
}
}
@@ -0,0 +1,15 @@
package com.sap.sailing.gwt.settings.client.utils;
import com.sap.sailing.gwt.ui.shared.settings.SailingSettingsConstants;
import com.sap.sse.security.ui.settings.StoredSettingsLocation;
public class SailingStoredSettingsLocation extends StoredSettingsLocation {
/**
* @see com.sap.sse.security.ui.settings.StoredSettingsLocation#StoredSettingsLocation(String, String)
*/
public SailingStoredSettingsLocation(String userSettingsIdPart, String documentSettingsIdPart) {
super(SailingSettingsConstants.USER_SETTINGS_UI, userSettingsIdPart, documentSettingsIdPart);
}
}
@@ -1,60 +0,0 @@
package com.sap.sailing.gwt.settings.client.utils;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardContextDefinition;
import com.sap.sailing.gwt.settings.client.raceboard.RaceboardContextDefinition;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaOverviewContextDefinition;
import com.sap.sse.security.ui.settings.StorageDefinitionId;
public class StorageDefinitionIdFactory {
private StorageDefinitionIdFactory() {
}
private static final String RACEBOARD = "Raceboard";
private static final String LEADERBOARD = "Leaderboard";
private static final String REGATTA_OVERVIEW = "RegattaOverview";
private static final String EVENT_REGATTA_LEADERBOARD = "EventRegattaLeaderboard";
private static final String SERIES_OVERALL_LEADERBOARD = "SeriesOverallLeaderboard";
private static final String SERIES_REGATTA_LEADERBOARDS = "SeriesRegattaLeaderboards";
public static final StorageDefinitionId createStorageDefinitionIdForRaceBoard(
RaceboardContextDefinition raceboardContextDefinition) {
String globalDefinitionId = RACEBOARD;
if (raceboardContextDefinition.getMode() != null) {
globalDefinitionId += "." + raceboardContextDefinition.getMode().toString();
}
String contextDefinitionId = StorageDefinitionId.buildContextDefinitionId(raceboardContextDefinition.getRegattaName(),
raceboardContextDefinition.getRaceName(), raceboardContextDefinition.getLeaderboardName());
return new StorageDefinitionId(globalDefinitionId, contextDefinitionId);
}
public static final StorageDefinitionId createStorageDefinitionIdForLeaderboard(
LeaderboardContextDefinition leaderboardContextDefinition) {
return new StorageDefinitionId(LEADERBOARD,
StorageDefinitionId.buildContextDefinitionId(leaderboardContextDefinition.getLeaderboardName()));
}
public static final StorageDefinitionId createStorageDefinitionIdForRegattaOverview(
RegattaOverviewContextDefinition regattaOverviewContextDefinition) {
return new StorageDefinitionId(REGATTA_OVERVIEW,
StorageDefinitionId.buildContextDefinitionId(regattaOverviewContextDefinition.getEvent().toString()));
}
public static final StorageDefinitionId createStorageDefinitionIdForEventRegattaLeaderboard(String leaderboardName) {
return new StorageDefinitionId(EVENT_REGATTA_LEADERBOARD,
StorageDefinitionId.buildContextDefinitionId(leaderboardName));
}
public static final StorageDefinitionId createStorageDefinitionIdForSeriesOverallLeaderboard(String leaderboardName) {
return new StorageDefinitionId(SERIES_OVERALL_LEADERBOARD,
StorageDefinitionId.buildContextDefinitionId(leaderboardName));
}
public static final StorageDefinitionId createStorageDefinitionIdForSeriesRegattaLeaderboards(String leaderboardName) {
return new StorageDefinitionId(SERIES_REGATTA_LEADERBOARDS,
StorageDefinitionId.buildContextDefinitionId(leaderboardName));
}
}
@@ -0,0 +1,65 @@
package com.sap.sailing.gwt.settings.client.utils;
import com.sap.sailing.gwt.settings.client.leaderboard.LeaderboardContextDefinition;
import com.sap.sailing.gwt.settings.client.raceboard.RaceboardContextDefinition;
import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaOverviewContextDefinition;
import com.sap.sse.security.ui.settings.StoredSettingsLocation;
/**
* Factory for {@link StoredSettingsLocation}s which are used in Sailing Analytics.
*
* @author Vladislav Chumak
*
*/
public class StoredSettingsLocationFactory {
private StoredSettingsLocationFactory() {
}
private static final String RACEBOARD = "Raceboard";
private static final String LEADERBOARD = "Leaderboard";
private static final String REGATTA_OVERVIEW = "RegattaOverview";
private static final String EVENT_REGATTA_LEADERBOARD = "EventRegattaLeaderboard";
private static final String SERIES_OVERALL_LEADERBOARD = "SeriesOverallLeaderboard";
private static final String SERIES_REGATTA_LEADERBOARDS = "SeriesRegattaLeaderboards";
public static final StoredSettingsLocation createStoredSettingsLocatorForRaceBoard(
RaceboardContextDefinition raceboardContextDefinition, String raceBoardModeName) {
String userSettingsIdPart = RACEBOARD;
if(raceBoardModeName != null) {
userSettingsIdPart += "." + raceBoardModeName;
}
String documentSettingsIdPart = StoredSettingsLocation.buildDocumentSettingsIdPart(raceboardContextDefinition.getRegattaName(),
raceboardContextDefinition.getRaceName(), raceboardContextDefinition.getLeaderboardName());
return new SailingStoredSettingsLocation(userSettingsIdPart, documentSettingsIdPart);
}
public static final StoredSettingsLocation createStoredSettingsLocatorForLeaderboard(
LeaderboardContextDefinition leaderboardContextDefinition) {
return new SailingStoredSettingsLocation(LEADERBOARD,
StoredSettingsLocation.buildDocumentSettingsIdPart(leaderboardContextDefinition.getLeaderboardName()));
}
public static final StoredSettingsLocation createStoredSettingsLocatorForRegattaOverview(
RegattaOverviewContextDefinition regattaOverviewContextDefinition) {
return new SailingStoredSettingsLocation(REGATTA_OVERVIEW,
StoredSettingsLocation.buildDocumentSettingsIdPart(regattaOverviewContextDefinition.getEvent().toString()));
}
public static final StoredSettingsLocation createStoredSettingsLocatorForEventRegattaLeaderboard(String leaderboardName) {
return new SailingStoredSettingsLocation(EVENT_REGATTA_LEADERBOARD,
StoredSettingsLocation.buildDocumentSettingsIdPart(leaderboardName));
}
public static final StoredSettingsLocation createStoredSettingsLocatorForSeriesOverallLeaderboard(String leaderboardName) {
return new SailingStoredSettingsLocation(SERIES_OVERALL_LEADERBOARD,
StoredSettingsLocation.buildDocumentSettingsIdPart(leaderboardName));
}
public static final StoredSettingsLocation createStoredSettingsLocatorForSeriesRegattaLeaderboards(String leaderboardName) {
return new SailingStoredSettingsLocation(SERIES_REGATTA_LEADERBOARDS,
StoredSettingsLocation.buildDocumentSettingsIdPart(leaderboardName));
}
}
@@ -233,18 +233,18 @@ public abstract class AbstractLeaderboardConfigPanel extends FormPanel implement
@Override
public void onSelectionChange(SelectionChangeEvent event) {
Set<RaceDTO> selectedRaces = refreshableTrackedRaceSelectionModel.getSelectedSet();
RaceDTO selectedRace = selectedRaces.iterator().next();
RaceColumnDTOAndFleetDTOWithNameBasedEquality selectedRaceColumnAndFleetName = getSelectedRaceColumnWithFleet();
RaceColumnDTO selectedRaceColumn = selectedRaceColumnAndFleetName.getA();
FleetDTO selectedRaceColumnFleet = selectedRaceColumnAndFleetName.getB();
// if no leaderboard column is selected, ignore the race selection change
if (selectedRaceColumnAndFleetName != null) {
RaceColumnDTO selectedRaceColumn = selectedRaceColumnAndFleetName.getA();
FleetDTO selectedRaceColumnFleet = selectedRaceColumnAndFleetName.getB();
if (selectedRaces.isEmpty()) {
if (hasLink(selectedRaceColumnAndFleetName)) {
unlinkRaceColumnFromTrackedRace(selectedRaceColumn.getRaceColumnName(),
selectedRaceColumnFleet);
}
} else {
RaceDTO selectedRace = selectedRaces.iterator().next();
if (hasLink(selectedRaceColumnAndFleetName)
&& !isLinkedToRace(selectedRaceColumnAndFleetName, selectedRace)) {
if (Window.confirm(stringMessages.trackedRaceAlreadyLinked())) {
@@ -56,7 +56,7 @@ import com.sap.sse.gwt.client.panels.CustomizableFilterablePanel;
import com.sap.sse.gwt.client.shared.components.AbstractCompositeComponent;
import com.sap.sse.gwt.client.shared.components.Component;
import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent;
import com.sap.sse.gwt.client.shared.perspective.ComponentContext;
import com.sap.sse.gwt.client.shared.settings.ComponentContext;
public abstract class AbstractTrackedRacesListComposite extends AbstractCompositeComponent<TrackedRacesSettings> implements
RegattasDisplayer {
@@ -435,7 +435,7 @@ public abstract class AbstractTrackedRacesListComposite extends AbstractComposit
}
@Override
public SettingsDialogComponent<TrackedRacesSettings> getSettingsDialogComponent() {
public SettingsDialogComponent<TrackedRacesSettings> getSettingsDialogComponent(TrackedRacesSettings settings) {
return new TrackedRacesSettingsDialogComponent<TrackedRacesSettings>(settings, stringMessages);
}
@@ -377,18 +377,21 @@ public class EventListComposite extends Composite implements EventsRefresher, Le
table.addColumn(eventActionColumn, stringMessages.actions());
table.setSelectionModel(eventSelectionCheckboxColumn.getSelectionModel(), eventSelectionCheckboxColumn.getSelectionManager());
table.addColumnSortHandler(getEventTableColumnSortHandler(eventListDataProvider.getList(), eventNameColumn,
venueNameColumn, startEndDateColumn, isPublicColumn, courseAreasColumn, leaderboardGroupsColumn));
table.addColumnSortHandler(getEventTableColumnSortHandler(eventListDataProvider.getList(),
eventSelectionCheckboxColumn, eventNameColumn, venueNameColumn, startEndDateColumn, isPublicColumn,
courseAreasColumn, leaderboardGroupsColumn));
table.getColumnSortList().push(startEndDateColumn);
return table;
}
private ListHandler<EventDTO> getEventTableColumnSortHandler(List<EventDTO> eventRecords,
Column<EventDTO, SafeHtml> eventNameColumn, TextColumn<EventDTO> venueNameColumn,
TextColumn<EventDTO> startEndDateColumn, TextColumn<EventDTO> isPublicColumn, Column<EventDTO, SafeHtml> courseAreasColumn,
SelectionCheckboxColumn<EventDTO> eventSelectionCheckboxColumn, Column<EventDTO, SafeHtml> eventNameColumn,
TextColumn<EventDTO> venueNameColumn, TextColumn<EventDTO> startEndDateColumn,
TextColumn<EventDTO> isPublicColumn, Column<EventDTO, SafeHtml> courseAreasColumn,
Column<EventDTO, List<MultipleLinkCell.CellLink>> leaderboardGroupsColumn) {
ListHandler<EventDTO> result = new ListHandler<EventDTO>(eventRecords);
result.setComparator(eventSelectionCheckboxColumn, eventSelectionCheckboxColumn.getComparator());
result.setComparator(eventNameColumn, new Comparator<EventDTO>() {
@Override
public int compare(EventDTO e1, EventDTO e2) {
@@ -527,6 +527,14 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel implements
return group.description.length() <= 100 ? group.description : group.description.substring(0, 98) + "...";
}
};
groupDescriptionColumn.setSortable(true);
leaderboardGroupsListHandler.setComparator(groupDescriptionColumn, new Comparator<LeaderboardGroupDTO>() {
@Override
public int compare(LeaderboardGroupDTO group1, LeaderboardGroupDTO group2) {
return new NaturalComparator(false).compare(group1.description, group2.description);
}
});
TextColumn<LeaderboardGroupDTO> groupDisplayNameColumn = new TextColumn<LeaderboardGroupDTO>() {
@Override
public String getValue(LeaderboardGroupDTO group) {
@@ -534,6 +542,14 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel implements
group.getDisplayName().length() <= 100 ? group.getDisplayName() : group.getDisplayName().substring(0, 98) + "...";
}
};
groupDisplayNameColumn.setSortable(true);
leaderboardGroupsListHandler.setComparator(groupDisplayNameColumn, new Comparator<LeaderboardGroupDTO>() {
@Override
public int compare(LeaderboardGroupDTO group1, LeaderboardGroupDTO group2) {
return new NaturalComparator(false).compare(group1.getDisplayName(), group2.getDisplayName());
}
});
TextColumn<LeaderboardGroupDTO> hasOverallLeaderboardColumn = new TextColumn<LeaderboardGroupDTO>() {
@Override
public String getValue(LeaderboardGroupDTO group) {
@@ -544,6 +560,14 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel implements
return result;
}
};
hasOverallLeaderboardColumn.setSortable(true);
leaderboardGroupsListHandler.setComparator(hasOverallLeaderboardColumn, new Comparator<LeaderboardGroupDTO>() {
@Override
public int compare(LeaderboardGroupDTO group1, LeaderboardGroupDTO group2) {
return new NaturalComparator(false).compare(hasOverallLeaderboardColumn.getValue(group1),
hasOverallLeaderboardColumn.getValue(group2));
}
});
ImagesBarColumn<LeaderboardGroupDTO, LeaderboardGroupConfigImagesBarCell> groupActionsColumn = new ImagesBarColumn<LeaderboardGroupDTO, LeaderboardGroupConfigImagesBarCell>(
new LeaderboardGroupConfigImagesBarCell(stringMessages));
Loaded 100 of 279 files, more files were not shown because too many files have changed in this diff. Show more