Merge branch 'master' into bug3378

Conflicts:
	java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java

Change-Id: I25bdf84204d891856ce0c71d5585885fc0216795
This commit is contained in:
Axel Uhl committed 2015-12-11 16:39:39 +01:00
commit 0dbd65f20e
147 files changed
+1703 -2423

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@ for i in $*; do
gzip -cd $i
else
cat $i
fi | iconv -f ISO-8859-1 -t UTF8 |
fi | recode ISO-8859-1..UTF-8 |
sed -e 's/^\([^T]*\)T\([^.]*\)[^ ]* [^ ]* \([^:]*\):[^ ]* [^ ]* [^ ]* [^ ]* [^ ]* [^ ]* \([^ ]*\) \([^ ]*\) [^ ]* \(\"[^"]*\"\) \(\"[^"]*\"\).*$/'$PREFIX' \3 - - [\1:\2 +0000] \6 \4 \5 "http:\/\/'$PREFIX'" \7/' |
sed -e 's/\[\([0-9]*\)-01-\([0-9]*\):/\[\2\/Jan\/\1:/' |
sed -e 's/\[\([0-9]*\)-02-\([0-9]*\):/\[\2\/Feb\/\1:/' |
+3 -3
View File
@@ -28,7 +28,7 @@ for i in $*; do
gzip -cd $i
else
cat $i
fi | iconv -f ISO-8859-1 -t UTF8 | sed -e 's/^\([^ ]*\) \([^ ]*\) \([^ ]*\) \([^ ]*\) \[\([^:]*\):\([^]]*\)\] \"[^"]*\" [^ ]* [^ ]* \"[^"]*\" \"\([^"]*\)\"/\1 \2 \5 \7/' | while read referrer hit; do
fi | recode ISO-8859-1..UTF-8 | sed -e 's/^\([^ ]*\) \([^ ]*\) \([^ ]*\) \([^ ]*\) \[\([^:]*\):\([^]]*\)\] \"[^"]*\" [^ ]* [^ ]* \"[^"]*\" \"\([^"]*\)\"/\1 \2 \5 \7/' | while read referrer hit; do
echo "$hit" >>${STATS}/${referrer}.ips
done
echo "$i" >>$VISITED_FILES
@@ -49,7 +49,7 @@ for month in `cat $MONTHS`; do
echo -n "`basename $i .ips` "
cat $i | grep "^[^ ]* [0-9]*/$month .*" | sort -u | wc | awk '{ print $1; }'
# TODO consider producing an AWStats configuration file for each virtual host name and splitting all new logs into virtual host name-specific log files
done | tee $STATS/unique-ips-days-useragents-per-event-$month
echo "Wrote per-month results to $STATS/unique-ips-days-useragents-per-event-$month"
done | tee $STATS/unique-ips-days-useragents-per-event-`echo $month | tr / -`
echo "Wrote per-month results to $STATS/unique-ips-days-useragents-per-event-`echo $month | tr / -`"
done
echo "Done at `date`."
@@ -11,6 +11,6 @@ for month in `cat $MONTHS`; do
cat $i | grep "^[^ ]* [0-9]*/$month .*" | sort -u | wc | awk '{ print $1; }'
# TODO consider producing an AWStats configuration file for each virtual host name and splitting all new logs into virtual host name-specific log files
done | tee $STATS/unique-ips-days-useragents-per-event-`echo $month | tr / -`
echo "Wrote per-month results to $STATS/unique-ips-days-useragents-per-event-$month"
echo "Wrote per-month results to $STATS/unique-ips-days-useragents-per-event-`echo $month | tr / -`"
done
echo "Done."
@@ -94,8 +94,8 @@ public class TracTrac {
new MillisecondsTimePoint(record.getTrackingStartTime().asMillis()),
new MillisecondsTimePoint(record.getTrackingEndTime().asMillis()),
raceLogStore, regattaLogStore,
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, /* simulateWithStartTimeNow */
false, /*useTracTracMarkPassings*/ false,
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, /* offsetToStartTimeOfSimulatedRace */
null, /*useTracTracMarkPassings*/ false,
/* tracTracUsername */"", /* tracTracPassword */"", record.getRaceStatus(),
record.getRaceVisibility());
} else {
@@ -167,12 +167,13 @@ public abstract class AbstractLeaderboardDTO implements Serializable {
* must not be null
*/
public RaceColumnDTO addRace(String raceColumnName, Double explicitFactor, double effectiveFactor,
String regattaName, String seriesName, FleetDTO fleetDTO, boolean medalRace, RegattaAndRaceIdentifier trackedRaceIdentifier, RaceDTO race) {
String regattaName, String seriesName, FleetDTO fleetDTO, boolean medalRace,
RegattaAndRaceIdentifier trackedRaceIdentifier, RaceDTO race, boolean isMetaLeaderboardColumn) {
assert fleetDTO != null;
RaceColumnDTO raceColumnDTO = getRaceColumnByName(raceColumnName);
if (raceColumnDTO == null) {
raceColumnDTO = RaceColumnDTOFactory.INSTANCE.createRaceColumnDTO(raceColumnName, medalRace,
explicitFactor, regattaName, seriesName);
explicitFactor, regattaName, seriesName, isMetaLeaderboardColumn);
races.add(raceColumnDTO);
}
raceColumnDTO.setEffectiveFactor(effectiveFactor);
@@ -191,9 +192,10 @@ public abstract class AbstractLeaderboardDTO implements Serializable {
return raceColumnDTO;
}
public RaceColumnDTO createEmptyRaceColumn(String raceColumnName, boolean medalRace, String regattaName, String seriesName) {
public RaceColumnDTO createEmptyRaceColumn(String raceColumnName, boolean medalRace, String regattaName,
String seriesName, boolean isMetaLeaderboardColumn) {
final RaceColumnDTO raceColumn = RaceColumnDTOFactory.INSTANCE.createRaceColumnDTO(raceColumnName,
medalRace, /* explicit factor */ null, regattaName, seriesName);
medalRace, /* explicit factor */ null, regattaName, seriesName, isMetaLeaderboardColumn);
races.add(raceColumn);
return raceColumn;
}
@@ -345,6 +347,7 @@ public abstract class AbstractLeaderboardDTO implements Serializable {
result = prime * result + ((competitorDisplayNames == null) ? 0 : competitorDisplayNames.hashCode());
result = prime * result + Arrays.hashCode(discardThresholds);
result = prime * result + (hasCarriedPoints ? 1231 : 1237);
result = prime * result + ((type == null) ? 0 : type.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((scoringScheme == null) ? 0 : scoringScheme.hashCode());
if (races == null) {
@@ -0,0 +1,112 @@
package com.sap.sailing.domain.common.dto;
import java.util.Date;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.TimingConstants;
/**
* Master data about a single race that is to be transferred to the client. Holds only timing and a bit
* of information about the tracked race, if any. See also {@link RaceDTO} for a more comprehensive set
* of data about a race to be serialized to a client.<p>
*
* @author Axel Uhl (d043530)
*
*/
public class BasicRaceDTO extends NamedDTO {
private static final long serialVersionUID = -7884808503795229609L;
public Date startOfRace;
public Date endOfRace;
public TrackedRaceDTO trackedRace;
public BasicRaceDTO() {} // for GWT serialization only
public BasicRaceDTO(RegattaAndRaceIdentifier raceIdentifier, TrackedRaceDTO trackedRace) {
super(raceIdentifier.getRaceName());
this.trackedRace = trackedRace;
}
/**
* @see {@link TrackedRace#isLive} for further explanation.
* @param serverTimePointAsMillis
* the time point (in server clock time) at which to determine whether the race is/was live
* @return <code>true</code> if <code>serverTimePointAsMillis</code> is between (inclusively) the start and end time
* point of the "live" interval as defined above.
*/
public boolean isLive(long serverTimePointAsMillis) {
final Date startOfLivePeriod;
final Date endOfLivePeriod;
if (trackedRace == null || !trackedRace.hasGPSData || !trackedRace.hasWindData) {
startOfLivePeriod = null;
endOfLivePeriod = null;
} else {
if (startOfRace == null) {
startOfLivePeriod = trackedRace.startOfTracking;
} else {
startOfLivePeriod = new Date(startOfRace.getTime() - TimingConstants.PRE_START_PHASE_DURATION_IN_MILLIS);
}
if (endOfRace == null) {
if (trackedRace.timePointOfNewestEvent != null) {
endOfLivePeriod = new Date(trackedRace.timePointOfNewestEvent.getTime()
+ TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS);
} else {
endOfLivePeriod = null;
}
} else {
endOfLivePeriod = new Date(endOfRace.getTime() + TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS);
}
}
// if an empty timepoint is given then take the start of the race
if (serverTimePointAsMillis == 0) {
serverTimePointAsMillis = startOfLivePeriod.getTime()+1;
}
// whenLastTrackedRaceWasLive is null if there is no tracked race for fleet, or the tracked race hasn't started yet at the server time
// when this DTO was assembled, or there were no GPS or wind data
final boolean result =
startOfLivePeriod != null &&
endOfLivePeriod != null &&
startOfLivePeriod.getTime() <= serverTimePointAsMillis &&
serverTimePointAsMillis <= endOfLivePeriod.getTime();
return result;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((endOfRace == null) ? 0 : endOfRace.hashCode());
result = prime * result + ((startOfRace == null) ? 0 : startOfRace.hashCode());
result = prime * result + ((trackedRace == null) ? 0 : trackedRace.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
BasicRaceDTO other = (BasicRaceDTO) obj;
if (endOfRace == null) {
if (other.endOfRace != null)
return false;
} else if (!endOfRace.equals(other.endOfRace))
return false;
if (startOfRace == null) {
if (other.startOfRace != null)
return false;
} else if (!startOfRace.equals(other.startOfRace))
return false;
if (trackedRace == null) {
if (other.trackedRace != null)
return false;
} else if (!trackedRace.equals(other.trackedRace))
return false;
return true;
}
}
@@ -62,7 +62,6 @@ public class LeaderboardDTO extends AbstractLeaderboardDTO implements Serializab
/**
* @param uuidGenerator used to provide the {@link #id ID} for this object (see also {@link #getId()}) and for any clones produced
* from it by the {@link #clone()} operation.
* @param hasOverallDetails TODO
*/
public LeaderboardDTO(Date timePointOfLastCorrectionsValidity, String comment, ScoringSchemeType scoringScheme, boolean higherScoreIsBetter, UUIDGenerator uuidGenerator, boolean hasOverallDetails) {
initCollections();
@@ -79,7 +78,7 @@ public class LeaderboardDTO extends AbstractLeaderboardDTO implements Serializab
this.suppressedCompetitors = new ArrayList<CompetitorDTO>();
}
public LeaderboardDTO(String id) {
protected LeaderboardDTO(String id) {
initCollections();
this.id = id;
}
@@ -0,0 +1,49 @@
package com.sap.sailing.domain.common.dto;
import java.util.ArrayList;
public class MetaLeaderboardRaceColumnDTO extends RaceColumnDTO {
private static final long serialVersionUID = 6152752963316150432L;
private ArrayList<BasicRaceDTO> raceList = new ArrayList<BasicRaceDTO>();
public boolean isLive(FleetDTO fleet, long serverTimePointAsMillis) {
for (BasicRaceDTO race : raceList) {
if (race.isLive(serverTimePointAsMillis)) {
return true;
}
}
return false;
}
public void addRace(BasicRaceDTO race) {
raceList.add(race);
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((raceList == null) ? 0 : raceList.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
MetaLeaderboardRaceColumnDTO other = (MetaLeaderboardRaceColumnDTO) obj;
if (raceList == null) {
if (other.raceList != null)
return false;
} else if (!raceList.equals(other.raceList))
return false;
return true;
}
}
@@ -7,15 +7,17 @@ public class RaceColumnDTOFactory {
* @param regattaName
* must not be <code>null</code> if <code>seriesName</code> is not <code>null</code>
* @param seriesName
* when <code>null</code>, a regular {@link RaceColumnDTO} will be produced and initialized from the
* properties passed; otherwise, a {@link RaceColumnInSeriesDTO} will be created.
* when <code>null</code>, a regular {@link RaceColumnDTO} or {@link MetaLeaderboardRaceColumnDTO} will
* be produced (depending on <code>isMetaLeaderboardColumn</code>) and initialized from the properties
* passed; otherwise, a {@link RaceColumnInSeriesDTO} will be created.
*/
public RaceColumnDTO createRaceColumnDTO(String columnName, boolean isMedal, Double explicitFactor, String regattaName, String seriesName) {
public RaceColumnDTO createRaceColumnDTO(String columnName, boolean isMedal, Double explicitFactor,
String regattaName, String seriesName, boolean isMetaLeaderboardColumn) {
final RaceColumnDTO raceColumnDTO;
if (seriesName != null) {
raceColumnDTO = new RaceColumnInSeriesDTO(seriesName, regattaName);
} else {
raceColumnDTO = new RaceColumnDTO();
raceColumnDTO = isMetaLeaderboardColumn ? new MetaLeaderboardRaceColumnDTO() : new RaceColumnDTO();
}
fillRaceColumnDTO(raceColumnDTO, columnName, isMedal, explicitFactor);
return raceColumnDTO;
@@ -1,10 +1,7 @@
package com.sap.sailing.domain.common.dto;
import java.util.Date;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.TimingConstants;
/**
* Master data about a single race that is to be transferred to the client.<p>
@@ -12,7 +9,7 @@ import com.sap.sailing.domain.common.TimingConstants;
* @author Axel Uhl (d043530)
*
*/
public class RaceDTO extends NamedDTO {
public class RaceDTO extends BasicRaceDTO {
private static final long serialVersionUID = 2613189982608149975L;
public enum RaceLiveState { NOT_TRACKED, TRACKED, TRACKED_AND_LIVE, TRACKED_BUT_NOT_SCHEDULED };
@@ -24,13 +21,10 @@ public class RaceDTO extends NamedDTO {
*/
public boolean isTracked;
public Date startOfRace;
public Date endOfRace;
public RaceStatusDTO status;
public PlacemarkOrderDTO places;
public TrackedRaceDTO trackedRace;
public TrackedRaceStatisticsDTO trackedRaceStatistics;
private String regattaName;
@@ -43,19 +37,18 @@ public class RaceDTO extends NamedDTO {
}
public RaceDTO(RegattaAndRaceIdentifier raceIdentifier, TrackedRaceDTO trackedRace, boolean isCurrentlyTracked) {
super(raceIdentifier.getRaceName());
super(raceIdentifier, trackedRace);
this.regattaName = raceIdentifier.getRegattaName();
this.trackedRace = trackedRace;
this.isTracked = isCurrentlyTracked;
}
public RaceLiveState getLiveState(long serverTimePointAsMillis) {
RaceLiveState result = RaceLiveState.NOT_TRACKED;
if(trackedRace != null && trackedRace.hasGPSData && trackedRace.hasWindData) {
if (trackedRace != null && trackedRace.hasGPSData && trackedRace.hasWindData) {
result = RaceLiveState.TRACKED;
if(isLive(serverTimePointAsMillis)) {
if (isLive(serverTimePointAsMillis)) {
result = RaceLiveState.TRACKED_AND_LIVE;
if(startOfRace == null) {
if (startOfRace == null) {
result = RaceLiveState.TRACKED_BUT_NOT_SCHEDULED;
}
}
@@ -71,64 +64,15 @@ public class RaceDTO extends NamedDTO {
return regattaName;
}
/**
* @see {@link TrackedRace#isLive} for further explanation.
* @param serverTimePointAsMillis
* the time point (in server clock time) at which to determine whether the race is/was live
* @return <code>true</code> if <code>serverTimePointAsMillis</code> is between (inclusively) the start and end time
* point of the "live" interval as defined above.
*/
public boolean isLive(long serverTimePointAsMillis) {
final Date startOfLivePeriod;
final Date endOfLivePeriod;
if (trackedRace == null || !trackedRace.hasGPSData || !trackedRace.hasWindData) {
startOfLivePeriod = null;
endOfLivePeriod = null;
} else {
if (startOfRace == null) {
startOfLivePeriod = trackedRace.startOfTracking;
} else {
startOfLivePeriod = new Date(startOfRace.getTime() - TimingConstants.PRE_START_PHASE_DURATION_IN_MILLIS);
}
if (endOfRace == null) {
if (trackedRace.timePointOfNewestEvent != null) {
endOfLivePeriod = new Date(trackedRace.timePointOfNewestEvent.getTime()
+ TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS);
} else {
endOfLivePeriod = null;
}
} else {
endOfLivePeriod = new Date(endOfRace.getTime() + TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS);
}
}
// if an empty timepoint is given then take the start of the race
if (serverTimePointAsMillis == 0) {
serverTimePointAsMillis = startOfLivePeriod.getTime()+1;
}
// whenLastTrackedRaceWasLive is null if there is no tracked race for fleet, or the tracked race hasn't started yet at the server time
// when this DTO was assembled, or there were no GPS or wind data
final boolean result =
startOfLivePeriod != null &&
endOfLivePeriod != null &&
startOfLivePeriod.getTime() <= serverTimePointAsMillis &&
serverTimePointAsMillis <= endOfLivePeriod.getTime();
return result;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((boatClass == null) ? 0 : boatClass.hashCode());
result = prime * result + ((endOfRace == null) ? 0 : endOfRace.hashCode());
result = prime * result + (isTracked ? 1231 : 1237);
result = prime * result + ((places == null) ? 0 : places.hashCode());
result = prime * result + ((regattaName == null) ? 0 : regattaName.hashCode());
result = prime * result + ((startOfRace == null) ? 0 : startOfRace.hashCode());
result = prime * result + ((status == null) ? 0 : status.hashCode());
result = prime * result + ((trackedRace == null) ? 0 : trackedRace.hashCode());
return result;
}
@@ -146,11 +90,6 @@ public class RaceDTO extends NamedDTO {
return false;
} else if (!boatClass.equals(other.boatClass))
return false;
if (endOfRace == null) {
if (other.endOfRace != null)
return false;
} else if (!endOfRace.equals(other.endOfRace))
return false;
if (isTracked != other.isTracked)
return false;
if (places == null) {
@@ -163,21 +102,11 @@ public class RaceDTO extends NamedDTO {
return false;
} else if (!regattaName.equals(other.regattaName))
return false;
if (startOfRace == null) {
if (other.startOfRace != null)
return false;
} else if (!startOfRace.equals(other.startOfRace))
return false;
if (status == null) {
if (other.status != null)
return false;
} else if (!status.equals(other.status))
return false;
if (trackedRace == null) {
if (other.trackedRace != null)
return false;
} else if (!trackedRace.equals(other.trackedRace))
return false;
return true;
}
}
@@ -49,7 +49,8 @@ public class RaceLogFixedMarkPassingEventImpl extends RaceLogEventImpl implement
@Override
public String getShortInfo() {
return getInvolvedBoats().get(0).getName() + " at mark " + getZeroBasedIndexOfPassedWaypoint() + " at "
return (getInvolvedBoats() == null || getInvolvedBoats().get(0) == null ? "Unknown" :
getInvolvedBoats().get(0).getName()) + " at mark " + getZeroBasedIndexOfPassedWaypoint() + " at "
+ getTimePointOfFixedPassing();
}
}
@@ -35,4 +35,9 @@ public class RaceLogDefineMarkEventImpl extends RaceLogEventImpl implements Race
return mark;
}
@Override
public String getShortInfo() {
return mark.toString();
}
}
@@ -75,7 +75,4 @@ public class MarkImpl extends NamedImpl implements Mark {
public String toString() {
return getId() + " " + (getColor() == null ? "" : (getColor() + " ")) + super.toString();
}
}
@@ -60,7 +60,7 @@ public class MultipleClassesInRegattaTest {
httpAndHost
+ "/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=cce678c8-97e6-11e0-9aed-406186cbf87c"),
new URI(liveURI), new URI(storedURI), new URI(courseDesignUpdateURI),
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
@@ -71,7 +71,7 @@ public class MultipleClassesInRegattaTest {
httpAndHost
+ "/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=11290bd6-97e7-11e0-9aed-406186cbf87c"),
new URI(liveURI), new URI(storedURI), new URI(courseDesignUpdateURI),
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
@@ -82,7 +82,7 @@ public class MultipleClassesInRegattaTest {
httpAndHost
+ "/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=39635b24-97e7-11e0-9aed-406186cbf87c"),
new URI(liveURI), new URI(storedURI), new URI(courseDesignUpdateURI),
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
@@ -93,7 +93,7 @@ public class MultipleClassesInRegattaTest {
httpAndHost
+ "/events/event_20110505_SailingTea/clientparams.php?event=event_20110505_SailingTea&race=04498426-7dfd-11e0-8236-406186cbf87c"),
new URI(liveURI), new URI(storedURI), new URI(courseDesignUpdateURI),
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l, /* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, EmptyWindStore.INSTANCE,
EmptyGPSFixStore.INSTANCE, tracTracUsername, tracTracPassword,
TracTracConnectionConstants.ONLINE_STATUS, TracTracConnectionConstants.ONLINE_VISIBILITY,
@@ -67,7 +67,7 @@ public class UnicodeCharactersInCompetitorNamesTest {
+ TracTracConnectionConstants.PORT_STORED), new URI(
"http://tracms.traclive.dk/update_course"),
/* startOfTracking */null, /* endOfTracking */null, /* delayToLiveInMillis */0l,
/* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings*/
/* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings*/
false, EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
EmptyWindStore.INSTANCE, EmptyGPSFixStore.INSTANCE, "tracTest", "tracTest", "", "",
new DummyTrackedRegattaRegistry(), mock(RaceLogResolver.class));
@@ -44,6 +44,7 @@ import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sailing.domain.tractracadapter.impl.DomainFactoryImpl;
import com.sap.sailing.domain.tractracadapter.impl.RaceCourseReceiver;
import com.sap.sailing.domain.tractracadapter.impl.Simulator;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.tractrac.model.lib.api.data.IPosition;
@@ -95,7 +96,6 @@ public interface DomainFactory {
* Fetch a race definition previously created by a call to {@link #getOrCreateRaceDefinitionAndTrackedRace}. If no such
* race definition was created so far, the call blocks until such a definition is provided by a call to
* {@link #getOrCreateRaceDefinitionAndTrackedRace}.
* @param raceId TODO
*/
RaceDefinition getAndWaitForRaceDefinition(UUID raceId);
@@ -105,7 +105,6 @@ public interface DomainFactory {
* A new {@link com.sap.sailing.domain.base.Regatta} is created if no event by
* an equal name with a boat class with an equal name as the <code>event</code>'s
* boat class exists yet.
* @param trackedRegattaRegistry TODO
*/
com.sap.sailing.domain.base.Regatta getOrCreateDefaultRegatta(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
IRace race, TrackedRegattaRegistry trackedRegattaRegistry);
@@ -134,27 +133,30 @@ public interface DomainFactory {
* if <code>null</code>, all stored data until the "end of time" will be loaded that the event has
* to provide, particularly for the mark positions which are stored per event, not per race; otherwise,
* particularly the mark position loading will be constrained to this end time.
* @param offsetToStartTimeOfSimulatedRace
* if non-<code>null</code>, the {@link Simulator} will be used with this duration as start offset
* @param windStore
* Provides the capability to obtain the {@link WindTrack}s for the different wind sources. A trivial
* implementation is {@link EmptyWindStore} which simply provides new, empty tracks. This is always
* available but loses track of the wind, e.g., during server restarts.
* @param raceLogResolver TODO
*/
TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword,
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException, SubscriberInitializationException;
/**
* Same as {@link #createRaceTracker(URL, URI, URI, URI, TimePoint, TimePoint, WindStore, TrackedRegattaRegistry)}, only that
* a predefined {@link Regatta} is used to hold the resulting races.
* @param raceLogResolver TODO
* Same as {@link #createRaceTracker(URL, URI, URI, URI, TimePoint, TimePoint, WindStore, TrackedRegattaRegistry)},
* only that a predefined {@link Regatta} is used to hold the resulting races.
*
* @param offsetToStartTimeOfSimulatedRace
* if non-<code>null</code>, the {@link Simulator} will be used with this duration as start offset
*/
RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword,
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException,
@@ -262,9 +264,13 @@ public interface DomainFactory {
Util.Pair<Iterable<com.sap.sailing.domain.base.Competitor>, BoatClass> getCompetitorsAndDominantBoatClass(IRace race);
/**
* @param offsetToStartTimeOfSimulatedRace
* if non-<code>null</code>, the {@link Simulator} will be used with this duration as start offset
*/
RaceTrackingConnectivityParameters createTrackingConnectivityParameters(URL paramURL, URI liveURI, URI storedURI,
URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility);
/**
* Removes all knowledge about <code>tractracRace</code> which includes removing it from the race cache, from the
@@ -17,6 +17,8 @@ import com.sap.sailing.domain.regattalog.RegattaLogStore;
import com.sap.sailing.domain.tracking.RaceHandle;
import com.sap.sailing.domain.tracking.TrackerManager;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tractracadapter.impl.Simulator;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -65,12 +67,13 @@ public interface TracTracAdapter {
* created, with a single default series and a single default fleet. If a valid {@link RegattaIdentifier}
* is specified, a regatta lookup is performed with that identifier; if the regatta is found, it is used
* to add the races to. Otherwise, a default regatta as described above will be created and used.
* @param raceStatus
* @param offsetToStartTimeOfSimulatedRace
* if non-<code>null</code>, the {@link Simulator} will be used with this duration as start offset
*/
RaceHandle addTracTracRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, URL paramURL,
URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint trackingStartTime,
TimePoint trackingEndTime, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
long timeoutForReceivingRaceDefinitionInMilliseconds, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm,
long timeoutForReceivingRaceDefinitionInMilliseconds, Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm,
String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility)
throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception;
@@ -74,6 +74,7 @@ import com.sap.sailing.domain.tractracadapter.ReceiverType;
import com.sap.sailing.domain.tractracadapter.TracTracConfiguration;
import com.sap.sailing.domain.tractracadapter.TracTracControlPoint;
import com.sap.sailing.domain.tractracadapter.TracTracRaceTracker;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
@@ -652,27 +653,27 @@ public class DomainFactoryImpl implements DomainFactory {
@Override
public TracTracRaceTracker createRaceTracker(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername,
String tracTracPassword, String raceStatus, String raceVisibility,
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws MalformedURLException, FileNotFoundException,
URISyntaxException, CreateModelException, SubscriberInitializationException {
return new TracTracRaceTrackerImpl(this, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking,
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore,
endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore,
gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver);
}
@Override
public RaceTracker createRaceTracker(Regatta regatta, URL paramURL, URI liveURI, URI storedURI,
URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername,
String tracTracPassword, String raceStatus, String raceVisibility,
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
throws MalformedURLException, FileNotFoundException, URISyntaxException, CreateModelException,
SubscriberInitializationException {
return new TracTracRaceTrackerImpl(regatta, this, paramURL, liveURI, storedURI, courseDesignUpdateURI,
startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore,
startOfTracking, endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore,
regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus,
raceVisibility, trackedRegattaRegistry, raceLogResolver);
}
@@ -690,11 +691,11 @@ public class DomainFactoryImpl implements DomainFactory {
@Override
public RaceTrackingConnectivityParameters createTrackingConnectivityParameters(URL paramURL, URI liveURI,
URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking,
long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
long delayToLiveInMillis, Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
RegattaLogStore regattaLogStore, String tracTracUsername, String tracTracPassword, String raceStatus,
String raceVisibility) {
return new RaceTrackingConnectivityParametersImpl(paramURL, liveURI, storedURI, courseDesignUpdateURI,
startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore,
startOfTracking, endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore,
regattaLogStore, this, tracTracUsername, tracTracPassword, raceStatus, raceVisibility);
}
@@ -16,6 +16,7 @@ import com.sap.sailing.domain.tracking.RaceTrackingConnectivityParameters;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.tractrac.model.lib.api.event.CreateModelException;
import com.tractrac.subscription.lib.api.SubscriberInitializationException;
@@ -31,7 +32,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
private final RegattaLogStore regattaLogStore;
private final DomainFactory domainFactory;
private final long delayToLiveInMillis;
private final boolean simulateWithStartTimeNow;
private final Duration offsetToStartTimeOfSimulatedRace;
private final String tracTracUsername;
private final String tracTracPassword;
private final String raceStatus;
@@ -40,7 +41,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
public RaceTrackingConnectivityParametersImpl(URL paramURL, URI liveURI, URI storedURI, URI courseDesignUpdateURI,
TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
DomainFactory domainFactory, String tracTracUsername, String tracTracPassword, String raceStatus,
String raceVisibility) {
super();
@@ -52,7 +53,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
this.endOfTracking = endOfTracking;
this.delayToLiveInMillis = delayToLiveInMillis;
this.domainFactory = domainFactory;
this.simulateWithStartTimeNow = simulateWithStartTimeNow;
this.offsetToStartTimeOfSimulatedRace = offsetToStartTimeOfSimulatedRace;
this.raceLogStore = raceLogStore;
this.regattaLogStore = regattaLogStore;
this.tracTracUsername = tracTracUsername;
@@ -67,7 +68,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) throws MalformedURLException, FileNotFoundException, URISyntaxException,
CreateModelException, SubscriberInitializationException {
RaceTracker tracker = domainFactory.createRaceTracker(paramURL, liveURI, storedURI, courseDesignUpdateURI,
startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore,
startOfTracking, endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore,
regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus,
raceVisibility, trackedRegattaRegistry, raceLogResolver);
return tracker;
@@ -77,7 +78,7 @@ public class RaceTrackingConnectivityParametersImpl implements RaceTrackingConne
public RaceTracker createRaceTracker(Regatta regatta, TrackedRegattaRegistry trackedRegattaRegistry,
WindStore windStore, GPSFixStore gpsFixStore, RaceLogResolver raceLogResolver) throws Exception {
RaceTracker tracker = domainFactory.createRaceTracker(regatta, paramURL, liveURI, storedURI,
courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm,
courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm,
raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername, tracTracPassword, raceStatus,
raceVisibility, trackedRegattaRegistry, raceLogResolver);
return tracker;
@@ -4,7 +4,6 @@ import java.util.logging.Logger;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tractracadapter.DomainFactory;
@@ -57,13 +56,13 @@ public class RawPositionReceiver extends AbstractReceiverWithQueue<IRaceCompetit
IRace race = event.getA().getRace();
DynamicTrackedRace trackedRace = getTrackedRace(race);
if (trackedRace != null) {
GPSFixMoving fix = getDomainFactory().createGPSFixMoving(event.getB());
if (getSimulator() != null) {
fix = new GPSFixMovingImpl(fix.getPosition(), getSimulator().delay(
fix.getTimePoint()), fix.getSpeed());
}
final GPSFixMoving fix = getDomainFactory().createGPSFixMoving(event.getB());
Competitor competitor = getDomainFactory().getOrCreateCompetitor(event.getA().getCompetitor());
trackedRace.recordFix(competitor, fix);
if (getSimulator() != null) {
getSimulator().scheduleCompetitorPosition(competitor, fix);
} else {
trackedRace.recordFix(competitor, fix);
}
} else {
logger.warning("Couldn't find tracked race for race " + race.getName()
+ ". Dropping raw position event " + event);
@@ -24,7 +24,9 @@ import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class Simulator {
@@ -33,13 +35,15 @@ public class Simulator {
private DynamicTrackedRace trackedRace;
private final WindStore windStore;
private boolean stopped;
private long advanceInMillis = -1;
private Duration advanceInMillis = Duration.NULL.minus(1);
private Timer timer = new Timer("Timer for TracTrac Simulator");
private final Duration offsetToStart;
public Simulator(WindStore windStore) {
public Simulator(WindStore windStore, Duration offsetToStart) {
super();
assert windStore != null;
this.windStore = windStore;
this.offsetToStart = offsetToStart;
}
/**
@@ -69,7 +73,7 @@ public class Simulator {
/**
* This is what everybody is waiting for :-). Notifies all waiters.
*/
public synchronized void setAdvanceInMillis(long advanceInMillis) {
public synchronized void setAdvanceInMillis(Duration advanceInMillis) {
this.advanceInMillis = advanceInMillis;
notifyAll();
}
@@ -114,7 +118,7 @@ public class Simulator {
* Waits until {@link #advanceInMillis} is set to something not equal to -1 which is its initial value. Unblocked by
* {@link #setAdvanceInMillis(long)}.
*/
private synchronized long getAdvanceInMillis() {
private synchronized Duration getAdvance() {
while (!isAdvanceInMillisSet()) {
try {
wait(2000); // wait for two seconds, then re-evaluate whether there is a start time
@@ -126,6 +130,16 @@ public class Simulator {
return advanceInMillis;
}
private Duration getOffsetToStart() {
final Duration result;
if (offsetToStart != null) {
result = offsetToStart;
} else {
result = Duration.NULL;
}
return result;
}
/**
* Transforms <code>timed</code>'s time point according to this simulator's delay and waits roughly until this time
* has passed. Then, returns the adjusted time point which therefore should roughly equal "now."
@@ -157,12 +171,12 @@ public class Simulator {
* Like {@link #delay}, only that it doesn't wait until <code>timePoint</code> is reached in wall time.
*/
public TimePoint advance(TimePoint timePoint) {
return new MillisecondsTimePoint(timePoint.asMillis()+getAdvanceInMillis());
return timePoint.plus(getAdvance());
}
/**
* If {@link #advanceInMillis} is already set to a non-negative value, it is left alone, and
* {@link #delay(TimePoint)} is called. Otherwise, <code>time</code> is taken to be the original start time of the
* {@link #advance(TimePoint)} is called. Otherwise, <code>time</code> is taken to be the original start time of the
* race which is then used to compute {@link #advanceInMillis} such that
* <code>time.asMillis() + advanceInMillis == System.currentTimeMillis()</code>.
*/
@@ -183,13 +197,13 @@ public class Simulator {
if (isAdvanceInMillisSet()) {
return advance(time);
} else {
setAdvanceInMillis(System.currentTimeMillis() - time.asMillis());
setAdvanceInMillis(new MillisecondsDurationImpl(MillisecondsTimePoint.now().minus(time.asMillis()).plus(getOffsetToStart()).asMillis()));
return advance(time);
}
}
private boolean isAdvanceInMillisSet() {
return advanceInMillis != -1;
return !advanceInMillis.equals(Duration.NULL.minus(1));
}
/**
@@ -238,21 +252,35 @@ public class Simulator {
// deliver an empty list now
trackedRace.updateMarkPassings(competitor, markPassings);
}
}
public void scheduleCompetitorPosition(final Competitor competitor, GPSFixMoving competitorFix) {
final RecordGPSFix<Competitor> recorder = (c, f)->trackedRace.recordFix(c, f);
scheduleFixRecording(competitor, competitorFix, recorder);
}
@FunctionalInterface
private static interface RecordGPSFix<T> {
void recordFix(T objectForFix, GPSFixMoving fix);
}
public void scheduleMarkPosition(final Mark mark, GPSFixMoving markFix) {
final TimePoint transformedTimepoint = advance(markFix.getTimePoint());
final GPSFixMoving transformedMarkFix = new GPSFixMovingImpl(markFix.getPosition(), transformedTimepoint, markFix.getSpeed());
final RecordGPSFix<Mark> recorder = (m, f)->trackedRace.recordFix(mark, f);
scheduleFixRecording(mark, markFix, recorder);
}
private <T> void scheduleFixRecording(final T object, GPSFixMoving fix, final RecordGPSFix<T> recorder) {
final TimePoint transformedTimepoint = advance(fix.getTimePoint());
final GPSFixMoving transformedMarkFix = new GPSFixMovingImpl(fix.getPosition(), transformedTimepoint, fix.getSpeed());
long waitTime = getWaitTimeInMillisUntil(transformedMarkFix.getTimePoint());
if (waitTime <= 0) {
trackedRace.recordFix(mark, transformedMarkFix);
recorder.recordFix(object, transformedMarkFix);
} else {
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
trackedRace.recordFix(mark, transformedMarkFix);
recorder.recordFix(object, transformedMarkFix);
} catch (Exception e) {
logger.throwing(Simulator.class.getName(), "scheduleMarkPosition", e);
}
@@ -21,6 +21,7 @@ import com.sap.sailing.domain.tractracadapter.JSONService;
import com.sap.sailing.domain.tractracadapter.RaceRecord;
import com.sap.sailing.domain.tractracadapter.TracTracAdapter;
import com.sap.sailing.domain.tractracadapter.TracTracConfiguration;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -56,7 +57,7 @@ public class TracTracAdapterImpl implements TracTracAdapter {
getTracTracDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI,
courseDesignUpdateURI,
/* startOfTracking */null,
/* endOfTracking */null, delayToLiveInMillis, /* simulateWithStartTimeNow */false, /* ignoreTracTracMarkPassings */ false,
/* endOfTracking */null, delayToLiveInMillis, /* offsetToStartTimeOfSimulatedRace */null, /* ignoreTracTracMarkPassings */ false,
raceLogStore, regattaLogStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility),
timeoutInMilliseconds);
}
@@ -65,13 +66,13 @@ public class TracTracAdapterImpl implements TracTracAdapter {
public RaceHandle addTracTracRace(TrackerManager trackerManager, RegattaIdentifier regattaToAddTo, URL paramURL,
URI liveURI, URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking,
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, long timeoutInMilliseconds,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword, String raceStatus,
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword, String raceStatus,
String raceVisibility) throws Exception {
return trackerManager.addRace(
regattaToAddTo,
getTracTracDomainFactory().createTrackingConnectivityParameters(paramURL, liveURI, storedURI,
courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis,
simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, tracTracUsername, tracTracPassword,
offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, tracTracUsername, tracTracPassword,
raceStatus, raceVisibility), timeoutInMilliseconds);
}
@@ -49,6 +49,7 @@ import com.sap.sailing.domain.tractracadapter.DomainFactory;
import com.sap.sailing.domain.tractracadapter.Receiver;
import com.sap.sailing.domain.tractracadapter.TracTracConnectionConstants;
import com.sap.sailing.domain.tractracadapter.TracTracRaceTracker;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.tractrac.model.lib.api.ModelLocator;
@@ -253,26 +254,26 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
*/
protected TracTracRaceTrackerImpl(DomainFactory domainFactory, URL paramURL, URI liveURI, URI storedURI,
URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking, long delayToLiveInMillis,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername, String tracTracPassword,
String raceStatus, String raceVisibility, TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver)
throws URISyntaxException, MalformedURLException, FileNotFoundException, CreateModelException,
SubscriberInitializationException {
this(ModelLocator.getEventFactory().createRace(new URI(paramURL.toString())), domainFactory, paramURL, liveURI,
storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis,
simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername,
offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername,
tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver);
}
private TracTracRaceTrackerImpl(IRace tractracRace, DomainFactory domainFactory, URL paramURL, URI liveURI,
URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking,
long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
long delayToLiveInMillis, Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, RaceLogStore raceLogStore,
RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername,
String tracTracPassword, String raceStatus, String raceVisibility,
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws URISyntaxException, MalformedURLException,
FileNotFoundException, SubscriberInitializationException {
this(tractracRace, null, domainFactory, paramURL, liveURI, storedURI, courseDesignUpdateURI, startOfTracking,
endOfTracking, delayToLiveInMillis, simulateWithStartTimeNow, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore,
endOfTracking, delayToLiveInMillis, offsetToStartTimeOfSimulatedRace, useInternalMarkPassingAlgorithm, raceLogStore, regattaLogStore, windStore,
gpsFixStore, tracTracUsername, tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver);
}
@@ -284,14 +285,14 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
*/
protected TracTracRaceTrackerImpl(Regatta regatta, DomainFactory domainFactory, URL paramURL, URI liveURI,
URI storedURI, URI courseDesignUpdateURI, TimePoint startOfTracking, TimePoint endOfTracking,
long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean ignoreTracTracMarkPassings, RaceLogStore raceLogStore,
long delayToLiveInMillis, Duration offsetToStartTimeOfSimulatedRace, boolean ignoreTracTracMarkPassings, RaceLogStore raceLogStore,
RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore, String tracTracUsername,
String tracTracPassword, String raceStatus, String raceVisibility,
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws URISyntaxException,
MalformedURLException, FileNotFoundException, CreateModelException, SubscriberInitializationException {
this(ModelLocator.getEventFactory().createRace(new URI(paramURL.toString())), regatta, domainFactory, paramURL,
liveURI, storedURI, courseDesignUpdateURI, startOfTracking, endOfTracking, delayToLiveInMillis,
simulateWithStartTimeNow, ignoreTracTracMarkPassings, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername,
offsetToStartTimeOfSimulatedRace, ignoreTracTracMarkPassings, raceLogStore, regattaLogStore, windStore, gpsFixStore, tracTracUsername,
tracTracPassword, raceStatus, raceVisibility, trackedRegattaRegistry, raceLogResolver);
}
@@ -300,15 +301,15 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
* @param regatta
* if <code>null</code>, then <code>domainFactory.getOrCreateRegatta(tractracEvent)</code> will be used
* to obtain a default regatta
* @param simulateWithStartTimeNow
* if <code>true</code>, the connector will adjust the time stamps of all events received such that the
* @param offsetToStartTimeOfSimulatedRace
* if not <code>null</code>, the connector will adjust the time stamps of all events received such that the
* first mark passing for the first waypoint will be set to "now." It will delay the forwarding of all
* events received such that they seem to be sent in "real-time." So, more or less the time points
* events received such that they seem to be sent in "real-time" + <code>offsetToStartTimeOfSimulatedRace</code> So, more or less the time points
* attached to the events sent to the receivers will again approximate the wall time.
*/
private TracTracRaceTrackerImpl(IRace tractracRace, final Regatta regatta, DomainFactory domainFactory,
URL paramURL, URI liveURI, URI storedURI, URI tracTracUpdateURI, TimePoint startOfTracking,
TimePoint endOfTracking, long delayToLiveInMillis, boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm,
TimePoint endOfTracking, long delayToLiveInMillis, Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm,
RaceLogStore raceLogStore, RegattaLogStore regattaLogStore, WindStore windStore, GPSFixStore gpsFixStore,
String tracTracUsername, String tracTracPassword, String raceStatus, String raceVisibility,
TrackedRegattaRegistry trackedRegattaRegistry, RaceLogResolver raceLogResolver) throws URISyntaxException, MalformedURLException,
@@ -323,8 +324,8 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
this.gpsFixStore = gpsFixStore;
this.domainFactory = domainFactory;
this.lastProgressPerID = new HashMap<>();
if (simulateWithStartTimeNow) {
simulator = new Simulator(windStore);
if (offsetToStartTimeOfSimulatedRace != null) {
simulator = new Simulator(windStore, offsetToStartTimeOfSimulatedRace);
// don't write the transformed wind fixes into the DB again... see also bug 1974
this.windStore = EmptyWindStore.INSTANCE;
} else {
@@ -43,4 +43,6 @@ public interface Course extends CourseBase {
void update(Iterable<Util.Pair<ControlPoint, PassingInstruction>> newControlPoints, DomainFactory baseDomainFactory) throws PatchFailedException;
int getNumberOfWaypoints();
Leg getLeg(int zeroBasedIndexOfWaypoint);
}
@@ -246,6 +246,11 @@ public class CourseImpl extends NamedImpl implements Course {
return waypoints.size();
}
@Override
public Leg getLeg(int zeroBasedIndexOfWaypoint) {
return legs.get(zeroBasedIndexOfWaypoint);
}
@Override
public String toString() {
lockForRead();
@@ -42,6 +42,7 @@ import com.sap.sailing.domain.base.RaceColumnInSeries;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.LeaderboardType;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.MaxPointsReason;
@@ -51,12 +52,15 @@ import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.SpeedWithBearing;
import com.sap.sailing.domain.common.dto.BasicRaceDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.domain.common.dto.FleetDTO;
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
import com.sap.sailing.domain.common.dto.LeaderboardEntryDTO;
import com.sap.sailing.domain.common.dto.LeaderboardRowDTO;
import com.sap.sailing.domain.common.dto.LegEntryDTO;
import com.sap.sailing.domain.common.dto.MetaLeaderboardRaceColumnDTO;
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
import com.sap.sailing.domain.common.dto.RaceDTO;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.leaderboard.Leaderboard;
@@ -68,6 +72,7 @@ import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCache;
import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache;
import com.sap.sailing.domain.leaderboard.caching.LiveLeaderboardUpdater;
import com.sap.sailing.domain.leaderboard.meta.MetaLeaderboardColumn;
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
import com.sap.sailing.domain.ranking.RankingMetric.CompetitorRankingInfo;
import com.sap.sailing.domain.ranking.RankingMetric.RankingInfo;
@@ -1215,6 +1220,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
this.getScoreCorrection() == null ? null : this.getScoreCorrection().getComment(),
this.getScoringScheme() == null ? null : this.getScoringScheme().getType(), this
.getScoringScheme().isHigherBetter(), new UUIDGenerator(), addOverallDetails);
result.type = getLeaderboardType();
result.competitors = new ArrayList<CompetitorDTO>();
result.name = this.getName();
result.competitorDisplayNames = new HashMap<CompetitorDTO, String>();
@@ -1225,9 +1231,15 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
// futures to finish:
Map<RaceColumn, FutureTask<List<CompetitorDTO>>> competitorsFromBestToWorstTasks = new HashMap<>();
for (final RaceColumn raceColumn : this.getRaceColumns()) {
result.createEmptyRaceColumn(raceColumn.getName(), raceColumn.isMedalRace(),
boolean isMetaLeaderboardColumn = raceColumn instanceof MetaLeaderboardColumn;
RaceColumnDTO raceColumnDTO = result.createEmptyRaceColumn(raceColumn.getName(), raceColumn.isMedalRace(),
raceColumn instanceof RaceColumnInSeries ? ((RaceColumnInSeries) raceColumn).getRegatta().getName() : null,
raceColumn instanceof RaceColumnInSeries ? ((RaceColumnInSeries) raceColumn).getSeries().getName() : null);
raceColumn instanceof RaceColumnInSeries ? ((RaceColumnInSeries) raceColumn).getSeries().getName() : null,
isMetaLeaderboardColumn);
if (isMetaLeaderboardColumn && raceColumnDTO instanceof MetaLeaderboardRaceColumnDTO) {
calculateRacesMetadata((MetaLeaderboardColumn) raceColumn, (MetaLeaderboardRaceColumnDTO) raceColumnDTO,
trackedRegattaRegistry, baseDomainFactory);
}
for (Fleet fleet : raceColumn.getFleets()) {
RegattaAndRaceIdentifier raceIdentifier = null;
RaceDTO race = null;
@@ -1243,7 +1255,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
result.addRace(raceColumn.getName(), raceColumn.getExplicitFactor(), raceColumn.getFactor(),
raceColumn instanceof RaceColumnInSeries ? ((RaceColumnInSeries) raceColumn).getRegatta().getName() : null,
raceColumn instanceof RaceColumnInSeries ? ((RaceColumnInSeries) raceColumn).getSeries().getName() : null,
fleetDTO, raceColumn.isMedalRace(), raceIdentifier, race);
fleetDTO, raceColumn.isMedalRace(), raceIdentifier, race, isMetaLeaderboardColumn);
}
FutureTask<List<CompetitorDTO>> task = new FutureTask<List<CompetitorDTO>>(
() -> baseDomainFactory.getCompetitorDTOList(AbstractSimpleLeaderboardImpl.this.getCompetitorsFromBestToWorst(raceColumn, timePoint)));
@@ -1357,6 +1369,21 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
return result;
}
private void calculateRacesMetadata(MetaLeaderboardColumn metaLeaderboardColumn, MetaLeaderboardRaceColumnDTO columnDTO,
TrackedRegattaRegistry trackedRegattaRegistry, final DomainFactory baseDomainFactory) {
for (final RaceColumn raceColumn : metaLeaderboardColumn.getLeaderboard().getRaceColumns()) {
for (Fleet fleet : raceColumn.getFleets()) {
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
if (trackedRace != null) {
String regattaName = trackedRace.getTrackedRegatta().getRegatta().getName();
String raceName = trackedRace.getRace().getName();
RegattaAndRaceIdentifier raceIdentifier = new RegattaNameAndRaceName(regattaName, raceName);
columnDTO.addRace(new BasicRaceDTO(raceIdentifier, baseDomainFactory.createTrackedRaceDTO(trackedRace)));
}
}
}
}
private void addOverallDetailsToRow(final TimePoint timePoint,
final Competitor competitor, LeaderboardRowDTO row) throws NoWindException {
final com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> maximumSpeedOverGround = this.getMaximumSpeedOverGround(competitor, timePoint);
@@ -1904,4 +1931,7 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
public NumberOfCompetitorsInLeaderboardFetcher getNumberOfCompetitorsInLeaderboardFetcher() {
return new NumberOfCompetitorsFetcherImpl();
}
protected abstract LeaderboardType getLeaderboardType();
}
@@ -19,6 +19,7 @@ import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.impl.AbstractRaceExecutionOrderProvider;
import com.sap.sailing.domain.common.LeaderboardType;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
@@ -333,4 +334,9 @@ public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements
return result;
}
}
@Override
protected LeaderboardType getLeaderboardType() {
return LeaderboardType.FlexibleLeaderboard;
}
}
@@ -14,6 +14,7 @@ import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.impl.RaceColumnInSeriesImpl;
import com.sap.sailing.domain.common.LeaderboardType;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.domain.leaderboard.ResultDiscardingRule;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
@@ -114,4 +115,9 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R
public IsRegattaLike getRegattaLike() {
return regatta;
}
@Override
protected LeaderboardType getLeaderboardType() {
return LeaderboardType.RegattaLeaderboard;
}
}
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import com.sap.sailing.domain.base.CourseArea;
import com.sap.sailing.domain.common.LeaderboardType;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
@@ -61,4 +62,9 @@ public class FlexibleMetaLeaderboard extends AbstractMetaLeaderboard {
public CourseArea getDefaultCourseArea() {
return null;
}
@Override
protected LeaderboardType getLeaderboardType() {
return LeaderboardType.FlexibleMetaLeaderboard;
}
}
@@ -6,6 +6,7 @@ import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceColumnListener;
import com.sap.sailing.domain.base.impl.TrackedRaces;
import com.sap.sailing.domain.common.LeaderboardNameConstants;
import com.sap.sailing.domain.common.LeaderboardType;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.LeaderboardGroupListener;
@@ -89,4 +90,9 @@ public class LeaderboardGroupMetaLeaderboard extends AbstractMetaLeaderboard imp
public CourseArea getDefaultCourseArea() {
return null;
}
@Override
protected LeaderboardType getLeaderboardType() {
return LeaderboardType.RegattaMetaLeaderboard;
}
}
@@ -13,7 +13,6 @@ import java.util.ConcurrentModificationException;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
@@ -154,6 +153,7 @@ import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.concurrent.LockUtil;
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
import com.sap.sse.util.IdentityWrapper;
import com.sap.sse.util.SmartFutureCache;
import com.sap.sse.util.SmartFutureCache.AbstractCacheUpdater;
import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
@@ -183,7 +183,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
* By default, all wind sources are used, none are excluded. However, e.g., for performance reasons, particular wind
* sources such as the track-based estimation wind source, may be excluded by adding them to this set.
*/
private final Set<WindSource> windSourcesToExclude;
private final ConcurrentHashMap<WindSource, TrackedRaceImpl> windSourcesToExclude;
/**
* Keeps the oldest timestamp that is fed into this tracked race, either from a boat fix, a mark fix, a race
@@ -269,7 +269,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
*/
private transient SmartFutureCache<Competitor, com.sap.sse.common.Util.Triple<TimePoint, TimePoint, List<Maneuver>>, EmptyUpdateInterval> maneuverCache;
private transient Map<TimePoint, Future<Wind>> directionFromStartToNextMarkCache;
private transient ConcurrentHashMap<TimePoint, Future<Wind>> directionFromStartToNextMarkCache;
protected final MarkPassingCalculator markPassingCalculator;
@@ -354,7 +354,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
*/
private final NamedReentrantReadWriteLock loadingFromGPSFixStoreLock;
private final Map<Iterable<MarkPassing>, NamedReentrantReadWriteLock> locksForMarkPassings;
private final ConcurrentHashMap<IdentityWrapper<Iterable<MarkPassing>>, NamedReentrantReadWriteLock> locksForMarkPassings;
/**
* Caches wind requests for a few seconds to accelerate access in live mode
@@ -412,7 +412,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
rankingMetric = rankingMetricConstructor.apply(this);
raceStates = new WeakHashMap<>();
shortTimeWindCache = new ShortTimeWindCache(this, millisecondsOverWhichToAverageWind / 2);
locksForMarkPassings = new IdentityHashMap<>();
locksForMarkPassings = new ConcurrentHashMap<IdentityWrapper<Iterable<MarkPassing>>, NamedReentrantReadWriteLock>();
attachedRaceLogs = new ConcurrentHashMap<>();
attachedRegattaLogs = new ConcurrentHashMap<>();
attachedRaceExecutionOrderProviders = new ConcurrentHashMap<>();
@@ -424,8 +424,8 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
+ race.getName(), /* fair */ false);
this.cacheInvalidationTimerLock = new Object();
this.updateCount = 0;
this.windSourcesToExclude = new HashSet<WindSource>();
this.directionFromStartToNextMarkCache = new HashMap<TimePoint, Future<Wind>>();
this.windSourcesToExclude = new ConcurrentHashMap<>();
this.directionFromStartToNextMarkCache = new ConcurrentHashMap<TimePoint, Future<Wind>>();
this.millisecondsOverWhichToAverageSpeed = millisecondsOverWhichToAverageSpeed;
this.delayToLiveInMillis = delayToLiveInMillis;
this.startToNextMarkCacheInvalidationListeners = new ConcurrentHashMap<Mark, TrackedRaceImpl.StartToNextMarkCacheInvalidationListener>();
@@ -624,7 +624,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
gpsFixStore = EmptyGPSFixStore.INSTANCE;
competitorRankings = createCompetitorRankingsCache();
competitorRankingsLocks = createCompetitorRankingsLockMap();
directionFromStartToNextMarkCache = new HashMap<TimePoint, Future<Wind>>();
directionFromStartToNextMarkCache = new ConcurrentHashMap<>();
crossTrackErrorCache = new CrossTrackErrorCache(this);
crossTrackErrorCache.invalidate();
maneuverCache = createManeuverCache();
@@ -1146,11 +1146,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
int indexOfWaypoint = getRace().getCourse().getIndexOfWaypoint(startOfLeg);
if (indexOfWaypoint == -1) {
throw new IllegalArgumentException("Waypoint " + startOfLeg + " not found in " + getRace().getCourse());
} else if (indexOfWaypoint == Util.size(getRace().getCourse().getWaypoints()) - 1) {
} else if (indexOfWaypoint == getRace().getCourse().getNumberOfWaypoints() - 1) {
throw new IllegalArgumentException("Waypoint " + startOfLeg + " isn't start of any leg in "
+ getRace().getCourse());
}
return trackedLegs.get(race.getCourse().getLegs().get(indexOfWaypoint));
return trackedLegs.get(race.getCourse().getLeg(indexOfWaypoint));
} finally {
getRace().getCourse().unlockAfterRead();
}
@@ -1679,24 +1679,20 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
@Override
public Set<WindSource> getWindSourcesToExclude() {
synchronized (windSourcesToExclude) {
return Collections.unmodifiableSet(windSourcesToExclude);
}
return Collections.unmodifiableSet(windSourcesToExclude.keySet());
}
@Override
public void setWindSourcesToExclude(Iterable<? extends WindSource> windSourcesToExclude) {
Set<WindSource> old = new HashSet<>(this.windSourcesToExclude);
synchronized (this.windSourcesToExclude) {
LockUtil.lockForRead(getSerializationLock());
try {
this.windSourcesToExclude.clear();
for (WindSource windSourceToExclude : windSourcesToExclude) {
this.windSourcesToExclude.add(windSourceToExclude);
}
} finally {
LockUtil.unlockAfterRead(getSerializationLock());
Set<WindSource> old = new HashSet<>(getWindSourcesToExclude());
LockUtil.lockForRead(getSerializationLock());
try {
this.windSourcesToExclude.clear();
for (WindSource windSourceToExclude : windSourcesToExclude) {
this.windSourcesToExclude.put(windSourceToExclude, this);
}
} finally {
LockUtil.unlockAfterRead(getSerializationLock());
}
if (!old.equals(this.windSourcesToExclude)) {
clearAllCachesExceptManeuvers();
@@ -1742,30 +1738,33 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
public Wind getDirectionFromStartToNextMark(final TimePoint at) {
Future<Wind> future;
FutureTask<Wind> newFuture = null;
synchronized (directionFromStartToNextMarkCache) {
future = directionFromStartToNextMarkCache.get(at);
if (future == null) {
newFuture = new FutureTask<Wind>(new Callable<Wind>() {
@Override
public Wind call() {
Wind result;
Leg firstLeg = getRace().getCourse().getFirstLeg();
if (firstLeg != null) {
Position firstLegEnd = getApproximatePosition(firstLeg.getTo(), at);
Position firstLegStart = getApproximatePosition(firstLeg.getFrom(), at);
if (firstLegStart != null && firstLegEnd != null) {
result = new WindImpl(firstLegStart, at, new KnotSpeedWithBearingImpl(0.0,
firstLegEnd.getBearingGreatCircle(firstLegStart)));
future = directionFromStartToNextMarkCache.get(at);
if (future == null) {
synchronized (directionFromStartToNextMarkCache) {
future = directionFromStartToNextMarkCache.get(at);
if (future == null) {
newFuture = new FutureTask<Wind>(new Callable<Wind>() {
@Override
public Wind call() {
Wind result;
Leg firstLeg = getRace().getCourse().getFirstLeg();
if (firstLeg != null) {
Position firstLegEnd = getApproximatePosition(firstLeg.getTo(), at);
Position firstLegStart = getApproximatePosition(firstLeg.getFrom(), at);
if (firstLegStart != null && firstLegEnd != null) {
result = new WindImpl(firstLegStart, at, new KnotSpeedWithBearingImpl(0.0,
firstLegEnd.getBearingGreatCircle(firstLegStart)));
} else {
result = null;
}
} else {
result = null;
}
} else {
result = null;
return result;
}
return result;
}
});
directionFromStartToNextMarkCache.put(at, newFuture);
});
directionFromStartToNextMarkCache.put(at, newFuture);
}
}
}
if (newFuture != null) {
@@ -2062,15 +2061,19 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
}
protected NamedReentrantReadWriteLock getMarkPassingsLock(Iterable<MarkPassing> markPassings) {
synchronized (locksForMarkPassings) {
NamedReentrantReadWriteLock lock = locksForMarkPassings.get(markPassings);
if (lock == null) {
lock = new NamedReentrantReadWriteLock("mark passings lock for tracked race " + getRace().getName(), /* fair */
false);
locksForMarkPassings.put(markPassings, lock);
final IdentityWrapper<Iterable<MarkPassing>> markPassingsIdentity = new IdentityWrapper<>(markPassings);
NamedReentrantReadWriteLock lock = locksForMarkPassings.get(markPassingsIdentity);
if (lock == null) {
synchronized (locksForMarkPassings) {
lock = locksForMarkPassings.get(markPassingsIdentity);
if (lock == null) {
lock = new NamedReentrantReadWriteLock(
"mark passings lock for tracked race " + getRace().getName(), /* fair */false);
locksForMarkPassings.put(markPassingsIdentity, lock);
}
}
return lock;
}
return lock;
}
private void updateStartToNextMarkCacheInvalidationCacheListenersAfterWaypointRemoved(int zeroBasedIndex,
@@ -55,8 +55,6 @@
<plugin id="com.sap.sailing.sailwave.resultimport" autoStart="true" startLevel="3" />
<plugin id="com.sap.sailing.server" autoStart="true" startLevel="4" />
<plugin id="com.sap.sailing.server.gateway" autoStart="true" startLevel="4" />
<plugin id="com.sap.sailing.server.gateway.ess40" autoStart="true" startLevel="4" />
<plugin id="com.sap.sailing.server.replication" autoStart="true" startLevel="4" />
<plugin id="com.sap.sailing.velum.resultimport" autoStart="true" startLevel="3" />
<plugin id="com.sap.sailing.www" autoStart="true" startLevel="4" />
<plugin id="com.sap.sailing.www.events" autoStart="true" startLevel="4" />
-7
View File
@@ -87,13 +87,6 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al
version="0.0.0"
unpack="false"/>
<plugin
id="com.sap.sailing.server.gateway.ess40"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
<plugin
id="com.tractrac.clientmodule"
download-size="0"
@@ -95,7 +95,7 @@ public class GwtTestCaseColumnToggling extends GWTTestCase {
+ TracTracConnectionConstants.PORT_TUNNEL_STORED : "tcp://" + TracTracConnectionConstants.HOST_NAME
+ ":" + TracTracConnectionConstants.PORT_STORED,
COURSE_DESIGN_UPDATE_URI,
false, false, /* simulateWithStartTimeNow */ false, /* ignoreTracTracMarkPassings */ false, TRACTRAC_USERNAME, TRACTRAC_PASSWORD, new AsyncCallback<Void>() {
false, false, /* offsetToStartTimeOfSimulatedRace */ null, /* ignoreTracTracMarkPassings */ false, TRACTRAC_USERNAME, TRACTRAC_PASSWORD, new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
@@ -20,7 +20,7 @@ public class LeaderboardPanelMock extends LeaderboardPanel {
String leaderboardName, ErrorReporter errorReporter,
StringMessages stringMessages) {
super(sailingService, new AsyncActionsExecutor(), LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(
/* racesToShow */null, /* namesOfRacesToShow */ null, null, /* autoExpandFirstRace */ false, /* showRegattaRank */ true), new CompetitorSelectionModel(
/* racesToShow */null, /* namesOfRacesToShow */ null, null, /* autoExpandFirstRace */ false, /* showRegattaRank */ true, /* showCompetitorSailIdColumn */ true, /* showCompetitorFullNameColumn */ true), new CompetitorSelectionModel(
/* hasMultiSelection */true), leaderboardName, errorReporter, stringMessages, new UserAgentDetails("gecko1_8"), /* showRaceDetails */ true);
}
@@ -61,9 +61,9 @@ public class TestColumnSwapping {
return UUID.randomUUID().toString();
}
}, /* hasOverallDetails */ false);
leaderboardOriginalDTO.addRace("Race1", /* explicitFactor */ null, 2., /* regattaName */ null, /* seriesName */ null, DEFAULT_FLEET, true, null, null);
leaderboardOriginalDTO.addRace("Race3", /* explicitFactor */ null, 2., /* regattaName */ null, /* seriesName */ null, DEFAULT_FLEET, true, null, null);
leaderboardOriginalDTO.addRace("Race2", /* explicitFactor */ null, 2., /* regattaName */ null, /* seriesName */ null, DEFAULT_FLEET, true, null, null);
leaderboardOriginalDTO.addRace("Race1", /* explicitFactor */ null, 2., /* regattaName */ null, /* seriesName */ null, DEFAULT_FLEET, true, null, null, false);
leaderboardOriginalDTO.addRace("Race3", /* explicitFactor */ null, 2., /* regattaName */ null, /* seriesName */ null, DEFAULT_FLEET, true, null, null, false);
leaderboardOriginalDTO.addRace("Race2", /* explicitFactor */ null, 2., /* regattaName */ null, /* seriesName */ null, DEFAULT_FLEET, true, null, null, false);
} catch (Exception e) {
e.printStackTrace();
}
@@ -126,9 +126,9 @@ public class TestColumnSwapping {
}
}, /* hasOverallDetails */ false);
assertNotNull("Leaderboard != NULL", lb);
lb.addRace("1", /* explicitFactor */ null, 1., /* regattaName */ null, /* seriesName */ null, DEFAULT_FLEET, false, null, null);
lb.addRace("2", /* explicitFactor */ null, 1., /* regattaName */ null, /* seriesName */ null, DEFAULT_FLEET, false, null, null);
lb.addRace("3", /* explicitFactor */ null, 1., /* regattaName */ null, /* seriesName */ null, DEFAULT_FLEET, true, null, null);
lb.addRace("1", /* explicitFactor */ null, 1., /* regattaName */ null, /* seriesName */ null, DEFAULT_FLEET, false, null, null, false);
lb.addRace("2", /* explicitFactor */ null, 1., /* regattaName */ null, /* seriesName */ null, DEFAULT_FLEET, false, null, null, false);
lb.addRace("3", /* explicitFactor */ null, 1., /* regattaName */ null, /* seriesName */ null, DEFAULT_FLEET, true, null, null, false);
lb.moveRaceDown("1");
String[] s = new String[] { "2", "1", "3" };
for (int i = 0; i < lb.getRaceList().size(); i++) {
@@ -3,7 +3,11 @@ encoding//src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages.prop
encoding//src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_de.properties=UTF-8
encoding//src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_ru.properties=UTF-8
encoding//src/main/java/com/sap/sailing/gwt/common/client/i18n/TextMessages_zh.properties=UTF-8
encoding//src/main/java/com/sap/sailing/gwt/server/HomeServiceUtil.java=utf-8
encoding//src/main/java/com/sap/sailing/gwt/ui/adminconsole/IgtimiAccountsPanel.java=utf-8
encoding//src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties=UTF-8
encoding//src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties=UTF-8
encoding//src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties=UTF-8
encoding//src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties=UTF-8
encoding//src/main/java/com/sap/sailing/gwt/ui/datamining/presentation/AbstractResultsPresenter.java=utf-8
encoding//src/main/java/com/sap/sailing/gwt/ui/leaderboard/CompetitorFilterPanel.java=utf-8
+2 -2
View File
@@ -98,13 +98,13 @@ body, table td, select, button {
padding: 49px 0 0 80px;
width: 300px;
color: #7c7c7c;
background: url(images/important-message.png) left center no-repeat;
background: url(images/important-message.png) left center no-repeat;
}
.LeaderboardHeader {
position: relative;
margin: 0 auto;
width: 400px;
width: 100%;
text-align: center;
font-family: 'Open Sans', Arial, Verdana, sans-serif;
font-size: 18px;
+45 -2
View File
@@ -6,6 +6,13 @@
height: 0;
clear: both;
visibility: hidden;
RegattaRaceInformation-Header
RaceName-Label
RaceSeriesAndFleet-Label
RegattaAndRaceTime-Header???
RegattaName-Anchor
*/
@@ -87,6 +94,14 @@ table {
padding-top: 10px;
padding-left: 10px;
}
.CombinedWindPanelParentDiv.indentsmall,
.TrueNorthIndicatorPanelParentDiv.indentsmall {
padding-left: 30px;
}
.CombinedWindPanelParentDiv.indentbig,
.TrueNorthIndicatorPanelParentDiv.indentbig {
padding-left: 45px;
}
.MapSimulationLegendParentDiv {
padding-bottom: 10px;
@@ -573,7 +588,8 @@ img.openColumn {
url(images/viewicons/@1x/img/SAP_RV_Leaderboard_GHOSTED.png),
url(images/arrows_top_black_small.png);
background-repeat: no-repeat, no-repeat;
background-position: 4% 50%, 96% 50%
background-position: 4% 50%, 96% 50%;
background-position: 5px center, calc(100% - 6px) center;
}
.gwt-SplitLayoutPanel-EastToggleButton-Closed-leaderboard {
@@ -582,7 +598,8 @@ img.openColumn {
url(images/viewicons/@1x/img/SAP_RV_Leaderboard_INACTIVE.png),
url(images/arrows_bottom_black_small.png);
background-repeat: no-repeat, no-repeat;
background-position: 4% 50%, 96% 50%
background-position: 4% 50%, 96% 50%;
background-position: 5px center, calc(100% - 6px) center;
}
.gwt-SplitLayoutPanel-NorthSouthToggleButton-Closed-media,
@@ -664,6 +681,32 @@ img.openColumn {
margin-top: 5px;
}
.compactHeader .RegattaRaceInformation-Header {
left: 110px;
}
.compactHeader .RegattaRaceInformation-Header .RaceName-Label {
display: block;
font-size: 16px;
padding: 2px 0;
}
.compactHeader .RegattaRaceInformation-Header .RaceSeriesAndFleet-Label {
display: block;
margin-top: 5px;
white-space: nowrap;
}
.compactHeader .RegattaAndRaceTime-Header {
top: 11px;
}
.compactHeader .RegattaAndRaceTime-Header .RegattaName-Anchor {
width: 115px;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
padding: 2px 0 2px 20px;
background-position: 4px -1px;
}
.VideoPopup-Close-Button {
border: none;
}
@@ -107,7 +107,7 @@ public class AutoPlayController implements RaceTimesInfoProviderListener {
asyncActionsExecutor = new AsyncActionsExecutor();
showWindChart = false;
leaderboard = null;
leaderboardSettings = LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(null, null, null, /* autoExpandFirstRace */ false, /* showRegattaRank */ true);
leaderboardSettings = LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(null, null, null, /* autoExpandFirstRace */ false, /* showRegattaRank */ true, /* showCompetitorSailIdColumn */ true, /* showCompetitorFullNameColumn */ true);
leaderboardTimer = new Timer(PlayModes.Live, /* delayBetweenAutoAdvancesInMilliseconds */1000l);
leaderboardTimer.setLivePlayDelayInMillis(delayToLiveInMillis);
@@ -170,10 +170,10 @@ public class AutoPlayController implements RaceTimesInfoProviderListener {
RaceSelectionModel raceSelectionModel = new RaceSelectionModel();
List<RegattaAndRaceIdentifier> singletonList = Collections.singletonList(raceToShow);
raceSelectionModel.setSelection(singletonList);
RaceBoardPanel raceBoardPanel = new RaceBoardPanel(sailingService, mediaService, userService, asyncActionsExecutor,
competitorsAndTheirBoats, raceboardTimer, raceSelectionModel, leaderboardName, null, /* event */null, raceboardViewConfig,
errorReporter, StringMessages.INSTANCE, userAgent, raceTimesInfoProvider, /* showMapControls */false);
competitorsAndTheirBoats, raceboardTimer, raceSelectionModel, leaderboardName, null, /* event */ null, raceboardViewConfig,
errorReporter, StringMessages.INSTANCE, userAgent, raceTimesInfoProvider, /* showMapControls */ false,
/* isScreenLargeEnoughToOfferChartSupport */ true);
return raceBoardPanel;
}
@@ -18,6 +18,8 @@ public class AutomaticBatchingDispatch<CTX extends DispatchContext> implements D
private DispatchCallStack<CTX> currentCallstack;
private boolean processResultsScheduled;
/**
* Creates a batching dispatch service using the given dispatch implementation.
*
@@ -28,7 +30,21 @@ public class AutomaticBatchingDispatch<CTX extends DispatchContext> implements D
*
*/
public AutomaticBatchingDispatch(DispatchAsync<CTX> service) {
this(service, false);
}
/**
* Creates a batching dispatch service using the given dispatch implementation.
*
* The underlying dispatch service is responsible for the context propagation.
*
* @param service
* the underlying service implementation to use
*
*/
public AutomaticBatchingDispatch(DispatchAsync<CTX> service, boolean processResultsScheduled) {
this.executionContext = service;
this.processResultsScheduled = processResultsScheduled;
}
/**
@@ -73,7 +89,7 @@ public class AutomaticBatchingDispatch<CTX extends DispatchContext> implements D
@Override
public void onSuccess(BatchResult result) {
callStackInExecution.processResult(result);
callStackInExecution.processResult(result, processResultsScheduled);
}
});
}
@@ -2,6 +2,7 @@ package com.sap.sailing.gwt.dispatch.client.batching;
import java.util.LinkedList;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.gwt.dispatch.client.Action;
import com.sap.sailing.gwt.dispatch.client.DispatchContext;
@@ -70,22 +71,44 @@ public final class DispatchCallStack<CTX extends DispatchContext> {
*
* @param batchResult
*/
@SuppressWarnings("unchecked")
public void processResult(BatchResult batchResult) {
public void processResult(BatchResult batchResult, boolean processResultsScheduled) {
assert (batchResult != null);
int loop = 0;
for (@SuppressWarnings("rawtypes")
DispatchCall call : this.actionQueue) {
Result result = batchResult.getResult(loop);
Throwable exception = batchResult.getException(loop);
if (result == null) {
Throwable exception = batchResult.getException(loop);
call.getCallback().onFailure(exception);
CallbackCommand callbackCommand = new CallbackCommand(call, result, exception);
if(processResultsScheduled) {
SplitScheduler.get().schedule(callbackCommand);
} else {
call.getCallback().onSuccess(result);
callbackCommand.execute();
}
loop++;
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private class CallbackCommand implements ScheduledCommand {
private final DispatchCall call;
private final Result result;
private final Throwable exception;
public CallbackCommand(DispatchCall call, Result result, Throwable exception) {
this.call = call;
this.result = result;
this.exception = exception;
}
@Override
public void execute() {
if (result == null) {
call.getCallback().onFailure(exception);
} else {
call.getCallback().onSuccess(result);
}
}
}
}
@@ -0,0 +1,52 @@
package com.sap.sailing.gwt.dispatch.client.batching;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
public class SplitScheduler {
private static final SplitScheduler INSTANCE = new SplitScheduler();
private List<ScheduledCommand> pendingCommands = new ArrayList<ScheduledCommand>();
private boolean scheduled = false;
private final RepeatingCommand repeatingCommand = new RepeatingCommand() {
@Override
public boolean execute() {
ScheduledCommand commandToExecute = pendingCommands.remove(0);
try {
commandToExecute.execute();
} catch (Exception e) {
if(GWT.getUncaughtExceptionHandler() != null) {
GWT.getUncaughtExceptionHandler().onUncaughtException(e);
}
}
scheduled = !pendingCommands.isEmpty();
return scheduled;
}
};
private SplitScheduler() {
}
public static SplitScheduler get() {
return INSTANCE;
}
public void schedule(ScheduledCommand command) {
pendingCommands.add(command);
if(!scheduled) {
Scheduler.get().scheduleIncremental(repeatingCommand);
scheduled = true;
}
}
}
@@ -16,8 +16,16 @@ import com.sap.sailing.gwt.dispatch.client.rpcimpl.SimpleDispatch;
public class DispatchSystemImpl<CTX extends DispatchContext> implements DispatchSystem<CTX> {
private final SimpleDispatch<CTX> simpleDispatch = new SimpleDispatch<CTX>(null);
private final DispatchAsync<CTX> dispatch = new CachingDispatch<CTX>(new AutomaticBatchingDispatch<CTX>(
simpleDispatch));
private final DispatchAsync<CTX> dispatch;
public DispatchSystemImpl() {
this(false);
}
public DispatchSystemImpl(boolean processResultsScheduled) {
dispatch = new CachingDispatch<CTX>(new AutomaticBatchingDispatch<CTX>(
simpleDispatch, processResultsScheduled));
}
@Override
public <R extends Result, A extends Action<R, CTX>> void execute(final A action, final AsyncCallback<R> callback) {
@@ -43,7 +43,7 @@ public class GetRegattasAndLiveRacesForEventAction implements SailingAction<Resu
EventState eventState = HomeServiceUtil.calculateEventState(event);
final Duration ttl;
if(eventState == EventState.RUNNING) {
if(eventState == EventState.RUNNING || eventState == EventState.UPCOMING) {
EventActionUtil.forRacesOfEvent(context, eventId, new RaceCallback() {
@Override
public void doForRace(RaceContext context) {
@@ -1,5 +1,6 @@
package com.sap.sailing.gwt.home.desktop.partials.old;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.ui.FlowPanel;
@@ -8,6 +9,9 @@ import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.home.shared.partials.fullscreen.FullscreenContainer;
import com.sap.sse.common.Color;
import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator;
import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicatorResources;
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
public abstract class AbstractLeaderboardFullscreenViewer<T extends Widget> extends FullscreenContainer<T> implements
LeaderboardDelegate<T> {
@@ -15,14 +19,18 @@ public abstract class AbstractLeaderboardFullscreenViewer<T extends Widget> exte
private final Image autoRefreshControl = new Image("images/home/reload.svg");
private final Image settingsControl = new Image("images/home/settings.svg");
private final static BusyIndicatorResources RESOURCES = GWT.create(BusyIndicatorResources.class);
private final Label lastScoringUpdateTime = new Label();
private final Label lastScoringUpdateText = new Label();
protected final Label lastScoringComment = new Label();
protected final Label scoringScheme = new Label();
protected final BusyIndicator busyIndicator = new SimpleBusyIndicator(false, 0.9f, RESOURCES.busyIndicatorCircleInverted());
public AbstractLeaderboardFullscreenViewer() {
showLogo();
showBorder();
addToolbarBusyIndicator(busyIndicator);
addToolbarInfo(createPanel(lastScoringUpdateText, lastScoringUpdateTime));
addToolbarAction(autoRefreshControl);
addToolbarAction(settingsControl);
@@ -88,4 +96,13 @@ public abstract class AbstractLeaderboardFullscreenViewer<T extends Widget> exte
return scoringScheme.getElement();
}
@Override
public Element getBusyIndicatorElement() {
return busyIndicator.getElement();
}
@Override
public void setBusyState(boolean isBusy) {
busyIndicator.setBusy(isBusy);
}
}
@@ -106,6 +106,11 @@
background-color: #f0ab00;
}
.regattaleaderboard_meta_busyindicator {
display: inline-block;
margin: 0 0.666666666666667em;
}
.regattaleaderboard_meta_liverace {
color: red;
font-weight: 600;
@@ -30,6 +30,7 @@ public interface EventRegattaLeaderboardResources extends ClientBundle {
String regattaleaderboard_meta_update_type();
String regattaleaderboard_meta_scoring_timestamp();
String regattaleaderboard_meta_update_timestamp();
String regattaleaderboard_meta_busyindicator();
String regattaleaderboard_meta_scoring_text();
String regattaleaderboard_meta_update_text();
String regattaleaderboard_meta_reload();
@@ -10,6 +10,8 @@ public interface LeaderboardDelegate<T extends Widget> {
void setLeaderboardPanel(T leaderboardPanel);
void setBusyState(boolean isBusy);
Widget getAutoRefreshControl();
Widget getSettingsControl();
@@ -24,4 +26,5 @@ public interface LeaderboardDelegate<T extends Widget> {
Element getScoringSchemeElement();
Element getBusyIndicatorElement();
}
@@ -31,12 +31,14 @@ import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettings;
import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter;
import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator;
import com.sap.sse.gwt.client.controls.busyindicator.BusyStateChangeListener;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.client.player.Timer.PlayStates;
import com.sap.sse.gwt.client.shared.components.SettingsDialog;
public class OldLeaderboard extends Composite {
public class OldLeaderboard extends Composite implements BusyStateChangeListener {
private static OldLeaderboardUiBinder uiBinder = GWT.create(OldLeaderboardUiBinder.class);
interface OldLeaderboardUiBinder extends UiBinder<Widget, OldLeaderboard> {
@@ -52,6 +54,7 @@ public class OldLeaderboard extends Composite {
@UiField DivElement lastScoringCommentDiv;
@UiField DivElement scoringSchemeDiv;
@UiField DivElement hasLiveRaceDiv;
@UiField BusyIndicator busyIndicator;
@UiField EventRegattaLeaderboardResources local_res;
private LeaderboardPanel leaderboardPanel;
@@ -166,6 +169,7 @@ public class OldLeaderboard extends Composite {
this.autoRefreshTimer = timer;
this.leaderboardPanel = leaderboardPanel;
oldLeaderboardPanel.add(leaderboardPanel);
leaderboardPanel.addBusyStateChangeListener(this);
}
public void updatedLeaderboard(LeaderboardDTO leaderboard) {
@@ -218,7 +222,16 @@ public class OldLeaderboard extends Composite {
lastScoringUpdateTimeDiv.getStyle().setVisibility(Visibility.HIDDEN);
}
@Override
public void onBusyStateChange(boolean busyState) {
busyIndicator.setBusy(busyState);
if(delegate != null) {
delegate.setBusyState(busyState);
}
}
public interface OldLeaderboardDelegate extends LeaderboardDelegate<LeaderboardPanel> {
Element getHasLiveRaceElement();
}
}
@@ -1,16 +1,18 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:c="urn:import:com.sap.sse.gwt.client.controls.busyindicator">
<ui:with field="i18n" type="com.sap.sailing.gwt.common.client.i18n.TextMessages"/>
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.home.desktop.partials.old.EventRegattaLeaderboardResources" />
<g:HTMLPanel styleName=" {local_res.css.marginFix}">
<div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small7} {res.mediaCss.column} {local_res.css.regattaleaderboard_meta_scoring}">
<div class="{res.mediaCss.small6} {res.mediaCss.column} {local_res.css.regattaleaderboard_meta_scoring}">
<div ui:field="lastScoringCommentDiv" class="{local_res.css.regattaleaderboard_meta_scoring_comment}"></div>
<div ui:field="hasLiveRaceDiv" class="{local_res.css.regattaleaderboard_meta_liverace}"></div>
<div ui:field="scoringSchemeDiv" class="{local_res.css.regattaleaderboard_meta_scoring_type}"></div>
</div>
<div class="{res.mediaCss.small5} {res.mediaCss.column} {local_res.css.regattaleaderboard_meta_settings}">
<div class="{res.mediaCss.small6} {res.mediaCss.column} {local_res.css.regattaleaderboard_meta_settings}">
<c:SimpleBusyIndicator addStyleNames="{local_res.css.regattaleaderboard_meta_busyindicator}" ui:field="busyIndicator" />
<div class="{local_res.css.regattaleaderboard_meta_update}">
<div ui:field="lastScoringUpdateTextDiv" class="{local_res.css.regattaleaderboard_meta_update_text}"></div>
<div ui:field="lastScoringUpdateTimeDiv" class="{local_res.css.regattaleaderboard_meta_update_timestamp}"></div>
@@ -3,7 +3,7 @@ package com.sap.sailing.gwt.home.desktop.partials.old.multileaderboard;
import java.util.Date;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.ParagraphElement;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Style.Visibility;
@@ -27,15 +27,19 @@ import com.sap.sailing.gwt.home.desktop.partials.old.LeaderboardDelegate;
import com.sap.sailing.gwt.ui.client.DebugIdHelper;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettings;
import com.sap.sailing.gwt.ui.leaderboard.MultiLeaderboardPanel;
import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter;
import com.sap.sailing.gwt.ui.leaderboard.SelectedLeaderboardChangeListener;
import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator;
import com.sap.sse.gwt.client.controls.busyindicator.BusyStateChangeListener;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.client.player.Timer.PlayStates;
import com.sap.sse.gwt.client.shared.components.SettingsDialog;
public class OldMultiLeaderboard extends Composite {
public class OldMultiLeaderboard extends Composite implements SelectedLeaderboardChangeListener, BusyStateChangeListener {
private static OldMultiLeaderboardUiBinder uiBinder = GWT.create(OldMultiLeaderboardUiBinder.class);
interface OldMultiLeaderboardUiBinder extends UiBinder<Widget, OldMultiLeaderboard> {
@@ -46,15 +50,17 @@ public class OldMultiLeaderboard extends Composite {
@UiField Anchor settingsAnchor;
@UiField Anchor autoRefreshAnchor;
@UiField Anchor fullscreenAnchor;
@UiField ParagraphElement lastScoringUpdateTimeDiv;
@UiField ParagraphElement lastScoringUpdateTextDiv;
@UiField ParagraphElement lastScoringCommentDiv;
@UiField ParagraphElement scoringSchemeDiv;
@UiField DivElement lastScoringUpdateTimeDiv;
@UiField DivElement lastScoringUpdateTextDiv;
@UiField DivElement lastScoringCommentDiv;
@UiField DivElement scoringSchemeDiv;
@UiField BusyIndicator busyIndicator;
@UiField EventRegattaLeaderboardResources local_res;
private MultiLeaderboardPanel multiLeaderboardPanel;
private Timer autoRefreshTimer;
private final OldMultiLeaderboardDelegate delegate;
private LeaderboardPanel lastSelectedLeaderboardPanel;
public OldMultiLeaderboard() {
this(null);
@@ -69,6 +75,7 @@ public class OldMultiLeaderboard extends Composite {
fullscreenAnchor.setTitle(StringMessages.INSTANCE.openFullscreenView());
this.delegate = delegate;
this.setupFullscreenDelegate();
lastSelectedLeaderboardPanel = null;
}
private void setupFullscreenDelegate() {
@@ -163,6 +170,7 @@ public class OldMultiLeaderboard extends Composite {
public void setMultiLeaderboard(MultiLeaderboardPanel multiLeaderboardPanel, final Timer timer) {
this.autoRefreshTimer = timer;
this.multiLeaderboardPanel = multiLeaderboardPanel;
this.multiLeaderboardPanel.addSelectedLeaderboardChangeListener(this);
oldMultiLeaderboardPanel.add(multiLeaderboardPanel);
}
@@ -199,6 +207,23 @@ public class OldMultiLeaderboard extends Composite {
}
}
@Override
public void onBusyStateChange(boolean busyState) {
busyIndicator.setBusy(busyState);
if(delegate != null) {
delegate.setBusyState(busyState);
}
}
@Override
public void onSelectedLeaderboardChanged(LeaderboardPanel selectedLeaderboard) {
if(lastSelectedLeaderboardPanel != null) {
lastSelectedLeaderboardPanel.removeBusyStateChangeListener(this);
}
selectedLeaderboard.addBusyStateChangeListener(this);
lastSelectedLeaderboardPanel = selectedLeaderboard;
}
public interface OldMultiLeaderboardDelegate extends LeaderboardDelegate<MultiLeaderboardPanel>{
}
}
@@ -1,18 +1,20 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:c="urn:import:com.sap.sse.gwt.client.controls.busyindicator">
<ui:with field="i18n" type="com.sap.sailing.gwt.common.client.i18n.TextMessages"/>
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.home.desktop.partials.old.EventRegattaLeaderboardResources" />
<g:HTMLPanel styleName=" {local_res.css.marginFix}">
<div class="{res.mediaCss.grid}">
<div class="{res.mediaCss.small6} {res.mediaCss.column} {local_res.css.regattaleaderboard_meta_scoring}">
<p ui:field="lastScoringCommentDiv" class="{local_res.css.regattaleaderboard_meta_scoring_comment}"></p>
<p ui:field="scoringSchemeDiv" class="{local_res.css.regattaleaderboard_meta_scoring_type}"></p>
<div ui:field="lastScoringCommentDiv" class="{local_res.css.regattaleaderboard_meta_scoring_comment}"></div>
<div ui:field="scoringSchemeDiv" class="{local_res.css.regattaleaderboard_meta_scoring_type}"></div>
</div>
<div class="{res.mediaCss.small6} {res.mediaCss.column} {local_res.css.regattaleaderboard_meta_settings}">
<c:SimpleBusyIndicator addStyleNames="{local_res.css.regattaleaderboard_meta_busyindicator}" ui:field="busyIndicator"/>
<div class="{local_res.css.regattaleaderboard_meta_update}">
<p ui:field="lastScoringUpdateTextDiv" class="{local_res.css.regattaleaderboard_meta_update_text}"></p>
<p ui:field="lastScoringUpdateTimeDiv" class="{local_res.css.regattaleaderboard_meta_update_timestamp}"></p>
<div ui:field="lastScoringUpdateTextDiv" class="{local_res.css.regattaleaderboard_meta_update_text}"></div>
<div ui:field="lastScoringUpdateTimeDiv" class="{local_res.css.regattaleaderboard_meta_update_timestamp}"></div>
</div>
<g:Anchor ui:field="autoRefreshAnchor" href="javascript:;" styleName="{res.mainCss.button} {local_res.css.regattaleaderboard_meta_reload}"></g:Anchor>
<g:Anchor ui:field="settingsAnchor" href="javascript:;" styleName="{res.mainCss.button} {local_res.css.regattaleaderboard_meta_settings_button}"></g:Anchor>
@@ -108,7 +108,7 @@ public class EventParamUtils {
.createNewDefaultSettings(null, null,
/* overallDetails */overallDetails, null,
/* autoExpandFirstRace */false, refreshIntervalMillis, numberOfLastRacesToShow,
raceColumnSelectionStrategy);
raceColumnSelectionStrategy, /* showCompetitorSailIdColumns */ true, /*showCompetitorFullNameColumn*/ true);
}
return result;
}
@@ -44,7 +44,6 @@ import com.sap.sailing.gwt.home.shared.places.fakeseries.SeriesDefaultPlace;
import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
import com.sap.sailing.gwt.ui.raceboard.RaceBoardViewConfiguration;
import com.sap.sailing.gwt.ui.shared.util.NullSafeComparableComparator;
public abstract class AbstractEventActivity<PLACE extends AbstractEventPlace> extends AbstractActivity implements Presenter {
@@ -248,7 +247,6 @@ public abstract class AbstractEventActivity<PLACE extends AbstractEventPlace> ex
}
linkParams.put("raceName", trackedRaceName);
linkParams.put("regattaName", regattaName);
linkParams.put(RaceBoardViewConfiguration.PARAM_VIEW_MODE, "simple");
// TODO this must only be forwarded if there is a logged-on user
// linkParams.put(RaceBoardViewConfiguration.PARAM_CAN_REPLAY_DURING_LIVE_RACES, "true");
return linkParams;
@@ -54,7 +54,7 @@ public class ExperimentalFeatures {
/**
* Enables/disables the link to the race board on mobile races view (competition format), in case of a tracked race
*/
public static final boolean ENABLE_RACE_VIEWER_LINK_ON_MOBILE = false;
public static final boolean ENABLE_RACE_VIEWER_LINK_ON_MOBILE = true;
/**
* Provide selection to filter regattas by boat category on mobile multiregatta event overview
*/
@@ -8,7 +8,8 @@ public class BusyViewImpl extends Composite implements BusyView {
public BusyViewImpl() {
BusyViewResources.INSTANCE.css().ensureInjected();
initWidget(new SimpleBusyIndicator(true, 1.0f, "", BusyViewResources.INSTANCE.css().busy()));
SimpleBusyIndicator busyIndicator = new SimpleBusyIndicator(true, 1.0f);
busyIndicator.setImageStyleClass(BusyViewResources.INSTANCE.css().busy());
initWidget(busyIndicator);
}
}
@@ -37,6 +37,7 @@ public class FullscreenContainer<T extends Widget> {
String popup();
String toolbarInfo();
String toolbarAction();
String toolbarBusyIndicator();
String content();
String contentBorder();
}
@@ -89,6 +90,11 @@ public class FullscreenContainer<T extends Widget> {
toolbarUi.add(widget);
}
public void addToolbarBusyIndicator(Widget widget) {
widget.addStyleName(style.toolbarBusyIndicator());
toolbarUi.add(widget);
}
public void addToolbarInfo(Widget widget) {
widget.addStyleName(style.toolbarInfo());
toolbarUi.add(widget);
@@ -50,6 +50,13 @@
cursor: pointer;
padding: 10px;
}
.toolbarBusyIndicator {
display: inline-block;
height: 50px;
width: auto;
padding: 10px;
vertical-align: top;
}
.toolbarAction:hover {
background-color: #d79900;
}
@@ -237,7 +237,7 @@ public class RegattaOverviewPanel extends SimplePanel {
if (leaderboardsTabPanel != null) {
if (showLeaderboard) {
final CompetitorSelectionModel competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */ true);
final LeaderboardSettings leaderboardSettings = LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(null, null, null, /* autoExpandFirstRace */ false, /* showRegattaRank */ true);
final LeaderboardSettings leaderboardSettings = LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(null, null, null, /* autoExpandFirstRace */ false, /* showRegattaRank */ true, /* showCompetitorSailIdColumn */ true, /* showCompetitorFullNameColumn */ true);
sailingService.getLeaderboardsByEvent(eventDTO, new MarkedAsyncCallback<List<StrippedLeaderboardDTO>>(
new AsyncCallback<List<StrippedLeaderboardDTO>>() {
@Override
@@ -21,6 +21,7 @@ import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.common.ScoringSchemeType;
import com.sap.sailing.gwt.ui.client.DataEntryDialogWithBootstrap;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
import com.sap.sailing.gwt.ui.leaderboard.RankingMetricTypeFormatter;
import com.sap.sailing.gwt.ui.leaderboard.ScoringSchemeTypeFormatter;
import com.sap.sailing.gwt.ui.shared.BetterDateTimeBox;
@@ -134,20 +135,23 @@ public abstract class AbstractRegattaWithSeriesAndFleetsDialog<T> extends DataEn
if (additionalWidget != null) {
panel.add(additionalWidget);
}
Grid formGrid = new Grid(6, 2);
Grid formGrid = new Grid(7, 2);
panel.add(formGrid);
formGrid.setWidget(0, 0, new Label(stringMessages.startDate() + ":"));
formGrid.setWidget(0, 1, startDateBox);
formGrid.setWidget(1, 0, new Label(stringMessages.endDate() + ":"));
formGrid.setWidget(1, 1, endDateBox);
formGrid.setWidget(2, 0, new Label(stringMessages.scoringSystem() + ":"));
formGrid.setWidget(2, 1, scoringSchemeListBox);
formGrid.setWidget(3, 0, new Label(stringMessages.event() + ":"));
formGrid.setWidget(3, 1, sailingEventsListBox);
formGrid.setWidget(4, 0, new Label(stringMessages.courseArea() + ":"));
formGrid.setWidget(4, 1, courseAreaListBox);
formGrid.setWidget(5, 0, new Label(stringMessages.useStartTimeInference() + ":"));
formGrid.setWidget(5, 1, useStartTimeInferenceCheckBox);
formGrid.setWidget(0, 0, new Label(stringMessages.timeZone() + ":"));
formGrid.setWidget(0, 1, new Label(DateAndTimeFormatterUtil.getClientTimeZoneAsGMTString()));
formGrid.setWidget(1, 0, new Label(stringMessages.startDate() + ":"));
formGrid.setWidget(1, 1, startDateBox);
formGrid.setWidget(2, 0, new Label(stringMessages.endDate() + ":"));
formGrid.setWidget(2, 1, endDateBox);
formGrid.setWidget(3, 0, new Label(stringMessages.scoringSystem() + ":"));
formGrid.setWidget(3, 1, scoringSchemeListBox);
formGrid.setWidget(4, 0, new Label(stringMessages.event() + ":"));
formGrid.setWidget(4, 1, sailingEventsListBox);
formGrid.setWidget(5, 0, new Label(stringMessages.courseArea() + ":"));
formGrid.setWidget(5, 1, courseAreaListBox);
formGrid.setWidget(6, 0, new Label(stringMessages.useStartTimeInference() + ":"));
formGrid.setWidget(6, 1, useStartTimeInferenceCheckBox);
setupAdditionalWidgetsOnPanel(panel, formGrid);
return panel;
}
@@ -40,18 +40,18 @@ public class AddWindFixDialog extends DataEntryDialog<WindDTO> {
if(windDTO.trueWindSpeedInKnots == null) {
errorMessage = stringMessages.pleaseEnterAValue();
} else if(windDTO.trueWindSpeedInKnots != null && (windDTO.trueWindSpeedInKnots < 0.0 || windDTO.trueWindSpeedInKnots > 100.0)) {
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.speedInKnots(), "0", "100");
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.speedInKnots(), 0, 100);
} else if(windDTO.trueWindFromDeg == null){
errorMessage = stringMessages.pleaseEnterAValue();
} else if(windDTO.trueWindFromDeg != null && (windDTO.trueWindFromDeg < 0.0 || windDTO.trueWindFromDeg > 360.0)){
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.fromDeg(), "0", "360");
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.fromDeg(), 0, 360);
} else if(windDTO.measureTimepoint == null) {
errorMessage = stringMessages.pleaseEnterAValue();
} else if(windDTO.position != null) {
if(windDTO.position.getLatDeg() < -90.0 || windDTO.position.getLatDeg() > 90.0){
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.latitude(), "-90", "90");
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.latitude(), -90, 90);
} else if(windDTO.position.getLngDeg() < -180.0 || windDTO.position.getLngDeg() > 180.0){
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.longitude(), "-180", "180");
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.longitude(), -180, 180);
}
}
@@ -24,6 +24,7 @@ import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.gwt.ui.client.DataEntryDialogWithBootstrap;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
import com.sap.sailing.gwt.ui.shared.BetterDateTimeBox;
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
import com.sap.sailing.gwt.ui.shared.EventDTO;
@@ -195,24 +196,25 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap<EventDTO>
if (additionalWidget != null) {
panel.add(additionalWidget);
}
Grid formGrid = new Grid(8, 2);
Grid formGrid = new Grid(9, 2);
formGrid.setWidget(0, 0, new Label(stringMessages.name() + ":"));
formGrid.setWidget(0, 1, nameEntryField);
formGrid.setWidget(1, 0, new Label(stringMessages.description() + ":"));
formGrid.setWidget(1, 1, descriptionEntryField);
formGrid.setWidget(2, 0, new Label(stringMessages.venue() + ":"));
formGrid.setWidget(2, 1, venueEntryField);
formGrid.setWidget(3, 0, new Label(stringMessages.startDate() + ":"));
formGrid.setWidget(3, 1, startDateBox);
formGrid.setWidget(4, 0, new Label(stringMessages.endDate() + ":"));
formGrid.setWidget(4, 1, endDateBox);
formGrid.setWidget(5, 0, new Label(stringMessages.isPublic() + ":"));
formGrid.setWidget(5, 1, isPublicCheckBox);
formGrid.setWidget(6, 0, new Label(stringMessages.eventOfficialWebsiteURL() + ":"));
formGrid.setWidget(6, 1, officialWebsiteURLEntryField);
formGrid.setWidget(7, 0, new Label(stringMessages.eventSailorsInfoWebsiteURL() + ":"));
formGrid.setWidget(7, 1, sailorsInfoWebsiteURLEntryField);
formGrid.setWidget(3, 0, new Label(stringMessages.timeZone() + ":"));
formGrid.setWidget(3, 1, new Label(DateAndTimeFormatterUtil.getClientTimeZoneAsGMTString()));
formGrid.setWidget(4, 0, new Label(stringMessages.startDate() + ":"));
formGrid.setWidget(4, 1, startDateBox);
formGrid.setWidget(5, 0, new Label(stringMessages.endDate() + ":"));
formGrid.setWidget(5, 1, endDateBox);
formGrid.setWidget(6, 0, new Label(stringMessages.isPublic() + ":"));
formGrid.setWidget(6, 1, isPublicCheckBox);
formGrid.setWidget(7, 0, new Label(stringMessages.eventOfficialWebsiteURL() + ":"));
formGrid.setWidget(7, 1, officialWebsiteURLEntryField);
formGrid.setWidget(8, 0, new Label(stringMessages.eventSailorsInfoWebsiteURL() + ":"));
formGrid.setWidget(8, 1, sailorsInfoWebsiteURLEntryField);
TabLayoutPanel tabPanel = new TabLayoutPanel(30, Unit.PX);
tabPanel.setHeight("500px");
@@ -126,7 +126,6 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget {
@Override
public void onSuccess(RaceCourseDTO result) {
updateWaypointsAndControlPoints(result);
marks.refresh(result.getMarks());
}
@Override
@@ -134,5 +133,20 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget {
errorReporter.reportError("Could not load course: " + caught.getMessage());
}
});
sailingService.getMarksInRaceLog(leaderboardName, raceColumnName, fleetName,
new AsyncCallback<Iterable<MarkDTO>>() {
@Override
public void onSuccess(Iterable<MarkDTO> result) {
marks.refresh(result);
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError(
stringMessages.errorTryingToObtainTheMarksOfTheRace(
caught.getMessage()));
}
});
}
}
@@ -273,7 +273,8 @@ public class ReplicationPanel extends FlowPanel {
errorReporter.reportPersistentInformation(stringMessages.warningServerIsReplica());
registeredMasters.insertRow(i);
registeredMasters.setWidget(i, 0, new Label(stringMessages.replicatingFromMaster(replicatingFromMaster.getHostname(),
replicatingFromMaster.getMessagingPort(), replicatingFromMaster.getServletPort())));
replicatingFromMaster.getMessagingPort(), replicatingFromMaster.getServletPort(),
replicatingFromMaster.getMessagingHostname(), replicatingFromMaster.getExchangeName())));
i++;
addButton.setEnabled(false);
stopReplicationButton.setEnabled(true);
@@ -225,7 +225,7 @@ public class SwissTimingEventManagementPanel extends AbstractEventManagementPane
declinationCheckbox.setValue(true);
trackableRacesPanel.add(declinationCheckbox);
final CheckBox simulateWithStartTimeNow = new CheckBox(stringMessages.simulateWithStartTimeNow());
final CheckBox simulateWithStartTimeNow = new CheckBox(stringMessages.simulateAsLiveRace());
simulateWithStartTimeNow.setWordWrap(false);
simulateWithStartTimeNow.setValue(false);
trackableRacesPanel.add(simulateWithStartTimeNow);
@@ -24,6 +24,7 @@ import com.google.gwt.user.client.ui.CaptionPanel;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTMLTable.ColumnFormatter;
import com.google.gwt.user.client.ui.HorizontalPanel;
@@ -44,6 +45,7 @@ import com.sap.sailing.gwt.ui.client.shared.controls.SelectionCheckboxColumn;
import com.sap.sailing.gwt.ui.shared.RegattaDTO;
import com.sap.sailing.gwt.ui.shared.TracTracConfigurationDTO;
import com.sap.sailing.gwt.ui.shared.TracTracRaceRecordDTO;
import com.sap.sse.common.Duration;
import com.sap.sse.common.util.NaturalComparator;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
@@ -83,6 +85,7 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
private LabeledAbstractFilterablePanel<TracTracRaceRecordDTO> racesFilterablePanel;
private CellTable<TracTracRaceRecordDTO> racesTable;
private static final String ZERO_AS_STRING = "0";
public TracTracEventManagementPanel(final SailingServiceAsync sailingService, ErrorReporter errorReporter,
RegattaRefresher regattaRefresher, StringMessages stringMessages) {
@@ -229,17 +232,12 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
protected HorizontalPanel createRacesPanel() {
HorizontalPanel racesPanel = new HorizontalPanel();
CaptionPanel trackableRacesPanel = createTrackableRacesPanel();
racesPanel.add(trackableRacesPanel);
racesPanel.setCellWidth(trackableRacesPanel, "50%");
CaptionPanel trackedRacesPanel = createTrackedRacesPanel();
racesPanel.add(trackedRacesPanel);
racesPanel.setCellWidth(trackedRacesPanel, "50%");
return racesPanel;
}
@@ -276,10 +274,32 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
correctWindCheckBox.setWordWrap(false);
correctWindCheckBox.setValue(Boolean.TRUE);
final CheckBox simulateWithStartTimeNowCheckBox = new CheckBox(stringMessages.simulateWithStartTimeNow());
final TextBox offsetToStartTimeOfSimulatedRaceTextBox = new TextBox();
offsetToStartTimeOfSimulatedRaceTextBox.setWidth("40px");
offsetToStartTimeOfSimulatedRaceTextBox.setEnabled(false);
offsetToStartTimeOfSimulatedRaceTextBox.setValue(ZERO_AS_STRING);
final CheckBox simulateWithStartTimeNowCheckBox = new CheckBox(stringMessages.simulateAsLiveRace());
simulateWithStartTimeNowCheckBox.ensureDebugId("SimulateWithStartTimeNowCheckBox");
simulateWithStartTimeNowCheckBox.setWordWrap(false);
simulateWithStartTimeNowCheckBox.setValue(Boolean.FALSE);
simulateWithStartTimeNowCheckBox.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
offsetToStartTimeOfSimulatedRaceTextBox.setEnabled(simulateWithStartTimeNowCheckBox.getValue());
offsetToStartTimeOfSimulatedRaceTextBox.setFocus(simulateWithStartTimeNowCheckBox.getValue());
}
});
final FlowPanel simulateAsLiveRacePanel = new FlowPanel();
simulateAsLiveRacePanel.add(simulateWithStartTimeNowCheckBox);
final Label offsetToStartLabel = new Label(stringMessages.simulateWithOffset());
final HorizontalPanel simulateWithOffsetPanel = new HorizontalPanel();
simulateWithOffsetPanel.add(offsetToStartLabel);
simulateWithOffsetPanel.add(offsetToStartTimeOfSimulatedRaceTextBox);
final CheckBox ignoreTracTracMarkPassingsCheckbox = new CheckBox(stringMessages.useInternalAlgorithm());
ignoreTracTracMarkPassingsCheckbox.setWordWrap(false);
ignoreTracTracMarkPassingsCheckbox.setValue(Boolean.FALSE);
@@ -287,8 +307,9 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
layoutTable.setWidget(1, 0, trackSettingsLabel);
layoutTable.setWidget(1, 1, trackWindCheckBox);
layoutTable.setWidget(2, 1, correctWindCheckBox);
layoutTable.setWidget(3, 1, simulateWithStartTimeNowCheckBox);
layoutTable.setWidget(4, 1, ignoreTracTracMarkPassingsCheckbox);
layoutTable.setWidget(3, 1, simulateAsLiveRacePanel);
layoutTable.setWidget(4, 1, simulateWithOffsetPanel);
layoutTable.setWidget(5, 1, ignoreTracTracMarkPassingsCheckbox);
// Filter
Label racesFilterLabel = new Label(stringMessages.filterRacesByName() + ":");
@@ -310,8 +331,8 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
}
};
racesFilterablePanel.getTextBox().ensureDebugId("TrackableRacesFilterTextBox");
layoutTable.setWidget(5, 0, racesFilterLabel);
layoutTable.setWidget(5, 1, racesFilterablePanel);
layoutTable.setWidget(6, 0, racesFilterLabel);
layoutTable.setWidget(6, 1, racesFilterablePanel);
// Races
TextColumn<TracTracRaceRecordDTO> regattaNameColumn = new TextColumn<TracTracRaceRecordDTO>() {
@@ -357,7 +378,6 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
}
};
raceVisibilityColumn.setSortable(true);
SelectionCheckboxColumn<TracTracRaceRecordDTO> selectionCheckboxColumn = new SelectionCheckboxColumn<TracTracRaceRecordDTO>(tableResources.cellTableStyle().cellTableCheckboxSelected(),
tableResources.cellTableStyle().cellTableCheckboxDeselected(), tableResources.cellTableStyle().cellTableCheckboxColumnCell()) {
@Override
@@ -381,26 +401,24 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
raceNameColumn, boatClassColumn, raceStartTrackingColumn, raceStatusColumn));
racesTable.setSelectionModel(selectionCheckboxColumn.getSelectionModel(), selectionCheckboxColumn.getSelectionManager());
racesTable.setWidth("100%");
raceList.addDataDisplay(racesTable);
layoutTable.setWidget(6, 0, racesTable);
cellFormatter.setColSpan(6, 0, 2);
Button startTrackingButton = new Button(stringMessages.startTracking());
startTrackingButton.ensureDebugId("StartTrackingButton");
startTrackingButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
Duration offsetToStartTimeOfSimulatedRace = null;
if(simulateWithStartTimeNowCheckBox.getValue().booleanValue()) {
offsetToStartTimeOfSimulatedRace = getMillisecondsDurationFromMinutesAsString(offsetToStartTimeOfSimulatedRaceTextBox.getValue());
}
trackSelectedRaces(trackWindCheckBox.getValue(), correctWindCheckBox.getValue(),
simulateWithStartTimeNowCheckBox.getValue(), ignoreTracTracMarkPassingsCheckbox.getValue());
offsetToStartTimeOfSimulatedRace, ignoreTracTracMarkPassingsCheckbox.getValue());
}
});
layoutTable.setWidget(7, 1, startTrackingButton);
trackableRacesPanel.setContentWidget(layoutTable);
return trackableRacesPanel;
}
@@ -463,6 +481,17 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
return boatClassNames.substring(0, boatClassNames.length() - 2);
}
private Duration getMillisecondsDurationFromMinutesAsString(String minutesAsString) {
Duration result = null;
if (minutesAsString != null) {
Double minutesAsDouble = Double.parseDouble(minutesAsString);
if (minutesAsDouble != null) {
result = Duration.ONE_MINUTE.times(minutesAsDouble.longValue());
}
}
return result;
}
private void fillConfigurations() {
this.sailingService.getPreviousTracTracConfigurations(new MarkedAsyncCallback<List<TracTracConfigurationDTO>>(
new AsyncCallback<List<TracTracConfigurationDTO>>() {
@@ -551,7 +580,7 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
}));
}
private void trackSelectedRaces(boolean trackWind, boolean correctWind, final boolean simulateWithStartTimeNow, boolean ignoreTracTracMarkPassings) {
private void trackSelectedRaces(boolean trackWind, boolean correctWind, final Duration offsetToStartTimeOfSimulatedRace, boolean ignoreTracTracMarkPassings) {
String liveURI = liveURITextBox.getValue();
String storedURI = storedURITextBox.getValue();
String courseDesignUpdateURI = tracTracUpdateURITextBox.getValue();
@@ -577,7 +606,7 @@ public class TracTracEventManagementPanel extends AbstractEventManagementPanel {
}
if (checkBoatClassOK(selectedRegatta, selectedRaces)) {
sailingService.trackWithTracTrac(regattaIdentifier, selectedRaces, liveURI, storedURI,
courseDesignUpdateURI, trackWind, correctWind, simulateWithStartTimeNow, ignoreTracTracMarkPassings, tractracUsername,
courseDesignUpdateURI, trackWind, correctWind, offsetToStartTimeOfSimulatedRace, ignoreTracTracMarkPassings, tractracUsername,
tractracPassword, new MarkedAsyncCallback<Void>(new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
@@ -30,8 +30,8 @@ public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements R
private boolean redrawAllMarkersPendingForMinMaxBeingInitialized;
public RaceTimePanel(Timer timer, TimeRangeWithZoomProvider timeRangeProvider, StringMessages stringMessages,
RaceTimesInfoProvider raceTimesInfoProvider, boolean canReplayWhileLiveIsPossible) {
super(timer, timeRangeProvider, stringMessages, canReplayWhileLiveIsPossible);
RaceTimesInfoProvider raceTimesInfoProvider, boolean canReplayWhileLiveIsPossible, boolean isScreenLargeEnoughToOfferChartSupport) {
super(timer, timeRangeProvider, stringMessages, canReplayWhileLiveIsPossible, isScreenLargeEnoughToOfferChartSupport);
this.raceTimesInfoProvider = raceTimesInfoProvider;
selectedRace = null;
autoAdjustPlayMode = true;
@@ -86,6 +86,7 @@ import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
import com.sap.sailing.gwt.ui.shared.VenueDTO;
import com.sap.sailing.gwt.ui.shared.WindDTO;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
import com.sap.sse.common.Duration;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
@@ -116,7 +117,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
void trackWithTracTrac(RegattaIdentifier regattaToAddTo, Iterable<TracTracRaceRecordDTO> rrs, String liveURI,
String storedURI, String courseDesignUpdateURI, boolean trackWind, boolean correctWindByDeclination,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword) throws Exception;
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword) throws Exception;
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable<SwissTimingRaceRecordDTO> rrs, String hostname, int port,
boolean trackWind, boolean correctWindByDeclination, boolean useInternalMarkPassingAlgorithm) throws Exception;
@@ -78,6 +78,7 @@ import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
import com.sap.sailing.gwt.ui.shared.VenueDTO;
import com.sap.sailing.gwt.ui.shared.WindDTO;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
@@ -114,10 +115,10 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
* @param liveURI
* may be <code>null</code> or the empty string in which case the server will use the
* {@link TracTracRaceRecordDTO#liveURI} from the <code>rr</code> race record.
* @param simulateWithStartTimeNow
* if <code>true</code>, the connector will adjust the time stamps of all events received such that the
* @param offsetToStartTimeOfSimulatedRace
* if not <code>null</code>, the connector will adjust the time stamps of all events received such that the
* first mark passing for the first waypoint will be set to "now." It will delay the forwarding of all
* events received such that they seem to be sent in "real-time." So, more or less the time points
* events received such that they seem to be sent in "real-time" plus the <code>offsetToStartTimeOfSimulatedRace</code>. So, more or less the time points
* attached to the events sent to the receivers will again approximate the wall time.
* @param useInternalMarkPassingAlgorithm
* whether or not to ignore the TracTrac-provided mark passings; if <code>true</code>, a separate mark
@@ -128,7 +129,7 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan
*/
void trackWithTracTrac(RegattaIdentifier regattaToAddTo, Iterable<TracTracRaceRecordDTO> rrs, String liveURI,
String storedURI, String courseDesignUpdateURI, boolean trackWind, boolean correctWindByDeclination,
boolean simulateWithStartTimeNow, boolean useInternalMarkPassingAlgorithm, String tracTracUsername,
Duration offsetToStartTimeOfSimulatedRace, boolean useInternalMarkPassingAlgorithm, String tracTracUsername,
String tracTracPassword, AsyncCallback<Void> callback);
void trackWithSwissTiming(RegattaIdentifier regattaToAddTo, Iterable<SwissTimingRaceRecordDTO> rrs,
@@ -325,7 +325,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String messagingPortNumber();
String servletPortNumber();
String registeredAt(String string);
String replicatingFromMaster(String hostname, int jmsPort, int servletPort);
String replicatingFromMaster(String hostname, int jmsPort, int servletPort, String messagingHostname, String exchangeName);
String showWindSpeedSeries();
String showWindDirectionSeries();
String fleet();
@@ -361,7 +361,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String successfullyUpdatedScores();
String errorUpdatingScoresForLeaderboard(String leaderboardName, String message);
String maneuverTypesToShowWhenCompetitorIsClicked();
String simulateWithStartTimeNow();
String simulateAsLiveRace();
String simulateWithOffset();
String boatClassDoesNotMatchSelectedRegatta(String boatClass);
String regattaExistForSelectedBoatClass();
String reload();
@@ -436,7 +437,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String overallDetailsToShow();
String hhmmssUnit();
String actionAddWindData();
String valueMustBeBetweenMinMax(String name, String minValue, String maxValue);
String valueMustBeBetweenMinMax(String name, int minValue, int maxValue);
String valueMustBeGreaterThan(String name, String minValue);
String optional();
String pleaseEnterAValue();
String latitude();
@@ -503,6 +505,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String sideToWhichMarkAtLegStartWasRounded();
String raceIsLive(String raceName);
String racesAreLive(String raceNames);
String regattaIsLive(String regattaName);
String regattasAreLive(String regattaNames);
String scoringSchemeHighPointFirstGetsOne();
String scoringSchemeHighPointFirstGetsTen();
String knotsUnit();
@@ -1107,6 +1111,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String invalidSelection();
String advancePassId();
String pleaseSelectAScoringResult();
String timeZone();
String eventOfficialWebsiteURL();
String eventSailorsInfoWebsiteURL();
String eventOverviewURL();
@@ -1444,4 +1449,6 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String requiresValidRegatta();
String couldNotObtainRace(String regattaLikeName, String raceColumnName, String fleetName, String technicalErrorMessage);
String errorTryingToCreateEmbeddedMap(String message);
String transparentBufferLineOnHover();
String bufferLineStrokeWeight();
}
@@ -336,7 +336,7 @@ courseMiddleLine=Course middle line
messagingPortNumber=Messaging port number (0 for default)
servletPortNumber=Servlet port number
registeredAt=Registered at {0}
replicatingFromMaster=Replicating from master {0}, messaging port {1}, servlet port {2}
replicatingFromMaster=Replicating from master {0}:{2}, messaging port {3}:{1}, exchange {4}
showWindSpeedSeries=Show wind speed data
showWindDirectionSeries=Show wind directions data
fleet=Fleet
@@ -371,7 +371,8 @@ apply=Apply
successfullyUpdatedScores=Successfully updated scores
errorUpdatingScoresForLeaderboard=Error updating scores for leaderboard {0}: {1}
maneuverTypesToShowWhenCompetitorIsClicked=Maneuver types to show when competitor is clicked
simulateWithStartTimeNow=Simulate with "now" as start time
simulateAsLiveRace=Simulate as live race
simulateWithOffset=Offset before start in minutes:
boatClassDoesNotMatchSelectedRegatta=The selected races contain boat classes which are not the same as the boat class ''{0}'' of the selected regatta. No races will be loaded.
regattaExistForSelectedBoatClass=There is at least one regatta for the selected boat classes. Really create default regatta(s) for those race(s)?
reload=Reload
@@ -456,6 +457,7 @@ totalAverageSpeedOverGroundTooltip=Average speed over ground across the regatta.
hhmmssUnit=hh:mm:ss
actionAddWindData=Add wind data
valueMustBeBetweenMinMax=The value of ''{0}'' must be between {1} and {2}.
valueMustBeGreaterThan=The value of ''{0}'' must be greater than {1}.
optional=optional
pleaseEnterAValue=Please enter a value.
latitude=Latitude
@@ -527,6 +529,8 @@ sideToWhichMarkAtLegStartWasRounded=Mark rounded to
sideToWhichMarkAtLegStartWasRoundedTooltip=Side to which the mark at leg start was rounded.
raceIsLive=Race {0} is live
racesAreLive=Races {0} are live
regattaIsLive=Regatta {0} is live
regattasAreLive=Regattas {0} are live
knotsUnit=kts
knotsValue={0,number,#0.0} kts
knotsRange={0,number,#0.0} - {1,number,#0.0} kts
@@ -1078,6 +1082,7 @@ sponsorImageURLs=Sponsor Image URLs
invalidSelection=The current selection isn''t valid.
advancePassId=Advance Pass ID
pleaseSelectAScoringResult=Please select a scoring result...
timeZone=Time zone
eventOfficialWebsiteURL=Official Website URL
eventSailorsInfoWebsiteURL=Sailors Info Website URL
eventOverviewURL=Event Overview URL
@@ -1411,3 +1416,5 @@ pleaseSelect=Please select
requiresValidRegatta=This page requires a valid regatta, race column and fleet name to identify the race to show.
couldNotObtainRace=Could not obtain a race with name {1} for fleet {2} for a regatta with name {0}: {3}
errorTryingToCreateEmbeddedMap=Error trying to create the embedded map: {0}
transparentBufferLineOnHover=Transparent buffer lines on hover of helplines
bufferLineStrokeWeight=Buffer line stroke weight
@@ -337,7 +337,7 @@ courseMiddleLine=Kursmittellinie
messagingPortNumber=Messaging-Portnummer (0 für Default)
servletPortNumber=Servlet Portnummer
registeredAt=Registriert {0}
replicatingFromMaster=Repliziert von master {0}, Messaging Port {1}, Servlet Port {2}
replicatingFromMaster=Repliziert von master {0}:{2}, Messaging Port {3}:{1}, Exchange {4}
showWindSpeedSeries=Daten für Windgeschwindigkeit zeigen
showWindDirectionSeries=Daten für Windrichtung zeigen
fleet=Flotte
@@ -372,7 +372,8 @@ apply=Übernehmen
successfullyUpdatedScores=Ergebnisse erfolgreich aktualisiert
errorUpdatingScoresForLeaderboard=Fehler beim Aktualisieren der Ergebnisse für {0}: {1}
maneuverTypesToShowWhenCompetitorIsClicked=Anzuzeigende Manövertypen für angeklickte Teilnehmer
simulateWithStartTimeNow=Simulieren mit "jetzt" als Startzeit
simulateAsLiveRace=Simuliere als Live Rennen
simulateWithOffset=Zeit bis zum Start in Minuten:
boatClassDoesNotMatchSelectedRegatta=Die ausgewählten Rennen enthalten eine Bootsklasse, die nicht der Bootsklasse der ausgewählten Regatta ''{0}'' entspricht. Es werden keine Rennen geladen.
regattaExistForSelectedBoatClass=Es gibt mindestens eine Regatta zu den ausgewählten Bootsklassen. Dennoch Default-Regatta für diese(s) Rennen anlegen?
reload=Neu laden
@@ -456,7 +457,8 @@ totalAverageSpeedOverGround=\u2205 FüG
totalAverageSpeedOverGroundTooltip=Durchschnittliche Fahrt über Grund über die gesamte Regatta.
hhmmssUnit=hh:mm:ss
actionAddWindData=Winddaten hinzufügen
valueMustBeBetweenMinMax=Der Wert von ''{0}'' muß zwischen {1} und {2} sein.
valueMustBeBetweenMinMax=Der Wert von ''{0}'' muss zwischen {1} und {2} sein.
valueMustBeGreaterThan=Der Wert von ''{0}'' muss größer als {1} sein.
optional=optional
pleaseEnterAValue=Bitte geben Sie einen Wert ein.
latitude=Breite
@@ -528,6 +530,8 @@ sideToWhichMarkAtLegStartWasRounded=Tonne gerundet an
sideToWhichMarkAtLegStartWasRoundedTooltip=Seite, an der die Bahnmarke am Schenkelstart gerundet wurde
raceIsLive=Rennen {0} ist live
racesAreLive=Rennen {0} sind live
regattaIsLive=Regatta {0} ist live
regattasAreLive=Regatten {0} sind live
scoringSchemeHighPointFirstGetsOne=High Point System, Gewinner erhält 1 Punkt
scoringSchemeHighPointFirstGetsTen=High Point System, Gewinner erhält 10 Punkte
knotsUnit=kn
@@ -1073,6 +1077,7 @@ sponsorImageURLs=Sponsorenlogo-URLs
invalidSelection=Die aktuelle Selektion ist nicht gültig.
advancePassId=Pass ID erhöhen
pleaseSelectAScoringResult=Bitte ein Ergebnis auswählen...
timeZone=Zeitzone
eventOfficialWebsiteURL=URL der offiziellen Veranstaltungswebseite
eventSailorsInfoWebsiteURL=URL zur Webseite mit Seglerinfos
eventOverviewURL=URL der Veranstaltungsübersicht
@@ -1402,3 +1407,5 @@ pleaseSelect=Bitte auswählen
requiresValidRegatta=Diese Seite benötigt eine gültige Regatta, Rennspalte und einen gültigen Gruppennamen um die anzuzeigende Wettfahrt zu identifizieren.
couldNotObtainRace=Wettfahrt namens {1} für Gruppe {2} in einer Regatta names {0} konnte nicht gefunden werden: {3}
errorTryingToCreateEmbeddedMap=Fehler beim Erstellen der eingebetteten Karte: {0}
transparentBufferLineOnHover=Transparente Pufferlinien bei Maus über Hilfslinien
bufferLineStrokeWeight=Linienbreite der Pufferlinien
@@ -329,7 +329,7 @@ courseMiddleLine=Средняя линия курса
messagingPortNumber=Номер порта обмена сообщениями ( по умолчанию 0)
servletPortNumber=Номер порта сервлета
registeredAt=Зарегистрирован в {0}
replicatingFromMaster=Дублирование с основного {0}, порт передачи обмена сообщениями {1}, порт сервлета {2}
replicatingFromMaster=Replicating from master {0}:{2}, messaging port {3}:{1}, exchange {4}
showWindSpeedSeries=Показать данные о силе ветра
showWindDirectionSeries=Показать данные о направлении ветра
fleet=Флот
@@ -364,7 +364,8 @@ apply=Применить
successfullyUpdatedScores=Очки обновлены успешно
errorUpdatingScoresForLeaderboard=Ошибка обновления очков для таблицы лидеров {0}: {1}
maneuverTypesToShowWhenCompetitorIsClicked=Типы маневров для отображения при нажатии на участника
simulateWithStartTimeNow=Моделирования с "сейчас" в качестве времени начала
simulateAsLiveRace=Simulate as live race
simulateWithOffset=Offset before start in minutes:
boatClassDoesNotMatchSelectedRegatta=Выбранные гонки содержат классы судов не соответствующие классу судов ''{0}'' выбранной регаты.
regattaExistForSelectedBoatClass=Есть только одна регата для выбранных классов судов.
reload=Перезагрузить
@@ -440,6 +441,7 @@ totalAverageSpeedOverGroundTooltip=Средняя скорость относи
hhmmssUnit=чч:мм:сс
actionAddWindData=Добавить данные о ветре
valueMustBeBetweenMinMax=Значение ''{0}''должно быть в пределах от {1} до {2}.
valueMustBeGreaterThan=The value of ''{0}'' must be greater than {1}.
optional=Дополнительно
pleaseEnterAValue=Введите, пожалуйста, значение.
latitude=Широта
@@ -511,6 +513,8 @@ sideToWhichMarkAtLegStartWasRounded=Отметка округленная до
sideToWhichMarkAtLegStartWasRoundedTooltip=Сторона в которую округляется отметка на старте этапа.
raceIsLive=Гонка {0} в прямом эфире
racesAreLive=Гонки {0} в прямом эфире
regattaIsLive=Регата {0} в прямом эфире
regattasAreLive=Регаты {0} в прямом эфире
knotsUnit=Узлы
knotsValue={0,number,#0.0} Узлы
knotsRange={0,number,#0.0} - {1,number,#0.0} Узлы
@@ -1026,6 +1030,7 @@ imageURLs=Image URLs
videoURLs=Video URLs
sponsorImageURLs=Sponsor Image URLs
pleaseSelectAScoringResult=Please select a scoring result...
timeZone=Time zone
eventOfficialWebsiteURL=Official Website URL
eventSailorsInfoWebsiteURL=Sailors Info Website URL
eventOverviewURL=Event Overview URL
@@ -1341,3 +1346,5 @@ pleaseSelect=Please select
requiresValidRegatta=This page requires a valid regatta, race column and fleet name to identify the race to show.
couldNotObtainRace=Could not obtain a race with name {1} for fleet {2} for a regatta with name {0}: {3}
errorTryingToCreateEmbeddedMap=Error trying to create the embedded map: {0}
transparentBufferLineOnHover=Transparent buffer lines on hover of helplines
bufferLineStrokeWeight=Buffer line stroke weight
@@ -328,7 +328,7 @@ setFixedPassing=Set time as mark passing
maximumSpeedOverGroundInKnotsTooltip=比赛中参赛队的最大实际速度
twoMarkControlPoint=2-mark-controlpoint
earlyStarters=Early starters
replicatingFromMaster=Replicating from master {0}, messaging port {1}, servlet port {2}
replicatingFromMaster=Replicating from master {0}:{2}, messaging port {3}:{1}, exchange {4}
latitude=Latitude
filterByLeaderboard=Filter by Leaderboard
fromDeg=从 (角度)
@@ -538,6 +538,7 @@ connectors=Connectors
dampeningInterval=Dampening Interval
trackBasedEstimationWindSourceTypeTooltip=Calculated data from the competitor tracks
valueMustBeBetweenMinMax=The value of ''{0}'' must be between {1} and {2}.
valueMustBeGreaterThan=The value of ''{0}'' must be greater than {1}.
orMultipleEmails=or multiple E-Mails separated by comma
searchEvents=Search for events
explainNoConnectionsFromReplicas=No connections from a replica found. You can connect replicas by using their AdminConsole.
@@ -839,12 +840,16 @@ refreshIntervalMustBeGreaterThanXSeconds=刷新间隔必须大于0秒 {0}
authorName=Author name
raceIsInStartphase=开始阶段
pleaseSelectAScoringResult=Please select a scoring result...
timeZone=Time zone
portSide=左舷
explainReplicationHostname=Hostname where the replication master is running on.
igtimiAccounts=Igtimi Accounts
windChart=Wind Chart
events=活动
raceIsLive=Race {0} is live
racesAreLive=Races {0} are live
regattaIsLive=Regatta {0} is live
regattasAreLive=Regattas {0} are live
operatorNotContains=Not Contains
windwardDistanceToCompetitorFarthestAheadInMetersTooltip=迎/顺风航段时离开上风/下风第一名的平行距离或横风时的实际距离name 名字
errorAddingResultImportUrl=Error adding result import URL: {0}
@@ -1066,13 +1071,13 @@ polarSheetMinimumConfidenceMeasure=Minimum confidence measure
operator=operator
tractracUsername=TracTrac username
webWindSourceTypeName=Manual
raceIsLive=Race {0} is live
sapSailingAnalytics=航行分析
trackWind=Track Wind
rawFixes=All fixes (including outliers)
showCompetitorFullNameColumn=Show Competitor Full Name
disableRaceFilter=Disable filter
simulateWithStartTimeNow=Simulate with "now" as start time
simulateAsLiveRace=Simulate as live race
simulateWithOffset=Offset before start in minutes:
polarSheetOutlierDetectionRadiusTooltip=The radius used in the distance based outlierndetection algorithm.
noWindFixesAvailable=No Wind-Fixes available.
correctScoreFor=Correct score for competitor {0} in race {1}
@@ -1356,3 +1361,5 @@ pleaseSelect=Please select
requiresValidRegatta=This page requires a valid regatta, race column and fleet name to identify the race to show.
couldNotObtainRace=Could not obtain a race with name {1} for fleet {2} for a regatta with name {0}: {3}
errorTryingToCreateEmbeddedMap=Error trying to create the embedded map: {0}
transparentBufferLineOnHover=Transparent buffer lines on hover of helplines
bufferLineStrokeWeight=Buffer line stroke weight
@@ -89,7 +89,13 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
private static ClientResources resources = GWT.create(ClientResources.class);
protected static TimePanelCss timePanelCss = TimePanelCssResources.INSTANCE.css();
public TimePanel(Timer timer, TimeRangeWithZoomProvider timeRangeProvider, StringMessages stringMessages, boolean canReplayWhileLiveIsPossible) {
/**
* @param isScreenLargeEnoughToOfferChartSupport
* if <code>true</code>, the right padding will be set such that the time panel lines up with charts such
* as the competitor chart or the wind chart shown above it
*/
public TimePanel(Timer timer, TimeRangeWithZoomProvider timeRangeProvider, StringMessages stringMessages,
boolean canReplayWhileLiveIsPossible, boolean isScreenLargeEnoughToOfferChartSupport) {
this.timer = timer;
this.timeRangeProvider = timeRangeProvider;
this.stringMessages = stringMessages;
@@ -105,7 +111,9 @@ public class TimePanel<T extends TimePanelSettings> extends SimplePanel implemen
timePanelSliderFlowWrapper = new FlowPanel();
timePanelSlider.setStyleName("timePanelSlider");
timePanelSlider.getElement().getStyle().setPaddingLeft(66, Unit.PX);
timePanelSlider.getElement().getStyle().setPaddingRight(66, Unit.PX);
if (isScreenLargeEnoughToOfferChartSupport) {
timePanelSlider.getElement().getStyle().setPaddingRight(66, Unit.PX);
}
timePanelSliderFlowWrapper.add(timePanelSlider);
playSpeedImg = resources.timesliderPlaySpeedIcon();
@@ -83,7 +83,9 @@ public abstract class AbstractRaceChart extends AbsolutePanel implements RaceSel
timeRangeWithZoomProvider.addTimeZoomChangeListener(this);
timeRangeWithZoomProvider.addTimeRangeChangeListener(this);
chartsCss.ensureInjected();
busyIndicator = new SimpleBusyIndicator(/* busy */ true, 2.0f, chartsCss.busyIndicatorStyle(), chartsCss.busyIndicatorImageStyle());
busyIndicator = new SimpleBusyIndicator(/* busy */ true, 2.0f);
busyIndicator.setPanelStyleClass(chartsCss.busyIndicatorStyle());
busyIndicator.setImageStyleClass(chartsCss.busyIndicatorImageStyle());
settingsButton = createSettingsButton();
settingsButton.setStyleName(chartsCss.settingsButtonStyle());
settingsButton.addStyleName(chartsCss.settingsButtonBackgroundImage());
@@ -0,0 +1,103 @@
package com.sap.sailing.gwt.ui.client.shared.racemap;
import com.google.gwt.maps.client.base.LatLng;
import com.google.gwt.maps.client.mvc.MVCArray;
import com.google.gwt.maps.client.overlays.Polyline;
import com.google.gwt.user.client.Timer;
/**
* Moves a {@link Polyline} from its current position to a target position in a given duration with a fixed
* {@link #ANIMATION_PERIOD_MILLIS animation interval}. Since the timer may be triggered at non-exact intervals, the
* offset per animation tick is calculated based on the current time for each iteration.
* <p>
*
* If an animation is still going on, it is permissible for clients to invoke
* {@link #setNextPositionAndTransitionMillis(MVCArray, long)} which will have the effect that from its current position
* reached so far the {@link Polyline} will then be animated to the next target position in the specified time interval.
*
* @author Jonas Dann
*
*/
public class AdvantageLineAnimator extends Timer {
/**
* Time between two animation steps
*/
private static final int ANIMATION_PERIOD_MILLIS = 100;
/**
* The polyline to animate by updating its {@link Polyline#getPath() path}
*/
private final Polyline advantageLine;
/**
* The last time the coordinates in the {@link #advantageLine}'s path were updated
*/
private long lastTime;
/**
* The remaining time for the animation to move the {@link #advantageLine} to its {@link #nextPosition target
* position}. If <code>-1</code>, the {@link #advantageLine} will be moved to its {@link #nextPosition next target
* position} in one step.
*/
private long durationMillis = -1;
/**
* The "to-be" / target position to which to move the {@link #advantageLine}'s path gradually during the remaining
* {@link #durationMillis}.
*/
private MVCArray<LatLng> nextPosition;
public AdvantageLineAnimator(Polyline advantageLine) {
if (advantageLine == null) {
throw new NullPointerException("Advantage line must not be null");
}
this.advantageLine = advantageLine;
}
/**
* @param timeForPositionTransitionMillis if <code>-1</code> then no animation is requested and the {@link #advantageLine} will
* be moved to its {@link #nextPosition next target position} in one step.
*
* @param nextPosition the next target position for the {@link #advantageLine}; if <code>null</code>, no animation will happen at all
*/
public void setNextPositionAndTransitionMillis(MVCArray<LatLng> nextPosition, long timeForPositionTransitionMillis) {
if (nextPosition.getLength() != advantageLine.getPath().getLength()) {
throw new IllegalArgumentException("The next animation position for a polyline with "+advantageLine.getPath().getLength()+
" elements must have the same number of positions but did have "+nextPosition.getLength());
}
this.nextPosition = nextPosition;
this.lastTime = System.currentTimeMillis();
this.durationMillis = timeForPositionTransitionMillis;
this.scheduleRepeating(ANIMATION_PERIOD_MILLIS);
}
@Override
public void run() {
final long time = System.currentTimeMillis();
final double moveFactor; // how much of the delta to the nextPosition shall this tick move the advantage line?
if (durationMillis > 0) {
long deltaTime = time - lastTime;
moveFactor = Math.min(1.0, (double) deltaTime / (double) durationMillis); // don't overshoot
durationMillis -= deltaTime;
} else {
moveFactor = 1;
}
if (nextPosition != null) {
final MVCArray<LatLng> currentPosition = this.advantageLine.getPath();
for (int i = 0; i < nextPosition.getLength(); i++) {
final LatLng currentLatLng = currentPosition.get(i);
final LatLng nextLatLng = nextPosition.get(i);
currentPosition.setAt(i, LatLng.newInstance(currentLatLng.getLatitude() + (nextLatLng.getLatitude() - currentLatLng.getLatitude()) * moveFactor,
currentLatLng.getLongitude() + (nextLatLng.getLongitude() - currentLatLng.getLongitude()) * moveFactor));
}
}
if (durationMillis <= 0) {
cancel();
}
lastTime = time;
}
public void removeAnimation() {
this.durationMillis = -1;
}
}
@@ -0,0 +1,57 @@
package com.sap.sailing.gwt.ui.client.shared.racemap;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.maps.client.events.click.ClickMapHandler;
import com.google.gwt.maps.client.events.mouseout.MouseOutMapEvent;
import com.google.gwt.maps.client.events.mouseout.MouseOutMapHandler;
import com.google.gwt.maps.client.events.mouseover.MouseOverMapEvent;
import com.google.gwt.maps.client.events.mouseover.MouseOverMapHandler;
import com.google.gwt.maps.client.overlays.Polyline;
import com.google.gwt.maps.client.overlays.PolylineOptions;
public class Hoverline {
private static final double TRANSPARENT = 0;
private static final double VISIBLE = 0.2d;
private final Polyline hoverline;
private final PolylineOptions options;
public Hoverline(final Polyline polyline, PolylineOptions polylineOptions, final RaceMap map) {
this.options = PolylineOptions.newInstance();
this.options.setClickable(polylineOptions.getClickable());
this.options.setGeodesic(polylineOptions.getGeodesic());
this.options.setMap(polyline.getMap());
this.options.setPath(polyline.getPath());
this.options.setStrokeColor(polylineOptions.getStrokeColor());
this.options.setZindex(polylineOptions.getZindex());
this.hoverline = Polyline.newInstance(this.options);
this.hoverline.setVisible(false);
polyline.addMouseOverHandler(new MouseOverMapHandler() {
@Override
public void onEvent(MouseOverMapEvent event) {
options.setStrokeOpacity(map.getSettings().getTransparentHoverlines() ? TRANSPARENT : VISIBLE);
options.setStrokeWeight(map.getSettings().getHoverlineStrokeWeight());
options.setVisible(true);
hoverline.setOptions(options);
}
});
hoverline.addMouseOutMoveHandler(new MouseOutMapHandler() {
@Override
public void onEvent(MouseOutMapEvent event) {
hoverline.setVisible(false);
}
});
}
public HandlerRegistration addClickHandler(ClickMapHandler handler) {
return this.hoverline.addClickHandler(handler);
}
public HandlerRegistration addMouseOutMoveHandler(MouseOutMapHandler handler) {
return this.hoverline.addMouseOutMoveHandler(handler);
}
public HandlerRegistration addMouseOverHandler(MouseOverMapHandler handler) {
return this.hoverline.addMouseOverHandler(handler);
}
}
@@ -142,6 +142,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
public static final String GET_RACE_MAP_DATA_CATEGORY = "getRaceMapData";
public static final String GET_WIND_DATA_CATEGORY = "getWindData";
private static final String COMPACT_HEADER_STYLE = "compactHeader";
private MapWidget map;
/**
@@ -176,6 +178,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
*/
private Polyline advantageLine;
private AdvantageLineAnimator advantageTimer;
/**
* The windward of two Polylines representing a triangle between startline and first mark.
*/
@@ -534,9 +538,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
RaceMap.this.add(sapLogo);
}
map.setControls(ControlPosition.LEFT_TOP, combinedWindPanel);
combinedWindPanel.getParent().addStyleName("CombinedWindPanelParentDiv");
map.setControls(ControlPosition.LEFT_TOP, trueNorthIndicatorPanel);
trueNorthIndicatorPanel.getParent().addStyleName("TrueNorthIndicatorPanelParentDiv");
adjustLeftControlsIndent();
RaceMap.this.raceMapImageManager.loadMapIcons(map);
map.setSize("100%", "100%");
@@ -710,6 +713,10 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
for (CompetitorInfoOverlay infoOverlay : competitorInfoOverlays.values()) {
infoOverlay.removeCanvasPositionAndRotationTransition();
}
// remove the advantage line animation
if (advantageTimer != null) {
advantageTimer.removeAnimation();
}
}
public void redraw() {
@@ -766,6 +773,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
final Iterable<CompetitorDTO> competitorsToShow = getCompetitorsToShow();
if (race != null) {
final long transitionTimeInMillis = calculateTimeForPositionTransitionInMillis(newTime, oldTime);
final com.sap.sse.common.Util.Triple<Map<CompetitorDTO, Date>, Map<CompetitorDTO, Date>, Map<CompetitorDTO, Boolean>> fromAndToAndOverlap =
fixesAndTails.computeFromAndTo(newTime, competitorsToShow, settings.getEffectiveTailLengthInMilliseconds());
int requestID = ++boatPositionRequestIDCounter;
@@ -777,7 +785,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
final boolean updateMarksAndLinesExceptAdvantageLineInCallback;
if (getRaceMapDataForAllOverlappingAndTipsOfNonOverlapping != null) {
asyncActionsExecutor.execute(getRaceMapDataForAllOverlappingAndTipsOfNonOverlapping, GET_RACE_MAP_DATA_CATEGORY,
getRaceMapDataCallback(oldTime, newTime, fromAndToAndOverlap.getC(), competitorsToShow, requestID,
getRaceMapDataCallback(newTime, transitionTimeInMillis, fromAndToAndOverlap.getC(), competitorsToShow, requestID,
/* updateMarksAndLinesExceptAdvantageLineInCallback */ true));
updateMarksAndLinesExceptAdvantageLineInCallback = false; // don't do this again in the second call that mainly fetches
requestID = ++boatPositionRequestIDCounter;
@@ -789,7 +797,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
GetRaceMapDataAction getRaceMapDataAction = new GetRaceMapDataAction(sailingService, competitorSelection.getAllCompetitors(), race,
useNullAsTimePoint() ? null : newTime, fromAndToAndOverlap.getA(), fromAndToAndOverlap.getB(), /* extrapolate */ true, (settings.isShowSimulationOverlay() ? simulationOverlay.getLegIdentifier() : null));
asyncActionsExecutor.execute(getRaceMapDataAction, GET_RACE_MAP_DATA_CATEGORY,
getRaceMapDataCallback(oldTime, newTime, fromAndToAndOverlap.getC(), competitorsToShow, requestID,
getRaceMapDataCallback(newTime, transitionTimeInMillis, fromAndToAndOverlap.getC(), competitorsToShow, requestID,
updateMarksAndLinesExceptAdvantageLineInCallback));
// draw the wind into the map, get the combined wind
@@ -809,7 +817,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
List<com.sap.sse.common.Util.Pair<WindSource, WindTrackInfoDTO>> windSourcesToShow = new ArrayList<com.sap.sse.common.Util.Pair<WindSource, WindTrackInfoDTO>>();
if (windInfo != null) {
lastCombinedWindTrackInfoDTO = windInfo;
showAdvantageLine(competitorsToShow, newTime);
showAdvantageLine(competitorsToShow, newTime, transitionTimeInMillis);
for (WindSource windSource : windInfo.windTrackInfoByWindSource.keySet()) {
WindTrackInfoDTO windTrackInfoDTO = windInfo.windTrackInfoByWindSource.get(windSource);
switch (windSource.getType()) {
@@ -882,8 +890,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
* the advantage line will be updated.
*/
private AsyncCallback<RaceMapDataDTO> getRaceMapDataCallback(
final Date oldTime,
final Date newTime,
final long transitionTimeInMillis,
final Map<CompetitorDTO, Boolean> hasTailOverlapForCompetitor,
final Iterable<CompetitorDTO> competitorsToShow, final int requestID,
final boolean updateMarksAndLinesExceptAdvantageLineInCallback) {
@@ -908,7 +916,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
startedProcessingRequestID = requestID;
// Do boat specific actions
Map<CompetitorDTO, List<GPSFixDTO>> boatData = raceMapDataDTO.boatPositions;
long timeForPositionTransitionMillis = calculateTimeForPositionTransition(newTime, oldTime);
fixesAndTails.updateFixes(boatData, hasTailOverlapForCompetitor, RaceMap.this, transitionTimeInMillis);
Iterable<CompetitorDTO> competitorsForWhichNewFixesWereReveiced =
fixesAndTails.updateFixes(boatData, hasTailOverlapForCompetitor, RaceMap.this, timeForPositionTransitionMillis);
if (!Util.isEmpty(competitorsForWhichNewFixesWereReveiced)) {
@@ -916,7 +924,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
showCompetitorInfoOnMap(newTime, timeForPositionTransitionMillis, competitorSelection.getSelectedFilteredCompetitors());
// even though the wind data is retrieved by a separate call, re-draw the advantage line because it needs to
// adjust to new boat positions
showAdvantageLine(competitorsToShow, newTime);
showAdvantageLine(competitorsToShow, newTime, transitionTimeInMillis);
}
if (douglasMarkers != null) {
removeAllMarkDouglasPeuckerpoints();
@@ -1153,7 +1161,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
}
private long calculateTimeForPositionTransition(final Date newTime, final Date oldTime) {
private long calculateTimeForPositionTransitionInMillis(final Date newTime, final Date oldTime) {
final long timeForPositionTransitionMillis;
boolean hasTimeJumped = oldTime != null && Math.abs(oldTime.getTime() - newTime.getTime()) > 3*timer.getRefreshInterval();
if (timer.getPlayState() == PlayStates.Playing && !hasTimeJumped) {
@@ -1177,7 +1185,6 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
Polyline tail = fixesAndTails.getTail(competitorDTO);
if (tail == null) {
tail = fixesAndTails.createTailAndUpdateIndices(competitorDTO, tailsFromTime, tailsToTime, this);
tail.setMap(map);
} else {
fixesAndTails.updateTail(tail, competitorDTO, tailsFromTime, tailsToTime,
(int) (timeForPositionTransitionMillis==-1?-1:timeForPositionTransitionMillis/2));
@@ -1241,7 +1248,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
return null;
}
private void showAdvantageLine(Iterable<CompetitorDTO> competitorsToShow, Date date) {
private void showAdvantageLine(Iterable<CompetitorDTO> competitorsToShow, Date date, long timeForPositionTransitionMillis) {
if (map != null && lastRaceTimesInfo != null && quickRanks != null && lastCombinedWindTrackInfoDTO != null) {
boolean drawAdvantageLine = false;
if (settings.getHelpLinesSettings().isVisible(HelpLineTypes.ADVANTAGELINE)) {
@@ -1307,6 +1314,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
break;
}
MVCArray<LatLng> nextPath = MVCArray.newInstance();
LatLng advantageLinePos1 = calculatePositionAlongRhumbline(posAheadOfFirstBoat,
coordinateSystem.mapDegreeBearing(rotatedBearingDeg1), advantageLineLengthInKm / 2.0);
LatLng advantageLinePos2 = calculatePositionAlongRhumbline(posAheadOfFirstBoat,
@@ -1320,26 +1328,27 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
options.setStrokeOpacity(0.5);
advantageLine = Polyline.newInstance(options);
advantageTimer = new AdvantageLineAnimator(advantageLine);
MVCArray<LatLng> pointsAsArray = MVCArray.newInstance();
pointsAsArray.insertAt(0, advantageLinePos1);
pointsAsArray.insertAt(1, advantageLinePos2);
advantageLine.setPath(pointsAsArray);
advantageLine.setMap(map);
Hoverline advantageHoverline = new Hoverline(advantageLine, options, this);
advantageLineMouseOverHandler = new AdvantageLineMouseOverMapHandler(
bearingOfCombinedWindInDeg, new Date(windFix.measureTimepoint));
advantageLine.addMouseOverHandler(advantageLineMouseOverHandler);
advantageLine.addMouseOutMoveHandler(new MouseOutMapHandler() {
advantageHoverline.addMouseOutMoveHandler(new MouseOutMapHandler() {
@Override
public void onEvent(MouseOutMapEvent event) {
map.setTitle("");
}
});
advantageLine.setMap(map);
} else {
advantageLine.getPath().removeAt(1);
advantageLine.getPath().removeAt(0);
advantageLine.getPath().insertAt(0, advantageLinePos1);
advantageLine.getPath().insertAt(1, advantageLinePos2);
nextPath.push(advantageLinePos1);
nextPath.push(advantageLinePos2);
advantageTimer.setNextPositionAndTransitionMillis(nextPath, timeForPositionTransitionMillis);
advantageLineMouseOverHandler.setTrueWindBearing(bearingOfCombinedWindInDeg);
advantageLineMouseOverHandler.setDate(new Date(windFix.measureTimepoint));
}
@@ -1350,6 +1359,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
if (advantageLine != null) {
advantageLine.setMap(null);
advantageLine = null;
advantageTimer = null;
}
}
}
@@ -1580,20 +1590,20 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
pointsAsArray = MVCArray.newInstance();
lineToShowOrRemoveOrUpdate = Polyline.newInstance(options);
lineToShowOrRemoveOrUpdate.setPath(pointsAsArray);
lineToShowOrRemoveOrUpdate.setMap(map);
Hoverline lineToShowOrRemoveOrUpdateHoverline = new Hoverline(lineToShowOrRemoveOrUpdate, options, this);
lineToShowOrRemoveOrUpdate.addMouseOverHandler(new MouseOverMapHandler() {
@Override
public void onEvent(MouseOverMapEvent event) {
map.setTitle(lineInfoProvider.getLineInfo());
}
});
lineToShowOrRemoveOrUpdate.addMouseOutMoveHandler(new MouseOutMapHandler() {
lineToShowOrRemoveOrUpdateHoverline.addMouseOutMoveHandler(new MouseOutMapHandler() {
@Override
public void onEvent(MouseOutMapEvent event) {
map.setTitle("");
}
});
lineToShowOrRemoveOrUpdate.setMap(map);
} else {
pointsAsArray = lineToShowOrRemoveOrUpdate.getPath();
pointsAsArray.removeAt(1);
@@ -2347,6 +2357,12 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
updateCoordinateSystemFromSettings();
requiredRedraw = true;
}
if (newSettings.getTransparentHoverlines() != settings.getTransparentHoverlines()) {
settings.setTransparentHoverlines(newSettings.getTransparentHoverlines());
}
if (newSettings.getHoverlineStrokeWeight() != settings.getHoverlineStrokeWeight()) {
settings.setHoverlineStrokeWeight(newSettings.getHoverlineStrokeWeight());
}
if (requiredRedraw) {
redraw();
}
@@ -2469,6 +2485,25 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
map.triggerResize();
zoomMapToNewBounds(settings.getZoomSettings().getNewBounds(RaceMap.this));
}
// Adjust RaceMap headers to avoid overlapping based on the RaceMap width
boolean isCompactHeader = this.getOffsetWidth() <= 600;
getLeftHeaderPanel().setStyleName(COMPACT_HEADER_STYLE, isCompactHeader);
getRightHeaderPanel().setStyleName(COMPACT_HEADER_STYLE, isCompactHeader);
// Adjust combined wind and true north indicator panel indent, based on the RaceMap height
if (combinedWindPanel.getParent() != null && trueNorthIndicatorPanel.getParent() != null) {
this.adjustLeftControlsIndent();
}
}
private void adjustLeftControlsIndent() {
combinedWindPanel.getParent().setStyleName("CombinedWindPanelParentDiv");
trueNorthIndicatorPanel.getParent().setStyleName("TrueNorthIndicatorPanelParentDiv");
String leftControlsIndentStyle = getLeftControlsIndentStyle();
if (leftControlsIndentStyle != null) {
combinedWindPanel.getParent().addStyleName(leftControlsIndentStyle);
trueNorthIndicatorPanel.getParent().addStyleName(leftControlsIndentStyle);
}
}
@Override
@@ -2512,23 +2547,25 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
public Polyline createTail(final CompetitorDTO competitor, List<LatLng> points) {
PolylineOptions options = createTailStyle(competitor, displayHighlighted(competitor));
Polyline result = Polyline.newInstance(options);
MVCArray<LatLng> pointsAsArray = MVCArray.newInstance(points.toArray(new LatLng[0]));
result.setPath(pointsAsArray);
result.addClickHandler(new ClickMapHandler() {
result.setMap(map);
Hoverline resultHoverline = new Hoverline(result, options, this);
final ClickMapHandler clickHandler = new ClickMapHandler() {
@Override
public void onEvent(ClickMapEvent event) {
showCompetitorInfoWindow(competitor, event.getMouseEvent().getLatLng());
}
});
};
result.addClickHandler(clickHandler);
resultHoverline.addClickHandler(clickHandler);
result.addMouseOverHandler(new MouseOverMapHandler() {
@Override
public void onEvent(MouseOverMapEvent event) {
map.setTitle(competitor.getSailID() + ", " + competitor.getName());
}
});
result.addMouseOutMoveHandler(new MouseOutMapHandler() {
resultHoverline.addMouseOutMoveHandler(new MouseOutMapHandler() {
@Override
public void onEvent(MouseOutMapEvent event) {
map.setTitle("");
@@ -2617,4 +2654,11 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe
}
return mapOptions;
}
/**
* @return CSS style name to adjust the indent of left controls (combined wind and true north indicator).
*/
protected String getLeftControlsIndentStyle() {
return null;
}
}
@@ -20,6 +20,10 @@ public class RaceMapSettings extends AbstractSettings {
private RaceMapHelpLinesSettings helpLinesSettings;
private boolean transparentHoverlines = false; // as discussed with Stefan on 2015-12-08
private int hoverlineStrokeWeight = 15; // as discussed with Stefan on 2015-12-08
private long tailLengthInMilliseconds = 100000l;
private double buoyZoneRadiusInMeters = 0.0;
@@ -55,6 +59,8 @@ public class RaceMapSettings extends AbstractSettings {
public RaceMapSettings(RaceMapSettings settings) {
this.buoyZoneRadiusInMeters = settings.buoyZoneRadiusInMeters;
this.helpLinesSettings = new RaceMapHelpLinesSettings(settings.getHelpLinesSettings().getVisibleHelpLineTypes());
this.transparentHoverlines = settings.transparentHoverlines;
this.hoverlineStrokeWeight = settings.hoverlineStrokeWeight;
this.maneuverTypesToShow = settings.maneuverTypesToShow;
this.showDouglasPeuckerPoints = settings.showDouglasPeuckerPoints;
this.showOnlySelectedCompetitors = settings.showOnlySelectedCompetitors;
@@ -154,6 +160,22 @@ public class RaceMapSettings extends AbstractSettings {
this.helpLinesSettings = helpLinesSettings;
}
public boolean getTransparentHoverlines() {
return this.transparentHoverlines;
}
public void setTransparentHoverlines(boolean transparentHoverlines) {
this.transparentHoverlines = transparentHoverlines;
}
public int getHoverlineStrokeWeight() {
return this.hoverlineStrokeWeight;
}
public void setHoverlineStrokeWeight(int hoverlineStrokeWeight) {
this.hoverlineStrokeWeight = hoverlineStrokeWeight;
}
public boolean isShowSelectedCompetitorsInfo() {
return showSelectedCompetitorsInfo;
}
@@ -24,11 +24,14 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings.HelpLineTypes;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapZoomSettings.ZoomTypes;
import com.sap.sse.common.Util;
import com.sap.sse.gwt.client.controls.IntegerBox;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.Validator;
import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent;
public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<RaceMapSettings> {
private static final int MAX_BUOY_ZONE_RADIUS_IN_METERS = 100;
private static final int MAX_STROKE_WEIGHT = 33;
//Initializing the lists to prevent a null pointer exception in the first validation call
private List<Util.Pair<CheckBox, ManeuverType>> checkboxAndManeuverType = new ArrayList<Util.Pair<CheckBox, ManeuverType>>();
private List<Util.Pair<CheckBox, ZoomTypes>> checkboxAndZoomType = new ArrayList<Util.Pair<CheckBox,ZoomTypes>>();
@@ -43,6 +46,8 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
private CheckBox showSelectedCompetitorsInfoCheckBox;
private LongBox tailLengthBox;
private DoubleBox buoyZoneRadiusBox;
private CheckBox transparentHoverlines;
private IntegerBox hoverlineStrokeWeight;
private boolean showViewSimulation;
private final StringMessages stringMessages;
@@ -211,6 +216,17 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
vp.add(createHelpLineCheckBox(dialog, HelpLineTypes.STARTLINETOFIRSTMARKTRIANGLE));
vp.add(createHelpLineCheckBox(dialog, HelpLineTypes.COURSEGEOMETRY));
transparentHoverlines = dialog.createCheckbox(stringMessages.transparentBufferLineOnHover());
transparentHoverlines.setValue(initialSettings.getTransparentHoverlines());
vp.add(transparentHoverlines);
HorizontalPanel hoverlineStrokeWeightPanel = new HorizontalPanel();
Label hoverlineStrokeWeightLabel = new Label(stringMessages.bufferLineStrokeWeight() + ":");
hoverlineStrokeWeightPanel.add(hoverlineStrokeWeightLabel);
hoverlineStrokeWeight = dialog.createIntegerBox(initialSettings.getHoverlineStrokeWeight(), 3);
hoverlineStrokeWeightPanel.add(hoverlineStrokeWeight);
vp.add(hoverlineStrokeWeightPanel);
return vp;
}
@@ -267,6 +283,8 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
result.setBuoyZoneRadiusInMeters(value);
}
}
result.setTransparentHoverlines(transparentHoverlines.getValue());
result.setHoverlineStrokeWeight(hoverlineStrokeWeight.getValue());
return result;
}
@@ -304,8 +322,10 @@ public class RaceMapSettingsDialogComponent implements SettingsDialogComponent<R
if (valueToValidate.getHelpLinesSettings().isVisible(HelpLineTypes.BOATTAILS) && valueToValidate.getTailLengthInMilliseconds() <= 0) {
errorMessage = stringMessages.tailLengthMustBePositive();
} else if (valueToValidate.getHelpLinesSettings().isVisible(HelpLineTypes.BUOYZONE)
&& (valueToValidate.getBuoyZoneRadiusInMeters() < 0.0 || valueToValidate.getBuoyZoneRadiusInMeters() > 100.0)) {
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.buoyZone(), "0", "100");
&& (valueToValidate.getBuoyZoneRadiusInMeters() < 0 || valueToValidate.getBuoyZoneRadiusInMeters() > MAX_BUOY_ZONE_RADIUS_IN_METERS)) {
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.buoyZone(), 0, 100);
} else if (valueToValidate.getHoverlineStrokeWeight() < 0 || valueToValidate.getHoverlineStrokeWeight() > MAX_STROKE_WEIGHT) {
errorMessage = stringMessages.valueMustBeBetweenMinMax(stringMessages.bufferLineStrokeWeight(), 0, MAX_STROKE_WEIGHT);
}
return errorMessage;
}
@@ -60,4 +60,12 @@ public class DateAndTimeFormatterUtil {
return result;
}
public static String getClientTimeZoneAsGMTString() {
Date now = new Date();
@SuppressWarnings("deprecation")
int localeTimezoneOffset = now.getTimezoneOffset();
TimeZone localeTimeZone = TimeZone.createTimeZone(localeTimezoneOffset);
return localeTimeZone.getGMTString(now);
}
}
@@ -1,5 +1,6 @@
.competitorFilterContainer {
width: 400px;
max-width: 400px;
width: 100%;
height: 2.14em;
background-color: #FFFFFF;
margin-left: 0px;
@@ -22,7 +23,7 @@
.searchInput {
font-size: .933333333333333em;
height: 2.142857142857143em;
width: 280px;
width: 70%;
border: none;
background-color: #eaeaea;
padding: 0;
@@ -149,15 +149,15 @@ public abstract class ExpandableSortableColumn<C> extends LeaderboardSortableCol
*/
public void toggleExpansion() {
if (isExpansionEnabled()) {
final boolean oldBusyState = getLeaderboardPanel().getBusyIndicator().isBusy();
getLeaderboardPanel().getBusyIndicator().setBusy(true);
final boolean oldBusyState = getLeaderboardPanel().isBusy();
getLeaderboardPanel().setBusyState(true);
setTogglingInProcess(true);
final CellTable<LeaderboardRowDTO> table = getLeaderboardPanel().getLeaderboardTable();
if (isExpanded()) {
for (AbstractSortableColumnWithMinMax<LeaderboardRowDTO, ?> column : getAllVisibleChildren()) {
getLeaderboardPanel().removeColumn(column); // removes only the children currently displayed
}
getLeaderboardPanel().getBusyIndicator().setBusy(false);
getLeaderboardPanel().setBusyState(false);
setTogglingInProcess(false);
// important: toggle expanded state after asking for all visible children
setExpanded(!isExpanded());
@@ -177,7 +177,7 @@ public abstract class ExpandableSortableColumn<C> extends LeaderboardSortableCol
}
getLeaderboardPanel().getLeaderboardTable().redraw();
}
getLeaderboardPanel().getBusyIndicator().setBusy(oldBusyState);
getLeaderboardPanel().setBusyState(oldBusyState);
setTogglingInProcess(false);
}
});
@@ -258,7 +258,7 @@ public class LeaderboardEntryPoint extends AbstractSailingEntryPoint {
result = LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(null, null,
/* overallDetails */ overallDetails, null,
/* autoExpandFirstRace */false, refreshIntervalMillis, numberOfLastRacesToShow,
raceColumnSelectionStrategy);
raceColumnSelectionStrategy, /* showCompetitorSailIdColumns */ true, /*showCompetitorFullNameColumn*/ true);
}
return result;
}
@@ -102,6 +102,8 @@ import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator;
import com.sap.sse.gwt.client.controls.busyindicator.BusyStateChangeListener;
import com.sap.sse.gwt.client.controls.busyindicator.BusyStateProvider;
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
import com.sap.sse.gwt.client.player.PlayStateListener;
import com.sap.sse.gwt.client.player.TimeListener;
@@ -122,7 +124,8 @@ import com.sap.sse.gwt.client.useragent.UserAgentDetails;
*
*/
public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayStateListener, DisplayedLeaderboardRowsProvider,
Component<LeaderboardSettings>, IsEmbeddableComponent, CompetitorSelectionChangeListener, LeaderboardFetcher {
Component<LeaderboardSettings>, IsEmbeddableComponent, CompetitorSelectionChangeListener, LeaderboardFetcher,
BusyStateProvider {
public static final String LOAD_LEADERBOARD_DATA_CATEGORY = "loadLeaderboardData";
protected static final NumberFormat scoreFormat = NumberFormat.getFormat("0.##");
@@ -296,6 +299,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
private ImageResource playIcon;
private final BusyIndicator busyIndicator;
private final Set<BusyStateChangeListener> busyStateChangeListeners;
/**
* Tells whether the leaderboard settings were explicitly changed by an external call to
@@ -344,7 +348,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
private Element elementToBlur;
private boolean showSelectionCheckbox;
private List<LeaderboardUpdateListener> leaderboardUpdateListener;
private final List<LeaderboardUpdateListener> leaderboardUpdateListener;
private boolean initialCompetitorFilterHasBeenApplied = false;
private final boolean showCompetitorFilterStatus;
@@ -477,8 +481,8 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
break;
}
final boolean oldBusyState = getBusyIndicator().isBusy();
getBusyIndicator().setBusy(true);
final boolean oldBusyState = isBusy();
setBusyState(true);
Runnable doWhenNecessaryDetailHasBeenLoaded = new Runnable() {
@Override
public void run() {
@@ -501,7 +505,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
getLeaderboardTable().sortColumn(raceColumnByRaceName, /* ascending */true);
}
}
getBusyIndicator().setBusy(oldBusyState);
setBusyState(oldBusyState);
}
};
if (oldShallAddOverallDetails == shallAddOverallDetails() || oldShallAddOverallDetails || getLeaderboard().hasOverallDetails()) {
@@ -669,6 +673,13 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
final String twoLetterIsoCountryCode = competitor.getTwoLetterIsoCountryCode();
final String flagImageURL = competitor.getFlagImageURL();
boolean showBoatColor = !isShowCompetitorFullName() && LeaderboardPanel.this.isEmbedded && preSelectedRace != null;
if (showBoatColor) {
String competitorColor = LeaderboardPanel.this.competitorSelectionProvider.getColor(
competitorFetcher.getCompetitor(object), LeaderboardPanel.this.preSelectedRace).getAsHtml();
sb.appendHtmlConstant("<div style=\"border-bottom: 2px solid " + competitorColor + ";\">");
}
if (flagImageURL != null && !flagImageURL.isEmpty()) {
sb.appendHtmlConstant("<img src=\"" + flagImageURL + "\" width=\"18px\" height=\"12px\" title=\"" + competitor.getName() + "\"/>");
sb.appendHtmlConstant("&nbsp;");
@@ -685,6 +696,9 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
}
}
sb.appendEscaped(competitor.getSailID());
if (showBoatColor) {
sb.appendHtmlConstant("</div>");
}
}
@Override
@@ -1824,7 +1838,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
contentPanel.setStyleName(STYLE_LEADERBOARD_CONTENT);
busyIndicator = new SimpleBusyIndicator(false, 0.8f);
busyIndicator.ensureDebugId("BusyIndicator");
busyStateChangeListeners = new HashSet<>();
// the information panel
if (!isEmbedded) {
@@ -1920,7 +1934,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
filterClearButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
getBusyIndicator().setBusy(true);
setBusyState(true);
competitorFilterPanel.clearAllActiveFilters();
timeChanged(new Date(), null);
}
@@ -2237,19 +2251,19 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
@Override
public void onSuccess(LeaderboardDTO result) {
updateLeaderboard(result);
getBusyIndicator().setBusy(false);
setBusyState(false);
}
@Override
public void onFailure(Throwable caught) {
getBusyIndicator().setBusy(false);
setBusyState(false);
getErrorReporter()
.reportError("Error trying to obtain leaderboard contents: " + caught.getMessage(),
true /* silentMode */);
}
});
} else {
getBusyIndicator().setBusy(false);
setBusyState(false);
}
}
@@ -2399,32 +2413,13 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
scoreCorrectionLastUpdateTimeLabel.setText("");
}
List<com.sap.sse.common.Util.Pair<RaceColumnDTO, FleetDTO>> liveRaces = leaderboard.getLiveRaces(timer.getLiveTimePointInMillis());
boolean hasLiveRace = !liveRaces.isEmpty();
boolean hasLiveRace = !leaderboard.getLiveRaces(timer.getLiveTimePointInMillis()).isEmpty();
liveRaceLabel.setText(hasLiveRace ? getLiveRacesText() : "");
if (hasLiveRace) {
String liveRaceText = "";
if(liveRaces.size() == 1) {
com.sap.sse.common.Util.Pair<RaceColumnDTO, FleetDTO> liveRace = liveRaces.get(0);
liveRaceText = stringMessages.raceIsLive("'" + liveRace.getA().getRaceColumnName() + "'");
} else {
String raceNames = "";
for (com.sap.sse.common.Util.Pair<RaceColumnDTO, FleetDTO> liveRace : liveRaces) {
raceNames += "'" + liveRace.getA().getRaceColumnName() + "', ";
}
// remove last ", "
raceNames = raceNames.substring(0, raceNames.length() - 2);
liveRaceText = stringMessages.racesAreLive(raceNames);
}
liveRaceLabel.setText(liveRaceText);
} else {
liveRaceLabel.setText("");
}
scoreCorrectionLastUpdateTimeLabel.setVisible(!hasLiveRace);
liveRaceLabel.setVisible(hasLiveRace);
}
informLeaderboardUpdateListenersAboutLeaderboardUpdated(leaderboard);
getBusyIndicator().setBusy(false);
setBusyState(false);
}
}
@@ -3147,16 +3142,6 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
}
}
@Override
public BusyIndicator getBusyIndicator() {
return busyIndicator;
}
@Override
public boolean hasBusyIndicator() {
return true;
}
private Iterable<LeaderboardRowDTO> getSelectedRows() {
return leaderboardSelectionModel.getSelectedSet();
}
@@ -3197,7 +3182,7 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
if (timer != null) {
timer.removeTimeListener(this);
}
if(leaderboardUpdateListener != null) {
if (leaderboardUpdateListener != null) {
leaderboardUpdateListener.clear();
}
}
@@ -3256,18 +3241,20 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
public String getLiveRacesText() {
String result = "";
List<com.sap.sse.common.Util.Pair<RaceColumnDTO, FleetDTO>> liveRaces = leaderboard.getLiveRaces(timer.getLiveTimePointInMillis());
boolean isMeta = leaderboard.type.isMetaLeaderboard();
if (!liveRaces.isEmpty()) {
if(liveRaces.size() == 1) {
if (liveRaces.size() == 1) {
com.sap.sse.common.Util.Pair<RaceColumnDTO, FleetDTO> liveRace = liveRaces.get(0);
result = stringMessages.raceIsLive("'" + liveRace.getA().getRaceColumnName() + "'");
String text = "'" + liveRace.getA().getRaceColumnName() + "'";
result = isMeta ? stringMessages.regattaIsLive(text) : stringMessages.raceIsLive(text);
} else {
String raceNames = "";
String names = "";
for (com.sap.sse.common.Util.Pair<RaceColumnDTO, FleetDTO> liveRace : liveRaces) {
raceNames += "'" + liveRace.getA().getRaceColumnName() + "', ";
names += "'" + liveRace.getA().getRaceColumnName() + "', ";
}
// remove last ", "
raceNames = raceNames.substring(0, raceNames.length() - 2);
result = stringMessages.racesAreLive(raceNames);
names = names.substring(0, names.length() - 2);
result = isMeta ? stringMessages.regattasAreLive(names) : stringMessages.racesAreLive(names);
}
}
return result;
@@ -3277,4 +3264,29 @@ public class LeaderboardPanel extends SimplePanel implements TimeListener, PlayS
public String getDependentCssClassName() {
return "leaderboard";
}
@Override
public void addBusyStateChangeListener(BusyStateChangeListener listener) {
busyStateChangeListeners.add(listener);
}
@Override
public void removeBusyStateChangeListener(BusyStateChangeListener listener) {
busyStateChangeListeners.remove(listener);
}
@Override
public boolean isBusy() {
return busyIndicator.isBusy();
}
@Override
public void setBusyState(boolean isBusy) {
if (busyIndicator.isBusy() != isBusy) {
busyIndicator.setBusy(isBusy);
for (BusyStateChangeListener listener : busyStateChangeListeners) {
listener.onBusyStateChange(isBusy);
}
}
}
}
@@ -78,11 +78,11 @@ public class LeaderboardSettingsFactory {
/* refresh interval */ null, /* name of race to sort */ nameOfRaceToSort,
/* ascending */ true, /* updateUponPlayStateChange */ true, raceColumnSelection.getType(),
/*showAddedScores*/ false, /*showOverallRacesCompleted*/ false,
/*showCompetitorSailIdColumns*/showCompetitorSailIdColumn, /*showCompetitorFullNameColumn*/showCompetitorNameColumn);
showCompetitorSailIdColumn, showCompetitorNameColumn);
break;
case Replay:
settings = createNewDefaultSettings(namesOfRaceColumnsToShow, namesOfRacesToShow, nameOfRaceToSort, /* autoExpandFirstRace */
nameOfRaceColumnToShow != null, showRegattaRank);
nameOfRaceColumnToShow != null, showRegattaRank, showCompetitorSailIdColumn, showCompetitorNameColumn);
break;
}
return settings;
@@ -127,28 +127,32 @@ public class LeaderboardSettingsFactory {
* such a meta leaderboard exists; if multiple such meta leaderboards exist, they are all shown
*/
public LeaderboardSettings createNewDefaultSettings(List<String> namesOfRaceColumnsToShow,
List<String> namesOfRacesToShow, String nameOfRaceToSort, boolean autoExpandPreSelectedRace, Boolean showRegattaRank) {
List<String> namesOfRacesToShow, String nameOfRaceToSort, boolean autoExpandPreSelectedRace, Boolean showRegattaRank,
boolean showCompetitorSailIdColumn, boolean showCompetitorFullNameColumn) {
final List<DetailType> overallDetails = createOverallDetailsForShowRegattaRank(showRegattaRank);
return createNewDefaultSettings(namesOfRaceColumnsToShow, namesOfRacesToShow, overallDetails,
nameOfRaceToSort, autoExpandPreSelectedRace, /* refreshIntervalMillis */ null);
nameOfRaceToSort, autoExpandPreSelectedRace, /* refreshIntervalMillis */ null,
showCompetitorSailIdColumn, showCompetitorFullNameColumn);
}
/**
* Like {@link #createNewDefaultSettings(List, List, String, boolean, boolean)}, only that an additional refresh interval for auto-refresh
* Like {@link #createNewDefaultSettings(List, List, String, boolean, boolean, boolean, boolean)}, only that an additional refresh interval for auto-refresh
* may be specified; if <code>null</code>, no auto-refresh shall be performed
*/
public LeaderboardSettings createNewDefaultSettings(List<String> namesOfRaceColumnsToShow,
private LeaderboardSettings createNewDefaultSettings(List<String> namesOfRaceColumnsToShow,
List<String> namesOfRacesToShow, List<DetailType> overallDetailsToShow, String nameOfRaceToSort,
boolean autoExpandPreSelectedRace, Long refreshIntervalMillis) {
boolean autoExpandPreSelectedRace, Long refreshIntervalMillis, boolean showCompetitorSailIdColumns, boolean showCompetitorFullNameColumn) {
return createNewDefaultSettings(namesOfRaceColumnsToShow, namesOfRacesToShow, overallDetailsToShow,
nameOfRaceToSort, autoExpandPreSelectedRace, refreshIntervalMillis,
/* numberOfLastRacesToShow */null, /* raceColumnSelectionStrategy */ RaceColumnSelectionStrategies.EXPLICIT);
/* numberOfLastRacesToShow */null, /* raceColumnSelectionStrategy */ RaceColumnSelectionStrategies.EXPLICIT,
showCompetitorSailIdColumns, showCompetitorFullNameColumn);
}
public LeaderboardSettings createNewDefaultSettings(List<String> namesOfRaceColumnsToShow,
List<String> namesOfRacesToShow, List<DetailType> overallDetailsToShow, String nameOfRaceToSort,
boolean autoExpandPreSelectedRace, Long refreshIntervalMillis, Integer numberOfLastRacesToShow,
RaceColumnSelectionStrategies raceColumnSelectionStrategy) {
RaceColumnSelectionStrategies raceColumnSelectionStrategy, boolean showCompetitorSailIdColumns,
boolean showCompetitorFullNameColumn) {
if (namesOfRaceColumnsToShow != null && namesOfRacesToShow != null) {
throw new IllegalArgumentException("Can specify race columns either by column or by race name, not both");
}
@@ -168,7 +172,7 @@ public class LeaderboardSettingsFactory {
autoExpandPreSelectedRace, refreshIntervalMillis, /* sort by column */ nameOfRaceToSort,
/* ascending */ true, /* updateUponPlayStateChange */ true, raceColumnSelectionStrategy,
/*showAddedScores*/ false, /*showOverallRacesCompleted*/ false,
/*showCompetitorSailIdColumns*/true, /*showCompetitorFullNameColumn*/true);
showCompetitorSailIdColumns, showCompetitorFullNameColumn);
}
public LeaderboardSettings mergeLeaderboardSettings(LeaderboardSettings settingsWithRaceSelection, LeaderboardSettings settingsWithDetails) {
@@ -106,7 +106,7 @@ public class LeaderboardUrlConfigurationDialog extends SettingsDialog<Leaderboar
}
LeaderboardSettings settings = LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(
namesOfRaceColumnsToShow, /* namesOfRacesToShow */null, /* nameOfRaceToSort */null, /* autoExpandPreSelectedRace */
false, /* showRegattaRank */ true);
false, /* showRegattaRank */ true, /* showCompetitorSailIdColumn */ true, /* showCompetitorFullNameColumn */ true);
leaderboardSettingsDialogComponent = new LeaderboardSettingsDialogComponent(settings.getManeuverDetailsToShow(),
settings.getLegDetailsToShow(), settings.getRaceDetailsToShow(), settings.getOverallDetailsToShow(), raceList,
/* select all races by default */ raceList, new ExplicitRaceColumnSelection(),
@@ -3,8 +3,10 @@ package com.sap.sailing.gwt.ui.leaderboard;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.dom.client.Style.FontWeight;
@@ -35,7 +37,7 @@ import com.sap.sse.gwt.client.useragent.UserAgentDetails;
* A panel managing multiple {@link LeaderboardPanel}s (e.g. from a meta leaderboard) so that the user can switch between them.
* @author Frank
*/
public class MultiLeaderboardPanel extends AbstractLazyComponent<LeaderboardSettings> implements TimeListener {
public class MultiLeaderboardPanel extends AbstractLazyComponent<LeaderboardSettings> implements TimeListener, SelectedLeaderboardChangeProvider {
private LeaderboardPanel selectedLeaderboardPanel;
private FlowPanel selectedLeaderboardFlowPanel;
@@ -60,7 +62,8 @@ public class MultiLeaderboardPanel extends AbstractLazyComponent<LeaderboardSett
private final String metaLeaderboardName;
private final boolean isEmbedded;
private List<LeaderboardUpdateListener> leaderboardUpdateListener;
private final Set<LeaderboardUpdateListener> leaderboardUpdateListeners;
private final Set<SelectedLeaderboardChangeListener> selectedLeaderboardChangeListeners;
public MultiLeaderboardPanel(SailingServiceAsync sailingService, String metaLeaderboardName, AsyncActionsExecutor asyncActionsExecutor,
Timer timer, boolean isEmbedded, String preselectedLeaderboardName, RaceIdentifier preselectedRace,
@@ -81,13 +84,14 @@ public class MultiLeaderboardPanel extends AbstractLazyComponent<LeaderboardSett
selectedLeaderboardPanel = null;
leaderboardNamesAndDisplayNames = new ArrayList<Util.Pair<String, String>>();
leaderboardNamesAndSettings = new HashMap<String, LeaderboardSettings>();
leaderboardUpdateListener = new ArrayList<LeaderboardUpdateListener>();
leaderboardUpdateListeners = new HashSet<LeaderboardUpdateListener>();
selectedLeaderboardChangeListeners = new HashSet<SelectedLeaderboardChangeListener>();
}
private LeaderboardSettings getOrCreateLeaderboardSettings(String leaderboardName, LeaderboardSettings currentLeaderboardSettings) {
LeaderboardSettings newLeaderboardSettings = leaderboardNamesAndSettings.get(leaderboardName);
if(newLeaderboardSettings == null) {
newLeaderboardSettings = LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(null, null, null, false, /* showRegattaRank */ true);
newLeaderboardSettings = LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(null, null, null, false, /* showRegattaRank */ true, /* showCompetitorSailIdColumn */ true, /* showCompetitorFullNameColumn */ true);
}
if(currentLeaderboardSettings != null) {
newLeaderboardSettings = LeaderboardSettingsFactory.getInstance().mergeLeaderboardSettings(newLeaderboardSettings, currentLeaderboardSettings);
@@ -152,7 +156,7 @@ public class MultiLeaderboardPanel extends AbstractLazyComponent<LeaderboardSett
}
public void addLeaderboardUpdateListener(LeaderboardUpdateListener listener) {
this.leaderboardUpdateListener.add(listener);
this.leaderboardUpdateListeners.add(listener);
}
public void setLeaderboardNames(List<Util.Pair<String, String>> newLeaderboardNamesAndDisplayNames) {
@@ -177,6 +181,10 @@ public class MultiLeaderboardPanel extends AbstractLazyComponent<LeaderboardSett
});
}
// public LeaderboardPanel getSelectedLeaderboardPanel() {
// return selectedLeaderboardPanel;
// }
//
private void updateLeaderboardSelection() {
if(leaderboardsTabPanel != null) {
leaderboardsTabPanel.clear();
@@ -215,16 +223,16 @@ public class MultiLeaderboardPanel extends AbstractLazyComponent<LeaderboardSett
selectedLeaderboardFlowPanel = (FlowPanel) leaderboardsTabPanel.getWidget(newTabIndex);
LeaderboardSettings newLeaderboardSettings = getOrCreateLeaderboardSettings(newSelectedLeaderboardName, leaderboardNamesAndSettings.get(selectedLeaderboardName));
selectedLeaderboardPanel = new LeaderboardPanel(sailingService, asyncActionsExecutor, newLeaderboardSettings, isEmbedded,
LeaderboardPanel newSelectedLeaderboardPanel = new LeaderboardPanel(sailingService, asyncActionsExecutor, newLeaderboardSettings, isEmbedded,
/* preselectedRace*/ null, new CompetitorSelectionModel(true), timer,
null, newSelectedLeaderboardName, errorReporter, stringMessages, userAgent,
showRaceDetails, /* competitorSearchTextBox */ null, /* showSelectionCheckbox */ true, /* raceTimesInfoProvider */null,
false, /* adjustTimerDelay */ true, /*autoApplyTopNFilter*/ false, false);
selectedLeaderboardFlowPanel.add(selectedLeaderboardPanel);
for(LeaderboardUpdateListener listener: leaderboardUpdateListener) {
selectedLeaderboardPanel.addLeaderboardUpdateListener(listener);
selectedLeaderboardFlowPanel.add(newSelectedLeaderboardPanel);
for(LeaderboardUpdateListener listener: leaderboardUpdateListeners) {
newSelectedLeaderboardPanel.addLeaderboardUpdateListener(listener);
}
setSelectedLeaderboard(newSelectedLeaderboardPanel);
} else {
if(selectedLeaderboardPanel != null && selectedLeaderboardFlowPanel != null) {
selectedLeaderboardPanel.removeAllListeners();
@@ -254,4 +262,23 @@ public class MultiLeaderboardPanel extends AbstractLazyComponent<LeaderboardSett
}
}
@Override
public void addSelectedLeaderboardChangeListener(SelectedLeaderboardChangeListener listener) {
selectedLeaderboardChangeListeners.add(listener);
}
@Override
public void removeSelectedLeaderboardChangeListener(SelectedLeaderboardChangeListener listener) {
selectedLeaderboardChangeListeners.remove(listener);
}
@Override
public void setSelectedLeaderboard(LeaderboardPanel selectedLeaderboard) {
if(this.selectedLeaderboardPanel != selectedLeaderboard) {
this.selectedLeaderboardPanel = selectedLeaderboard;
for (SelectedLeaderboardChangeListener listener : selectedLeaderboardChangeListeners) {
listener.onSelectedLeaderboardChanged(selectedLeaderboardPanel);
}
}
}
}
@@ -0,0 +1,14 @@
package com.sap.sailing.gwt.ui.leaderboard;
/**
* Allows UI components to observe a change of the selected leaderboard in a Multi-Leaderboard scenario.
*/
public interface SelectedLeaderboardChangeListener {
/**
* @param selectedLeaderboard the selected non-<code>null</code> LeaderboardPanel
*/
void onSelectedLeaderboardChanged(LeaderboardPanel selectedLeaderboard);
}
@@ -0,0 +1,11 @@
package com.sap.sailing.gwt.ui.leaderboard;
public interface SelectedLeaderboardChangeProvider {
void addSelectedLeaderboardChangeListener(SelectedLeaderboardChangeListener listener);
void removeSelectedLeaderboardChangeListener(SelectedLeaderboardChangeListener listener);
void setSelectedLeaderboard(LeaderboardPanel selectedLeaderboard);
}
@@ -319,13 +319,13 @@ public class EditableLeaderboardPanel extends LeaderboardPanel {
final RowUpdateWhiteboard<LeaderboardRowDTO> whiteboard = new RowUpdateWhiteboard<LeaderboardRowDTO>(
EditableLeaderboardPanel.this.getData());
getWhiteboardOwner().whiteboardProduced(whiteboard);
getBusyIndicator().setBusy(true);
setBusyState(true);
getSailingService().updateLeaderboardMaxPointsReason(getLeaderboardName(), row.competitor.getIdAsString(),
raceColumnName, value == null || value.trim().length() == 0 ? null : MaxPointsReason.valueOf(value.trim()),
getLeaderboardDisplayDate(), new AsyncCallback<Util.Triple<Double, Double, Boolean>>() {
@Override
public void onFailure(Throwable t) {
getBusyIndicator().setBusy(false);
setBusyState(false);
getErrorReporter().reportError(
"Error trying to update max points reason for competitor "
+ row.competitor.getName() + " in leaderboard " + getLeaderboardName()
@@ -334,7 +334,7 @@ public class EditableLeaderboardPanel extends LeaderboardPanel {
@Override
public void onSuccess(Util.Triple<Double, Double, Boolean> newNetAndTotalPointsAndIsCorrected) {
getBusyIndicator().setBusy(false);
setBusyState(false);
row.fieldsByRaceColumnName.get(raceColumnName).reasonForMaxPoints = value == null
|| value.length() == 0 ? null : MaxPointsReason.valueOf(value.trim());
row.fieldsByRaceColumnName.get(raceColumnName).netPoints = newNetAndTotalPointsAndIsCorrected.getA();
@@ -444,14 +444,14 @@ public class EditableLeaderboardPanel extends LeaderboardPanel {
final RowUpdateWhiteboard<LeaderboardRowDTO> whiteboard = new RowUpdateWhiteboard<LeaderboardRowDTO>(
EditableLeaderboardPanel.this.getData());
getWhiteboardOwner().whiteboardProduced(whiteboard);
getBusyIndicator().setBusy(true);
setBusyState(true);
getSailingService().updateLeaderboardScoreCorrection(getLeaderboardName(), row.competitor.getIdAsString(), raceColumnName,
value == null || value.trim().length() == 0 ? null : value.trim().equals("n/a") ? null
: Double.valueOf(value.trim()), getLeaderboardDisplayDate(),
new AsyncCallback<Util.Triple<Double, Double, Boolean>>() {
@Override
public void onFailure(Throwable t) {
getBusyIndicator().setBusy(false);
setBusyState(false);
getErrorReporter().reportError("Error trying to update score correction for competitor "+
row.competitor.getName()+" in leaderboard "+getLeaderboardName()+
" for race "+raceColumnName+": "+t.getMessage()+
@@ -460,7 +460,7 @@ public class EditableLeaderboardPanel extends LeaderboardPanel {
@Override
public void onSuccess(Util.Triple<Double, Double, Boolean> newNetAndTotalPointsAndIsCorrected) {
getBusyIndicator().setBusy(false);
setBusyState(false);
final LeaderboardEntryDTO leaderboardEntryDTO = row.fieldsByRaceColumnName.get(raceColumnName);
leaderboardEntryDTO.netPoints = value == null || value.length() == 0 ? newNetAndTotalPointsAndIsCorrected
.getA() : Double.valueOf(value.trim());
@@ -523,13 +523,13 @@ public class EditableLeaderboardPanel extends LeaderboardPanel {
row.fieldsByRaceColumnName.get(raceColumnName).netPoints, new DialogCallback<Util.Pair<MaxPointsReason, Double>>() {
@Override
public void ok(final Util.Pair<MaxPointsReason, Double> editedObject) {
getBusyIndicator().setBusy(true);
setBusyState(true);
getSailingService().updateLeaderboardScoreCorrection(getLeaderboardName(), row.competitor.getIdAsString(), raceColumnName,
editedObject.getB(), getLeaderboardDisplayDate(),
new AsyncCallback<Util.Triple<Double, Double, Boolean>>() {
@Override
public void onFailure(Throwable t) {
getBusyIndicator().setBusy(false);
setBusyState(false);
getErrorReporter().reportError("Error trying to update score correction for competitor "+
row.competitor.getName()+" in leaderboard "+getLeaderboardName()+
" for race "+raceColumnName+": "+t.getMessage()+
@@ -543,7 +543,7 @@ public class EditableLeaderboardPanel extends LeaderboardPanel {
new AsyncCallback<Util.Triple<Double, Double, Boolean>>() {
@Override
public void onFailure(Throwable t) {
getBusyIndicator().setBusy(false);
setBusyState(false);
getErrorReporter().reportError("Error trying to update score correction for competitor "+
row.competitor.getName()+" in leaderboard "+getLeaderboardName()+
" for race "+raceColumnName+": "+t.getMessage()+
@@ -552,7 +552,7 @@ public class EditableLeaderboardPanel extends LeaderboardPanel {
@Override
public void onSuccess(Util.Triple<Double, Double, Boolean> newNetAndTotalPointsAndIsCorrected) {
getBusyIndicator().setBusy(false);
setBusyState(false);
final LeaderboardEntryDTO leaderboardEntryDTO = row.fieldsByRaceColumnName.get(raceColumnName);
leaderboardEntryDTO.reasonForMaxPoints = editedObject.getA();
leaderboardEntryDTO.netPoints = newNetAndTotalPointsAndIsCorrected.getA();
@@ -584,7 +584,7 @@ public class EditableLeaderboardPanel extends LeaderboardPanel {
String leaderboardName, String leaderboardGroupName, final ErrorReporter errorReporter,
final StringMessages stringMessages, UserAgentDetails userAgent) {
super(sailingService, asyncActionsExecutor, LeaderboardSettingsFactory.getInstance().createNewDefaultSettings(
/* racesToShow */ null, /* namesOfRacesToShow */ null, null, /* autoExpandFirstRace */ false, /* showRegattaRank */ true),
/* racesToShow */ null, /* namesOfRacesToShow */ null, null, /* autoExpandFirstRace */ false, /* showRegattaRank */ true, /* showCompetitorSailIdColumn */ true, /* showCompetitorFullNameColumn */ true),
new CompetitorSelectionModel(/* hasMultiSelection */true),
leaderboardName, errorReporter, stringMessages, userAgent, /* showRaceDetails */ true);
suppressedCompetitorsShown = new ListDataProvider<CompetitorDTO>(new ArrayList<CompetitorDTO>());
@@ -409,11 +409,11 @@ public class MatchAndApplyScoreCorrectionsDialog extends DataEntryDialog<BulkSco
@Override
public void ok(final BulkScoreCorrectionDTO result) {
leaderboardPanel.getBusyIndicator().setBusy(true);
leaderboardPanel.setBusyState(true);
sailingService.updateLeaderboardScoreCorrectionsAndMaxPointsReasons(result, new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
leaderboardPanel.getBusyIndicator().setBusy(false);
leaderboardPanel.setBusyState(false);
errorReporter.reportError(stringMessages.errorUpdatingScoresForLeaderboard(result.getLeaderboardName(),
caught.getMessage()));
}
@@ -214,19 +214,19 @@ public class ResultSelectionAndApplyDialog extends DataEntryDialog<Util.Triple<S
final String eventName = providerNameAndEventNameBoatClassNameCapturedWhen.getB();
final String boatClassName = providerNameAndEventNameBoatClassNameCapturedWhen.getC().getA();
final Date timePointWhenResultPublished = providerNameAndEventNameBoatClassNameCapturedWhen.getC().getB();
leaderboardPanel.getBusyIndicator().setBusy(true);
leaderboardPanel.setBusyState(true);
sailingService.getScoreCorrections(scoreCorrectionProviderName, eventName, boatClassName, timePointWhenResultPublished,
new AsyncCallback<RegattaScoreCorrectionDTO>() {
@Override
public void onFailure(Throwable caught) {
leaderboardPanel.getBusyIndicator().setBusy(false);
leaderboardPanel.setBusyState(false);
errorReporter.reportError(stringMessages.errorObtainingScoreCorrections(scoreCorrectionProviderName,
eventName, boatClassName, timePointWhenResultPublished.toString(), caught.getMessage()));
}
@Override
public void onSuccess(RegattaScoreCorrectionDTO result) {
leaderboardPanel.getBusyIndicator().setBusy(false);
leaderboardPanel.setBusyState(false);
new MatchAndApplyScoreCorrectionsDialog(leaderboardPanel, stringMessages, sailingService,
errorReporter, result).show();
}
@@ -151,7 +151,8 @@ public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint
// Use a TimePanel to manage wind chart zoom, although the TimePanel itself is not being displayed;
// let the time panel always return to "live" mode.
final TimePanel<TimePanelSettings> timePanel = new TimePanel<TimePanelSettings>(
timer, timeRangeWithZoomProvider, getStringMessages(), /* canReplayWhileLive */ false) {
timer, timeRangeWithZoomProvider, getStringMessages(), /* canReplayWhileLive */ false,
/* isScreenLargeEnoughToOfferChartSupport set to true iff wind chart will be displayed */ showWindChart) {
protected boolean isLiveModeToBeMadePossible() {
return true;
}
@@ -6,6 +6,7 @@ import java.util.List;
import java.util.UUID;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -97,7 +98,12 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
sailingService.getRaceboardData(regattaName, raceName, leaderboardName, leaderboardGroupName, eventId, new AsyncCallback<RaceboardDataDTO>() {
@Override
public void onSuccess(RaceboardDataDTO result) {
checkUrlParameters(result, canReplayWhileLiveIsPossible, showMapControls);
// Determine if the screen is large enough to display charts such as the competitor chart or the wind chart.
// This decision is made once based on the initial screen height. Resizing the window afterwards will have
// no impact on the chart support, i.e. they are available/unavailable based on the initial decision.
boolean isScreenLargeEnoughToOfferChartSupport = Document.get().getClientHeight() >= 600;
checkUrlParameters(result, canReplayWhileLiveIsPossible, showMapControls,
isScreenLargeEnoughToOfferChartSupport);
}
@Override
@@ -116,7 +122,8 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
vp.add(new Label(message));
}
private void checkUrlParameters(RaceboardDataDTO raceboardData, boolean canReplayWhileLiveIsPossible, boolean showMapControls) {
private void checkUrlParameters(RaceboardDataDTO raceboardData, boolean canReplayWhileLiveIsPossible, boolean showMapControls,
boolean isScreenLargeEnoughToOfferChartSupport) {
if (!raceboardData.isValidLeaderboard()) {
createErrorPage(getStringMessages().noSuchLeaderboard());
return;
@@ -148,21 +155,22 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
RaceTimesInfoProvider raceTimesInfoProvider = new RaceTimesInfoProvider(sailingService, asyncActionsExecutor, this, singletonList, 5000l /* requestInterval*/);
RaceBoardPanel raceBoardPanel = new RaceBoardPanel(sailingService, mediaService, getUserService(), asyncActionsExecutor,
raceboardData.getCompetitorAndTheirBoats(), timer, raceSelectionModel, leaderboardName, leaderboardGroupName, eventId,
raceboardViewConfig, RaceBoardEntryPoint.this, getStringMessages(), userAgent, raceTimesInfoProvider, showMapControls);
raceboardViewConfig, RaceBoardEntryPoint.this, getStringMessages(), userAgent, raceTimesInfoProvider, showMapControls,
isScreenLargeEnoughToOfferChartSupport);
createRaceBoardInOneScreenMode(raceBoardPanel, raceboardViewConfig);
}
private FlowPanel createTimePanel(RaceBoardPanel raceBoardPanel) {
FlowPanel timeLineInnerBgPanel = new FlowPanel();
FlowPanel timeLineInnerBgPanel = new ResizableFlowPanel();
timeLineInnerBgPanel.addStyleName("timeLineInnerBgPanel");
timeLineInnerBgPanel.add(raceBoardPanel.getTimePanel());
FlowPanel timeLineInnerPanel = new FlowPanel();
FlowPanel timeLineInnerPanel = new ResizableFlowPanel();
timeLineInnerPanel.add(timeLineInnerBgPanel);
timeLineInnerPanel.addStyleName("timeLineInnerPanel");
FlowPanel timelinePanel = new FlowPanel();
FlowPanel timelinePanel = new ResizableFlowPanel();
timelinePanel.add(timeLineInnerPanel);
timelinePanel.addStyleName("timeLinePanel");
@@ -7,6 +7,8 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Style.Unit;
@@ -17,8 +19,10 @@ import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.domain.common.LeaderboardNameConstants;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
@@ -79,7 +83,8 @@ import com.sap.sse.security.ui.client.UserService;
* @author Frank Mittag, Axel Uhl (d043530)
*
*/
public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeListener, LeaderboardUpdateListener, PopupPositionProvider {
public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeListener,
LeaderboardUpdateListener, PopupPositionProvider, RequiresResize {
private final SailingServiceAsync sailingService;
private final MediaServiceAsync mediaService;
private final UUID eventId;
@@ -123,13 +128,17 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
* @param eventId
* an optional event that can be used for "back"-navigation in case the race board shows a race in the
* context of an event; may be <code>null</code>.
* @param isScreenLargeEnoughToOfferChartSupport
* if the screen is large enough to display charts such as the competitor chart or the wind chart, a
* padding is provided for the RaceTimePanel that aligns its right border with that of the charts, and
* the charts are created. This decision is made once on startup in the {@link RaceBoardEntryPoint} class.
*/
public RaceBoardPanel(SailingServiceAsync sailingService, MediaServiceAsync mediaService,
UserService userService, AsyncActionsExecutor asyncActionsExecutor, Map<CompetitorDTO, BoatDTO> competitorsAndTheirBoats,
Timer timer, RaceSelectionProvider theRaceSelectionProvider, String leaderboardName,
String leaderboardGroupName, UUID eventId, RaceBoardViewConfiguration raceboardViewConfiguration,
ErrorReporter errorReporter, final StringMessages stringMessages,
UserAgentDetails userAgent, RaceTimesInfoProvider raceTimesInfoProvider, boolean showMapControls) {
UserAgentDetails userAgent, RaceTimesInfoProvider raceTimesInfoProvider, boolean showMapControls, boolean isScreenLargeEnoughToOfferChartSupport) {
this.sailingService = sailingService;
this.mediaService = mediaService;
this.stringMessages = stringMessages;
@@ -146,7 +155,7 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
selectedRaceIdentifier = raceSelectionProvider.getSelectedRaces().iterator().next();
this.setRaceBoardName(selectedRaceIdentifier.getRaceName());
this.asyncActionsExecutor = asyncActionsExecutor;
FlowPanel mainPanel = new FlowPanel();
FlowPanel mainPanel = new ResizableFlowPanel();
mainPanel.setSize("100%", "100%");
setWidget(mainPanel);
raceInformationHeader = new FlowPanel();
@@ -161,7 +170,33 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
raceMapResources.combinedWindPanelStyle().ensureInjected();
raceMap = new RaceMap(sailingService, asyncActionsExecutor, errorReporter, timer,
competitorSelectionProvider, stringMessages, showMapControls, getConfiguration().isShowViewStreamlets(), getConfiguration().isShowViewStreamletColors(), getConfiguration().isShowViewSimulation(),
selectedRaceIdentifier, raceMapResources.combinedWindPanelStyle(), /* showHeaderPanel */ true);
selectedRaceIdentifier, raceMapResources.combinedWindPanelStyle(), /* showHeaderPanel */ true) {
private static final String INDENT_SMALL_CONTROL_STYLE = "indentsmall";
private static final String INDENT_BIG_CONTROL_STYLE = "indentbig";
@Override
public void onResize() {
super.onResize();
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
// Show/hide the leaderboard panels toggle button text based on the race map height
leaderboardAndMapViewer.setLeftComponentToggleButtonTextVisibilityAndDraggerPosition(raceMap.getOffsetHeight() > 400);
}
});
}
@Override
protected String getLeftControlsIndentStyle() {
// Calculate style name for left control indent based on race map height an leaderboard panel visibility
if (raceMap.getOffsetHeight() <= 300) {
return INDENT_BIG_CONTROL_STYLE;
}
if (leaderboardPanel.isVisible() && raceMap.getOffsetHeight() <= 500) {
return INDENT_SMALL_CONTROL_STYLE;
}
return super.getLeftControlsIndentStyle();
}
};
CompetitorFilterPanel competitorSearchTextBox = new CompetitorFilterPanel(competitorSelectionProvider, stringMessages, raceMap,
new LeaderboardFetcher() {
@Override
@@ -172,11 +207,14 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
raceMap.getLeftHeaderPanel().add(raceInformationHeader);
raceMap.getRightHeaderPanel().add(regattaAndRaceTimeInformationHeader);
leaderboardPanel = createLeaderboardPanel(leaderboardName, leaderboardGroupName, competitorSearchTextBox);
// Determine if the screen is large enough to initially display the leaderboard panel on the left side of the
// map based on the initial screen width. Afterwards, the leaderboard panel visibility can be toggled as usual.
boolean isScreenLargeEnoughToInitiallyDisplayLeaderboard = Document.get().getClientWidth() >= 1024;
leaderboardPanel = createLeaderboardPanel(leaderboardName, leaderboardGroupName, competitorSearchTextBox, isScreenLargeEnoughToInitiallyDisplayLeaderboard);
leaderboardPanel.setTitle(stringMessages.leaderboard());
leaderboardPanel.getElement().getStyle().setMarginLeft(6, Unit.PX);
leaderboardPanel.getElement().getStyle().setMarginTop(10, Unit.PX);
createOneScreenView(leaderboardName, leaderboardGroupName, eventId, mainPanel, showMapControls, raceMap, userService); // initializes the raceMap field
createOneScreenView(leaderboardName, leaderboardGroupName, eventId, mainPanel, showMapControls, isScreenLargeEnoughToOfferChartSupport, isScreenLargeEnoughToInitiallyDisplayLeaderboard, raceMap, userService); // initializes the raceMap field
leaderboardPanel.addLeaderboardUpdateListener(this);
// in case the URL configuration contains the name of a competitors filter set we try to activate it
// FIXME the competitorsFilterSets has now moved to CompetitorSearchTextBox (which should probably be renamed); pass on the parameters to the LeaderboardPanel and see what it does with it
@@ -190,7 +228,7 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
}
}
timePanel = new RaceTimePanel(timer, timeRangeWithZoomModel, stringMessages, raceTimesInfoProvider,
raceboardViewConfiguration.isCanReplayDuringLiveRaces());
raceboardViewConfiguration.isCanReplayDuringLiveRaces(), isScreenLargeEnoughToOfferChartSupport);
timeRangeWithZoomModel.addTimeZoomChangeListener(timePanel);
raceTimesInfoProvider.addRaceTimesInfoProviderListener(timePanel);
raceSelectionProvider.addRaceSelectionChangeListener(timePanel);
@@ -198,32 +236,40 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
}
/**
* @param event an optional event; may be <code>null</code> or else can be used to show some context information in
* the {@link GlobalNavigationPanel}.
* @param event
* an optional event; may be <code>null</code> or else can be used to show some context information in
* the {@link GlobalNavigationPanel}.
* @param isScreenLargeEnoughToOfferChartSupport
* if the screen is large enough to display charts such as the competitor chart or the wind chart, a
* padding is provided for the RaceTimePanel that aligns its right border with that of the charts, and
* the charts are created.
* @param isScreenLargeEnoughToInitiallyDisplayLeaderboard TODO
*/
private void createOneScreenView(String leaderboardName, String leaderboardGroupName, UUID event, FlowPanel mainPanel,
boolean showMapControls, RaceMap raceMap, UserService userService) {
boolean showMapControls, boolean isScreenLargeEnoughToOfferChartSupport, boolean isScreenLargeEnoughToInitiallyDisplayLeaderboard, RaceMap raceMap, UserService userService) {
// create the default leaderboard and select the right race
raceTimesInfoProvider.addRaceTimesInfoProviderListener(raceMap);
raceMap.onRaceSelectionChange(Collections.singletonList(selectedRaceIdentifier));
List<Component<?>> components = new ArrayList<Component<?>>();
competitorChart = new MultiCompetitorRaceChart(sailingService, asyncActionsExecutor, competitorSelectionProvider, raceSelectionProvider,
timer, timeRangeWithZoomModel, stringMessages, errorReporter, true, true, leaderboardGroupName, leaderboardName);
competitorChart.onRaceSelectionChange(raceSelectionProvider.getSelectedRaces());
competitorChart.getEntryWidget().setTitle(stringMessages.competitorCharts());
competitorChart.setVisible(false);
components.add(competitorChart);
windChart = new WindChart(sailingService, raceSelectionProvider, timer, timeRangeWithZoomModel, new WindChartSettings(),
stringMessages, asyncActionsExecutor, errorReporter, /* compactChart */ true);
windChart.setVisible(false);
windChart.onRaceSelectionChange(raceSelectionProvider.getSelectedRaces());
windChart.getEntryWidget().setTitle(stringMessages.windChart());
components.add(windChart);
editMarkPassingPanel = new EditMarkPassingsPanel(sailingService, selectedRaceIdentifier,
stringMessages, competitorSelectionProvider, errorReporter, timer);
editMarkPassingPanel.setLeaderboard(leaderboardPanel.getLeaderboard());
editMarkPassingPanel.getEntryWidget().setTitle(stringMessages.editMarkPassings());
components.add(editMarkPassingPanel);
if (isScreenLargeEnoughToOfferChartSupport) {
competitorChart = new MultiCompetitorRaceChart(sailingService, asyncActionsExecutor, competitorSelectionProvider, raceSelectionProvider,
timer, timeRangeWithZoomModel, stringMessages, errorReporter, true, true, leaderboardGroupName, leaderboardName);
competitorChart.onRaceSelectionChange(raceSelectionProvider.getSelectedRaces());
competitorChart.getEntryWidget().setTitle(stringMessages.competitorCharts());
competitorChart.setVisible(false);
components.add(competitorChart);
windChart = new WindChart(sailingService, raceSelectionProvider, timer, timeRangeWithZoomModel, new WindChartSettings(),
stringMessages, asyncActionsExecutor, errorReporter, /* compactChart */ true);
windChart.setVisible(false);
windChart.onRaceSelectionChange(raceSelectionProvider.getSelectedRaces());
windChart.getEntryWidget().setTitle(stringMessages.windChart());
components.add(windChart);
editMarkPassingPanel = new EditMarkPassingsPanel(sailingService, selectedRaceIdentifier,
stringMessages, competitorSelectionProvider, errorReporter, timer);
editMarkPassingPanel.setLeaderboard(leaderboardPanel.getLeaderboard());
editMarkPassingPanel.getEntryWidget().setTitle(stringMessages.editMarkPassings());
components.add(editMarkPassingPanel);
}
boolean autoSelectMedia = getConfiguration().isAutoSelectMedia();
MediaPlayerManagerComponent mediaPlayerManagerComponent = new MediaPlayerManagerComponent(
selectedRaceIdentifier, raceTimesInfoProvider, timer, mediaService, userService, stringMessages,
@@ -233,13 +279,12 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
for (ComponentViewer componentViewer : componentViewers) {
mainPanel.add(componentViewer.getViewerWidget());
}
boolean showLeaderboard = getConfiguration().isShowLeaderboard();
if (Document.get().getClientWidth() <= 1024) {
showLeaderboard = false;
}
boolean showLeaderboard = getConfiguration().isShowLeaderboard() && isScreenLargeEnoughToInitiallyDisplayLeaderboard;
setLeaderboardVisible(showLeaderboard);
setWindChartVisible(getConfiguration().isShowWindChart());
setCompetitorChartVisible(getConfiguration().isShowCompetitorsChart());
if (isScreenLargeEnoughToOfferChartSupport) {
setWindChartVisible(getConfiguration().isShowWindChart());
setCompetitorChartVisible(getConfiguration().isShowCompetitorsChart());
}
// make sure to load leaderboard data for filtering to work
if (!showLeaderboard) {
leaderboardPanel.setVisible(true);
@@ -258,13 +303,16 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
}
}
private LeaderboardPanel createLeaderboardPanel(String leaderboardName, String leaderboardGroupName, CompetitorFilterPanel competitorSearchTextBox) {
private LeaderboardPanel createLeaderboardPanel(String leaderboardName, String leaderboardGroupName,
CompetitorFilterPanel competitorSearchTextBox, boolean isScreenLargeEnoughToInitiallyDisplayLeaderboard) {
LeaderboardSettings leaderBoardSettings = LeaderboardSettingsFactory.getInstance()
.createNewSettingsForPlayMode(timer.getPlayMode(),
/* nameOfRaceToSort */ selectedRaceIdentifier.getRaceName(),
/* nameOfRaceColumnToShow */ null, /* nameOfRaceToShow */ selectedRaceIdentifier.getRaceName(),
new ExplicitRaceColumnSelectionWithPreselectedRace(selectedRaceIdentifier), /* showRegattaRank */ false,
/*showCompetitorSailIdColumn*/true, /*showCompetitorFullNameColumn*/true);
/*showCompetitorSailIdColumn*/true,
/* don't showCompetitorFullNameColumn in case screen is so small that we don't
* even display the leaderboard initially */ isScreenLargeEnoughToInitiallyDisplayLeaderboard);
return new LeaderboardPanel(sailingService, asyncActionsExecutor, leaderBoardSettings, selectedRaceIdentifier != null, selectedRaceIdentifier,
competitorSelectionProvider, timer, leaderboardGroupName, leaderboardName, errorReporter, stringMessages,
userAgent, /* showRaceDetails */ true, competitorSearchTextBox,
@@ -345,7 +393,9 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
@Override
public void updatedLeaderboard(LeaderboardDTO leaderboard) {
leaderboardAndMapViewer.setLeftComponentWidth(leaderboardPanel.getContentPanel().getOffsetWidth());
editMarkPassingPanel.setLeaderboard(leaderboard);
if (editMarkPassingPanel != null) {
editMarkPassingPanel.setLeaderboard(leaderboard);
}
}
@Override
@@ -360,7 +410,7 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
if (fleetForRaceName.equals(LeaderboardNameConstants.DEFAULT_FLEET_NAME)) {
fleetForRaceName = "";
} else {
fleetForRaceName = " - "+fleetForRaceName;
fleetForRaceName = (seriesName.isEmpty() ? "" : " - ") + fleetForRaceName;
}
final Label raceNameLabel = new Label(stringMessages.race() + " " + raceColumn.getRaceColumnName());
raceNameLabel.setStyleName("RaceName-Label");
@@ -370,6 +420,7 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
raceInformationHeader.add(raceNameLabel);
raceInformationHeader.add(raceAdditionalInformationLabel);
final Anchor regattaNameAnchor = new Anchor(raceIdentifier.getRegattaName());
regattaNameAnchor.setTitle(raceIdentifier.getRegattaName());
if (eventId != null) {
// we don't use the EntryPointLinkFactory here, because of lacking support for Places
String debugParam = Window.Location.getParameter("gwt.codesvr");
@@ -394,19 +445,6 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
}
}
regattaNameAnchor.setStyleName("RegattaName-Anchor");
// TODO: Strange behavior... check
// Window.addResizeHandler(new ResizeHandler() {
// @Override
// public void onResize(ResizeEvent event) {
// int headerPanelWidth = raceMap.getRightHeaderPanel().getOffsetWidth() - 150; // 150px is the width of the sapLogo
// int raceNameAndFleetLabelWidth = raceInformationHeader.getOffsetWidth();
// int regattaAnchorWidth = regattaNameAnchor.getOffsetWidth();
// boolean overlap = raceNameAndFleetLabelWidth + regattaAnchorWidth > headerPanelWidth;
// raceInformationHeader.setVisible(!overlap);
// }
// });
Label raceTimeLabel = computeRaceInformation(raceColumn, fleet);
raceTimeLabel.setStyleName("RaceTime-Label");
regattaAndRaceTimeInformationHeader.clear();
@@ -433,5 +471,13 @@ public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeLi
raceInformationLabel.setText(formatter.format(raceColumn.getStartDate(fleet)));
return raceInformationLabel;
}
@Override
public void onResize() {
Widget child = getWidget();
if (child != null && child instanceof RequiresResize) {
((RequiresResize) child).onResize();
}
}
}
@@ -0,0 +1,23 @@
package com.sap.sailing.gwt.ui.raceboard;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.WidgetCollection;
/**
* Utility class extending {@link FlowPanel} and implementing {@link RequiresResize} interface. All
* {@link #getChildren() children} also implementing {@link RequiresResize} are informed by calling their
* {@link RequiresResize#onResize()} method.
*/
class ResizableFlowPanel extends FlowPanel implements RequiresResize {
@Override
public void onResize() {
WidgetCollection children = getChildren();
for (Widget widget : children) {
if (widget instanceof RequiresResize) {
((RequiresResize) widget).onResize();
}
}
}
}
Loaded 100 of 147 files, more files were not shown because too many files have changed in this diff. Show more