mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-07 12:51:02 +00:00
Merge branch 'master' into mak-change-timepanel-controls
This commit is contained in:
commit
552d10027a
61 files changed
+799
-350
No files matched your search
+10
-3
@@ -57,7 +57,10 @@ public class DeclinationServiceImpl implements DeclinationService {
|
||||
int year = cal.get(Calendar.YEAR);
|
||||
QuadTree<Declination> set;
|
||||
while ((set = getYearStore(year)) != null) {
|
||||
Declination resultForYear = set.get(position);
|
||||
Declination resultForYear;
|
||||
synchronized (set) {
|
||||
resultForYear = set.get(position);
|
||||
}
|
||||
Distance spatialDistance = resultForYear.getPosition().getDistance(position);
|
||||
// consider result only if it's closer than maxDistance
|
||||
if (spatialDistance.compareTo(maxDistance) <= 0) {
|
||||
@@ -73,7 +76,9 @@ public class DeclinationServiceImpl implements DeclinationService {
|
||||
if (result == null) {
|
||||
QuadTree<Declination> importerCacheForYear = importerCache.get(year);
|
||||
if (importerCacheForYear != null) {
|
||||
result = importerCacheForYear.get(position);
|
||||
synchronized (importerCacheForYear) {
|
||||
result = importerCacheForYear.get(position);
|
||||
}
|
||||
if (result.getPosition().getDistance(position).compareTo(maxDistance) <= 0) {
|
||||
return result;
|
||||
// else it's further away from the requested position as demanded by maxDistance
|
||||
@@ -85,7 +90,9 @@ public class DeclinationServiceImpl implements DeclinationService {
|
||||
importerCacheForYear = new QuadTree<Declination>();
|
||||
importerCache.put(year, importerCacheForYear);
|
||||
}
|
||||
importerCacheForYear.put(result.getPosition(), result);
|
||||
synchronized (importerCacheForYear) {
|
||||
importerCacheForYear.put(result.getPosition(), result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
+19
-5
@@ -49,7 +49,9 @@ public class DeclinationStore {
|
||||
result = new QuadTree<Declination>();
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(is));
|
||||
while ((record = readExternal(in)) != null) {
|
||||
result.put(record.getPosition(), record);
|
||||
synchronized (result) {
|
||||
result.put(record.getPosition(), record);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -150,7 +152,10 @@ public class DeclinationStore {
|
||||
System.out.println("Date: " + year + "/" + (month + 1) + ", Latitude: " + lat);
|
||||
for (double lng = 0; lng < 180; lng += grid) {
|
||||
Position point = new DegreePosition(lat, lng);
|
||||
Declination existingDeclinationRecord = storedDeclinations.get(point);
|
||||
Declination existingDeclinationRecord;
|
||||
synchronized (storedDeclinations) {
|
||||
existingDeclinationRecord = storedDeclinations.get(point);
|
||||
}
|
||||
if (existingDeclinationRecord == null
|
||||
|| DeclinationServiceImpl.timeAndSpaceDistance(existingDeclinationRecord
|
||||
.getPosition().getDistance(point), timePoint, existingDeclinationRecord
|
||||
@@ -161,7 +166,10 @@ public class DeclinationStore {
|
||||
}
|
||||
for (double lng = -grid; lng > -180; lng -= grid) {
|
||||
Position point = new DegreePosition(lat, lng);
|
||||
Declination existingDeclinationRecord = storedDeclinations.get(point);
|
||||
Declination existingDeclinationRecord;
|
||||
synchronized (storedDeclinations) {
|
||||
existingDeclinationRecord = storedDeclinations.get(point);
|
||||
}
|
||||
if (existingDeclinationRecord == null
|
||||
|| DeclinationServiceImpl.timeAndSpaceDistance(existingDeclinationRecord
|
||||
.getPosition().getDistance(point), timePoint, existingDeclinationRecord
|
||||
@@ -175,7 +183,10 @@ public class DeclinationStore {
|
||||
System.out.println("Date: " + year + "/" + (month + 1) + ", Latitude: " + lat);
|
||||
for (double lng = 0; lng < 180; lng += grid) {
|
||||
Position point = new DegreePosition(lat, lng);
|
||||
Declination existingDeclinationRecord = storedDeclinations.get(point);
|
||||
Declination existingDeclinationRecord;
|
||||
synchronized (storedDeclinations) {
|
||||
existingDeclinationRecord = storedDeclinations.get(point);
|
||||
}
|
||||
if (DeclinationServiceImpl.timeAndSpaceDistance(existingDeclinationRecord.getPosition().getDistance(point),
|
||||
timePoint, existingDeclinationRecord.getTimePoint()) > 0.1) {
|
||||
// less than ~6 nautical miles and/or ~.6 months off
|
||||
@@ -184,7 +195,10 @@ public class DeclinationStore {
|
||||
}
|
||||
for (double lng = -grid; lng > -180; lng -= grid) {
|
||||
Position point = new DegreePosition(lat, lng);
|
||||
Declination existingDeclinationRecord = storedDeclinations.get(point);
|
||||
Declination existingDeclinationRecord;
|
||||
synchronized (storedDeclinations) {
|
||||
existingDeclinationRecord = storedDeclinations.get(point);
|
||||
}
|
||||
if (DeclinationServiceImpl.timeAndSpaceDistance(existingDeclinationRecord.getPosition().getDistance(point),
|
||||
timePoint, existingDeclinationRecord.getTimePoint()) > 0.1) {
|
||||
// less than ~6 nautical miles and/or ~.6 months off
|
||||
|
||||
@@ -7,4 +7,5 @@ Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
Export-Package: com.sap.sailing.domain.common,
|
||||
com.sap.sailing.domain.common.impl,
|
||||
com.sap.sailing.domain.common.quadtree
|
||||
com.sap.sailing.domain.common.quadtree,
|
||||
com.sap.sailing.domain.common.quadtree.impl;x-friends:="com.sap.sailing.domain.test"
|
||||
+6
-3
@@ -12,9 +12,12 @@ public class AbstractPosition implements Position {
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof Position &&
|
||||
getLatRad() == ((Position) o).getLatRad() &&
|
||||
getLngRad() == ((Position) o).getLngRad();
|
||||
if (o == null) {
|
||||
return false;
|
||||
} else {
|
||||
return o instanceof Position && getLatRad() == ((Position) o).getLatRad()
|
||||
&& getLngRad() == ((Position) o).getLngRad();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
-4
@@ -32,11 +32,16 @@ import com.sap.sailing.domain.common.quadtree.impl.Bounds;
|
||||
import com.sap.sailing.domain.common.quadtree.impl.QuadTreeNode;
|
||||
|
||||
/**
|
||||
* The QuadTree lets you organize objects in a grid, that redefines
|
||||
* itself and focuses more gridding when more objects appear in a
|
||||
* certain area.
|
||||
* The QuadTree lets you organize objects in a grid, that redefines itself and focuses more gridding when more objects
|
||||
* appear in a certain area.
|
||||
* <p>
|
||||
*
|
||||
* @param <T> type of object stored by coordinates
|
||||
* Note that this class is not thread safe. If multiple threads can access the same instance concurrently, callers have
|
||||
* to ensure proper synchronization. Concurrent reads are permissible while any write should block all other operations.
|
||||
*
|
||||
* @param <T>
|
||||
* type of object stored by coordinates
|
||||
* @author Axel Uhl (D043530)
|
||||
*/
|
||||
public class QuadTree<T> implements Serializable {
|
||||
|
||||
|
||||
+3
-5
@@ -110,7 +110,7 @@ public class QuadTreeNode<T> implements Serializable {
|
||||
* into the children.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void split() {
|
||||
protected void split() {
|
||||
// Make sure we're bigger than the minimum, if we care,
|
||||
if (minSize != NO_MIN_SIZE) {
|
||||
if (Math.abs(bounds.getNorthEast().getLatDeg() - bounds.getSouthWest().getLatDeg()) < minSize
|
||||
@@ -121,7 +121,6 @@ public class QuadTreeNode<T> implements Serializable {
|
||||
double nsHalf = (bounds.getNorthEast().getLatDeg() + bounds.getSouthWest().getLatDeg()) / 2.0;
|
||||
double ewHalf = (bounds.getNorthEast().getLngDeg() + bounds.getSouthWest().getLngDeg()) / 2.0;
|
||||
children = new QuadTreeNode[4];
|
||||
|
||||
children[NORTHWEST] = new QuadTreeNode<T>(new Bounds(new DegreePosition(nsHalf, bounds.getSouthWest().getLngDeg()), new DegreePosition(bounds.getNorthEast().getLatDeg(), ewHalf)), maxItems);
|
||||
children[NORTHEAST] = new QuadTreeNode<T>(new Bounds(new DegreePosition(nsHalf, ewHalf), bounds.getNorthEast()), maxItems);
|
||||
children[SOUTHEAST] = new QuadTreeNode<T>(new Bounds(new DegreePosition(bounds.getSouthWest().getLatDeg(), ewHalf), new DegreePosition(nsHalf, bounds.getNorthEast().getLngDeg())), maxItems);
|
||||
@@ -131,7 +130,6 @@ public class QuadTreeNode<T> implements Serializable {
|
||||
for (Iterator<QuadTreeLeaf<T>> i=temp.iterator(); i.hasNext(); ) {
|
||||
put(i.next());
|
||||
}
|
||||
//items.removeAllElements();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,9 +206,9 @@ public class QuadTreeNode<T> implements Serializable {
|
||||
this.allTheSamePoint = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.items.size() > maxItems && !this.allTheSamePoint)
|
||||
if (this.items.size() > maxItems && !this.allTheSamePoint) {
|
||||
split();
|
||||
}
|
||||
} else {
|
||||
QuadTreeNode<T> node = getChild(leaf.getPoint());
|
||||
if (node != null) {
|
||||
|
||||
+2
-1
@@ -51,6 +51,7 @@ import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
@@ -170,7 +171,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
}
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule = new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces);
|
||||
FlexibleLeaderboardImplWithDelayedCarriedPoints result = new FlexibleLeaderboardImplWithDelayedCarriedPoints(
|
||||
(String) o.get(FieldNames.LEADERBOARD_NAME.name()), scoreCorrection, resultDiscardingRule);
|
||||
(String) o.get(FieldNames.LEADERBOARD_NAME.name()), scoreCorrection, resultDiscardingRule, new LowerScoreIsBetter());
|
||||
BasicDBList dbRaceColumns = (BasicDBList) o.get(FieldNames.LEADERBOARD_COLUMNS.name());
|
||||
// For a FlexibleLeaderboard, fleets are owned by the leaderboard's RaceColumn objects. We need to manage them here:
|
||||
Map<String, Fleet> fleetsByName = new HashMap<String, Fleet>();
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
package com.sap.sailing.domain.persistence.impl;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
@@ -60,8 +61,8 @@ public class FlexibleLeaderboardImplWithDelayedCarriedPoints extends FlexibleLea
|
||||
}
|
||||
|
||||
public FlexibleLeaderboardImplWithDelayedCarriedPoints(String name, SettableScoreCorrection scoreCorrection,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(name, scoreCorrection, resultDiscardingRule);
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule, Comparator<Integer> scoreComparator) {
|
||||
super(name, scoreCorrection, resultDiscardingRule, scoreComparator);
|
||||
carriedPointsByCompetitorName = new HashMap<String, Integer>();
|
||||
maxPointsReasonsByCompetitorName = new HashMap<String, Map<RaceColumn,MaxPointsReason>>();
|
||||
correctedScoresByCompetitorName = new HashMap<String, Map<RaceColumn,Integer>>();
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.sap.sailing.domain.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -80,4 +82,46 @@ public class CourseTest {
|
||||
assertEquals(0, Util.size(course.getWaypoints()));
|
||||
assertEquals(0, Util.size(course.getLegs()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertWaypointToCourseWithTwoWaypoints() {
|
||||
List<Waypoint> waypoints = new ArrayList<Waypoint>();
|
||||
final WaypointImpl wp1 = new WaypointImpl(new BuoyImpl("Test Buoy 1"));
|
||||
waypoints.add(wp1);
|
||||
final WaypointImpl wp2 = new WaypointImpl(new BuoyImpl("Test Buoy 2"));
|
||||
waypoints.add(wp2);
|
||||
Course course = new CourseImpl("Test Course", waypoints);
|
||||
assertEquals(2, Util.size(course.getWaypoints()));
|
||||
assertEquals(1, Util.size(course.getLegs()));
|
||||
final WaypointImpl wp1_5 = new WaypointImpl(new BuoyImpl("Test Buoy 1.5"));
|
||||
course.addWaypoint(1, wp1_5);
|
||||
assertEquals(3, Util.size(course.getWaypoints()));
|
||||
assertEquals(2, Util.size(course.getLegs()));
|
||||
assertTrue(Util.equals(Arrays.asList(new Waypoint[] { wp1, wp1_5, wp2 }), course.getWaypoints()));
|
||||
assertEquals(0, course.getIndexOfWaypoint(wp1));
|
||||
assertEquals(1, course.getIndexOfWaypoint(wp1_5));
|
||||
assertEquals(2, course.getIndexOfWaypoint(wp2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemovetWaypointFromCourseWithThreeWaypoints() {
|
||||
List<Waypoint> waypoints = new ArrayList<Waypoint>();
|
||||
final WaypointImpl wp1 = new WaypointImpl(new BuoyImpl("Test Buoy 1"));
|
||||
waypoints.add(wp1);
|
||||
final WaypointImpl wp2 = new WaypointImpl(new BuoyImpl("Test Buoy 2"));
|
||||
waypoints.add(wp2);
|
||||
final WaypointImpl wp3 = new WaypointImpl(new BuoyImpl("Test Buoy 3"));
|
||||
waypoints.add(wp3);
|
||||
Course course = new CourseImpl("Test Course", waypoints);
|
||||
assertEquals(3, Util.size(course.getWaypoints()));
|
||||
assertEquals(2, Util.size(course.getLegs()));
|
||||
course.removeWaypoint(1);
|
||||
assertEquals(2, Util.size(course.getWaypoints()));
|
||||
assertEquals(1, Util.size(course.getLegs()));
|
||||
assertTrue(Util.equals(Arrays.asList(new Waypoint[] { wp1, wp3 }), course.getWaypoints()));
|
||||
assertEquals(0, course.getIndexOfWaypoint(wp1));
|
||||
assertEquals(-1, course.getIndexOfWaypoint(wp2));
|
||||
assertEquals(1, course.getIndexOfWaypoint(wp3));
|
||||
}
|
||||
|
||||
}
|
||||
+3
-1
@@ -20,6 +20,7 @@ import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.WindImpl;
|
||||
@@ -35,7 +36,8 @@ public class LeaderboardForKielWeekTest extends OnlineTracTracBasedTest {
|
||||
|
||||
@Test
|
||||
public void leaderboardWithOneRaceTest() throws URISyntaxException, NoWindException, IOException, InterruptedException {
|
||||
leaderboard = new FlexibleLeaderboardImpl("Kiel Week 2011 505s", new ScoreCorrectionImpl(), new ResultDiscardingRuleImpl(new int[] { 3, 6 }));
|
||||
leaderboard = new FlexibleLeaderboardImpl("Kiel Week 2011 505s", new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(new int[] { 3, 6 }), new LowerScoreIsBetter());
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
MillisecondsTimePoint now = MillisecondsTimePoint.now();
|
||||
loadRace("357c700a-9d9a-11e0-85be-406186cbf87c"); // 505 Race 2
|
||||
|
||||
+5
-4
@@ -25,6 +25,7 @@ import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
@@ -85,7 +86,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
@Test
|
||||
public void ensureMedalRaceParamIsIgnoredIfRaceColumnAlreadyExists() {
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ScoreCorrectionImpl(), new ResultDiscardingRuleImpl(
|
||||
new int[] { 5, 8 }));
|
||||
new int[] { 5, 8 }), new LowerScoreIsBetter());
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
final String columnName = "abc";
|
||||
setupRaces(1, 0);
|
||||
@@ -108,7 +109,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
}
|
||||
ScoreCorrectionImpl scoreCorrection = new ScoreCorrectionImpl();
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", scoreCorrection, new ResultDiscardingRuleImpl(
|
||||
new int[] { 1 }));
|
||||
new int[] { 1 }), new LowerScoreIsBetter());
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
int i=0;
|
||||
int bestScore = Integer.MAX_VALUE;
|
||||
@@ -144,7 +145,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
}
|
||||
ScoreCorrectionImpl scoreCorrection = new ScoreCorrectionImpl();
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", scoreCorrection, new ResultDiscardingRuleImpl(
|
||||
new int[] { 1 }));
|
||||
new int[] { 1 }), new LowerScoreIsBetter());
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
int i=0;
|
||||
int bestScore = Integer.MAX_VALUE;
|
||||
@@ -171,7 +172,7 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
int secondDiscardingThreshold, Integer carry, boolean addOneMedalRace, int numberOfUntrackedRaces) throws NoWindException {
|
||||
setupRaces(numberOfStartedRaces, numberOfNotStartedRaces);
|
||||
FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl("Test Leaderboard", new ScoreCorrectionImpl(), new ResultDiscardingRuleImpl(
|
||||
new int[] { firstDiscardingThreshold, secondDiscardingThreshold }));
|
||||
new int[] { firstDiscardingThreshold, secondDiscardingThreshold }), new LowerScoreIsBetter());
|
||||
Fleet defaultFleet = leaderboard.getFleet(null);
|
||||
int i=0;
|
||||
for (TrackedRace race : testRaces) {
|
||||
|
||||
+30
-1
@@ -22,9 +22,11 @@ import com.sap.sailing.domain.base.impl.FleetImpl;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.base.impl.SeriesImpl;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
|
||||
import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
@@ -36,7 +38,7 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
private Leaderboard createLeaderboard(Regatta regatta, int[] discardingThresholds) {
|
||||
ScoreCorrectionImpl scoreCorrections = new ScoreCorrectionImpl();
|
||||
ResultDiscardingRuleImpl discardingRules = new ResultDiscardingRuleImpl(discardingThresholds);
|
||||
return new RegattaLeaderboardImpl(regatta, scoreCorrections, discardingRules);
|
||||
return new RegattaLeaderboardImpl(regatta, scoreCorrections, discardingRules, new LowerScoreIsBetter());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -56,6 +58,33 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
assertEquals(competitors, rankedCompetitors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the competitors ranking worse than the disqualified competitor advance by one
|
||||
*/
|
||||
@Test
|
||||
public void testOneStartedRaceWithDifferentScoresAndDisqualification() {
|
||||
List<Competitor> competitors = createCompetitors(10);
|
||||
Regatta regatta = createRegatta(/* qualifying */0, new String[] { "Default" }, /* final */1,
|
||||
new String[] { "Default" },
|
||||
/* medal */false, "testOneStartedRaceWithDifferentScores",
|
||||
DomainFactory.INSTANCE.getOrCreateBoatClass("49er", /* typicallyStartsUpwind */true));
|
||||
Leaderboard leaderboard = createLeaderboard(regatta, /* discarding thresholds */ new int[0]);
|
||||
Series finalSeries;
|
||||
Iterator<? extends Series> seriesIter = regatta.getSeries().iterator();
|
||||
seriesIter.next();
|
||||
finalSeries = seriesIter.next();
|
||||
leaderboard.getScoreCorrection().setMaxPointsReason(competitors.get(5), finalSeries.getRaceColumnByName("F1"), MaxPointsReason.DSQ);
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
|
||||
TrackedRace f1 = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors);
|
||||
RaceColumn f1Column = series.get(1).getRaceColumnByName("F1");
|
||||
f1Column.setTrackedRace(f1Column.getFleets().iterator().next(), f1);
|
||||
List<Competitor> rankedCompetitors = leaderboard.getCompetitorsFromBestToWorst(later);
|
||||
assertEquals(competitors.subList(0, 5), rankedCompetitors.subList(0, 5));
|
||||
assertEquals(competitors.subList(6, 10), rankedCompetitors.subList(5, 9));
|
||||
assertEquals(competitors.get(5), rankedCompetitors.get(9));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistributionAcrossQualifyingFleetsWithDifferentScores() {
|
||||
List<Competitor> competitors = createCompetitors(10);
|
||||
|
||||
+6
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
@@ -43,6 +44,11 @@ public class MockedTrackedRaceWithFixedRank extends MockedTrackedRace {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) {
|
||||
return Collections.singletonList(competitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStarted(TimePoint at) {
|
||||
return started;
|
||||
|
||||
+5
@@ -412,4 +412,9 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) {
|
||||
return competitorsFromBestToWorst;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
package com.sap.sailing.domain.test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.quadtree.QuadTree;
|
||||
import com.sap.sailing.domain.common.quadtree.impl.QuadTreeNode;
|
||||
|
||||
public class QuadTreeTest {
|
||||
private class GLatLngQuadTree extends QuadTree<Position> {
|
||||
@@ -21,6 +23,53 @@ public class QuadTreeTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static class QuadTreeWithPublicGetTop<T> extends QuadTree<T> {
|
||||
private static final long serialVersionUID = -783622065160380333L;
|
||||
@Override
|
||||
public QuadTreeNode<T> getTop() {
|
||||
return super.getTop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoNPEDuringSecondPutInSameLeaf() {
|
||||
final QuadTreeWithPublicGetTop<Object> qt = new QuadTreeWithPublicGetTop<Object>();
|
||||
final Position p = new DegreePosition(0, 0);
|
||||
final NullPointerException[] npe = new NullPointerException[1];
|
||||
final boolean[] stop = new boolean[1];
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stop[0]) {
|
||||
synchronized (qt) {
|
||||
try {
|
||||
qt.wait();
|
||||
// if the following try/catch is moved outside the synchronized block, occasional NPEs result
|
||||
try {
|
||||
qt.put(p, p);
|
||||
} catch (NullPointerException e) {
|
||||
npe[0] = e;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
new Thread(r, "1").start();
|
||||
new Thread(r, "2").start();
|
||||
new Thread(r, "3").start();
|
||||
new Thread(r, "4").start();
|
||||
for (int i=0; i<10000000; i++) {
|
||||
synchronized(qt) {
|
||||
qt.notifyAll();
|
||||
}
|
||||
assertNull("NullPointerException "+(npe[0]==null?"":npe[0].getMessage())+" during iteration "+i, npe[0]);
|
||||
}
|
||||
stop[0] = true;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDistance() {
|
||||
GLatLngQuadTree quadtree = new GLatLngQuadTree(new DegreePosition(49.29,
|
||||
|
||||
+6
@@ -620,4 +620,10 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,8 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
*/
|
||||
public interface RaceColumn extends Named {
|
||||
/**
|
||||
* @return the fleets for each of which this column has a single race and therefore optionally a {@link TrackedRace}
|
||||
* @return the fleets for each of which this column has a single race and therefore optionally a {@link TrackedRace}, in
|
||||
* ascending order; best fleets first
|
||||
*/
|
||||
Iterable<? extends Fleet> getFleets();
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@ import com.sap.sailing.domain.common.Named;
|
||||
*
|
||||
*/
|
||||
public interface Series extends Named {
|
||||
/**
|
||||
* Returns the fleets of this series, on ascending order, better fleets first.
|
||||
*/
|
||||
Iterable<? extends Fleet> getFleets();
|
||||
|
||||
/**
|
||||
|
||||
@@ -87,6 +87,14 @@ public class CourseImpl extends NamedImpl implements Course {
|
||||
@Override
|
||||
public synchronized void addWaypoint(int zeroBasedPosition, Waypoint waypointToAdd) {
|
||||
waypoints.add(zeroBasedPosition, waypointToAdd);
|
||||
Map<Waypoint, Integer> updatesToWaypointIndexes = new HashMap<Waypoint, Integer>();
|
||||
updatesToWaypointIndexes.put(waypointToAdd, zeroBasedPosition);
|
||||
for (Map.Entry<Waypoint, Integer> e : waypointIndexes.entrySet()) {
|
||||
if (e.getValue() >= zeroBasedPosition) {
|
||||
updatesToWaypointIndexes.put(e.getKey(), e.getValue()+1);
|
||||
}
|
||||
}
|
||||
waypointIndexes.putAll(updatesToWaypointIndexes);
|
||||
int legStartWaypointIndex;
|
||||
if (zeroBasedPosition == waypoints.size()-1) { // added to end
|
||||
legStartWaypointIndex = zeroBasedPosition-1;
|
||||
@@ -104,6 +112,14 @@ public class CourseImpl extends NamedImpl implements Course {
|
||||
if (zeroBasedPosition >= 0) {
|
||||
boolean isLast = zeroBasedPosition == waypoints.size()-1;
|
||||
Waypoint removedWaypoint = waypoints.remove(zeroBasedPosition);
|
||||
waypointIndexes.remove(removedWaypoint);
|
||||
Map<Waypoint, Integer> updatesToWaypointIndexes = new HashMap<Waypoint, Integer>();
|
||||
for (Map.Entry<Waypoint, Integer> e : waypointIndexes.entrySet()) {
|
||||
if (e.getValue() > zeroBasedPosition) { // only > because the entry with == was just removed
|
||||
updatesToWaypointIndexes.put(e.getKey(), e.getValue()-1);
|
||||
}
|
||||
}
|
||||
waypointIndexes.putAll(updatesToWaypointIndexes);
|
||||
if (isLast) {
|
||||
if (waypoints.size() > 0) { // if we had only one waypoint, we didn't have any legs
|
||||
// last waypoint was removed; remove last leg
|
||||
@@ -167,7 +183,7 @@ public class CourseImpl extends NamedImpl implements Course {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexOfWaypoint(Waypoint waypoint) {
|
||||
public synchronized int getIndexOfWaypoint(Waypoint waypoint) {
|
||||
int result = -1;
|
||||
Integer indexEntry = waypointIndexes.get(waypoint);
|
||||
if (indexEntry != null) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.base.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -13,6 +14,7 @@ import com.sap.sailing.domain.common.impl.NamedImpl;
|
||||
public class SeriesImpl extends NamedImpl implements Series {
|
||||
private static final long serialVersionUID = -1640404303144907381L;
|
||||
private final Map<String, Fleet> fleetsByName;
|
||||
private final List<Fleet> fleetsInAscendingOrder;
|
||||
private final Iterable<RaceColumnInSeriesImpl> raceColumns;
|
||||
private boolean isMedal;
|
||||
|
||||
@@ -22,6 +24,8 @@ public class SeriesImpl extends NamedImpl implements Series {
|
||||
for (Fleet fleet : fleets) {
|
||||
this.fleetsByName.put(fleet.getName(), fleet);
|
||||
}
|
||||
fleetsInAscendingOrder = new ArrayList<Fleet>(fleetsByName.values());
|
||||
Collections.sort(fleetsInAscendingOrder);
|
||||
List<RaceColumnInSeriesImpl> myRaceColumns = new ArrayList<RaceColumnInSeriesImpl>();
|
||||
for (String raceColumnName : raceColumnNames) {
|
||||
RaceColumnInSeriesImpl raceColumn = new RaceColumnInSeriesImpl(raceColumnName, this);
|
||||
@@ -32,7 +36,7 @@ public class SeriesImpl extends NamedImpl implements Series {
|
||||
}
|
||||
|
||||
public Iterable<? extends Fleet> getFleets() {
|
||||
return fleetsByName.values();
|
||||
return fleetsInAscendingOrder;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+44
-5
@@ -5,6 +5,7 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -18,6 +19,7 @@ import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ScoreCorrection;
|
||||
import com.sap.sailing.domain.leaderboard.ScoreCorrection.Result;
|
||||
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
@@ -46,6 +48,8 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
|
||||
* provided by this map are considered by {@link #getTotalPoints(Competitor, TimePoint)}.
|
||||
*/
|
||||
private final Map<Competitor, Integer> carriedPoints;
|
||||
|
||||
private final Comparator<Integer> scoreComparator;
|
||||
|
||||
/**
|
||||
* A leaderboard entry representing a snapshot of a cell at a given time point for a single race/competitor.
|
||||
@@ -96,13 +100,16 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scoreComparator the comparator to use to compare basic scores, such as net points
|
||||
* @param name must not be <code>null</code>
|
||||
*/
|
||||
public AbstractLeaderboardImpl(SettableScoreCorrection scoreCorrection, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
public AbstractLeaderboardImpl(SettableScoreCorrection scoreCorrection,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule, Comparator<Integer> scoreComparator) {
|
||||
this.carriedPoints = new HashMap<Competitor, Integer>();
|
||||
this.scoreCorrection = scoreCorrection;
|
||||
this.displayNames = new HashMap<Competitor, String>();
|
||||
this.resultDiscardingRule = resultDiscardingRule;
|
||||
this.scoreComparator = scoreComparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -186,7 +193,38 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
|
||||
@Override
|
||||
public int getTrackedRank(Competitor competitor, RaceColumn race, TimePoint timePoint) throws NoWindException {
|
||||
final TrackedRace trackedRace = race.getTrackedRace(competitor);
|
||||
return trackedRace == null ? 0 : trackedRace.hasStarted(timePoint) ? trackedRace.getRank(competitor, timePoint) : 0;
|
||||
return trackedRace == null ? 0
|
||||
: trackedRace.hasStarted(timePoint) ? improveByDisqualificationsOfBetterRankedCompetitors(race, trackedRace, timePoint, trackedRace
|
||||
.getRank(competitor, timePoint)) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Per competitor disqualified ({@link ScoreCorrection} has a {@link MaxPointsReason} for the competitor), all
|
||||
* competitors ranked worse by the tracking system need to have their rank corrected by one.
|
||||
* @param trackedRace the race to which the rank refers; look for disqualifications / max points reasons in this column
|
||||
* @param timePoint
|
||||
* time point at which to consider disqualifications (not used yet because currently we don't remember
|
||||
* <em>when</em> a competitor was disqualified)
|
||||
* @param rank a competitors rank according to the tracking system
|
||||
*
|
||||
* @return the unmodified <code>rank</code> if no disqualifications for better-ranked competitors exist for <code>race</code>,
|
||||
* or otherwise a rank improved (lowered) by the number of disqualifications of competitors whose tracked rank is better (lower)
|
||||
* than <code>rank</code>.
|
||||
*/
|
||||
private int improveByDisqualificationsOfBetterRankedCompetitors(RaceColumn raceColumn, TrackedRace trackedRace, TimePoint timePoint, int rank) {
|
||||
int correctedRank = rank;
|
||||
List<Competitor> competitorsFromBestToWorst = trackedRace.getCompetitorsFromBestToWorst(timePoint);
|
||||
int betterCompetitorRank=1;
|
||||
Iterator<Competitor> ci = competitorsFromBestToWorst.iterator();
|
||||
while (betterCompetitorRank < rank && ci.hasNext()) {
|
||||
Competitor betterTrackedCompetitor = ci.next();
|
||||
MaxPointsReason maxPointsReasonForBetterCompetitor = getScoreCorrection().getMaxPointsReason(betterTrackedCompetitor, raceColumn);
|
||||
if (maxPointsReasonForBetterCompetitor != null && maxPointsReasonForBetterCompetitor != MaxPointsReason.NONE) {
|
||||
correctedRank--;
|
||||
}
|
||||
betterCompetitorRank++;
|
||||
}
|
||||
return correctedRank;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -233,7 +271,8 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
|
||||
boolean discarded = isDiscarded(competitor, race, timePoint);
|
||||
return new EntryImpl(trackedPoints, correctedResults.getCorrectedScore(), correctedResults.isCorrected(),
|
||||
discarded ? 0
|
||||
: correctedResults.getCorrectedScore() * (race.isMedalRace() ? 2 : 1), correctedResults.getMaxPointsReason(), discarded);
|
||||
: correctedResults.getCorrectedScore() * (race.isMedalRace() ? MEDAL_RACE_FACTOR : 1),
|
||||
correctedResults.getMaxPointsReason(), discarded);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -345,7 +384,7 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
|
||||
} else {
|
||||
comparisonResult = netPointsAndFleet.get(o1).getB().compareTo(netPointsAndFleet.get(o2).getB());
|
||||
if (comparisonResult == 0) {
|
||||
comparisonResult = netPointsAndFleet.get(o1).getA() - netPointsAndFleet.get(o2).getA();
|
||||
comparisonResult = scoreComparator.compare(netPointsAndFleet.get(o1).getA(), netPointsAndFleet.get(o2).getA());
|
||||
}
|
||||
}
|
||||
return comparisonResult;
|
||||
@@ -365,6 +404,6 @@ public abstract class AbstractLeaderboardImpl implements Leaderboard {
|
||||
}
|
||||
|
||||
protected Comparator<? super Competitor> getTotalRankComparator(TimePoint timePoint) {
|
||||
return new LeaderboardTotalRankComparator(this, timePoint);
|
||||
return new LeaderboardTotalRankComparator(this, timePoint, scoreComparator);
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.leaderboard.impl;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -31,8 +32,8 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
|
||||
private String name;
|
||||
|
||||
public FlexibleLeaderboardImpl(String name, SettableScoreCorrection scoreCorrection,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(scoreCorrection, resultDiscardingRule);
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule, Comparator<Integer> scoreComparator) {
|
||||
super(scoreCorrection, resultDiscardingRule, scoreComparator);
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("A leaderboard's name must not be null");
|
||||
}
|
||||
|
||||
+5
-8
@@ -46,11 +46,13 @@ import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
public class LeaderboardTotalRankComparator implements Comparator<Competitor> {
|
||||
private final Leaderboard leaderboard;
|
||||
private final TimePoint timePoint;
|
||||
private final Comparator<Integer> scoreComparator;
|
||||
|
||||
public LeaderboardTotalRankComparator(Leaderboard leaderboard, TimePoint timePoint) {
|
||||
public LeaderboardTotalRankComparator(Leaderboard leaderboard, TimePoint timePoint, Comparator<Integer> scoreComparator) {
|
||||
super();
|
||||
this.leaderboard = leaderboard;
|
||||
this.timePoint = timePoint;
|
||||
this.scoreComparator = scoreComparator;
|
||||
}
|
||||
|
||||
protected Leaderboard getLeaderboard() {
|
||||
@@ -202,19 +204,14 @@ public class LeaderboardTotalRankComparator implements Comparator<Competitor> {
|
||||
* the integer numbers by their natural ordering.
|
||||
*/
|
||||
protected Comparator<Integer> getScoreComparator() {
|
||||
return new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer o1, Integer o2) {
|
||||
return o1-o2;
|
||||
}
|
||||
};
|
||||
return scoreComparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation ranks a competitor better (lesser) if it has the lower score sum
|
||||
*/
|
||||
protected int compareByScoreSum(int o1ScoreSum, int o2ScoreSum) {
|
||||
return o1ScoreSum - o2ScoreSum;
|
||||
return getScoreComparator().compare(o1ScoreSum, o2ScoreSum);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
package com.sap.sailing.domain.leaderboard.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* The score comparator as used by the ISAF standard scoring scheme. Lower scores are better.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class LowerScoreIsBetter implements Comparator<Integer>, Serializable {
|
||||
private static final long serialVersionUID = -2767385186133743330L;
|
||||
|
||||
@Override
|
||||
public int compare(Integer o1, Integer o2) {
|
||||
return o1-o2;
|
||||
}
|
||||
|
||||
}
|
||||
+10
-1
@@ -1,5 +1,9 @@
|
||||
package com.sap.sailing.domain.leaderboard.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.impl.AbstractRaceColumn;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
|
||||
@@ -17,7 +21,12 @@ public class RaceColumnImpl extends AbstractRaceColumn implements FlexibleRaceCo
|
||||
public RaceColumnImpl(String name, boolean medalRace, Iterable<Fleet> fleets) {
|
||||
super(name);
|
||||
this.medalRace = medalRace;
|
||||
this.fleets = fleets;
|
||||
List<Fleet> myFleets = new ArrayList<Fleet>();
|
||||
for (Fleet fleet : fleets) {
|
||||
myFleets.add(fleet);
|
||||
}
|
||||
Collections.sort(myFleets);
|
||||
this.fleets = myFleets;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-2
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.leaderboard.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
@@ -22,8 +23,9 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl {
|
||||
private static final long serialVersionUID = 2370461218294770084L;
|
||||
private final Regatta regatta;
|
||||
|
||||
public RegattaLeaderboardImpl(Regatta regatta, SettableScoreCorrection scoreCorrection, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(scoreCorrection, resultDiscardingRule);
|
||||
public RegattaLeaderboardImpl(Regatta regatta, SettableScoreCorrection scoreCorrection,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule, Comparator<Integer> scoreComparator) {
|
||||
super(scoreCorrection, resultDiscardingRule, scoreComparator);
|
||||
this.regatta = regatta;
|
||||
}
|
||||
|
||||
|
||||
@@ -391,4 +391,10 @@ public interface TrackedRace extends Serializable {
|
||||
WindStore getWindStore();
|
||||
|
||||
Competitor getOverallLeader(TimePoint timePoint) throws NoWindException;
|
||||
|
||||
/**
|
||||
* Returns the competitors of this tracked race, according to their ranking. Competitors whose {@link #getRank(Competitor)} is 0 will
|
||||
* be sorted "worst".
|
||||
*/
|
||||
List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint);
|
||||
}
|
||||
+1
@@ -104,6 +104,7 @@ public class TrackedLegImpl implements TrackedLeg, RaceChangeListener {
|
||||
}
|
||||
// ensure that race isn't updated by events as we're tying to sort the competitors
|
||||
synchronized (getTrackedRace()) {
|
||||
// TODO See bug 469; competitors already disqualified may need to be ranked worst
|
||||
Collections.sort(rankedCompetitorList, new WindwardToGoComparator(this, timePoint));
|
||||
rankedCompetitorList = Collections.unmodifiableList(rankedCompetitorList);
|
||||
synchronized (competitorTracksOrderedByRank) {
|
||||
|
||||
+10
-3
@@ -610,7 +610,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
public synchronized Competitor getOverallLeader(TimePoint timePoint) throws NoWindException {
|
||||
try {
|
||||
Competitor result = null;
|
||||
List<Competitor> ranks = getRanks(timePoint);
|
||||
List<Competitor> ranks = getCompetitorsFromBestToWorst(timePoint);
|
||||
if (ranks != null && !ranks.isEmpty()) {
|
||||
result = ranks.iterator().next();
|
||||
}
|
||||
@@ -623,13 +623,20 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
@Override
|
||||
public synchronized int getRank(Competitor competitor, TimePoint timePoint) throws NoWindException {
|
||||
try {
|
||||
return getRanks(timePoint).indexOf(competitor) + 1;
|
||||
int result;
|
||||
if (getMarkPassings(competitor).isEmpty()) {
|
||||
result = 0;
|
||||
} else {
|
||||
result = getCompetitorsFromBestToWorst(timePoint).indexOf(competitor) + 1;
|
||||
}
|
||||
return result;
|
||||
} catch (NoWindError e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Competitor> getRanks(TimePoint timePoint) {
|
||||
@Override
|
||||
public List<Competitor> getCompetitorsFromBestToWorst(TimePoint timePoint) {
|
||||
synchronized (competitorRankings) {
|
||||
List<Competitor> rankedCompetitors = competitorRankings.get(timePoint);
|
||||
if (rankedCompetitors == null) {
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<property name="expedition.udp.port" value="2010" />
|
||||
<property name="mongo.port" value="10200" />
|
||||
<property name="osgi.noShutdown" value="true" />
|
||||
<property name="replication.brokerURL" value="tcp://localhost:61616" />
|
||||
<property name="replication.brokerURL" value="tcp://0.0.0.0:61616" />
|
||||
<property name="replication.persistenceDir" value="." />
|
||||
<property name="replication.useJMX" value="false" />
|
||||
</configurations>
|
||||
|
||||
+9
-3
@@ -194,7 +194,9 @@ public class ReverseGeocoderImpl implements ReverseGeocoder {
|
||||
private void cachePlacemarks(Position position, Double radius, List<Placemark> placemarks) {
|
||||
Collections.sort(placemarks, new Placemark.ByDistance(position));
|
||||
if (position != null) {
|
||||
cache.put(position, new Triple<Position, Double, List<Placemark>>(position, radius, placemarks));
|
||||
synchronized (cache) {
|
||||
cache.put(position, new Triple<Position, Double, List<Placemark>>(position, radius, placemarks));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +213,9 @@ public class ReverseGeocoderImpl implements ReverseGeocoder {
|
||||
*/
|
||||
private void updateCachedPlacemarks(Position cachedPoint, Double newRadius, List<Placemark> newPlacemarks) {
|
||||
if (cachedPoint != null) {
|
||||
cache.replace(cachedPoint, new Triple<Position, Double, List<Placemark>>(cachedPoint, newRadius, newPlacemarks));
|
||||
synchronized (cache) {
|
||||
cache.replace(cachedPoint, new Triple<Position, Double, List<Placemark>>(cachedPoint, newRadius, newPlacemarks));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +227,9 @@ public class ReverseGeocoderImpl implements ReverseGeocoder {
|
||||
* {@link ReverseGeocoderImpl#POSITION_CACHE_DISTANCE_LIMIT the distance limit}
|
||||
*/
|
||||
private Triple<Position, Double, List<Placemark>> checkCache(Position position) {
|
||||
return cache.get(position, POSITION_CACHE_DISTANCE_LIMIT);
|
||||
synchronized (cache) {
|
||||
return cache.get(position, POSITION_CACHE_DISTANCE_LIMIT);
|
||||
}
|
||||
}
|
||||
|
||||
private JSONArray callNearestService(Position position) throws MalformedURLException, IOException, ParseException {
|
||||
|
||||
@@ -143,15 +143,23 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.titleLabel {
|
||||
.titleLabelWrapper {
|
||||
position: absolute;
|
||||
width: 400px;
|
||||
text-align: right;
|
||||
font-family: 'UbuntuMedium', Arial, Verdana, sans-serif;
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
right: 5px;
|
||||
top: 41px;
|
||||
min-width: 400px;
|
||||
text-align: right;
|
||||
height: 68px;
|
||||
right: 0;
|
||||
top: 0;
|
||||
font-family: 'UbuntuMedium', Arial, Verdana, sans-serif;
|
||||
font-size: 16px;
|
||||
color: #fff;
|
||||
//background: url(images/titleLabelWrapper.png) right center no-repeat;
|
||||
}
|
||||
|
||||
.titleLabel {
|
||||
background: url(images/titleLabelInner.png) left center no-repeat;
|
||||
height: 26px;
|
||||
padding: 41px 7px 0 130px;
|
||||
}
|
||||
|
||||
|
||||
@@ -297,9 +305,9 @@
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
background-image: url(images/header_bg_modern_eventname.png), url(images/white_gradient_header.png), url(images/header_bg_modern.png);
|
||||
background-position: right top, center top, 0 0;
|
||||
background-repeat: no-repeat, no-repeat, repeat-x;
|
||||
background-image: url(images/white_gradient_header.png), url(images/header_bg_modern.png);
|
||||
background-position: center top, 0 0;
|
||||
background-repeat: no-repeat, repeat-x;
|
||||
box-shadow: 0 0 20px #858585;
|
||||
-moz-box-shadow: 0 0 20px #858585;
|
||||
-webkit-box-shadow: 0 0 20px #858585;
|
||||
|
||||
@@ -111,7 +111,45 @@ input.opencoloumn {
|
||||
right:0;
|
||||
}
|
||||
|
||||
.globalNavigation-home {
|
||||
.globalNavigation-home {
|
||||
border-radius: 0px 0px 4px 4px;
|
||||
-moz-border-radius: 0px 0px 4px 4px;
|
||||
-webkit-border-radius: 0px 0px 4px 4px;
|
||||
margin: 0 10px 0 0;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.globalNavigation-home a{
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
background: url(images/globalNavigation-home_bg.png) 5px center no-repeat #7c7b7c;
|
||||
padding: 5px 6px 5px 25px;
|
||||
border-radius: 0px 0px 4px 4px;
|
||||
-moz-border-radius: 0px 0px 4px 4px;
|
||||
-webkit-border-radius: 0px 0px 4px 4px;
|
||||
}
|
||||
|
||||
.globalNavigation-leaderBoard {
|
||||
border-radius: 0px 0px 4px 4px;
|
||||
-moz-border-radius: 0px 0px 4px 4px;
|
||||
-webkit-border-radius: 0px 0px 4px 4px;
|
||||
margin: 0 5px 0 0;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.globalNavigation-leaderBoard a {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
background: url(images/globalNavigation-leaderBoard_bg.png) 5px center no-repeat #7c7b7c;
|
||||
border-radius: 0px 0px 4px 4px;
|
||||
-moz-border-radius: 0px 0px 4px 4px;
|
||||
-webkit-border-radius: 0px 0px 4px 4px;
|
||||
padding: 5px 6px 5px 25px;
|
||||
}
|
||||
|
||||
.globalNavigation-leaderBoardGroup {
|
||||
background: url(images/globalNavigation-home_bg.png) 5px center no-repeat #7c7b7c;
|
||||
border-radius: 0px 0px 4px 4px;
|
||||
-moz-border-radius: 0px 0px 4px 4px;
|
||||
@@ -121,33 +159,14 @@ input.opencoloumn {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.globalNavigation-home a{
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.globalNavigation-leaderBoard {
|
||||
background: url(images/globalNavigation-leaderBoard_bg.png) 5px center no-repeat #7c7b7c;
|
||||
border-radius: 0px 0px 4px 4px;
|
||||
-moz-border-radius: 0px 0px 4px 4px;
|
||||
-webkit-border-radius: 0px 0px 4px 4px;
|
||||
padding: 5px 6px 5px 25px;
|
||||
margin: 0 10px 0 0;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.globalNavigation-leaderBoard a {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.globalNavigation-leaderBoardGroup {
|
||||
background-color: gray;
|
||||
.globalNavigation-leaderBoardGroup a {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.raceBoardNavigation {
|
||||
float: left;
|
||||
margin: 3px;;
|
||||
margin: 9px 0 0 7px;
|
||||
font-family: 'UbuntuLight', Arial, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
@@ -196,6 +215,40 @@ input.opencoloumn {
|
||||
|
||||
.raceBoardNavigation-settingsButtonPanel {
|
||||
float: right;
|
||||
margin: 3px;;
|
||||
margin: 9px 12px 0 0;
|
||||
}
|
||||
|
||||
.raceBoardNavigation-settingsButton {
|
||||
background: url(images/settings_white.png), url(images/btn-cta-orangeleft.png);
|
||||
background-position: center, center 0;
|
||||
background-repeat: no-repeat, repeat-x;
|
||||
width: 27px;
|
||||
height: 23px;
|
||||
margin: 0 5px 0 1px;
|
||||
-webkit-border-radius: 0px 3px 3px 0px;
|
||||
border-radius: 0px 3px 3px 0px;
|
||||
}
|
||||
|
||||
.raceBoardNavigation-settingsButton:hover {
|
||||
background-image: url(images/settings_white.png), url(images/btn-cta-orangeleft.png);
|
||||
background-position: center, center -30px;
|
||||
background-repeat: no-repeat, repeat-x;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.raceBoardNavigation-innerElement {
|
||||
background: url("images/btn-cta-orangeleft.png") repeat-x scroll center 0 transparent;
|
||||
border-bottom-left-radius: 3px;
|
||||
border-top-left-radius: 3px;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
font-family: UbuntuBold,Verdana,Arial,sans-serif;
|
||||
font-size: 14px;
|
||||
margin: 0 0 0 0;
|
||||
padding: 2px 7px 2px 3px;
|
||||
height: 19px;
|
||||
}
|
||||
.raceBoardNavigation-innerElement:hover {
|
||||
background: url("images/btn-cta-orangeleft.png") repeat-x scroll center -30px transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 743 B |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
+5
-1
@@ -22,9 +22,13 @@ public class LogoAndTitlePanel extends FlowPanel {
|
||||
sailingAnalyticsLabel.addStyleName("sailingAnalyticsLabel boldLabel");
|
||||
this.add(labelPanel);
|
||||
|
||||
FlowPanel titleLabelWrapper = new FlowPanel();
|
||||
titleLabelWrapper.addStyleName("titleLabelWrapper");
|
||||
titleLabel = new Label(title);
|
||||
titleLabel.addStyleName("titleLabel");
|
||||
this.add(titleLabel);
|
||||
titleLabelWrapper.add(titleLabel);
|
||||
this.add(titleLabelWrapper);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+13
-13
@@ -45,9 +45,9 @@ import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
|
||||
import com.google.gwt.view.client.SelectionModel;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.ui.actions.AsyncActionsExecutor;
|
||||
import com.sap.sailing.gwt.ui.actions.GetLeaderboardByNameAction;
|
||||
import com.sap.sailing.gwt.ui.client.Collator;
|
||||
@@ -63,7 +63,6 @@ import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
|
||||
import com.sap.sailing.gwt.ui.client.Timer.PlayStates;
|
||||
import com.sap.sailing.gwt.ui.client.UserAgentChecker.UserAgentTypes;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LegDetailColumn.LegDetailField;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.NetPointsComparator.SortOrderCalculator;
|
||||
import com.sap.sailing.gwt.ui.shared.CompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardEntryDTO;
|
||||
@@ -478,17 +477,18 @@ public class LeaderboardPanel extends FormPanel implements TimeListener, PlaySta
|
||||
|
||||
@Override
|
||||
public Comparator<LeaderboardRowDTO> getComparator() {
|
||||
if (race.isMedalRace()) {
|
||||
return getLeaderboard().getMedalRaceComparator(race.getRaceColumnName());
|
||||
} else {
|
||||
SortOrderCalculator sortOrderCalculator = new SortOrderCalculator() {
|
||||
@Override
|
||||
public boolean isAscending() {
|
||||
return isSortedAscendingForThisColumn(getLeaderboardPanel().getLeaderboardTable());
|
||||
}
|
||||
};
|
||||
return new NetPointsComparator(sortOrderCalculator, race.getRaceColumnName());
|
||||
}
|
||||
return new Comparator<LeaderboardRowDTO>() {
|
||||
@Override
|
||||
public int compare(LeaderboardRowDTO o1, LeaderboardRowDTO o2) {
|
||||
List<CompetitorDTO> competitorsFromBestToWorst = getLeaderboard().getCompetitorsFromBestToWorst(race);
|
||||
boolean ascending = isSortedAscendingForThisColumn(getLeaderboardPanel().getLeaderboardTable());
|
||||
int o1Rank = competitorsFromBestToWorst.indexOf(o1.competitor) + 1;
|
||||
int o2Rank = competitorsFromBestToWorst.indexOf(o2.competitor) + 1;
|
||||
return o1Rank == 0 ? o2Rank == 0 ? 0
|
||||
: ascending ? 1 : -1 : o2Rank == 0 ? ascending ? -1 : 1
|
||||
: o1Rank - o2Rank;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -326,7 +326,7 @@ public class LegColumn extends ExpandableSortableColumn<String> {
|
||||
@Override
|
||||
public String getValue(LeaderboardRowDTO row) {
|
||||
LegEntryDTO legEntry = getLegEntry(row);
|
||||
if (legEntry != null) {
|
||||
if (legEntry != null && legEntry.rank != 0) {
|
||||
return ""+legEntry.rank;
|
||||
} else {
|
||||
return "";
|
||||
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
package com.sap.sailing.gwt.ui.leaderboard;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardEntryDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardRowDTO;
|
||||
|
||||
public class NetPointsComparator implements Comparator<LeaderboardRowDTO> {
|
||||
private final SortOrderCalculator sortOrderCalculator;
|
||||
private final String raceName;
|
||||
|
||||
public interface SortOrderCalculator {
|
||||
boolean isAscending();
|
||||
}
|
||||
|
||||
public NetPointsComparator(SortOrderCalculator sortOrderCalculator, String raceName) {
|
||||
super();
|
||||
this.sortOrderCalculator = sortOrderCalculator;
|
||||
this.raceName = raceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* sorts a meaningless <code>0</code> value to the bottom always, regardless whether ascending/descending sorting is
|
||||
* requested
|
||||
*/
|
||||
@Override
|
||||
public int compare(LeaderboardRowDTO o1, LeaderboardRowDTO o2) {
|
||||
boolean ascending = sortOrderCalculator.isAscending();
|
||||
LeaderboardEntryDTO o1Entry = o1.fieldsByRaceName.get(raceName);
|
||||
LeaderboardEntryDTO o2Entry = o2.fieldsByRaceName.get(raceName);
|
||||
return (o1Entry == null || o1Entry.netPoints == 0) ? (o2Entry == null || o2Entry.netPoints == 0) ? 0
|
||||
: ascending ? 1 : -1 : (o2Entry == null || o2Entry.netPoints == 0) ? ascending ? -1 : 1
|
||||
: o1Entry.netPoints - o2Entry.netPoints;
|
||||
}
|
||||
}
|
||||
+10
-8
@@ -34,12 +34,12 @@ public class GlobalNavigationPanel extends FlowPanel {
|
||||
String homeLink = spectatorViewLink;
|
||||
|
||||
if(showHomeNavigation) {
|
||||
addNavigationLink(stringMessages.home(), homeLink, "home");
|
||||
}
|
||||
|
||||
if (leaderboardGroupName != null && !leaderboardGroupName.isEmpty()) {
|
||||
String leaderBoardGroupLink = spectatorViewLink + "?leaderboardGroupName=" + leaderboardGroupName;
|
||||
addNavigationLink(leaderboardGroupName, leaderBoardGroupLink, "leaderBoardGroup");
|
||||
if (leaderboardGroupName != null && !leaderboardGroupName.isEmpty()) {
|
||||
String leaderBoardGroupLink = spectatorViewLink + "?leaderboardGroupName=" + leaderboardGroupName;
|
||||
addNavigationLink(leaderboardGroupName, leaderBoardGroupLink, "leaderBoardGroup", "Go to the Event overview.");
|
||||
} else {
|
||||
addNavigationLink(stringMessages.home(), homeLink, "home", "Go to the Event overview.");
|
||||
}
|
||||
}
|
||||
|
||||
if (leaderboardName != null && !leaderboardName.isEmpty()) {
|
||||
@@ -47,11 +47,12 @@ public class GlobalNavigationPanel extends FlowPanel {
|
||||
if (leaderboardGroupName != null && !leaderboardGroupName.isEmpty()) {
|
||||
leaderBoardLink += "&leaderboardGroupName=" + leaderboardGroupName;
|
||||
}
|
||||
addNavigationLink(leaderboardName, leaderBoardLink, "leaderBoard");
|
||||
addNavigationLink(leaderboardName, leaderBoardLink, "leaderBoard", "Go to the overview and see all Races in one Leaderboard");
|
||||
}
|
||||
}
|
||||
|
||||
private void addNavigationLink(String linkName, String linkUrl, String styleNameExtension) {
|
||||
private void addNavigationLink(String linkName, String linkUrl, String styleNameExtension, String htmlTitle) {
|
||||
String setHtmlTitle = htmlTitle;
|
||||
String url = linkUrl;
|
||||
if(debugParam != null && !debugParam.isEmpty()) {
|
||||
url += url.contains("?") ? "&" : "?";
|
||||
@@ -60,6 +61,7 @@ public class GlobalNavigationPanel extends FlowPanel {
|
||||
|
||||
HTML linkHtml = new HTML(ANCHORTEMPLATE.anchor(URLFactory.INSTANCE.encode(url), linkName));
|
||||
linkHtml.addStyleName(STYLE_NAME_PREFIX + styleNameExtension);
|
||||
linkHtml.setTitle(setHtmlTitle);
|
||||
add(linkHtml);
|
||||
}
|
||||
}
|
||||
-2
@@ -183,9 +183,7 @@ public class RaceBoardEntryPoint extends AbstractEntryPoint {
|
||||
|
||||
FlowPanel toolbarPanel = new FlowPanel();
|
||||
|
||||
//TODO Quickfix for touch devices
|
||||
toolbarPanel.add(raceBoardPanel.getNavigationWidget());
|
||||
toolbarPanel.add(raceBoardPanel.getSettingsWidget());
|
||||
|
||||
FlowPanel logoAndTitlePanel = createLogoAndTitlePanel(raceBoardPanel);
|
||||
FlowPanel timePanel = createTimePanel(raceBoardPanel);
|
||||
|
||||
+25
-38
@@ -17,7 +17,6 @@ import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.FormPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.MenuBar;
|
||||
import com.google.gwt.user.client.ui.ToggleButton;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
@@ -175,23 +174,10 @@ public class RaceBoardPanel extends FormPanel implements RegattaDisplayer, RaceS
|
||||
mainPanel.add(componentViewer.getViewerWidget());
|
||||
}
|
||||
|
||||
settingsPanel = new FlowPanel();
|
||||
settingsPanel.addStyleName("raceBoardNavigation-settingsButtonPanel");
|
||||
Label settingsLabel = new Label("Settings: ");
|
||||
settingsLabel.addStyleName("raceBoardNavigation-settingsLabel");
|
||||
settingsLabel.getElement().getStyle().setFloat(Style.Float.LEFT);
|
||||
settingsLabel.getElement().getStyle().setPadding(3, Style.Unit.PX);
|
||||
settingsPanel.add(settingsLabel);
|
||||
|
||||
addSettingsMenuButton(settingsPanel, leaderboardPanel);
|
||||
addSettingsMenuButton(settingsPanel, raceMap);
|
||||
addSettingsMenuButton(settingsPanel, windChart);
|
||||
addSettingsMenuButton(settingsPanel, competitorChart);
|
||||
|
||||
addComponentAsCheckboxToNavigationMenu(leaderboardAndMapViewer, leaderboardPanel);
|
||||
addComponentAsCheckboxToNavigationMenu(leaderboardAndMapViewer, windChart);
|
||||
addComponentAsCheckboxToNavigationMenu(leaderboardAndMapViewer, competitorChart);
|
||||
|
||||
addComponentToNavigationMenu(leaderboardAndMapViewer, leaderboardPanel, true);
|
||||
addComponentToNavigationMenu(leaderboardAndMapViewer, windChart, true);
|
||||
addComponentToNavigationMenu(leaderboardAndMapViewer, competitorChart, true);
|
||||
addComponentToNavigationMenu(leaderboardAndMapViewer, raceMap, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@@ -205,23 +191,6 @@ public class RaceBoardPanel extends FormPanel implements RegattaDisplayer, RaceS
|
||||
}
|
||||
}
|
||||
|
||||
private <SettingsType> void addSettingsMenuButton(FlowPanel settingsPanel, final Component<SettingsType> component) {
|
||||
if(component.hasSettings()) {
|
||||
Button settingsButton = new Button(component.getLocalizedShortName());
|
||||
settingsButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
new SettingsDialog<SettingsType>(component, stringMessages).show();
|
||||
}
|
||||
});
|
||||
settingsButton.addStyleName("raceBoardNavigation-settingsButton");
|
||||
settingsButton.getElement().getStyle().setFloat(Style.Float.LEFT);
|
||||
settingsButton.getElement().getStyle().setPadding(3, Style.Unit.PX);
|
||||
|
||||
settingsPanel.add(settingsButton);
|
||||
}
|
||||
}
|
||||
|
||||
private LeaderboardPanel createLeaderboardPanel(String leaderboardName, String leaderboardGroupName) {
|
||||
LeaderboardSettings leaderBoardSettings = LeaderboardSettingsFactory.getInstance()
|
||||
.createNewSettingsForPlayMode(timer.getPlayMode(), /* nameOfRaceToSort */
|
||||
@@ -232,13 +201,15 @@ public class RaceBoardPanel extends FormPanel implements RegattaDisplayer, RaceS
|
||||
userAgentType);
|
||||
}
|
||||
|
||||
private void addComponentAsCheckboxToNavigationMenu(final ComponentViewer componentViewer,
|
||||
final Component<?> component) {
|
||||
private <SettingsType> void addComponentToNavigationMenu(final ComponentViewer componentViewer,
|
||||
final Component<SettingsType> component, boolean withCheckbox) {
|
||||
final CheckBox checkBox= new CheckBox(component.getLocalizedShortName());
|
||||
checkBox.getElement().getStyle().setFloat(Style.Float.LEFT);
|
||||
|
||||
|
||||
checkBox.setEnabled(withCheckbox);
|
||||
checkBox.setValue(component.isVisible());
|
||||
checkBox.setTitle(stringMessages.showHideComponent(component.getLocalizedShortName()));
|
||||
checkBox.addStyleName("raceBoardNavigation-innerElement");
|
||||
|
||||
checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
@@ -259,6 +230,22 @@ public class RaceBoardPanel extends FormPanel implements RegattaDisplayer, RaceS
|
||||
});
|
||||
|
||||
componentsNavigationPanel.add(checkBox);
|
||||
|
||||
if(component.hasSettings()) {
|
||||
Button settingsButton = new Button("");
|
||||
settingsButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
new SettingsDialog<SettingsType>(component, stringMessages).show();
|
||||
}
|
||||
});
|
||||
settingsButton.addStyleName("raceBoardNavigation-settingsButton");
|
||||
settingsButton.getElement().getStyle().setFloat(Style.Float.LEFT);
|
||||
settingsButton.setTitle(stringMessages.settingsForComponent(component.getLocalizedShortName()));
|
||||
|
||||
componentsNavigationPanel.add(settingsButton);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void addComponentAsToogleButtonToNavigationMenu(final ComponentViewer componentViewer,
|
||||
|
||||
+34
-16
@@ -19,6 +19,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -214,8 +215,11 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
|
||||
|
||||
private final Executor executor;
|
||||
|
||||
private final WeakHashMap<Competitor, CompetitorDTO> weakCompetitorDTOCache;
|
||||
|
||||
public SailingServiceImpl() {
|
||||
BundleContext context = Activator.getDefault();
|
||||
weakCompetitorDTOCache = new WeakHashMap<Competitor, CompetitorDTO>();
|
||||
racingEventServiceTracker = createAndOpenRacingEventServiceTracker(context);
|
||||
replicationServiceTracker = createAndOpenReplicationServiceTracker(context);
|
||||
mongoObjectFactory = MongoFactory.INSTANCE.getDefaultMongoObjectFactory();
|
||||
@@ -258,7 +262,7 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
|
||||
result.name = leaderboard.getName();
|
||||
result.competitorDisplayNames = new HashMap<CompetitorDTO, String>();
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
result.createEmptyRaceColumn(raceColumn.getName(), raceColumn.isMedalRace());
|
||||
RaceColumnDTO raceColumnDTO = result.createEmptyRaceColumn(raceColumn.getName(), raceColumn.isMedalRace());
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
RegattaAndRaceIdentifier raceIdentifier = null;
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
@@ -269,6 +273,7 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
|
||||
result.addRace(raceColumn.getName(), fleet.getName(), raceColumn.isMedalRace(),
|
||||
raceIdentifier, /* StrippedRaceDTO */ null);
|
||||
}
|
||||
result.setCompetitorsFromBestToWorst(raceColumnDTO, getCompetitorDTOList(leaderboard.getCompetitorsFromBestToWorst(raceColumn, timePoint)));
|
||||
}
|
||||
result.rows = new HashMap<CompetitorDTO, LeaderboardRowDTO>();
|
||||
result.hasCarriedPoints = leaderboard.hasCarriedPoints();
|
||||
@@ -285,15 +290,15 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
|
||||
final Entry entry = leaderboard.getEntry(competitor, raceColumn, timePoint);
|
||||
RunnableFuture<LeaderboardEntryDTO> future = new FutureTask<LeaderboardEntryDTO>(new Callable<LeaderboardEntryDTO>() {
|
||||
@Override
|
||||
public LeaderboardEntryDTO call() {
|
||||
try {
|
||||
return getLeaderboardEntryDTO(entry, raceColumn.getTrackedRace(competitor), competitor, timePoint,
|
||||
namesOfRaceColumnsForWhichToLoadLegDetails != null
|
||||
&& namesOfRaceColumnsForWhichToLoadLegDetails.contains(raceColumn.getName()));
|
||||
} catch (NoWindException e) {
|
||||
throw new NoWindError(e);
|
||||
}
|
||||
}
|
||||
public LeaderboardEntryDTO call() {
|
||||
try {
|
||||
return getLeaderboardEntryDTO(entry, raceColumn.getTrackedRace(competitor), competitor, timePoint,
|
||||
namesOfRaceColumnsForWhichToLoadLegDetails != null
|
||||
&& namesOfRaceColumnsForWhichToLoadLegDetails.contains(raceColumn.getName()));
|
||||
} catch (NoWindException e) {
|
||||
throw new NoWindError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
executor.execute(future);
|
||||
futuresForColumnName.put(raceColumn.getName(), future);
|
||||
@@ -319,6 +324,14 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<CompetitorDTO> getCompetitorDTOList(List<Competitor> competitorsFromBestToWorst) {
|
||||
List<CompetitorDTO> result = new ArrayList<CompetitorDTO>();
|
||||
for (Competitor competitor : competitorsFromBestToWorst) {
|
||||
result.add(getCompetitorDTO(competitor));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stressTestLeaderboardByName(String leaderboardName, int times) throws Exception {
|
||||
Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
|
||||
@@ -474,12 +487,17 @@ public class SailingServiceImpl extends RemoteServiceServlet implements SailingS
|
||||
}
|
||||
|
||||
private CompetitorDTO getCompetitorDTO(Competitor c) {
|
||||
CountryCode countryCode = c.getTeam().getNationality().getCountryCode();
|
||||
CompetitorDTO competitorDTO = new CompetitorDTO(c.getName(), countryCode == null ? ""
|
||||
: countryCode.getTwoLetterISOCode(), countryCode == null ? "" : countryCode.getThreeLetterIOCCode(),
|
||||
countryCode == null ? "" : countryCode.getName(), c.getBoat().getSailID(), c.getId().toString(),
|
||||
new BoatClassDTO(c.getBoat().getBoatClass().getName(), c.getBoat().getBoatClass().getHullLength()
|
||||
.getMeters()));
|
||||
CompetitorDTO competitorDTO = weakCompetitorDTOCache.get(c);
|
||||
if (competitorDTO == null) {
|
||||
CountryCode countryCode = c.getTeam().getNationality().getCountryCode();
|
||||
competitorDTO = new CompetitorDTO(c.getName(), countryCode == null ? ""
|
||||
: countryCode.getTwoLetterISOCode(),
|
||||
countryCode == null ? "" : countryCode.getThreeLetterIOCCode(), countryCode == null ? ""
|
||||
: countryCode.getName(), c.getBoat().getSailID(), c.getId().toString(),
|
||||
new BoatClassDTO(c.getBoat().getBoatClass().getName(), c.getBoat().getBoatClass().getHullLength()
|
||||
.getMeters()));
|
||||
weakCompetitorDTOCache.put(c, competitorDTO);
|
||||
}
|
||||
return competitorDTO;
|
||||
}
|
||||
|
||||
|
||||
+6
-43
@@ -2,7 +2,6 @@ package com.sap.sailing.gwt.ui.shared;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -32,10 +31,6 @@ public abstract class AbstractLeaderboardDTO implements IsSerializable {
|
||||
}
|
||||
}
|
||||
|
||||
public Comparator<LeaderboardRowDTO> getMedalRaceComparator(String medalRaceName) {
|
||||
return new MedalRaceComparator(medalRaceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the race whose name is specified in <code>raceName</code> has any competitor who has valid
|
||||
* {@link LeaderboardEntryDTO#legDetails} for that race, the number of entries in the leg details is returned,
|
||||
@@ -72,39 +67,6 @@ public abstract class AbstractLeaderboardDTO implements IsSerializable {
|
||||
return totalPoints;
|
||||
}
|
||||
|
||||
private class MedalRaceComparator implements Comparator<LeaderboardRowDTO> {
|
||||
private final String medalRaceName;
|
||||
|
||||
public MedalRaceComparator(String medalRaceName) {
|
||||
this.medalRaceName = medalRaceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(LeaderboardRowDTO o1, LeaderboardRowDTO o2) {
|
||||
int result;
|
||||
if (scoredInMedalRace(o1.competitor)) {
|
||||
if (scoredInMedalRace(o2.competitor)) {
|
||||
// both scored in medal race
|
||||
result = o1.fieldsByRaceName.get(medalRaceName).netPoints
|
||||
- o2.fieldsByRaceName.get(medalRaceName).netPoints;
|
||||
} else {
|
||||
// only o1 scored in medal race, so o1 scores better = "less"
|
||||
result = -1;
|
||||
}
|
||||
} else {
|
||||
if (scoredInMedalRace(o2.competitor)) {
|
||||
// only o2 scored in medal race, so o2 scores better, o1 scores worse = "greater"
|
||||
result = 1;
|
||||
} else {
|
||||
// neither one scored in any medal race; to be considered equal for medal race comparison
|
||||
result = 0;
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public int getNetPoints(CompetitorDTO competitor, String nameOfLastRaceSoFar) {
|
||||
int result = 0;
|
||||
LeaderboardRowDTO row = rows.get(competitor);
|
||||
@@ -186,11 +148,12 @@ public abstract class AbstractLeaderboardDTO implements IsSerializable {
|
||||
races.add(index, raceInLeaderboardDTO);
|
||||
}
|
||||
|
||||
public void createEmptyRaceColumn(String raceColumnName, boolean medalRace) {
|
||||
RaceColumnDTO raceInLeaderboardDTO = new RaceColumnDTO();
|
||||
raceInLeaderboardDTO.setRaceColumnName(raceColumnName);
|
||||
raceInLeaderboardDTO.setMedalRace(medalRace);
|
||||
races.add(raceInLeaderboardDTO);
|
||||
public RaceColumnDTO createEmptyRaceColumn(String raceColumnName, boolean medalRace) {
|
||||
RaceColumnDTO raceColumn = new RaceColumnDTO();
|
||||
raceColumn.setRaceColumnName(raceColumnName);
|
||||
raceColumn.setMedalRace(medalRace);
|
||||
races.add(raceColumn);
|
||||
return raceColumn;
|
||||
}
|
||||
|
||||
protected RaceColumnDTO getRaceInLeaderboardByName(String raceColumnName) {
|
||||
|
||||
+15
-1
@@ -1,6 +1,8 @@
|
||||
package com.sap.sailing.gwt.ui.shared;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
||||
|
||||
@@ -17,8 +19,20 @@ public class LeaderboardDTO extends AbstractLeaderboardDTO implements IsSerializ
|
||||
* The competitor list, ordered ascending by total rank
|
||||
*/
|
||||
public List<CompetitorDTO> competitors;
|
||||
|
||||
private Map<RaceColumnDTO, List<CompetitorDTO>> competitorOrderingPerRace;
|
||||
|
||||
public LeaderboardDTO() {}
|
||||
public LeaderboardDTO() {
|
||||
competitorOrderingPerRace = new HashMap<RaceColumnDTO, List<CompetitorDTO>>();
|
||||
}
|
||||
|
||||
public void setCompetitorsFromBestToWorst(RaceColumnDTO raceColumn, List<CompetitorDTO> orderedCompetitors) {
|
||||
competitorOrderingPerRace.put(raceColumn, orderedCompetitors);
|
||||
}
|
||||
|
||||
public List<CompetitorDTO> getCompetitorsFromBestToWorst(RaceColumnDTO raceColumn) {
|
||||
return competitorOrderingPerRace.get(raceColumn);
|
||||
}
|
||||
|
||||
public int getRank(CompetitorDTO competitor) {
|
||||
return competitors.indexOf(competitor) + 1;
|
||||
|
||||
+3
-6
@@ -13,7 +13,7 @@ import com.google.gwt.user.client.rpc.IsSerializable;
|
||||
public class LegEntryDTO implements IsSerializable {
|
||||
public Double distanceTraveledInMeters;
|
||||
public Double averageSpeedOverGroundInKnots;
|
||||
public Integer rank;
|
||||
public int rank;
|
||||
public Double gapToLeaderInSeconds;
|
||||
public Double estimatedTimeToNextWaypointInSeconds;
|
||||
|
||||
@@ -57,7 +57,7 @@ public class LegEntryDTO implements IsSerializable {
|
||||
result = prime * result + ((numberOfJibes == null) ? 0 : numberOfJibes.hashCode());
|
||||
result = prime * result + ((numberOfPenaltyCircles == null) ? 0 : numberOfPenaltyCircles.hashCode());
|
||||
result = prime * result + ((numberOfTacks == null) ? 0 : numberOfTacks.hashCode());
|
||||
result = prime * result + ((rank == null) ? 0 : rank.hashCode());
|
||||
result = prime * result + rank;
|
||||
result = prime * result + (started ? 1231 : 1237);
|
||||
result = prime * result + (int) (timeInMilliseconds ^ (timeInMilliseconds >>> 32));
|
||||
result = prime * result + ((velocityMadeGoodInKnots == null) ? 0 : velocityMadeGoodInKnots.hashCode());
|
||||
@@ -116,10 +116,7 @@ public class LegEntryDTO implements IsSerializable {
|
||||
return false;
|
||||
} else if (!numberOfTacks.equals(other.numberOfTacks))
|
||||
return false;
|
||||
if (rank == null) {
|
||||
if (other.rank != null)
|
||||
return false;
|
||||
} else if (!rank.equals(other.rank))
|
||||
if (rank != other.rank)
|
||||
return false;
|
||||
if (started != other.started)
|
||||
return false;
|
||||
|
||||
+69
-50
@@ -79,6 +79,12 @@ implements CompetitorSelectionChangeListener, RequiresResize {
|
||||
private long stepSize = 5000;
|
||||
private DetailType dataToShow;
|
||||
private final CompetitorSelectionProvider competitorSelectionProvider;
|
||||
|
||||
/**
|
||||
* When the chart is not visible and the competitor selection changes, no loading is performed. However, in this case
|
||||
* we need to remember that loading will be necessary as soon as the chart becomes visible.
|
||||
*/
|
||||
private boolean needToLoadWhenMadeVisible;
|
||||
|
||||
public AbstractChartPanel(SailingServiceAsync sailingService, AsyncActionsExecutor asyncActionsExecutor,
|
||||
CompetitorSelectionProvider competitorSelectionProvider, RaceSelectionProvider raceSelectionProvider,
|
||||
@@ -104,6 +110,14 @@ implements CompetitorSelectionChangeListener, RequiresResize {
|
||||
timer.addTimeListener(this);
|
||||
timeZoomProvider.addTimeZoomChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
super.setVisible(visible);
|
||||
if (needToLoadWhenMadeVisible) {
|
||||
loadData(/* showBusyIndicator */ true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new chart for the given {@link DetailType} <code>dataToShow</code> and also
|
||||
@@ -120,7 +134,6 @@ implements CompetitorSelectionChangeListener, RequiresResize {
|
||||
.setMarginRight(65)
|
||||
.setBorderColor(new Color("#A6A6A6"))
|
||||
.setBorderWidth(1)
|
||||
// .setBackgroundColor(new Color("#C6C6C6"))
|
||||
.setChartSubtitle(new ChartSubtitle().setText(stringMessages.clickAndDragToZoomIn()))
|
||||
.setLinePlotOptions(new LinePlotOptions().setLineWidth(LINE_WIDTH).setMarker(new Marker().setEnabled(false).setHoverState(
|
||||
new Marker().setEnabled(true).setRadius(4))).setShadow(false)
|
||||
@@ -211,60 +224,70 @@ implements CompetitorSelectionChangeListener, RequiresResize {
|
||||
* @param showBusyIndicator If <code>true</code> is the busy indicator shown while loading the data from the server.
|
||||
*/
|
||||
protected void loadData(boolean showBusyIndicator) {
|
||||
if (needsDataLoading()) {
|
||||
if (showBusyIndicator) {
|
||||
setWidget(chart);
|
||||
showLoading("Loading competitor data...");
|
||||
}
|
||||
if (chartData == null || chartData.getDetailType() != getDataToShow()) {
|
||||
chartData = new MultiCompetitorRaceDataDTO(getDataToShow());
|
||||
}
|
||||
|
||||
// Date toDate = new Date(System.currentTimeMillis() - timer.getLivePlayDelayInMillis());
|
||||
final ArrayList<Pair<Date, CompetitorDTO>> dataQuery = new ArrayList<Pair<Date, CompetitorDTO>>();
|
||||
for (CompetitorDTO competitor : getVisibleCompetitors()) {
|
||||
Date chartDataDateOfNewestData = chartData.getDateOfNewestData();
|
||||
Date competitorDateOfNewestData = chartData.contains(competitor) ? chartData.getCompetitorData(competitor).getDateOfNewestData() : null;
|
||||
if (!chartData.contains(competitor)) {
|
||||
dataQuery.add(new Pair<Date, CompetitorDTO>(new Date(0), competitor));
|
||||
} else if (competitorDateOfNewestData.before(chartDataDateOfNewestData) || competitorDateOfNewestData.before(maxTimepoint)) {
|
||||
dataQuery.add(new Pair<Date, CompetitorDTO>(new Date(competitorDateOfNewestData.getTime() + getStepSize()), competitor));
|
||||
if (isVisible()) {
|
||||
if (hasVisibleCompetitors()) {
|
||||
needToLoadWhenMadeVisible = false; // we're loading it now
|
||||
if (showBusyIndicator) {
|
||||
setWidget(chart);
|
||||
showLoading("Loading competitor data...");
|
||||
}
|
||||
if (chartData == null || chartData.getDetailType() != getDataToShow()) {
|
||||
chartData = new MultiCompetitorRaceDataDTO(getDataToShow());
|
||||
}
|
||||
}
|
||||
|
||||
GetCompetitorsRaceDataAction getCompetitorsRaceDataAction = new GetCompetitorsRaceDataAction(sailingService,
|
||||
selectedRaceIdentifier, dataQuery, maxTimepoint, getStepSize(), getDataToShow(),
|
||||
new AsyncCallback<MultiCompetitorRaceDataDTO>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(getStringMessages().failedToLoadRaceData() + ": " + caught.toString(),
|
||||
// Date toDate = new Date(System.currentTimeMillis() - timer.getLivePlayDelayInMillis());
|
||||
final ArrayList<Pair<Date, CompetitorDTO>> dataQuery = new ArrayList<Pair<Date, CompetitorDTO>>();
|
||||
for (CompetitorDTO competitor : getVisibleCompetitors()) {
|
||||
Date chartDataDateOfNewestData = chartData.getDateOfNewestData();
|
||||
Date competitorDateOfNewestData = chartData.contains(competitor) ? chartData.getCompetitorData(
|
||||
competitor).getDateOfNewestData() : null;
|
||||
if (!chartData.contains(competitor)) {
|
||||
dataQuery.add(new Pair<Date, CompetitorDTO>(new Date(0), competitor));
|
||||
} else if (competitorDateOfNewestData.before(chartDataDateOfNewestData)
|
||||
|| competitorDateOfNewestData.before(maxTimepoint)) {
|
||||
dataQuery.add(new Pair<Date, CompetitorDTO>(new Date(competitorDateOfNewestData.getTime()
|
||||
+ getStepSize()), competitor));
|
||||
}
|
||||
}
|
||||
|
||||
GetCompetitorsRaceDataAction getCompetitorsRaceDataAction = new GetCompetitorsRaceDataAction(
|
||||
sailingService, selectedRaceIdentifier, dataQuery, maxTimepoint, getStepSize(),
|
||||
getDataToShow(), new AsyncCallback<MultiCompetitorRaceDataDTO>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(
|
||||
getStringMessages().failedToLoadRaceData() + ": " + caught.toString(),
|
||||
timer.getPlayMode() == PlayModes.Live);
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(MultiCompetitorRaceDataDTO result) {
|
||||
if (result != null) {
|
||||
for (CompetitorRaceDataDTO competitorData : result.getAllRaceData()) {
|
||||
if (chartData.contains(competitorData.getCompetitor())) {
|
||||
chartData.addCompetitorRaceData(competitorData);
|
||||
chartData.setCompetitorMarkPassingsData(competitorData);
|
||||
} else {
|
||||
chartData.setCompetitorData(competitorData.getCompetitor(), competitorData);
|
||||
@Override
|
||||
public void onSuccess(MultiCompetitorRaceDataDTO result) {
|
||||
if (result != null) {
|
||||
for (CompetitorRaceDataDTO competitorData : result.getAllRaceData()) {
|
||||
if (chartData.contains(competitorData.getCompetitor())) {
|
||||
chartData.addCompetitorRaceData(competitorData);
|
||||
chartData.setCompetitorMarkPassingsData(competitorData);
|
||||
} else {
|
||||
chartData.setCompetitorData(competitorData.getCompetitor(), competitorData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
chart.getXAxis().setMin(minTimepoint.getTime());
|
||||
chart.getXAxis().setMax(maxTimepoint.getTime());
|
||||
chart.getXAxis().setMin(minTimepoint.getTime());
|
||||
chart.getXAxis().setMax(maxTimepoint.getTime());
|
||||
|
||||
drawChartData();
|
||||
chart.hideLoading();
|
||||
}
|
||||
});
|
||||
asyncActionsExecutor.execute(getCompetitorsRaceDataAction);
|
||||
drawChartData();
|
||||
hideLoading();
|
||||
}
|
||||
});
|
||||
asyncActionsExecutor.execute(getCompetitorsRaceDataAction);
|
||||
} else {
|
||||
setWidget(noCompetitorsSelectedLabel);
|
||||
}
|
||||
} else {
|
||||
setWidget(noCompetitorsSelectedLabel);
|
||||
// not visible; don't load data but remember that data needs to be loaded as soon as the chart becomes visible
|
||||
needToLoadWhenMadeVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,10 +593,6 @@ implements CompetitorSelectionChangeListener, RequiresResize {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean needsDataLoading() {
|
||||
return hasVisibleCompetitors() && isVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResize() {
|
||||
if(getChartData() != null) {
|
||||
|
||||
+5
-10
@@ -107,7 +107,7 @@ public abstract class RaceChart extends SimplePanel implements RaceTimesInfoProv
|
||||
}
|
||||
|
||||
protected void hideLoading() {
|
||||
if(timer.getPlayMode() != PlayModes.Live) {
|
||||
if (timer.getPlayMode() != PlayModes.Live) {
|
||||
chart.hideLoading();
|
||||
}
|
||||
isLoading = false;
|
||||
@@ -134,14 +134,9 @@ public abstract class RaceChart extends SimplePanel implements RaceTimesInfoProv
|
||||
}
|
||||
|
||||
protected boolean onClick(ChartClickEvent chartClickEvent) {
|
||||
if(!isLoading && !isZoomed) {
|
||||
// when the user zooms into the chart first a AxisSetExtremesEvent is sent and a ChartClickEvent afterwards
|
||||
// if (ignoreClickOnce) {
|
||||
// ignoreClickOnce = false;
|
||||
// } else {
|
||||
timer.setPlayMode(PlayModes.Replay);
|
||||
timer.setTime(chartClickEvent.getXAxisValueAsLong());
|
||||
// }
|
||||
if (!isLoading && !isZoomed) {
|
||||
timer.setPlayMode(PlayModes.Replay);
|
||||
timer.setTime(chartClickEvent.getXAxisValueAsLong());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -168,7 +163,7 @@ public abstract class RaceChart extends SimplePanel implements RaceTimesInfoProv
|
||||
* visibility state.
|
||||
*/
|
||||
protected void useCheckboxesToShowAndHide(final Chart chart) {
|
||||
chart.setLegend(new Legend().setEnabled(true).setBorderWidth(0).setSymbolPadding(20)); // make room for checkbox
|
||||
chart.setLegend(new Legend().setEnabled(true).setBorderWidth(0).setSymbolPadding(25)); // make room for checkbox
|
||||
chart.setSeriesPlotOptions(new SeriesPlotOptions().setSeriesCheckboxClickEventHandler(new SeriesCheckboxClickEventHandler() {
|
||||
@Override
|
||||
public boolean onClick(SeriesCheckboxClickEvent seriesCheckboxClickEvent) {
|
||||
|
||||
+3
-3
@@ -103,7 +103,7 @@ public class SliderBar extends FocusPanel implements RequiresResize, HasValue<Do
|
||||
*
|
||||
* @return a prototype of this image
|
||||
*/
|
||||
@Source("slider.png")
|
||||
@Source("slider_blue.png")
|
||||
ImageResource slider();
|
||||
|
||||
/**
|
||||
@@ -111,7 +111,7 @@ public class SliderBar extends FocusPanel implements RequiresResize, HasValue<Do
|
||||
*
|
||||
* @return a prototype of this image
|
||||
*/
|
||||
@Source("slider.png")
|
||||
@Source("slider_blue.png")
|
||||
ImageResource sliderDisabled();
|
||||
|
||||
/**
|
||||
@@ -119,7 +119,7 @@ public class SliderBar extends FocusPanel implements RequiresResize, HasValue<Do
|
||||
*
|
||||
* @return a prototype of this image
|
||||
*/
|
||||
@Source("slider.png")
|
||||
@Source("slider_blue.png")
|
||||
ImageResource sliderSliding();
|
||||
|
||||
@NotStrict
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 596 B |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 422 B |
+11
-10
@@ -15,6 +15,7 @@ import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
@@ -43,16 +44,16 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
|
||||
final ArrayList<Leaderboard> leaderboards = new ArrayList<>();
|
||||
|
||||
Leaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
|
||||
leaderboards.add(leaderboard);
|
||||
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
|
||||
leaderboards.add(leaderboard);
|
||||
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[2], new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
|
||||
leaderboards.add(leaderboard);
|
||||
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[3], new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
|
||||
leaderboards.add(leaderboard);
|
||||
|
||||
final LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl(groupName, groupDescription, leaderboards);
|
||||
@@ -80,10 +81,10 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
|
||||
final ArrayList<Leaderboard> leaderboards = new ArrayList<>();
|
||||
|
||||
Leaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[0], new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
|
||||
leaderboards.add(leaderboard);
|
||||
leaderboard = new FlexibleLeaderboardImpl(leaderboardNames[1], new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
|
||||
leaderboards.add(leaderboard);
|
||||
|
||||
final LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl(groupName, groupDescription, leaderboards);
|
||||
@@ -93,11 +94,11 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
|
||||
|
||||
final Leaderboard[] ungroupedLeaderboards = {
|
||||
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[0], new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces)),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter()),
|
||||
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[1], new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces)),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter()),
|
||||
new FlexibleLeaderboardImpl(ungroupedLeaderboardNames[2], new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces)) };
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter()) };
|
||||
mongoObjectFactory.storeLeaderboard(ungroupedLeaderboards[0]);
|
||||
mongoObjectFactory.storeLeaderboard(ungroupedLeaderboards[1]);
|
||||
mongoObjectFactory.storeLeaderboard(ungroupedLeaderboards[2]);
|
||||
@@ -133,7 +134,7 @@ public class TestStoringAndRetrievingLeaderboardGroups extends AbstractMongoDBTe
|
||||
final String groupDescription = "A leaderboard group";
|
||||
final ArrayList<Leaderboard> leaderboards = new ArrayList<>();
|
||||
|
||||
final FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(), new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
|
||||
final FlexibleLeaderboard leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(), new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
|
||||
final Fleet fleet = leaderboard.getFleet(null);
|
||||
final RaceColumn race = leaderboard.addRaceColumn(columnName, false, fleet);
|
||||
leaderboards.add(leaderboard);
|
||||
|
||||
+6
-5
@@ -22,6 +22,7 @@ import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl;
|
||||
@@ -35,7 +36,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
|
||||
final String leaderboardName = "TestLeaderboard";
|
||||
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
|
||||
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
|
||||
new MongoObjectFactoryImpl(db).storeLeaderboard(leaderboard);
|
||||
Leaderboard loadedLeaderboard = new DomainObjectFactoryImpl(db).loadLeaderboard(leaderboardName);
|
||||
assertEquals(leaderboardName, loadedLeaderboard.getName());
|
||||
@@ -50,7 +51,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
|
||||
final int carriedPointsForWolfgangHunger = 3;
|
||||
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
|
||||
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
|
||||
Competitor competitor = createCompetitor();
|
||||
TrackedRace raceWithOneCompetitor = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
|
||||
leaderboard.addRace(raceWithOneCompetitor, raceColumnName, /* medalRace */ false, leaderboard.getFleet(null));
|
||||
@@ -75,7 +76,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
|
||||
final int correctedPoints = 2;
|
||||
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
|
||||
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
|
||||
Competitor competitor = createCompetitor();
|
||||
TrackedRace raceWithOneCompetitor1 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
|
||||
TrackedRace raceWithOneCompetitor2 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 2, /* started */ true);
|
||||
@@ -101,7 +102,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
|
||||
final MaxPointsReason maxPointsReason = MaxPointsReason.DNF;
|
||||
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
|
||||
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
|
||||
Competitor competitor = createCompetitor();
|
||||
TrackedRace raceWithOneCompetitor1 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
|
||||
TrackedRace raceWithOneCompetitor2 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 2, /* started */ true);
|
||||
@@ -128,7 +129,7 @@ public class TestStoringAndRetrievingLeaderboards extends AbstractMongoDBTest {
|
||||
final MaxPointsReason maxPointsReason = MaxPointsReason.DNF;
|
||||
final int[] discardIndexResultsStartingWithHowManyRaces = new int[] { 5, 8 };
|
||||
FlexibleLeaderboardImpl leaderboard = new FlexibleLeaderboardImpl(leaderboardName, new ScoreCorrectionImpl(),
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces));
|
||||
new ResultDiscardingRuleImpl(discardIndexResultsStartingWithHowManyRaces), new LowerScoreIsBetter());
|
||||
Competitor competitor = createCompetitor();
|
||||
TrackedRace raceWithOneCompetitor1 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 1, /* started */ true);
|
||||
TrackedRace raceWithOneCompetitor2 = new MockedTrackedRaceWithFixedRank(competitor, /* rank */ 2, /* started */ true);
|
||||
|
||||
@@ -24,5 +24,5 @@
|
||||
<booleanAttribute key="tracing" value="false"/>
|
||||
<booleanAttribute key="useCustomFeatures" value="false"/>
|
||||
<booleanAttribute key="useDefaultConfigArea" value="false"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.tractrac.clientmodule@default:default,com.tractrac.resultapi@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
<stringAttribute key="workspace_bundles" value="com.google.gwt.osgi@default:default,com.googlecode.java-diff-utils@default:default,com.mongodb.driver@default:default,com.sap.sailing.declination@default:default,com.sap.sailing.domain.common@default:default,com.sap.sailing.domain.persistence@default:default,com.sap.sailing.domain.swisstimingadapter.persistence@default:default,com.sap.sailing.domain.swisstimingadapter@default:default,com.sap.sailing.domain.tractracadapter.persistence@default:default,com.sap.sailing.domain.tractracadapter@default:default,com.sap.sailing.domain@default:default,com.sap.sailing.expeditionconnector@default:default,com.sap.sailing.geocoding@default:default,com.sap.sailing.gwt.ui@default:default,com.sap.sailing.mongodb@default:default,com.sap.sailing.operationaltransformation@default:default,com.sap.sailing.server.replication@default:default,com.sap.sailing.server@default:default,com.sap.sailing.udpconnector@default:default,com.sap.sailing.www.events@default:default,com.sap.sailing.www@default:default,com.sap.sailing.xcelsiusadapter@default:default,com.tractrac.clientmodule@default:default,org.json.simple@default:default,org.moxieapps.gwt.highcharts@default:default"/>
|
||||
</launchConfiguration>
|
||||
@@ -31,4 +31,22 @@
|
||||
<servlet-name>ExpeditionThroughHttpPostServlet</servlet-name>
|
||||
<url-pattern>/expedition</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>ListLeaderboards</servlet-name>
|
||||
<servlet-class>com.sap.sailing.server.impl.ListLeaderboards</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ListLeaderboards</servlet-name>
|
||||
<url-pattern>/listleaderboards</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>LeaderboardJsonExport</servlet-name>
|
||||
<servlet-class>com.sap.sailing.server.impl.LeaderboardJsonExport</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>LeaderboardJsonExport</servlet-name>
|
||||
<url-pattern>/leaderboard</url-pattern>
|
||||
</servlet-mapping>
|
||||
</web-app>
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package com.sap.sailing.server.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.server.Servlet;
|
||||
|
||||
public class LeaderboardJsonExport extends Servlet {
|
||||
private static final long serialVersionUID = -2460691283231361152L;
|
||||
private static final String PARAM_NAME_LEADERBOARDNAME = "leaderboardName";
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
TimePoint timePoint = MillisecondsTimePoint.now();
|
||||
String leaderboardName = req.getParameter(PARAM_NAME_LEADERBOARDNAME);
|
||||
if (leaderboardName == null) {
|
||||
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Need to specify a leaderboard name using the "+
|
||||
PARAM_NAME_LEADERBOARDNAME+" parameter");
|
||||
} else {
|
||||
Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
|
||||
if (leaderboard == null) {
|
||||
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Leaderboard "+leaderboardName+" not found");
|
||||
} else {
|
||||
try {
|
||||
List<Competitor> competitorsFromBestToWorstAccordingToTotalRank = leaderboard
|
||||
.getCompetitorsFromBestToWorst(timePoint);
|
||||
Map<RaceColumn, List<Competitor>> rankedCompetitorsPerColumn = new HashMap<RaceColumn, List<Competitor>>();
|
||||
JSONObject jsonLeaderboard = new JSONObject();
|
||||
jsonLeaderboard.put("name", leaderboard.getName());
|
||||
JSONArray jsonColumnNames = new JSONArray();
|
||||
jsonLeaderboard.put("columnNames", jsonColumnNames);
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
jsonColumnNames.add(raceColumn.getName());
|
||||
}
|
||||
JSONArray jsonCompetitorEntries = new JSONArray();
|
||||
jsonLeaderboard.put("competitors", jsonCompetitorEntries);
|
||||
for (Competitor competitor : competitorsFromBestToWorstAccordingToTotalRank) {
|
||||
JSONObject jsonCompetitor = new JSONObject();
|
||||
jsonCompetitor.put("name", competitor.getName());
|
||||
final String displayName = leaderboard.getDisplayName(competitor);
|
||||
jsonCompetitor.put("displayName", displayName==null?competitor.getName():displayName);
|
||||
jsonCompetitor.put("id", competitor.getId().toString());
|
||||
jsonCompetitor.put("sailID", competitor.getBoat().getSailID());
|
||||
jsonCompetitor.put("nationality", competitor.getTeam().getNationality()
|
||||
.getThreeLetterIOCAcronym());
|
||||
jsonCompetitor.put("rank",
|
||||
competitorsFromBestToWorstAccordingToTotalRank.indexOf(competitor) + 1);
|
||||
jsonCompetitor.put("totalPoints", leaderboard.getTotalPoints(competitor, timePoint));
|
||||
jsonCompetitorEntries.add(jsonCompetitor);
|
||||
JSONObject jsonRaceColumns = new JSONObject();
|
||||
jsonCompetitor.put("raceScores", jsonRaceColumns);
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
List<Competitor> rankedCompetitorsForColumn = rankedCompetitorsPerColumn.get(raceColumn);
|
||||
if (rankedCompetitorsForColumn == null) {
|
||||
rankedCompetitorsForColumn = leaderboard.getCompetitorsFromBestToWorst(raceColumn, timePoint);
|
||||
rankedCompetitorsPerColumn.put(raceColumn, rankedCompetitorsForColumn);
|
||||
}
|
||||
JSONObject jsonEntry = new JSONObject();
|
||||
jsonRaceColumns.put(raceColumn.getName(), jsonEntry);
|
||||
final Fleet fleetOfCompetitor = raceColumn.getFleetOfCompetitor(competitor);
|
||||
jsonEntry.put("fleet", fleetOfCompetitor==null?"":fleetOfCompetitor.getName());
|
||||
jsonEntry.put("netPoints", leaderboard.getNetPoints(competitor, raceColumn, timePoint));
|
||||
jsonEntry.put("totalPoints", leaderboard.getTotalPoints(competitor, raceColumn, timePoint));
|
||||
jsonEntry.put("maxPointsReason", leaderboard.getMaxPointsReason(competitor, raceColumn, timePoint));
|
||||
jsonEntry.put("rank", rankedCompetitorsForColumn.indexOf(competitor)+1);
|
||||
jsonEntry.put("isDiscarded", leaderboard.isDiscarded(competitor, raceColumn, timePoint));
|
||||
}
|
||||
}
|
||||
jsonLeaderboard.writeJSONString(resp.getWriter());
|
||||
} catch (NoWindException e) {
|
||||
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.sap.sailing.server.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.server.Servlet;
|
||||
|
||||
public class ListLeaderboards extends Servlet {
|
||||
private static final long serialVersionUID = -2193421590275280102L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
JSONArray jsonLeaderboards = new JSONArray();
|
||||
Map<String, Leaderboard> leaderboards = getService().getLeaderboards();
|
||||
for (String leaderboardName : leaderboards.keySet()) {
|
||||
jsonLeaderboards.add(leaderboardName);
|
||||
}
|
||||
jsonLeaderboards.writeJSONString(resp.getWriter());
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -51,6 +51,7 @@ import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.LowerScoreIsBetter;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.persistence.DomainObjectFactory;
|
||||
@@ -207,7 +208,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen
|
||||
@Override
|
||||
public Leaderboard addFlexibleLeaderboard(String name, int[] discardThresholds) {
|
||||
Leaderboard result = new FlexibleLeaderboardImpl(name, new ScoreCorrectionImpl(), new ResultDiscardingRuleImpl(
|
||||
discardThresholds));
|
||||
discardThresholds), new LowerScoreIsBetter());
|
||||
synchronized (leaderboardsByName) {
|
||||
if (leaderboardsByName.containsKey(name)) {
|
||||
throw new IllegalArgumentException("Leaderboard with name "+name+" already exists");
|
||||
|
||||
+13
-12
@@ -1495,7 +1495,6 @@ public abstract class BaseChart<T> extends Widget {
|
||||
|
||||
// Once we're rendered, we're maintaining the point state in the DOM, so we can dump our internal list to save memory
|
||||
series.clearInternalPointsList();
|
||||
nativeAdjustCheckboxPosition(get(series.getId()));
|
||||
}
|
||||
|
||||
return returnThis();
|
||||
@@ -1818,6 +1817,7 @@ public abstract class BaseChart<T> extends Widget {
|
||||
public T redraw() {
|
||||
if (isRendered()) {
|
||||
nativeRedraw(chart);
|
||||
nativeAdjustCheckboxPosition(chart);
|
||||
}
|
||||
return returnThis();
|
||||
}
|
||||
@@ -1969,7 +1969,6 @@ public abstract class BaseChart<T> extends Widget {
|
||||
for (Series series : seriesList) {
|
||||
series.clearInternalPointsList();
|
||||
series.setRendered(true);
|
||||
nativeAdjustCheckboxPosition(get(series.getId()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2489,20 +2488,22 @@ public abstract class BaseChart<T> extends Widget {
|
||||
|
||||
/**
|
||||
* Fixing a bug currently in the base Highcharts implementation regarding the placement of the checkbox in the legend.
|
||||
* Requires the symbol padding (see {@link Legend#setSymbolPadding(Number)}) to be set to <code>20</code>. Invoked
|
||||
* whenever a series is added / displayed in a rendered chart.<p>
|
||||
* Requires the symbol padding (see {@link Legend#setSymbolPadding(Number)}) to be set to <code>25</code>. Invoked
|
||||
* whenever the chart is rendered.<p>
|
||||
*
|
||||
* The implementation moves the legend item text 15px to the left, using the space made by setting the symbol
|
||||
* padding to 20px; the checkbox is moved 18px to the left with the top margin set to 0px.
|
||||
* The implementation moves the checkbox between the legend symbol and the legend item, using the space made by setting the symbol
|
||||
* padding to 25px.
|
||||
*/
|
||||
private static native JavaScriptObject nativeAdjustCheckboxPosition(JavaScriptObject series) /*-{
|
||||
if (series.legendItem && series.checkbox) {
|
||||
series.legendItem.translate(-15, 0);
|
||||
series.checkbox.style.marginLeft = '-18px'
|
||||
series.checkbox.style.marginTop = '0px'
|
||||
private static native JavaScriptObject nativeAdjustCheckboxPosition(JavaScriptObject chart) /*-{
|
||||
var series = chart.series;
|
||||
for(var i= 0; i<series.length; i++) {
|
||||
if(series[i].legendItem && series[i].checkbox) {
|
||||
series[i].checkbox.style.marginLeft = - series[i].legendItemWidth + 20 + "px";
|
||||
series[i].checkbox.style.marginTop = '0px';
|
||||
}
|
||||
}
|
||||
}-*/;
|
||||
|
||||
|
||||
private static native void nativeRedraw(JavaScriptObject chart) /*-{
|
||||
chart.redraw();
|
||||
}-*/;
|
||||
|
||||
Reference in new issue
Block a user