Merge remote-tracking branch 'origin/gwt' into gwt

This commit is contained in:
fmittag committed 2012-02-02 17:00:53 +01:00
commit 39ddae4b25
33 files changed
+712 -157

No files matched your search

@@ -1,8 +1,7 @@
package com.sap.sailing.domain.base;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.confidence.HasConfidence;
import com.sap.sailing.domain.confidence.HasConfidenceAndIsScalable;
public interface SpeedWithConfidence<RelativeTo> extends HasConfidence<Speed, Speed, RelativeTo> {
Speed getObject();
public interface SpeedWithConfidence<RelativeTo> extends HasConfidenceAndIsScalable<Double, Speed, RelativeTo> {
}
@@ -0,0 +1,48 @@
package com.sap.sailing.domain.base.impl;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.confidence.ScalableValue;
public class SpeedWithConfidenceImpl<RelativeTo> extends HasConfidenceImpl<Double, Speed, RelativeTo> implements SpeedWithConfidence<RelativeTo> {
public SpeedWithConfidenceImpl(Speed object, double confidence, RelativeTo relativeTo) {
super(object, confidence, relativeTo);
}
@Override
public ScalableValue<Double, Speed> getScalableValue() {
return new ScalableSpeed(getObject());
}
private static class ScalableSpeed implements ScalableValue<Double, Speed> {
private final double knots;
public ScalableSpeed(Speed speed) {
this.knots = speed.getKnots();
}
private ScalableSpeed(double knots) {
this.knots = knots;
}
@Override
public ScalableValue<Double, Speed> multiply(double factor) {
return new ScalableSpeed(factor*knots);
}
@Override
public ScalableValue<Double, Speed> add(ScalableValue<Double, Speed> t) {
return new ScalableSpeed(knots+t.getValue());
}
@Override
public Speed divide(double divisor, double confidence) {
return new KnotSpeedImpl(knots / divisor);
}
@Override
public Double getValue() {
return knots;
}
}
}
@@ -10,7 +10,8 @@ public interface ConfidenceBasedAverager<ValueType, BaseType, RelativeTo> {
* <code>null</code> average with confidence is returned. Note, however, that the
* {@link HasConfidence#getObject() object} in the {@link HasConfidence} result may be <code>null</code>,
* e.g., if the combined confidence went to 0.0 and the averager was unable to determine a reasonable
* average value.
* average value. The result's confidence is the arithmetic average of the confidences of all values
* that contributed to the result.
*/
HasConfidence<ValueType, BaseType, RelativeTo> getAverage(
Iterable<? extends HasConfidenceAndIsScalable<ValueType, BaseType, RelativeTo>> values, RelativeTo at);
@@ -61,7 +61,7 @@ public class ConfidenceBasedAveragerImpl<ValueType, BaseType, RelativeTo> implem
}
confidenceSum += relativeWeight;
}
// TODO determine new confidence, e.g., based on the variance of estimates averaged
// TODO consider greater variance to reduce the confidence
double newConfidence = confidenceSum / Util.size(values);
BaseType result = numerator.divide(confidenceSum, newConfidence);
return new HasConfidenceImpl<ValueType, BaseType, RelativeTo>(result, newConfidence, at);
@@ -1,11 +1,13 @@
package com.sap.sailing.domain.tracking;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.confidence.Weigher;
/**
* A track records the {@link GPSFix}es received for an object of type
@@ -74,6 +76,19 @@ public interface GPSFixTrack<ItemType, FixType extends GPSFix> extends Track<Fix
* by the GPS fixes in this track at time point <code>at</code>.
*/
SpeedWithBearing getEstimatedSpeed(TimePoint at);
/**
* Estimates the tracked item's speed/bearing, returning the result as a value with confidence. The confidences of
* the individual fixes contributing to the estimation are computed using the <code>weigher</code>. The result's
* confidence is the average confidence of the fixes used. While this is probably not a mathematically meaningful
* confidence value, it helps in comparing confidences of different estimations relative to each other.
*/
SpeedWithBearingWithConfidence<TimePoint> getEstimatedSpeed(TimePoint at, Weigher<TimePoint> weigher);
/**
* Same as {@link #getEstimatedSpeed(TimePoint, Weigher)}, but using the raw fixes.
*/
SpeedWithBearingWithConfidence<TimePoint> getRawEstimatedSpeed(TimePoint at, Weigher<TimePoint> weigher);
long getMillisecondsOverWhichToAverageSpeed();
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.tracking.impl;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -7,15 +8,21 @@ import java.util.NavigableSet;
import com.sap.sailing.domain.base.BearingWithConfidence;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.impl.BearingWithConfidenceImpl;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.base.impl.SpeedWithBearingWithConfidenceImpl;
import com.sap.sailing.domain.base.impl.SpeedWithConfidenceImpl;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.KilometersPerHourSpeedImpl;
import com.sap.sailing.domain.confidence.ConfidenceBasedAverager;
import com.sap.sailing.domain.confidence.ConfidenceFactory;
import com.sap.sailing.domain.confidence.HasConfidence;
import com.sap.sailing.domain.confidence.Weigher;
import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixMoving;
@@ -44,42 +51,47 @@ public class DynamicGPSFixMovingTrackImpl<ItemType> extends DynamicTrackImpl<Ite
}
@Override
protected SpeedWithBearing getEstimatedSpeed(TimePoint at, NavigableSet<GPSFixMoving> fixesToUseForSpeedEstimation) {
protected SpeedWithBearingWithConfidence<TimePoint> getEstimatedSpeed(TimePoint at,
NavigableSet<GPSFixMoving> fixesToUseForSpeedEstimation, Weigher<TimePoint> weigher) {
List<GPSFixMoving> relevantFixes = getFixesRelevantForSpeedEstimation(at, fixesToUseForSpeedEstimation);
double knotSum = 0;
Weigher<TimePoint> weigher = ConfidenceFactory.INSTANCE.createExponentialTimeDifferenceWeigher(
// use a minimum confidence to avoid the bearing to flip to 270deg in case all is zero
/* halfConfidenceAfterMilliseconds */ getMillisecondsOverWhichToAverageSpeed());
List<SpeedWithConfidence<TimePoint>> speeds = new ArrayList<SpeedWithConfidence<TimePoint>>();
BearingWithConfidenceCluster<TimePoint> bearingCluster = new BearingWithConfidenceCluster<TimePoint>(weigher);
int count = 0;
if (!relevantFixes.isEmpty()) {
Iterator<GPSFixMoving> fixIter = relevantFixes.iterator();
GPSFixMoving last = fixIter.next();
knotSum = last.getSpeed().getKnots();
SpeedWithConfidenceImpl<TimePoint> speedWithConfidence = new SpeedWithConfidenceImpl<TimePoint>(last.getSpeed(),
/* original confidence */ 0.9, last.getTimePoint());
speeds.add(speedWithConfidence);
bearingCluster.add(new BearingWithConfidenceImpl<TimePoint>(last.getSpeed().getBearing(), /* confidence */ 0.9, last.getTimePoint()));
count = 1;
while (fixIter.hasNext()) {
// TODO bug #169: use confidence-based averager for speed, too, and not only for bearing
// add to average the position and time difference
GPSFixMoving next = fixIter.next();
knotSum += last.getPosition().getDistance(next.getPosition())
.inTime(next.getTimePoint().asMillis() - last.getTimePoint().asMillis()).getKnots();
SpeedWithConfidenceImpl<TimePoint> measuredSpeedWithConfidence = new SpeedWithConfidenceImpl<TimePoint>(
last.getPosition().getDistance(next.getPosition())
.inTime(next.getTimePoint().asMillis() - last.getTimePoint().asMillis()),
/* original confidence */0.9, new MillisecondsTimePoint((last.getTimePoint().asMillis()+next.getTimePoint().asMillis())/2));
speeds.add(measuredSpeedWithConfidence);
bearingCluster.add(new BearingWithConfidenceImpl<TimePoint>(last.getPosition().getBearingGreatCircle(next.getPosition()),
/* confidence */ weigher.getConfidence(last.getTimePoint(), next.getTimePoint()),
new MillisecondsTimePoint((last.getTimePoint().asMillis()+next.getTimePoint().asMillis())/2)));
count++;
// add to average the speed and bearing provided by the GPSFixMoving
knotSum += next.getSpeed().getKnots();
SpeedWithConfidenceImpl<TimePoint> computedSpeedWithConfidence = new SpeedWithConfidenceImpl<TimePoint>(
next.getSpeed(), /* original confidence */0.9, next.getTimePoint());
speeds.add(computedSpeedWithConfidence);
bearingCluster.add(new BearingWithConfidenceImpl<TimePoint>(next.getSpeed().getBearing(), /* confidence */ 0.9, next.getTimePoint()));
count++;
last = next;
}
}
BearingWithConfidence<TimePoint> average = bearingCluster.getAverage(at);
Bearing bearing = average == null ? null : average.getObject();
SpeedWithBearing avgSpeed = (count == 0 || bearing == null) ? null : new KnotSpeedWithBearingImpl(knotSum / count, bearing);
return avgSpeed;
ConfidenceBasedAverager<Double, Speed, TimePoint> speedAverager = ConfidenceFactory.INSTANCE.createAverager(weigher);
HasConfidence<Double, Speed, TimePoint> speedWithConfidence = speedAverager.getAverage(speeds, at);
BearingWithConfidence<TimePoint> bearingAverage = bearingCluster.getAverage(at);
Bearing bearing = bearingAverage == null ? null : bearingAverage.getObject();
SpeedWithBearing avgSpeed = (speedWithConfidence == null || bearing == null) ? null :
new KnotSpeedWithBearingImpl(speedWithConfidence.getObject().getKnots(), bearing);
SpeedWithBearingWithConfidence<TimePoint> result = new SpeedWithBearingWithConfidenceImpl<TimePoint>(avgSpeed,
/* confidence */ (speedWithConfidence.getConfidence() + bearingAverage.getConfidence())/2., at);
return result;
}
private List<GPSFixMoving> getFixesRelevantForSpeedEstimation(TimePoint at,
@@ -1,5 +1,6 @@
package com.sap.sailing.domain.tracking.impl;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.Iterator;
@@ -10,10 +11,14 @@ import java.util.Set;
import com.sap.sailing.domain.base.BearingWithConfidence;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.impl.BearingWithConfidenceImpl;
import com.sap.sailing.domain.base.impl.KnotSpeedImpl;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.base.impl.SpeedWithBearingWithConfidenceImpl;
import com.sap.sailing.domain.base.impl.SpeedWithConfidenceImpl;
import com.sap.sailing.domain.common.Bearing;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.Position;
@@ -21,7 +26,10 @@ import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.impl.NauticalMileDistance;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.confidence.ConfidenceBasedAverager;
import com.sap.sailing.domain.confidence.ConfidenceFactory;
import com.sap.sailing.domain.confidence.HasConfidence;
import com.sap.sailing.domain.confidence.Weigher;
import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.GPSFixTrack;
@@ -301,12 +309,26 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends TrackImpl
*/
@Override
public synchronized SpeedWithBearing getEstimatedSpeed(TimePoint at) {
return getEstimatedSpeed(at, getInternalFixes());
return getEstimatedSpeed(at, getInternalFixes(), ConfidenceFactory.INSTANCE.createExponentialTimeDifferenceWeigher(
// use a minimum confidence to avoid the bearing to flip to 270deg in case all is zero
getMillisecondsOverWhichToAverageSpeed())).getObject();
}
@Override
public synchronized SpeedWithBearing getRawEstimatedSpeed(TimePoint at) {
return getEstimatedSpeed(at, getRawFixes());
return getEstimatedSpeed(at, getRawFixes(), ConfidenceFactory.INSTANCE.createExponentialTimeDifferenceWeigher(
// use a minimum confidence to avoid the bearing to flip to 270deg in case all is zero
getMillisecondsOverWhichToAverageSpeed())).getObject();
}
@Override
public SpeedWithBearingWithConfidence<TimePoint> getEstimatedSpeed(TimePoint at, Weigher<TimePoint> weigher) {
return getEstimatedSpeed(at, getInternalFixes(), weigher);
}
@Override
public SpeedWithBearingWithConfidence<TimePoint> getRawEstimatedSpeed(TimePoint at, Weigher<TimePoint> weigher) {
return getEstimatedSpeed(at, getRawFixes(), weigher);
}
/**
@@ -315,17 +337,20 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends TrackImpl
* {@link #millisecondsOverWhichToAverage} milliseconds around <code>at</code>. Subclasses that know about the
* particular fix type may redefine this to exploit a {@link SpeedWithBearing} attached, e.g., to a
* {@link GPSFixMoving}.
*
* @param weigher
* If <code>null</code>, a confidence of 1.0 is assumed for all fixes used in the speed/bearing
* estimation. Otherwise, the confidence of each fix contributing to the estimation is computed using the
* <code>weigher</code>.
* @return a speed/bearing with the average confidence attributed to the fixes that contributed to the estimation
*/
protected SpeedWithBearing getEstimatedSpeed(TimePoint at, NavigableSet<FixType> fixesToUseForSpeedEstimation) {
protected SpeedWithBearingWithConfidence<TimePoint> getEstimatedSpeed(TimePoint at,
NavigableSet<FixType> fixesToUseForSpeedEstimation, Weigher<TimePoint> weigher) {
@SuppressWarnings("unchecked")
NavigableSet<GPSFix> gpsFixesToUseForSpeedEstimation = (NavigableSet<GPSFix>) fixesToUseForSpeedEstimation;
List<GPSFix> relevantFixes = getFixesRelevantForSpeedEstimation(at, gpsFixesToUseForSpeedEstimation);
double knotSum = 0;
BearingWithConfidenceCluster<TimePoint> bearingCluster = new BearingWithConfidenceCluster<TimePoint>(
ConfidenceFactory.INSTANCE.createExponentialTimeDifferenceWeigher(
// use a minimum confidence to avoid the bearing to flip to 270deg in case all is zero
getMillisecondsOverWhichToAverageSpeed()));
int count = 0;
List<SpeedWithConfidence<TimePoint>> speeds = new ArrayList<SpeedWithConfidence<TimePoint>>();
BearingWithConfidenceCluster<TimePoint> bearingCluster = new BearingWithConfidenceCluster<TimePoint>(weigher);
if (!relevantFixes.isEmpty()) {
Iterator<GPSFix> fixIter = relevantFixes.iterator();
GPSFix last = fixIter.next();
@@ -333,20 +358,27 @@ public class GPSFixTrackImpl<ItemType, FixType extends GPSFix> extends TrackImpl
// TODO bug #169: consider time difference between next.getTimepoint() and at to compute a confidence
GPSFix next = fixIter.next();
// TODO bug #169: use SpeedWithConfidence to aggregate confidence-tagged speed values
knotSum += last.getPosition().getDistance(next.getPosition())
.inTime(next.getTimePoint().asMillis() - last.getTimePoint().asMillis()).getKnots();
MillisecondsTimePoint relativeTo = new MillisecondsTimePoint((last.getTimePoint().asMillis() + next.getTimePoint().asMillis())/2);
Speed speed = last.getPosition().getDistance(next.getPosition())
.inTime(next.getTimePoint().asMillis() - last.getTimePoint().asMillis());
SpeedWithConfidenceImpl<TimePoint> speedWithConfidence = new SpeedWithConfidenceImpl<TimePoint>(speed, /* original confidence */
0.9, relativeTo);
speeds.add(speedWithConfidence);
bearingCluster.add(new BearingWithConfidenceImpl<TimePoint>(last.getPosition().getBearingGreatCircle(next.getPosition()),
/* confidence */ 0.9, // TODO use number of tracked satellites to determine confidence of single fix
new MillisecondsTimePoint((last.getTimePoint().asMillis() + next.getTimePoint().asMillis())/2)));
count++;
relativeTo));
last = next;
}
}
// TODO bug #169: return SpeedWithBearingWithConfidence to reflect the confidence reduction incurred by the difference of the fix's time point and "at"
BearingWithConfidence<TimePoint> average = bearingCluster.getAverage(at);
Bearing bearing = average == null ? null : average.getObject();
SpeedWithBearing avgSpeed = (count == 0 || bearing == null) ? null : new KnotSpeedWithBearingImpl(knotSum / count, bearing);
return avgSpeed;
ConfidenceBasedAverager<Double, Speed, TimePoint> speedAverager = ConfidenceFactory.INSTANCE.createAverager(weigher);
HasConfidence<Double, Speed, TimePoint> speedWithConfidence = speedAverager.getAverage(speeds, at);
BearingWithConfidence<TimePoint> bearingAverage = bearingCluster.getAverage(at);
Bearing bearing = bearingAverage == null ? null : bearingAverage.getObject();
SpeedWithBearing avgSpeed = (speedWithConfidence == null || bearing == null) ? null :
new KnotSpeedWithBearingImpl(speedWithConfidence.getObject().getKnots(), bearing);
SpeedWithBearingWithConfidence<TimePoint> result = avgSpeed == null ? null :
new SpeedWithBearingWithConfidenceImpl<TimePoint>(avgSpeed, (bearingAverage.getConfidence() + speedWithConfidence.getConfidence())/2., at);
return result;
}
private List<GPSFix> getFixesRelevantForSpeedEstimation(TimePoint at,
@@ -16,6 +16,7 @@ import java.util.logging.Logger;
import org.json.simple.parser.ParseException;
import com.sap.sailing.domain.base.BearingWithConfidence;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Buoy;
import com.sap.sailing.domain.base.Competitor;
@@ -24,8 +25,10 @@ import com.sap.sailing.domain.base.CourseListener;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.SpeedWithBearing;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.base.Timed;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BearingWithConfidenceImpl;
import com.sap.sailing.domain.base.impl.DouglasPeucker;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
@@ -47,6 +50,8 @@ import com.sap.sailing.domain.common.impl.RacePlaceOrderImpl;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.common.impl.Util.Pair;
import com.sap.sailing.domain.common.impl.Util.Triple;
import com.sap.sailing.domain.confidence.ConfidenceFactory;
import com.sap.sailing.domain.confidence.Weigher;
import com.sap.sailing.domain.tracking.GPSFix;
import com.sap.sailing.domain.tracking.GPSFixMoving;
import com.sap.sailing.domain.tracking.GPSFixTrack;
@@ -646,9 +651,12 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
@Override
public Wind getEstimatedWindDirection(Position position, TimePoint timePoint) {
Map<LegType, BearingCluster> bearings = new HashMap<LegType, BearingCluster>();
Weigher<TimePoint> weigher = ConfidenceFactory.INSTANCE.createExponentialTimeDifferenceWeigher(
// use a minimum confidence to avoid the bearing to flip to 270deg in case all is zero
getMillisecondsOverWhichToAverageSpeed());
Map<LegType, BearingWithConfidenceCluster<TimePoint>> bearings = new HashMap<LegType, BearingWithConfidenceCluster<TimePoint>>();
for (LegType legType : LegType.values()) {
bearings.put(legType, new BearingCluster());
bearings.put(legType, new BearingWithConfidenceCluster<TimePoint>(weigher));
}
for (Competitor competitor : getRace().getCompetitors()) {
TrackedLegOfCompetitor leg = getTrackedLeg(competitor, timePoint);
@@ -665,44 +673,58 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
GPSFixTrack<Competitor, GPSFixMoving> track = getTrack(competitor);
// TODO bug #167 could be fixed here by excluding competitors that are x seconds before/after a mark passing
if (!track.hasDirectionChange(timePoint, getManeuverDegreeAngleThreshold())) {
SpeedWithBearing estimatedSpeed = track.getEstimatedSpeed(timePoint);
if (estimatedSpeed != null) {
// TODO but #169: preserve confidence of estimatedSpeed relative to timePoint so as to feed into a BearingWithConfidenceCluster here
Bearing bearing = estimatedSpeed.getBearing();
BearingCluster bearingClusterForLegType = bearings.get(legType);
SpeedWithBearingWithConfidence<TimePoint> estimatedSpeedWithConfidence = track.getEstimatedSpeed(timePoint,
weigher);
if (estimatedSpeedWithConfidence != null) {
BearingWithConfidence<TimePoint> bearing = new BearingWithConfidenceImpl<TimePoint>(
estimatedSpeedWithConfidence.getObject().getBearing(), estimatedSpeedWithConfidence.getConfidence(),
estimatedSpeedWithConfidence.getRelativeTo());
BearingWithConfidenceCluster<TimePoint> bearingClusterForLegType = bearings.get(legType);
bearingClusterForLegType.add(bearing);
}
}
}
}
}
Bearing reversedUpwindAverage = null;
int upwindConfidence = 0;
BearingCluster[] bearingClustersUpwind = bearings.get(LegType.UPWIND).splitInTwo(getMinimumAngleBetweenDifferentTacksUpwind());
// use the minimum confidence of the four "quadrants" as the result's confidence
BearingWithConfidenceImpl<TimePoint> reversedUpwindAverage = null;
int upwindNumberOfRelevantBoats = 0;
double confidence = 0;
BearingWithConfidenceCluster<TimePoint>[] bearingClustersUpwind = bearings.get(LegType.UPWIND).splitInTwo(
getMinimumAngleBetweenDifferentTacksUpwind(), timePoint);
if (!bearingClustersUpwind[0].isEmpty() && !bearingClustersUpwind[1].isEmpty()) {
reversedUpwindAverage = bearingClustersUpwind[0].getAverage().middle(bearingClustersUpwind[1].getAverage()).reverse();
upwindConfidence = Math.min(bearingClustersUpwind[0].size(), bearingClustersUpwind[1].size());
BearingWithConfidence<TimePoint> average0 = bearingClustersUpwind[0].getAverage(timePoint);
BearingWithConfidence<TimePoint> average1 = bearingClustersUpwind[1].getAverage(timePoint);
confidence = Math.min(average0.getConfidence(), average1.getConfidence());
reversedUpwindAverage = new BearingWithConfidenceImpl<TimePoint>(average0.getObject().middle(average1.getObject()).reverse(),
confidence, timePoint);
upwindNumberOfRelevantBoats = Math.min(bearingClustersUpwind[0].size(), bearingClustersUpwind[1].size());
}
Bearing downwindAverage = null;
int downwindConfidence = 0;
BearingCluster[] bearingClustersDownwind = bearings.get(LegType.DOWNWIND).splitInTwo(getMinimumAngleBetweenDifferentTacksDownwind());
BearingWithConfidenceImpl<TimePoint> downwindAverage = null;
int downwindNumberOfRelevantBoats = 0;
BearingWithConfidenceCluster<TimePoint>[] bearingClustersDownwind = bearings.get(LegType.DOWNWIND).splitInTwo(
getMinimumAngleBetweenDifferentTacksDownwind(), timePoint);
if (!bearingClustersDownwind[0].isEmpty() && !bearingClustersDownwind[1].isEmpty()) {
downwindAverage = bearingClustersDownwind[0].getAverage().middle(bearingClustersDownwind[1].getAverage());
downwindConfidence = Math.min(bearingClustersDownwind[0].size(), bearingClustersDownwind[1].size());
BearingWithConfidence<TimePoint> average0 = bearingClustersDownwind[0].getAverage(timePoint);
BearingWithConfidence<TimePoint> average1 = bearingClustersDownwind[1].getAverage(timePoint);
double downwindConfidence = Math.min(average0.getConfidence(), average1.getConfidence());
confidence = Math.min(confidence, downwindConfidence);
downwindAverage = new BearingWithConfidenceImpl<TimePoint>(average0.getObject().middle(average1.getObject()), downwindConfidence, timePoint);
downwindNumberOfRelevantBoats = Math.min(bearingClustersDownwind[0].size(), bearingClustersDownwind[1].size());
}
int confidence = upwindConfidence + downwindConfidence;
BearingCluster resultCluster = new BearingCluster();
assert upwindConfidence == 0 || reversedUpwindAverage != null;
for (int i=0; i<upwindConfidence; i++) {
int numberOfBoatsRelevantForEstimate = upwindNumberOfRelevantBoats + downwindNumberOfRelevantBoats;
BearingWithConfidenceCluster<TimePoint> resultCluster = new BearingWithConfidenceCluster<TimePoint>(weigher);
assert upwindNumberOfRelevantBoats == 0 || reversedUpwindAverage != null;
if (upwindNumberOfRelevantBoats > 0) {
resultCluster.add(reversedUpwindAverage);
}
assert downwindConfidence == 0 || downwindAverage != null;
for (int i=0; i<downwindConfidence; i++) {
assert downwindNumberOfRelevantBoats == 0 || downwindAverage != null;
if (downwindNumberOfRelevantBoats > 0) {
resultCluster.add(downwindAverage);
}
Bearing resultBearing = resultCluster.getAverage();
BearingWithConfidence<TimePoint> resultBearing = resultCluster.getAverage(timePoint);
return resultBearing == null ? null : new WindImpl(null, timePoint,
new KnotSpeedWithBearingImpl(/* speedInKnots */ confidence, resultBearing));
new KnotSpeedWithBearingImpl(/* speedInKnots */ numberOfBoatsRelevantForEstimate, resultBearing.getObject()));
}
/**
@@ -134,8 +134,7 @@ public class WindTrackImpl extends TrackImpl<Wind> implements WindTrack {
Iterator<Wind> afterIter = afterSet.iterator();
double knotSum = 0;
// TODO bug #169: also measure speed with confidence; return confidence
Weigher<TimePoint> weigher = ConfidenceFactory.INSTANCE.createLinearTimeDifferenceWeigher(millisecondsOverWhichToAverage);
// Weigher<TimePoint> weigher = ConfidenceFactory.INSTANCE.createConstantWeigher(1.0);
Weigher<TimePoint> weigher = ConfidenceFactory.INSTANCE.createLinearTimeDifferenceWeigher(millisecondsOverWhichToAverage/10);
BearingWithConfidenceCluster<TimePoint> bearingCluster = new BearingWithConfidenceCluster<TimePoint>(weigher);
int count = 0;
long beforeDistanceToAt = 0;
@@ -1,5 +1,5 @@
#Tue Jan 24 01:20:58 CET 2012
#Thu Feb 02 12:04:27 CET 2012
eclipse.preferences.version=1
entryPointModules=
filesCopiedToWebInfLib=gwt-servlet.jar
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgLiAtbG9jYWxXb3JrZXJzIDMgLXN0cmljdCAtbG9nTGV2ZWwgVFJBQ0VdXT48L2V4dHJhLWFyZ3M+PHZtLWFyZ3M+PCFbQ0RBVEFbLVhteDUxMm1dXT48L3ZtLWFyZ3M+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLkFkbWluQ29uc29sZTwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5MZWFkZXJib2FyZDwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5MZWFkZXJib2FyZEVkaXRpbmc8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVXNlck1hbmFnZW1lbnQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuU3BlY3RhdG9yPC9lbnRyeS1wb2ludC1tb2R1bGU+PC9nd3QtY29tcGlsZS1zZXR0aW5ncz4\=
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgLiAtbG9jYWxXb3JrZXJzIDMgLXN0cmljdCAtbG9nTGV2ZWwgVFJBQ0VdXT48L2V4dHJhLWFyZ3M+PHZtLWFyZ3M+PCFbQ0RBVEFbLVhteDUxMm1dXT48L3ZtLWFyZ3M+PC9nd3QtY29tcGlsZS1zZXR0aW5ncz4\=
+39
View File
@@ -236,3 +236,42 @@ input.magnifier {
text-decoration: none;
}
.leaderboardGroupPanel-GroupName {
float: left;
}
.leaderboardGroupPanel-GroupDescription {
float: left;
}
.leaderboardGroupPanel-LeaderboardsTableLabel {
}
.leaderboardGroupPanel-ActiveLeaderboard{
}
.leaderboardGroupPanel-ActiveRace {
}
.leaderboardGroupPanel-InactiveRace {
}
.welcomeWidget-WelcomePanel{
}
.welcomeWidget-CloseButton {
}
.welcomeWidget-Header {
}
.welcomeWidget-WelcomeText {
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

@@ -0,0 +1,22 @@
package com.sap.sailing.gwt.ui.client;
import com.sap.sailing.gwt.ui.shared.panels.ClosableWelcomeWidget;
import com.sap.sailing.gwt.ui.shared.panels.SimpleWelcomeWidget;
import com.sap.sailing.gwt.ui.shared.panels.WelcomeWidget;
/**
* Classes which implement this interface have the ability to display a {@link WelcomeWidget}.
*
* @author Lennart Hensler (D054527)
*/
public interface HasWelcomeWidget {
/**
* Sets the welcome widget of the component.
* @param welcome The new welcome widget
* @see {@link WelcomeWidget}, {@link SimpleWelcomeWidget}, {@link ClosableWelcomeWidget}, ...
*/
void setWelcomeWidget(WelcomeWidget welcome);
void setWelcomeWidgetVisible(boolean isVisible);
}
@@ -26,7 +26,7 @@ import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
import com.sap.sailing.gwt.ui.shared.components.Component;
import com.sap.sailing.gwt.ui.shared.components.SettingsDialog;
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
import com.sap.sailing.gwt.ui.shared.controls.SliderBar;
import com.sap.sailing.gwt.ui.shared.controls.slider.SliderBar;
public class TimePanel extends FormPanel implements Component<TimePanelSettings>, TimeListener, PlayStateListener, RequiresResize {
private final Timer timer;
@@ -1060,6 +1060,13 @@ public class LeaderboardPanel extends FormPanel implements TimeListener, PlaySta
Collections.sort(getData().getList(), getRankColumn().getComparator());
getLeaderboardTable().getColumnSortList().push(getRankColumn());
}
//Reselect the selected rows
leaderboardSelectionModel.clear();
for (LeaderboardRowDTO row : data.getList()) {
if (competitorSelectionProvider.isSelected(row.competitor)) {
leaderboardSelectionModel.setSelected(row, true);
}
}
}
}
@@ -1,15 +0,0 @@
package com.sap.sailing.gwt.ui.shared.components;
import com.google.gwt.user.client.ui.Widget;
public interface HasWelcomeWidget {
/**
* Sets the welcome widget of the component.
* @param welcome The new welcome widget
* @see {@link WelcomeWidget}, {@link SimpleWelcomeWidget}, {@link ClosableWelcomeWidget}, ...
*/
void setWelcomeWidget(Widget welcome);
void setWelcomeWidgetVisible(boolean isVisible);
}
@@ -1,17 +0,0 @@
package com.sap.sailing.gwt.ui.shared.components;
public interface WelcomeWidget {
/**
* Sets the text of the header component.
* @param headerText The new header text
*/
void setWelcomeHeaderText(String headerText);
/**
* Sets the text of the component under the header
* @param welcomeText The new welcome text
*/
void setWelcomeText(String welcomeText);
}
@@ -1,4 +1,4 @@
package com.sap.sailing.gwt.ui.shared.controls;
package com.sap.sailing.gwt.ui.shared.controls.slider;
/*
* Copyright 2008 Google Inc.
@@ -0,0 +1,51 @@
package com.sap.sailing.gwt.ui.shared.panels;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.sap.sailing.domain.common.impl.Util.Pair;
public class BreadcrumbPanel extends FlowPanel {
interface AnchorTemplates extends SafeHtmlTemplates {
@SafeHtmlTemplates.Template("<a href=\"{0}\">{1}</a>")
SafeHtml anchor(String url, String displayName);
}
public static final AnchorTemplates ANCHORTEMPLATE = GWT.create(AnchorTemplates.class);
public static final String STYLE_NAME_PREFIX = "breadcrumbPanel-";
/**
* Creates a new BreadcrumbPanel with the <code>breadcrumbLinks</code> as active links and <code>actualBreadcrumb</code> as Label
* @param breadcrumbLinksData The data of the breadcrumbs which will be displayed as links. Part A of the pair is the URL and part B the displayed text.
* @param actualBreadcrumbName The text as Label. Should be the name of the component in which the BreadcrumbPanel is displayed.
*/
public BreadcrumbPanel(Iterable<Pair<String, String>> breadcrumbLinksData, String actualBreadcrumbName) {
super();
//Adding the active breadcrumbs
for (Pair<String, String> breadcrumbData : breadcrumbLinksData) {
HTML breadcrumb = new HTML(ANCHORTEMPLATE.anchor(breadcrumbData.getA(), breadcrumbData.getB()));
breadcrumb.addStyleName(STYLE_NAME_PREFIX + "ActiveBreadcrumb");
breadcrumb.getElement().getStyle().setFloat(Style.Float.LEFT);
breadcrumb.getElement().getStyle().setPadding(5, Style.Unit.PX);
add(breadcrumb);
Label nextArrow = new Label(">");
nextArrow.setStyleName(STYLE_NAME_PREFIX + "NextArrow");
nextArrow.getElement().getStyle().setFloat(Style.Float.LEFT);
nextArrow.getElement().getStyle().setPadding(5, Style.Unit.PX);
add(nextArrow);
}
//Adding the actual breadcrumb
Label actualBreadcrumb = new Label(actualBreadcrumbName);
actualBreadcrumb.addStyleName(STYLE_NAME_PREFIX + "InactiveBreadcrumb");
actualBreadcrumb.getElement().getStyle().setFloat(Style.Float.LEFT);
actualBreadcrumb.getElement().getStyle().setPadding(5, Style.Unit.PX);
add(actualBreadcrumb);
}
}
@@ -1,4 +1,4 @@
package com.sap.sailing.gwt.ui.shared.components;
package com.sap.sailing.gwt.ui.shared.panels;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -8,8 +8,8 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
public class ClosableWelcomeWidget extends SimpleWelcomeWidget {
private StringMessages stringConstants;
private Button closeButton;
private boolean closable;
private Button closeButton;
/**
* Creates a new closable welcome widget. It has the same components as the {@link SimpleWelcomeWidget} and a Button
@@ -18,10 +18,9 @@ public class ClosableWelcomeWidget extends SimpleWelcomeWidget {
* @param closable Sets the visibility of the close Button
* @param headerText The text of the header component
* @param welcomeText The text of the component under the header (welcome component)
* @param horizontalAlignment The alignment of the header and the welcomen component
*/
public ClosableWelcomeWidget(boolean closable, String headerText, String welcomeText, HorizontalAlignmentConstant horizontalAlignment, StringMessages stringConstants) {
super(headerText, welcomeText, horizontalAlignment);
public ClosableWelcomeWidget(boolean closable, String headerText, String welcomeText, StringMessages stringConstants) {
super(headerText, welcomeText);
this.stringConstants = stringConstants;
this.closable = closable;
@@ -33,8 +32,8 @@ public class ClosableWelcomeWidget extends SimpleWelcomeWidget {
}
});
closeButton.setVisible(this.closable);
setHorizontalAlignment(ALIGN_RIGHT);
insert(closeButton, 0);
closeButton.setStyleName(STYLE_NAME_PREFIX + "CloseButton");
mainPanel.insert(closeButton, 0);
}
/**
@@ -1,12 +1,13 @@
package com.sap.sailing.gwt.ui.shared.components;
package com.sap.sailing.gwt.ui.shared.panels;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
public class SimpleWelcomeWidget extends VerticalPanel implements WelcomeWidget {
public class SimpleWelcomeWidget extends WelcomeWidget {
protected FlowPanel mainPanel;
private Label welcomeHeader;
private HTML welcomeText;
@@ -14,20 +15,25 @@ public class SimpleWelcomeWidget extends VerticalPanel implements WelcomeWidget
* Creates a VerticalPanel as welcome widget with a header and a welcome message
* @param headerText The text of the header component
* @param welcomeText The text of the welcome message
* @param horizontalAlignment The alignment of the components in the VerticalPanel
*/
public SimpleWelcomeWidget(String headerText, String welcomeText, HorizontalAlignmentConstant horizontalAlignment) {
public SimpleWelcomeWidget(String headerText, String welcomeText) {
super();
setHorizontalAlignment(horizontalAlignment);
mainPanel = new FlowPanel();
mainPanel.setStyleName(STYLE_NAME_PREFIX + "WelcomePanel");
add(mainPanel);
welcomeHeader = new Label(headerText);
add(welcomeHeader);
welcomeHeader.setStyleName(STYLE_NAME_PREFIX + "Header");
mainPanel.add(welcomeHeader);
this.welcomeText = new HTML(new SafeHtmlBuilder().appendEscapedLines(welcomeText).toSafeHtml());
add(this.welcomeText);
this.welcomeText.setStyleName(STYLE_NAME_PREFIX + "WelcomeText");
mainPanel.add(this.welcomeText);
}
@Override
public void setWelcomeText(String welcomeText) {
this.welcomeText = new HTML(new SafeHtmlBuilder().appendEscapedLines(welcomeText).toSafeHtml());
this.welcomeText.setStyleName(STYLE_NAME_PREFIX + "WelcomeText");
}
@Override
@@ -0,0 +1,25 @@
package com.sap.sailing.gwt.ui.shared.panels;
import com.google.gwt.user.client.ui.SimplePanel;
/**
* A WelcomeWidget displays a short message to the user to show him the functionality (or whatever) of the component on which it's displayed.
* @author Lennart Hensler (D054527)
*/
public abstract class WelcomeWidget extends SimplePanel {
final static String STYLE_NAME_PREFIX = "welcomeWidget-";
/**
* Sets the text of the header component.
* @param headerText The new header text
*/
abstract void setWelcomeHeaderText(String headerText);
/**
* Sets the text of the component under the header
* @param welcomeText The new welcome text
*/
abstract void setWelcomeText(String welcomeText);
}
@@ -0,0 +1,134 @@
@CHARSET "ISO-8859-1";
.cellTableWidget {
border-left: 1px solid #c9caca;
border-top: 1px solid #c9caca;
}
/** v-align images in the table header
* grey background for table header
*/
.cellTableHeader {
position: relative;
vertical-align: middle;
background-color: #e5e5e5;
border-right: 1px solid #ffffff !important;
border-top: none !important;
border-bottom: 1px solid #c9caca !important;
padding: 3px 12px;
text-align: center;
}
.cellTableFirstColumnHeader {
position: relative;
vertical-align: middle;
background-color: #e5e5e5;
border-left: none !important;
border-right: 1px solid #ffffff !important;
border-top: none !important;
border-bottom: 1px solid #c9caca !important;
padding: 3px 12px;
text-align: center;
}
.cellTableLastColumnHeader {
position: relative;
vertical-align: middle;
background-color: #e5e5e5;
border-right: 1px solid #c9caca !important;
border-top: none !important;
border-bottom: 1px solid #c9caca !important;
padding: 3px 12px;
text-align: center;
}
.cellTableHeader > span > img:first-child {
position: relative;
vertical-align: middle;
}
.cellTableEvenRow {
border-bottom: 1px solid #e5e5e5;
background-color: rgba(255,255,255,0.5);
}
.cellTableEvenRowCell {
border-right: 1px solid #c9caca !important;
border-left: none;
border-top: none !important;
border-bottom: 1px solid #c9caca !important;
padding: 5px 17px 5px !important;
white-space: nowrap;
}
.cellTableOddRow {
border-bottom: 1px solid #e5e5e5;
background-color: rgba(242,242,242,0.5);
}
.cellTableOddRowCell {
border-left: none !important;
border-right: 1px solid #c9caca !important;
border-top: none !important;
border-bottom: 1px solid #c9caca !important;
padding: 5px 17px 5px !important;
white-space: nowrap;
}
.cellTableHoveredRow {
background-color: rgba(229,242,249,0.5);
border-bottom: 1px solid #e5e5e5;
}
.cellTableSelectedRow {
color: #000000;
background-color: rgba(229,242,249,0.5);
border-right: 2px solid #21a0e4 !important;
border-left: 2px solid #21a0e4 !important;
border: 2px solid #21a0e4;
}
.cellTableSelectedRow > td:FIRST-CHILD {
border-left: 2px solid rgba(33,160,228,0.5) !important;
}
.cellTableSelectedRow > td:LAST-CHILD {
border-right: 2px solid rgba(33,160,228,0.5) !important;
}
.cellTableSelectedRowCell {
border-left: none;
border-right: 1px solid #e5e5e5;
border-top: 2px solid #21a0e4 !important;
border-bottom: 2px solid #21a0e4 !important;
}
.cellTableRaceColumnHeader {
background-color: #e0e0e0;
padding: 3px 12px;
}
.cellTableLegColumnHeader {
background-color: #efefef;
padding: 3px 12px;
}
.cellTableLegDetailColumnHeader {
background-color: #f4f5f6;
padding: 3px 12px;
}
.cellTableRaceColumn {
background-color: #e0e0e0 !important;
}
.cellTableLegColumn {
background-color: #efefef !important;
}
.cellTableLegDetailColumn {
background-color: #ffffff !important;
}
.cellTableTotalColumn {
background-color: #e0e0e0 !important;
}
@@ -0,0 +1,12 @@
package com.sap.sailing.gwt.ui.spectator;
import com.google.gwt.user.cellview.client.CellTable;
import com.sap.sailing.gwt.ui.adminconsole.AdminConsoleTableResources.AdminConsoleTableStyle;
public interface LeaderboardGroupCompactTableResources extends CellTable.Resources {
@Source({ CellTable.Style.DEFAULT_CSS, "LeaderboardGroupFullTable.css" })
AdminConsoleTableStyle cellTableStyle();
interface LeaderboardGroupTableStyle extends CellTable.Style {
}
}
@@ -0,0 +1,134 @@
@CHARSET "ISO-8859-1";
.cellTableWidget {
border-left: 1px solid #c9caca;
border-top: 1px solid #c9caca;
}
/** v-align images in the table header
* grey background for table header
*/
.cellTableHeader {
position: relative;
vertical-align: middle;
background-color: #e5e5e5;
border-right: 1px solid #ffffff !important;
border-top: none !important;
border-bottom: 1px solid #c9caca !important;
padding: 3px 12px;
text-align: center;
}
.cellTableFirstColumnHeader {
position: relative;
vertical-align: middle;
background-color: #e5e5e5;
border-left: none !important;
border-right: 1px solid #ffffff !important;
border-top: none !important;
border-bottom: 1px solid #c9caca !important;
padding: 3px 12px;
text-align: center;
}
.cellTableLastColumnHeader {
position: relative;
vertical-align: middle;
background-color: #e5e5e5;
border-right: 1px solid #c9caca !important;
border-top: none !important;
border-bottom: 1px solid #c9caca !important;
padding: 3px 12px;
text-align: center;
}
.cellTableHeader > span > img:first-child {
position: relative;
vertical-align: middle;
}
.cellTableEvenRow {
border-bottom: 1px solid #e5e5e5;
background-color: rgba(255,255,255,0.5);
}
.cellTableEvenRowCell {
border-right: 1px solid #c9caca !important;
border-left: none;
border-top: none !important;
border-bottom: 1px solid #c9caca !important;
padding: 5px 17px 5px !important;
white-space: nowrap;
}
.cellTableOddRow {
border-bottom: 1px solid #e5e5e5;
background-color: rgba(242,242,242,0.5);
}
.cellTableOddRowCell {
border-left: none !important;
border-right: 1px solid #c9caca !important;
border-top: none !important;
border-bottom: 1px solid #c9caca !important;
padding: 5px 17px 5px !important;
white-space: nowrap;
}
.cellTableHoveredRow {
background-color: rgba(229,242,249,0.5);
border-bottom: 1px solid #e5e5e5;
}
.cellTableSelectedRow {
color: #000000;
background-color: rgba(229,242,249,0.5);
border-right: 2px solid #21a0e4 !important;
border-left: 2px solid #21a0e4 !important;
border: 2px solid #21a0e4;
}
.cellTableSelectedRow > td:FIRST-CHILD {
border-left: 2px solid rgba(33,160,228,0.5) !important;
}
.cellTableSelectedRow > td:LAST-CHILD {
border-right: 2px solid rgba(33,160,228,0.5) !important;
}
.cellTableSelectedRowCell {
border-left: none;
border-right: 1px solid #e5e5e5;
border-top: 2px solid #21a0e4 !important;
border-bottom: 2px solid #21a0e4 !important;
}
.cellTableRaceColumnHeader {
background-color: #e0e0e0;
padding: 3px 12px;
}
.cellTableLegColumnHeader {
background-color: #efefef;
padding: 3px 12px;
}
.cellTableLegDetailColumnHeader {
background-color: #f4f5f6;
padding: 3px 12px;
}
.cellTableRaceColumn {
background-color: #e0e0e0 !important;
}
.cellTableLegColumn {
background-color: #efefef !important;
}
.cellTableLegDetailColumn {
background-color: #ffffff !important;
}
.cellTableTotalColumn {
background-color: #e0e0e0 !important;
}
@@ -0,0 +1,12 @@
package com.sap.sailing.gwt.ui.spectator;
import com.google.gwt.user.cellview.client.CellTable;
import com.sap.sailing.gwt.ui.adminconsole.AdminConsoleTableResources.AdminConsoleTableStyle;
public interface LeaderboardGroupFullTableResources extends CellTable.Resources {
@Source({ CellTable.Style.DEFAULT_CSS, "LeaderboardGroupCompactTable.css" })
AdminConsoleTableStyle cellTableStyle();
interface LeaderboardGroupTableStyle extends CellTable.Style {
}
}
@@ -13,50 +13,61 @@ import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.CaptionPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.NoSelectionModel;
import com.sap.sailing.domain.common.EventNameAndRaceName;
import com.sap.sailing.gwt.ui.adminconsole.LeaderboardConfigPanel.AnchorCell;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.HasWelcomeWidget;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
import com.sap.sailing.gwt.ui.shared.RaceInLeaderboardDTO;
import com.sap.sailing.gwt.ui.shared.components.HasWelcomeWidget;
import com.sap.sailing.gwt.ui.shared.panels.WelcomeWidget;
public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget {
interface AnchorTemplates extends SafeHtmlTemplates {
@SafeHtmlTemplates.Template("<a href=\"{0}\">{1}</a>")
SafeHtml anchor(String url, String displayName);
@SafeHtmlTemplates.Template("<a class=\"{2}\" href=\"{0}\">{1}</a>")
SafeHtml anchor(String url, String displayName, String styleClass);
}
interface TextWithClassTemplate extends SafeHtmlTemplates {
@SafeHtmlTemplates.Template("<span class=\"{1}\">{0}</span>")
SafeHtml textWithClass(String text, String styleClass);
}
private static final AnchorTemplates ANCHORTEMPLATE = GWT.create(AnchorTemplates.class);
private static final int MAX_COLUMNS_IN_ROW = 10;
private static final TextWithClassTemplate TEXTTEMPLATE = GWT.create(TextWithClassTemplate.class);
private static final int MAX_COLUMNS_IN_ROW = 10;
private static final String STYLE_NAME_PREFIX = "leaderboardGroupPanel-";
private SailingServiceAsync sailingService;
private StringMessages stringConstants;
private ErrorReporter errorReporter;
private LeaderboardGroupDTO group;
private String root;
private VerticalPanel mainPanel;
private FlowPanel mainPanel;
private Widget welcomeWidget = null;
public LeaderboardGroupPanel(SailingServiceAsync sailingService, StringMessages stringConstants,
ErrorReporter errorReporter, final String groupName) {
ErrorReporter errorReporter, final String groupName, String root) {
super();
this.sailingService = sailingService;
this.stringConstants = stringConstants;
this.errorReporter = errorReporter;
this.root = root;
if (this.root == null || this.root.length() == 0) {
this.root = "leaderboardGroupPanel";
}
mainPanel = new VerticalPanel();
mainPanel = new FlowPanel();
mainPanel.setWidth("95%");
add(mainPanel);
final Runnable buildGUI = new Runnable() {
@@ -90,23 +101,27 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
private void buildGUI() {
//Create group details GUI
HorizontalPanel groupDetailsPanel = new HorizontalPanel();
groupDetailsPanel.setSpacing(8);
FlowPanel groupDetailsPanel = new FlowPanel();
groupDetailsPanel.setStyleName(STYLE_NAME_PREFIX + "GroupDetailsPanel");
mainPanel.add(groupDetailsPanel);
Label groupNameLabel = new Label(group.name + ":");
groupNameLabel.setStyleName(STYLE_NAME_PREFIX + "GroupName");
groupDetailsPanel.add(groupNameLabel);
//Using HTML to display the line breaks in the description
HTML groupDescriptionLabel = new HTML(new SafeHtmlBuilder().appendEscapedLines(group.description).toSafeHtml());
groupDescriptionLabel.setStyleName(STYLE_NAME_PREFIX + "GroupDescription");
groupDetailsPanel.add(groupDescriptionLabel);
//Create group leaderboards GUI
CaptionPanel leaderboardsCaptionPanel = new CaptionPanel(stringConstants.leaderboards());
mainPanel.add(leaderboardsCaptionPanel);
Label leaderboardsTableLabel = new Label(stringConstants.leaderboards());
leaderboardsTableLabel.setStyleName(STYLE_NAME_PREFIX + "LeaderboardsTableLabel");
mainPanel.add(leaderboardsTableLabel);
if (group.leaderboards.size() <= MAX_COLUMNS_IN_ROW) {
CellTable<Integer> leaderboardsTable = new CellTable<Integer>();
LeaderboardGroupFullTableResources tableResources = GWT.create(LeaderboardGroupFullTableResources.class);
CellTable<Integer> leaderboardsTable = new CellTable<Integer>(200, tableResources);
leaderboardsTable.setWidth("100%");
leaderboardsTable.setSelectionModel(new NoSelectionModel<Integer>());
@@ -133,7 +148,7 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
}
leaderboardsTable.setRowData(tableData);
leaderboardsCaptionPanel.add(leaderboardsTable);
mainPanel.add(leaderboardsTable);
} else {
AnchorCell nameAnchorCell = new AnchorCell();
Column<LeaderboardDTO, SafeHtml> nameColumn = new Column<LeaderboardDTO, SafeHtml>(nameAnchorCell) {
@@ -141,9 +156,9 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
public SafeHtml getValue(LeaderboardDTO leaderboard) {
String debugParam = Window.Location.getParameter("gwt.codesvr");
return ANCHORTEMPLATE.anchor("/gwt/Leaderboard.html?name=" + leaderboard.name
+ "&leaderboardGroupName=" + group.name
+ "&leaderboardGroupName=" + group.name + "&root=" + root
+ (debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr=" + debugParam : ""),
leaderboard.name);
leaderboard.name, STYLE_NAME_PREFIX + "ActiveLeaderboard");
}
};
@@ -155,7 +170,8 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
}
};
CellTable<LeaderboardDTO> leaderboardsTable = new CellTable<LeaderboardDTO>();
LeaderboardGroupCompactTableResources tableResources = GWT.create(LeaderboardGroupCompactTableResources.class);
CellTable<LeaderboardDTO> leaderboardsTable = new CellTable<LeaderboardDTO>(200, tableResources);
leaderboardsTable.setWidth("100%");
leaderboardsTable.setSelectionModel(new NoSelectionModel<LeaderboardDTO>());
@@ -165,7 +181,7 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
leaderboardsTable.setColumnWidth(racesColumn, "70%");
leaderboardsTable.setRowData(group.leaderboards);
leaderboardsCaptionPanel.add(leaderboardsTable);
mainPanel.add(leaderboardsTable);
}
}
@@ -174,18 +190,19 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
SafeHtmlBuilder b = new SafeHtmlBuilder();
String displayName = race.getRaceColumnName();
if (race.getRaceColumnName().equals(stringConstants.overview())) {
String link = "/gwt/Leaderboard.html?name=" + leaderboard.name + "&leaderboardGroupName=" + group.name +
(debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr="+debugParam : "");
b.append(ANCHORTEMPLATE.anchor(link, displayName));
String link = "/gwt/Leaderboard.html?name=" + leaderboard.name + "&leaderboardGroupName=" + group.name
+ "&root=" + root
+ (debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr=" + debugParam : "");
b.append(ANCHORTEMPLATE.anchor(link, displayName, STYLE_NAME_PREFIX + "ActiveLeaderboard"));
} else {
if (race.getRaceIdentifier() != null) {
EventNameAndRaceName raceId = (EventNameAndRaceName) race.getRaceIdentifier();
String link = "/gwt/RaceBoard.html?leaderboardName=" + leaderboard.name + "&raceName=" + raceId.getRaceName()
+ "&eventName=" + raceId.getEventName() + "&leaderboardGroupName=" + group.name
+ "&eventName=" + raceId.getEventName() + "&leaderboardGroupName=" + group.name + "&root=" + root
+ (debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr=" + debugParam : "");
b.append(ANCHORTEMPLATE.anchor(link, displayName));
b.append(ANCHORTEMPLATE.anchor(link, displayName, STYLE_NAME_PREFIX + "ActiveRace"));
} else {
b.appendHtmlConstant(race.getRaceColumnName());
b.append(TEXTTEMPLATE.textWithClass(race.getRaceColumnName(), STYLE_NAME_PREFIX + "InactiveRace"));
}
}
return b.toSafeHtml();
@@ -201,12 +218,12 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
}
if (race.getRaceIdentifier() != null) {
EventNameAndRaceName raceId = (EventNameAndRaceName) race.getRaceIdentifier();
String link = "/gwt/RaceBoard.html?leaderboardName=" + leaderboard.name + "&raceName="
String link = "/gwt/RaceBoard.html?leaderboardName=" + leaderboard.name + "&raceName=" + "&root=" + root
+ raceId.getRaceName() + "&eventName=" + raceId.getEventName() + "&leaderboardGroupName="
+ group.name + (debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr=" + debugParam : "");
b.append(ANCHORTEMPLATE.anchor(link, race.getRaceColumnName()));
b.append(ANCHORTEMPLATE.anchor(link, race.getRaceColumnName(), STYLE_NAME_PREFIX + "ActiveRace"));
} else {
b.appendHtmlConstant(race.getRaceColumnName());
b.append(TEXTTEMPLATE.textWithClass(race.getRaceColumnName(), STYLE_NAME_PREFIX + "InactiveRace"));
}
first = false;
}
@@ -221,7 +238,7 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
}
@Override
public void setWelcomeWidget(Widget welcome) {
public void setWelcomeWidget(WelcomeWidget welcome) {
boolean needsToBeInserted = welcomeWidget == null;
welcomeWidget = welcome;
welcomeWidget.setWidth("100%");
@@ -8,8 +8,7 @@ import com.sap.sailing.gwt.ui.client.AbstractEntryPoint;
import com.sap.sailing.gwt.ui.client.EventRefresher;
import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel;
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
import com.sap.sailing.gwt.ui.shared.components.ClosableWelcomeWidget;
import com.sap.sailing.gwt.ui.shared.components.SimpleWelcomeWidget;
import com.sap.sailing.gwt.ui.shared.panels.ClosableWelcomeWidget;
/**
*
@@ -22,9 +21,7 @@ public class SpectatorEntryPoint extends AbstractEntryPoint implements EventRefr
public void onModuleLoad() {
super.onModuleLoad();
//Fill fixed leaderboard selection
String groupParamValue = Window.Location.getParameter("leaderboardGroupName");
final String groupName;
if(groupParamValue == null || groupParamValue.isEmpty()) {
groupName = null;
@@ -40,6 +37,11 @@ public class SpectatorEntryPoint extends AbstractEntryPoint implements EventRefr
});
}
String root = Window.Location.getParameter("root");
//Check if the root contains an allowed value
if (root != null) {
root = (root.equals("leaderboardGroupPanel") || root.equals("overview")) ? root : null;
}
RootPanel rootPanel = RootPanel.get();
rootPanel.setSize("100%", "100%");
@@ -52,10 +54,10 @@ public class SpectatorEntryPoint extends AbstractEntryPoint implements EventRefr
if (groupName == null) {
panelToDisplay = new OverviewEventPanel(sailingService, this, this, stringMessages);
} else {
panelToDisplay = new LeaderboardGroupPanel(sailingService, stringMessages, this, groupName);
panelToDisplay = new LeaderboardGroupPanel(sailingService, stringMessages, this, groupName, root);
LeaderboardGroupPanel groupPanel = (LeaderboardGroupPanel) panelToDisplay;
groupPanel.setWelcomeWidget(new ClosableWelcomeWidget(true, stringMessages.welcomeToSailingAnalytics(),
"Ipsum lorum\nHello World!", SimpleWelcomeWidget.ALIGN_RIGHT, stringMessages));
"Ipsum lorum\nHello World!", stringMessages));
}
panelToDisplay.setSize("100%", "100%");
rootPanel.add(panelToDisplay);
@@ -25,7 +25,6 @@
<inherits name='com.sap.ui.commons.Module' />
<inherits name="com.google.gwt.resources.Resources" />
<inherits name="com.google.gwt.logging.Logging"/>
<!-- Other module inherits -->
<inherits name="com.sap.sailing.domain.SailingDomain" />