mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-25 05:23:51 +00:00
Merge remote-tracking branch 'origin/master' into ttcm_with_metadata
This commit is contained in:
commit
05b81d7646
243 files changed
+11151
-3214
No files matched your search
Binary file not shown.
@@ -0,0 +1,11 @@
|
||||
Exporting swisstiming 'Store and forward' messages
|
||||
------------------------------------------------------
|
||||
|
||||
27012: local MongoDB "winddb" instance
|
||||
|
||||
/opt/mongodb/bin/mongoexport --port 27017 -d winddb -c SWISSTIMING_CONFIGURATIONS > /tmp/swisstiming_configurations.json
|
||||
/opt/mongodb/bin/mongoexport --port 27017 -d winddb -c LAST_MESSAGE_COUNT > /tmp/swisstiming_last_message_count.json
|
||||
/opt/mongodb/bin/mongoexport --port 27017 -d winddb -c RACES_MASTERDATA > /tmp/swisstiming_races_masterdata.json
|
||||
/opt/mongodb/bin/mongoexport --port 27017 -d winddb -c RACES_MESSAGES > /tmp/swisstiming_races_massages.json
|
||||
/opt/mongodb/bin/mongoexport --port 27017 -d winddb -c COMMAND_MESSAGES > /tmp/swisstiming_command_messages.json
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -2,4 +2,5 @@
|
||||
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.4.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.4.0/distro-source/core/src/gwt-module.dtd">
|
||||
<module>
|
||||
<source path='common'/>
|
||||
<source path='common/impl'/>
|
||||
</module>
|
||||
@@ -24,6 +24,8 @@ public enum DetailType implements Serializable {
|
||||
TACK(0, ASCENDING), JIBE(0, ASCENDING), PENALTY_CIRCLE(0, ASCENDING), MARK_PASSING(0, ASCENDING), CURRENT_LEG(0, ASCENDING),
|
||||
DISPLAY_LEGS(0, NONE), TIME_TRAVELED(0, ASCENDING),
|
||||
TOTAL_TIME_SAILED_DOWNWIND_IN_SECONDS(1, ASCENDING),
|
||||
TOTAL_TIME_SAILED_UPWIND_IN_SECONDS(1, ASCENDING),
|
||||
TOTAL_TIME_SAILED_REACHING_IN_SECONDS(1, ASCENDING),
|
||||
MAXIMUM_SPEED_OVER_GROUND_IN_KNOTS(1, DESCENDING),
|
||||
TOTAL_TIME_SAILED_IN_SECONDS(1, ASCENDING), RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING);
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.sap.sailing.domain.base.impl;
|
||||
package com.sap.sailing.domain.common.impl;
|
||||
|
||||
import com.sap.sailing.domain.common.AbstractDistance;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
+3
-2
@@ -39,8 +39,9 @@ public interface MongoObjectFactory {
|
||||
void renameLeaderboard(String oldName, String newName);
|
||||
|
||||
/**
|
||||
* Stores the group, if it doesn't exist or updates it.<br />
|
||||
* Leaderboards in the group, which aren't stored in the database, will be stored.
|
||||
* Stores the group, if it doesn't exist or updates it. Leaderboards in the group, which aren't stored in the
|
||||
* database, will be stored. If the leaderboard group has an {@link LeaderboardGroup#getOverallLeaderboard() overall
|
||||
* leaderboard}, it will be stored / updated as well.
|
||||
*/
|
||||
void storeLeaderboardGroup(LeaderboardGroup leaderboardGroup);
|
||||
|
||||
|
||||
+8
@@ -198,6 +198,14 @@ public class DelayedLeaderboardCorrectionsImpl implements DelayedLeaderboardCorr
|
||||
public void raceColumnRemovedFromContainer(RaceColumn raceColumn) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceColumnMoved(RaceColumn raceColumn, int newIndex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void factorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransient() {
|
||||
return false;
|
||||
|
||||
+18
-1
@@ -220,6 +220,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
DelayedLeaderboardCorrections loadedLeaderboardCorrections = new DelayedLeaderboardCorrectionsImpl(result);
|
||||
loadLeaderboardCorrections(dbLeaderboard, loadedLeaderboardCorrections, scoreCorrection);
|
||||
loadSuppressedCompetitors(dbLeaderboard, loadedLeaderboardCorrections);
|
||||
loadColumnFactors(dbLeaderboard, result);
|
||||
// add the leaderboard to the registry
|
||||
if (leaderboardRegistry != null) {
|
||||
leaderboardRegistry.addLeaderboard(result);
|
||||
@@ -230,6 +231,17 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void loadColumnFactors(DBObject dbLeaderboard, Leaderboard result) {
|
||||
DBObject dbColumnFactors = (DBObject) dbLeaderboard.get(FieldNames.LEADERBOARD_COLUMN_FACTORS.name());
|
||||
if (dbColumnFactors != null) {
|
||||
for (String encodedRaceColumnName : dbColumnFactors.keySet()) {
|
||||
double factor = ((Number) dbColumnFactors.get(encodedRaceColumnName)).doubleValue();
|
||||
String raceColumnName = MongoUtils.unescapeDollarAndDot(encodedRaceColumnName);
|
||||
result.getRaceColumnByName(raceColumnName).setFactor(factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadSuppressedCompetitors(DBObject dbLeaderboard,
|
||||
DelayedLeaderboardCorrections loadedLeaderboardCorrections) {
|
||||
BasicDBList dbSuppressedCompetitorNames = (BasicDBList) dbLeaderboard.get(FieldNames.LEADERBOARD_SUPPRESSED_COMPETITORS.name());
|
||||
@@ -432,6 +444,11 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
DBCollection leaderboardCollection = database.getCollection(CollectionNames.LEADERBOARDS.name());
|
||||
String name = (String) o.get(FieldNames.LEADERBOARD_GROUP_NAME.name());
|
||||
String description = (String) o.get(FieldNames.LEADERBOARD_GROUP_DESCRIPTION.name());
|
||||
boolean displayGroupsInReverseOrder = false; // default value
|
||||
Object displayGroupsInReverseOrderObj = o.get(FieldNames.LEADERBOARD_GROUP_DISPLAY_IN_REVERSE_ORDER.name());
|
||||
if(displayGroupsInReverseOrderObj != null) {
|
||||
displayGroupsInReverseOrder = (Boolean) displayGroupsInReverseOrderObj;
|
||||
}
|
||||
ArrayList<Leaderboard> leaderboards = new ArrayList<Leaderboard>();
|
||||
BasicDBList dbLeaderboardIds = (BasicDBList) o.get(FieldNames.LEADERBOARD_GROUP_LEADERBOARDS.name());
|
||||
for (Object object : dbLeaderboardIds) {
|
||||
@@ -443,7 +460,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
}
|
||||
}
|
||||
logger.info("loaded leaderboard group "+name);
|
||||
LeaderboardGroupImpl result = new LeaderboardGroupImpl(name, description, leaderboards);
|
||||
LeaderboardGroupImpl result = new LeaderboardGroupImpl(name, description, displayGroupsInReverseOrder, leaderboards);
|
||||
Object overallLeaderboardIdOrName = o.get(FieldNames.LEADERBOARD_GROUP_OVERALL_LEADERBOARD.name());
|
||||
if (overallLeaderboardIdOrName != null) {
|
||||
final DBObject dbOverallLeaderboard;
|
||||
|
||||
+2
-1
@@ -47,10 +47,11 @@ public enum FieldNames {
|
||||
LEADERBOARD_NAME, LEADERBOARD_SUPPRESSED_COMPETITORS, LEADERBOARD_COLUMNS, LEADERBOARD_COLUMN_NAME, LEADERBOARD_COMPETITOR_DISPLAY_NAMES,
|
||||
LEADERBOARD_IS_MEDAL_RACE_COLUMN, LEADERBOARD_CARRIED_POINTS, LEADERBOARD_SCORE_CORRECTIONS, LEADERBOARD_DISCARDING_THRESHOLDS,
|
||||
LEADERBOARD_SCORE_CORRECTION_MAX_POINTS_REASON, LEADERBOARD_CORRECTED_SCORE, LEADERBOARD_SCORE_CORRECTION_TIMESTAMP,
|
||||
LEADERBOARD_SCORE_CORRECTION_COMMENT,
|
||||
LEADERBOARD_SCORE_CORRECTION_COMMENT, LEADERBOARD_COLUMN_FACTORS,
|
||||
|
||||
// leaderboard group
|
||||
LEADERBOARD_GROUP_NAME, LEADERBOARD_GROUP_DESCRIPTION, LEADERBOARD_GROUP_LEADERBOARDS, LEADERBOARD_GROUP_OVERALL_LEADERBOARD,
|
||||
LEADERBOARD_GROUP_DISPLAY_IN_REVERSE_ORDER,
|
||||
|
||||
// race ID to regatta name
|
||||
RACE_ID_AS_STRING;
|
||||
|
||||
+15
@@ -152,10 +152,22 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
// at least store the scoring scheme
|
||||
dbLeaderboard.put(FieldNames.SCORING_SCHEME_TYPE.name(), leaderboard.getScoringScheme().getType().name());
|
||||
}
|
||||
storeColumnFactors(leaderboard, dbLeaderboard);
|
||||
storeLeaderboardCorrectionsAndDiscards(leaderboard, dbLeaderboard);
|
||||
leaderboardCollection.update(query, dbLeaderboard, /* upsrt */ true, /* multi */ false);
|
||||
}
|
||||
|
||||
private void storeColumnFactors(Leaderboard leaderboard, BasicDBObject dbLeaderboard) {
|
||||
DBObject raceColumnFactors = new BasicDBObject();
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
Double explicitFactor = raceColumn.getExplicitFactor();
|
||||
if (explicitFactor != null) {
|
||||
raceColumnFactors.put(MongoUtils.escapeDollarAndDot(raceColumn.getName()), explicitFactor);
|
||||
}
|
||||
}
|
||||
dbLeaderboard.put(FieldNames.LEADERBOARD_COLUMN_FACTORS.name(), raceColumnFactors);
|
||||
}
|
||||
|
||||
private void storeRegattaLeaderboard(RegattaLeaderboard leaderboard, DBObject dbLeaderboard) {
|
||||
dbLeaderboard.put(FieldNames.REGATTA_NAME.name(), leaderboard.getRegatta().getName());
|
||||
}
|
||||
@@ -234,6 +246,8 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
}
|
||||
}
|
||||
if (!dbCorrectionForRace.isEmpty()) {
|
||||
// using the column name as the key for the score corrections requires re-writing the score corrections
|
||||
// of a meta-leaderboard if the name of one of its leaderboards changes
|
||||
dbScoreCorrections.put(raceColumn.getName(), dbCorrectionForRace);
|
||||
}
|
||||
}
|
||||
@@ -276,6 +290,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
BasicDBObject dbLeaderboardGroup = new BasicDBObject();
|
||||
dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_NAME.name(), leaderboardGroup.getName());
|
||||
dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DESCRIPTION.name(), leaderboardGroup.getDescription());
|
||||
dbLeaderboardGroup.put(FieldNames.LEADERBOARD_GROUP_DISPLAY_IN_REVERSE_ORDER.name(), leaderboardGroup.isDisplayGroupsInReverseOrder());
|
||||
final Leaderboard overallLeaderboard = leaderboardGroup.getOverallLeaderboard();
|
||||
if (overallLeaderboard != null) {
|
||||
BasicDBObject overallLeaderboardQuery = new BasicDBObject(FieldNames.LEADERBOARD_NAME.name(), overallLeaderboard.getName());
|
||||
|
||||
+14
-4
@@ -157,7 +157,7 @@ public class StoreAndForward implements Runnable {
|
||||
if (lastMessageCountRecord == null) {
|
||||
lastMessageCountCollection.insert(new BasicDBObject().append(FieldNames.LAST_MESSAGE_COUNT.name(), 0l));
|
||||
}
|
||||
return lastMessageCountRecord == null ? 0 : (Long) lastMessageCountRecord.get(FieldNames.LAST_MESSAGE_COUNT.name());
|
||||
return lastMessageCountRecord == null ? 0 : ((Number) lastMessageCountRecord.get(FieldNames.LAST_MESSAGE_COUNT.name())).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,13 +241,23 @@ public class StoreAndForward implements Runnable {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws InterruptedException, IOException {
|
||||
int listenPort = Integer.valueOf(args[0]);
|
||||
int clientPort = Integer.valueOf(args[1]);
|
||||
String hostname = null;
|
||||
int i=0;
|
||||
if (args[i].equals("-h")) {
|
||||
hostname = args[++i];
|
||||
i++;
|
||||
}
|
||||
int sailMasterPort = Integer.valueOf(args[i++]);
|
||||
int clientPort = Integer.valueOf(args[i++]);
|
||||
|
||||
MongoDBService mongoDBService = MongoDBService.INSTANCE;
|
||||
mongoDBService.setConfiguration(MongoDBConfiguration.getDefaultConfiguration());
|
||||
SwissTimingAdapterPersistence swissTimingAdapterPersistence = SwissTimingAdapterPersistence.INSTANCE;
|
||||
new StoreAndForward(listenPort, clientPort, SwissTimingFactory.INSTANCE, swissTimingAdapterPersistence, mongoDBService);
|
||||
if (hostname == null) {
|
||||
new StoreAndForward(sailMasterPort, clientPort, SwissTimingFactory.INSTANCE, swissTimingAdapterPersistence, mongoDBService);
|
||||
} else {
|
||||
new StoreAndForward(hostname, sailMasterPort, clientPort, SwissTimingFactory.INSTANCE, swissTimingAdapterPersistence, mongoDBService);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ public class SwissTimingAdapterPersistenceImpl implements SwissTimingAdapterPers
|
||||
List<SailMasterMessage> result = new ArrayList<SailMasterMessage>();
|
||||
for (DBObject o : results) {
|
||||
SailMasterMessage msg = swissTimingFactory.createMessage((String) o.get(FieldNames.MESSAGE_CONTENT.name()),
|
||||
(Long) o.get(FieldNames.MESSAGE_SEQUENCE_NUMBER.name()));
|
||||
((Number) o.get(FieldNames.MESSAGE_SEQUENCE_NUMBER.name())).longValue());
|
||||
result.add(msg);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
RAC|1|W4702;Women 470 Race 2STL|W4702|46|ARG 8;ARG;ARG 8|AUS 7;AUS;AUS 7|AUT 431;AUT;AUT 431|BRA 177;BRA;BRA 177|BRA 1187;BRA;BRA 1187|CAN 11;CAN;CAN 11|CAN 610;CAN;CAN 610|CHN 1211;CHN;CHN 1211|CHN 1261;CHN;CHN 1261|CHN 221;CHN;CHN 221|CHN 616;CHN;CHN 616|CRO 111;CRO;CRO 111|DEN 143;DEN;DEN 143|ESP 133;ESP;ESP 133|ESP 696;ESP;ESP 696|EST 20;EST;EST 20|FRA 12;FRA;FRA 12|FRA 4;FRA;FRA 4|FRA 9;FRA;FRA 9|GBR 812;GBR;GBR 812|GBR 831;GBR;GBR 831|GBR 841;GBR;GBR 841|GBR 847;GBR;GBR 847|GBR 850;GBR;GBR 850|GBR 855;GBR;GBR 855|GER 12;GER;GER 12|GER 21;GER;GER 21|GER 61;GER;GER 61|GER 66;GER;GER 66|GER 72;GER;GER 72|ISR 311;ISR;ISR 311|ITA 23;ITA;ITA 23|JPN 4151;JPN;JPN 4151|JPN 4321;JPN;JPN 4321|NED 11;NED;NED 11|NED 24;NED;NED 24|NZL 75;NZL;NZL 75|RUS 12;RUS;RUS 12|RUS 700;RUS;RUS 700|SLO 64;SLO;SLO 64|SUI 14;SUI;SUI 14|SWE 342;SWE;SWE 342|SWE 344;SWE;SWE 344|USA 1712;USA;USA 1712|USA 1736;USA;USA 1736|USA 1757;USA;USA 1757RPD|W4702|0|2011-06-06T17:54:19+02:00|||||61|SB;2;0;50.621933;-2.366140;0.2;;;90;;;;;|MB4;4;0;50.605008;-2.373398;0.2;;;17;;;;;|MB3;4;0;50.607335;-2.388345;0.8;;;69;;;;;|MB2;4;0;50.617526;-2.352416;0.2;;;220;;;;;|MB1;4;0;50.619644;-2.363547;0.4;;;81;;;;;|M7;5;0;50.621848;-2.366225;0.0;;;90;;;;;|M6;5;0;50.607561;-2.387959;0.8;;;108;;;;;|M5;5;0;50.605096;-2.373590;0.4;;;222;;;;;|M4;5;0;50.617094;-2.352122;1.0;;;32;;;;;|M3;5;0;50.620254;-2.366982;1.0;;;167;;;;;|M2;5;0;50.619848;-2.366420;0.6;;;311;;;;;|M1;5;0;50.617360;-2.352805;0.6;;;134;;;;;|FP;4;0;50.617521;-2.352463;0.2;;;180;;;;;|FB;4;0;50.619268;-2.354392;0.6;;;27;;;;;|SP;4;0;50.619847;-2.363828;0.4;;;322;;;;;|ARG 8;1;0;50.621380;-2.365032;0.8;;;225;;;;;|AUS 7;1;0;50.621263;-2.364862;0.8;;;243;;;;;|AUT 431;1;0;50.621965;-2.366063;2.1;;;90;;;;;|BRA 177;1;0;50.622014;-2.366027;0.4;;;180;;;;;|BRA 1187;1;0;50.621852;-2.365759;0.6;;;153;;;;;|CAN 11;1;0;50.621128;-2.364736;0.6;;;180;;;;;|CAN 610;1;0;50.621951;-2.365865;1.6;;;243;;;;;|CHN 1211;1;0;50.621690;-2.365462;0.8;;;225;;;;;|CHN 1261;1;0;50.621501;-2.365166;1.7;;;169;;;;;|CHN 221;1;0;50.620430;-2.363818;0.2;;;225;;;;;|CHN 616;1;0;50.620251;-2.363536;3.3;;;219;;;;;|CRO 111;1;0;50.621173;-2.364813;0.0;;;225;;;;;|DEN 143;1;0;50.620934;-2.364467;0.8;;;243;;;;;|ESP 133;1;0;50.620624;-2.364079;0.6;;;180;;;;;|ESP 696;1;0;50.621312;-2.364947;0.6;;;162;;;;;|EST 20;1;0;50.621785;-2.365646;1.6;;;108;;;;;|FRA 12;1;0;50.621659;-2.365364;1.9;;;180;;;;;|FRA 4;1;0;50.621713;-2.365547;0.8;;;225;;;;;|FRA 9;1;0;50.620723;-2.364178;0.8;;;225;;;;;|GBR 812;1;0;50.621868;-2.365812;0.6;;;132;;;;;|GBR 831;1;;;;;;;;;;;;|GBR 841;1;0;50.620964;-2.364544;1.7;;;174;;;;;|GBR 847;1;0;50.621773;-2.365637;3.5;;;191;;;;;|GBR 850;1;0;50.621475;-2.365135;2.3;;;273;;;;;|GBR 855;1;0;50.619879;-2.363592;1.0;;;296;;;;;|GER 12;1;0;50.621562;-2.365258;0.6;;;179;;;;;|GER 21;1;0;50.620871;-2.364329;1.4;;;193;;;;;|GER 61;1;0;50.620787;-2.364242;1.0;;;183;;;;;|GER 66;1;0;50.620484;-2.363859;1.7;;;200;;;;;|GER 72;1;0;50.621653;-2.365376;1.9;;;174;;;;;|ISR 311;1;0;50.622183;-2.366012;1.4;;;211;;;;;|ITA 23;1;0;50.620513;-2.363913;2.1;;;278;;;;;|JPN 4151;1;0;50.620337;-2.363733;1.9;;;208;;;;;|JPN 4321;1;0;50.621128;-2.364648;1.0;;;157;;;;;|NED 11;1;0;50.620606;-2.364038;0.4;;;272;;;;;|NED 24;1;;;;;;;;;;;;|NZL 75;1;0;50.621411;-2.365085;0.6;;;332;;;;;|RUS 12;1;0;50.622181;-2.366163;1.9;;;161;;;;;|RUS 700;1;0;50.622005;-2.365919;0.8;;;217;;;;;|SLO 64;1;0;50.621017;-2.364512;3.9;;;259;;;;;|SUI 14;1;0;50.621708;-2.365600;0.2;;;270;;;;;|SWE 342;1;0;50.620647;-2.364130;0.6;;;274;;;;;|SWE 344;1;0;50.621326;-2.364849;5.6;;;142;;;;;|USA 1712;1;0;50.621901;-2.365836;0.0;;;155;;;;;|USA 1736;1;0;50.620603;-2.363976;0.6;;;207;;;;;|USA 1757;1;0;50.621044;-2.364583;1.6;;;196;;;;;RPD|W4702|0|2011-06-06T17:54:20+02:00|||||61|SB;2;0;50.621933;-2.366140;0.2;;;90;;;;;|MB4;4;0;50.605010;-2.373399;0.2;;;0;;;;;|MB3;4;0;50.607337;-2.388341;0.8;;;63;;;;;|MB2;4;0;50.617524;-2.352420;0.2;;;225;;;;;|MB1;4;0;50.619644;-2.363544;0.4;;;90;;;;;|M7;5;0;50.621848;-2.366225;0.0;;;90;;;;;|M6;5;0;50.607561;-2.387960;0.8;;;90;;;;;|M5;5;0;50.605096;-2.373589;0.4;;;90;;;;;|M4;5;0;50.617096;-2.352124;1.0;;;0;;;;;|M3;5;0;50.620253;-2.366984;1.0;;;180;;;;;|M2;5;0;50.619848;-2.366419;0.6;;;90;;;;;|M1;5;0;50.617358;-2.352802;0.6;;;135;;;;;|FP;4;0;50.617519;-2.352463;0.2;;;180;;;;;|FB;4;0;50.619273;-2.354388;0.6;;;27;;;;;|SP;4;0;50.619846;-2.363826;0.4;;;90;;;;;|ARG 8;1;0;50.621375;-2.365036;0.8;;;213;;;;;|AUS 7;1;0;50.621261;-2.364871;0.6;;;250;;;;;|AUT 431;1;0;50.621959;-2.366061;1.0;;;170;;;;;|BRA 177;1;0;50.622012;-2.366027;0.6;;;181;;;;;|BRA 1187;1;0;50.621850;-2.365762;1.0;;;220;;;;;|CAN 11;1;0;50.621125;-2.364739;0.8;;;219;;;;;|CAN 610;1;0;50.621948;-2.365866;1.4;;;194;;;;;|CHN 1211;1;0;50.621688;-2.365462;0.6;;;175;;;;;|CHN 1261;1;0;50.621496;-2.365174;1.7;;;228;;;;;|CHN 221;1;0;50.620427;-2.363819;0.4;;;191;;;;;|CHN 616;1;0;50.620246;-2.363549;2.1;;;239;;;;;|CRO 111;1;0;50.621171;-2.364817;0.0;;;225;;;;;|DEN 143;1;0;50.620934;-2.364478;0.8;;;268;;;;;|ESP 133;1;0;50.62062Line truncated
|
||||
+4650
File diff suppressed because it is too large.
Load diff
+3
@@ -0,0 +1,3 @@
|
||||
RAC|1|W4702;Women 470 Race 2
|
||||
STL|W4702|46|ARG 8;ARG;ARG 8|AUS 7;AUS;AUS 7|AUT 431;AUT;AUT 431|BRA 177;BRA;BRA 177|BRA 1187;BRA;BRA 1187|CAN 11;CAN;CAN 11|CAN 610;CAN;CAN 610|CHN 1211;CHN;CHN 1211|CHN 1261;CHN;CHN 1261|CHN 221;CHN;CHN 221|CHN 616;CHN;CHN 616|CRO 111;CRO;CRO 111|DEN 143;DEN;DEN 143|ESP 133;ESP;ESP 133|ESP 696;ESP;ESP 696|EST 20;EST;EST 20|FRA 12;FRA;FRA 12|FRA 4;FRA;FRA 4|FRA 9;FRA;FRA 9|GBR 812;GBR;GBR 812|GBR 831;GBR;GBR 831|GBR 841;GBR;GBR 841|GBR 847;GBR;GBR 847|GBR 850;GBR;GBR 850|GBR 855;GBR;GBR 855|GER 12;GER;GER 12|GER 21;GER;GER 21|GER 61;GER;GER 61|GER 66;GER;GER 66|GER 72;GER;GER 72|ISR 311;ISR;ISR 311|ITA 23;ITA;ITA 23|JPN 4151;JPN;JPN 4151|JPN 4321;JPN;JPN 4321|NED 11;NED;NED 11|NED 24;NED;NED 24|NZL 75;NZL;NZL 75|RUS 12;RUS;RUS 12|RUS 700;RUS;RUS 700|SLO 64;SLO;SLO 64|SUI 14;SUI;SUI 14|SWE 342;SWE;SWE 342|SWE 344;SWE;SWE 344|USA 1712;USA;USA 1712|USA 1736;USA;USA 1736|USA 1757;USA;USA 1757
|
||||
CCG|W4702|7|0;StartGate;M1;M7|1;Buoy6;M6|2;Buoy5;M5|3;LeeGate;M2;M3|4;Buoy6;M6|5;Buoy5;M5|6;FinishGate;M1;M4
|
||||
+16
-3
@@ -17,14 +17,15 @@ import java.util.List;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.base.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Competitor;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Mark;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Race;
|
||||
import com.sap.sailing.domain.swisstimingadapter.SailMasterMessage;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Mark.MarkType;
|
||||
import com.sap.sailing.domain.swisstimingadapter.classes.messages.CAMMessage;
|
||||
import com.sap.sailing.domain.swisstimingadapter.classes.messages.CCGMessage;
|
||||
import com.sap.sailing.domain.swisstimingadapter.classes.messages.ClockAtMarkElement;
|
||||
@@ -193,8 +194,20 @@ public class MessageFileServiceImpl implements MessageFileService {
|
||||
List<Mark> marks = new ArrayList<Mark>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
String[] markDetails = message.getSections()[3 + i].split(";");
|
||||
marks.add(new MarkImpl(markDetails[1], Integer.valueOf(markDetails[0]), Arrays.asList(markDetails).subList(
|
||||
2, markDetails.length)));
|
||||
MarkType markType = null;
|
||||
final int devicesNamesStartIndex;
|
||||
if (message.getSections()[3+i].split(";", -1).length == 5) {
|
||||
// this is the SailMaster protocol version 1.0 (May 2012) or later (see bug 1000), containing
|
||||
// a MarkType specification before the two tracker IDs:
|
||||
int markTypeIndex = Integer.valueOf(markDetails[2]);
|
||||
markType = MarkType.values()[markTypeIndex];
|
||||
devicesNamesStartIndex = 3;
|
||||
} else {
|
||||
devicesNamesStartIndex = 2;
|
||||
}
|
||||
marks.add(new MarkImpl(markDetails[1], Integer.valueOf(markDetails[0]),
|
||||
Arrays.asList(markDetails).subList(devicesNamesStartIndex, markDetails.length),
|
||||
markType));
|
||||
}
|
||||
return new CCGMessage(raceId, marks);
|
||||
}
|
||||
|
||||
+18
-4
@@ -89,9 +89,10 @@ public class EndToEndListeningStoreAndFowardTest {
|
||||
new BasicDBObject().append(FieldNames.LAST_MESSAGE_COUNT.name(), 0l),
|
||||
/* upsert */true, /* multi */false);
|
||||
// important: construct a new domain factory each time to make sure the competitor cache starts out empty
|
||||
final com.sap.sailing.domain.base.impl.DomainFactoryImpl baseDomainFactory = new com.sap.sailing.domain.base.impl.DomainFactoryImpl();
|
||||
racingEventService = new RacingEventServiceImpl(mongoDBService, SwissTimingFactory.INSTANCE,
|
||||
new DomainFactoryImpl(new com.sap.sailing.domain.base.impl.DomainFactoryImpl()),
|
||||
com.sap.sailing.domain.tractracadapter.DomainFactory.INSTANCE);
|
||||
new DomainFactoryImpl(baseDomainFactory),
|
||||
new com.sap.sailing.domain.tractracadapter.impl.DomainFactoryImpl(baseDomainFactory));
|
||||
raceHandles = new ArrayList<RacesHandle>();
|
||||
}
|
||||
|
||||
@@ -140,7 +141,19 @@ public class EndToEndListeningStoreAndFowardTest {
|
||||
String scriptName1 = "/SailMasterDataInterfaceRACandSTL.txt";
|
||||
String scriptName2 = "/SailMasterDataInterface-ExampleAsText.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName1, scriptName2);
|
||||
coreOfTestLongRaceLog();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongRaceLogNewVersion() throws Exception {
|
||||
String[] racesToTrack = new String[] { "W4702" };
|
||||
String scriptName1 = "/W4702RACandSTLandCCG.txt";
|
||||
String scriptName2 = "/W4702AsText.txt";
|
||||
setUpUsingScript(racesToTrack, scriptName1, scriptName2);
|
||||
coreOfTestLongRaceLog();
|
||||
}
|
||||
|
||||
private void coreOfTestLongRaceLog() {
|
||||
Set<TrackedRace> allTrackedRaces = new HashSet<TrackedRace>();
|
||||
Iterable<Regatta> allRegattas = racingEventService.getAllRegattas();
|
||||
for (Regatta regatta : allRegattas) {
|
||||
@@ -163,7 +176,8 @@ public class EndToEndListeningStoreAndFowardTest {
|
||||
assertEquals(7, Util.size(race.getCourse().getWaypoints()));
|
||||
assertEquals(6, Util.size(race.getCourse().getLegs()));
|
||||
for (Competitor competitor : race.getCompetitors()) {
|
||||
if (!competitor.getName().equals("Competitor 35") && !competitor.getName().equals("Competitor 20")) {
|
||||
if (!competitor.getName().equals("Competitor 35") && !competitor.getName().equals("Competitor 20")
|
||||
&& !competitor.getName().equals("GBR 831") && !competitor.getName().equals("NED 24")) {
|
||||
final GPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
|
||||
track.lockForRead();
|
||||
try {
|
||||
@@ -227,7 +241,7 @@ public class EndToEndListeningStoreAndFowardTest {
|
||||
assertEquals(2, Util.size(race.getCourse().getLegs()));
|
||||
for (Competitor competitor : race.getCompetitors()) {
|
||||
if (!competitor.getName().equals("NED 24") && !competitor.getName().equals("Competitor 35")
|
||||
&& !competitor.getName().equals("Competitor 20")) {
|
||||
&& !competitor.getName().equals("Competitor 20") && !competitor.getName().equals("GBR 831")) {
|
||||
final GPSFixTrack<Competitor, GPSFixMoving> track = trackedRace.getTrack(competitor);
|
||||
track.lockForRead();
|
||||
try {
|
||||
|
||||
+62
-4
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -14,6 +15,7 @@ import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.RegattaImpl;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Competitor;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Course;
|
||||
@@ -30,6 +32,62 @@ import com.sap.sailing.server.impl.RacingEventServiceImpl;
|
||||
import difflib.PatchFailedException;
|
||||
|
||||
public class SimpleDomainFactoryTest {
|
||||
/**
|
||||
* Tests that an unknown boat class encoded in a regular "SA" format race ID is returned as the unknown boat class
|
||||
* instead of null.
|
||||
*/
|
||||
@Test
|
||||
public void testUnknownBoatClassInValidRaceID() {
|
||||
DomainFactory domainFactory = DomainFactory.INSTANCE;
|
||||
final String raceID = "SAX920103";
|
||||
RaceDefinition raceDefinition = domainFactory.createRaceDefinition(domainFactory.getOrCreateRegatta(raceID,
|
||||
new RacingEventServiceImpl()),
|
||||
new Race() {
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRaceID() {
|
||||
return raceID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getStartTime() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStartTime(TimePoint timePoint) {
|
||||
}
|
||||
|
||||
}, new StartList() {
|
||||
@Override
|
||||
public String getRaceID() {
|
||||
return raceID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Competitor> getCompetitors() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}, new Course() {
|
||||
@Override
|
||||
public String getRaceID() {
|
||||
return raceID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Mark> getMarks() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
});
|
||||
assertNotNull(raceDefinition.getBoatClass());
|
||||
assertEquals("Unknown", raceDefinition.getBoatClass().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCourseConfigForBuoy() throws PatchFailedException {
|
||||
DomainFactory domainFactory = DomainFactory.INSTANCE;
|
||||
@@ -38,8 +96,8 @@ public class SimpleDomainFactoryTest {
|
||||
Race race = new RaceImpl("1234", "Race 1234");
|
||||
Iterable<Competitor> competitors = Collections.emptyList();
|
||||
StartList startList = new StartListImpl("1234", competitors);
|
||||
Mark mark1 = new MarkImpl("M1", 0, Arrays.asList("D1", "D2"));
|
||||
Mark mark2 = new MarkImpl("M1", 0, Arrays.asList("D3", "D4"));
|
||||
Mark mark1 = new MarkImpl("M1", 0, Arrays.asList("D1", "D2"), /* markType */ null);
|
||||
Mark mark2 = new MarkImpl("M1", 0, Arrays.asList("D3", "D4"), /* markType */ null);
|
||||
List<Mark> marks = Arrays.asList(mark1, mark2);
|
||||
Course course = new CourseImpl("1234", marks);
|
||||
RaceDefinition raceDefinition = domainFactory.createRaceDefinition(regatta, race, startList, course);
|
||||
@@ -63,8 +121,8 @@ public class SimpleDomainFactoryTest {
|
||||
Race race = new RaceImpl("1234", "Race 1234");
|
||||
Iterable<Competitor> competitors = Collections.emptyList();
|
||||
StartList startList = new StartListImpl("1234", competitors);
|
||||
Mark mark1 = new MarkImpl("M1", 0, Arrays.asList("D1", "D2"));
|
||||
Mark mark2 = new MarkImpl("M1", 0, Arrays.asList("D3", "D4"));
|
||||
Mark mark1 = new MarkImpl("M1", 0, Arrays.asList("D1", "D2"), /* markType */ null);
|
||||
Mark mark2 = new MarkImpl("M1", 0, Arrays.asList("D3", "D4"), /* markType */ null);
|
||||
List<Mark> marks = Arrays.asList(mark1, mark2);
|
||||
Course course = new CourseImpl("1234", marks);
|
||||
RaceDefinition raceDefinition = domainFactory.createRaceDefinition(regatta, race, startList, course);
|
||||
|
||||
+1
-1
@@ -270,7 +270,7 @@ public class EditCCG extends javax.swing.JDialog {
|
||||
private class MarkWithDesc extends MarkImpl {
|
||||
|
||||
public MarkWithDesc(String description, int index, Iterable<String> devices) {
|
||||
super(description, index, devices);
|
||||
super(description, index, devices, /* markType */ null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+6
@@ -34,4 +34,10 @@ public interface Fix {
|
||||
Distance getDistanceToLeader();
|
||||
|
||||
Distance getDistanceToNextMark();
|
||||
|
||||
/**
|
||||
* Obtains a disqualification reason which is one of { None, BFD, DNS, DNF, DNC, DSQ, OCS, RAF, SCP, ZFP }. May be
|
||||
* <code>null</code>.
|
||||
*/
|
||||
String getBoatIRM();
|
||||
}
|
||||
+4
@@ -1,7 +1,11 @@
|
||||
package com.sap.sailing.domain.swisstimingadapter;
|
||||
|
||||
public interface Mark extends WithDescription {
|
||||
public enum MarkType { MANUAL, LINE_CROSSING, BUOY_ROUNDING };
|
||||
|
||||
int getIndex();
|
||||
|
||||
Iterable<String> getDevices();
|
||||
|
||||
MarkType getMarkType();
|
||||
}
|
||||
+2
-2
@@ -54,12 +54,12 @@ public enum MessageType {
|
||||
/**
|
||||
* Weather Information
|
||||
*/
|
||||
WEA(/* isRaceSpecific */ false),
|
||||
WEA(/* isRaceSpecific */ true),
|
||||
|
||||
/**
|
||||
* Wind Data
|
||||
*/
|
||||
WND(/* isRaceSpecific */ false),
|
||||
WND(/* isRaceSpecific */ true),
|
||||
|
||||
/**
|
||||
* Version
|
||||
|
||||
+16
-12
@@ -70,15 +70,15 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
controlPointCache = new HashMap<Iterable<String>, ControlPoint>();
|
||||
olympicClassesByID = new HashMap<String, BoatClass>();
|
||||
/*
|
||||
SAM102000 Men's Windsurfer = Windsufer Männer RS:X
|
||||
SAM102000 Men's Windsurfer = Windsufer M�nner RS:X
|
||||
SAW102000 Women's Windsurfer = Windsurfer Damen RS:X
|
||||
SAM004000 Men's One Person Dinghy = Laser Männer
|
||||
SAM004000 Men's One Person Dinghy = Laser M�nner
|
||||
SAW103000 Women's One Person Dinghy = Laser Damen Laser Radial
|
||||
SAM002000 Men's One Person Dinghy Heavy = Finn Dinghy Männer
|
||||
SAM005000 Men's Two Person Dinghy = 470er Männer
|
||||
SAM002000 Men's One Person Dinghy Heavy = Finn Dinghy M�nner
|
||||
SAM005000 Men's Two Person Dinghy = 470er M�nner
|
||||
SAW005000 Women's Two Person Dinghy = 470er Damen
|
||||
SAM009000 Men's Skiff = 49er Männer
|
||||
SAM007000 Men's Keelboat = Starboot Männer
|
||||
SAM009000 Men's Skiff = 49er M�nner
|
||||
SAM007000 Men's Keelboat = Starboot M�nner
|
||||
SAW010000 Women's Match Racing = Matchrace Damen Elliott 6M (modified)
|
||||
*/
|
||||
olympicClassesByID.put("102", baseDomainFactory.getOrCreateBoatClass("RS:X", /* typicallyStartsUpwind */ true));
|
||||
@@ -148,20 +148,24 @@ public class DomainFactoryImpl implements DomainFactory {
|
||||
private BoatClass getOrCreateBoatClassFromRaceID(String raceID) {
|
||||
BoatClass result;
|
||||
/*
|
||||
SAM102000 Men's Windsurfer = Windsufer Männer RS:X
|
||||
SAM102000 Men's Windsurfer = Windsufer M�nner RS:X
|
||||
SAW102000 Women's Windsurfer = Windsurfer Damen RS:X
|
||||
SAM004000 Men's One Person Dinghy = Laser Männer
|
||||
SAM004000 Men's One Person Dinghy = Laser M�nner
|
||||
SAW103000 Women's One Person Dinghy = Laser Damen Laser Radial
|
||||
SAM002000 Men's One Person Dinghy Heavy = Finn Dinghy Männer
|
||||
SAM005000 Men's Two Person Dinghy = 470er Männer
|
||||
SAM002000 Men's One Person Dinghy Heavy = Finn Dinghy M�nner
|
||||
SAM005000 Men's Two Person Dinghy = 470er M�nner
|
||||
SAW005000 Women's Two Person Dinghy = 470er Damen
|
||||
SAM009000 Men's Skiff = 49er Männer
|
||||
SAM007000 Men's Keelboat = Starboot Männer
|
||||
SAM009000 Men's Skiff = 49er M�nner
|
||||
SAM007000 Men's Keelboat = Starboot M�nner
|
||||
SAW010000 Women's Match Racing = Matchrace Damen Elliott 6M (modified)
|
||||
*/
|
||||
if (raceID.startsWith("SA") && raceID.length() == 9) {
|
||||
String classID = raceID.substring(3, 6);
|
||||
result = olympicClassesByID.get(classID);
|
||||
if (result == null) {
|
||||
// unknown code
|
||||
result = unknownBoatClass;
|
||||
}
|
||||
} else {
|
||||
result = unknownBoatClass;
|
||||
}
|
||||
|
||||
+11
-1
@@ -20,10 +20,14 @@ public class FixImpl implements Fix {
|
||||
private final Distance distanceToLeader;
|
||||
private final Distance distanceToNextMark;
|
||||
|
||||
/**
|
||||
* A disqualification reason, such as "DNC" or "DNS". May be <code>null</code>.
|
||||
*/
|
||||
private final String boatIRM;
|
||||
|
||||
public FixImpl(String boatID, TrackerType trackerType, Long ageOfDataInMilliseconds, Position position,
|
||||
SpeedWithBearing speed, Integer nextMarkIndex, Integer rank, Speed averageSpeedOverGroundPerLeg,
|
||||
Speed velocityMadeGood, Distance distanceToLeader, Distance distanceToNextMark) {
|
||||
Speed velocityMadeGood, Distance distanceToLeader, Distance distanceToNextMark, String boatIRM) {
|
||||
super();
|
||||
this.boatID = boatID;
|
||||
this.trackerType = trackerType;
|
||||
@@ -36,6 +40,12 @@ public class FixImpl implements Fix {
|
||||
this.velocityMadeGood = velocityMadeGood;
|
||||
this.distanceToLeader = distanceToLeader;
|
||||
this.distanceToNextMark = distanceToNextMark;
|
||||
this.boatIRM = boatIRM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBoatIRM() {
|
||||
return boatIRM;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+8
-2
@@ -8,12 +8,13 @@ public class MarkImpl implements Mark {
|
||||
private final String description;
|
||||
private final int index;
|
||||
private final Iterable<String> devices;
|
||||
private final MarkType markType;
|
||||
|
||||
|
||||
public MarkImpl(String description, int index, Iterable<String> devices) {
|
||||
public MarkImpl(String description, int index, Iterable<String> devices, MarkType markType) {
|
||||
super();
|
||||
this.description = description;
|
||||
this.index = index;
|
||||
this.markType = markType;
|
||||
ArrayList<String> l = new ArrayList<String>();
|
||||
for (String device : devices) {
|
||||
l.add(device);
|
||||
@@ -21,6 +22,11 @@ public class MarkImpl implements Mark {
|
||||
this.devices = l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MarkType getMarkType() {
|
||||
return markType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
|
||||
+58
-80
@@ -27,7 +27,6 @@ import java.util.logging.Logger;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedImpl;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.base.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
@@ -36,12 +35,14 @@ import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.DegreePosition;
|
||||
import com.sap.sailing.domain.common.impl.KilometersPerHourSpeedImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Competitor;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Course;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Fix;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Mark;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Mark.MarkType;
|
||||
import com.sap.sailing.domain.swisstimingadapter.MessageType;
|
||||
import com.sap.sailing.domain.swisstimingadapter.Race;
|
||||
import com.sap.sailing.domain.swisstimingadapter.RaceSpecificMessageLoader;
|
||||
@@ -336,7 +337,7 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement
|
||||
parseHHMMSSToMilliseconds(details[2]);
|
||||
markIndicesRanksAndTimesSinceStartInMilliseconds.add(new Triple<Integer, Integer, Long>(markIndex, rank, timeSinceStartInMilliseconds));
|
||||
}
|
||||
for (SailMasterListener listener : listeners) {
|
||||
for (SailMasterListener listener : getGeneralAndRaceSpecificListeners(message.getRaceID())) {
|
||||
try {
|
||||
listener.receivedTimingData(raceID, boatID, markIndicesRanksAndTimesSinceStartInMilliseconds);
|
||||
} catch (Throwable t) {
|
||||
@@ -344,22 +345,11 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement
|
||||
logger.throwing(SailMasterConnectorImpl.class.getName(), "notifyListenersTMD", t);
|
||||
}
|
||||
}
|
||||
Set<SailMasterListener> raceSpecificListenerSet = raceSpecificListeners.get(message.getRaceID());
|
||||
if (raceSpecificListenerSet != null) {
|
||||
for (SailMasterListener listener : raceSpecificListenerSet) {
|
||||
try {
|
||||
listener.receivedTimingData(raceID, boatID, markIndicesRanksAndTimesSinceStartInMilliseconds);
|
||||
} catch (Throwable t) {
|
||||
logger.info("Exception occurred trying to notify listener "+listener+" about "+message+": "+t.getMessage());
|
||||
logger.throwing(SailMasterConnectorImpl.class.getName(), "notifyListenersTMD", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListenersCAM(SailMasterMessage message) throws ParseException {
|
||||
List<Triple<Integer, TimePoint, String>> clockAtMarkResults = parseClockAtMarkMessage(message);
|
||||
for (SailMasterListener listener : listeners) {
|
||||
for (SailMasterListener listener : getGeneralAndRaceSpecificListeners(message.getRaceID())) {
|
||||
try {
|
||||
listener.receivedClockAtMark(message.getSections()[1], clockAtMarkResults);
|
||||
} catch (Throwable t) {
|
||||
@@ -367,22 +357,11 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement
|
||||
logger.throwing(SailMasterConnectorImpl.class.getName(), "notifyListenersCAM", t);
|
||||
}
|
||||
}
|
||||
Set<SailMasterListener> raceSpecificListenerSet = raceSpecificListeners.get(message.getRaceID());
|
||||
if (raceSpecificListenerSet != null) {
|
||||
for (SailMasterListener listener : raceSpecificListenerSet) {
|
||||
try {
|
||||
listener.receivedClockAtMark(message.getSections()[1], clockAtMarkResults);
|
||||
} catch (Throwable t) {
|
||||
logger.info("Exception occurred trying to notify listener "+listener+" about "+message+": "+t.getMessage());
|
||||
logger.throwing(SailMasterConnectorImpl.class.getName(), "notifyListenersCAM", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListenersSTL(SailMasterMessage message) {
|
||||
StartList startListMessage = parseStartListMessage(message);
|
||||
for (SailMasterListener listener : listeners) {
|
||||
for (SailMasterListener listener : getGeneralAndRaceSpecificListeners(message.getRaceID())) {
|
||||
try {
|
||||
listener.receivedStartList(message.getSections()[1], startListMessage);
|
||||
} catch (Throwable t) {
|
||||
@@ -390,22 +369,11 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement
|
||||
logger.throwing(SailMasterConnectorImpl.class.getName(), "notifyListenersSTL", t);
|
||||
}
|
||||
}
|
||||
Set<SailMasterListener> raceSpecificListenerSet = raceSpecificListeners.get(message.getRaceID());
|
||||
if (raceSpecificListenerSet != null) {
|
||||
for (SailMasterListener listener : raceSpecificListenerSet) {
|
||||
try {
|
||||
listener.receivedStartList(message.getSections()[1], startListMessage);
|
||||
} catch (Throwable t) {
|
||||
logger.info("Exception occurred trying to notify listener "+listener+" about "+message+": "+t.getMessage());
|
||||
logger.throwing(SailMasterConnectorImpl.class.getName(), "notifyListenersSTL", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListenersCCG(SailMasterMessage message) {
|
||||
Course course = parseCourseConfigurationMessage(message);
|
||||
for (SailMasterListener listener : listeners) {
|
||||
for (SailMasterListener listener : getGeneralAndRaceSpecificListeners(message.getRaceID())) {
|
||||
try {
|
||||
listener.receivedCourseConfiguration(message.getSections()[1], course);
|
||||
} catch (Throwable t) {
|
||||
@@ -413,16 +381,6 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement
|
||||
logger.throwing(SailMasterConnectorImpl.class.getName(), "notifyListenersCCG", t);
|
||||
}
|
||||
}
|
||||
Set<SailMasterListener> raceSpecificListenerSet = raceSpecificListeners.get(message.getRaceID());
|
||||
if (raceSpecificListenerSet != null) {
|
||||
for (SailMasterListener listener : raceSpecificListenerSet) {
|
||||
try {
|
||||
listener.receivedCourseConfiguration(message.getSections()[1], course);
|
||||
} catch (Throwable t) {
|
||||
logger.throwing(SailMasterConnectorImpl.class.getName(), "notifyListenersCCG", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListenersRAC(SailMasterMessage message) {
|
||||
@@ -458,53 +416,52 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement
|
||||
Collection<Fix> fixes = new ArrayList<Fix>();
|
||||
for (int i=0; i<count; i++) {
|
||||
int fixDetailIndex = 0;
|
||||
String[] fixSections = sections[9+i].split(";");
|
||||
final String[] fixSections = sections[9+i].split(";");
|
||||
final boolean postVersion1_0 = sections[9+i].split(";", -1).length >= 14;
|
||||
if (fixSections.length > 2) {
|
||||
String boatID = fixSections[fixDetailIndex++];
|
||||
TrackerType trackerType = TrackerType.values()[Integer.valueOf(fixSections[fixDetailIndex++])];
|
||||
Long ageOfDataInMilliseconds = 1000l * Long.valueOf(fixSections[fixDetailIndex++]);
|
||||
Position position = new DegreePosition(Double.valueOf(fixSections[fixDetailIndex++]),
|
||||
final String boatID = fixSections[fixDetailIndex++];
|
||||
final TrackerType trackerType = TrackerType.values()[Integer.valueOf(fixSections[fixDetailIndex++])];
|
||||
final Long ageOfDataInMilliseconds = 1000l * Long.valueOf(fixSections[fixDetailIndex++]);
|
||||
final Position position = new DegreePosition(Double.valueOf(fixSections[fixDetailIndex++]),
|
||||
Double.valueOf(fixSections[fixDetailIndex++]));
|
||||
Double speedOverGroundInKnots = Double.valueOf(fixSections[fixDetailIndex++]);
|
||||
Speed averageSpeedOverGround = fixSections[fixDetailIndex].trim().length() == 0 ? null
|
||||
: new KnotSpeedImpl(Double.valueOf(fixSections[fixDetailIndex]));
|
||||
fixDetailIndex++;
|
||||
Speed velocityMadeGood = fixSections[fixDetailIndex].trim().length() == 0 ? null : new KnotSpeedImpl(
|
||||
Double.valueOf(fixSections[fixDetailIndex]));
|
||||
fixDetailIndex++;
|
||||
SpeedWithBearing speed = new KnotSpeedWithBearingImpl(speedOverGroundInKnots, new DegreeBearingImpl(
|
||||
Double.valueOf(fixSections[fixDetailIndex++])));
|
||||
Integer nextMarkIndex = fixSections.length <= fixDetailIndex
|
||||
final Double speedOverGroundInKnots = Double.valueOf(fixSections[fixDetailIndex++]);
|
||||
final int alsIndex = postVersion1_0 ? fixDetailIndex+1 : fixDetailIndex;
|
||||
final int vmgIndex = postVersion1_0 ? fixDetailIndex : fixDetailIndex+1;
|
||||
final Speed averageSpeedOverGround = fixSections[alsIndex].trim().length() == 0 ? null
|
||||
: new KnotSpeedImpl(Double.valueOf(fixSections[alsIndex]));
|
||||
final Speed velocityMadeGood = fixSections[vmgIndex].trim().length() == 0 ? null : new KnotSpeedImpl(
|
||||
Double.valueOf(fixSections[vmgIndex]));
|
||||
fixDetailIndex += 2;
|
||||
final DegreeBearingImpl cog = new DegreeBearingImpl(
|
||||
Double.valueOf(fixSections[fixDetailIndex++]));
|
||||
final SpeedWithBearing speed = new KnotSpeedWithBearingImpl(speedOverGroundInKnots, cog);
|
||||
final Integer nextMarkIndex = fixSections.length <= fixDetailIndex
|
||||
|| fixSections[fixDetailIndex].trim().length() == 0 ? null : Integer
|
||||
.valueOf(fixSections[fixDetailIndex]);
|
||||
fixDetailIndex++;
|
||||
Integer rank = fixSections.length <= fixDetailIndex || fixSections[fixDetailIndex].trim().length() == 0 ? null
|
||||
final Integer rank = fixSections.length <= fixDetailIndex || fixSections[fixDetailIndex].trim().length() == 0 ? null
|
||||
: Integer.valueOf(fixSections[fixDetailIndex]);
|
||||
fixDetailIndex++;
|
||||
Distance distanceToLeader = fixSections.length <= fixDetailIndex
|
||||
final Distance distanceToLeader = fixSections.length <= fixDetailIndex
|
||||
|| fixSections[fixDetailIndex].trim().length() == 0 ? null : new MeterDistance(
|
||||
Double.valueOf(fixSections[fixDetailIndex]));
|
||||
fixDetailIndex++;
|
||||
Distance distanceToNextMark = fixSections.length <= fixDetailIndex
|
||||
final Distance distanceToNextMark = fixSections.length <= fixDetailIndex
|
||||
|| fixSections[fixDetailIndex].trim().length() == 0 ? null : new MeterDistance(
|
||||
Double.valueOf(fixSections[fixDetailIndex]));
|
||||
fixDetailIndex++;
|
||||
final String boatIRM; // the "disqualification" or "MaxPointReason"
|
||||
if (postVersion1_0 && fixSections.length > fixDetailIndex) {
|
||||
boatIRM = fixSections[fixDetailIndex++];
|
||||
} else {
|
||||
boatIRM = null;
|
||||
}
|
||||
fixes.add(new FixImpl(boatID, trackerType, ageOfDataInMilliseconds, position, speed, nextMarkIndex,
|
||||
rank, averageSpeedOverGround, velocityMadeGood, distanceToLeader, distanceToNextMark));
|
||||
rank, averageSpeedOverGround, velocityMadeGood, distanceToLeader, distanceToNextMark, boatIRM));
|
||||
}
|
||||
}
|
||||
for (SailMasterListener listener : listeners) {
|
||||
try {
|
||||
listener.receivedRacePositionData(raceID, status, timePoint, startTimeEstimatedStartTime, millisecondsSinceRaceStart,
|
||||
nextMarkIndexForLeader, distanceToNextMarkForLeader, fixes);
|
||||
} catch (Throwable t) {
|
||||
logger.info("Exception occurred trying to notify listener "+listener+" about "+message+": "+t.getMessage());
|
||||
logger.throwing(SailMasterConnectorImpl.class.getName(), "notifyListenersRPD", t);
|
||||
}
|
||||
}
|
||||
Set<SailMasterListener> raceSpecificListenerSet = raceSpecificListeners.get(message.getRaceID());
|
||||
if (raceSpecificListenerSet != null) {
|
||||
for (SailMasterListener listener : raceSpecificListenerSet) {
|
||||
Set<SailMasterListener> allListeners = getGeneralAndRaceSpecificListeners(message.getRaceID());
|
||||
for (SailMasterListener listener : allListeners) {
|
||||
try {
|
||||
listener.receivedRacePositionData(raceID, status, timePoint, startTimeEstimatedStartTime, millisecondsSinceRaceStart,
|
||||
nextMarkIndexForLeader, distanceToNextMarkForLeader, fixes);
|
||||
@@ -514,6 +471,14 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Set<SailMasterListener> getGeneralAndRaceSpecificListeners(String raceID) {
|
||||
Set<SailMasterListener> allListeners = new HashSet<SailMasterListener>(listeners);
|
||||
Set<SailMasterListener> listenersForThisRace = raceSpecificListeners.get(raceID);
|
||||
if (listenersForThisRace != null) {
|
||||
allListeners.addAll(listenersForThisRace);
|
||||
}
|
||||
return allListeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -630,7 +595,20 @@ public class SailMasterConnectorImpl extends SailMasterTransceiverImpl implement
|
||||
List<Mark> marks = new ArrayList<Mark>();
|
||||
for (int i=0; i<count; i++) {
|
||||
String[] markDetails = courseConfigurationMessage.getSections()[3+i].split(";");
|
||||
marks.add(new MarkImpl(markDetails[1], Integer.valueOf(markDetails[0]), Arrays.asList(markDetails).subList(2, markDetails.length)));
|
||||
MarkType markType = null;
|
||||
final int devicesNamesStartIndex;
|
||||
if (courseConfigurationMessage.getSections()[3+i].split(";", -1).length == 5) {
|
||||
// this is the SailMaster protocol version 1.0 (May 2012) or later (see bug 1000), containing
|
||||
// a MarkType specification before the two tracker IDs:
|
||||
int markTypeIndex = Integer.valueOf(markDetails[2]);
|
||||
markType = MarkType.values()[markTypeIndex];
|
||||
devicesNamesStartIndex = 3;
|
||||
} else {
|
||||
devicesNamesStartIndex = 2;
|
||||
}
|
||||
marks.add(new MarkImpl(markDetails[1], Integer.valueOf(markDetails[0]),
|
||||
Arrays.asList(markDetails).subList(devicesNamesStartIndex, markDetails.length),
|
||||
markType));
|
||||
}
|
||||
return new CourseImpl(courseConfigurationMessage.getSections()[1], marks);
|
||||
}
|
||||
|
||||
-2
@@ -15,9 +15,7 @@ public class SailMasterLiveSimulatorConnectorImpl extends SailMasterConnectorImp
|
||||
|
||||
public SailMasterLiveSimulatorConnectorImpl(String host, int port, RaceSpecificMessageLoader messageLoader, boolean canSendRequests) throws InterruptedException {
|
||||
super(host, port, messageLoader, canSendRequests);
|
||||
|
||||
bufferedMessageList = Collections.synchronizedList(new ArrayList<SailMasterMessage>());
|
||||
|
||||
Thread messageDeliveryThread = new Thread("SailMasterLiveSimulatorConnector") {
|
||||
public void run() {
|
||||
while(true) {
|
||||
|
||||
+1
-1
@@ -247,7 +247,7 @@ public class SwissTimingRaceTrackerImpl extends AbstractRaceTrackerImpl implemen
|
||||
public void receivedClockAtMark(String raceID,
|
||||
List<Triple<Integer, TimePoint, String>> markIndicesTimePointsAndBoatIDs) {
|
||||
// Ignored because it's covered by TMD. Mail from Kai Hahndorf of 2011-11-15T12:42:00Z:
|
||||
// "Die TMD werden immer gesendet. Das CAM Protokoll ist nur für unsere TV-Grafik wichtig, da damit die Rückstandsuhr gestartet wird."
|
||||
// "Die TMD werden immer gesendet. Das CAM Protokoll ist nur fuer unsere TV-Grafik wichtig, da damit die Rueckstandsuhr gestartet wird."
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -17,10 +17,10 @@ import org.junit.Test;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.impl.DouglasPeucker;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.base.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.tracking.DynamicGPSFixTrack;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
|
||||
+80
-1
@@ -8,8 +8,11 @@ import static org.junit.Assert.assertTrue;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -20,10 +23,14 @@ import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.base.Series;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.BuoyImpl;
|
||||
import com.sap.sailing.domain.base.impl.FleetImpl;
|
||||
import com.sap.sailing.domain.base.impl.GateImpl;
|
||||
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.base.impl.WaypointImpl;
|
||||
import com.sap.sailing.domain.common.MaxPointsReason;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
@@ -41,7 +48,11 @@ import com.sap.sailing.domain.leaderboard.impl.ResultDiscardingRuleImpl;
|
||||
import com.sap.sailing.domain.leaderboard.impl.ScoreCorrectionImpl;
|
||||
import com.sap.sailing.domain.leaderboard.meta.LeaderboardGroupMetaLeaderboard;
|
||||
import com.sap.sailing.domain.test.mock.MockedTrackedRaceWithStartTimeAndRanks;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
|
||||
import com.sap.sailing.domain.tracking.impl.TimedComparator;
|
||||
import com.sap.sailing.util.impl.ArrayListNavigableSet;
|
||||
|
||||
public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
private ArrayList<Series> series;
|
||||
@@ -512,6 +523,48 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
assertEquals(reversedCompetitors, leaderboard.getCompetitorsFromBestToWorst(later));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTotalTimeNotCountedForRacesStartedLaterThanTimePointRequested() {
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
TimePoint earlier = now.minus(1000000);
|
||||
TimePoint later = now.plus(1000000); // first race from "earlier" to "now", second from "now" to "later", third from "later" to "finish"
|
||||
TimePoint finish = later.plus(1000000);
|
||||
Competitor[] c = createCompetitors(3).toArray(new Competitor[0]);
|
||||
Competitor[] f1 = new Competitor[] { c[0], c[1], c[2] };
|
||||
Competitor[] f2 = new Competitor[] { c[0], c[1], c[2] };
|
||||
Competitor[] f3 = new Competitor[] { c[1], c[2], c[0] };
|
||||
Regatta regatta = createRegatta(/* qualifying */0, new String[] { "Default" }, /* final */3, new String[] { "Default" },
|
||||
/* medal */ false, "testTotalTimeNotCountedForRacesStartedLaterThanTimePointReqeusted",
|
||||
DomainFactory.INSTANCE.getOrCreateBoatClass("49er", /* typicallyStartsUpwind */true), DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT));
|
||||
Leaderboard leaderboard = createLeaderboard(regatta, /* discarding thresholds */ new int[0]);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Competitor, TimePoint>[] lastMarkPassingTimesForCompetitors = (Map<Competitor, TimePoint>[]) new HashMap<?, ?>[3];
|
||||
lastMarkPassingTimesForCompetitors[0] = new HashMap<>();
|
||||
lastMarkPassingTimesForCompetitors[0].put(c[0], now);
|
||||
lastMarkPassingTimesForCompetitors[0].put(c[1], now);
|
||||
lastMarkPassingTimesForCompetitors[0].put(c[2], now);
|
||||
lastMarkPassingTimesForCompetitors[1] = new HashMap<>();
|
||||
lastMarkPassingTimesForCompetitors[1].put(c[0], later);
|
||||
lastMarkPassingTimesForCompetitors[1].put(c[1], later);
|
||||
lastMarkPassingTimesForCompetitors[1].put(c[2], later);
|
||||
lastMarkPassingTimesForCompetitors[2] = new HashMap<>();
|
||||
lastMarkPassingTimesForCompetitors[2].put(c[0], finish);
|
||||
lastMarkPassingTimesForCompetitors[2].put(c[1], finish);
|
||||
lastMarkPassingTimesForCompetitors[2].put(c[2], finish);
|
||||
createAndAttachTrackedRacesWithStartTimeAndLastMarkPassingTimes(series.get(1), "Default",
|
||||
new Competitor[][] { f1, f2, f3 }, new TimePoint[] { earlier, now, later }, lastMarkPassingTimesForCompetitors);
|
||||
long totalTimeSailedC0_InRace1 = leaderboard.getTotalTimeSailedInMilliseconds(c[0], earlier.plus(1000));
|
||||
assertEquals(1000l, totalTimeSailedC0_InRace1);
|
||||
long totalTimeSailedC0_InRace2 = leaderboard.getTotalTimeSailedInMilliseconds(c[0], now.plus(1000));
|
||||
assertEquals(now.asMillis()-earlier.asMillis() + 1000, totalTimeSailedC0_InRace2);
|
||||
long totalTimeSailedC0_InRace3 = leaderboard.getTotalTimeSailedInMilliseconds(c[0], later.plus(1000));
|
||||
assertEquals(later.asMillis()-earlier.asMillis() + 1000, totalTimeSailedC0_InRace3);
|
||||
long totalTimeSailedC0_AtEndOfRace3 = leaderboard.getTotalTimeSailedInMilliseconds(c[0], finish);
|
||||
assertEquals(finish.asMillis()-earlier.asMillis(), totalTimeSailedC0_AtEndOfRace3);
|
||||
long totalTimeSailedC0_AfterRace3 = leaderboard.getTotalTimeSailedInMilliseconds(c[0], finish.plus(1000));
|
||||
assertEquals(finish.asMillis()-earlier.asMillis(), totalTimeSailedC0_AfterRace3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTieBreakWithTwoVersusOneWins() throws NoWindException {
|
||||
Competitor[] c = createCompetitors(3).toArray(new Competitor[0]);
|
||||
@@ -644,7 +697,7 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
leaderboard1.getFleet(null));
|
||||
assertTrue(leaderboard3.getCompetitorsFromBestToWorst(later).indexOf(c[3]) <
|
||||
leaderboard3.getCompetitorsFromBestToWorst(later).indexOf(c[0])); // c3 better than c0; won last race
|
||||
LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl("Leaderboard Group", "Leaderboard Group", Arrays.asList(leaderboard1,
|
||||
LeaderboardGroup leaderboardGroup = new LeaderboardGroupImpl("Leaderboard Group", "Leaderboard Group", false, Arrays.asList(leaderboard1,
|
||||
leaderboard2, leaderboard3));
|
||||
leaderboardGroup.setOverallLeaderboard(new LeaderboardGroupMetaLeaderboard(leaderboardGroup, new HighPointExtremeSailingSeriesOverall(),
|
||||
new ResultDiscardingRuleImpl(new int[0])));
|
||||
@@ -670,6 +723,32 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
return later;
|
||||
}
|
||||
|
||||
private void createAndAttachTrackedRacesWithStartTimeAndLastMarkPassingTimes(
|
||||
Series theSeries, String fleetName, Competitor[][] competitorLists, TimePoint[] startTimes,
|
||||
Map<Competitor, TimePoint>[] lastMarkPassingTimesForCompetitors) {
|
||||
Iterator<? extends RaceColumn> columnIter = theSeries.getRaceColumns().iterator();
|
||||
int i=0;
|
||||
for (Competitor[] competitorList : competitorLists) {
|
||||
RaceColumn raceColumn = columnIter.next();
|
||||
final Map<Competitor, TimePoint> lastMarkPassingTimes = lastMarkPassingTimesForCompetitors[i];
|
||||
final Waypoint start = new WaypointImpl(new GateImpl(new BuoyImpl("Left StartBuoy"), new BuoyImpl("Right StartBuoy"), "Start"));
|
||||
final Waypoint finish = new WaypointImpl(new BuoyImpl("FinishBuoy"));
|
||||
TrackedRace trackedRace = new MockedTrackedRaceWithStartTimeAndRanks(startTimes[i], Arrays.asList(competitorList)) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override
|
||||
public NavigableSet<MarkPassing> getMarkPassings(Competitor competitor) {
|
||||
ArrayListNavigableSet<MarkPassing> result = new ArrayListNavigableSet<>(new TimedComparator());
|
||||
result.add(new MarkPassingImpl(lastMarkPassingTimes.get(competitor), finish, competitor));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
trackedRace.getRace().getCourse().addWaypoint(0, start);
|
||||
trackedRace.getRace().getCourse().addWaypoint(1, finish);
|
||||
raceColumn.setTrackedRace(raceColumn.getFleetByName(fleetName), trackedRace);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Competitor> createCompetitors(int numberOfCompetitorsToCreate) {
|
||||
List<Competitor> result = new ArrayList<Competitor>();
|
||||
for (int i=1; i<=numberOfCompetitorsToCreate; i++) {
|
||||
|
||||
+1
-1
@@ -20,7 +20,6 @@ import org.junit.Test;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.impl.DouglasPeucker;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.base.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
@@ -28,6 +27,7 @@ import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
|
||||
+1
-2
@@ -78,8 +78,7 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
||||
|
||||
@Override
|
||||
public TimePoint getStartOfRace() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
return startTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,7 +10,7 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
com.googlecode.java-diff-utils;bundle-version="1.3.0",
|
||||
com.sap.sailing.domain.common
|
||||
Export-Package: com.sap.sailing.domain.tractracadapter,
|
||||
com.sap.sailing.domain.tractracadapter.impl;x-friends:="com.sap.sailing.domain.test"
|
||||
com.sap.sailing.domain.tractracadapter.impl;x-friends:="com.sap.sailing.domain.test,com.sap.sailing.domain.swisstimingadapter.test"
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Import-Package: org.json.simple,
|
||||
org.json.simple.parser
|
||||
@@ -108,11 +108,11 @@ public interface RaceColumn extends Named {
|
||||
*/
|
||||
Pair<Competitor, RaceColumn> getKey(Competitor competitor);
|
||||
|
||||
public abstract RaceColumnListeners getRaceColumnListeners();
|
||||
RaceColumnListeners getRaceColumnListeners();
|
||||
|
||||
public abstract void removeRaceColumnListener(RaceColumnListener listener);
|
||||
void removeRaceColumnListener(RaceColumnListener listener);
|
||||
|
||||
public abstract void addRaceColumnListener(RaceColumnListener listener);
|
||||
void addRaceColumnListener(RaceColumnListener listener);
|
||||
|
||||
/**
|
||||
* Releases the {@link TrackedRace} previously set by {@link #setTrackedRace(Fleet, TrackedRace)} but leaves the
|
||||
@@ -123,4 +123,24 @@ public interface RaceColumn extends Named {
|
||||
* the fleet for which to release its tracked race
|
||||
*/
|
||||
void releaseTrackedRace(Fleet fleet);
|
||||
|
||||
/**
|
||||
* Usually, the scores in each leaderboard column count as they are for the overall score. However, if a column is
|
||||
* a medal race column it usually counts double. Under certain circumstances, columns may also count with factors different
|
||||
* from 1 or 2. For example, we've seen cases in the Extreme Sailing Series where the race committee defined that in the
|
||||
* overall series leaderboard the last two columns each count 1.5 times their scores.
|
||||
*/
|
||||
double getFactor();
|
||||
|
||||
/**
|
||||
* @param factor if <code>null</code>, {@link #getFactor()} will again compute a default value; otherwise, {@link #getFactor()} will
|
||||
* then return the double value of <code>factor</code>.
|
||||
*/
|
||||
void setFactor(Double factor);
|
||||
|
||||
/**
|
||||
* If <code>null</code>, the {@link #getFactor() factor} defaults to 1 for non-medal and {@link #DEFAULT_MEDAL_RACE_FACTOR} for
|
||||
* medal races. Otherwise, the explicit factor is used.
|
||||
*/
|
||||
Double getExplicitFactor();
|
||||
}
|
||||
@@ -17,6 +17,10 @@ public interface RaceColumnListener extends Serializable {
|
||||
|
||||
void raceColumnRemovedFromContainer(RaceColumn raceColumn);
|
||||
|
||||
void raceColumnMoved(RaceColumn raceColumn, int newIndex);
|
||||
|
||||
void factorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor);
|
||||
|
||||
/**
|
||||
* A listener can use this to specify that it must not be serialized together with other listeners.
|
||||
* Background: the collections holding race column listeners are usually non-transient. This will cause
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.sap.sailing.domain.base.impl;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.DomainFactory;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.impl.NamedImpl;
|
||||
|
||||
public class BoatClassImpl extends NamedImpl implements BoatClass {
|
||||
|
||||
@@ -48,7 +48,7 @@ public class BuoyImpl extends NamedImpl implements Buoy {
|
||||
|
||||
@Override
|
||||
public Buoy resolve(DomainFactory domainFactory) {
|
||||
Buoy result = domainFactory.getOrCreateBuoy(getName());
|
||||
Buoy result = domainFactory.getOrCreateBuoy(getName(), getDisplayColor());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -230,6 +230,16 @@ public class RegattaImpl extends NamedImpl implements Regatta, RaceColumnListene
|
||||
raceColumnListeners.notifyListenersAboutRaceColumnRemovedFromContainer(raceColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceColumnMoved(RaceColumn raceColumn, int newIndex) {
|
||||
raceColumnListeners.notifyListenersAboutRaceColumnMoved(raceColumn, newIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void factorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor) {
|
||||
raceColumnListeners.notifyListenersAboutFactorChanged(raceColumn, oldFactor, newFactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransient() {
|
||||
return false;
|
||||
|
||||
@@ -223,6 +223,16 @@ public class SeriesImpl extends NamedImpl implements Series, RaceColumnListener
|
||||
raceColumnListeners.notifyListenersAboutRaceColumnRemovedFromContainer(raceColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceColumnMoved(RaceColumn raceColumn, int newIndex) {
|
||||
raceColumnListeners.notifyListenersAboutRaceColumnMoved(raceColumn, newIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void factorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor) {
|
||||
raceColumnListeners.notifyListenersAboutFactorChanged(raceColumn, oldFactor, newFactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransient() {
|
||||
return false;
|
||||
|
||||
+30
@@ -13,6 +13,19 @@ public abstract class SimpleAbstractRaceColumn implements RaceColumn {
|
||||
private static final long serialVersionUID = -3590156714385187908L;
|
||||
private final RaceColumnListeners raceColumnListeners;
|
||||
|
||||
/**
|
||||
* The factor by which a medal race score is multiplied by default in the overall point scheme.
|
||||
*
|
||||
* @see #getFactor()
|
||||
*/
|
||||
private static final double DEFAULT_MEDAL_RACE_FACTOR = 2.0;
|
||||
|
||||
/**
|
||||
* If <code>null</code>, the {@link #getFactor() factor} defaults to 1 for non-medal and {@link #DEFAULT_MEDAL_RACE_FACTOR} for
|
||||
* medal races. Otherwise, the explicit factor is used.
|
||||
*/
|
||||
private Double explicitFactor;
|
||||
|
||||
public SimpleAbstractRaceColumn() {
|
||||
raceColumnListeners = new RaceColumnListeners();
|
||||
}
|
||||
@@ -45,4 +58,21 @@ public abstract class SimpleAbstractRaceColumn implements RaceColumn {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getFactor() {
|
||||
return explicitFactor == null ? (isMedalRace() ? DEFAULT_MEDAL_RACE_FACTOR : 1.) : explicitFactor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFactor(Double factor) {
|
||||
Double oldExplicitFactor = getExplicitFactor();
|
||||
explicitFactor = factor;
|
||||
raceColumnListeners.notifyListenersAboutFactorChanged(this, oldExplicitFactor, factor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getExplicitFactor() {
|
||||
return explicitFactor;
|
||||
}
|
||||
}
|
||||
+2
@@ -15,6 +15,8 @@ public interface LeaderboardGroup extends Renamable {
|
||||
String getDescription();
|
||||
void setDescriptiom(String description);
|
||||
|
||||
boolean isDisplayGroupsInReverseOrder();
|
||||
|
||||
Iterable<Leaderboard> getLeaderboards();
|
||||
int getIndexOf(Leaderboard leaderboard);
|
||||
void addLeaderboard(Leaderboard leaderboard);
|
||||
|
||||
+22
-12
@@ -47,11 +47,6 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
|
||||
static final Double DOUBLE_0 = new Double(0);
|
||||
|
||||
/**
|
||||
* The factor by which a medal race score is multiplied in the overall point scheme
|
||||
*/
|
||||
static final double MEDAL_RACE_FACTOR = 2.0;
|
||||
|
||||
private final SettableScoreCorrection scoreCorrection;
|
||||
|
||||
private ThresholdBasedResultDiscardingRule resultDiscardingRule;
|
||||
@@ -232,7 +227,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
if (netPoints == null) {
|
||||
result = null;
|
||||
} else {
|
||||
result = (raceColumn.isMedalRace() ? MEDAL_RACE_FACTOR : 1.0) * netPoints;
|
||||
result = raceColumn.getFactor() * netPoints;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -367,7 +362,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
final Double correctedScore = correctedResults.getCorrectedScore();
|
||||
return new EntryImpl(trackedRankProvider, correctedScore, correctedResults.isCorrected(),
|
||||
discarded ? DOUBLE_0
|
||||
: correctedScore == null ? null : Double.valueOf(correctedScore * (race.isMedalRace() ? MEDAL_RACE_FACTOR : 1.0)),
|
||||
: correctedScore == null ? null : Double.valueOf(correctedScore * race.getFactor()),
|
||||
correctedResults.getMaxPointsReason(), discarded, race.getFleetOfCompetitor(competitor));
|
||||
}
|
||||
|
||||
@@ -394,7 +389,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
final Double correctedScore = correctedResults.getCorrectedScore();
|
||||
Entry entry = new EntryImpl(trackedRankProvider, correctedScore,
|
||||
correctedResults.isCorrected(), discarded ? DOUBLE_0 : (correctedScore==null?null:
|
||||
Double.valueOf((correctedScore * (raceColumn.isMedalRace() ? MEDAL_RACE_FACTOR : 1.0)))),
|
||||
Double.valueOf((correctedScore * raceColumn.getFactor()))),
|
||||
correctedResults.getMaxPointsReason(), discarded,
|
||||
raceColumn.getFleetOfCompetitor(competitor));
|
||||
result.put(new Pair<Competitor, RaceColumn>(competitor, raceColumn), entry);
|
||||
@@ -418,6 +413,16 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
getRaceColumnListeners().notifyListenersAboutIsMedalRaceChanged(raceColumn, newIsMedalRace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceColumnMoved(RaceColumn raceColumn, int newIndex) {
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(raceColumn, newIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void factorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor) {
|
||||
getRaceColumnListeners().notifyListenersAboutFactorChanged(raceColumn, oldFactor, newFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* A leaderboard will only accept the addition of a race column if the column's name is unique across the leaderboard.
|
||||
*/
|
||||
@@ -566,14 +571,18 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
NavigableSet<MarkPassing> markPassings = trackedRace.getMarkPassings(competitor);
|
||||
if (!markPassings.isEmpty()) {
|
||||
TimePoint from = trackedRace.getStartOfRace(); // start counting at race start, not when the competitor passed the line
|
||||
if (!timePoint.before(from)) { // but only if the race started after timePoint
|
||||
TimePoint to;
|
||||
if (timePoint.after(markPassings.last().getTimePoint()) &&
|
||||
markPassings.last().getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint()) {
|
||||
if (timePoint.after(markPassings.last().getTimePoint())
|
||||
&& markPassings.last().getWaypoint() == trackedRace.getRace().getCourse()
|
||||
.getLastWaypoint()) {
|
||||
// stop counting when competitor finished the race
|
||||
to = markPassings.last().getTimePoint();
|
||||
} else {
|
||||
if (trackedRace.getEndOfTracking() != null && timePoint.after(trackedRace.getEndOfTracking())) {
|
||||
result = null; // race not finished until end of tracking; no reasonable value can be computed for competitor
|
||||
if (trackedRace.getEndOfTracking() != null
|
||||
&& timePoint.after(trackedRace.getEndOfTracking())) {
|
||||
result = null; // race not finished until end of tracking; no reasonable value can be
|
||||
// computed for competitor
|
||||
break;
|
||||
} else {
|
||||
to = timePoint;
|
||||
@@ -588,6 +597,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -10,8 +10,8 @@ public class EventLeaderboardImpl extends LeaderboardGroupImpl implements EventL
|
||||
private static final long serialVersionUID = -8933204023833087837L;
|
||||
private Event event;
|
||||
|
||||
public EventLeaderboardImpl(Event event, String name, String description, List<Leaderboard> leaderboards) {
|
||||
super(name, description, leaderboards);
|
||||
public EventLeaderboardImpl(Event event, String name, String description, boolean displayGroupsInReverseOrder, List<Leaderboard> leaderboards) {
|
||||
super(name, description, displayGroupsInReverseOrder, leaderboards);
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
|
||||
+8
-9
@@ -140,15 +140,15 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
|
||||
race = r;
|
||||
}
|
||||
}
|
||||
if (race == null) {
|
||||
return;
|
||||
}
|
||||
if (race != null) {
|
||||
int index = 0;
|
||||
index = races.lastIndexOf(race);
|
||||
index--;
|
||||
if (index >= 0) {
|
||||
races.remove(race);
|
||||
races.add(index, race);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(race, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,18 +160,17 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
|
||||
race = r;
|
||||
}
|
||||
}
|
||||
if (race == null) {
|
||||
return;
|
||||
}
|
||||
if (race != null) {
|
||||
int index = 0;
|
||||
index = races.lastIndexOf(race);
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
if (index != -1) {
|
||||
index++;
|
||||
if (index < races.size()) {
|
||||
races.remove(race);
|
||||
races.add(index, race);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(race, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -5,7 +5,10 @@ import java.util.List;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
|
||||
/**
|
||||
* In this variant of the {@link HighPoint}
|
||||
* In this variant of the {@link HighPoint} scoring scheme, scoring by "better race" (sometimes referred to as a
|
||||
* "back run" where the races are sorted with best races first and the first difference is counted) is disabled, such
|
||||
* that even if the last race is not a medeal race, the last race score decides the ordering.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
|
||||
+7
-1
@@ -15,6 +15,7 @@ public class LeaderboardGroupImpl implements LeaderboardGroup {
|
||||
private static final long serialVersionUID = 2035927369446736934L;
|
||||
private String name;
|
||||
private String description;
|
||||
private boolean displayGroupsInReverseOrder;
|
||||
private final List<Leaderboard> leaderboards;
|
||||
private final Set<LeaderboardGroupListener> listeners;
|
||||
|
||||
@@ -25,9 +26,10 @@ public class LeaderboardGroupImpl implements LeaderboardGroup {
|
||||
*/
|
||||
private Leaderboard overallLeaderboard;
|
||||
|
||||
public LeaderboardGroupImpl(String name, String description, List<? extends Leaderboard> leaderboards) {
|
||||
public LeaderboardGroupImpl(String name, String description, boolean displayGroupsInReverseOrder, List<? extends Leaderboard> leaderboards) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.displayGroupsInReverseOrder = displayGroupsInReverseOrder;
|
||||
this.leaderboards = new ArrayList<Leaderboard>(leaderboards);
|
||||
this.listeners = new HashSet<LeaderboardGroupListener>();
|
||||
}
|
||||
@@ -140,4 +142,8 @@ public class LeaderboardGroupImpl implements LeaderboardGroup {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisplayGroupsInReverseOrder() {
|
||||
return displayGroupsInReverseOrder;
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -36,7 +36,7 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
* Instances of subclasses need to register a {@link ScoreCorrectionChangeForwarder} as listener on each leaderboard
|
||||
* referenced by this meta leaderboard to ensure that score corrections applied to the "inner" leaderboard are signaled
|
||||
* to {@link ScoreCorrectionListeners} on this meta leaderboard's score correction. See
|
||||
* {@link #registerScoreCorrectionChangeForwarder(Leaderboard)} and
|
||||
* {@link #registerScoreCorrectionAndRaceColumnChangeForwarder(Leaderboard)} and
|
||||
* {@link #unregisterScoreCorrectionChangeForwarder(Leaderboard)}.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
@@ -130,12 +130,14 @@ public abstract class AbstractMetaLeaderboard extends AbstractSimpleLeaderboardI
|
||||
RaceColumn result = columnsForLeaderboards.get(leaderboard);
|
||||
if (result == null) {
|
||||
result = new MetaLeaderboardColumn(leaderboard, metaFleet);
|
||||
result.addRaceColumnListener(this);
|
||||
columnsForLeaderboards.put(leaderboard, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void registerScoreCorrectionChangeForwarder(Leaderboard leaderboard) {
|
||||
protected void registerScoreCorrectionAndRaceColumnChangeForwarder(Leaderboard leaderboard) {
|
||||
leaderboard.addRaceColumnListener(this);
|
||||
final ScoreCorrectionChangeForwarder listener = new ScoreCorrectionChangeForwarder();
|
||||
scoreCorrectionChangeForwardersByLeaderboard.put(leaderboard, listener);
|
||||
leaderboard.getScoreCorrection().addScoreCorrectionListener(listener);
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ public class FlexibleMetaLeaderboard extends AbstractMetaLeaderboard {
|
||||
LockUtil.lockForWrite(leaderboardsLock);
|
||||
try {
|
||||
leaderboards.add(leaderboard);
|
||||
registerScoreCorrectionChangeForwarder(leaderboard);
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(getColumnForLeaderboard(leaderboard));
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(leaderboardsLock);
|
||||
|
||||
+6
-8
@@ -20,9 +20,9 @@ import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
* <p>
|
||||
*
|
||||
* After an object of this type has been de-serialized, and after all objects referenced by it (leaderboard, leaderboard
|
||||
* group) have been initialized, {@link #registerAsScoreCorrectionChangeForwarderOnAllLeaderboards()} must be called to
|
||||
* group) have been initialized, {@link #registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards()} must be called to
|
||||
* ensure that score corrections are propagated as desired. This is because score correction listeners are "transient"
|
||||
* and are as such not serialized. Note: calling {@link #registerAsScoreCorrectionChangeForwarderOnAllLeaderboards()}
|
||||
* and are as such not serialized. Note: calling {@link #registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards()}
|
||||
* during <code>readObject</code> or <code>readResolve</code> is not possible because the object graph hasn't been fully
|
||||
* initialized yet when those methods are called. Hence, the structures for registering the score correction listeners
|
||||
* are not yet in place at that time.
|
||||
@@ -40,13 +40,12 @@ public class LeaderboardGroupMetaLeaderboard extends AbstractMetaLeaderboard imp
|
||||
super(leaderboardGroup.getName()+" "+LeaderboardNameConstants.OVERALL, scoringScheme, resultDiscardingRule);
|
||||
this.leaderboardGroup = leaderboardGroup;
|
||||
leaderboardGroup.addLeaderboardGroupListener(this);
|
||||
registerAsScoreCorrectionChangeForwarderOnAllLeaderboards();
|
||||
registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards();
|
||||
}
|
||||
|
||||
public void registerAsScoreCorrectionChangeForwarderOnAllLeaderboards() {
|
||||
public void registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards() {
|
||||
for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
|
||||
leaderboard.addRaceColumnListener(this);
|
||||
registerScoreCorrectionChangeForwarder(leaderboard);
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +56,7 @@ public class LeaderboardGroupMetaLeaderboard extends AbstractMetaLeaderboard imp
|
||||
|
||||
@Override
|
||||
public void leaderboardAdded(LeaderboardGroup group, Leaderboard leaderboard) {
|
||||
leaderboard.addRaceColumnListener(this);
|
||||
registerScoreCorrectionChangeForwarder(leaderboard);
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
|
||||
+10
-8
@@ -39,14 +39,6 @@ public class MetaLeaderboardColumn extends SimpleAbstractRaceColumn implements R
|
||||
return leaderboard.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRaceColumnListener(RaceColumnListener listener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRaceColumnListener(RaceColumnListener listener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<? extends Fleet> getFleets() {
|
||||
return Collections.singleton(metaFleet);
|
||||
@@ -129,6 +121,16 @@ public class MetaLeaderboardColumn extends SimpleAbstractRaceColumn implements R
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(raceColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceColumnMoved(RaceColumn raceColumn, int newIndex) {
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(raceColumn, newIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void factorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor) {
|
||||
getRaceColumnListeners().notifyListenersAboutFactorChanged(raceColumn, oldFactor, newFactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransient() {
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.sap.sailing.domain.tracking;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
|
||||
@@ -15,4 +16,6 @@ public interface Maneuver extends GPSFix {
|
||||
|
||||
double getDirectionChangeInDegrees();
|
||||
|
||||
Distance getManeuverLoss();
|
||||
|
||||
}
|
||||
+22
@@ -6,6 +6,7 @@ import java.util.List;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
@@ -13,6 +14,7 @@ import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.tracking.impl.TrackedLegImpl;
|
||||
|
||||
public interface TrackedLegOfCompetitor extends Serializable {
|
||||
Leg getLeg();
|
||||
@@ -169,6 +171,26 @@ public interface TrackedLegOfCompetitor extends Serializable {
|
||||
|
||||
Distance getAverageCrossTrackError(TimePoint timePoint, boolean waitForLatestAnalysis) throws NoWindException;
|
||||
|
||||
/**
|
||||
* If the current {@link #getLeg() leg} is +/- {@link TrackedLegImpl#UPWIND_DOWNWIND_TOLERANCE_IN_DEG} degrees
|
||||
* co-linear with the wind's bearing, the competitor's position is projected onto the line crossing
|
||||
* <code>buoy</code> in the wind's bearing, and the distance from the projection to the <code>buoy</code> is
|
||||
* returned. Otherwise, it is assumed that the leg is neither an upwind nor a downwind leg, and hence the along-track
|
||||
* distance to <code>buoy</code> is returned.
|
||||
*
|
||||
* @param at
|
||||
* the wind estimation is performed for this point in time
|
||||
*/
|
||||
Distance getWindwardDistance(Position pos1, Position pos2, TimePoint at) throws NoWindException;
|
||||
|
||||
/**
|
||||
* Computes the maneuver loss as the "windward distance" that the boat lost compared to not having maneuvered.
|
||||
* As defined by {@link TrackedLegOfCompetitor#getWindwardDistance(Position, Position, TimePoint)}, distances for
|
||||
* reaching legs are computed as the along-track distance. For upwind/downwind legs it's taken to be the
|
||||
* along-wind projection. With this distance measure, the competitors speed and bearing before the maneuver,
|
||||
* as defined by <code>timePointBeforeManeuver</code> is extrapolated until <code>timePointAfterManeuver</code>,
|
||||
* and the resulting extrapolated position's "windward distance" is computed to the competitor's actual position
|
||||
* at that time. This distance is returned as the result of this method.
|
||||
*/
|
||||
Distance getManeuverLoss(MillisecondsTimePoint timePointBeforeManeuver, MillisecondsTimePoint timePointAfterManeuver) throws NoWindException;
|
||||
}
|
||||
+1
-1
@@ -11,11 +11,11 @@ import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.base.Timed;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.LegType;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.tracking.GPSFix;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
|
||||
+14
-2
@@ -1,12 +1,17 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.tracking.Maneuver;
|
||||
|
||||
/**
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class ManeuverImpl extends AbstractGPSFixImpl implements Maneuver {
|
||||
private static final long serialVersionUID = -5317959066507472580L;
|
||||
private final ManeuverType type;
|
||||
@@ -16,9 +21,10 @@ public class ManeuverImpl extends AbstractGPSFixImpl implements Maneuver {
|
||||
private final SpeedWithBearing speedWithBearingBefore;
|
||||
private final SpeedWithBearing speedWithBearingAfter;
|
||||
private final double directionChangeInDegrees;
|
||||
private final Distance maneuverLoss;
|
||||
|
||||
public ManeuverImpl(ManeuverType type, Tack newTack, Position position, TimePoint timePoint, SpeedWithBearing speedWithBearingBefore,
|
||||
SpeedWithBearing speedWithBearingAfter, double directionChangeInDegrees) {
|
||||
SpeedWithBearing speedWithBearingAfter, double directionChangeInDegrees, Distance maneuverLoss) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.newTack = newTack;
|
||||
@@ -27,6 +33,7 @@ public class ManeuverImpl extends AbstractGPSFixImpl implements Maneuver {
|
||||
this.speedWithBearingBefore = speedWithBearingBefore;
|
||||
this.speedWithBearingAfter = speedWithBearingAfter;
|
||||
this.directionChangeInDegrees = directionChangeInDegrees;
|
||||
this.maneuverLoss = maneuverLoss;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,11 +71,16 @@ public class ManeuverImpl extends AbstractGPSFixImpl implements Maneuver {
|
||||
return newTack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getManeuverLoss() {
|
||||
return maneuverLoss;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " " + type + " on new tack " + newTack + " on position " + position
|
||||
+ " at time point " + timePoint + ". " + "Speed before maneuver " + speedWithBearingBefore
|
||||
+ " speed after maneuver " + speedWithBearingAfter + ". The maneuver changed the course by "
|
||||
+ directionChangeInDegrees + "deg.";
|
||||
+ directionChangeInDegrees + "deg." + (getManeuverLoss() == null ? "" : " Lost approximately "+getManeuverLoss());
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -35,7 +35,7 @@ public class TrackedLegImpl implements TrackedLeg, RaceChangeListener {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(TrackedLegImpl.class.getName());
|
||||
|
||||
private final static double UPWIND_DOWNWIND_TOLERANCE_IN_DEG = 45; // TracTrac does 22.5, Marcus Baur suggest 40; Nils Schröder suggests 60
|
||||
private final static double UPWIND_DOWNWIND_TOLERANCE_IN_DEG = 45; // TracTrac does 22.5, Marcus Baur suggest 40; Nils Schr�der suggests 60
|
||||
|
||||
private final Leg leg;
|
||||
private final Map<Competitor, TrackedLegOfCompetitor> trackedLegsOfCompetitors;
|
||||
@@ -135,7 +135,8 @@ public class TrackedLegImpl implements TrackedLeg, RaceChangeListener {
|
||||
public LegType getLegType(TimePoint at) throws NoWindException {
|
||||
Wind wind = getWindOnLeg(at);
|
||||
if (wind == null) {
|
||||
throw new NoWindException("Need to know wind direction to determine whether leg "+getLeg()+
|
||||
throw new NoWindException("Need to know wind direction in race "+getTrackedRace().getRace().getName()+
|
||||
" to determine whether leg "+getLeg()+
|
||||
" is an upwind or downwind leg");
|
||||
}
|
||||
Bearing legBearing = getLegBearing(at);
|
||||
|
||||
+37
-3
@@ -8,7 +8,7 @@ import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Leg;
|
||||
import com.sap.sailing.domain.base.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
|
||||
import com.sap.sailing.domain.base.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
import com.sap.sailing.domain.common.Distance;
|
||||
import com.sap.sailing.domain.common.ManeuverType;
|
||||
@@ -16,6 +16,7 @@ import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.common.Position;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.MeterDistance;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.domain.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.tracking.GPSFixTrack;
|
||||
@@ -196,10 +197,10 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current {@link #getLeg() leg} is +/- {@link #UPWIND_DOWNWIND_TOLERANCE_IN_DEG} degrees collinear with the
|
||||
* If the current {@link #getLeg() leg} is +/- {@link TrackedLegImpl#UPWIND_DOWNWIND_TOLERANCE_IN_DEG} degrees collinear with the
|
||||
* wind's bearing, the competitor's position is projected onto the line crossing <code>buoy</code> in the wind's
|
||||
* bearing, and the distance from the projection to the <code>buoy</code> is returned. Otherwise, it is assumed that
|
||||
* the leg is neither an upwind nor a downwind leg, and hence the true distance to <code>buoy</code> is returned.
|
||||
* the leg is neither an upwind nor a downwind leg, and hence the along-track distance to <code>buoy</code> is returned.
|
||||
*
|
||||
* @param at the wind estimation is performed for this point in time
|
||||
*/
|
||||
@@ -578,4 +579,37 @@ public class TrackedLegOfCompetitorImpl implements TrackedLegOfCompetitor {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Distance getManeuverLoss(MillisecondsTimePoint timePointBeforeManeuver,
|
||||
MillisecondsTimePoint timePointAfterManeuver) throws NoWindException {
|
||||
assert timePointBeforeManeuver != null;
|
||||
assert timePointAfterManeuver != null;
|
||||
Distance result;
|
||||
long millisecondsOverWhichToAverageSpeed = getTrackedRace().getMillisecondsOverWhichToAverageSpeed();
|
||||
TimePoint extrapolationBase = timePointBeforeManeuver.minus(millisecondsOverWhichToAverageSpeed/2);
|
||||
final GPSFixTrack<Competitor, GPSFixMoving> track = getTrackedRace().getTrack(getCompetitor());
|
||||
Position estimatedPositionAtBase = track.getEstimatedPosition(extrapolationBase, /* extrapolate */ false);
|
||||
if (estimatedPositionAtBase != null) {
|
||||
SpeedWithBearing estimatedSpeedAtBase = track.getEstimatedSpeed(extrapolationBase);
|
||||
if (estimatedSpeedAtBase != null) {
|
||||
TimePoint extrapolationTarget = timePointAfterManeuver.plus(millisecondsOverWhichToAverageSpeed / 2);
|
||||
Position extrapolatedPositionWithoutManeuver = estimatedSpeedAtBase.travelTo(estimatedPositionAtBase,
|
||||
extrapolationBase, extrapolationTarget);
|
||||
Position estimatedActualPositionAfterManeuver = track.getEstimatedPosition(extrapolationTarget, /* extrapolate */
|
||||
false);
|
||||
if (estimatedActualPositionAfterManeuver != null) {
|
||||
result = getWindwardDistance(estimatedActualPositionAfterManeuver, extrapolatedPositionWithoutManeuver,
|
||||
new MillisecondsTimePoint((timePointBeforeManeuver.asMillis() + timePointAfterManeuver.asMillis())/2));
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+20
-12
@@ -92,7 +92,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TrackedRaceImpl.class.getName());
|
||||
|
||||
private static final double PENALTY_CIRCLE_DEGREES_THRESHOLD = 320;
|
||||
private static final double PENALTY_CIRCLE_DEGREES_THRESHOLD = 270;
|
||||
|
||||
// TODO make this variable
|
||||
private static final long DELAY_FOR_CACHE_CLEARING_IN_MILLISECONDS = 7500;
|
||||
@@ -1402,6 +1402,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
toRemove = last;
|
||||
}
|
||||
if (toRemove != null) {
|
||||
logger.info("Removing tracked leg starting at "+toRemove.getFrom()+" from tracked race "+getRace().getName());
|
||||
trackedLegs.remove(toRemove);
|
||||
updated(/* time point */null);
|
||||
}
|
||||
@@ -1846,11 +1847,8 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
List<Pair<GPSFixMoving, CourseChange>> group = new ArrayList<Pair<GPSFixMoving, CourseChange>>();
|
||||
if (!courseChangeSequenceInSameDirection.isEmpty()) {
|
||||
Distance twoHullLengths = competitor.getBoat().getBoatClass().getHullLength().scale(2);
|
||||
SpeedWithBearing beforeGroupOnApproximation = speedWithBearingOnApproximationAtBeginning; // speed/bearing
|
||||
// before group
|
||||
SpeedWithBearing beforeCurrentCourseChangeOnApproximation = beforeGroupOnApproximation; // speed/bearing
|
||||
// before current
|
||||
// course change
|
||||
SpeedWithBearing beforeGroupOnApproximation = speedWithBearingOnApproximationAtBeginning; // speed/bearing before group
|
||||
SpeedWithBearing beforeCurrentCourseChangeOnApproximation = beforeGroupOnApproximation; // speed/bearing before current course change
|
||||
Iterator<Pair<GPSFixMoving, CourseChange>> iter = courseChangeSequenceInSameDirection.iterator();
|
||||
double totalCourseChangeInDegrees = 0.0;
|
||||
long totalMilliseconds = 0l;
|
||||
@@ -1909,17 +1907,21 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
Tack tackAfterManeuver = getTack(maneuverPosition, timePointAfterManeuver,
|
||||
speedWithBearingOnApproximationAtEnd.getBearing());
|
||||
ManeuverType maneuverType;
|
||||
Distance maneuverLoss = null;
|
||||
// the TrackedLegOfCompetitor variables may be null, e.g., in case the time points are before or after the race
|
||||
TrackedLegOfCompetitor legBeforeManeuver = getTrackedLeg(competitor, timePointBeforeManeuver);
|
||||
TrackedLegOfCompetitor legAfterManeuver = getTrackedLeg(competitor, timePointAfterManeuver);
|
||||
if (Math.abs(totalCourseChangeInDegrees) > PENALTY_CIRCLE_DEGREES_THRESHOLD) {
|
||||
maneuverType = ManeuverType.PENALTY_CIRCLE;
|
||||
} else if (legBeforeManeuver != legAfterManeuver
|
||||
&&
|
||||
// check for mask passing first; a tacking / jibe-setting mark rounding thus takes precedence over being detected as a penalty circle
|
||||
if (legBeforeManeuver != legAfterManeuver
|
||||
// a maneuver at the start line is not to be considered a MARK_PASSING maneuver; show a tack as a tack
|
||||
legAfterManeuver != null
|
||||
&& legAfterManeuver != null
|
||||
&& legAfterManeuver.getLeg().getFrom() != getRace().getCourse().getFirstWaypoint()) {
|
||||
maneuverType = ManeuverType.MARK_PASSING;
|
||||
} else if (Math.abs(totalCourseChangeInDegrees) > PENALTY_CIRCLE_DEGREES_THRESHOLD) {
|
||||
maneuverType = ManeuverType.PENALTY_CIRCLE;
|
||||
if (legBeforeManeuver != null) {
|
||||
maneuverLoss = legBeforeManeuver.getManeuverLoss(timePointBeforeManeuver, timePointAfterManeuver);
|
||||
}
|
||||
} else {
|
||||
if (tackBeforeManeuver != tackAfterManeuver) {
|
||||
LegType legType = legBeforeManeuver != null ? getTrackedLeg(legBeforeManeuver.getLeg()).getLegType(
|
||||
@@ -1930,9 +1932,15 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
switch (legType) {
|
||||
case UPWIND:
|
||||
maneuverType = ManeuverType.TACK;
|
||||
if (legBeforeManeuver != null) {
|
||||
maneuverLoss = legBeforeManeuver.getManeuverLoss(timePointBeforeManeuver, timePointAfterManeuver);
|
||||
}
|
||||
break;
|
||||
case DOWNWIND:
|
||||
maneuverType = ManeuverType.JIBE;
|
||||
if (legBeforeManeuver != null) {
|
||||
maneuverLoss = legBeforeManeuver.getManeuverLoss(timePointBeforeManeuver, timePointAfterManeuver);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
maneuverType = ManeuverType.UNKNOWN;
|
||||
@@ -1963,7 +1971,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
}
|
||||
Maneuver maneuver = new ManeuverImpl(maneuverType, tackAfterManeuver, maneuverPosition, maneuverTimePoint,
|
||||
speedWithBearingOnApproximationAtBeginning, speedWithBearingOnApproximationAtEnd,
|
||||
totalCourseChangeInDegrees);
|
||||
totalCourseChangeInDegrees, maneuverLoss);
|
||||
return maneuver;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,12 @@ public class RaceColumnListeners implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyListenersAboutFactorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor) {
|
||||
for (RaceColumnListener listener : getRaceColumnListeners()) {
|
||||
listener.factorChanged(raceColumn, oldFactor, newFactor);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyListenersAboutIsMedalRaceChanged(RaceColumn raceColumn, boolean newIsMedalRace) {
|
||||
for (RaceColumnListener listener : getRaceColumnListeners()) {
|
||||
listener.isMedalRaceChanged(raceColumn, newIsMedalRace);
|
||||
@@ -87,6 +93,12 @@ public class RaceColumnListeners implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyListenersAboutRaceColumnMoved(RaceColumn raceColumn, int newIndex) {
|
||||
for (RaceColumnListener listener : getRaceColumnListeners()) {
|
||||
listener.raceColumnMoved(raceColumn, newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<RaceColumnListener> getRaceColumnListeners() {
|
||||
synchronized (raceColumnListeners) {
|
||||
return new HashSet<RaceColumnListener>(raceColumnListeners);
|
||||
@@ -103,4 +115,5 @@ public class RaceColumnListeners implements Serializable {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,9 +17,26 @@ import com.sap.sailing.util.impl.SmartFutureCache.UpdateInterval;
|
||||
* A cache for which a background update can be triggered. Readers can decide whether they want to wait for any ongoing
|
||||
* background update or read the latest cached value for a key. An update trigger can provide an optional parameter for
|
||||
* the update which may, e.g., control the interval of the cached value to update. When an update is triggered and
|
||||
* another update is already running, the update is queued. If there already is an update queued for the same key,
|
||||
* the optional update parameters are "joined" (for example, the two update intervals are joined to form one interval
|
||||
* which incorporates both original update intervals).
|
||||
* another update is already running, the update is queued. If there already is an update queued for the same key, the
|
||||
* optional update parameters are "joined" (for example, the two update intervals are joined to form one interval which
|
||||
* incorporates both original update intervals).
|
||||
* <p>
|
||||
*
|
||||
* A {@link CacheUpdater} needs to be passed to the constructor which carries out the actual calculation whose values
|
||||
* are to be cached. The {@link CacheUpdater} interface assumes that a cache update may be computed in two steps: first,
|
||||
* a value is computed for a key and an update interval which may be computationally expensive. Then, in a second step,
|
||||
* the new value is combined with the previous cache value for the same key and update interval. The default
|
||||
* implementation of {@link CacheUpdater#provideNewCacheValue(Object, Object, Object, UpdateInterval)} simply returns
|
||||
* the <code>computedCacheUpdate</code> parameter which is the result computed by
|
||||
* {@link CacheUpdater#computeCacheUpdate(Object, UpdateInterval)} before.
|
||||
*
|
||||
* @param <K>
|
||||
* the key type for which values of type <code>V</code> are cached
|
||||
* @param <V>
|
||||
* the value type of which instances are cached for particular keys of type <code>K</code>
|
||||
* @param <U>
|
||||
* a parameter type for the cache update method for a single key, such that the parameters of multiple queued
|
||||
* requests for the same key can be joined into one for a faster update
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
@@ -85,7 +102,7 @@ public class SmartFutureCache<K, V, U extends UpdateInterval<U>> {
|
||||
V computeCacheUpdate(K key, U updateInterval) throws Exception;
|
||||
|
||||
/**
|
||||
* Expected to deliver an updated cache value quick (compared to the potentially much more expensive
|
||||
* Expected to deliver an updated cache value quickly (compared to the potentially much more expensive
|
||||
* {@link #computeCacheUpdate(Object, UpdateInterval)} method which is run in a background task and doesn't lock
|
||||
* the cache for readers).
|
||||
*
|
||||
@@ -220,6 +237,12 @@ public class SmartFutureCache<K, V, U extends UpdateInterval<U>> {
|
||||
recalculator.execute(future);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a value for <code>key</code> from the cache. If no {@link #triggerUpdate(Object, UpdateInterval)} for the <code>key</code>
|
||||
* has ever happened, <code>null</code> will be returned. Otherwise, depending on <code>waitForLatest</code> the result is taken
|
||||
* from the cache straight away (<code>waitForLatest==false</code>) or, if a re-calculation for the <code>key</code> is still
|
||||
* ongoing, the result of that ongoing re-calculation is returned.
|
||||
*/
|
||||
public V get(K key, boolean waitForLatest) {
|
||||
V value = null;
|
||||
if (waitForLatest) {
|
||||
|
||||
+6
-6
@@ -53,9 +53,9 @@ public class TestColumnSwapping {
|
||||
try {
|
||||
// get Leaderboard with name and current date
|
||||
leaderboardOriginalDTO = new LeaderboardDTO(null, null, /* higherScoreIsBetter */ false);
|
||||
leaderboardOriginalDTO.addRace("Race1", DEFAULT_FLEET, true, null, null);
|
||||
leaderboardOriginalDTO.addRace("Race3", DEFAULT_FLEET, true, null, null);
|
||||
leaderboardOriginalDTO.addRace("Race2", DEFAULT_FLEET, true, null, null);
|
||||
leaderboardOriginalDTO.addRace("Race1", /* explicitFactor */ null, DEFAULT_FLEET, true, null, null);
|
||||
leaderboardOriginalDTO.addRace("Race3", /* explicitFactor */ null, DEFAULT_FLEET, true, null, null);
|
||||
leaderboardOriginalDTO.addRace("Race2", /* explicitFactor */ null, DEFAULT_FLEET, true, null, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -104,9 +104,9 @@ public class TestColumnSwapping {
|
||||
public void testLeaderBoardDTOMethods() {
|
||||
lb = new LeaderboardDTO(null, null, /* higherScoreIsBetter */ false);
|
||||
assertNotNull("Leaderboard != NULL", lb);
|
||||
lb.addRace("1", DEFAULT_FLEET, false, null, null);
|
||||
lb.addRace("2", DEFAULT_FLEET, false, null, null);
|
||||
lb.addRace("3", DEFAULT_FLEET, true, null, null);
|
||||
lb.addRace("1", /* explicitFactor */ null, DEFAULT_FLEET, false, null, null);
|
||||
lb.addRace("2", /* explicitFactor */ null, DEFAULT_FLEET, false, null, null);
|
||||
lb.addRace("3", /* explicitFactor */ null, DEFAULT_FLEET, true, null, null);
|
||||
lb.moveRaceDown("1");
|
||||
String[] s = new String[] { "2", "1", "3" };
|
||||
for (int i = 0; i < lb.getRaceList().size(); i++)
|
||||
|
||||
@@ -186,7 +186,7 @@ body ::-webkit-scrollbar-track {
|
||||
|
||||
.subTitleLabelWrapper {
|
||||
position: absolute;
|
||||
min-width: 400px;
|
||||
min-width: 200px;
|
||||
text-align: right;
|
||||
height: 68px;
|
||||
right: 0;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<stringAttribute key="com.google.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.GWTShell"/>
|
||||
<booleanAttribute key="com.google.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/>
|
||||
<listAttribute key="com.google.gwt.eclipse.core.ENTRY_POINT_MODULES">
|
||||
<listEntry value="com.sap.sailing.gwt.ui.RaceBoard"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.TvView"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/AdminConsole.html"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
@@ -19,7 +19,7 @@
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.google.gwt.eclipse.core.moduleClasspathProvider"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/UserManagement.html com.sap.sailing.gwt.ui.UserManagement -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9997 -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/UserManagement.html com.sap.sailing.gwt.ui.UserManagement -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/TvView.html com.sap.sailing.gwt.ui.TvView"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -XX:MaxPermSize=512m"/>
|
||||
</launchConfiguration>
|
||||
@@ -0,0 +1,33 @@
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<title>SAP Sailing Analytics TV View</title>
|
||||
<meta content='width = device-width, initial-scale = 1.0, user-scalable = yes' name='viewport'>
|
||||
<meta content='yes' name='apple-mobile-web-app-capable'>
|
||||
<meta content='black' name='apple-mobile-web-app-status-bar-style'>
|
||||
<!-- <link href='iphone-splash-screen.png' rel='apple-touch-startup-image'> -->
|
||||
<link href='images/sap-sailing-app-icon.png' rel='apple-touch-icon'>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/sap.ico" />
|
||||
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="highcharts/js/highcharts.js"></script>
|
||||
|
||||
<!-- Optionally, add a highcharts theme file -->
|
||||
<script type="text/javascript" src="highcharts/js/themes/grid.js"></script>
|
||||
|
||||
<script type="text/javascript" language="javascript" src="com.sap.sailing.gwt.ui.TvView/com.sap.sailing.gwt.ui.TvView.nocache.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
|
||||
<!-- RECOMMENDED if your web app will not function without JavaScript enabled -->
|
||||
<noscript>
|
||||
<div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
|
||||
Your web browser must have JavaScript enabled
|
||||
in order for this application to display correctly.
|
||||
</div>
|
||||
</noscript>
|
||||
</body>
|
||||
</html>
|
||||
@@ -28,5 +28,7 @@ bin.includes = META-INF/,\
|
||||
highcharts/,\
|
||||
Spectator.css,\
|
||||
fontface.css,\
|
||||
webfonts/
|
||||
webfonts/,\
|
||||
TvView.html,\
|
||||
com.sap.sailing.gwt.ui.TvView/
|
||||
output.. = WEB-INF/classes/
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 19 KiB |
@@ -50,6 +50,7 @@
|
||||
<module>com.sap.sailing.gwt.ui.AdminConsole</module>
|
||||
<module>com.sap.sailing.gwt.ui.Leaderboard</module>
|
||||
<module>com.sap.sailing.gwt.ui.UserManagement</module>
|
||||
<module>com.sap.sailing.gwt.ui.TvView</module>
|
||||
</modules>
|
||||
<gen>${basedir}/.generated</gen>
|
||||
<localWorkers>3</localWorkers>
|
||||
|
||||
+3
@@ -8,6 +8,9 @@ interface AdminConsoleResources extends ClientBundle {
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/settings.png")
|
||||
ImageResource settingsIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/settingsActionIcon.png")
|
||||
ImageResource settingsActionIcon();
|
||||
|
||||
@Source("com/sap/sailing/gwt/ui/client/images/remove.png")
|
||||
ImageResource removeIcon();
|
||||
|
||||
|
||||
+80
-13
@@ -1,21 +1,66 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import com.google.gwt.cell.client.AbstractSafeHtmlCell;
|
||||
import com.google.gwt.cell.client.FieldUpdater;
|
||||
import com.google.gwt.cell.client.ValueUpdater;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.dom.client.EventTarget;
|
||||
import com.google.gwt.dom.client.NativeEvent;
|
||||
import com.google.gwt.resources.client.ImageResource;
|
||||
import com.google.gwt.safecss.shared.SafeStyles;
|
||||
import com.google.gwt.safecss.shared.SafeStylesUtils;
|
||||
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
|
||||
import com.google.gwt.safehtml.shared.SafeHtml;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.text.shared.SafeHtmlRenderer;
|
||||
import com.google.gwt.text.shared.SimpleSafeHtmlRenderer;
|
||||
import com.google.gwt.user.cellview.client.CellTable;
|
||||
import com.google.gwt.user.client.ui.AbstractImagePrototype;
|
||||
|
||||
/**
|
||||
* A cell type for use in a {@link CellTable} which renders a horizontal sequence of images. Use by subclassing and
|
||||
* overriding the {@link #getImageSpecs()} method where action name, tool tip and image prototype can be provided for
|
||||
* each image to be rendered. Add a {@link FieldUpdater} to the column rendered using this cell type; the updater will
|
||||
* receive the clicked image's action name as the <code>value</code> parameter. The image rendering style can be adjusted by
|
||||
* overriding the default {@link #getImageStyle()} implementation.
|
||||
*/
|
||||
public abstract class ImagesBarCell extends AbstractSafeHtmlCell<String> {
|
||||
/**
|
||||
* Subclasses use this template to render a single image tag
|
||||
*/
|
||||
private final static ImagesBarTemplates imageTemplate = GWT.create(ImagesBarTemplates.class);
|
||||
|
||||
protected class ImageSpec {
|
||||
private final AbstractImagePrototype imagePrototype;
|
||||
private final String actionName;
|
||||
private final String tooltip;
|
||||
public ImageSpec(String actionName, String tooltip, AbstractImagePrototype imagePrototype) {
|
||||
super();
|
||||
this.imagePrototype = imagePrototype;
|
||||
this.actionName = actionName;
|
||||
this.tooltip = tooltip;
|
||||
}
|
||||
public AbstractImagePrototype getImagePrototype() {
|
||||
return imagePrototype;
|
||||
}
|
||||
public String getActionName() {
|
||||
return actionName;
|
||||
}
|
||||
public String getTooltip() {
|
||||
return tooltip;
|
||||
}
|
||||
}
|
||||
|
||||
interface ImagesBarTemplates extends SafeHtmlTemplates {
|
||||
/**
|
||||
* @param name
|
||||
* @param title
|
||||
* the tool-tip to display for the image on mouse-over
|
||||
* @param value
|
||||
* how to render the image; this needs to be an <img> tag, not enclosed by any other element,
|
||||
* as returned by {@link ImagesBarCell#makeImagePrototype(ImageResource)}
|
||||
*/
|
||||
@SafeHtmlTemplates.Template("<div name=\"{0}\" style=\"{1}\" title=\"{2}\">{3}</div>")
|
||||
SafeHtml cell(String name, SafeStyles styles, String title, SafeHtml value);
|
||||
}
|
||||
@@ -28,6 +73,10 @@ public abstract class ImagesBarCell extends AbstractSafeHtmlCell<String> {
|
||||
super(renderer, "click", "keydown");
|
||||
}
|
||||
|
||||
protected static ImagesBarTemplates getImageTemplate() {
|
||||
return imageTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an event occurs in a rendered instance of this Cell. The
|
||||
* parent element refers to the element that contains the rendered cell, NOT
|
||||
@@ -42,26 +91,22 @@ public abstract class ImagesBarCell extends AbstractSafeHtmlCell<String> {
|
||||
if ("click".equals(event.getType())) {
|
||||
// Ignore clicks that occur outside of the outermost element.
|
||||
EventTarget eventTarget = event.getEventTarget();
|
||||
|
||||
if (parent.isOrHasChild(Element.as(eventTarget))) {
|
||||
|
||||
// if (parent.getFirstChildElement().isOrHasChild(
|
||||
// Element.as(eventTarget))) {
|
||||
// use this to get the selected element!!
|
||||
Element el = Element.as(eventTarget);
|
||||
|
||||
// check if we really click on the image
|
||||
if (el.getNodeName().equalsIgnoreCase("IMG")) {
|
||||
doAction(el.getParentElement().getAttribute("name"), valueUpdater);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* onEnterKeyDown is called when the user presses the ENTER key will the
|
||||
* Cell is selected. You are not required to override this method, but its a
|
||||
* common convention that allows your cell to respond to key events.
|
||||
* onEnterKeyDown is called when the user presses the ENTER key while the Cell is selected. You are not required to
|
||||
* override this method, but it is a common convention that allows your cell to respond to key events.
|
||||
*/
|
||||
@Override
|
||||
protected void onEnterKeyDown(Context context, Element parent,
|
||||
@@ -80,16 +125,38 @@ public abstract class ImagesBarCell extends AbstractSafeHtmlCell<String> {
|
||||
// Trigger a value updater. In this case, the value doesn't actually
|
||||
// change, but we use a ValueUpdater to let the app know that a value
|
||||
// was clicked.
|
||||
if (valueUpdater != null)
|
||||
if (valueUpdater != null) {
|
||||
valueUpdater.update(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make icons available as SafeHtml
|
||||
* @param resource
|
||||
* @return
|
||||
* Make icons available as image prototype
|
||||
*/
|
||||
protected static SafeHtml makeImage(ImageResource resource) {
|
||||
return AbstractImagePrototype.create(resource).getSafeHtml();
|
||||
protected static AbstractImagePrototype makeImagePrototype(ImageResource resource) {
|
||||
return AbstractImagePrototype.create(resource);
|
||||
}
|
||||
|
||||
protected abstract Iterable<ImageSpec> getImageSpecs();
|
||||
|
||||
@Override
|
||||
protected void render(com.google.gwt.cell.client.Cell.Context context, SafeHtml data, SafeHtmlBuilder sb) {
|
||||
/*
|
||||
* Always do a null check on the value. Cell widgets can pass null to
|
||||
* cells if the underlying data contains a null, or if the data arrives
|
||||
* out of order.
|
||||
*/
|
||||
if (data != null) {
|
||||
SafeStyles imgStyle = getImageStyle();
|
||||
for (ImageSpec imageSpec : getImageSpecs()) {
|
||||
SafeHtml rendered = getImageTemplate().cell(imageSpec.getActionName(), imgStyle, imageSpec.getTooltip(),
|
||||
imageSpec.getImagePrototype().getSafeHtml());
|
||||
sb.append(rendered);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected SafeStyles getImageStyle() {
|
||||
return SafeStylesUtils.fromTrustedString("float:left;cursor:hand;cursor:pointer;padding-right:5px;");
|
||||
}
|
||||
}
|
||||
+16
-39
@@ -1,57 +1,34 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.safecss.shared.SafeStyles;
|
||||
import com.google.gwt.safecss.shared.SafeStylesUtils;
|
||||
import com.google.gwt.safehtml.shared.SafeHtml;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.text.shared.SafeHtmlRenderer;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
public class LeaderboardConfigImagesBarCell extends ImagesBarCell {
|
||||
public static final String ACTION_REMOVE = "ACTION_REMOVE";
|
||||
public static final String ACTION_EDIT_SCORES = "ACTION_EDIT_SCORES";
|
||||
public static final String ACTION_EDIT = "ACTION_EDIT";
|
||||
public static final String ACTION_CONFIGURE_URL = "ACTION_CONFIGURE_URL";
|
||||
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
public LeaderboardConfigImagesBarCell(StringMessages stringConstants) {
|
||||
public LeaderboardConfigImagesBarCell(StringMessages stringMessages) {
|
||||
super();
|
||||
this.stringConstants = stringConstants;
|
||||
this.stringMessages = stringMessages;
|
||||
}
|
||||
|
||||
public LeaderboardConfigImagesBarCell(SafeHtmlRenderer<String> renderer, StringMessages stringConstants) {
|
||||
super();
|
||||
this.stringConstants = stringConstants;
|
||||
this.stringMessages = stringConstants;
|
||||
}
|
||||
|
||||
private static ImagesBarTemplates templates = GWT.create(ImagesBarTemplates.class);
|
||||
|
||||
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
|
||||
private static final SafeHtml ICON_EDIT = makeImage(resources.editIcon());
|
||||
|
||||
private static final SafeHtml ICON_REMOVE = makeImage(resources.removeIcon());
|
||||
|
||||
private static final SafeHtml ICON_EDIT_SCORES = makeImage(resources.scoresIcon());
|
||||
|
||||
private StringMessages stringConstants;
|
||||
|
||||
@Override
|
||||
protected void render(com.google.gwt.cell.client.Cell.Context context, SafeHtml data, SafeHtmlBuilder sb) {
|
||||
/*
|
||||
* Always do a null check on the value. Cell widgets can pass null to
|
||||
* cells if the underlying data contains a null, or if the data arrives
|
||||
* out of order.
|
||||
*/
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
SafeStyles imgStyle = SafeStylesUtils.fromTrustedString("float:left;cursor:hand;cursor:pointer;padding-right:5px;");
|
||||
|
||||
SafeHtml rendered = templates.cell("ACTION_EDIT", imgStyle, stringConstants.actionEdit(), ICON_EDIT);
|
||||
sb.append(rendered);
|
||||
|
||||
rendered = templates.cell("ACTION_EDIT_SCORES", imgStyle, stringConstants.actionEditScores(), ICON_EDIT_SCORES);
|
||||
sb.append(rendered);
|
||||
|
||||
rendered = templates.cell("ACTION_REMOVE", imgStyle, stringConstants.actionRemove(), ICON_REMOVE);
|
||||
sb.append(rendered);
|
||||
protected Iterable<ImageSpec> getImageSpecs() {
|
||||
return Arrays.asList(new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(resources.editIcon())),
|
||||
new ImageSpec(ACTION_EDIT_SCORES, stringMessages.actionEditScores(), makeImagePrototype(resources.scoresIcon())),
|
||||
new ImageSpec(ACTION_CONFIGURE_URL, stringMessages.actionConfigureUrl(), makeImagePrototype(resources.settingsActionIcon())),
|
||||
new ImageSpec(ACTION_REMOVE, stringMessages.actionRemove(), makeImagePrototype(resources.removeIcon())));
|
||||
}
|
||||
}
|
||||
+63
-21
@@ -47,6 +47,7 @@ import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaName;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.RaceColumnInLeaderboardDialog.RaceColumnDescriptor;
|
||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.ParallelExecutionCallback;
|
||||
@@ -58,7 +59,9 @@ import com.sap.sailing.gwt.ui.client.RegattaDisplayer;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.URLFactory;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardEntryPoint;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter;
|
||||
import com.sap.sailing.gwt.ui.shared.AbstractLeaderboardDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.FleetDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
|
||||
@@ -231,11 +234,11 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
|
||||
leaderboardActionColumn.setFieldUpdater(new FieldUpdater<StrippedLeaderboardDTO, String>() {
|
||||
@Override
|
||||
public void update(int index, StrippedLeaderboardDTO leaderboardDTO, String value) {
|
||||
if ("ACTION_REMOVE".equals(value)) {
|
||||
if (LeaderboardConfigImagesBarCell.ACTION_REMOVE.equals(value)) {
|
||||
if (Window.confirm("Do you really want to remove the leaderboard: '" + leaderboardDTO.name + "' ?")) {
|
||||
removeLeaderboard(leaderboardDTO);
|
||||
}
|
||||
} else if ("ACTION_EDIT".equals(value)) {
|
||||
} else if (LeaderboardConfigImagesBarCell.ACTION_EDIT.equals(value)) {
|
||||
final String oldLeaderboardName = leaderboardDTO.name;
|
||||
List<StrippedLeaderboardDTO> otherExistingLeaderboard = new ArrayList<StrippedLeaderboardDTO>();
|
||||
otherExistingLeaderboard.addAll(availableLeaderboardList);
|
||||
@@ -278,10 +281,12 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
} else if ("ACTION_EDIT_SCORES".equals(value)) {
|
||||
} else if (LeaderboardConfigImagesBarCell.ACTION_EDIT_SCORES.equals(value)) {
|
||||
String debugParam = Window.Location.getParameter("gwt.codesvr");
|
||||
Window.open("/gwt/LeaderboardEditing.html?name=" + leaderboardDTO.name
|
||||
+ (debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr=" + debugParam : ""), "_blank", null);
|
||||
} else if (LeaderboardConfigImagesBarCell.ACTION_CONFIGURE_URL.equals(value)) {
|
||||
openLeaderboardUrlConfigDialog(leaderboardDTO, stringMessages);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -382,6 +387,12 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
|
||||
return object.getB().name;
|
||||
}
|
||||
};
|
||||
TextColumn<Pair<RaceColumnDTO, FleetDTO>> explicitFactorColumn = new TextColumn<Pair<RaceColumnDTO, FleetDTO>>() {
|
||||
@Override
|
||||
public String getValue(Pair<RaceColumnDTO, FleetDTO> object) {
|
||||
return object.getA().getExplicitFactor() == null ? "" : object.getA().getExplicitFactor().toString();
|
||||
}
|
||||
};
|
||||
|
||||
Column<Pair<RaceColumnDTO, FleetDTO>, Boolean> isMedalRaceCheckboxColumn = new Column<Pair<RaceColumnDTO, FleetDTO>, Boolean>(
|
||||
new CheckboxCell()) {
|
||||
@@ -411,39 +422,35 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
|
||||
raceActionColumn.setFieldUpdater(new FieldUpdater<Pair<RaceColumnDTO, FleetDTO>, String>() {
|
||||
@Override
|
||||
public void update(int index, Pair<RaceColumnDTO, FleetDTO> object, String value) {
|
||||
if ("ACTION_REMOVE".equals(value)) {
|
||||
if (LeaderboardRaceConfigImagesBarCell.ACTION_REMOVE.equals(value)) {
|
||||
if (Window.confirm(stringMessages.reallyRemoveRace(object.getA().getRaceColumnName()))) {
|
||||
removeRaceColumn(object.getA());
|
||||
}
|
||||
} else if ("ACTION_EDIT".equals(value)) {
|
||||
} else if (LeaderboardRaceConfigImagesBarCell.ACTION_EDIT.equals(value)) {
|
||||
editRaceColumnOfLeaderboard(object);
|
||||
} else if ("ACTION_UNLINK".equals(value)) {
|
||||
} else if (LeaderboardRaceConfigImagesBarCell.ACTION_UNLINK.equals(value)) {
|
||||
unlinkRaceColumnFromTrackedRace(object.getA().getRaceColumnName(), object.getB());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Label lblRaceNamesIn = new Label(stringMessages.races());
|
||||
vPanel.add(lblRaceNamesIn);
|
||||
|
||||
raceColumnTable = new CellTable<Pair<RaceColumnDTO, FleetDTO>>(/* pageSize */200, tableRes);
|
||||
raceColumnTable.addColumn(raceLinkColumn, stringMessages.name());
|
||||
raceColumnTable.addColumn(fleetNameColumn, stringMessages.fleet());
|
||||
raceColumnTable.addColumn(isMedalRaceCheckboxColumn, stringMessages.medalRace());
|
||||
raceColumnTable.addColumn(isLinkedRaceColumn, stringMessages.islinked());
|
||||
raceColumnTable.addColumn(explicitFactorColumn, stringMessages.factor());
|
||||
raceColumnTable.addColumn(raceActionColumn, stringMessages.actions());
|
||||
raceColumnAndFleetList.addDataDisplay(raceColumnTable);
|
||||
raceColumnTable.setWidth("500px");
|
||||
raceColumnTableSelectionModel = new SingleSelectionModel<Pair<RaceColumnDTO, FleetDTO>>();
|
||||
|
||||
raceColumnTable.setSelectionModel(raceColumnTableSelectionModel);
|
||||
|
||||
raceColumnTableSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
|
||||
public void onSelectionChange(SelectionChangeEvent event) {
|
||||
leaderboardRaceColumnSelectionChanged();
|
||||
}
|
||||
});
|
||||
|
||||
vPanel.add(raceColumnTable);
|
||||
|
||||
HorizontalPanel selectedLeaderboardRaceButtonPanel = new HorizontalPanel();
|
||||
@@ -483,6 +490,16 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
|
||||
loadAndRefreshLeaderboards();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the user to combine the various URL parameters that exist for the {@link LeaderboardEntryPoint} and obtain the
|
||||
* resulting URL in a link. The link's reference target is updated dynamically as the user adjusts the settings. Therefore,
|
||||
* the link can be clicked, bookmarked or copied to the clipboard at any time. The OK / Cancel actions for the dialog shown
|
||||
* are no-ops.
|
||||
*/
|
||||
private void openLeaderboardUrlConfigDialog(AbstractLeaderboardDTO leaderboard, StringMessages stringMessages) {
|
||||
LeaderboardEntryPoint.getUrlConfigurationDialog(leaderboard, stringMessages).show();
|
||||
}
|
||||
|
||||
public void loadAndRefreshLeaderboards() {
|
||||
sailingService.getLeaderboards(new AsyncCallback<List<StrippedLeaderboardDTO>>() {
|
||||
@Override
|
||||
@@ -687,27 +704,43 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
|
||||
|
||||
private void editRaceColumnOfLeaderboard(final Pair<RaceColumnDTO, FleetDTO> raceColumnWithFleet) {
|
||||
final String selectedLeaderboardName = getSelectedLeaderboardName();
|
||||
final boolean oldIsMedalRace = raceColumnWithFleet.getA().isMedalRace();
|
||||
final String oldRaceColumnName = raceColumnWithFleet.getA().getRaceColumnName();
|
||||
final Double oldExplicitFactor = raceColumnWithFleet.getA().getExplicitFactor();
|
||||
List<RaceColumnDTO> existingRacesWithoutThisRace = new ArrayList<RaceColumnDTO>();
|
||||
for(Pair<RaceColumnDTO, FleetDTO> pair: raceColumnAndFleetList.getList()) {
|
||||
existingRacesWithoutThisRace.add(pair.getA());
|
||||
}
|
||||
existingRacesWithoutThisRace.remove(raceColumnWithFleet.getA());
|
||||
final RaceColumnInLeaderboardDialog raceDialog = new RaceColumnInLeaderboardDialog(existingRacesWithoutThisRace,
|
||||
raceColumnWithFleet.getA(), stringMessages, new DialogCallback<RaceColumnDTO>() {
|
||||
raceColumnWithFleet.getA(), stringMessages, new DialogCallback<RaceColumnDescriptor>() {
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ok(final RaceColumnDTO result) {
|
||||
public void ok(final RaceColumnDescriptor result) {
|
||||
boolean rename = !oldRaceColumnName.equals(result.getName());
|
||||
boolean updateIsMedalRace = oldIsMedalRace != result.isMedalRace();
|
||||
boolean updateFactor = oldExplicitFactor != result.getExplicitFactor();
|
||||
List<ParallelExecutionCallback<Void>> callbacks = new ArrayList<ParallelExecutionCallback<Void>>();
|
||||
final ParallelExecutionCallback<Void> renameLeaderboardColumnCallback = new ParallelExecutionCallback<Void>();
|
||||
if (rename) {
|
||||
callbacks.add(renameLeaderboardColumnCallback);
|
||||
}
|
||||
final ParallelExecutionCallback<Void> updateIsMedalRaceCallback = new ParallelExecutionCallback<Void>();
|
||||
new ParallelExecutionHolder(renameLeaderboardColumnCallback, updateIsMedalRaceCallback) {
|
||||
if (updateIsMedalRace) {
|
||||
callbacks.add(updateIsMedalRaceCallback);
|
||||
}
|
||||
final ParallelExecutionCallback<Void> updateLeaderboardColumnFactorCallback = new ParallelExecutionCallback<Void>();
|
||||
if (updateFactor) {
|
||||
callbacks.add(updateLeaderboardColumnFactorCallback);
|
||||
}
|
||||
new ParallelExecutionHolder(callbacks.toArray(new ParallelExecutionCallback<?>[0])) {
|
||||
@Override
|
||||
public void handleSuccess() {
|
||||
loadAndRefreshLeaderboard(selectedLeaderboardName);
|
||||
selectRaceColumn(result.getRaceColumnName());
|
||||
selectRaceColumn(result.getName());
|
||||
}
|
||||
@Override
|
||||
public void handleFailure(Throwable t) {
|
||||
@@ -716,11 +749,19 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
|
||||
+ t.getMessage());
|
||||
}
|
||||
};
|
||||
if (rename) {
|
||||
sailingService.renameLeaderboardColumn(selectedLeaderboardName, oldRaceColumnName,
|
||||
result.getRaceColumnName(), renameLeaderboardColumnCallback);
|
||||
sailingService.updateIsMedalRace(selectedLeaderboardName, result.getRaceColumnName(),
|
||||
result.getName(), renameLeaderboardColumnCallback);
|
||||
}
|
||||
if (updateIsMedalRace) {
|
||||
sailingService.updateIsMedalRace(selectedLeaderboardName, result.getName(),
|
||||
result.isMedalRace(), updateIsMedalRaceCallback);
|
||||
}
|
||||
if (updateFactor) {
|
||||
sailingService.updateLeaderboardColumnFactor(selectedLeaderboardName, result.getName(),
|
||||
result.getExplicitFactor(), updateLeaderboardColumnFactorCallback);
|
||||
}
|
||||
}
|
||||
});
|
||||
raceDialog.show();
|
||||
}
|
||||
@@ -729,11 +770,10 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
|
||||
final boolean isMedalRace) {
|
||||
sailingService.updateIsMedalRace(leaderboardName, raceInLeaderboard.getRaceColumnName(), isMedalRace,
|
||||
new AsyncCallback<Void>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError(stringMessages.errorUpdatingIsMedalRace(caught.getMessage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
selectedLeaderboard.setIsMedalRace(raceInLeaderboard.getRaceColumnName(), isMedalRace);
|
||||
@@ -801,7 +841,7 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
|
||||
raceSelectionProvider.addRaceSelectionChangeListener(LeaderboardConfigPanel.this);
|
||||
}
|
||||
});
|
||||
if (selectedLeaderboard != null && !selectedLeaderboard.isMetaLeaderboard) {
|
||||
if (selectedLeaderboard != null) {
|
||||
raceColumnAndFleetList.getList().clear();
|
||||
for (RaceColumnDTO raceColumn : selectedLeaderboard.getRaceList()) {
|
||||
for (FleetDTO fleet : raceColumn.getFleets()) {
|
||||
@@ -809,8 +849,10 @@ public class LeaderboardConfigPanel extends FormPanel implements RegattaDisplaye
|
||||
}
|
||||
}
|
||||
selectedLeaderBoardPanel.setVisible(true);
|
||||
trackedRacesCaptionPanel.setVisible(true);
|
||||
selectedLeaderBoardPanel.setCaptionText("Details of leaderboard '" + selectedLeaderboard.name + "'");
|
||||
if (!selectedLeaderboard.isMetaLeaderboard) {
|
||||
trackedRacesCaptionPanel.setVisible(true);
|
||||
}
|
||||
} else {
|
||||
selectedLeaderBoardPanel.setVisible(false);
|
||||
trackedRacesCaptionPanel.setVisible(false);
|
||||
|
||||
+16
-38
@@ -1,52 +1,30 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.safecss.shared.SafeStyles;
|
||||
import com.google.gwt.safecss.shared.SafeStylesUtils;
|
||||
import com.google.gwt.safehtml.shared.SafeHtml;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.text.shared.SafeHtmlRenderer;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
public class LeaderboardGroupConfigImagesBarCell extends ImagesBarCell {
|
||||
|
||||
public LeaderboardGroupConfigImagesBarCell(StringMessages stringConstants) {
|
||||
super();
|
||||
this.stringConstants = stringConstants;
|
||||
}
|
||||
|
||||
public LeaderboardGroupConfigImagesBarCell(SafeHtmlRenderer<String> renderer, StringMessages stringConstants) {
|
||||
super();
|
||||
this.stringConstants = stringConstants;
|
||||
}
|
||||
|
||||
private static ImagesBarTemplates templates = GWT.create(ImagesBarTemplates.class);
|
||||
|
||||
public static final String ACTION_REMOVE = "ACTION_REMOVE";
|
||||
public static final String ACTION_EDIT = "ACTION_EDIT";
|
||||
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
private static final SafeHtml ICON_EDIT = makeImage(resources.editIcon());
|
||||
public LeaderboardGroupConfigImagesBarCell(StringMessages stringMessages) {
|
||||
super();
|
||||
this.stringMessages = stringMessages;
|
||||
}
|
||||
|
||||
private static final SafeHtml ICON_REMOVE = makeImage(resources.removeIcon());
|
||||
|
||||
private StringMessages stringConstants;
|
||||
public LeaderboardGroupConfigImagesBarCell(SafeHtmlRenderer<String> renderer, StringMessages stringMessages) {
|
||||
super();
|
||||
this.stringMessages = stringMessages;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void render(com.google.gwt.cell.client.Cell.Context context, SafeHtml data, SafeHtmlBuilder sb) {
|
||||
/*
|
||||
* Always do a null check on the value. Cell widgets can pass null to
|
||||
* cells if the underlying data contains a null, or if the data arrives
|
||||
* out of order.
|
||||
*/
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
SafeStyles imgStyle = SafeStylesUtils.fromTrustedString("float:left;cursor:hand;cursor:pointer;padding-right:5px;");
|
||||
|
||||
SafeHtml rendered = templates.cell("ACTION_EDIT", imgStyle, stringConstants.actionEdit(), ICON_EDIT);
|
||||
sb.append(rendered);
|
||||
|
||||
rendered = templates.cell("ACTION_REMOVE", imgStyle, stringConstants.actionRemove(), ICON_REMOVE);
|
||||
sb.append(rendered);
|
||||
protected Iterable<ImageSpec> getImageSpecs() {
|
||||
return Arrays.asList(new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(resources.editIcon())),
|
||||
new ImageSpec(ACTION_REMOVE, stringMessages.actionRemove(), makeImagePrototype(resources.removeIcon())));
|
||||
}
|
||||
}
|
||||
+44
-18
@@ -36,6 +36,7 @@ import com.google.gwt.view.client.MultiSelectionModel;
|
||||
import com.google.gwt.view.client.SelectionChangeEvent;
|
||||
import com.google.gwt.view.client.SingleSelectionModel;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.LeaderboardConfigPanel.AnchorCell;
|
||||
import com.sap.sailing.gwt.ui.adminconsole.LeaderboardGroupDialog.LeaderboardGroupDescriptor;
|
||||
import com.sap.sailing.gwt.ui.client.AbstractRegattaPanel;
|
||||
import com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
@@ -446,21 +447,22 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel {
|
||||
new LeaderboardGroupConfigImagesBarCell(stringMessages));
|
||||
groupActionsColumn.setFieldUpdater(new FieldUpdater<LeaderboardGroupDTO, String>() {
|
||||
@Override
|
||||
public void update(int index, LeaderboardGroupDTO group, String command) {
|
||||
if (command.equals("ACTION_EDIT")) {
|
||||
public void update(int index, final LeaderboardGroupDTO group, String command) {
|
||||
if (command.equals(LeaderboardGroupConfigImagesBarCell.ACTION_EDIT)) {
|
||||
final String oldGroupName = group.name;
|
||||
ArrayList<LeaderboardGroupDTO> otherExistingGroups = new ArrayList<LeaderboardGroupDTO>(availableLeaderboardGroups);
|
||||
otherExistingGroups.remove(group);
|
||||
LeaderboardGroupEditDialog dialog = new LeaderboardGroupEditDialog(group, otherExistingGroups, stringMessages, new DialogCallback<LeaderboardGroupDTO>() {
|
||||
LeaderboardGroupEditDialog dialog = new LeaderboardGroupEditDialog(group, otherExistingGroups, stringMessages,
|
||||
new DialogCallback<LeaderboardGroupDescriptor>() {
|
||||
@Override
|
||||
public void cancel() {}
|
||||
@Override
|
||||
public void ok(LeaderboardGroupDTO group) {
|
||||
updateGroup(oldGroupName, group);
|
||||
public void ok(LeaderboardGroupDescriptor groupDescriptor) {
|
||||
updateGroup(oldGroupName, group, groupDescriptor);
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
} else if (command.equals("ACTION_REMOVE")) {
|
||||
} else if (command.equals(LeaderboardGroupConfigImagesBarCell.ACTION_REMOVE)) {
|
||||
if (Window.confirm("Do you really want to remove the leaderboard group: '" + group.name + "' ?")) {
|
||||
removeLeaderboardGroup(group);
|
||||
}
|
||||
@@ -558,24 +560,24 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel {
|
||||
private void addNewGroup() {
|
||||
LeaderboardGroupCreateDialog dialog = new LeaderboardGroupCreateDialog(
|
||||
Collections.unmodifiableCollection(availableLeaderboardGroups), stringMessages,
|
||||
new DialogCallback<LeaderboardGroupDTO>() {
|
||||
new DialogCallback<LeaderboardGroupDescriptor>() {
|
||||
@Override
|
||||
public void cancel() {}
|
||||
@Override
|
||||
public void ok(LeaderboardGroupDTO newGroup) {
|
||||
public void ok(LeaderboardGroupDescriptor newGroup) {
|
||||
createNewGroup(newGroup);
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void createNewGroup(final LeaderboardGroupDTO newGroup) {
|
||||
sailingService.createLeaderboardGroup(newGroup.name, newGroup.description,
|
||||
newGroup.getOverallLeaderboardDiscardThresholds(), newGroup.getOverallLeaderboardScoringSchemeType(),
|
||||
new AsyncCallback<LeaderboardGroupDTO>() {
|
||||
private void createNewGroup(final LeaderboardGroupDescriptor newGroup) {
|
||||
sailingService.createLeaderboardGroup(newGroup.getName(), newGroup.getDescription(), newGroup.isDisplayLeaderboardsInReverseOrder(),
|
||||
newGroup.getOverallLeaderboardDiscardThresholds(),
|
||||
newGroup.getOverallLeaderboardScoringSchemeType(), new AsyncCallback<LeaderboardGroupDTO>() {
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
errorReporter.reportError("Error trying to create new leaderboard group" + newGroup.name
|
||||
errorReporter.reportError("Error trying to create new leaderboard group" + newGroup.getName()
|
||||
+ ": " + t.getMessage());
|
||||
}
|
||||
@Override
|
||||
@@ -588,14 +590,14 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel {
|
||||
});
|
||||
}
|
||||
|
||||
private void updateGroup(final String oldGroupName, final LeaderboardGroupDTO groupToUpdate) {
|
||||
private void updateGroup(final String oldGroupName, final LeaderboardGroupDTO groupToUpdate, final LeaderboardGroupDescriptor updateDescriptor) {
|
||||
List<String> leaderboardNames = new ArrayList<String>();
|
||||
for (StrippedLeaderboardDTO leaderboardDTO : groupToUpdate.leaderboards) {
|
||||
leaderboardNames.add(leaderboardDTO.name);
|
||||
}
|
||||
sailingService.updateLeaderboardGroup(oldGroupName, groupToUpdate.name, groupToUpdate.description,
|
||||
leaderboardNames, groupToUpdate.getOverallLeaderboardDiscardThresholds(),
|
||||
groupToUpdate.getOverallLeaderboardScoringSchemeType(), new AsyncCallback<Void>() {
|
||||
sailingService.updateLeaderboardGroup(oldGroupName, updateDescriptor.getName(), updateDescriptor.getDescription(),
|
||||
leaderboardNames, updateDescriptor.getOverallLeaderboardDiscardThresholds(),
|
||||
updateDescriptor.getOverallLeaderboardScoringSchemeType(), new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
errorReporter.reportError("Error trying to update leaderboard group " + oldGroupName + ": "
|
||||
@@ -607,6 +609,11 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel {
|
||||
for (int i = 0; i < availableLeaderboardGroups.size(); i++) {
|
||||
LeaderboardGroupDTO group = availableLeaderboardGroups.get(i);
|
||||
if (oldGroupName.equals(group.name)) {
|
||||
groupToUpdate.name = updateDescriptor.getName();
|
||||
groupToUpdate.description = updateDescriptor.getDescription();
|
||||
groupToUpdate.displayLeaderboardsInReverseOrder = updateDescriptor.isDisplayLeaderboardsInReverseOrder();
|
||||
groupToUpdate.setOverallLeaderboardDiscardThresholds(updateDescriptor.getOverallLeaderboardDiscardThresholds());
|
||||
groupToUpdate.setOverallLeaderboardScoringSchemeType(updateDescriptor.getOverallLeaderboardScoringSchemeType());
|
||||
availableLeaderboardGroups.set(i, groupToUpdate);
|
||||
int displayedIndex = groupsProvider.getList().indexOf(group);
|
||||
if (displayedIndex != -1) {
|
||||
@@ -618,8 +625,27 @@ public class LeaderboardGroupConfigPanel extends AbstractRegattaPanel {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a change in the group's leaderboard list to the server
|
||||
*/
|
||||
private void updateGroup(final LeaderboardGroupDTO group) {
|
||||
updateGroup(group.name, group);
|
||||
List<String> leaderboardNames = new ArrayList<String>();
|
||||
for (StrippedLeaderboardDTO leaderboardDTO : group.leaderboards) {
|
||||
leaderboardNames.add(leaderboardDTO.name);
|
||||
}
|
||||
sailingService.updateLeaderboardGroup(group.name, group.name, group.description,
|
||||
leaderboardNames, group.getOverallLeaderboardDiscardThresholds(),
|
||||
group.getOverallLeaderboardScoringSchemeType(), new AsyncCallback<Void>() {
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
errorReporter.reportError("Error trying to update leaderboard group " + group.name + ": "
|
||||
+ t.getMessage());
|
||||
}
|
||||
@Override
|
||||
public void onSuccess(Void v) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void removeLeaderboardGroup(final LeaderboardGroupDTO group) {
|
||||
|
||||
+3
-2
@@ -8,11 +8,12 @@ import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
||||
public class LeaderboardGroupCreateDialog extends LeaderboardGroupDialog {
|
||||
|
||||
public LeaderboardGroupCreateDialog(Collection<LeaderboardGroupDTO> existingGroups,
|
||||
StringMessages stringMessages, DialogCallback<LeaderboardGroupDTO> callback) {
|
||||
StringMessages stringMessages, DialogCallback<LeaderboardGroupDescriptor> callback) {
|
||||
super(new LeaderboardGroupDTO(), stringMessages,
|
||||
callback, existingGroups);
|
||||
nameEntryField = createTextBox(null);
|
||||
descriptionEntryField = createTextArea(null);
|
||||
displayLeaderboardsInReverseOrderCheckBox.setValue(false);
|
||||
useOverallLeaderboardCheckBox.setValue(false);
|
||||
}
|
||||
|
||||
}
|
||||
+68
-37
@@ -25,20 +25,55 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
|
||||
|
||||
public class LeaderboardGroupDialog extends DataEntryDialog<LeaderboardGroupDTO> {
|
||||
|
||||
public class LeaderboardGroupDialog extends DataEntryDialog<LeaderboardGroupDialog.LeaderboardGroupDescriptor> {
|
||||
protected StringMessages stringMessages;
|
||||
protected LeaderboardGroupDTO group;
|
||||
|
||||
protected TextBox nameEntryField;
|
||||
protected TextArea descriptionEntryField;
|
||||
|
||||
private CheckBox useOverallLeaderboardCheckBox;
|
||||
protected CheckBox displayLeaderboardsInReverseOrderCheckBox;
|
||||
protected CheckBox useOverallLeaderboardCheckBox;
|
||||
private Panel overallLeaderboardConfigPanel;
|
||||
private LongBox[] overallLeaderboardDiscardThresholdFields;
|
||||
private ListBox overallLeaderboardScoringSchemeListBox;
|
||||
|
||||
protected static class LeaderboardGroupParameterValidator implements Validator<LeaderboardGroupDTO> {
|
||||
public static class LeaderboardGroupDescriptor {
|
||||
private final String name;
|
||||
private final String description;
|
||||
private final boolean displayLeaderboardsInReverseOrder;
|
||||
private final boolean useOverallLeaderboard;
|
||||
private final int[] overallLeaderboardDiscardThresholds;
|
||||
private final ScoringSchemeType overallLeaderboardScoringSchemeType;
|
||||
public LeaderboardGroupDescriptor(String name, String description, boolean displayLeaderboardsInReverseOrder,
|
||||
boolean useOverallLeaderboard, int[] overallLeaderboardDiscardThresholds,
|
||||
ScoringSchemeType overallLeaderboardScoringSchemeType) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.displayLeaderboardsInReverseOrder = displayLeaderboardsInReverseOrder;
|
||||
this.useOverallLeaderboard = useOverallLeaderboard;
|
||||
this.overallLeaderboardDiscardThresholds = overallLeaderboardDiscardThresholds;
|
||||
this.overallLeaderboardScoringSchemeType = overallLeaderboardScoringSchemeType;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
public boolean isDisplayLeaderboardsInReverseOrder() {
|
||||
return displayLeaderboardsInReverseOrder;
|
||||
}
|
||||
public boolean isUseOverallLeaderboard() {
|
||||
return useOverallLeaderboard;
|
||||
}
|
||||
public int[] getOverallLeaderboardDiscardThresholds() {
|
||||
return overallLeaderboardDiscardThresholds;
|
||||
}
|
||||
public ScoringSchemeType getOverallLeaderboardScoringSchemeType() {
|
||||
return overallLeaderboardScoringSchemeType;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class LeaderboardGroupParameterValidator implements Validator<LeaderboardGroupDescriptor> {
|
||||
private final StringMessages stringMessages;
|
||||
private final ArrayList<LeaderboardGroupDTO> existingGroups;
|
||||
|
||||
@@ -49,14 +84,14 @@ public class LeaderboardGroupDialog extends DataEntryDialog<LeaderboardGroupDTO>
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorMessage(LeaderboardGroupDTO groupToValidate) {
|
||||
public String getErrorMessage(LeaderboardGroupDescriptor groupToValidate) {
|
||||
String errorMessage = null;
|
||||
boolean nameNotEmpty = groupToValidate.name != null && groupToValidate.name.length() > 0;
|
||||
boolean descrNotEmpty = groupToValidate.description != null && groupToValidate.description.length() > 0;
|
||||
boolean nameNotEmpty = groupToValidate.getName() != null && groupToValidate.getName().length() > 0;
|
||||
boolean descrNotEmpty = groupToValidate.getDescription() != null && groupToValidate.getDescription().length() > 0;
|
||||
|
||||
boolean unique = true;
|
||||
for (LeaderboardGroupDTO group : existingGroups) {
|
||||
if (group.name.equals(groupToValidate.name)) {
|
||||
if (group.name.equals(groupToValidate.getName())) {
|
||||
unique = false;
|
||||
break;
|
||||
}
|
||||
@@ -88,16 +123,12 @@ public class LeaderboardGroupDialog extends DataEntryDialog<LeaderboardGroupDTO>
|
||||
return overallLeaderboardDiscardThresholdFields;
|
||||
}
|
||||
|
||||
protected CheckBox getUseOverallLeaderboardCheckBox() {
|
||||
return useOverallLeaderboardCheckBox;
|
||||
}
|
||||
|
||||
public LeaderboardGroupDialog(LeaderboardGroupDTO group, StringMessages stringMessages,
|
||||
DialogCallback<LeaderboardGroupDTO> callback, Collection<LeaderboardGroupDTO> existingLeaderboardGroups) {
|
||||
DialogCallback<LeaderboardGroupDescriptor> callback, Collection<LeaderboardGroupDTO> existingLeaderboardGroups) {
|
||||
super(stringMessages.leaderboardGroup(), null, stringMessages.ok(), stringMessages.cancel(),
|
||||
new LeaderboardGroupParameterValidator(stringMessages, existingLeaderboardGroups), callback);
|
||||
this.stringMessages = stringMessages;
|
||||
this.group = group;
|
||||
displayLeaderboardsInReverseOrderCheckBox = createCheckbox(stringMessages.displayGroupsInReverseOrder());
|
||||
useOverallLeaderboardCheckBox = createCheckbox(stringMessages.useOverallLeaderboard());
|
||||
Grid formGrid = new Grid(3,2);
|
||||
formGrid.setCellSpacing(3);
|
||||
@@ -126,19 +157,14 @@ public class LeaderboardGroupDialog extends DataEntryDialog<LeaderboardGroupDTO>
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LeaderboardGroupDTO getResult() {
|
||||
group.name = nameEntryField.getText();
|
||||
group.description = descriptionEntryField.getText();
|
||||
if (useOverallLeaderboardCheckBox.getValue()) {
|
||||
group.setOverallLeaderboardDiscardThresholds(AbstractLeaderboardDialog
|
||||
.getDiscardThresholds(getOverallLeaderboardDiscardThresholdFields()));
|
||||
group.setOverallLeaderboardScoringSchemeType(AbstractLeaderboardDialog.getSelectedScoringSchemeType(
|
||||
overallLeaderboardScoringSchemeListBox, stringMessages));
|
||||
} else {
|
||||
group.setOverallLeaderboardDiscardThresholds(null);
|
||||
group.setOverallLeaderboardScoringSchemeType(null);
|
||||
}
|
||||
return group;
|
||||
protected LeaderboardGroupDescriptor getResult() {
|
||||
return new LeaderboardGroupDescriptor(nameEntryField.getText(), descriptionEntryField.getText(),
|
||||
displayLeaderboardsInReverseOrderCheckBox.getValue(),
|
||||
useOverallLeaderboardCheckBox.getValue(),
|
||||
useOverallLeaderboardCheckBox.getValue() ? AbstractLeaderboardDialog
|
||||
.getDiscardThresholds(getOverallLeaderboardDiscardThresholdFields()) : null,
|
||||
useOverallLeaderboardCheckBox.getValue() ? AbstractLeaderboardDialog.getSelectedScoringSchemeType(
|
||||
overallLeaderboardScoringSchemeListBox, stringMessages) : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -155,26 +181,31 @@ public class LeaderboardGroupDialog extends DataEntryDialog<LeaderboardGroupDTO>
|
||||
descriptionEntryField.setVisibleLines(6);
|
||||
descriptionEntryField.getElement().getStyle().setProperty("resize", "none");
|
||||
panel.add(descriptionEntryField);
|
||||
panel.add(displayLeaderboardsInReverseOrderCheckBox);
|
||||
panel.add(useOverallLeaderboardCheckBox);
|
||||
useOverallLeaderboardCheckBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
public void onValueChange(ValueChangeEvent<Boolean> event) {
|
||||
if (event.getValue()) {
|
||||
updateOverallLeaderboardDetailsVisibility(event.getValue(), panel);
|
||||
}
|
||||
});
|
||||
updateOverallLeaderboardDetailsVisibility(useOverallLeaderboardCheckBox.getValue(), panel);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private void updateOverallLeaderboardDetailsVisibility(boolean overallLeaderboardDetailsVisible, Panel panel) {
|
||||
if (overallLeaderboardDetailsVisible) {
|
||||
useOverallLeaderboard(panel);
|
||||
} else {
|
||||
dontUseOverallLeaderboard(panel);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
return panel;
|
||||
}
|
||||
|
||||
protected void useOverallLeaderboard(final VerticalPanel panel) {
|
||||
protected void useOverallLeaderboard(final Panel panel) {
|
||||
panel.add(overallLeaderboardConfigPanel);
|
||||
}
|
||||
|
||||
protected void dontUseOverallLeaderboard(final VerticalPanel panel) {
|
||||
protected void dontUseOverallLeaderboard(final Panel panel) {
|
||||
panel.remove(overallLeaderboardConfigPanel);
|
||||
}
|
||||
|
||||
|
||||
+4
-9
@@ -2,24 +2,19 @@ package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO;
|
||||
|
||||
public class LeaderboardGroupEditDialog extends LeaderboardGroupDialog {
|
||||
public LeaderboardGroupEditDialog(LeaderboardGroupDTO group, Collection<LeaderboardGroupDTO> otherExistingGroups,
|
||||
StringMessages stringMessages, DialogCallback<LeaderboardGroupDTO> callback) {
|
||||
StringMessages stringMessages, DialogCallback<LeaderboardGroupDescriptor> callback) {
|
||||
super(group, stringMessages, callback, otherExistingGroups);
|
||||
// don't allow editing the overall leaderboard's scoring scheme if the group already uses an overall leaderboard
|
||||
getOverallLeaderboardScoringSchemeListBox().setEnabled(!group.hasOverallLeaderboard());
|
||||
nameEntryField = createTextBox(group.name);
|
||||
descriptionEntryField = createTextArea(group.description);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget getAdditionalWidget() {
|
||||
Widget result = super.getAdditionalWidget();
|
||||
getUseOverallLeaderboardCheckBox().setValue(group.hasOverallLeaderboard(), /* fire event */ true);
|
||||
return result;
|
||||
displayLeaderboardsInReverseOrderCheckBox.setValue(group.displayLeaderboardsInReverseOrder);
|
||||
displayLeaderboardsInReverseOrderCheckBox.setEnabled(false);
|
||||
useOverallLeaderboardCheckBox.setValue(group.hasOverallLeaderboard());
|
||||
}
|
||||
}
|
||||
+14
-39
@@ -1,57 +1,32 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.safecss.shared.SafeStyles;
|
||||
import com.google.gwt.safecss.shared.SafeStylesUtils;
|
||||
import com.google.gwt.safehtml.shared.SafeHtml;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.text.shared.SafeHtmlRenderer;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
public class LeaderboardRaceConfigImagesBarCell extends ImagesBarCell {
|
||||
|
||||
private StringMessages stringConstants;
|
||||
public static final String ACTION_REMOVE = "ACTION_REMOVE";
|
||||
public static final String ACTION_UNLINK = "ACTION_UNLINK";
|
||||
public static final String ACTION_EDIT = "ACTION_EDIT";
|
||||
private final StringMessages stringMessages;
|
||||
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
|
||||
public LeaderboardRaceConfigImagesBarCell(StringMessages stringConstants) {
|
||||
super();
|
||||
this.stringConstants = stringConstants;
|
||||
this.stringMessages = stringConstants;
|
||||
}
|
||||
|
||||
public LeaderboardRaceConfigImagesBarCell(SafeHtmlRenderer<String> renderer, StringMessages stringConstants) {
|
||||
public LeaderboardRaceConfigImagesBarCell(SafeHtmlRenderer<String> renderer, StringMessages stringMessages) {
|
||||
super();
|
||||
this.stringConstants = stringConstants;
|
||||
this.stringMessages = stringMessages;
|
||||
}
|
||||
|
||||
private static ImagesBarTemplates templates = GWT.create(ImagesBarTemplates.class);
|
||||
|
||||
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
|
||||
private static final SafeHtml ICON_EDIT = makeImage(resources.editIcon());
|
||||
|
||||
private static final SafeHtml ICON_UNLINK = makeImage(resources.unlinkIcon());
|
||||
|
||||
private static final SafeHtml ICON_REMOVE = makeImage(resources.removeIcon());
|
||||
|
||||
@Override
|
||||
protected void render(com.google.gwt.cell.client.Cell.Context context, SafeHtml data, SafeHtmlBuilder sb) {
|
||||
/*
|
||||
* Always do a null check on the value. Cell widgets can pass null to cells if the underlying data contains a
|
||||
* null, or if the data arrives out of order.
|
||||
*/
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
SafeStyles imgStyle = SafeStylesUtils
|
||||
.fromTrustedString("float:left;cursor:hand;cursor:pointer;padding-right:5px;");
|
||||
|
||||
SafeHtml rendered = templates.cell("ACTION_EDIT", imgStyle, stringConstants.actionRaceEdit(), ICON_EDIT);
|
||||
sb.append(rendered);
|
||||
|
||||
rendered = templates.cell("ACTION_UNLINK", imgStyle, stringConstants.actionRaceUnlink(), ICON_UNLINK);
|
||||
sb.append(rendered);
|
||||
|
||||
rendered = templates.cell("ACTION_REMOVE", imgStyle, stringConstants.actionRaceRemove(), ICON_REMOVE);
|
||||
sb.append(rendered);
|
||||
protected Iterable<ImageSpec> getImageSpecs() {
|
||||
return Arrays.asList(new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(resources.editIcon())),
|
||||
new ImageSpec(ACTION_UNLINK, stringMessages.actionRaceUnlink(), makeImagePrototype(resources.unlinkIcon())),
|
||||
new ImageSpec(ACTION_REMOVE, stringMessages.actionRaceRemove(), makeImagePrototype(resources.removeIcon())));
|
||||
}
|
||||
}
|
||||
+53
-19
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.adminconsole;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.user.client.ui.CheckBox;
|
||||
import com.google.gwt.user.client.ui.DoubleBox;
|
||||
import com.google.gwt.user.client.ui.HasVerticalAlignment;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
@@ -18,14 +19,43 @@ import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class RaceColumnInLeaderboardDialog extends DataEntryDialog<RaceColumnDTO> {
|
||||
public class RaceColumnInLeaderboardDialog extends DataEntryDialog<RaceColumnInLeaderboardDialog.RaceColumnDescriptor> {
|
||||
private final TextBox raceNameBox;
|
||||
private final DoubleBox explicitFactorBox;
|
||||
private final CheckBox isMedalRace;
|
||||
private final StringMessages stringConstants;
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
private RaceColumnDTO raceColumnToEdit;
|
||||
public static class RaceColumnDescriptor {
|
||||
private String name;
|
||||
private boolean isMedalRace;
|
||||
private Double explicitFactor;
|
||||
public RaceColumnDescriptor(String name, boolean isMedalRace, Double explicitFactor) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.isMedalRace = isMedalRace;
|
||||
this.explicitFactor = explicitFactor;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public boolean isMedalRace() {
|
||||
return isMedalRace;
|
||||
}
|
||||
public void setMedalRace(boolean isMedalRace) {
|
||||
this.isMedalRace = isMedalRace;
|
||||
}
|
||||
public Double getExplicitFactor() {
|
||||
return explicitFactor;
|
||||
}
|
||||
public void setExplicitFactor(Double explicitFactor) {
|
||||
this.explicitFactor = explicitFactor;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RaceDialogValidator implements Validator<RaceColumnDTO> {
|
||||
private static class RaceDialogValidator implements Validator<RaceColumnDescriptor> {
|
||||
|
||||
private StringMessages stringConstants;
|
||||
private List<RaceColumnDTO> existingRaces;
|
||||
@@ -36,16 +66,16 @@ public class RaceColumnInLeaderboardDialog extends DataEntryDialog<RaceColumnDTO
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorMessage(RaceColumnDTO valueToValidate) {
|
||||
public String getErrorMessage(RaceColumnDescriptor valueToValidate) {
|
||||
String errorMessage;
|
||||
String racename = valueToValidate.getRaceColumnName();
|
||||
String racename = valueToValidate.getName();
|
||||
Boolean isMedalRace = valueToValidate.isMedalRace();
|
||||
boolean isNameNotEmpty = racename != null & racename != "";
|
||||
boolean medalRaceNotNull = isMedalRace != null;
|
||||
|
||||
boolean unique = true;
|
||||
for (RaceColumnDTO raceColumn : existingRaces) {
|
||||
if (raceColumn.getRaceColumnName().equals(valueToValidate.getRaceColumnName())) {
|
||||
if (raceColumn.getRaceColumnName().equals(valueToValidate.getName())) {
|
||||
unique = false;
|
||||
}
|
||||
}
|
||||
@@ -64,21 +94,21 @@ public class RaceColumnInLeaderboardDialog extends DataEntryDialog<RaceColumnDTO
|
||||
}
|
||||
|
||||
public RaceColumnInLeaderboardDialog(List<RaceColumnDTO> existingRaces, RaceColumnDTO raceColumnToEdit,
|
||||
StringMessages stringConstants, DialogCallback<RaceColumnDTO> callback) {
|
||||
super(stringConstants.actionRaceEdit(), null, stringConstants.ok(), stringConstants.cancel(),
|
||||
new RaceDialogValidator(stringConstants, existingRaces), callback);
|
||||
this.raceColumnToEdit = raceColumnToEdit;
|
||||
this.stringConstants = stringConstants;
|
||||
StringMessages stringMessages, DialogCallback<RaceColumnDescriptor> callback) {
|
||||
super(stringMessages.actionRaceEdit(), null, stringMessages.ok(), stringMessages.cancel(),
|
||||
new RaceDialogValidator(stringMessages, existingRaces), callback);
|
||||
this.stringMessages = stringMessages;
|
||||
raceNameBox = createTextBox(raceColumnToEdit.getRaceColumnName());
|
||||
isMedalRace = createCheckbox(stringConstants.medalRace());
|
||||
explicitFactorBox = raceColumnToEdit.getExplicitFactor() == null ?
|
||||
createDoubleBox(/* visibleLength */ 4) : createDoubleBox(raceColumnToEdit.getExplicitFactor(), /* visibleLength */ 4);
|
||||
isMedalRace = createCheckbox(stringMessages.medalRace());
|
||||
isMedalRace.setValue(raceColumnToEdit.isMedalRace());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RaceColumnDTO getResult() {
|
||||
raceColumnToEdit.name = raceNameBox.getValue();
|
||||
raceColumnToEdit.setMedalRace(isMedalRace.getValue());
|
||||
return raceColumnToEdit;
|
||||
protected RaceColumnDescriptor getResult() {
|
||||
return new RaceColumnDescriptor(raceNameBox.getValue(), isMedalRace.getValue(),
|
||||
explicitFactorBox.getText().trim().length() == 0 ? null : explicitFactorBox.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,10 +118,14 @@ public class RaceColumnInLeaderboardDialog extends DataEntryDialog<RaceColumnDTO
|
||||
HorizontalPanel raceNamePanel = new HorizontalPanel();
|
||||
raceNamePanel.setSpacing(3);
|
||||
mainPanel.add(raceNamePanel);
|
||||
raceNamePanel.add(new Label(stringConstants.name() + ":"));
|
||||
raceNamePanel.add(new Label(stringMessages.name() + ":"));
|
||||
raceNamePanel.add(raceNameBox);
|
||||
HorizontalPanel factorPanel = new HorizontalPanel();
|
||||
factorPanel.setSpacing(3);
|
||||
mainPanel.add(factorPanel);
|
||||
factorPanel.add(new Label(stringMessages.factor() + ":"));
|
||||
factorPanel.add(explicitFactorBox);
|
||||
alignAllPanelWidgetsVertically(raceNamePanel, HasVerticalAlignment.ALIGN_MIDDLE);
|
||||
|
||||
mainPanel.add(isMedalRace);
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ public class RaceColumnInRegattaSeriesDialog extends DataEntryDialog<Pair<Series
|
||||
raceNamePrefixTextBox.setText(seriesName.substring(0, 1).toUpperCase());
|
||||
}
|
||||
} else {
|
||||
seriesListBox.addItem("Please select a series");
|
||||
seriesListBox.addItem(stringMessages.pleaseSelectASeries());
|
||||
for (SeriesDTO series : regatta.series) {
|
||||
seriesListBox.addItem(series.name);
|
||||
}
|
||||
|
||||
+10
@@ -378,6 +378,7 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
|
||||
}
|
||||
};
|
||||
result.addColumn(buoyNameColumn, stringMessages.buoy());
|
||||
|
||||
final SafeHtmlCell buoyPositionCell = new SafeHtmlCell();
|
||||
Column<BuoyDTO, SafeHtml> buoyPositionColumn = new Column<BuoyDTO, SafeHtml>(buoyPositionCell) {
|
||||
@Override
|
||||
@@ -388,6 +389,15 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
|
||||
}
|
||||
};
|
||||
result.addColumn(buoyPositionColumn, stringMessages.position());
|
||||
|
||||
TextColumn<BuoyDTO> buoyColorColumn = new TextColumn<BuoyDTO>() {
|
||||
@Override
|
||||
public String getValue(BuoyDTO buoyDTO) {
|
||||
return buoyDTO.displayColor != null ? buoyDTO.displayColor : "";
|
||||
}
|
||||
};
|
||||
result.addColumn(buoyColorColumn, stringMessages.color());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+9
-35
@@ -1,56 +1,30 @@
|
||||
package com.sap.sailing.gwt.ui.adminconsole;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.safecss.shared.SafeStyles;
|
||||
import com.google.gwt.safecss.shared.SafeStylesUtils;
|
||||
import com.google.gwt.safehtml.shared.SafeHtml;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.text.shared.SafeHtmlRenderer;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
public class RegattaConfigImagesBarCell extends ImagesBarCell {
|
||||
|
||||
static final String ACTION_REMOVE = "ACTION_REMOVE";
|
||||
|
||||
static final String ACTION_EDIT = "ACTION_EDIT";
|
||||
private final StringMessages stringMessages;
|
||||
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
|
||||
public RegattaConfigImagesBarCell(StringMessages stringConstants) {
|
||||
super();
|
||||
this.stringMessages = stringConstants;
|
||||
}
|
||||
|
||||
public RegattaConfigImagesBarCell(SafeHtmlRenderer<String> renderer, StringMessages stringConstants) {
|
||||
public RegattaConfigImagesBarCell(SafeHtmlRenderer<String> renderer, StringMessages stringMessages) {
|
||||
super();
|
||||
this.stringMessages = stringConstants;
|
||||
this.stringMessages = stringMessages;
|
||||
}
|
||||
|
||||
private static ImagesBarTemplates templates = GWT.create(ImagesBarTemplates.class);
|
||||
|
||||
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
|
||||
|
||||
private static final SafeHtml ICON_EDIT = makeImage(resources.editIcon());
|
||||
|
||||
private static final SafeHtml ICON_REMOVE = makeImage(resources.removeIcon());
|
||||
|
||||
private StringMessages stringMessages;
|
||||
|
||||
@Override
|
||||
protected void render(com.google.gwt.cell.client.Cell.Context context, SafeHtml data, SafeHtmlBuilder sb) {
|
||||
/*
|
||||
* Always do a null check on the value. Cell widgets can pass null to
|
||||
* cells if the underlying data contains a null, or if the data arrives
|
||||
* out of order.
|
||||
*/
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
SafeStyles imgStyle = SafeStylesUtils.fromTrustedString("float:left;cursor:hand;cursor:pointer;padding-right:5px;");
|
||||
|
||||
SafeHtml rendered = templates.cell(ACTION_EDIT, imgStyle, stringMessages.actionEdit(), ICON_EDIT);
|
||||
sb.append(rendered);
|
||||
|
||||
rendered = templates.cell(ACTION_REMOVE, imgStyle, stringMessages.actionRemove(), ICON_REMOVE);
|
||||
sb.append(rendered);
|
||||
protected Iterable<ImageSpec> getImageSpecs() {
|
||||
return Arrays.asList(new ImageSpec(ACTION_EDIT, stringMessages.actionEdit(), makeImagePrototype(resources.editIcon())),
|
||||
new ImageSpec(ACTION_REMOVE, stringMessages.actionRemove(), makeImagePrototype(resources.removeIcon())));
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -530,10 +530,11 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
|
||||
List<TracTracRaceRecordDTO> racesWithNotMatchingBoatClasses = new ArrayList<TracTracRaceRecordDTO>();
|
||||
for (TracTracRaceRecordDTO rr : raceList.getList()) {
|
||||
if (raceTable.getSelectionModel().isSelected(rr)) {
|
||||
if(!checkBoatClassMatch(rr, selectedRegatta))
|
||||
if (!checkBoatClassMatch(rr, selectedRegatta)) {
|
||||
racesWithNotMatchingBoatClasses.add(rr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (racesWithNotMatchingBoatClasses.size() > 0) {
|
||||
String warningText = "WARNING\n";
|
||||
|
||||
+5
-4
@@ -297,7 +297,7 @@ public class TrackedRacesListComposite extends SimplePanel implements Component<
|
||||
TextColumn<RaceDTO> hasWindDataColumn = new TextColumn<RaceDTO>() {
|
||||
@Override
|
||||
public String getValue(RaceDTO raceDTO) {
|
||||
if (raceDTO.isTracked && raceDTO.trackedRace != null && raceDTO.trackedRace.hasWindData == true)
|
||||
if (raceDTO.trackedRace != null && raceDTO.trackedRace.hasWindData == true)
|
||||
return stringMessages.yes();
|
||||
else
|
||||
return stringMessages.no();
|
||||
@@ -307,17 +307,18 @@ public class TrackedRacesListComposite extends SimplePanel implements Component<
|
||||
TextColumn<RaceDTO> hasGPSDataColumn = new TextColumn<RaceDTO>() {
|
||||
@Override
|
||||
public String getValue(RaceDTO raceDTO) {
|
||||
if (raceDTO.isTracked && raceDTO.trackedRace != null && raceDTO.trackedRace.hasGPSData == true)
|
||||
if (raceDTO.trackedRace != null && raceDTO.trackedRace.hasGPSData == true) {
|
||||
return stringMessages.yes();
|
||||
else
|
||||
} else {
|
||||
return stringMessages.no();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TextColumn<RaceDTO> raceLiveDelayColumn = new TextColumn<RaceDTO>() {
|
||||
@Override
|
||||
public String getValue(RaceDTO raceDTO) {
|
||||
if (raceDTO.isTracked && raceDTO.trackedRace.delayToLiveInMs > 0) {
|
||||
if (raceDTO.isTracked && raceDTO.trackedRace != null && raceDTO.trackedRace.delayToLiveInMs > 0) {
|
||||
return "" + raceDTO.trackedRace.delayToLiveInMs / 1000;
|
||||
}
|
||||
return "";
|
||||
|
||||
+2
-1
@@ -39,7 +39,8 @@ public class ColorMap<T> {
|
||||
* Returns a color that is computed once.
|
||||
*
|
||||
* @param object
|
||||
* An ID unique for a competitor.
|
||||
* An ID unique for something this map is to provide a color for. Color assignment is based on the
|
||||
* object's {@link Object#equals(Object)} and {@link Object#hashCode()}.
|
||||
* @return A color in hex/html-format (e.g. #ff0000)
|
||||
*/
|
||||
public String getColorByID(T object) {
|
||||
|
||||
+16
-5
@@ -22,6 +22,7 @@ import com.google.gwt.user.client.ui.IntegerBox;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.ListBox;
|
||||
import com.google.gwt.user.client.ui.LongBox;
|
||||
import com.google.gwt.user.client.ui.RadioButton;
|
||||
import com.google.gwt.user.client.ui.TextArea;
|
||||
import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
@@ -296,15 +297,12 @@ public abstract class DataEntryDialog<T> {
|
||||
|
||||
public FlowPanel createHeadline(String headlineText, boolean regularHeadline) {
|
||||
FlowPanel headlinePanel = new FlowPanel();
|
||||
|
||||
Label headlineLabel = new Label(headlineText);
|
||||
|
||||
if (regularHeadline) {
|
||||
headlinePanel.addStyleName("dialogInnerHeadline");
|
||||
} else {
|
||||
headlinePanel.addStyleName("dialogInnerHeadlineOther");
|
||||
}
|
||||
|
||||
headlinePanel.add(headlineLabel);
|
||||
return headlinePanel;
|
||||
}
|
||||
@@ -323,6 +321,20 @@ public abstract class DataEntryDialog<T> {
|
||||
return result;
|
||||
}
|
||||
|
||||
public RadioButton createRadioButton(String radioButtonGroupName, String radioButtonLabel) {
|
||||
RadioButton result = new RadioButton(radioButtonGroupName, radioButtonLabel);
|
||||
result.setWordWrap(false);
|
||||
result.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||
@Override
|
||||
public void onValueChange(ValueChangeEvent<Boolean> event) {
|
||||
validate();
|
||||
}
|
||||
});
|
||||
AbstractEntryPoint.linkEnterToButton(getOkButton(), result);
|
||||
AbstractEntryPoint.linkEscapeToButton(getCancelButton(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public ListBox createListBox(boolean isMultipleSelect) {
|
||||
ListBox result = new ListBox(isMultipleSelect);
|
||||
result.addChangeHandler(new ChangeHandler() {
|
||||
@@ -336,13 +348,12 @@ public abstract class DataEntryDialog<T> {
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void alignAllPanelWidgetsVertically(HorizontalPanel panel, HasVerticalAlignment.VerticalAlignmentConstant alignment) {
|
||||
public void alignAllPanelWidgetsVertically(HorizontalPanel panel, HasVerticalAlignment.VerticalAlignmentConstant alignment) {
|
||||
for(int i = 0; i < panel.getWidgetCount(); i++) {
|
||||
panel.setCellVerticalAlignment(panel.getWidget(i), alignment);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Can contribute an additional widget to be displayed underneath the text entry field. If <code>null</code> is
|
||||
* returned, no additional widget will be displayed. This is the default behavior of this default implementation.
|
||||
|
||||
+4
@@ -62,6 +62,10 @@ public class DetailTypeFormatter {
|
||||
return stringMessages.maximumSpeedOverGroundInKnots();
|
||||
case TOTAL_TIME_SAILED_DOWNWIND_IN_SECONDS:
|
||||
return stringMessages.totalTimeSailedDownwindInSeconds();
|
||||
case TOTAL_TIME_SAILED_UPWIND_IN_SECONDS:
|
||||
return stringMessages.totalTimeSailedUpwindInSeconds();
|
||||
case TOTAL_TIME_SAILED_REACHING_IN_SECONDS:
|
||||
return stringMessages.totalTimeSailedReachingInSeconds();
|
||||
case TOTAL_TIME_SAILED_IN_SECONDS:
|
||||
return stringMessages.totalTimeSailedInSeconds();
|
||||
}
|
||||
|
||||
+19
@@ -50,4 +50,23 @@ public class LogoAndTitlePanel extends FlowPanel {
|
||||
}
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return titleLabel != null ? titleLabel.getText() : null;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
if(titleLabel != null) {
|
||||
titleLabel.setText(title);
|
||||
}
|
||||
}
|
||||
|
||||
public String getSubTitle() {
|
||||
return subTitleLabel != null ? subTitleLabel.getText() : null;
|
||||
}
|
||||
|
||||
public void setSubTitle(String subTitle) {
|
||||
if(subTitleLabel != null) {
|
||||
subTitleLabel.setText(subTitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -13,7 +13,7 @@ import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent;
|
||||
|
||||
public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements RaceSelectionChangeListener, RaceTimesInfoProviderListener {
|
||||
private RaceTimesInfoProvider raceTimesInfoProvider;
|
||||
private final RaceTimesInfoProvider raceTimesInfoProvider;
|
||||
private RegattaAndRaceIdentifier selectedRace;
|
||||
private boolean autoAdjustPlayMode;
|
||||
private RaceTimesInfoDTO lastRaceTimesInfo;
|
||||
@@ -84,9 +84,10 @@ public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements R
|
||||
|
||||
@Override
|
||||
public void onTimeZoomChanged(Date zoomStartTimepoint, Date zoomEndTimepoint) {
|
||||
super.onTimeZoomChanged(zoomStartTimepoint, zoomEndTimepoint);
|
||||
isTimeZoomed = true;
|
||||
timeSlider.setZoomed(true);
|
||||
timer.setAutoAdvance(false);
|
||||
// timer.setAutoAdvance(false);
|
||||
setMinMax(zoomStartTimepoint, zoomEndTimepoint, false);
|
||||
timeSlider.clearMarkersAndLabelsAndTicks();
|
||||
redrawAllMarkers(lastRaceTimesInfo);
|
||||
@@ -94,9 +95,10 @@ public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements R
|
||||
|
||||
@Override
|
||||
public void onTimeZoomReset() {
|
||||
super.onTimeZoomReset();
|
||||
isTimeZoomed = false;
|
||||
timeSlider.setZoomed(false);
|
||||
timer.setAutoAdvance(true);
|
||||
// timer.setAutoAdvance(true);
|
||||
updateMinMax(this.lastRaceTimesInfo);
|
||||
timeSlider.clearMarkersAndLabelsAndTicks();
|
||||
redrawAllMarkers(lastRaceTimesInfo);
|
||||
|
||||
+37
-17
@@ -11,44 +11,46 @@ import java.util.Set;
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.ui.shared.FleetDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||
|
||||
public class RaceTimesInfoProvider {
|
||||
|
||||
private SailingServiceAsync sailingService;
|
||||
private ErrorReporter errorReporter;
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final ErrorReporter errorReporter;
|
||||
|
||||
private Set<RegattaAndRaceIdentifier> raceIdentifiers;
|
||||
private long requestInterval;
|
||||
private final Set<RegattaAndRaceIdentifier> raceIdentifiers;
|
||||
private long requestIntervalInMillis;
|
||||
|
||||
private HashMap<RegattaAndRaceIdentifier, RaceTimesInfoDTO> raceTimesInfos;
|
||||
private final HashMap<RegattaAndRaceIdentifier, RaceTimesInfoDTO> raceTimesInfos;
|
||||
|
||||
private Set<RaceTimesInfoProviderListener> listeners;
|
||||
private final Set<RaceTimesInfoProviderListener> listeners;
|
||||
|
||||
/**
|
||||
* The <code>raceIdentifiers</code> has to be <code>not-null</code>, but can be empty.
|
||||
* The <code>raceIdentifiers</code> has to be non-<code>null</code>, but can be empty.
|
||||
*/
|
||||
public RaceTimesInfoProvider(SailingServiceAsync sailingService, ErrorReporter errorReporter, Collection<RegattaAndRaceIdentifier> raceIdentifiers, long requestInterval) {
|
||||
public RaceTimesInfoProvider(SailingServiceAsync sailingService, ErrorReporter errorReporter,
|
||||
Collection<RegattaAndRaceIdentifier> raceIdentifiers, long requestIntervalInMillis) {
|
||||
this.sailingService = sailingService;
|
||||
this.errorReporter = errorReporter;
|
||||
this.raceIdentifiers = new HashSet<RegattaAndRaceIdentifier>(raceIdentifiers);
|
||||
this.requestInterval = requestInterval;
|
||||
this.requestIntervalInMillis = requestIntervalInMillis;
|
||||
raceTimesInfos = new HashMap<RegattaAndRaceIdentifier, RaceTimesInfoDTO>();
|
||||
listeners = new HashSet<RaceTimesInfoProviderListener>();
|
||||
|
||||
RepeatingCommand command = new RepeatingCommand() {
|
||||
@Override
|
||||
public boolean execute() {
|
||||
readTimesInfos();
|
||||
Scheduler.get().scheduleFixedPeriod(this, (int) RaceTimesInfoProvider.this.requestInterval);
|
||||
Scheduler.get().scheduleFixedPeriod(this, (int) RaceTimesInfoProvider.this.requestIntervalInMillis);
|
||||
// don't execute *this* particular scheduled repeating command again; the line above re-scheduled already
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Scheduler.get().scheduleFixedPeriod(command, (int) this.requestInterval);
|
||||
|
||||
forceTimesInfosUpdate();
|
||||
command.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,7 +115,7 @@ public class RaceTimesInfoProvider {
|
||||
}
|
||||
|
||||
public long getRequestInterval() {
|
||||
return requestInterval;
|
||||
return requestIntervalInMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +123,7 @@ public class RaceTimesInfoProvider {
|
||||
* @param requestInterval The new request interval
|
||||
*/
|
||||
public void setRequestInterval(long requestInterval){
|
||||
this.requestInterval = requestInterval;
|
||||
this.requestIntervalInMillis = requestInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,4 +179,22 @@ public class RaceTimesInfoProvider {
|
||||
}
|
||||
}
|
||||
|
||||
public RegattaAndRaceIdentifier getFirstStartedAndUnfinishedRace(LeaderboardDTO leaderboard) {
|
||||
RegattaAndRaceIdentifier firstStartedAndUnfinishedRace = null;
|
||||
Map<RegattaAndRaceIdentifier, RaceTimesInfoDTO> raceTimesInfos = getRaceTimesInfos();
|
||||
for (RaceColumnDTO race : leaderboard.getRaceList()) {
|
||||
for (FleetDTO fleet : race.getFleets()) {
|
||||
RegattaAndRaceIdentifier raceIdentifier = race.getRaceIdentifier(fleet);
|
||||
if (raceIdentifier != null) {
|
||||
RaceTimesInfoDTO raceTimes = raceTimesInfos.get(raceIdentifier);
|
||||
if (raceTimes != null && raceTimes.startOfTracking != null && raceTimes.endOfRace == null) {
|
||||
firstStartedAndUnfinishedRace = raceIdentifier;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return firstStartedAndUnfinishedRace;
|
||||
}
|
||||
|
||||
}
|
||||
+4
-1
@@ -203,7 +203,8 @@ public interface SailingService extends RemoteService {
|
||||
|
||||
void removeLeaderboardGroup(String groupName);
|
||||
|
||||
LeaderboardGroupDTO createLeaderboardGroup(String groupName, String description, int[] overallLeaderboardDiscardThresholds,
|
||||
LeaderboardGroupDTO createLeaderboardGroup(String groupName, String description,
|
||||
boolean displayGroupsInReverseOrder, int[] overallLeaderboardDiscardThresholds,
|
||||
ScoringSchemeType overallLeaderboardScoringSchemeType);
|
||||
|
||||
void updateLeaderboardGroup(String oldName, String newName, String description, List<String> leaderboardNames,
|
||||
@@ -264,4 +265,6 @@ public interface SailingService extends RemoteService {
|
||||
StrippedLeaderboardDTO getLeaderboard(String leaderboardName);
|
||||
|
||||
void suppressCompetitorInLeaderboard(String leaderboardName, String competitorIdAsString, boolean suppressed);
|
||||
|
||||
void updateLeaderboardColumnFactor(String leaderboardName, String columnName, Double newFactor);
|
||||
}
|
||||
+7
-2
@@ -302,10 +302,11 @@ public interface SailingServiceAsync {
|
||||
|
||||
/**
|
||||
* Creates a new group with the name <code>groupname</code>, the description <code>description</code> and an empty list of leaderboards.<br/>
|
||||
* @param displayGroupsInReverseOrder TODO
|
||||
*/
|
||||
void createLeaderboardGroup(String groupName, String description,
|
||||
int[] overallLeaderboardDiscardThresholds, ScoringSchemeType overallLeaderboardScoringSchemeType,
|
||||
AsyncCallback<LeaderboardGroupDTO> callback);
|
||||
boolean displayGroupsInReverseOrder, int[] overallLeaderboardDiscardThresholds,
|
||||
ScoringSchemeType overallLeaderboardScoringSchemeType, AsyncCallback<LeaderboardGroupDTO> callback);
|
||||
|
||||
/**
|
||||
* Updates the data of the group with the name <code>oldName</code>.
|
||||
@@ -421,4 +422,8 @@ public interface SailingServiceAsync {
|
||||
|
||||
void suppressCompetitorInLeaderboard(String leaderboardName, String competitorIdAsString, boolean suppressed, AsyncCallback<Void> asyncCallback);
|
||||
|
||||
void updateLeaderboardColumnFactor(String leaderboardName, String columnName, Double newFactor,
|
||||
AsyncCallback<Void> callback);
|
||||
|
||||
|
||||
}
|
||||
+21
@@ -389,6 +389,8 @@ public interface StringMessages extends Messages {
|
||||
String racesWithNamePrefix();
|
||||
String maximumSpeedOverGroundInKnots();
|
||||
String totalTimeSailedDownwindInSeconds();
|
||||
String totalTimeSailedUpwindInSeconds();
|
||||
String totalTimeSailedReachingInSeconds();
|
||||
String totalTimeSailedInSeconds();
|
||||
String overallDetailsToShow();
|
||||
String hhmmssUnit();
|
||||
@@ -405,4 +407,23 @@ public interface StringMessages extends Messages {
|
||||
String unsuppress();
|
||||
String suppressedCompetitors();
|
||||
String pleaseSelectASeries();
|
||||
String pleaseSelectARace();
|
||||
String displayGroupsInReverseOrder();
|
||||
String actionConfigureUrl();
|
||||
String configureLeaderboardUrlDescription();
|
||||
String embedded();
|
||||
String additionalUrlSettings();
|
||||
String restrictToSingleSelectedRace();
|
||||
String expandSelectedRace();
|
||||
String showRaceDetails();
|
||||
String numberOfRaces();
|
||||
String numberOfRacesMustBeNonNegativeNumber();
|
||||
String chooseTheWayYouSelectRaces();
|
||||
String selectFromAllRaces();
|
||||
String selectANumberOfRaces();
|
||||
String numberOfLastNRaces();
|
||||
String expandLastRace();
|
||||
String factor();
|
||||
String errorUpdatingIsMedalRace(String message);
|
||||
String maneuverLoss();
|
||||
}
|
||||
+22
-2
@@ -390,6 +390,8 @@ actionAddRaces=Add races
|
||||
racesWithNamePrefix=races with name prefix
|
||||
maximumSpeedOverGroundInKnots=Max SOG
|
||||
totalTimeSailedDownwindInSeconds=Total time downwind
|
||||
totalTimeSailedUpwindInSeconds=Total time upwind
|
||||
totalTimeSailedReachingInSeconds=Total time reaching
|
||||
totalTimeSailedInSeconds=Total time
|
||||
hhmmssUnit=hh:mm:ss
|
||||
actionAddWindData=Add wind data
|
||||
@@ -405,5 +407,23 @@ isPublic=Is public
|
||||
suppress=Suppress
|
||||
unsuppress=Unsuppress
|
||||
suppressedCompetitors=Suppressed Competitors
|
||||
pleaseSelectASeries=Please select a series.
|
||||
|
||||
pleaseSelectASeries=Please select a series
|
||||
pleaseSelectARace=Please select a race
|
||||
displayGroupsInReverseOrder=Display groups in reverse order
|
||||
actionConfigureUrl=Configure URL
|
||||
configureLeaderboardUrlDescription=Configure a leaderboard and obtain the resulting URL from the link
|
||||
embedded=Embedded
|
||||
additionalUrlSettings=Additional URL Settings
|
||||
restrictToSingleSelectedRace=Restrict to single selected race
|
||||
expandSelectedRace=Expand selected race
|
||||
showRaceDetails=Allow for race details
|
||||
numberOfRaces=Number of races
|
||||
numberOfRacesMustBeNonNegativeNumber=Please enter the number of last races to be displayed
|
||||
chooseTheWayYouSelectRaces=Choose the way you select races
|
||||
selectFromAllRaces=Select from all races
|
||||
selectANumberOfRaces=Select a number of races
|
||||
numberOfLastNRaces=Number of most current races to show
|
||||
expandLastRace=Always expand last race shown
|
||||
factor=Factor
|
||||
errorUpdatingIsMedalRace=Error updating the medal race setting: {0}
|
||||
maneuverLoss=Maneuver loss
|
||||
+23
-2
@@ -389,8 +389,10 @@ overallStandings=Gesamtstand
|
||||
type=Typ
|
||||
actionAddRaces=Rennen hinzuf�gen
|
||||
racesWithNamePrefix=Rennen mit Namens-Pr�fix
|
||||
maximumSpeedOverGroundInKnots=Max F�G
|
||||
maximumSpeedOverGroundInKnots=Max FüG
|
||||
totalTimeSailedDownwindInSeconds=Gesamtzeit Vorwind
|
||||
totalTimeSailedUpwindInSeconds=Gesamtzeit Kreuz
|
||||
totalTimeSailedReachingInSeconds=Gesamtzeit Holeschlag
|
||||
totalTimeSailedInSeconds=Gesamtzeit
|
||||
hhmmssUnit=hh:mm:ss
|
||||
actionAddWindData=Winddaten hinzufügen
|
||||
@@ -406,4 +408,23 @@ isPublic=Öffentlich zugänglich
|
||||
suppress=Entfernen
|
||||
unsuppress=Wieder hinzufügen
|
||||
suppressedCompetitors=Unterdrückte Wettkampfteilnehmer
|
||||
pleaseSelectASeries=Bitte wählen Sie eine Serie aus.
|
||||
pleaseSelectASeries=Bitte wählen Sie eine Serie aus
|
||||
pleaseSelectARace=Bitte wählen Sie ein Rennen aus
|
||||
displayGroupsInReverseOrder=Zeige die Gruppen in umgekehrter Reihenfolge
|
||||
actionConfigureUrl=URL konfigurieren
|
||||
configureLeaderboardUrlDescription=Ergebnisansicht konfigurieren. Die fertige URL kann dem Link entnommen werden.
|
||||
embedded=Eingebettet
|
||||
additionalUrlSettings=Weitere URL-relevante Einstellungen
|
||||
restrictToSingleSelectedRace=Nur einzelnes ausgewähltes Rennen zeigen
|
||||
expandSelectedRace=Details des ausgewähltes Rennens zeigen
|
||||
showRaceDetails=Details anbieten
|
||||
numberOfRaces=Anzahl Rennen
|
||||
numberOfRacesMustBeNonNegativeNumber=Bitte Anzahl der anzuzeigenden letzten Rennen eingeben
|
||||
chooseTheWayYouSelectRaces=Wie wollen die anzuzeigenden Rennen ausgewählt werden?
|
||||
selectFromAllRaces=Aus allen Rennen auswählen
|
||||
selectANumberOfRaces=Eine Anzahl anzuzeigender Rennen auswählen
|
||||
numberOfLastNRaces=Anzahl der zu zeigenden aktuellsten Rennen
|
||||
expandLastRace=Immer letztes gezeigtes Rennen expandieren
|
||||
factor=Faktor
|
||||
errorUpdatingIsMedalRace=Fehler beim Ändern der Medaillenrennen-Einstellung: {0}
|
||||
maneuverLoss=Manöververlust
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.sap.sailing.gwt.ui.leaderboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
||||
|
||||
public abstract class AbstractRaceColumnSelection implements RaceColumnSelection {
|
||||
@Override
|
||||
public boolean isSelected(String raceColumnName) {
|
||||
return Util.contains(getSelectedRaceColumnNames(), raceColumnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> getSelectedRaceColumnNames() {
|
||||
List<String> names = new ArrayList<String>();
|
||||
for (RaceColumnDTO column : getSelectedRaceColumns()) {
|
||||
names.add(column.name);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<RaceColumnDTO> getSelectedRaceColumnsOrderedAsInLeaderboard(LeaderboardDTO leaderboard) {
|
||||
Iterable<RaceColumnDTO> selectedColumns = getSelectedRaceColumns();
|
||||
List<RaceColumnDTO> result = new ArrayList<RaceColumnDTO>();
|
||||
for (RaceColumnDTO column : leaderboard.getRaceList()) {
|
||||
if (Util.contains(selectedColumns, column)) {
|
||||
result.add(column);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.sap.sailing.gwt.ui.leaderboard;
|
||||
|
||||
import com.google.gwt.i18n.client.NumberFormat;
|
||||
import com.sap.sailing.domain.common.SortingOrder;
|
||||
import com.sap.sailing.gwt.ui.client.NumberFormatterFactory;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardRowDTO;
|
||||
|
||||
public class AbstractTimeInHoursMinutesSecondsColumn extends FormattedDoubleLegDetailColumn {
|
||||
|
||||
public AbstractTimeInHoursMinutesSecondsColumn(String title, String unit,
|
||||
com.sap.sailing.gwt.ui.leaderboard.LegDetailColumn.LegDetailField<Double> field, int decimals, SortingOrder preferredSortingOrder,
|
||||
String headerStyle, String columnStyle) {
|
||||
super(title, unit, field, decimals, preferredSortingOrder, headerStyle, columnStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStringValueToRender(LeaderboardRowDTO object) {
|
||||
Double timeInSeconds = getDoubleValue(object);
|
||||
String result;
|
||||
if (timeInSeconds == null) {
|
||||
result = null;
|
||||
} else {
|
||||
int hh = (int) (timeInSeconds / 3600);
|
||||
int mm = (int) ((timeInSeconds - 3600 * hh) / 60);
|
||||
int ss = (int) (timeInSeconds - 3600 * hh - 60 * mm);
|
||||
NumberFormat numberFormat = NumberFormatterFactory.getDecimalFormat(2, 0);
|
||||
result = "" + numberFormat.format(hh) + ":" + numberFormat.format(mm) + ":" + numberFormat.format(ss);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+61
-6
@@ -1,27 +1,37 @@
|
||||
package com.sap.sailing.gwt.ui.leaderboard;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.dom.client.Style.Float;
|
||||
import com.google.gwt.event.dom.client.ChangeEvent;
|
||||
import com.google.gwt.event.dom.client.ChangeHandler;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.ListBox;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.impl.Util.Pair;
|
||||
import com.sap.sailing.gwt.ui.actions.AsyncActionsExecutor;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionProvider;
|
||||
import com.sap.sailing.gwt.ui.client.ErrorReporter;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionModel;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
|
||||
import com.sap.sailing.gwt.ui.client.RaceTimesCalculationUtil;
|
||||
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider;
|
||||
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProviderListener;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.TimeRangeChangeListener;
|
||||
import com.sap.sailing.gwt.ui.client.TimeRangeWithZoomModel;
|
||||
import com.sap.sailing.gwt.ui.client.TimeRangeWithZoomProvider;
|
||||
import com.sap.sailing.gwt.ui.client.Timer;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.charts.MultiChartPanel;
|
||||
import com.sap.sailing.gwt.ui.shared.charts.MultiChartSettings;
|
||||
import com.sap.sailing.gwt.ui.shared.components.ComponentToolbar;
|
||||
@@ -32,27 +42,36 @@ import com.sap.sailing.gwt.ui.shared.components.ComponentToolbar;
|
||||
* @author Benjamin Ebling, Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class CompareCompetitorsChartDialog extends DialogBoxExt {
|
||||
public class CompareCompetitorsChartDialog extends DialogBoxExt implements RaceTimesInfoProviderListener {
|
||||
private final RaceSelectionProvider raceSelectionProvider;
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final TimeRangeWithZoomProvider timeRangeWithZoomProvider;
|
||||
private final Timer timer;
|
||||
private final ErrorReporter errorReporter;
|
||||
|
||||
private final MultiChartPanel multiChartPanel;
|
||||
|
||||
final ListBox racesListBox;
|
||||
private final ListBox racesListBox;
|
||||
|
||||
public CompareCompetitorsChartDialog(SailingServiceAsync sailingService,
|
||||
List<RegattaAndRaceIdentifier> races, final CompetitorSelectionProvider competitorSelectionProvider, Timer timer,
|
||||
StringMessages stringConstants, ErrorReporter errorReporter) {
|
||||
List<RegattaAndRaceIdentifier> races, final RaceTimesInfoProvider raceTimesInfoProvider, final CompetitorSelectionProvider competitorSelectionProvider,
|
||||
Timer timer, StringMessages stringConstants, ErrorReporter errorReporter) {
|
||||
super(new Label(stringConstants.close()));
|
||||
this.sailingService = sailingService;
|
||||
this.timer = timer;
|
||||
this.errorReporter = errorReporter;
|
||||
this.timeRangeWithZoomProvider = new TimeRangeWithZoomModel();
|
||||
this.setPopupPosition(15, 15);
|
||||
this.setHTML(stringConstants.compareCompetitors());
|
||||
this.setWidth(Window.getClientWidth() - 250 + "px");
|
||||
this.setAnimationEnabled(true);
|
||||
|
||||
raceTimesInfoProvider.addRaceTimesInfoProviderListener(this);
|
||||
raceSelectionProvider = new RaceSelectionModel();
|
||||
raceSelectionProvider.setAllRaces(races);
|
||||
|
||||
multiChartPanel = new MultiChartPanel(sailingService, new AsyncActionsExecutor(), competitorSelectionProvider, raceSelectionProvider,
|
||||
timer, new TimeRangeWithZoomModel(), stringConstants, errorReporter, false, false);
|
||||
timer, timeRangeWithZoomProvider, stringConstants, errorReporter, false, false);
|
||||
multiChartPanel.setSize("100%", "100%");
|
||||
|
||||
VerticalPanel contentPanel = new VerticalPanel();
|
||||
@@ -66,7 +85,7 @@ public class CompareCompetitorsChartDialog extends DialogBoxExt {
|
||||
HorizontalPanel raceSelectionPanel = new HorizontalPanel();
|
||||
raceSelectionPanel.setSpacing(3);
|
||||
racesListBox = new ListBox();
|
||||
raceSelectionPanel.add(new Label("Select a race:"));
|
||||
raceSelectionPanel.add(new Label(stringConstants.pleaseSelectARace() + ":"));
|
||||
raceSelectionPanel.add(racesListBox);
|
||||
for (RegattaAndRaceIdentifier race : raceSelectionProvider.getAllRaces()) {
|
||||
racesListBox.addItem(race.toString());
|
||||
@@ -101,7 +120,43 @@ public class CompareCompetitorsChartDialog extends DialogBoxExt {
|
||||
}
|
||||
|
||||
private void selectRace(final RegattaAndRaceIdentifier selectedRace) {
|
||||
sailingService.getRaceTimesInfo(selectedRace, new AsyncCallback<RaceTimesInfoDTO>() {
|
||||
@Override
|
||||
public void onSuccess(RaceTimesInfoDTO raceTimesInfo) {
|
||||
updateMinMax(raceTimesInfo);
|
||||
raceSelectionProvider.setSelection(Collections.singletonList(selectedRace));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
errorReporter.reportError("Error obtaining race times: " + caught.getMessage(), true /*silentMode */);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void updateMinMax(RaceTimesInfoDTO newRaceTimesInfo) {
|
||||
Pair<Date, Date> raceMinMax = RaceTimesCalculationUtil.caluclateRaceMinMax(timer, newRaceTimesInfo);
|
||||
|
||||
Date min = raceMinMax.getA();
|
||||
Date max = raceMinMax.getB();
|
||||
|
||||
// never reduce max if it was already set
|
||||
if (min != null && max != null && (timeRangeWithZoomProvider.getToTime() == null || timeRangeWithZoomProvider.getToTime().before(max))) {
|
||||
timeRangeWithZoomProvider.setTimeRange(min, max, new TimeRangeChangeListener[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private RegattaAndRaceIdentifier getSelectedRace() {
|
||||
return raceSelectionProvider.getSelectedRaces().size() > 0 ? raceSelectionProvider.getSelectedRaces().get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceTimesInfosReceived(Map<RegattaAndRaceIdentifier, RaceTimesInfoDTO> raceTimesInfos) {
|
||||
RegattaAndRaceIdentifier selectedRace = getSelectedRace();
|
||||
if(selectedRace != null) {
|
||||
updateMinMax(raceTimesInfos.get(selectedRace));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package com.sap.sailing.gwt.ui.leaderboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettings.RaceColumnSelectionStrategies;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
||||
|
||||
/**
|
||||
* An explicit selection of race columns. Requests to add to or clear the selection are respected. If an updated version
|
||||
* of the leaderboard is announced, race columns added are implicitly also added to this selection.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class ExplicitRaceColumnSelection extends AbstractRaceColumnSelection implements RaceColumnSelection {
|
||||
private final Map<String, RaceColumnDTO> selectedRaceColumns;
|
||||
|
||||
public ExplicitRaceColumnSelection() {
|
||||
this.selectedRaceColumns = new HashMap<String, RaceColumnDTO>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<RaceColumnDTO> getSelectedRaceColumns() {
|
||||
return selectedRaceColumns.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestRaceColumnSelection(String raceColumnName, RaceColumnDTO column) {
|
||||
selectedRaceColumns.put(raceColumnName, column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestClear() {
|
||||
selectedRaceColumns.clear();
|
||||
}
|
||||
|
||||
private List<RaceColumnDTO> getRacesAddedNew(LeaderboardDTO oldLeaderboard, LeaderboardDTO newLeaderboard) {
|
||||
List<RaceColumnDTO> result = new ArrayList<RaceColumnDTO>();
|
||||
for (RaceColumnDTO s : newLeaderboard.getRaceList()) {
|
||||
if (oldLeaderboard == null || !leaderboardContainsColumnNamed(oldLeaderboard, s.getRaceColumnName())) {
|
||||
result.add(s);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean leaderboardContainsColumnNamed(LeaderboardDTO leaderboard, String raceColumnName) {
|
||||
for (RaceColumnDTO column : leaderboard.getRaceList()) {
|
||||
if (column.getRaceColumnName().equals(raceColumnName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Considers the {@link #preSelectedRace} field as follows: if <code>null</code>, all race columns that
|
||||
* <code>leaderboard</code> adds on top of the existing <code>oldLeaderboard</code> are returned.
|
||||
* Otherwise, the column list obtained as described before is filtered such that only columns pass whose race
|
||||
* identifier equals {@link #preSelectedRace}.
|
||||
*
|
||||
* @param newLeaderboard
|
||||
* the new leaderboard, not yet {@link #setLeaderboard(LeaderboardDTO) set}, so as to allow for a
|
||||
* comparison
|
||||
*/
|
||||
protected List<RaceColumnDTO> getRaceColumnsToAddImplicitly(LeaderboardDTO newLeaderboard, LeaderboardDTO oldLeaderboard) {
|
||||
List<RaceColumnDTO> columnsToAddImplicitly = getRacesAddedNew(oldLeaderboard, newLeaderboard);
|
||||
return columnsToAddImplicitly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void autoUpdateRaceColumnSelectionForUpdatedLeaderboard(LeaderboardDTO oldLeaderboard, LeaderboardDTO newLeaderboard) {
|
||||
for (RaceColumnDTO selectedRaceColumn : getRaceColumnsToAddImplicitly(newLeaderboard, oldLeaderboard)) {
|
||||
requestRaceColumnSelection(selectedRaceColumn.name, selectedRaceColumn);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceColumnSelectionStrategies getType() {
|
||||
return RaceColumnSelectionStrategies.EXPLICIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getNumberOfLastRaceColumnsToShow() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.sap.sailing.gwt.ui.leaderboard;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceColumnDTO;
|
||||
|
||||
/**
|
||||
* A variant of {@link ExplicitRaceColumnSelection} which has a pre-selected race. As opposed to the base class,
|
||||
* a new leaderboard column is added implicitly only if it is linked to the pre-selected race.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class ExplicitRaceColumnSelectionWithPreselectedRace extends ExplicitRaceColumnSelection {
|
||||
private final RaceIdentifier preSelectedRace;
|
||||
|
||||
/**
|
||||
* @param preSelectedRace must be non-<code>null</code>. Otherwise, you may use the superclass instead.
|
||||
*/
|
||||
public ExplicitRaceColumnSelectionWithPreselectedRace(RaceIdentifier preSelectedRace) {
|
||||
super();
|
||||
assert preSelectedRace != null;
|
||||
this.preSelectedRace = preSelectedRace;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<RaceColumnDTO> getRaceColumnsToAddImplicitly(LeaderboardDTO newLeaderboard,
|
||||
LeaderboardDTO oldLeaderboard) {
|
||||
List<RaceColumnDTO> columnsToAddImplicitly = super.getRaceColumnsToAddImplicitly(newLeaderboard, oldLeaderboard);
|
||||
if (preSelectedRace != null) {
|
||||
for (Iterator<RaceColumnDTO> i = columnsToAddImplicitly.iterator(); i.hasNext();) {
|
||||
RaceColumnDTO next = i.next();
|
||||
if (!next.containsRace(preSelectedRace)) {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
return columnsToAddImplicitly;
|
||||
}
|
||||
}
|
||||
+1
-19
@@ -1,8 +1,6 @@
|
||||
package com.sap.sailing.gwt.ui.leaderboard;
|
||||
|
||||
import com.google.gwt.i18n.client.NumberFormat;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.gwt.ui.client.NumberFormatterFactory;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.LeaderboardRowDTO;
|
||||
|
||||
@@ -12,7 +10,7 @@ import com.sap.sailing.gwt.ui.shared.LeaderboardRowDTO;
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class KingOfTheDownwindColumn extends FormattedDoubleLegDetailColumn {
|
||||
public class KingOfTheDownwindColumn extends AbstractTimeInHoursMinutesSecondsColumn {
|
||||
|
||||
private static class KingOfTheDownwindField implements LegDetailField<Double> {
|
||||
@Override
|
||||
@@ -29,20 +27,4 @@ public class KingOfTheDownwindColumn extends FormattedDoubleLegDetailColumn {
|
||||
headerStyle, columnStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStringValueToRender(LeaderboardRowDTO object) {
|
||||
Double timeInSeconds = getDoubleValue(object);
|
||||
String result;
|
||||
if (timeInSeconds == null) {
|
||||
result = null;
|
||||
} else {
|
||||
int hh = (int) (timeInSeconds / 3600);
|
||||
int mm = (int) ((timeInSeconds - 3600 * hh) / 60);
|
||||
int ss = (int) (timeInSeconds - 3600 * hh - 60 * mm);
|
||||
NumberFormat numberFormat = NumberFormatterFactory.getDecimalFormat(2, 0);
|
||||
result = "" + numberFormat.format(hh) + ":" + numberFormat.format(mm) + ":" + numberFormat.format(ss);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Loaded 100 of 243 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user