mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-21 03:30:12 +00:00
Merge branch 'master' into bug3212
This commit is contained in:
commit
6dd4665cfc
124 files changed
+13197
-12230
No files matched your search
@@ -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 {
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sailing.domain.common</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-source-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>plugin-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>plugin-source</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sailing.domain.common</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-source-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>plugin-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>plugin-source</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+1
-1
@@ -21,7 +21,7 @@ public abstract class AbstractSpeedImpl implements Speed {
|
||||
|
||||
@Override
|
||||
public Duration getDuration(Distance distance) {
|
||||
return new MillisecondsDurationImpl((long) (1000 * distance.getMeters() / getMetersPerSecond()));
|
||||
return distance == null ? null : new MillisecondsDurationImpl((long) (1000 * distance.getMeters() / getMetersPerSecond()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+433
-430
@@ -1,430 +1,433 @@
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public abstract class AbstractLeaderboardDTO implements Serializable {
|
||||
private static final long serialVersionUID = -205106531931903527L;
|
||||
|
||||
public String name;
|
||||
|
||||
private List<RaceColumnDTO> races;
|
||||
public Map<CompetitorDTO, String> competitorDisplayNames;
|
||||
public Map<CompetitorDTO, LeaderboardRowDTO> rows;
|
||||
public boolean hasCarriedPoints;
|
||||
public int[] discardThresholds;
|
||||
|
||||
/**
|
||||
* Set to the non-<code>null</code> regatta name if this DTO represents a <code>RegattaLeaderboard</code>.
|
||||
*/
|
||||
public String regattaName;
|
||||
public String displayName;
|
||||
public UUID defaultCourseAreaId;
|
||||
public String defaultCourseAreaName;
|
||||
public ScoringSchemeType scoringScheme;
|
||||
public LeaderboardType type;
|
||||
|
||||
private Long delayToLiveInMillisForLatestRace;
|
||||
|
||||
public AbstractLeaderboardDTO() {
|
||||
races = new ArrayList<RaceColumnDTO>();
|
||||
}
|
||||
|
||||
public Set<BoatClassDTO> getBoatClasses() {
|
||||
Set<BoatClassDTO> result = new HashSet<BoatClassDTO>();
|
||||
if(rows != null) {
|
||||
for (CompetitorDTO competitor : rows.keySet()) {
|
||||
result.add(competitor.getBoatClass());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getDisplayName(CompetitorDTO competitor) {
|
||||
if (competitorDisplayNames == null || competitorDisplayNames.get(competitor) == null) {
|
||||
return competitor.getName();
|
||||
} else {
|
||||
return competitorDisplayNames.get(competitor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the race column whose name is specified in <code>raceColumnName</code> has at least one competitor who has valid
|
||||
* {@link LeaderboardEntryDTO#legDetails} for that race column, the maximum number of entries of all such competitors in
|
||||
* the leg details is returned, telling the number of legs that the race column shall display. Otherwise, -1 is returned.
|
||||
* If you specify an non null <code>preselectedRace</code> the leg count is calculated only for that race for the column
|
||||
* holding that race. All other columns will be unaffected by <code>preselectedRace</code> and will return their regular
|
||||
* leg count. Note that this may lead to a situation where some competitors may have sailed more legs than others because
|
||||
* their fleet association may have varied across races.<p>
|
||||
*
|
||||
* See also bug 2604 and bug 2035.
|
||||
*/
|
||||
public int getLegCount(String raceColumnName, RaceIdentifier preselectedRace) {
|
||||
int result = -1;
|
||||
final boolean preselectedRaceIsInRaceColumn = isRaceInColumn(preselectedRace, raceColumnName);
|
||||
for (LeaderboardRowDTO row : rows.values()) {
|
||||
LeaderboardEntryDTO leaderboardEntryDTO = row.fieldsByRaceColumnName.get(raceColumnName);
|
||||
if (leaderboardEntryDTO != null && leaderboardEntryDTO.legDetails != null
|
||||
// when no race is pre-selected, always use the actual leg count;
|
||||
// otherwise, if the pre-selected race is in the column identified by
|
||||
// raceColumnName, use the entry only if it's in the pre-selected race;
|
||||
// otherwise (a race is pre-selected but a different column's leg count
|
||||
// is requested), use the regular leg count as is.
|
||||
&& (preselectedRace == null || !preselectedRaceIsInRaceColumn || preselectedRace.equals(leaderboardEntryDTO.race))) {
|
||||
result = Math.max(result, leaderboardEntryDTO.legDetails.size());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isRaceInColumn(RaceIdentifier preselectedRace, String raceColumnName) {
|
||||
RaceColumnDTO raceColumn = getRaceColumnByName(raceColumnName);
|
||||
return raceColumn.containsRace(preselectedRace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the <code>competitor</code> scored (and therefore presumably participated) in a medal race represented
|
||||
* in this leaderboard.
|
||||
*/
|
||||
public boolean scoredInMedalRace(CompetitorDTO competitor) {
|
||||
LeaderboardRowDTO row = rows.get(competitor);
|
||||
for (RaceColumnDTO race : races) {
|
||||
if (race.isMedalRace() && row.fieldsByRaceColumnName.get(race.getRaceColumnName()).totalPoints > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Double getNetPoints(CompetitorDTO competitor, String nameOfLastRaceSoFar) {
|
||||
Double netPoints = null;
|
||||
LeaderboardRowDTO row = rows.get(competitor);
|
||||
if (row != null) {
|
||||
LeaderboardEntryDTO field = row.fieldsByRaceColumnName.get(nameOfLastRaceSoFar);
|
||||
if (field != null && field.netPoints != null) {
|
||||
netPoints = field.netPoints;
|
||||
}
|
||||
}
|
||||
return netPoints;
|
||||
}
|
||||
|
||||
public boolean raceIsTracked(String raceColumnName) {
|
||||
for (RaceColumnDTO race : races) {
|
||||
if (race.getRaceColumnName().equals(raceColumnName)) {
|
||||
for (FleetDTO fleet : race.getFleets()) {
|
||||
if (race.isTrackedRace(fleet)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public boolean raceIsMedalRace(String raceColumnName) {
|
||||
return getRaceColumnByName(raceColumnName).isMedalRace();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the {@link RaceColumnDTO} by the name <code>raceColumnName</code> doesn't exist yet within this leaderboard
|
||||
* DTO, it is created, setting is {@link RaceColumnDTO#isValidInTotalScore()} to <code>true</code>. This method
|
||||
* ensures that a fleet named <code>fleetName</code> is present. If it's not present yet, it's added to the race
|
||||
* column's fleet name list. The <code>trackedRaceIdentifier</code> and <code>race</code> are associated with the
|
||||
* column for the fleet identified by <code>fleetName</code>.
|
||||
*
|
||||
* @param explicitFactor
|
||||
* factor by which to multiply the race column's points for the overall score; if <code>null</code>, the
|
||||
* default will be determined by whether or not the column is marked as medal race
|
||||
* @param effectiveFactor
|
||||
* is what you get when you call {@link RaceColumn#getFactor()} on the race column that the resulting
|
||||
* {@link RaceColumnDTO} represents
|
||||
* @param regattaName
|
||||
* must not be <code>null</code> if <code>seriesName</code> is not <code>null</code>; specified
|
||||
* separately from <code>trackedRaceIdentifier</code> because a column may belong to regatta/series
|
||||
* despite not having a tracked race associated
|
||||
* @param seriesName
|
||||
* if <code>null</code>, this method will produce a {@link RaceColumnDTO}, otherwise a
|
||||
* {@link RaceColumnInSeriesDTO}
|
||||
* @param fleetDTO
|
||||
* 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) {
|
||||
assert fleetDTO != null;
|
||||
RaceColumnDTO raceColumnDTO = getRaceColumnByName(raceColumnName);
|
||||
if (raceColumnDTO == null) {
|
||||
raceColumnDTO = RaceColumnDTOFactory.INSTANCE.createRaceColumnDTO(raceColumnName, medalRace,
|
||||
explicitFactor, regattaName, seriesName);
|
||||
races.add(raceColumnDTO);
|
||||
}
|
||||
raceColumnDTO.setEffectiveFactor(effectiveFactor);
|
||||
boolean contains = false;
|
||||
for (FleetDTO fleet : raceColumnDTO.getFleets()) {
|
||||
if (fleet.getName().equals(fleetDTO.getName())) {
|
||||
contains = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!contains) {
|
||||
raceColumnDTO.addFleet(fleetDTO);
|
||||
}
|
||||
raceColumnDTO.setRaceIdentifier(fleetDTO, trackedRaceIdentifier);
|
||||
raceColumnDTO.setRace(fleetDTO, race);
|
||||
return raceColumnDTO;
|
||||
}
|
||||
|
||||
public RaceColumnDTO createEmptyRaceColumn(String raceColumnName, boolean medalRace, String regattaName, String seriesName) {
|
||||
final RaceColumnDTO raceColumn = RaceColumnDTOFactory.INSTANCE.createRaceColumnDTO(raceColumnName,
|
||||
medalRace, /* explicit factor */ null, regattaName, seriesName);
|
||||
races.add(raceColumn);
|
||||
return raceColumn;
|
||||
}
|
||||
|
||||
public RaceColumnDTO getRaceColumnByName(String raceColumnName) {
|
||||
for (RaceColumnDTO race : races) {
|
||||
if (race.getRaceColumnName().equals(raceColumnName)) {
|
||||
return race;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getRaceColumnsCount() {
|
||||
return races.size();
|
||||
}
|
||||
|
||||
public int getRacesCount() {
|
||||
int result = 0;
|
||||
for (RaceColumnDTO race : getRaceList()) {
|
||||
result += race.getFleets().size();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getTrackedRacesCount() {
|
||||
int result = 0;
|
||||
for (RaceColumnDTO raceColumn : getRaceList()) {
|
||||
for (FleetDTO fleet : raceColumn.getFleets()) {
|
||||
RaceDTO race = raceColumn.getRace(fleet);
|
||||
if(race != null && race.trackedRace != null && race.trackedRace.hasGPSData && race.trackedRace.hasWindData) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<RaceColumnDTO> getRaceList() {
|
||||
return races;
|
||||
}
|
||||
|
||||
public void setRaceList(List<RaceColumnDTO> raceList) {
|
||||
this.races = raceList;
|
||||
}
|
||||
|
||||
public boolean raceListContains(String raceColumnName) {
|
||||
return getRaceColumnByName(raceColumnName) != null;
|
||||
}
|
||||
|
||||
public void moveRaceUp(String raceColumnName) {
|
||||
RaceColumnDTO race = getRaceColumnByName(raceColumnName);
|
||||
int index = races.indexOf(race);
|
||||
index--;
|
||||
if (index >= 0) {
|
||||
races.remove(index + 1);
|
||||
races.add(index, race);
|
||||
}
|
||||
}
|
||||
|
||||
public void moveRaceDown(String raceColumnName) {
|
||||
RaceColumnDTO race = getRaceColumnByName(raceColumnName);
|
||||
int index = races.indexOf(race);
|
||||
if (index != -1) {
|
||||
index++;
|
||||
if (index < races.size()) {
|
||||
races.remove(index - 1);
|
||||
races.add(index, race);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setIsMedalRace(String raceColumnName, boolean medalRace) {
|
||||
getRaceColumnByName(raceColumnName).setMedalRace(medalRace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The earliest start date of the races, or <code>null</code> if no start dates of the races are available.
|
||||
*/
|
||||
public Date getStartDate() {
|
||||
Date leaderboardStart = null;
|
||||
for (RaceColumnDTO race : getRaceList()) {
|
||||
for (FleetDTO fleet: race.getFleets()) {
|
||||
Date raceStart = race.getStartDate(fleet);
|
||||
if (raceStart != null) {
|
||||
if (leaderboardStart == null) {
|
||||
leaderboardStart = new Date();
|
||||
} else {
|
||||
leaderboardStart = leaderboardStart.before(raceStart) ? leaderboardStart : raceStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return leaderboardStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the {@link PlacemarkOrderDTO} of all races in this leaderboard, if the PlacemarkOrderDTO for the race is
|
||||
* available, and fills all {@link PlacemarkDTO} in a new PlacemarkOrderDTO.<br />
|
||||
* The order of the races in this leaderboard determine the order of the PlacemarkDTOs in the PlacemarkOrderDTO.
|
||||
*
|
||||
* @return The places of this leaderboard in form of a {@link PlacemarkOrderDTO}, or <code>null</code> if the
|
||||
* {@link PlacemarkOrderDTO places} of no race are available
|
||||
*/
|
||||
public PlacemarkOrderDTO getPlaces() {
|
||||
PlacemarkOrderDTO leaderboardPlaces = null;
|
||||
for (RaceColumnDTO race : getRaceList()) {
|
||||
PlacemarkOrderDTO racePlaces = race.getPlaces();
|
||||
if (racePlaces != null) {
|
||||
if (leaderboardPlaces == null) {
|
||||
leaderboardPlaces = new PlacemarkOrderDTO();
|
||||
}
|
||||
leaderboardPlaces.getPlacemarks().addAll(racePlaces.getPlacemarks());
|
||||
}
|
||||
}
|
||||
return leaderboardPlaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the leaderboard contains a race which is live
|
||||
*/
|
||||
public boolean hasLiveRace(long serverTimePointAsMillis) {
|
||||
for (RaceColumnDTO race : getRaceList()) {
|
||||
for (FleetDTO fleet : race.getFleets()) {
|
||||
if (race.isLive(fleet, serverTimePointAsMillis)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Util.Pair<RaceColumnDTO, FleetDTO>> getLiveRaces(long serverTimePointAsMillis) {
|
||||
List<Util.Pair<RaceColumnDTO, FleetDTO>> result = new ArrayList<Util.Pair<RaceColumnDTO, FleetDTO>>();
|
||||
for (RaceColumnDTO race : getRaceList()) {
|
||||
for (FleetDTO fleet : race.getFleets()) {
|
||||
if (race.isLive(fleet, serverTimePointAsMillis)) {
|
||||
result.add(new Util.Pair<RaceColumnDTO, FleetDTO>(race, fleet));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((competitorDisplayNames == null) ? 0 : competitorDisplayNames.hashCode());
|
||||
result = prime * result + Arrays.hashCode(discardThresholds);
|
||||
result = prime * result + (hasCarriedPoints ? 1231 : 1237);
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((scoringScheme == null) ? 0 : scoringScheme.hashCode());
|
||||
if (races == null) {
|
||||
result = prime * result;
|
||||
} else {
|
||||
List<String> raceNames = new ArrayList<String>();
|
||||
for (RaceColumnDTO race : races) {
|
||||
raceNames.add(race.getName());
|
||||
}
|
||||
result = prime * result + raceNames.hashCode();
|
||||
}
|
||||
result = prime * result + ((rows == null) ? 0 : rows.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
AbstractLeaderboardDTO other = (AbstractLeaderboardDTO) obj;
|
||||
if (competitorDisplayNames == null) {
|
||||
if (other.competitorDisplayNames != null)
|
||||
return false;
|
||||
} else if (!competitorDisplayNames.equals(other.competitorDisplayNames))
|
||||
return false;
|
||||
if (!Arrays.equals(discardThresholds, other.discardThresholds))
|
||||
return false;
|
||||
if (hasCarriedPoints != other.hasCarriedPoints)
|
||||
return false;
|
||||
if (type != other.type)
|
||||
return false;
|
||||
if (scoringScheme != other.scoringScheme)
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (races == null) {
|
||||
if (other.races != null)
|
||||
return false;
|
||||
} else {
|
||||
// compare race column names only, not the contents
|
||||
if (races.size() != (other.races==null?0:other.races.size())) {
|
||||
return false;
|
||||
}
|
||||
List<String> raceColumnNames = new ArrayList<String>(races.size());
|
||||
List<String> otherRaceColumnNames = new ArrayList<String>(races.size());
|
||||
for (RaceColumnDTO race : races) {
|
||||
raceColumnNames.add(race.getName());
|
||||
}
|
||||
if (other.races != null) {
|
||||
for (RaceColumnDTO otherRace : other.races) {
|
||||
otherRaceColumnNames.add(otherRace.getName());
|
||||
}
|
||||
}
|
||||
if (!raceColumnNames.equals(otherRaceColumnNames))
|
||||
return false;
|
||||
if (rows == null) {
|
||||
if (other.rows != null)
|
||||
return false;
|
||||
} else if (!rows.equals(other.rows))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDisplayNameSet(CompetitorDTO competitor) {
|
||||
return competitorDisplayNames.get(competitor) != null;
|
||||
}
|
||||
|
||||
public Long getDelayToLiveInMillisForLatestRace() {
|
||||
return delayToLiveInMillisForLatestRace;
|
||||
}
|
||||
|
||||
public void setDelayToLiveInMillisForLatestRace(Long delayToLiveInMillisForLatestRace) {
|
||||
this.delayToLiveInMillisForLatestRace = delayToLiveInMillisForLatestRace;
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.common.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.LeaderboardType;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public abstract class AbstractLeaderboardDTO implements Serializable {
|
||||
private static final long serialVersionUID = -205106531931903527L;
|
||||
|
||||
public String name;
|
||||
|
||||
private List<RaceColumnDTO> races;
|
||||
public Map<CompetitorDTO, String> competitorDisplayNames;
|
||||
public Map<CompetitorDTO, LeaderboardRowDTO> rows;
|
||||
public boolean hasCarriedPoints;
|
||||
public int[] discardThresholds;
|
||||
|
||||
/**
|
||||
* Set to the non-<code>null</code> regatta name if this DTO represents a <code>RegattaLeaderboard</code>.
|
||||
*/
|
||||
public String regattaName;
|
||||
public String displayName;
|
||||
public UUID defaultCourseAreaId;
|
||||
public String defaultCourseAreaName;
|
||||
public ScoringSchemeType scoringScheme;
|
||||
public LeaderboardType type;
|
||||
|
||||
private Long delayToLiveInMillisForLatestRace;
|
||||
|
||||
public AbstractLeaderboardDTO() {
|
||||
races = new ArrayList<RaceColumnDTO>();
|
||||
}
|
||||
|
||||
public Set<BoatClassDTO> getBoatClasses() {
|
||||
Set<BoatClassDTO> result = new HashSet<BoatClassDTO>();
|
||||
if(rows != null) {
|
||||
for (CompetitorDTO competitor : rows.keySet()) {
|
||||
result.add(competitor.getBoatClass());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getDisplayName(CompetitorDTO competitor) {
|
||||
if (competitorDisplayNames == null || competitorDisplayNames.get(competitor) == null) {
|
||||
return competitor.getName();
|
||||
} else {
|
||||
return competitorDisplayNames.get(competitor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the race column whose name is specified in <code>raceColumnName</code> has at least one competitor who has valid
|
||||
* {@link LeaderboardEntryDTO#legDetails} for that race column, the maximum number of entries of all such competitors in
|
||||
* the leg details is returned, telling the number of legs that the race column shall display. Otherwise, -1 is returned.
|
||||
* If you specify an non null <code>preselectedRace</code> the leg count is calculated only for that race for the column
|
||||
* holding that race. All other columns will be unaffected by <code>preselectedRace</code> and will return their regular
|
||||
* leg count. Note that this may lead to a situation where some competitors may have sailed more legs than others because
|
||||
* their fleet association may have varied across races.<p>
|
||||
*
|
||||
* See also bug 2604 and bug 2035.
|
||||
*/
|
||||
public int getLegCount(String raceColumnName, RaceIdentifier preselectedRace) {
|
||||
int result = -1;
|
||||
final boolean preselectedRaceIsInRaceColumn = isRaceInColumn(preselectedRace, raceColumnName);
|
||||
for (LeaderboardRowDTO row : rows.values()) {
|
||||
LeaderboardEntryDTO leaderboardEntryDTO = row.fieldsByRaceColumnName.get(raceColumnName);
|
||||
if (leaderboardEntryDTO != null && leaderboardEntryDTO.legDetails != null
|
||||
// when no race is pre-selected, always use the actual leg count;
|
||||
// otherwise, if the pre-selected race is in the column identified by
|
||||
// raceColumnName, use the entry only if it's in the pre-selected race;
|
||||
// otherwise (a race is pre-selected but a different column's leg count
|
||||
// is requested), use the regular leg count as is.
|
||||
&& (preselectedRace == null || !preselectedRaceIsInRaceColumn || preselectedRace.equals(leaderboardEntryDTO.race))) {
|
||||
result = Math.max(result, leaderboardEntryDTO.legDetails.size());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isRaceInColumn(RaceIdentifier preselectedRace, String raceColumnName) {
|
||||
RaceColumnDTO raceColumn = getRaceColumnByName(raceColumnName);
|
||||
return raceColumn.containsRace(preselectedRace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the <code>competitor</code> scored (and therefore presumably participated) in a medal race represented
|
||||
* in this leaderboard.
|
||||
*/
|
||||
public boolean scoredInMedalRace(CompetitorDTO competitor) {
|
||||
LeaderboardRowDTO row = rows.get(competitor);
|
||||
for (RaceColumnDTO race : races) {
|
||||
if (race.isMedalRace() && row.fieldsByRaceColumnName.get(race.getRaceColumnName()).totalPoints > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Double getNetPoints(CompetitorDTO competitor, String nameOfLastRaceSoFar) {
|
||||
Double netPoints = null;
|
||||
LeaderboardRowDTO row = rows.get(competitor);
|
||||
if (row != null) {
|
||||
LeaderboardEntryDTO field = row.fieldsByRaceColumnName.get(nameOfLastRaceSoFar);
|
||||
if (field != null && field.netPoints != null) {
|
||||
netPoints = field.netPoints;
|
||||
}
|
||||
}
|
||||
return netPoints;
|
||||
}
|
||||
|
||||
public boolean raceIsTracked(String raceColumnName) {
|
||||
for (RaceColumnDTO race : races) {
|
||||
if (race.getRaceColumnName().equals(raceColumnName)) {
|
||||
for (FleetDTO fleet : race.getFleets()) {
|
||||
if (race.isTrackedRace(fleet)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public boolean raceIsMedalRace(String raceColumnName) {
|
||||
return getRaceColumnByName(raceColumnName).isMedalRace();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the {@link RaceColumnDTO} by the name <code>raceColumnName</code> doesn't exist yet within this leaderboard
|
||||
* DTO, it is created, setting is {@link RaceColumnDTO#isValidInTotalScore()} to <code>true</code>. This method
|
||||
* ensures that a fleet named <code>fleetName</code> is present. If it's not present yet, it's added to the race
|
||||
* column's fleet name list. The <code>trackedRaceIdentifier</code> and <code>race</code> are associated with the
|
||||
* column for the fleet identified by <code>fleetName</code>.
|
||||
*
|
||||
* @param explicitFactor
|
||||
* factor by which to multiply the race column's points for the overall score; if <code>null</code>, the
|
||||
* default will be determined by whether or not the column is marked as medal race
|
||||
* @param effectiveFactor
|
||||
* is what you get when you call {@link RaceColumn#getFactor()} on the race column that the resulting
|
||||
* {@link RaceColumnDTO} represents
|
||||
* @param regattaName
|
||||
* must not be <code>null</code> if <code>seriesName</code> is not <code>null</code>; specified
|
||||
* separately from <code>trackedRaceIdentifier</code> because a column may belong to regatta/series
|
||||
* despite not having a tracked race associated
|
||||
* @param seriesName
|
||||
* if <code>null</code>, this method will produce a {@link RaceColumnDTO}, otherwise a
|
||||
* {@link RaceColumnInSeriesDTO}
|
||||
* @param fleetDTO
|
||||
* 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, boolean isMetaLeaderboardColumn) {
|
||||
assert fleetDTO != null;
|
||||
RaceColumnDTO raceColumnDTO = getRaceColumnByName(raceColumnName);
|
||||
if (raceColumnDTO == null) {
|
||||
raceColumnDTO = RaceColumnDTOFactory.INSTANCE.createRaceColumnDTO(raceColumnName, medalRace,
|
||||
explicitFactor, regattaName, seriesName, isMetaLeaderboardColumn);
|
||||
races.add(raceColumnDTO);
|
||||
}
|
||||
raceColumnDTO.setEffectiveFactor(effectiveFactor);
|
||||
boolean contains = false;
|
||||
for (FleetDTO fleet : raceColumnDTO.getFleets()) {
|
||||
if (fleet.getName().equals(fleetDTO.getName())) {
|
||||
contains = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!contains) {
|
||||
raceColumnDTO.addFleet(fleetDTO);
|
||||
}
|
||||
raceColumnDTO.setRaceIdentifier(fleetDTO, trackedRaceIdentifier);
|
||||
raceColumnDTO.setRace(fleetDTO, race);
|
||||
return raceColumnDTO;
|
||||
}
|
||||
|
||||
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, isMetaLeaderboardColumn);
|
||||
races.add(raceColumn);
|
||||
return raceColumn;
|
||||
}
|
||||
|
||||
public RaceColumnDTO getRaceColumnByName(String raceColumnName) {
|
||||
for (RaceColumnDTO race : races) {
|
||||
if (race.getRaceColumnName().equals(raceColumnName)) {
|
||||
return race;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getRaceColumnsCount() {
|
||||
return races.size();
|
||||
}
|
||||
|
||||
public int getRacesCount() {
|
||||
int result = 0;
|
||||
for (RaceColumnDTO race : getRaceList()) {
|
||||
result += race.getFleets().size();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getTrackedRacesCount() {
|
||||
int result = 0;
|
||||
for (RaceColumnDTO raceColumn : getRaceList()) {
|
||||
for (FleetDTO fleet : raceColumn.getFleets()) {
|
||||
RaceDTO race = raceColumn.getRace(fleet);
|
||||
if(race != null && race.trackedRace != null && race.trackedRace.hasGPSData && race.trackedRace.hasWindData) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<RaceColumnDTO> getRaceList() {
|
||||
return races;
|
||||
}
|
||||
|
||||
public void setRaceList(List<RaceColumnDTO> raceList) {
|
||||
this.races = raceList;
|
||||
}
|
||||
|
||||
public boolean raceListContains(String raceColumnName) {
|
||||
return getRaceColumnByName(raceColumnName) != null;
|
||||
}
|
||||
|
||||
public void moveRaceUp(String raceColumnName) {
|
||||
RaceColumnDTO race = getRaceColumnByName(raceColumnName);
|
||||
int index = races.indexOf(race);
|
||||
index--;
|
||||
if (index >= 0) {
|
||||
races.remove(index + 1);
|
||||
races.add(index, race);
|
||||
}
|
||||
}
|
||||
|
||||
public void moveRaceDown(String raceColumnName) {
|
||||
RaceColumnDTO race = getRaceColumnByName(raceColumnName);
|
||||
int index = races.indexOf(race);
|
||||
if (index != -1) {
|
||||
index++;
|
||||
if (index < races.size()) {
|
||||
races.remove(index - 1);
|
||||
races.add(index, race);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setIsMedalRace(String raceColumnName, boolean medalRace) {
|
||||
getRaceColumnByName(raceColumnName).setMedalRace(medalRace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The earliest start date of the races, or <code>null</code> if no start dates of the races are available.
|
||||
*/
|
||||
public Date getStartDate() {
|
||||
Date leaderboardStart = null;
|
||||
for (RaceColumnDTO race : getRaceList()) {
|
||||
for (FleetDTO fleet: race.getFleets()) {
|
||||
Date raceStart = race.getStartDate(fleet);
|
||||
if (raceStart != null) {
|
||||
if (leaderboardStart == null) {
|
||||
leaderboardStart = new Date();
|
||||
} else {
|
||||
leaderboardStart = leaderboardStart.before(raceStart) ? leaderboardStart : raceStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return leaderboardStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the {@link PlacemarkOrderDTO} of all races in this leaderboard, if the PlacemarkOrderDTO for the race is
|
||||
* available, and fills all {@link PlacemarkDTO} in a new PlacemarkOrderDTO.<br />
|
||||
* The order of the races in this leaderboard determine the order of the PlacemarkDTOs in the PlacemarkOrderDTO.
|
||||
*
|
||||
* @return The places of this leaderboard in form of a {@link PlacemarkOrderDTO}, or <code>null</code> if the
|
||||
* {@link PlacemarkOrderDTO places} of no race are available
|
||||
*/
|
||||
public PlacemarkOrderDTO getPlaces() {
|
||||
PlacemarkOrderDTO leaderboardPlaces = null;
|
||||
for (RaceColumnDTO race : getRaceList()) {
|
||||
PlacemarkOrderDTO racePlaces = race.getPlaces();
|
||||
if (racePlaces != null) {
|
||||
if (leaderboardPlaces == null) {
|
||||
leaderboardPlaces = new PlacemarkOrderDTO();
|
||||
}
|
||||
leaderboardPlaces.getPlacemarks().addAll(racePlaces.getPlacemarks());
|
||||
}
|
||||
}
|
||||
return leaderboardPlaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the leaderboard contains a race which is live
|
||||
*/
|
||||
public boolean hasLiveRace(long serverTimePointAsMillis) {
|
||||
for (RaceColumnDTO race : getRaceList()) {
|
||||
for (FleetDTO fleet : race.getFleets()) {
|
||||
if (race.isLive(fleet, serverTimePointAsMillis)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<Util.Pair<RaceColumnDTO, FleetDTO>> getLiveRaces(long serverTimePointAsMillis) {
|
||||
List<Util.Pair<RaceColumnDTO, FleetDTO>> result = new ArrayList<Util.Pair<RaceColumnDTO, FleetDTO>>();
|
||||
for (RaceColumnDTO race : getRaceList()) {
|
||||
for (FleetDTO fleet : race.getFleets()) {
|
||||
if (race.isLive(fleet, serverTimePointAsMillis)) {
|
||||
result.add(new Util.Pair<RaceColumnDTO, FleetDTO>(race, fleet));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
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) {
|
||||
result = prime * result;
|
||||
} else {
|
||||
List<String> raceNames = new ArrayList<String>();
|
||||
for (RaceColumnDTO race : races) {
|
||||
raceNames.add(race.getName());
|
||||
}
|
||||
result = prime * result + raceNames.hashCode();
|
||||
}
|
||||
result = prime * result + ((rows == null) ? 0 : rows.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
AbstractLeaderboardDTO other = (AbstractLeaderboardDTO) obj;
|
||||
if (competitorDisplayNames == null) {
|
||||
if (other.competitorDisplayNames != null)
|
||||
return false;
|
||||
} else if (!competitorDisplayNames.equals(other.competitorDisplayNames))
|
||||
return false;
|
||||
if (!Arrays.equals(discardThresholds, other.discardThresholds))
|
||||
return false;
|
||||
if (hasCarriedPoints != other.hasCarriedPoints)
|
||||
return false;
|
||||
if (type != other.type)
|
||||
return false;
|
||||
if (scoringScheme != other.scoringScheme)
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (races == null) {
|
||||
if (other.races != null)
|
||||
return false;
|
||||
} else {
|
||||
// compare race column names only, not the contents
|
||||
if (races.size() != (other.races==null?0:other.races.size())) {
|
||||
return false;
|
||||
}
|
||||
List<String> raceColumnNames = new ArrayList<String>(races.size());
|
||||
List<String> otherRaceColumnNames = new ArrayList<String>(races.size());
|
||||
for (RaceColumnDTO race : races) {
|
||||
raceColumnNames.add(race.getName());
|
||||
}
|
||||
if (other.races != null) {
|
||||
for (RaceColumnDTO otherRace : other.races) {
|
||||
otherRaceColumnNames.add(otherRace.getName());
|
||||
}
|
||||
}
|
||||
if (!raceColumnNames.equals(otherRaceColumnNames))
|
||||
return false;
|
||||
if (rows == null) {
|
||||
if (other.rows != null)
|
||||
return false;
|
||||
} else if (!rows.equals(other.rows))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDisplayNameSet(CompetitorDTO competitor) {
|
||||
return competitorDisplayNames.get(competitor) != null;
|
||||
}
|
||||
|
||||
public Long getDelayToLiveInMillisForLatestRace() {
|
||||
return delayToLiveInMillisForLatestRace;
|
||||
}
|
||||
|
||||
public void setDelayToLiveInMillisForLatestRace(Long delayToLiveInMillisForLatestRace) {
|
||||
this.delayToLiveInMillisForLatestRace = delayToLiveInMillisForLatestRace;
|
||||
}
|
||||
}
|
||||
+112
@@ -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;
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -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;
|
||||
}
|
||||
|
||||
+49
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+6
-4
@@ -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;
|
||||
|
||||
+7
-78
@@ -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,21 +37,20 @@ 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) {
|
||||
RaceLiveState result = RaceLiveState.NOT_TRACKED;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sailing.domain.shared.android</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-source-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>plugin-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>plugin-source</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sailing.domain.shared.android</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-source-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>plugin-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>plugin-source</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
Binary file not shown.
+4
-4
@@ -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,
|
||||
|
||||
+1
-1
@@ -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));
|
||||
|
||||
+15
-9
@@ -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
|
||||
|
||||
+5
-2
@@ -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;
|
||||
|
||||
|
||||
+7
-6
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+6
-5
@@ -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;
|
||||
|
||||
+6
-7
@@ -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);
|
||||
|
||||
+41
-13
@@ -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
|
||||
@@ -125,6 +129,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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+4
-3
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+13
-12
@@ -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();
|
||||
|
||||
+1937
-1907
File diff suppressed because it is too large.
Load diff
+342
-336
@@ -1,336 +1,342 @@
|
||||
package com.sap.sailing.domain.leaderboard.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
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.leaderboard.FlexibleLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.FlexibleRaceColumn;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.regattalike.BaseRegattaLikeImpl;
|
||||
import com.sap.sailing.domain.regattalike.FlexibleLeaderboardAsRegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.IsRegattaLike;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeListener;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.Duration;
|
||||
|
||||
/**
|
||||
* A leaderboard implementation that allows users to flexibly configure which columns exist. No constraints need to be observed regarding
|
||||
* the columns belonging to the same regatta or even boat class.<p>
|
||||
*
|
||||
* The flexible leaderboard listens as {@link RaceColumnListener} on all its {@link RaceColumn}s and forwards all events to
|
||||
* all {@link RaceColumnListener}s subscribed with this leaderboard.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements FlexibleLeaderboard {
|
||||
private static Logger logger = Logger.getLogger(FlexibleLeaderboardImpl.class.getName());
|
||||
|
||||
protected static final DefaultFleetImpl defaultFleet = new DefaultFleetImpl();
|
||||
private static final long serialVersionUID = -5708971849158747846L;
|
||||
private final List<FlexibleRaceColumn> races;
|
||||
private final ScoringScheme scoringScheme;
|
||||
private String name;
|
||||
private transient RaceLogStore raceLogStore;
|
||||
private CourseArea courseArea;
|
||||
private RaceExecutionOrderProvider raceExecutionOrderProvider;
|
||||
|
||||
/**
|
||||
* @see RegattaLog for the reason why the leaderboard manages a {@code RegattaLog}
|
||||
*/
|
||||
private final IsRegattaLike regattaLikeHelper;
|
||||
|
||||
public FlexibleLeaderboardImpl(String name, ThresholdBasedResultDiscardingRule resultDiscardingRule,
|
||||
ScoringScheme scoringScheme, CourseArea courseArea) {
|
||||
this(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
|
||||
name, resultDiscardingRule, scoringScheme, courseArea);
|
||||
}
|
||||
|
||||
public FlexibleLeaderboardImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
String name, ThresholdBasedResultDiscardingRule resultDiscardingRule,
|
||||
ScoringScheme scoringScheme, CourseArea courseArea) {
|
||||
super(resultDiscardingRule);
|
||||
this.scoringScheme = scoringScheme;
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("A leaderboard's name must not be null");
|
||||
}
|
||||
this.name = name;
|
||||
this.races = new ArrayList<>();
|
||||
this.raceLogStore = raceLogStore;
|
||||
this.courseArea = courseArea;
|
||||
this.regattaLikeHelper = new BaseRegattaLikeImpl(new FlexibleLeaderboardAsRegattaLikeIdentifier(this), regattaLogStore) {
|
||||
private static final long serialVersionUID = 4082392360832548953L;
|
||||
|
||||
@Override
|
||||
public RaceColumn getRaceColumnByName(String raceColumnName) {
|
||||
return getRaceColumnByName(raceColumnName);
|
||||
}
|
||||
};
|
||||
this.raceExecutionOrderProvider = new RaceExecutionOrderCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialization has to be maintained in lock-step with {@link #writeObject(ObjectOutputStream) serialization}.
|
||||
* When de-serializing, a possibly remote {@link #raceLogStore} is ignored because it is transient. Instead, an
|
||||
* {@link EmptyRaceLogStore} is used for the de-serialized instance. A new {@link RaceLogInformation} is
|
||||
* assembled for this empty race log and applied to all columns.
|
||||
*/
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
ois.defaultReadObject();
|
||||
raceLogStore = EmptyRaceLogStore.INSTANCE;
|
||||
for (RaceColumn column : getRaceColumns()) {
|
||||
column.setRaceLogInformation(raceLogStore, new FlexibleLeaderboardAsRegattaLikeIdentifier(this));
|
||||
}
|
||||
}
|
||||
|
||||
protected Object readResolve() throws ObjectStreamException {
|
||||
raceExecutionOrderProvider.triggerUpdate();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param newName must not be <code>null</code>
|
||||
*/
|
||||
public void setName(String newName) {
|
||||
if (newName == null) {
|
||||
throw new IllegalArgumentException("A leaderboard's name must not be null");
|
||||
}
|
||||
this.name = newName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceColumn addRace(TrackedRace race, String columnName, boolean medalRace) {
|
||||
FlexibleRaceColumn column = addRaceColumn(columnName, medalRace, /* logAlreadyExistingColumn */false);
|
||||
column.setTrackedRace(defaultFleet, race); // triggers listeners because this object was registered above as
|
||||
// race column listener on the column
|
||||
return column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlexibleRaceColumn addRaceColumn(String name, boolean medalRace) {
|
||||
return addRaceColumn(name, medalRace, /* logAlreadyExistingColumn */true);
|
||||
}
|
||||
|
||||
private FlexibleRaceColumn addRaceColumn(String name, boolean medalRace, boolean logAlreadyExistingColumn) {
|
||||
FlexibleRaceColumn column = getRaceColumnByName(name);
|
||||
if (column != null) {
|
||||
if (logAlreadyExistingColumn) {
|
||||
final String msg = "Trying to create race column with duplicate name " + name + " in leaderboard " + getName();
|
||||
logger.severe(msg);
|
||||
}
|
||||
} else {
|
||||
column = createRaceColumn(name, medalRace);
|
||||
column.addRaceColumnListener(this);
|
||||
races.add(column);
|
||||
column.setRaceLogInformation(raceLogStore, new FlexibleLeaderboardAsRegattaLikeIdentifier(this));
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(column);
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlexibleRaceColumn getRaceColumnByName(String columnName) {
|
||||
return (FlexibleRaceColumn) super.getRaceColumnByName(columnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fleet getFleet(String fleetName) {
|
||||
Fleet result;
|
||||
if (fleetName == null) {
|
||||
result = defaultFleet;
|
||||
} else {
|
||||
result = super.getFleet(fleetName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRaceColumn(String columnName) {
|
||||
final FlexibleRaceColumn raceColumn = getRaceColumnByName(columnName);
|
||||
if (raceColumn != null) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
raceLogStore.removeRaceLog(raceColumn.getRaceLogIdentifier(fleet));
|
||||
if (raceColumn.getTrackedRace(fleet) != null) {
|
||||
raceColumn.getTrackedRace(fleet).detachRaceExecutionOrderProvider(raceExecutionOrderProvider);
|
||||
}
|
||||
}
|
||||
races.remove(raceColumn);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(raceColumn);
|
||||
raceColumn.removeRaceColumnListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<RaceColumn> getRaceColumns() {
|
||||
final Iterable<RaceColumn> result;
|
||||
if (races != null) {
|
||||
result = Collections.unmodifiableCollection(new ArrayList<RaceColumn>(races));
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected RaceColumnImpl createRaceColumn(String column, boolean medalRace) {
|
||||
return new RaceColumnImpl(column, medalRace, raceExecutionOrderProvider);
|
||||
}
|
||||
|
||||
protected Iterable<Fleet> turnNullOrEmptyFleetsIntoDefaultFleet(Fleet... fleets) {
|
||||
Iterable<Fleet> theFleets;
|
||||
if (fleets == null || fleets.length == 0) {
|
||||
Fleet defaultfleetCasted = defaultFleet;
|
||||
theFleets = Collections.singleton(defaultfleetCasted);
|
||||
} else {
|
||||
theFleets = Arrays.asList(fleets);
|
||||
}
|
||||
return theFleets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRaceColumnUp(String name) {
|
||||
FlexibleRaceColumn race = null;
|
||||
for (FlexibleRaceColumn r : races) {
|
||||
if (r.getName().equals(name)) {
|
||||
race = r;
|
||||
}
|
||||
}
|
||||
if (race != null) {
|
||||
int index = 0;
|
||||
index = races.lastIndexOf(race);
|
||||
index--;
|
||||
if (index >= 0) {
|
||||
races.remove(race);
|
||||
races.add(index, race);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(race, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRaceColumnDown(String name) {
|
||||
FlexibleRaceColumn race = null;
|
||||
for (FlexibleRaceColumn r : races) {
|
||||
if (r.getName().equals(name)) {
|
||||
race = r;
|
||||
}
|
||||
}
|
||||
if (race != null) {
|
||||
int index = 0;
|
||||
index = races.lastIndexOf(race);
|
||||
if (index != -1) {
|
||||
index++;
|
||||
if (index < races.size()) {
|
||||
races.remove(race);
|
||||
races.add(index, race);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(race, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateIsMedalRace(String raceName, boolean isMedalRace) {
|
||||
FlexibleRaceColumn race = null;
|
||||
for (FlexibleRaceColumn r : races) {
|
||||
if (r.getName().equals(raceName))
|
||||
race = r;
|
||||
}
|
||||
if (race != null) {
|
||||
race.setIsMedalRace(isMedalRace);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoringScheme getScoringScheme() {
|
||||
return scoringScheme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return courseArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultCourseArea(CourseArea newCourseArea) {
|
||||
this.courseArea = newCourseArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsRegattaLike getRegattaLike() {
|
||||
return regattaLikeHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegattaLog getRegattaLog() {
|
||||
return regattaLikeHelper.getRegattaLog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegattaLikeIdentifier getRegattaLikeIdentifier() {
|
||||
return regattaLikeHelper.getRegattaLikeIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(RegattaLikeListener listener) {
|
||||
regattaLikeHelper.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(RegattaLikeListener listener) {
|
||||
regattaLikeHelper.removeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getTimeOnTimeFactor(Competitor competitor) {
|
||||
return regattaLikeHelper.getTimeOnTimeFactor(competitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getTimeOnDistanceAllowancePerNauticalMile(Competitor competitor) {
|
||||
return regattaLikeHelper.getTimeOnDistanceAllowancePerNauticalMile(competitor);
|
||||
}
|
||||
|
||||
private class RaceExecutionOrderCache extends AbstractRaceExecutionOrderProvider {
|
||||
private static final long serialVersionUID = 652833386555762661L;
|
||||
|
||||
public RaceExecutionOrderCache() {
|
||||
super();
|
||||
addRaceColumnListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Fleet, Iterable<? extends RaceColumn>> getRaceColumnsOfSeries() {
|
||||
final Map<Fleet, Iterable<? extends RaceColumn>> result = new HashMap<>();
|
||||
result.put(FlexibleLeaderboardImpl.defaultFleet, getRaceColumns());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.leaderboard.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
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;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.racelog.RaceLogStore;
|
||||
import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
|
||||
import com.sap.sailing.domain.regattalike.BaseRegattaLikeImpl;
|
||||
import com.sap.sailing.domain.regattalike.FlexibleLeaderboardAsRegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.IsRegattaLike;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeIdentifier;
|
||||
import com.sap.sailing.domain.regattalike.RegattaLikeListener;
|
||||
import com.sap.sailing.domain.regattalog.RegattaLogStore;
|
||||
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
|
||||
import com.sap.sailing.domain.tracking.RaceExecutionOrderProvider;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sse.common.Duration;
|
||||
|
||||
/**
|
||||
* A leaderboard implementation that allows users to flexibly configure which columns exist. No constraints need to be observed regarding
|
||||
* the columns belonging to the same regatta or even boat class.<p>
|
||||
*
|
||||
* The flexible leaderboard listens as {@link RaceColumnListener} on all its {@link RaceColumn}s and forwards all events to
|
||||
* all {@link RaceColumnListener}s subscribed with this leaderboard.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class FlexibleLeaderboardImpl extends AbstractLeaderboardImpl implements FlexibleLeaderboard {
|
||||
private static Logger logger = Logger.getLogger(FlexibleLeaderboardImpl.class.getName());
|
||||
|
||||
protected static final DefaultFleetImpl defaultFleet = new DefaultFleetImpl();
|
||||
private static final long serialVersionUID = -5708971849158747846L;
|
||||
private final List<FlexibleRaceColumn> races;
|
||||
private final ScoringScheme scoringScheme;
|
||||
private String name;
|
||||
private transient RaceLogStore raceLogStore;
|
||||
private CourseArea courseArea;
|
||||
private RaceExecutionOrderProvider raceExecutionOrderProvider;
|
||||
|
||||
/**
|
||||
* @see RegattaLog for the reason why the leaderboard manages a {@code RegattaLog}
|
||||
*/
|
||||
private final IsRegattaLike regattaLikeHelper;
|
||||
|
||||
public FlexibleLeaderboardImpl(String name, ThresholdBasedResultDiscardingRule resultDiscardingRule,
|
||||
ScoringScheme scoringScheme, CourseArea courseArea) {
|
||||
this(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
|
||||
name, resultDiscardingRule, scoringScheme, courseArea);
|
||||
}
|
||||
|
||||
public FlexibleLeaderboardImpl(RaceLogStore raceLogStore, RegattaLogStore regattaLogStore,
|
||||
String name, ThresholdBasedResultDiscardingRule resultDiscardingRule,
|
||||
ScoringScheme scoringScheme, CourseArea courseArea) {
|
||||
super(resultDiscardingRule);
|
||||
this.scoringScheme = scoringScheme;
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("A leaderboard's name must not be null");
|
||||
}
|
||||
this.name = name;
|
||||
this.races = new ArrayList<>();
|
||||
this.raceLogStore = raceLogStore;
|
||||
this.courseArea = courseArea;
|
||||
this.regattaLikeHelper = new BaseRegattaLikeImpl(new FlexibleLeaderboardAsRegattaLikeIdentifier(this), regattaLogStore) {
|
||||
private static final long serialVersionUID = 4082392360832548953L;
|
||||
|
||||
@Override
|
||||
public RaceColumn getRaceColumnByName(String raceColumnName) {
|
||||
return getRaceColumnByName(raceColumnName);
|
||||
}
|
||||
};
|
||||
this.raceExecutionOrderProvider = new RaceExecutionOrderCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialization has to be maintained in lock-step with {@link #writeObject(ObjectOutputStream) serialization}.
|
||||
* When de-serializing, a possibly remote {@link #raceLogStore} is ignored because it is transient. Instead, an
|
||||
* {@link EmptyRaceLogStore} is used for the de-serialized instance. A new {@link RaceLogInformation} is
|
||||
* assembled for this empty race log and applied to all columns.
|
||||
*/
|
||||
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
|
||||
ois.defaultReadObject();
|
||||
raceLogStore = EmptyRaceLogStore.INSTANCE;
|
||||
for (RaceColumn column : getRaceColumns()) {
|
||||
column.setRaceLogInformation(raceLogStore, new FlexibleLeaderboardAsRegattaLikeIdentifier(this));
|
||||
}
|
||||
}
|
||||
|
||||
protected Object readResolve() throws ObjectStreamException {
|
||||
raceExecutionOrderProvider.triggerUpdate();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param newName must not be <code>null</code>
|
||||
*/
|
||||
public void setName(String newName) {
|
||||
if (newName == null) {
|
||||
throw new IllegalArgumentException("A leaderboard's name must not be null");
|
||||
}
|
||||
this.name = newName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceColumn addRace(TrackedRace race, String columnName, boolean medalRace) {
|
||||
FlexibleRaceColumn column = addRaceColumn(columnName, medalRace, /* logAlreadyExistingColumn */false);
|
||||
column.setTrackedRace(defaultFleet, race); // triggers listeners because this object was registered above as
|
||||
// race column listener on the column
|
||||
return column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlexibleRaceColumn addRaceColumn(String name, boolean medalRace) {
|
||||
return addRaceColumn(name, medalRace, /* logAlreadyExistingColumn */true);
|
||||
}
|
||||
|
||||
private FlexibleRaceColumn addRaceColumn(String name, boolean medalRace, boolean logAlreadyExistingColumn) {
|
||||
FlexibleRaceColumn column = getRaceColumnByName(name);
|
||||
if (column != null) {
|
||||
if (logAlreadyExistingColumn) {
|
||||
final String msg = "Trying to create race column with duplicate name " + name + " in leaderboard " + getName();
|
||||
logger.severe(msg);
|
||||
}
|
||||
} else {
|
||||
column = createRaceColumn(name, medalRace);
|
||||
column.addRaceColumnListener(this);
|
||||
races.add(column);
|
||||
column.setRaceLogInformation(raceLogStore, new FlexibleLeaderboardAsRegattaLikeIdentifier(this));
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(column);
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlexibleRaceColumn getRaceColumnByName(String columnName) {
|
||||
return (FlexibleRaceColumn) super.getRaceColumnByName(columnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fleet getFleet(String fleetName) {
|
||||
Fleet result;
|
||||
if (fleetName == null) {
|
||||
result = defaultFleet;
|
||||
} else {
|
||||
result = super.getFleet(fleetName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRaceColumn(String columnName) {
|
||||
final FlexibleRaceColumn raceColumn = getRaceColumnByName(columnName);
|
||||
if (raceColumn != null) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
raceLogStore.removeRaceLog(raceColumn.getRaceLogIdentifier(fleet));
|
||||
if (raceColumn.getTrackedRace(fleet) != null) {
|
||||
raceColumn.getTrackedRace(fleet).detachRaceExecutionOrderProvider(raceExecutionOrderProvider);
|
||||
}
|
||||
}
|
||||
races.remove(raceColumn);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(raceColumn);
|
||||
raceColumn.removeRaceColumnListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<RaceColumn> getRaceColumns() {
|
||||
final Iterable<RaceColumn> result;
|
||||
if (races != null) {
|
||||
result = Collections.unmodifiableCollection(new ArrayList<RaceColumn>(races));
|
||||
} else {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected RaceColumnImpl createRaceColumn(String column, boolean medalRace) {
|
||||
return new RaceColumnImpl(column, medalRace, raceExecutionOrderProvider);
|
||||
}
|
||||
|
||||
protected Iterable<Fleet> turnNullOrEmptyFleetsIntoDefaultFleet(Fleet... fleets) {
|
||||
Iterable<Fleet> theFleets;
|
||||
if (fleets == null || fleets.length == 0) {
|
||||
Fleet defaultfleetCasted = defaultFleet;
|
||||
theFleets = Collections.singleton(defaultfleetCasted);
|
||||
} else {
|
||||
theFleets = Arrays.asList(fleets);
|
||||
}
|
||||
return theFleets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRaceColumnUp(String name) {
|
||||
FlexibleRaceColumn race = null;
|
||||
for (FlexibleRaceColumn r : races) {
|
||||
if (r.getName().equals(name)) {
|
||||
race = r;
|
||||
}
|
||||
}
|
||||
if (race != null) {
|
||||
int index = 0;
|
||||
index = races.lastIndexOf(race);
|
||||
index--;
|
||||
if (index >= 0) {
|
||||
races.remove(race);
|
||||
races.add(index, race);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(race, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveRaceColumnDown(String name) {
|
||||
FlexibleRaceColumn race = null;
|
||||
for (FlexibleRaceColumn r : races) {
|
||||
if (r.getName().equals(name)) {
|
||||
race = r;
|
||||
}
|
||||
}
|
||||
if (race != null) {
|
||||
int index = 0;
|
||||
index = races.lastIndexOf(race);
|
||||
if (index != -1) {
|
||||
index++;
|
||||
if (index < races.size()) {
|
||||
races.remove(race);
|
||||
races.add(index, race);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnMoved(race, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateIsMedalRace(String raceName, boolean isMedalRace) {
|
||||
FlexibleRaceColumn race = null;
|
||||
for (FlexibleRaceColumn r : races) {
|
||||
if (r.getName().equals(raceName))
|
||||
race = r;
|
||||
}
|
||||
if (race != null) {
|
||||
race.setIsMedalRace(isMedalRace);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoringScheme getScoringScheme() {
|
||||
return scoringScheme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return courseArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultCourseArea(CourseArea newCourseArea) {
|
||||
this.courseArea = newCourseArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsRegattaLike getRegattaLike() {
|
||||
return regattaLikeHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegattaLog getRegattaLog() {
|
||||
return regattaLikeHelper.getRegattaLog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegattaLikeIdentifier getRegattaLikeIdentifier() {
|
||||
return regattaLikeHelper.getRegattaLikeIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(RegattaLikeListener listener) {
|
||||
regattaLikeHelper.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(RegattaLikeListener listener) {
|
||||
regattaLikeHelper.removeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getTimeOnTimeFactor(Competitor competitor) {
|
||||
return regattaLikeHelper.getTimeOnTimeFactor(competitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getTimeOnDistanceAllowancePerNauticalMile(Competitor competitor) {
|
||||
return regattaLikeHelper.getTimeOnDistanceAllowancePerNauticalMile(competitor);
|
||||
}
|
||||
|
||||
private class RaceExecutionOrderCache extends AbstractRaceExecutionOrderProvider {
|
||||
private static final long serialVersionUID = 652833386555762661L;
|
||||
|
||||
public RaceExecutionOrderCache() {
|
||||
super();
|
||||
addRaceColumnListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Fleet, Iterable<? extends RaceColumn>> getRaceColumnsOfSeries() {
|
||||
final Map<Fleet, Iterable<? extends RaceColumn>> result = new HashMap<>();
|
||||
result.put(FlexibleLeaderboardImpl.defaultFleet, getRaceColumns());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LeaderboardType getLeaderboardType() {
|
||||
return LeaderboardType.FlexibleLeaderboard;
|
||||
}
|
||||
}
|
||||
+123
-117
@@ -1,117 +1,123 @@
|
||||
package com.sap.sailing.domain.leaderboard.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.RaceColumnInSeries;
|
||||
import com.sap.sailing.domain.base.RaceColumnListener;
|
||||
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.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ResultDiscardingRule;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.regattalike.IsRegattaLike;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
* A leaderboard that is based on the definition of a {@link Regatta} with its {@link Series} and {@link Fleet}. The regatta
|
||||
* leaderboard listens to its {@link Regatta} as a {@link RaceColumnListener} and forwards all link/unlink events for
|
||||
* {@link TrackedRace}s being linked to / unlinked from race columns to all {@link RaceColumnListener}s subscribed with
|
||||
* this leaderboard.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements RegattaLeaderboard {
|
||||
private static final long serialVersionUID = 2370461218294770084L;
|
||||
private final Regatta regatta;
|
||||
|
||||
public RegattaLeaderboardImpl(Regatta regatta, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(resultDiscardingRule);
|
||||
this.regatta = regatta;
|
||||
regatta.addRaceColumnListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the display name of this regatta leaderboard so that the regatta's name is no longer used as the default name.
|
||||
*/
|
||||
@Override
|
||||
public void setName(String newName) {
|
||||
setDisplayName(newName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Regatta getRegatta() {
|
||||
return regatta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getRegatta().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<RaceColumn> getRaceColumns() {
|
||||
List<RaceColumn> result = new ArrayList<RaceColumn>();
|
||||
for (Series series : getRegatta().getSeries()) {
|
||||
for (RaceColumn raceColumn : series.getRaceColumns()) {
|
||||
result.add(raceColumn);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceColumnInSeries getRaceColumnByName(String columnName) {
|
||||
return (RaceColumnInSeriesImpl) super.getRaceColumnByName(columnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoringScheme getScoringScheme() {
|
||||
return regatta.getScoringScheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return regatta.getDefaultCourseArea();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the regatta' series {@link Regatta#definesSeriesDiscardThresholds() define} their own result discarding rules, this leaderboard uses
|
||||
* a composite result discarding rule of type {@link PerSeriesResultDiscardingRuleImpl} that contains discards within each series according
|
||||
* to the series' discarding rules. Otherwise, the default cross-leaderboard result discarding rule is obtained from the super class
|
||||
* implementation.
|
||||
*/
|
||||
@Override
|
||||
public ResultDiscardingRule getResultDiscardingRule() {
|
||||
if (regatta.definesSeriesDiscardThresholds()) {
|
||||
return new PerSeriesResultDiscardingRuleImpl(regatta);
|
||||
} else {
|
||||
return super.getResultDiscardingRule();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Regatta#getAllCompetitors()} which is expected to deliver all competitors from this
|
||||
* leaderboard's regatta which includes those belonging to {@link RaceDefinition races}
|
||||
* {@link Regatta#getAllRaces() belonging to the regatta} as well as competitors listed on the regatta's
|
||||
* {@link RegattaLog}.
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Competitor> getAllCompetitors() {
|
||||
return regatta.getAllCompetitors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsRegattaLike getRegattaLike() {
|
||||
return regatta;
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.leaderboard.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.abstractlog.regatta.RegattaLog;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.base.RaceColumn;
|
||||
import com.sap.sailing.domain.base.RaceColumnInSeries;
|
||||
import com.sap.sailing.domain.base.RaceColumnListener;
|
||||
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;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.regattalike.IsRegattaLike;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
* A leaderboard that is based on the definition of a {@link Regatta} with its {@link Series} and {@link Fleet}. The regatta
|
||||
* leaderboard listens to its {@link Regatta} as a {@link RaceColumnListener} and forwards all link/unlink events for
|
||||
* {@link TrackedRace}s being linked to / unlinked from race columns to all {@link RaceColumnListener}s subscribed with
|
||||
* this leaderboard.
|
||||
*
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements RegattaLeaderboard {
|
||||
private static final long serialVersionUID = 2370461218294770084L;
|
||||
private final Regatta regatta;
|
||||
|
||||
public RegattaLeaderboardImpl(Regatta regatta, ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(resultDiscardingRule);
|
||||
this.regatta = regatta;
|
||||
regatta.addRaceColumnListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the display name of this regatta leaderboard so that the regatta's name is no longer used as the default name.
|
||||
*/
|
||||
@Override
|
||||
public void setName(String newName) {
|
||||
setDisplayName(newName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Regatta getRegatta() {
|
||||
return regatta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getRegatta().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<RaceColumn> getRaceColumns() {
|
||||
List<RaceColumn> result = new ArrayList<RaceColumn>();
|
||||
for (Series series : getRegatta().getSeries()) {
|
||||
for (RaceColumn raceColumn : series.getRaceColumns()) {
|
||||
result.add(raceColumn);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceColumnInSeries getRaceColumnByName(String columnName) {
|
||||
return (RaceColumnInSeriesImpl) super.getRaceColumnByName(columnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScoringScheme getScoringScheme() {
|
||||
return regatta.getScoringScheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return regatta.getDefaultCourseArea();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the regatta' series {@link Regatta#definesSeriesDiscardThresholds() define} their own result discarding rules, this leaderboard uses
|
||||
* a composite result discarding rule of type {@link PerSeriesResultDiscardingRuleImpl} that contains discards within each series according
|
||||
* to the series' discarding rules. Otherwise, the default cross-leaderboard result discarding rule is obtained from the super class
|
||||
* implementation.
|
||||
*/
|
||||
@Override
|
||||
public ResultDiscardingRule getResultDiscardingRule() {
|
||||
if (regatta.definesSeriesDiscardThresholds()) {
|
||||
return new PerSeriesResultDiscardingRuleImpl(regatta);
|
||||
} else {
|
||||
return super.getResultDiscardingRule();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Regatta#getAllCompetitors()} which is expected to deliver all competitors from this
|
||||
* leaderboard's regatta which includes those belonging to {@link RaceDefinition races}
|
||||
* {@link Regatta#getAllRaces() belonging to the regatta} as well as competitors listed on the regatta's
|
||||
* {@link RegattaLog}.
|
||||
*/
|
||||
@Override
|
||||
public Iterable<Competitor> getAllCompetitors() {
|
||||
return regatta.getAllCompetitors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsRegattaLike getRegattaLike() {
|
||||
return regatta;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LeaderboardType getLeaderboardType() {
|
||||
return LeaderboardType.RegattaLeaderboard;
|
||||
}
|
||||
}
|
||||
+70
-64
@@ -1,64 +1,70 @@
|
||||
package com.sap.sailing.domain.leaderboard.meta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sse.concurrent.LockUtil;
|
||||
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
||||
|
||||
public class FlexibleMetaLeaderboard extends AbstractMetaLeaderboard {
|
||||
private static final long serialVersionUID = 789076326144062944L;
|
||||
|
||||
private final List<Leaderboard> leaderboards;
|
||||
|
||||
private final NamedReentrantReadWriteLock leaderboardsLock;
|
||||
|
||||
public FlexibleMetaLeaderboard(String name, ScoringScheme scoringScheme,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(name, scoringScheme, resultDiscardingRule);
|
||||
leaderboards = new ArrayList<Leaderboard>();
|
||||
leaderboardsLock = new NamedReentrantReadWriteLock("leaderboards collection of "+FlexibleMetaLeaderboard.class.getSimpleName()+" "+getName(),
|
||||
/* fair */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Leaderboard> getLeaderboards() {
|
||||
LockUtil.lockForRead(leaderboardsLock);
|
||||
try {
|
||||
return new ArrayList<Leaderboard>(leaderboards);
|
||||
} finally {
|
||||
LockUtil.unlockAfterRead(leaderboardsLock);
|
||||
}
|
||||
}
|
||||
|
||||
public void addLeaderboard(Leaderboard leaderboard) {
|
||||
LockUtil.lockForWrite(leaderboardsLock);
|
||||
try {
|
||||
leaderboards.add(leaderboard);
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(getColumnForLeaderboard(leaderboard));
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(leaderboardsLock);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeLeaderboard(Leaderboard leaderboard) {
|
||||
LockUtil.lockForWrite(leaderboardsLock);
|
||||
try {
|
||||
leaderboards.remove(leaderboard);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(getColumnForLeaderboard(leaderboard));
|
||||
unregisterScoreCorrectionChangeForwarder(leaderboard);
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(leaderboardsLock);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.leaderboard.meta;
|
||||
|
||||
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;
|
||||
import com.sap.sse.concurrent.LockUtil;
|
||||
import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
|
||||
|
||||
public class FlexibleMetaLeaderboard extends AbstractMetaLeaderboard {
|
||||
private static final long serialVersionUID = 789076326144062944L;
|
||||
|
||||
private final List<Leaderboard> leaderboards;
|
||||
|
||||
private final NamedReentrantReadWriteLock leaderboardsLock;
|
||||
|
||||
public FlexibleMetaLeaderboard(String name, ScoringScheme scoringScheme,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(name, scoringScheme, resultDiscardingRule);
|
||||
leaderboards = new ArrayList<Leaderboard>();
|
||||
leaderboardsLock = new NamedReentrantReadWriteLock("leaderboards collection of "+FlexibleMetaLeaderboard.class.getSimpleName()+" "+getName(),
|
||||
/* fair */ false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Leaderboard> getLeaderboards() {
|
||||
LockUtil.lockForRead(leaderboardsLock);
|
||||
try {
|
||||
return new ArrayList<Leaderboard>(leaderboards);
|
||||
} finally {
|
||||
LockUtil.unlockAfterRead(leaderboardsLock);
|
||||
}
|
||||
}
|
||||
|
||||
public void addLeaderboard(Leaderboard leaderboard) {
|
||||
LockUtil.lockForWrite(leaderboardsLock);
|
||||
try {
|
||||
leaderboards.add(leaderboard);
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(getColumnForLeaderboard(leaderboard));
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(leaderboardsLock);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeLeaderboard(Leaderboard leaderboard) {
|
||||
LockUtil.lockForWrite(leaderboardsLock);
|
||||
try {
|
||||
leaderboards.remove(leaderboard);
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(getColumnForLeaderboard(leaderboard));
|
||||
unregisterScoreCorrectionChangeForwarder(leaderboard);
|
||||
} finally {
|
||||
LockUtil.unlockAfterWrite(leaderboardsLock);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LeaderboardType getLeaderboardType() {
|
||||
return LeaderboardType.FlexibleMetaLeaderboard;
|
||||
}
|
||||
}
|
||||
+98
-92
@@ -1,92 +1,98 @@
|
||||
package com.sap.sailing.domain.leaderboard.meta;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
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.TrackedRaces;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroupListener;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
* A meta leaderboard which considers all regular leaderboards of a {@link LeaderboardGroup}. To stay up to date, this
|
||||
* meta leaderboard registers itself as a {@link LeaderboardGroupListener} on the leaderboard group it represents. This
|
||||
* way, whenever a leaderboard is added to or removed from the group, this meta leaderboard can in turn inform its
|
||||
* {@link RaceColumnListener}s about the impact this change has on the set of {@link TrackedRaces} and therefore the
|
||||
* competitors attached to this meta leaderboard.
|
||||
* <p>
|
||||
*
|
||||
* After an object of this type has been de-serialized, and after all objects referenced by it (leaderboard, leaderboard
|
||||
* group) have been initialized, {@link #registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards()} must be called to
|
||||
* ensure that score corrections are propagated as desired. This is because score correction listeners are "transient"
|
||||
* and are as such not serialized. Note: calling {@link #registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards()}
|
||||
* during <code>readObject</code> or <code>readResolve</code> is not possible because the object graph hasn't been fully
|
||||
* initialized yet when those methods are called. Hence, the structures for registering the score correction listeners
|
||||
* are not yet in place at that time.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class LeaderboardGroupMetaLeaderboard extends AbstractMetaLeaderboard implements LeaderboardGroupListener, RaceColumnListener {
|
||||
private static final long serialVersionUID = 8087872002175528002L;
|
||||
|
||||
private final LeaderboardGroup leaderboardGroup;
|
||||
|
||||
public LeaderboardGroupMetaLeaderboard(LeaderboardGroup leaderboardGroup, ScoringScheme scoringScheme,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(leaderboardGroup.getName() + " " + LeaderboardNameConstants.OVERALL, scoringScheme, resultDiscardingRule);
|
||||
this.leaderboardGroup = leaderboardGroup;
|
||||
leaderboardGroup.addLeaderboardGroupListener(this);
|
||||
registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards();
|
||||
}
|
||||
|
||||
public void registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards() {
|
||||
for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Leaderboard> getLeaderboards() {
|
||||
return leaderboardGroup.getLeaderboards();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaderboardAdded(LeaderboardGroup group, Leaderboard leaderboard) {
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
if (trackedRace != null) {
|
||||
getRaceColumnListeners().notifyListenersAboutTrackedRaceLinked(raceColumn, fleet, trackedRace);
|
||||
}
|
||||
}
|
||||
}
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(getColumnForLeaderboard(leaderboard));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaderboardRemoved(LeaderboardGroup group, Leaderboard leaderboard) {
|
||||
leaderboard.removeRaceColumnListener(this);
|
||||
unregisterScoreCorrectionChangeForwarder(leaderboard);
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
if (trackedRace != null) {
|
||||
getRaceColumnListeners().notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
|
||||
}
|
||||
}
|
||||
}
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(getColumnForLeaderboard(leaderboard));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.domain.leaderboard.meta;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
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.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;
|
||||
import com.sap.sailing.domain.leaderboard.ScoringScheme;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
|
||||
/**
|
||||
* A meta leaderboard which considers all regular leaderboards of a {@link LeaderboardGroup}. To stay up to date, this
|
||||
* meta leaderboard registers itself as a {@link LeaderboardGroupListener} on the leaderboard group it represents. This
|
||||
* way, whenever a leaderboard is added to or removed from the group, this meta leaderboard can in turn inform its
|
||||
* {@link RaceColumnListener}s about the impact this change has on the set of {@link TrackedRaces} and therefore the
|
||||
* competitors attached to this meta leaderboard.
|
||||
* <p>
|
||||
*
|
||||
* After an object of this type has been de-serialized, and after all objects referenced by it (leaderboard, leaderboard
|
||||
* group) have been initialized, {@link #registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards()} must be called to
|
||||
* ensure that score corrections are propagated as desired. This is because score correction listeners are "transient"
|
||||
* and are as such not serialized. Note: calling {@link #registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards()}
|
||||
* during <code>readObject</code> or <code>readResolve</code> is not possible because the object graph hasn't been fully
|
||||
* initialized yet when those methods are called. Hence, the structures for registering the score correction listeners
|
||||
* are not yet in place at that time.
|
||||
*
|
||||
* @author Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class LeaderboardGroupMetaLeaderboard extends AbstractMetaLeaderboard implements LeaderboardGroupListener, RaceColumnListener {
|
||||
private static final long serialVersionUID = 8087872002175528002L;
|
||||
|
||||
private final LeaderboardGroup leaderboardGroup;
|
||||
|
||||
public LeaderboardGroupMetaLeaderboard(LeaderboardGroup leaderboardGroup, ScoringScheme scoringScheme,
|
||||
ThresholdBasedResultDiscardingRule resultDiscardingRule) {
|
||||
super(leaderboardGroup.getName() + " " + LeaderboardNameConstants.OVERALL, scoringScheme, resultDiscardingRule);
|
||||
this.leaderboardGroup = leaderboardGroup;
|
||||
leaderboardGroup.addLeaderboardGroupListener(this);
|
||||
registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards();
|
||||
}
|
||||
|
||||
public void registerAsScoreCorrectionChangeForwarderAndRaceColumnListenerOnAllLeaderboards() {
|
||||
for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Leaderboard> getLeaderboards() {
|
||||
return leaderboardGroup.getLeaderboards();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaderboardAdded(LeaderboardGroup group, Leaderboard leaderboard) {
|
||||
registerScoreCorrectionAndRaceColumnChangeForwarder(leaderboard);
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
if (trackedRace != null) {
|
||||
getRaceColumnListeners().notifyListenersAboutTrackedRaceLinked(raceColumn, fleet, trackedRace);
|
||||
}
|
||||
}
|
||||
}
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnAddedToContainer(getColumnForLeaderboard(leaderboard));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaderboardRemoved(LeaderboardGroup group, Leaderboard leaderboard) {
|
||||
leaderboard.removeRaceColumnListener(this);
|
||||
unregisterScoreCorrectionChangeForwarder(leaderboard);
|
||||
for (RaceColumn raceColumn : leaderboard.getRaceColumns()) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
if (trackedRace != null) {
|
||||
getRaceColumnListeners().notifyListenersAboutTrackedRaceUnlinked(raceColumn, fleet, trackedRace);
|
||||
}
|
||||
}
|
||||
}
|
||||
getRaceColumnListeners().notifyListenersAboutRaceColumnRemovedFromContainer(getColumnForLeaderboard(leaderboard));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseArea getDefaultCourseArea() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LeaderboardType getLeaderboardType() {
|
||||
return LeaderboardType.RegattaMetaLeaderboard;
|
||||
}
|
||||
}
|
||||
+53
-50
@@ -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,
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+162
-162
@@ -1,162 +1,162 @@
|
||||
package com.sap.sailing.gwt.ui.test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||
import com.sap.sailing.gwt.ui.server.SailingServiceImpl;
|
||||
|
||||
public class TestColumnSwapping {
|
||||
|
||||
private LeaderboardDTO lb = null;
|
||||
private static final String LEADERBOARDNAME = "test";
|
||||
private static final String DEFAULT_FLEET_NAME = "Default";
|
||||
private static final FleetDTO DEFAULT_FLEET = new FleetDTO(DEFAULT_FLEET_NAME, /* ordering */ 0, /* color */ null);
|
||||
private SailingServiceImpl service;
|
||||
private LeaderboardDTO leaderboardOriginalDTO;
|
||||
private LeaderboardDTO leaderboardDTO;
|
||||
private Collection<String> leglist;
|
||||
private Date leaderboardCreationDate;
|
||||
private SailingServiceImpl sailingService = null;
|
||||
|
||||
// Test-Data
|
||||
private final String TEST_LEADERBOARD_NAME = "test_board";
|
||||
private final String[] races = { "1", "2", "3" };
|
||||
private final boolean[] isMedalRace = { false, false, true };
|
||||
|
||||
@Before
|
||||
public void prepareColumnSwapping() {
|
||||
service = new SailingServiceImplMock();
|
||||
int[] disc = { 5, 8, 9, 0, 7, 5, 43 };
|
||||
service.removeLeaderboard(LEADERBOARDNAME);
|
||||
service.createFlexibleLeaderboard(LEADERBOARDNAME, null, disc, ScoringSchemeType.LOW_POINT, null);
|
||||
service.addColumnToLeaderboard("Race1", LEADERBOARDNAME, true);
|
||||
service.addColumnToLeaderboard("Race2", LEADERBOARDNAME, true);
|
||||
service.addColumnToLeaderboard("Race3", LEADERBOARDNAME, true);
|
||||
leglist = new ArrayList<String>();
|
||||
leglist.add("Race1");
|
||||
leglist.add("Race2");
|
||||
leglist.add("Race3");
|
||||
leaderboardCreationDate = new Date();
|
||||
try {
|
||||
// get Leaderboard with name and current date
|
||||
leaderboardOriginalDTO = new LeaderboardDTO(null, null, ScoringSchemeType.LOW_POINT, /* higherScoreIsBetter */ false, new LeaderboardDTO.UUIDGenerator() {
|
||||
@Override
|
||||
public String generateRandomUUID() {
|
||||
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);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColumnSwapping() {
|
||||
testColumnSwappingFabian();
|
||||
testLeaderBoardDTOMethods();
|
||||
testSailingService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSailingService() {
|
||||
sailingService = new SailingServiceImplMock();
|
||||
assertNotNull("Sailingservice != NULL", sailingService);
|
||||
int td[] = { 5, 8 };
|
||||
sailingService.removeLeaderboard(TEST_LEADERBOARD_NAME);
|
||||
sailingService.createFlexibleLeaderboard(TEST_LEADERBOARD_NAME, null, td, ScoringSchemeType.LOW_POINT, null);
|
||||
for (int i = 0; i < races.length; i++)
|
||||
sailingService.addColumnToLeaderboard(races[i], TEST_LEADERBOARD_NAME, isMedalRace[i]);
|
||||
sailingService.moveLeaderboardColumnDown(TEST_LEADERBOARD_NAME, races[0]);
|
||||
sailingService.moveLeaderboardColumnDown(TEST_LEADERBOARD_NAME, races[0]);
|
||||
sailingService.moveLeaderboardColumnUp(TEST_LEADERBOARD_NAME, races[2]);
|
||||
sailingService.updateIsMedalRace(TEST_LEADERBOARD_NAME, races[0], true);
|
||||
sailingService.updateIsMedalRace(TEST_LEADERBOARD_NAME, races[2], false);
|
||||
try {
|
||||
for (int i = 0; i < races.length; i++)
|
||||
sailingService.addColumnToLeaderboard(races[i], TEST_LEADERBOARD_NAME, isMedalRace[i]);
|
||||
sailingService.moveLeaderboardColumnDown(TEST_LEADERBOARD_NAME, races[0]);
|
||||
sailingService.moveLeaderboardColumnDown(TEST_LEADERBOARD_NAME, races[0]);
|
||||
sailingService.moveLeaderboardColumnUp(TEST_LEADERBOARD_NAME, races[2]);
|
||||
sailingService.updateIsMedalRace(TEST_LEADERBOARD_NAME, races[0], true);
|
||||
sailingService.updateIsMedalRace(TEST_LEADERBOARD_NAME, races[2], false);
|
||||
lb = sailingService.getLeaderboardByName(TEST_LEADERBOARD_NAME, new Date(), /* races to load */ null, /* addOverallDetails */ true, /* previous leaderboard ID */ null,
|
||||
/* fillNetPointsUncorrected */ false).getLeaderboardDTO(/* previousVersion */ null);
|
||||
} catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
fail(e.getLocalizedMessage());
|
||||
}
|
||||
assertNotNull("LeaderboardDTO != NULL", lb);
|
||||
|
||||
// asserted data
|
||||
String[] raceNames = new String[] { "3", "2", "1" };
|
||||
boolean[] medalRace = { true, false, false };
|
||||
|
||||
for (int i = 0; i < lb.getRaceList().size(); i++) {
|
||||
assertEquals("Race[" + i + "] == " + raceNames[i], raceNames[i], lb.getRaceList().get(i).getName());
|
||||
assertTrue("Race[" + i + "] is " + (medalRace[i] ? "" : "no ") + "medalrace.",
|
||||
lb.raceIsMedalRace(races[i]) == medalRace[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeaderBoardDTOMethods() {
|
||||
lb = new LeaderboardDTO(null, null, ScoringSchemeType.LOW_POINT, /* higherScoreIsBetter */ false, new LeaderboardDTO.UUIDGenerator() {
|
||||
@Override
|
||||
public String generateRandomUUID() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
}, /* 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.moveRaceDown("1");
|
||||
String[] s = new String[] { "2", "1", "3" };
|
||||
for (int i = 0; i < lb.getRaceList().size(); i++) {
|
||||
assertEquals("Race[" + i + "] = " + s[i], s[i], lb.getRaceList().get(i).getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColumnSwappingFabian() {
|
||||
service.moveLeaderboardColumnUp(LEADERBOARDNAME, "Race3");
|
||||
try {
|
||||
leaderboardDTO = service.getLeaderboardByName(LEADERBOARDNAME, leaderboardCreationDate, leglist, /* addOverallDetails */
|
||||
true, /* previous leaderboard ID */null, /* fillNetPointsUncorrected */false).getLeaderboardDTO(/* previousVersion */null);
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// check if leaderboardDTO an dleaderboardOriginalDTO same
|
||||
List<RaceColumnDTO> leaderboardList = leaderboardDTO.getRaceList();
|
||||
List<RaceColumnDTO> leaderboardOriginalList = leaderboardOriginalDTO.getRaceList();
|
||||
|
||||
// ??????? assert races in list
|
||||
assertArrayEquals(leaderboardList.toArray(), leaderboardOriginalList.toArray());
|
||||
|
||||
for (RaceColumnDTO raceDTO : leaderboardOriginalList) {
|
||||
assert leaderboardDTO.raceIsMedalRace(raceDTO.getRaceColumnName()) == leaderboardOriginalDTO.raceIsMedalRace(raceDTO.getRaceColumnName());
|
||||
assert leaderboardDTO.raceIsTracked(raceDTO.getRaceColumnName()) == leaderboardOriginalDTO.raceIsTracked(raceDTO.getRaceColumnName());
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.gwt.ui.test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.dto.FleetDTO;
|
||||
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||
import com.sap.sailing.gwt.ui.server.SailingServiceImpl;
|
||||
|
||||
public class TestColumnSwapping {
|
||||
|
||||
private LeaderboardDTO lb = null;
|
||||
private static final String LEADERBOARDNAME = "test";
|
||||
private static final String DEFAULT_FLEET_NAME = "Default";
|
||||
private static final FleetDTO DEFAULT_FLEET = new FleetDTO(DEFAULT_FLEET_NAME, /* ordering */ 0, /* color */ null);
|
||||
private SailingServiceImpl service;
|
||||
private LeaderboardDTO leaderboardOriginalDTO;
|
||||
private LeaderboardDTO leaderboardDTO;
|
||||
private Collection<String> leglist;
|
||||
private Date leaderboardCreationDate;
|
||||
private SailingServiceImpl sailingService = null;
|
||||
|
||||
// Test-Data
|
||||
private final String TEST_LEADERBOARD_NAME = "test_board";
|
||||
private final String[] races = { "1", "2", "3" };
|
||||
private final boolean[] isMedalRace = { false, false, true };
|
||||
|
||||
@Before
|
||||
public void prepareColumnSwapping() {
|
||||
service = new SailingServiceImplMock();
|
||||
int[] disc = { 5, 8, 9, 0, 7, 5, 43 };
|
||||
service.removeLeaderboard(LEADERBOARDNAME);
|
||||
service.createFlexibleLeaderboard(LEADERBOARDNAME, null, disc, ScoringSchemeType.LOW_POINT, null);
|
||||
service.addColumnToLeaderboard("Race1", LEADERBOARDNAME, true);
|
||||
service.addColumnToLeaderboard("Race2", LEADERBOARDNAME, true);
|
||||
service.addColumnToLeaderboard("Race3", LEADERBOARDNAME, true);
|
||||
leglist = new ArrayList<String>();
|
||||
leglist.add("Race1");
|
||||
leglist.add("Race2");
|
||||
leglist.add("Race3");
|
||||
leaderboardCreationDate = new Date();
|
||||
try {
|
||||
// get Leaderboard with name and current date
|
||||
leaderboardOriginalDTO = new LeaderboardDTO(null, null, ScoringSchemeType.LOW_POINT, /* higherScoreIsBetter */ false, new LeaderboardDTO.UUIDGenerator() {
|
||||
@Override
|
||||
public String generateRandomUUID() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
}, /* hasOverallDetails */ false);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColumnSwapping() {
|
||||
testColumnSwappingFabian();
|
||||
testLeaderBoardDTOMethods();
|
||||
testSailingService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSailingService() {
|
||||
sailingService = new SailingServiceImplMock();
|
||||
assertNotNull("Sailingservice != NULL", sailingService);
|
||||
int td[] = { 5, 8 };
|
||||
sailingService.removeLeaderboard(TEST_LEADERBOARD_NAME);
|
||||
sailingService.createFlexibleLeaderboard(TEST_LEADERBOARD_NAME, null, td, ScoringSchemeType.LOW_POINT, null);
|
||||
for (int i = 0; i < races.length; i++)
|
||||
sailingService.addColumnToLeaderboard(races[i], TEST_LEADERBOARD_NAME, isMedalRace[i]);
|
||||
sailingService.moveLeaderboardColumnDown(TEST_LEADERBOARD_NAME, races[0]);
|
||||
sailingService.moveLeaderboardColumnDown(TEST_LEADERBOARD_NAME, races[0]);
|
||||
sailingService.moveLeaderboardColumnUp(TEST_LEADERBOARD_NAME, races[2]);
|
||||
sailingService.updateIsMedalRace(TEST_LEADERBOARD_NAME, races[0], true);
|
||||
sailingService.updateIsMedalRace(TEST_LEADERBOARD_NAME, races[2], false);
|
||||
try {
|
||||
for (int i = 0; i < races.length; i++)
|
||||
sailingService.addColumnToLeaderboard(races[i], TEST_LEADERBOARD_NAME, isMedalRace[i]);
|
||||
sailingService.moveLeaderboardColumnDown(TEST_LEADERBOARD_NAME, races[0]);
|
||||
sailingService.moveLeaderboardColumnDown(TEST_LEADERBOARD_NAME, races[0]);
|
||||
sailingService.moveLeaderboardColumnUp(TEST_LEADERBOARD_NAME, races[2]);
|
||||
sailingService.updateIsMedalRace(TEST_LEADERBOARD_NAME, races[0], true);
|
||||
sailingService.updateIsMedalRace(TEST_LEADERBOARD_NAME, races[2], false);
|
||||
lb = sailingService.getLeaderboardByName(TEST_LEADERBOARD_NAME, new Date(), /* races to load */ null, /* addOverallDetails */ true, /* previous leaderboard ID */ null,
|
||||
/* fillNetPointsUncorrected */ false).getLeaderboardDTO(/* previousVersion */ null);
|
||||
} catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
fail(e.getLocalizedMessage());
|
||||
}
|
||||
assertNotNull("LeaderboardDTO != NULL", lb);
|
||||
|
||||
// asserted data
|
||||
String[] raceNames = new String[] { "3", "2", "1" };
|
||||
boolean[] medalRace = { true, false, false };
|
||||
|
||||
for (int i = 0; i < lb.getRaceList().size(); i++) {
|
||||
assertEquals("Race[" + i + "] == " + raceNames[i], raceNames[i], lb.getRaceList().get(i).getName());
|
||||
assertTrue("Race[" + i + "] is " + (medalRace[i] ? "" : "no ") + "medalrace.",
|
||||
lb.raceIsMedalRace(races[i]) == medalRace[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLeaderBoardDTOMethods() {
|
||||
lb = new LeaderboardDTO(null, null, ScoringSchemeType.LOW_POINT, /* higherScoreIsBetter */ false, new LeaderboardDTO.UUIDGenerator() {
|
||||
@Override
|
||||
public String generateRandomUUID() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
}, /* hasOverallDetails */ false);
|
||||
assertNotNull("Leaderboard != NULL", lb);
|
||||
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++) {
|
||||
assertEquals("Race[" + i + "] = " + s[i], s[i], lb.getRaceList().get(i).getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColumnSwappingFabian() {
|
||||
service.moveLeaderboardColumnUp(LEADERBOARDNAME, "Race3");
|
||||
try {
|
||||
leaderboardDTO = service.getLeaderboardByName(LEADERBOARDNAME, leaderboardCreationDate, leglist, /* addOverallDetails */
|
||||
true, /* previous leaderboard ID */null, /* fillNetPointsUncorrected */false).getLeaderboardDTO(/* previousVersion */null);
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// check if leaderboardDTO an dleaderboardOriginalDTO same
|
||||
List<RaceColumnDTO> leaderboardList = leaderboardDTO.getRaceList();
|
||||
List<RaceColumnDTO> leaderboardOriginalList = leaderboardOriginalDTO.getRaceList();
|
||||
|
||||
// ??????? assert races in list
|
||||
assertArrayEquals(leaderboardList.toArray(), leaderboardOriginalList.toArray());
|
||||
|
||||
for (RaceColumnDTO raceDTO : leaderboardOriginalList) {
|
||||
assert leaderboardDTO.raceIsMedalRace(raceDTO.getRaceColumnName()) == leaderboardOriginalDTO.raceIsMedalRace(raceDTO.getRaceColumnName());
|
||||
assert leaderboardDTO.raceIsTracked(raceDTO.getRaceColumnName()) == leaderboardOriginalDTO.raceIsTracked(raceDTO.getRaceColumnName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ 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/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
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<listEntry value="com.sap.sailing.gwt.AutoPlay"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
|
||||
<listEntry value="com.sap.sailing.gwt.home.Home"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/>
|
||||
<listEntry value="com.sap.sailing.gwt.AutoPlay"/>
|
||||
</listAttribute>
|
||||
<booleanAttribute key="com.google.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/>
|
||||
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
|
||||
@@ -73,7 +73,7 @@
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -workDir "${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work" -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9876 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-superDevMode -incremental -workDir "${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work" -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9876 -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/EmbeddedMapAndWindChart com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/AutoPlay.html com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard com.sap.sailing.gwt.ui.EmbeddedMapAndWindChart"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1024m -Xmx3072m"/>
|
||||
</launchConfiguration>
|
||||
@@ -16,7 +16,7 @@
|
||||
<listEntry value="com.sap.sailing.gwt.AutoPlay"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/>
|
||||
<listEntry value="com.sap.sailing.gwt.home.Home"/>
|
||||
<listEntry value="com.sap.sailing.gwt.ui.VideoPopup"/>
|
||||
<listEntry value="com.sap.sailing.gwt.AutoPlay"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="com.google.gwt.eclipse.core.URL" value="/gwt/Home.html"/>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
@@ -70,7 +70,7 @@
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -incremental -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort auto -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-nosuperDevMode -incremental -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort auto -startupUrl /gwt/Home.html com.sap.sailing.gwt.home.Home -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.ui.AdminConsole -startupUrl /gwt/LeaderboardEditing.html com.sap.sailing.gwt.ui.LeaderboardEditing -startupUrl /gwt/Leaderboard.html com.sap.sailing.gwt.ui.Leaderboard -startupUrl /gwt/Spectator.html com.sap.sailing.gwt.ui.Spectator -startupUrl /gwt/RaceBoard.html com.sap.sailing.gwt.ui.RaceBoard -startupUrl /gwt/RegattaOverview.html com.sap.sailing.gwt.regattaoverview.RegattaOverview -startupUrl /gwt/DataMining.html com.sap.sailing.gwt.ui.DataMining -startupUrl /gwt/Simulator.html com.sap.sailing.gwt.ui.Simulator -startupUrl /gwt/VideoPopup.html com.sap.sailing.gwt.ui.VideoPopup -startupUrl /gwt/AutoPlay.html com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole com.sap.sailing.gwt.AutoPlay com.sap.sailing.gwt.ui.YoutubePopup com.sap.sailing.gwt.ui.Simulator com.sap.sailing.gwt.ui.Leaderboard com.sap.sailing.gwt.regattaoverview.RegattaOverview com.sap.sailing.gwt.ui.Spectator com.sap.sailing.gwt.ui.LeaderboardEditing com.sap.sailing.gwt.ui.DataMining com.sap.sailing.gwt.ui.RaceBoard"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx2048m -Dgwt-usearchives=false -Dgwt.persistentunitcache=false"/>
|
||||
</launchConfiguration>
|
||||
+4
-4
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+17
@@ -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);
|
||||
}
|
||||
}
|
||||
+5
@@ -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;
|
||||
|
||||
+1
@@ -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();
|
||||
|
||||
+3
@@ -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();
|
||||
}
|
||||
+15
-2
@@ -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) {
|
||||
@@ -217,8 +221,17 @@ 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();
|
||||
}
|
||||
|
||||
}
|
||||
+5
-3
@@ -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>
|
||||
|
||||
+32
-7
@@ -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,16 +50,18 @@ 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);
|
||||
}
|
||||
@@ -198,6 +206,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>{
|
||||
}
|
||||
|
||||
+8
-6
@@ -1,23 +1,25 @@
|
||||
<!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>
|
||||
<g:Anchor ui:field="fullscreenAnchor" href="javascript:;" styleName="{res.mainCss.button} {local_res.css.regattaleaderboard_meta_fullscreen_button}"></g:Anchor>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="{res.mediaCss.grid}">
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
-2
@@ -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;
|
||||
|
||||
+1
-1
@@ -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
|
||||
*/
|
||||
|
||||
+3
-2
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+7
-1
@@ -37,6 +37,7 @@ public class FullscreenContainer<T extends Widget> {
|
||||
String popup();
|
||||
String toolbarInfo();
|
||||
String toolbarAction();
|
||||
String toolbarBusyIndicator();
|
||||
String content();
|
||||
String contentBorder();
|
||||
}
|
||||
@@ -88,7 +89,12 @@ public class FullscreenContainer<T extends Widget> {
|
||||
widget.addStyleName(style.toolbarAction());
|
||||
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);
|
||||
|
||||
+7
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+4
-4
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+50
-21
@@ -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,7 +85,8 @@ 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) {
|
||||
super(sailingService, regattaRefresher, errorReporter, new RaceSelectionModel(), true, 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;
|
||||
}
|
||||
|
||||
@@ -462,6 +480,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>>(
|
||||
@@ -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) {
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+2
-1
@@ -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;
|
||||
|
||||
+5
-4
@@ -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,
|
||||
|
||||
+8
-2
@@ -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();
|
||||
@@ -1444,4 +1448,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();
|
||||
}
|
||||
+8
-2
@@ -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
|
||||
@@ -1410,4 +1414,6 @@ selectALeaderboardGroup=Select a leaderboard group...
|
||||
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}
|
||||
errorTryingToCreateEmbeddedMap=Error trying to create the embedded map: {0}
|
||||
transparentBufferLineOnHover=Transparent buffer lines on hover of helplines
|
||||
bufferLineStrokeWeight=Buffer line stroke weight
|
||||
+9
-3
@@ -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
|
||||
@@ -1401,4 +1405,6 @@ selectALeaderboardGroup=Bitte eine Ranglisten-Gruppe auswählen...
|
||||
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}
|
||||
errorTryingToCreateEmbeddedMap=Fehler beim Erstellen der eingebetteten Karte: {0}
|
||||
transparentBufferLineOnHover=Transparente Pufferlinien bei Maus über Hilfslinien
|
||||
bufferLineStrokeWeight=Linienbreite der Pufferlinien
|
||||
+8
-2
@@ -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} Узлы
|
||||
@@ -1340,4 +1344,6 @@ selectALeaderboardGroup=Select a leaderboard group...
|
||||
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}
|
||||
errorTryingToCreateEmbeddedMap=Error trying to create the embedded map: {0}
|
||||
transparentBufferLineOnHover=Transparent buffer lines on hover of helplines
|
||||
bufferLineStrokeWeight=Buffer line stroke weight
|
||||
+9
-3
@@ -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.
|
||||
@@ -844,7 +845,10 @@ 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 +1070,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}
|
||||
@@ -1355,4 +1359,6 @@ selectALeaderboardGroup=Select a leaderboard group...
|
||||
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}
|
||||
errorTryingToCreateEmbeddedMap=Error trying to create the embedded map: {0}
|
||||
transparentBufferLineOnHover=Transparent buffer lines on hover of helplines
|
||||
bufferLineStrokeWeight=Buffer line stroke weight
|
||||
+10
-2
@@ -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();
|
||||
|
||||
+3
-1
@@ -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());
|
||||
|
||||
+57
@@ -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);
|
||||
}
|
||||
}
|
||||
+2636
-2601
File diff suppressed because it is too large.
Load diff
+22
@@ -19,6 +19,10 @@ public class RaceMapSettings extends AbstractSettings {
|
||||
private RaceMapZoomSettings zoomSettings;
|
||||
|
||||
private RaceMapHelpLinesSettings helpLinesSettings;
|
||||
|
||||
private boolean transparentHoverlines = true;
|
||||
|
||||
private int hoverlineStrokeWeight = 10;
|
||||
|
||||
private long tailLengthInMilliseconds = 100000l;
|
||||
|
||||
@@ -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;
|
||||
@@ -153,6 +159,22 @@ public class RaceMapSettings extends AbstractSettings {
|
||||
public void setHelpLinesSettings(RaceMapHelpLinesSettings helpLinesSettings) {
|
||||
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;
|
||||
|
||||
+22
-2
@@ -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;
|
||||
}
|
||||
|
||||
+3
-2
@@ -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;
|
||||
|
||||
+4
-4
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
+3292
-3280
File diff suppressed because it is too large.
Load diff
+14
-10
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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(),
|
||||
|
||||
+37
-10
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -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);
|
||||
|
||||
}
|
||||
+11
@@ -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);
|
||||
}
|
||||
+11
-11
@@ -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>());
|
||||
|
||||
+2
-2
@@ -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()));
|
||||
}
|
||||
|
||||
+3
-3
@@ -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();
|
||||
}
|
||||
|
||||
+2
-1
@@ -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;
|
||||
}
|
||||
|
||||
+205
-197
@@ -1,197 +1,205 @@
|
||||
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.rpc.ServiceDefTarget;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.RootLayoutPanel;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
|
||||
import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel;
|
||||
import com.sap.sailing.gwt.ui.client.MediaService;
|
||||
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionModel;
|
||||
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider;
|
||||
import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceWithCompetitorsDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceboardDataDTO;
|
||||
import com.sap.sse.gwt.client.EntryPointHelper;
|
||||
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
|
||||
import com.sap.sse.gwt.client.player.Timer;
|
||||
import com.sap.sse.gwt.client.player.Timer.PlayModes;
|
||||
import com.sap.sse.gwt.shared.GwtHttpRequestUtils;
|
||||
|
||||
public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
|
||||
private RaceWithCompetitorsDTO selectedRace;
|
||||
|
||||
private static final String PARAM_REGATTA_NAME = "regattaName";
|
||||
private static final String PARAM_RACE_NAME = "raceName";
|
||||
private static final String PARAM_LEADERBOARD_NAME = "leaderboardName";
|
||||
private static final String PARAM_LEADERBOARD_GROUP_NAME = "leaderboardGroupName";
|
||||
private static final String PARAM_EVENT_ID = "eventId";
|
||||
|
||||
private String regattaName;
|
||||
private String raceName;
|
||||
private String leaderboardName;
|
||||
private String leaderboardGroupName;
|
||||
private UUID eventId;
|
||||
private RaceBoardViewConfiguration raceboardViewConfig;
|
||||
|
||||
private final MediaServiceAsync mediaService = GWT.create(MediaService.class);
|
||||
|
||||
@Override
|
||||
protected void doOnModuleLoad() {
|
||||
super.doOnModuleLoad();
|
||||
EntryPointHelper.registerASyncService((ServiceDefTarget) mediaService, RemoteServiceMappingConstants.mediaServiceRemotePath);
|
||||
// read mandatory parameters
|
||||
regattaName = Window.Location.getParameter(PARAM_REGATTA_NAME);
|
||||
raceName = Window.Location.getParameter(PARAM_RACE_NAME);
|
||||
String leaderboardNameParamValue = Window.Location.getParameter(PARAM_LEADERBOARD_NAME);
|
||||
String leaderboardGroupNameParamValue = Window.Location.getParameter(PARAM_LEADERBOARD_GROUP_NAME);
|
||||
if (leaderboardNameParamValue != null && !leaderboardNameParamValue.isEmpty()) {
|
||||
leaderboardName = leaderboardNameParamValue;
|
||||
}
|
||||
if (leaderboardGroupNameParamValue != null && !leaderboardGroupNameParamValue.isEmpty()) {
|
||||
leaderboardGroupName = leaderboardGroupNameParamValue;
|
||||
}
|
||||
String eventIdParamValue = Window.Location.getParameter(PARAM_EVENT_ID);
|
||||
if (eventIdParamValue != null && !eventIdParamValue.isEmpty()) {
|
||||
eventId = UUID.fromString(eventIdParamValue);
|
||||
}
|
||||
if (leaderboardGroupNameParamValue != null && !leaderboardGroupNameParamValue.isEmpty()) {
|
||||
leaderboardGroupName = leaderboardGroupNameParamValue;
|
||||
}
|
||||
if (regattaName == null || regattaName.isEmpty() || raceName == null || raceName.isEmpty() ||
|
||||
leaderboardName == null || leaderboardName.isEmpty()) {
|
||||
createErrorPage("This page requires a valid regatta name, race name and leaderboard name.");
|
||||
return;
|
||||
}
|
||||
|
||||
// read optional parameters
|
||||
boolean showLeaderboard = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_LEADERBOARD, true /* default*/);
|
||||
boolean showWindChart = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_WINDCHART, false /* default*/);
|
||||
boolean showCompetitorsChart = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_COMPETITORSCHART, false /* default*/);
|
||||
boolean showViewStreamlets = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_STREAMLETS, false /* default*/);
|
||||
boolean showViewStreamletColors = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_STREAMLET_COLORS, false /* default*/);
|
||||
boolean showViewSimulation = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_SIMULATION, true /* default*/);
|
||||
String activeCompetitorsFilterSetName = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_VIEW_COMPETITOR_FILTER, null /* default*/);
|
||||
final boolean canReplayWhileLiveIsPossible = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_CAN_REPLAY_DURING_LIVE_RACES, false);
|
||||
final boolean autoSelectMedia = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_AUTOSELECT_MEDIA, true);
|
||||
final String defaultMedia = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_DEFAULT_MEDIA, null /* default*/);
|
||||
final boolean showMapControls = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_MAPCONTROLS, true /* default*/);
|
||||
raceboardViewConfig = new RaceBoardViewConfiguration(activeCompetitorsFilterSetName, showLeaderboard,
|
||||
showWindChart, showCompetitorsChart, showViewStreamlets, showViewStreamletColors, showViewSimulation, canReplayWhileLiveIsPossible, autoSelectMedia, defaultMedia);
|
||||
|
||||
sailingService.getRaceboardData(regattaName, raceName, leaderboardName, leaderboardGroupName, eventId, new AsyncCallback<RaceboardDataDTO>() {
|
||||
@Override
|
||||
public void onSuccess(RaceboardDataDTO result) {
|
||||
checkUrlParameters(result, canReplayWhileLiveIsPossible, showMapControls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
reportError("Error trying to create the raceboard: " + caught.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createErrorPage(String message) {
|
||||
final DockLayoutPanel vp = new DockLayoutPanel(Unit.PX);
|
||||
LogoAndTitlePanel logoAndTitlePanel = new LogoAndTitlePanel(getStringMessages(), this, getUserService());
|
||||
logoAndTitlePanel.addStyleName("LogoAndTitlePanel");
|
||||
RootLayoutPanel.get().add(vp);
|
||||
vp.addNorth(logoAndTitlePanel, 100);
|
||||
vp.add(new Label(message));
|
||||
}
|
||||
|
||||
private void checkUrlParameters(RaceboardDataDTO raceboardData, boolean canReplayWhileLiveIsPossible, boolean showMapControls) {
|
||||
if (!raceboardData.isValidLeaderboard()) {
|
||||
createErrorPage(getStringMessages().noSuchLeaderboard());
|
||||
return;
|
||||
}
|
||||
if (eventId != null && !raceboardData.isValidEvent()) {
|
||||
createErrorPage(getStringMessages().noSuchEvent());
|
||||
}
|
||||
if (leaderboardGroupName != null) {
|
||||
if(!raceboardData.isValidLeaderboardGroup()) {
|
||||
createErrorPage(getStringMessages().leaderboardNotContainedInLeaderboardGroup(leaderboardName, leaderboardGroupName));
|
||||
return;
|
||||
}
|
||||
if (eventId != null && raceboardData.isValidLeaderboardGroup() && !raceboardData.isValidEvent()) {
|
||||
createErrorPage(getStringMessages().leaderboardGroupNotContainedInEvent(leaderboardGroupName, eventId.toString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (raceboardData.getRace() == null) {
|
||||
createErrorPage("Could not obtain a race with name " + raceName + " for a regatta with name " + regattaName);
|
||||
return;
|
||||
}
|
||||
selectedRace = raceboardData.getRace();
|
||||
Window.setTitle(selectedRace.getName());
|
||||
RaceSelectionModel raceSelectionModel = new RaceSelectionModel();
|
||||
List<RegattaAndRaceIdentifier> singletonList = Collections.singletonList(selectedRace.getRaceIdentifier());
|
||||
raceSelectionModel.setSelection(singletonList);
|
||||
Timer timer = new Timer(PlayModes.Replay, 1000l);
|
||||
AsyncActionsExecutor asyncActionsExecutor = new AsyncActionsExecutor();
|
||||
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);
|
||||
|
||||
createRaceBoardInOneScreenMode(raceBoardPanel, raceboardViewConfig);
|
||||
}
|
||||
|
||||
private FlowPanel createTimePanel(RaceBoardPanel raceBoardPanel) {
|
||||
FlowPanel timeLineInnerBgPanel = new FlowPanel();
|
||||
timeLineInnerBgPanel.addStyleName("timeLineInnerBgPanel");
|
||||
timeLineInnerBgPanel.add(raceBoardPanel.getTimePanel());
|
||||
|
||||
FlowPanel timeLineInnerPanel = new FlowPanel();
|
||||
timeLineInnerPanel.add(timeLineInnerBgPanel);
|
||||
timeLineInnerPanel.addStyleName("timeLineInnerPanel");
|
||||
|
||||
FlowPanel timelinePanel = new FlowPanel();
|
||||
timelinePanel.add(timeLineInnerPanel);
|
||||
timelinePanel.addStyleName("timeLinePanel");
|
||||
|
||||
return timelinePanel;
|
||||
}
|
||||
|
||||
private void createRaceBoardInOneScreenMode(final RaceBoardPanel raceBoardPanel,
|
||||
RaceBoardViewConfiguration raceboardViewConfiguration) {
|
||||
final DockLayoutPanel p = new DockLayoutPanel(Unit.PX);
|
||||
RootLayoutPanel.get().add(p);
|
||||
final FlowPanel timePanel = createTimePanel(raceBoardPanel);
|
||||
final Button toggleButton = raceBoardPanel.getTimePanel().getAdvancedToggleButton();
|
||||
toggleButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
boolean advancedModeShown = raceBoardPanel.getTimePanel().toggleAdvancedMode();
|
||||
if (advancedModeShown) {
|
||||
p.setWidgetSize(timePanel, 96);
|
||||
toggleButton.removeStyleDependentName("Closed");
|
||||
toggleButton.addStyleDependentName("Open");
|
||||
} else {
|
||||
p.setWidgetSize(timePanel, 67);
|
||||
toggleButton.addStyleDependentName("Closed");
|
||||
toggleButton.removeStyleDependentName("Open");
|
||||
}
|
||||
}
|
||||
});
|
||||
p.addSouth(timePanel, 67);
|
||||
p.add(raceBoardPanel);
|
||||
p.addStyleName("dockLayoutPanel");
|
||||
}
|
||||
}
|
||||
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import java.util.Collections;
|
||||
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;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.rpc.ServiceDefTarget;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.RootLayoutPanel;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
|
||||
import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel;
|
||||
import com.sap.sailing.gwt.ui.client.MediaService;
|
||||
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionModel;
|
||||
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider;
|
||||
import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceWithCompetitorsDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceboardDataDTO;
|
||||
import com.sap.sse.gwt.client.EntryPointHelper;
|
||||
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
|
||||
import com.sap.sse.gwt.client.player.Timer;
|
||||
import com.sap.sse.gwt.client.player.Timer.PlayModes;
|
||||
import com.sap.sse.gwt.shared.GwtHttpRequestUtils;
|
||||
|
||||
public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
|
||||
private RaceWithCompetitorsDTO selectedRace;
|
||||
|
||||
private static final String PARAM_REGATTA_NAME = "regattaName";
|
||||
private static final String PARAM_RACE_NAME = "raceName";
|
||||
private static final String PARAM_LEADERBOARD_NAME = "leaderboardName";
|
||||
private static final String PARAM_LEADERBOARD_GROUP_NAME = "leaderboardGroupName";
|
||||
private static final String PARAM_EVENT_ID = "eventId";
|
||||
|
||||
private String regattaName;
|
||||
private String raceName;
|
||||
private String leaderboardName;
|
||||
private String leaderboardGroupName;
|
||||
private UUID eventId;
|
||||
private RaceBoardViewConfiguration raceboardViewConfig;
|
||||
|
||||
private final MediaServiceAsync mediaService = GWT.create(MediaService.class);
|
||||
|
||||
@Override
|
||||
protected void doOnModuleLoad() {
|
||||
super.doOnModuleLoad();
|
||||
EntryPointHelper.registerASyncService((ServiceDefTarget) mediaService, RemoteServiceMappingConstants.mediaServiceRemotePath);
|
||||
// read mandatory parameters
|
||||
regattaName = Window.Location.getParameter(PARAM_REGATTA_NAME);
|
||||
raceName = Window.Location.getParameter(PARAM_RACE_NAME);
|
||||
String leaderboardNameParamValue = Window.Location.getParameter(PARAM_LEADERBOARD_NAME);
|
||||
String leaderboardGroupNameParamValue = Window.Location.getParameter(PARAM_LEADERBOARD_GROUP_NAME);
|
||||
if (leaderboardNameParamValue != null && !leaderboardNameParamValue.isEmpty()) {
|
||||
leaderboardName = leaderboardNameParamValue;
|
||||
}
|
||||
if (leaderboardGroupNameParamValue != null && !leaderboardGroupNameParamValue.isEmpty()) {
|
||||
leaderboardGroupName = leaderboardGroupNameParamValue;
|
||||
}
|
||||
String eventIdParamValue = Window.Location.getParameter(PARAM_EVENT_ID);
|
||||
if (eventIdParamValue != null && !eventIdParamValue.isEmpty()) {
|
||||
eventId = UUID.fromString(eventIdParamValue);
|
||||
}
|
||||
if (leaderboardGroupNameParamValue != null && !leaderboardGroupNameParamValue.isEmpty()) {
|
||||
leaderboardGroupName = leaderboardGroupNameParamValue;
|
||||
}
|
||||
if (regattaName == null || regattaName.isEmpty() || raceName == null || raceName.isEmpty() ||
|
||||
leaderboardName == null || leaderboardName.isEmpty()) {
|
||||
createErrorPage("This page requires a valid regatta name, race name and leaderboard name.");
|
||||
return;
|
||||
}
|
||||
|
||||
// read optional parameters
|
||||
boolean showLeaderboard = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_LEADERBOARD, true /* default*/);
|
||||
boolean showWindChart = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_WINDCHART, false /* default*/);
|
||||
boolean showCompetitorsChart = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_COMPETITORSCHART, false /* default*/);
|
||||
boolean showViewStreamlets = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_STREAMLETS, false /* default*/);
|
||||
boolean showViewStreamletColors = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_STREAMLET_COLORS, false /* default*/);
|
||||
boolean showViewSimulation = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_SIMULATION, true /* default*/);
|
||||
String activeCompetitorsFilterSetName = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_VIEW_COMPETITOR_FILTER, null /* default*/);
|
||||
final boolean canReplayWhileLiveIsPossible = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_CAN_REPLAY_DURING_LIVE_RACES, false);
|
||||
final boolean autoSelectMedia = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_AUTOSELECT_MEDIA, true);
|
||||
final String defaultMedia = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_DEFAULT_MEDIA, null /* default*/);
|
||||
final boolean showMapControls = GwtHttpRequestUtils.getBooleanParameter(RaceBoardViewConfiguration.PARAM_VIEW_SHOW_MAPCONTROLS, true /* default*/);
|
||||
raceboardViewConfig = new RaceBoardViewConfiguration(activeCompetitorsFilterSetName, showLeaderboard,
|
||||
showWindChart, showCompetitorsChart, showViewStreamlets, showViewStreamletColors, showViewSimulation, canReplayWhileLiveIsPossible, autoSelectMedia, defaultMedia);
|
||||
|
||||
sailingService.getRaceboardData(regattaName, raceName, leaderboardName, leaderboardGroupName, eventId, new AsyncCallback<RaceboardDataDTO>() {
|
||||
@Override
|
||||
public void onSuccess(RaceboardDataDTO result) {
|
||||
// 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
|
||||
public void onFailure(Throwable caught) {
|
||||
reportError("Error trying to create the raceboard: " + caught.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createErrorPage(String message) {
|
||||
final DockLayoutPanel vp = new DockLayoutPanel(Unit.PX);
|
||||
LogoAndTitlePanel logoAndTitlePanel = new LogoAndTitlePanel(getStringMessages(), this, getUserService());
|
||||
logoAndTitlePanel.addStyleName("LogoAndTitlePanel");
|
||||
RootLayoutPanel.get().add(vp);
|
||||
vp.addNorth(logoAndTitlePanel, 100);
|
||||
vp.add(new Label(message));
|
||||
}
|
||||
|
||||
private void checkUrlParameters(RaceboardDataDTO raceboardData, boolean canReplayWhileLiveIsPossible, boolean showMapControls,
|
||||
boolean isScreenLargeEnoughToOfferChartSupport) {
|
||||
if (!raceboardData.isValidLeaderboard()) {
|
||||
createErrorPage(getStringMessages().noSuchLeaderboard());
|
||||
return;
|
||||
}
|
||||
if (eventId != null && !raceboardData.isValidEvent()) {
|
||||
createErrorPage(getStringMessages().noSuchEvent());
|
||||
}
|
||||
if (leaderboardGroupName != null) {
|
||||
if(!raceboardData.isValidLeaderboardGroup()) {
|
||||
createErrorPage(getStringMessages().leaderboardNotContainedInLeaderboardGroup(leaderboardName, leaderboardGroupName));
|
||||
return;
|
||||
}
|
||||
if (eventId != null && raceboardData.isValidLeaderboardGroup() && !raceboardData.isValidEvent()) {
|
||||
createErrorPage(getStringMessages().leaderboardGroupNotContainedInEvent(leaderboardGroupName, eventId.toString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (raceboardData.getRace() == null) {
|
||||
createErrorPage("Could not obtain a race with name " + raceName + " for a regatta with name " + regattaName);
|
||||
return;
|
||||
}
|
||||
selectedRace = raceboardData.getRace();
|
||||
Window.setTitle(selectedRace.getName());
|
||||
RaceSelectionModel raceSelectionModel = new RaceSelectionModel();
|
||||
List<RegattaAndRaceIdentifier> singletonList = Collections.singletonList(selectedRace.getRaceIdentifier());
|
||||
raceSelectionModel.setSelection(singletonList);
|
||||
Timer timer = new Timer(PlayModes.Replay, 1000l);
|
||||
AsyncActionsExecutor asyncActionsExecutor = new AsyncActionsExecutor();
|
||||
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,
|
||||
isScreenLargeEnoughToOfferChartSupport);
|
||||
|
||||
createRaceBoardInOneScreenMode(raceBoardPanel, raceboardViewConfig);
|
||||
}
|
||||
|
||||
private FlowPanel createTimePanel(RaceBoardPanel raceBoardPanel) {
|
||||
FlowPanel timeLineInnerBgPanel = new ResizableFlowPanel();
|
||||
timeLineInnerBgPanel.addStyleName("timeLineInnerBgPanel");
|
||||
timeLineInnerBgPanel.add(raceBoardPanel.getTimePanel());
|
||||
|
||||
FlowPanel timeLineInnerPanel = new ResizableFlowPanel();
|
||||
timeLineInnerPanel.add(timeLineInnerBgPanel);
|
||||
timeLineInnerPanel.addStyleName("timeLineInnerPanel");
|
||||
|
||||
FlowPanel timelinePanel = new ResizableFlowPanel();
|
||||
timelinePanel.add(timeLineInnerPanel);
|
||||
timelinePanel.addStyleName("timeLinePanel");
|
||||
|
||||
return timelinePanel;
|
||||
}
|
||||
|
||||
private void createRaceBoardInOneScreenMode(final RaceBoardPanel raceBoardPanel,
|
||||
RaceBoardViewConfiguration raceboardViewConfiguration) {
|
||||
final DockLayoutPanel p = new DockLayoutPanel(Unit.PX);
|
||||
RootLayoutPanel.get().add(p);
|
||||
final FlowPanel timePanel = createTimePanel(raceBoardPanel);
|
||||
final Button toggleButton = raceBoardPanel.getTimePanel().getAdvancedToggleButton();
|
||||
toggleButton.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
boolean advancedModeShown = raceBoardPanel.getTimePanel().toggleAdvancedMode();
|
||||
if (advancedModeShown) {
|
||||
p.setWidgetSize(timePanel, 96);
|
||||
toggleButton.removeStyleDependentName("Closed");
|
||||
toggleButton.addStyleDependentName("Open");
|
||||
} else {
|
||||
p.setWidgetSize(timePanel, 67);
|
||||
toggleButton.addStyleDependentName("Closed");
|
||||
toggleButton.removeStyleDependentName("Open");
|
||||
}
|
||||
}
|
||||
});
|
||||
p.addSouth(timePanel, 67);
|
||||
p.add(raceBoardPanel);
|
||||
p.addStyleName("dockLayoutPanel");
|
||||
}
|
||||
}
|
||||
+483
-437
@@ -1,437 +1,483 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.shared.GWT;
|
||||
import com.google.gwt.dom.client.Document;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
import com.google.gwt.user.client.Command;
|
||||
import com.google.gwt.user.client.Window;
|
||||
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.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.UIObject;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.dto.BoatDTO;
|
||||
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.RaceColumnDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorColorProvider;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorColorProviderImpl;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionProvider;
|
||||
import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory;
|
||||
import com.sap.sailing.gwt.ui.client.GlobalNavigationPanel;
|
||||
import com.sap.sailing.gwt.ui.client.LeaderboardUpdateListener;
|
||||
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
|
||||
import com.sap.sailing.gwt.ui.client.RaceTimePanel;
|
||||
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.media.MediaPlayerManagerComponent;
|
||||
import com.sap.sailing.gwt.ui.client.media.PopupPositionProvider;
|
||||
import com.sap.sailing.gwt.ui.client.shared.charts.EditMarkPassingsPanel;
|
||||
import com.sap.sailing.gwt.ui.client.shared.charts.MultiCompetitorRaceChart;
|
||||
import com.sap.sailing.gwt.ui.client.shared.charts.WindChart;
|
||||
import com.sap.sailing.gwt.ui.client.shared.charts.WindChartSettings;
|
||||
import com.sap.sailing.gwt.ui.client.shared.filter.FilterWithUI;
|
||||
import com.sap.sailing.gwt.ui.client.shared.filter.LeaderboardFetcher;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMap;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapResources;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.CompetitorFilterPanel;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.ExplicitRaceColumnSelectionWithPreselectedRace;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettings;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettingsFactory;
|
||||
import com.sap.sse.common.filter.FilterSet;
|
||||
import com.sap.sse.common.settings.AbstractSettings;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.URLEncoder;
|
||||
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
|
||||
import com.sap.sse.gwt.client.player.TimeRangeWithZoomModel;
|
||||
import com.sap.sse.gwt.client.player.Timer;
|
||||
import com.sap.sse.gwt.client.shared.components.Component;
|
||||
import com.sap.sse.gwt.client.shared.components.ComponentViewer;
|
||||
import com.sap.sse.gwt.client.shared.components.SettingsDialog;
|
||||
import com.sap.sse.gwt.client.useragent.UserAgentDetails;
|
||||
import com.sap.sse.security.ui.client.UserService;
|
||||
|
||||
/**
|
||||
* A view showing a list of components visualizing a race from the regattas announced by calls to {@link #fillRegattas(List)}.
|
||||
* The race selection is provided by a {@link RaceSelectionProvider} for which this is a {@link RaceSelectionChangeListener listener}.
|
||||
* {@link RaceIdentifier}-based race selection changes are converted to {@link RaceDTO} objects using the {@link #racesByIdentifier}
|
||||
* map maintained during {@link #fillRegattas(List)}. The race selection provider is expected to be single selection only.
|
||||
*
|
||||
* @author Frank Mittag, Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeListener, LeaderboardUpdateListener, PopupPositionProvider {
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final MediaServiceAsync mediaService;
|
||||
private final UUID eventId;
|
||||
private final StringMessages stringMessages;
|
||||
private final ErrorReporter errorReporter;
|
||||
private final RaceBoardViewConfiguration raceboardViewConfiguration;
|
||||
private String raceBoardName;
|
||||
|
||||
private final List<ComponentViewer> componentViewers;
|
||||
private RaceTimePanel timePanel;
|
||||
private final Timer timer;
|
||||
private final RaceSelectionProvider raceSelectionProvider;
|
||||
private final UserAgentDetails userAgent;
|
||||
private final CompetitorSelectionProvider competitorSelectionProvider;
|
||||
private final TimeRangeWithZoomModel timeRangeWithZoomModel;
|
||||
private final RegattaAndRaceIdentifier selectedRaceIdentifier;
|
||||
|
||||
private final String leaderboardName;
|
||||
private final LeaderboardPanel leaderboardPanel;
|
||||
private WindChart windChart;
|
||||
private MultiCompetitorRaceChart competitorChart;
|
||||
private EditMarkPassingsPanel editMarkPassingPanel;
|
||||
|
||||
/**
|
||||
* The component viewer in <code>ONESCREEN</code> view mode. <code>null</code> if in <code>CASCADE</code> view mode
|
||||
*/
|
||||
private SideBySideComponentViewer leaderboardAndMapViewer;
|
||||
|
||||
private final AsyncActionsExecutor asyncActionsExecutor;
|
||||
|
||||
private final RaceTimesInfoProvider raceTimesInfoProvider;
|
||||
private RaceMap raceMap;
|
||||
|
||||
private final FlowPanel raceInformationHeader;
|
||||
private final FlowPanel regattaAndRaceTimeInformationHeader;
|
||||
private boolean currentRaceHasBeenSelectedOnce;
|
||||
|
||||
private static final RaceMapResources raceMapResources = GWT.create(RaceMapResources.class);
|
||||
|
||||
/**
|
||||
* @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>.
|
||||
*/
|
||||
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) {
|
||||
this.sailingService = sailingService;
|
||||
this.mediaService = mediaService;
|
||||
this.stringMessages = stringMessages;
|
||||
this.raceboardViewConfiguration = raceboardViewConfiguration;
|
||||
this.raceSelectionProvider = theRaceSelectionProvider;
|
||||
this.raceTimesInfoProvider = raceTimesInfoProvider;
|
||||
this.errorReporter = errorReporter;
|
||||
this.userAgent = userAgent;
|
||||
this.timer = timer;
|
||||
this.eventId = eventId;
|
||||
this.currentRaceHasBeenSelectedOnce = false;
|
||||
this.leaderboardName = leaderboardName;
|
||||
raceSelectionProvider.addRaceSelectionChangeListener(this);
|
||||
selectedRaceIdentifier = raceSelectionProvider.getSelectedRaces().iterator().next();
|
||||
this.setRaceBoardName(selectedRaceIdentifier.getRaceName());
|
||||
this.asyncActionsExecutor = asyncActionsExecutor;
|
||||
FlowPanel mainPanel = new FlowPanel();
|
||||
mainPanel.setSize("100%", "100%");
|
||||
setWidget(mainPanel);
|
||||
raceInformationHeader = new FlowPanel();
|
||||
raceInformationHeader.setStyleName("RegattaRaceInformation-Header");
|
||||
regattaAndRaceTimeInformationHeader = new FlowPanel();
|
||||
regattaAndRaceTimeInformationHeader.setStyleName("RegattaAndRaceTime-Header");
|
||||
timeRangeWithZoomModel = new TimeRangeWithZoomModel();
|
||||
componentViewers = new ArrayList<ComponentViewer>();
|
||||
final CompetitorColorProvider colorProvider = new CompetitorColorProviderImpl(selectedRaceIdentifier, competitorsAndTheirBoats);
|
||||
competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */ true, colorProvider);
|
||||
|
||||
raceMapResources.combinedWindPanelStyle().ensureInjected();
|
||||
raceMap = new RaceMap(sailingService, asyncActionsExecutor, errorReporter, timer,
|
||||
competitorSelectionProvider, stringMessages, showMapControls, getConfiguration().isShowViewStreamlets(), getConfiguration().isShowViewStreamletColors(), getConfiguration().isShowViewSimulation(),
|
||||
selectedRaceIdentifier, raceMapResources.combinedWindPanelStyle(), /* showHeaderPanel */ true);
|
||||
CompetitorFilterPanel competitorSearchTextBox = new CompetitorFilterPanel(competitorSelectionProvider, stringMessages, raceMap,
|
||||
new LeaderboardFetcher() {
|
||||
@Override
|
||||
public LeaderboardDTO getLeaderboard() {
|
||||
return leaderboardPanel.getLeaderboard();
|
||||
}
|
||||
}, selectedRaceIdentifier);
|
||||
raceMap.getLeftHeaderPanel().add(raceInformationHeader);
|
||||
raceMap.getRightHeaderPanel().add(regattaAndRaceTimeInformationHeader);
|
||||
|
||||
leaderboardPanel = createLeaderboardPanel(leaderboardName, leaderboardGroupName, competitorSearchTextBox);
|
||||
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
|
||||
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
|
||||
if (raceboardViewConfiguration.getActiveCompetitorsFilterSetName() != null) {
|
||||
for (FilterSet<CompetitorDTO, FilterWithUI<CompetitorDTO>> filterSet : competitorSearchTextBox.getCompetitorsFilterSets()
|
||||
.getFilterSets()) {
|
||||
if (filterSet.getName().equals(raceboardViewConfiguration.getActiveCompetitorsFilterSetName())) {
|
||||
competitorSearchTextBox.getCompetitorsFilterSets().setActiveFilterSet(filterSet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
timePanel = new RaceTimePanel(timer, timeRangeWithZoomModel, stringMessages, raceTimesInfoProvider,
|
||||
raceboardViewConfiguration.isCanReplayDuringLiveRaces());
|
||||
timeRangeWithZoomModel.addTimeZoomChangeListener(timePanel);
|
||||
raceTimesInfoProvider.addRaceTimesInfoProviderListener(timePanel);
|
||||
raceSelectionProvider.addRaceSelectionChangeListener(timePanel);
|
||||
timePanel.onRaceSelectionChange(raceSelectionProvider.getSelectedRaces());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param event an optional event; may be <code>null</code> or else can be used to show some context information in
|
||||
* the {@link GlobalNavigationPanel}.
|
||||
*/
|
||||
private void createOneScreenView(String leaderboardName, String leaderboardGroupName, UUID event, FlowPanel mainPanel,
|
||||
boolean showMapControls, 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);
|
||||
boolean autoSelectMedia = getConfiguration().isAutoSelectMedia();
|
||||
MediaPlayerManagerComponent mediaPlayerManagerComponent = new MediaPlayerManagerComponent(
|
||||
selectedRaceIdentifier, raceTimesInfoProvider, timer, mediaService, userService, stringMessages,
|
||||
errorReporter, userAgent, this, autoSelectMedia);
|
||||
leaderboardAndMapViewer = new SideBySideComponentViewer(leaderboardPanel, raceMap, mediaPlayerManagerComponent, components, stringMessages, userService, editMarkPassingPanel);
|
||||
componentViewers.add(leaderboardAndMapViewer);
|
||||
for (ComponentViewer componentViewer : componentViewers) {
|
||||
mainPanel.add(componentViewer.getViewerWidget());
|
||||
}
|
||||
boolean showLeaderboard = getConfiguration().isShowLeaderboard();
|
||||
if (Document.get().getClientWidth() <= 1024) {
|
||||
showLeaderboard = false;
|
||||
}
|
||||
setLeaderboardVisible(showLeaderboard);
|
||||
setWindChartVisible(getConfiguration().isShowWindChart());
|
||||
setCompetitorChartVisible(getConfiguration().isShowCompetitorsChart());
|
||||
// make sure to load leaderboard data for filtering to work
|
||||
if (!showLeaderboard) {
|
||||
leaderboardPanel.setVisible(true);
|
||||
leaderboardPanel.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private <SettingsType extends AbstractSettings> void addSettingsMenuItem(MenuBar settingsMenu, final Component<SettingsType> component) {
|
||||
if (component.hasSettings()) {
|
||||
settingsMenu.addItem(component.getLocalizedShortName(), new Command() {
|
||||
public void execute() {
|
||||
new SettingsDialog<SettingsType>(component, stringMessages).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private LeaderboardPanel createLeaderboardPanel(String leaderboardName, String leaderboardGroupName, CompetitorFilterPanel competitorSearchTextBox) {
|
||||
LeaderboardSettings leaderBoardSettings = LeaderboardSettingsFactory.getInstance()
|
||||
.createNewSettingsForPlayMode(timer.getPlayMode(),
|
||||
/* nameOfRaceToSort */ selectedRaceIdentifier.getRaceName(),
|
||||
/* nameOfRaceColumnToShow */ null, /* nameOfRaceToShow */ selectedRaceIdentifier.getRaceName(),
|
||||
new ExplicitRaceColumnSelectionWithPreselectedRace(selectedRaceIdentifier), /* showRegattaRank */ false,
|
||||
/*showCompetitorSailIdColumn*/true, /*showCompetitorFullNameColumn*/true);
|
||||
return new LeaderboardPanel(sailingService, asyncActionsExecutor, leaderBoardSettings, selectedRaceIdentifier != null, selectedRaceIdentifier,
|
||||
competitorSelectionProvider, timer, leaderboardGroupName, leaderboardName, errorReporter, stringMessages,
|
||||
userAgent, /* showRaceDetails */ true, competitorSearchTextBox,
|
||||
/* showSelectionCheckbox */ true, raceTimesInfoProvider, /* autoExpandLastRaceColumn */ false,
|
||||
/* don't adjust the timer's delay from the leaderboard; control it solely from the RaceTimesInfoProvider */ false,
|
||||
/*autoApplyTopNFilter*/ false, /*showCompetitorFilterStatus*/ false);
|
||||
}
|
||||
|
||||
private void setComponentVisible(ComponentViewer componentViewer, Component<?> component, boolean visible) {
|
||||
component.setVisible(visible);
|
||||
componentViewer.forceLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the collapsable panel for the leaderboard open or close, if in <code>CASCADE</code> view mode.<br />
|
||||
* Displays or hides the leaderboard, if in <code>ONESCREEN</code> view mode.<br /><br />
|
||||
*
|
||||
* The race board should be completely rendered before this method is called, or a few exceptions could be thrown.
|
||||
*
|
||||
* @param visible <code>true</code> if the leaderboard shall be open/visible
|
||||
*/
|
||||
public void setLeaderboardVisible(boolean visible) {
|
||||
setComponentVisible(leaderboardAndMapViewer, leaderboardPanel, visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the collapsable panel for the wind chart open or close, if in <code>CASCADE</code> view mode.<br />
|
||||
* Displays or hides the wind chart, if in <code>ONESCREEN</code> view mode.<br /><br />
|
||||
*
|
||||
* The race board should be completely rendered before this method is called, or a few exceptions could be thrown.
|
||||
*
|
||||
* @param visible <code>true</code> if the wind chart shall be open/visible
|
||||
*/
|
||||
public void setWindChartVisible(boolean visible) {
|
||||
setComponentVisible(leaderboardAndMapViewer, windChart, visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the collapsable panel for the competitor chart open or close, if in <code>CASCADE</code> view mode.<br />
|
||||
* Displays or hides the competitor chart, if in <code>ONESCREEN</code> view mode.<br /><br />
|
||||
*
|
||||
* The race board should be completely rendered before this method is called, or a few exceptions could be thrown.
|
||||
*
|
||||
* @param visible <code>true</code> if the competitor chart shall be open/visible
|
||||
*/
|
||||
public void setCompetitorChartVisible(boolean visible) {
|
||||
setComponentVisible(leaderboardAndMapViewer, competitorChart, visible);
|
||||
}
|
||||
|
||||
public RaceTimePanel getTimePanel() {
|
||||
return timePanel;
|
||||
}
|
||||
|
||||
protected SailingServiceAsync getSailingService() {
|
||||
return sailingService;
|
||||
}
|
||||
|
||||
protected String getRaceBoardName() {
|
||||
return raceBoardName;
|
||||
}
|
||||
|
||||
protected void setRaceBoardName(String raceBoardName) {
|
||||
this.raceBoardName = raceBoardName;
|
||||
}
|
||||
|
||||
protected ErrorReporter getErrorReporter() {
|
||||
return errorReporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRaceSelectionChange(List<RegattaAndRaceIdentifier> selectedRaces) {
|
||||
}
|
||||
|
||||
public RaceBoardViewConfiguration getConfiguration() {
|
||||
return raceboardViewConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatedLeaderboard(LeaderboardDTO leaderboard) {
|
||||
leaderboardAndMapViewer.setLeftComponentWidth(leaderboardPanel.getContentPanel().getOffsetWidth());
|
||||
editMarkPassingPanel.setLeaderboard(leaderboard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void currentRaceSelected(RaceIdentifier raceIdentifier, RaceColumnDTO raceColumn) {
|
||||
if (!currentRaceHasBeenSelectedOnce) {
|
||||
FleetDTO fleet = raceColumn.getFleet(raceIdentifier);
|
||||
String seriesName = raceColumn.getSeriesName();
|
||||
if (LeaderboardNameConstants.DEFAULT_SERIES_NAME.equals(seriesName)) {
|
||||
seriesName = "";
|
||||
}
|
||||
String fleetForRaceName = fleet==null?"":fleet.getName();
|
||||
if (fleetForRaceName.equals(LeaderboardNameConstants.DEFAULT_FLEET_NAME)) {
|
||||
fleetForRaceName = "";
|
||||
} else {
|
||||
fleetForRaceName = " - "+fleetForRaceName;
|
||||
}
|
||||
final Label raceNameLabel = new Label(stringMessages.race() + " " + raceColumn.getRaceColumnName());
|
||||
raceNameLabel.setStyleName("RaceName-Label");
|
||||
final Label raceAdditionalInformationLabel = new Label(seriesName + fleetForRaceName);
|
||||
raceAdditionalInformationLabel.setStyleName("RaceSeriesAndFleet-Label");
|
||||
raceInformationHeader.clear();
|
||||
raceInformationHeader.add(raceNameLabel);
|
||||
raceInformationHeader.add(raceAdditionalInformationLabel);
|
||||
final Anchor regattaNameAnchor = new Anchor(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");
|
||||
String link = "/gwt/Home.html";
|
||||
if (debugParam != null && !debugParam.isEmpty()) {
|
||||
link += "?gwt.codesvr=" + debugParam;
|
||||
}
|
||||
link += "#EventPlace:eventId="+eventId.toString();
|
||||
link += "&navigationTab=Regatta&leaderboardName=" + URLEncoder.encode(leaderboardName);
|
||||
regattaNameAnchor.setHref(link);
|
||||
} else {
|
||||
String leaderboardGroupNameParam = Window.Location.getParameter("leaderboardGroupName");
|
||||
if(leaderboardGroupNameParam != null) {
|
||||
Map<String, String> leaderboardGroupLinkParameters = new HashMap<String, String>();
|
||||
leaderboardGroupLinkParameters.put("showRaceDetails", "true");
|
||||
leaderboardGroupLinkParameters.put("leaderboardGroupName", leaderboardGroupNameParam);
|
||||
String leaderBoardGroupLink = EntryPointLinkFactory.createLeaderboardGroupLink(leaderboardGroupLinkParameters);
|
||||
regattaNameAnchor.setHref(leaderBoardGroupLink);
|
||||
} else {
|
||||
// fallback
|
||||
regattaNameAnchor.setHref("javascript:window.history.back();");
|
||||
}
|
||||
}
|
||||
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();
|
||||
regattaAndRaceTimeInformationHeader.add(regattaNameAnchor);
|
||||
regattaAndRaceTimeInformationHeader.add(raceTimeLabel);
|
||||
currentRaceHasBeenSelectedOnce = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UIObject getXPositionUiObject() {
|
||||
return timePanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UIObject getYPositionUiObject() {
|
||||
return timePanel;
|
||||
}
|
||||
|
||||
private Label computeRaceInformation(RaceColumnDTO raceColumn, FleetDTO fleet) {
|
||||
Label raceInformationLabel = new Label();
|
||||
raceInformationLabel.setStyleName("Race-Time-Label");
|
||||
DateTimeFormat formatter = DateTimeFormat.getFormat("E d/M/y");
|
||||
raceInformationLabel.setText(formatter.format(raceColumn.getStartDate(fleet)));
|
||||
return raceInformationLabel;
|
||||
}
|
||||
}
|
||||
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
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;
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
import com.google.gwt.user.client.Command;
|
||||
import com.google.gwt.user.client.Window;
|
||||
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;
|
||||
import com.sap.sailing.domain.common.dto.BoatDTO;
|
||||
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.RaceColumnDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceDTO;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorColorProvider;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorColorProviderImpl;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
|
||||
import com.sap.sailing.gwt.ui.client.CompetitorSelectionProvider;
|
||||
import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory;
|
||||
import com.sap.sailing.gwt.ui.client.GlobalNavigationPanel;
|
||||
import com.sap.sailing.gwt.ui.client.LeaderboardUpdateListener;
|
||||
import com.sap.sailing.gwt.ui.client.MediaServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionChangeListener;
|
||||
import com.sap.sailing.gwt.ui.client.RaceSelectionProvider;
|
||||
import com.sap.sailing.gwt.ui.client.RaceTimePanel;
|
||||
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider;
|
||||
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.media.MediaPlayerManagerComponent;
|
||||
import com.sap.sailing.gwt.ui.client.media.PopupPositionProvider;
|
||||
import com.sap.sailing.gwt.ui.client.shared.charts.EditMarkPassingsPanel;
|
||||
import com.sap.sailing.gwt.ui.client.shared.charts.MultiCompetitorRaceChart;
|
||||
import com.sap.sailing.gwt.ui.client.shared.charts.WindChart;
|
||||
import com.sap.sailing.gwt.ui.client.shared.charts.WindChartSettings;
|
||||
import com.sap.sailing.gwt.ui.client.shared.filter.FilterWithUI;
|
||||
import com.sap.sailing.gwt.ui.client.shared.filter.LeaderboardFetcher;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMap;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapResources;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.CompetitorFilterPanel;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.ExplicitRaceColumnSelectionWithPreselectedRace;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettings;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardSettingsFactory;
|
||||
import com.sap.sse.common.filter.FilterSet;
|
||||
import com.sap.sse.common.settings.AbstractSettings;
|
||||
import com.sap.sse.gwt.client.ErrorReporter;
|
||||
import com.sap.sse.gwt.client.URLEncoder;
|
||||
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
|
||||
import com.sap.sse.gwt.client.player.TimeRangeWithZoomModel;
|
||||
import com.sap.sse.gwt.client.player.Timer;
|
||||
import com.sap.sse.gwt.client.shared.components.Component;
|
||||
import com.sap.sse.gwt.client.shared.components.ComponentViewer;
|
||||
import com.sap.sse.gwt.client.shared.components.SettingsDialog;
|
||||
import com.sap.sse.gwt.client.useragent.UserAgentDetails;
|
||||
import com.sap.sse.security.ui.client.UserService;
|
||||
|
||||
/**
|
||||
* A view showing a list of components visualizing a race from the regattas announced by calls to {@link #fillRegattas(List)}.
|
||||
* The race selection is provided by a {@link RaceSelectionProvider} for which this is a {@link RaceSelectionChangeListener listener}.
|
||||
* {@link RaceIdentifier}-based race selection changes are converted to {@link RaceDTO} objects using the {@link #racesByIdentifier}
|
||||
* map maintained during {@link #fillRegattas(List)}. The race selection provider is expected to be single selection only.
|
||||
*
|
||||
* @author Frank Mittag, Axel Uhl (d043530)
|
||||
*
|
||||
*/
|
||||
public class RaceBoardPanel extends SimplePanel implements RaceSelectionChangeListener,
|
||||
LeaderboardUpdateListener, PopupPositionProvider, RequiresResize {
|
||||
private final SailingServiceAsync sailingService;
|
||||
private final MediaServiceAsync mediaService;
|
||||
private final UUID eventId;
|
||||
private final StringMessages stringMessages;
|
||||
private final ErrorReporter errorReporter;
|
||||
private final RaceBoardViewConfiguration raceboardViewConfiguration;
|
||||
private String raceBoardName;
|
||||
|
||||
private final List<ComponentViewer> componentViewers;
|
||||
private RaceTimePanel timePanel;
|
||||
private final Timer timer;
|
||||
private final RaceSelectionProvider raceSelectionProvider;
|
||||
private final UserAgentDetails userAgent;
|
||||
private final CompetitorSelectionProvider competitorSelectionProvider;
|
||||
private final TimeRangeWithZoomModel timeRangeWithZoomModel;
|
||||
private final RegattaAndRaceIdentifier selectedRaceIdentifier;
|
||||
|
||||
private final String leaderboardName;
|
||||
private final LeaderboardPanel leaderboardPanel;
|
||||
private WindChart windChart;
|
||||
private MultiCompetitorRaceChart competitorChart;
|
||||
private EditMarkPassingsPanel editMarkPassingPanel;
|
||||
|
||||
/**
|
||||
* The component viewer in <code>ONESCREEN</code> view mode. <code>null</code> if in <code>CASCADE</code> view mode
|
||||
*/
|
||||
private SideBySideComponentViewer leaderboardAndMapViewer;
|
||||
|
||||
private final AsyncActionsExecutor asyncActionsExecutor;
|
||||
|
||||
private final RaceTimesInfoProvider raceTimesInfoProvider;
|
||||
private RaceMap raceMap;
|
||||
|
||||
private final FlowPanel raceInformationHeader;
|
||||
private final FlowPanel regattaAndRaceTimeInformationHeader;
|
||||
private boolean currentRaceHasBeenSelectedOnce;
|
||||
|
||||
private static final RaceMapResources raceMapResources = GWT.create(RaceMapResources.class);
|
||||
|
||||
/**
|
||||
* @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, boolean isScreenLargeEnoughToOfferChartSupport) {
|
||||
this.sailingService = sailingService;
|
||||
this.mediaService = mediaService;
|
||||
this.stringMessages = stringMessages;
|
||||
this.raceboardViewConfiguration = raceboardViewConfiguration;
|
||||
this.raceSelectionProvider = theRaceSelectionProvider;
|
||||
this.raceTimesInfoProvider = raceTimesInfoProvider;
|
||||
this.errorReporter = errorReporter;
|
||||
this.userAgent = userAgent;
|
||||
this.timer = timer;
|
||||
this.eventId = eventId;
|
||||
this.currentRaceHasBeenSelectedOnce = false;
|
||||
this.leaderboardName = leaderboardName;
|
||||
raceSelectionProvider.addRaceSelectionChangeListener(this);
|
||||
selectedRaceIdentifier = raceSelectionProvider.getSelectedRaces().iterator().next();
|
||||
this.setRaceBoardName(selectedRaceIdentifier.getRaceName());
|
||||
this.asyncActionsExecutor = asyncActionsExecutor;
|
||||
FlowPanel mainPanel = new ResizableFlowPanel();
|
||||
mainPanel.setSize("100%", "100%");
|
||||
setWidget(mainPanel);
|
||||
raceInformationHeader = new FlowPanel();
|
||||
raceInformationHeader.setStyleName("RegattaRaceInformation-Header");
|
||||
regattaAndRaceTimeInformationHeader = new FlowPanel();
|
||||
regattaAndRaceTimeInformationHeader.setStyleName("RegattaAndRaceTime-Header");
|
||||
timeRangeWithZoomModel = new TimeRangeWithZoomModel();
|
||||
componentViewers = new ArrayList<ComponentViewer>();
|
||||
final CompetitorColorProvider colorProvider = new CompetitorColorProviderImpl(selectedRaceIdentifier, competitorsAndTheirBoats);
|
||||
competitorSelectionProvider = new CompetitorSelectionModel(/* hasMultiSelection */ true, colorProvider);
|
||||
|
||||
raceMapResources.combinedWindPanelStyle().ensureInjected();
|
||||
raceMap = new RaceMap(sailingService, asyncActionsExecutor, errorReporter, timer,
|
||||
competitorSelectionProvider, stringMessages, showMapControls, getConfiguration().isShowViewStreamlets(), getConfiguration().isShowViewStreamletColors(), getConfiguration().isShowViewSimulation(),
|
||||
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
|
||||
public LeaderboardDTO getLeaderboard() {
|
||||
return leaderboardPanel.getLeaderboard();
|
||||
}
|
||||
}, selectedRaceIdentifier);
|
||||
raceMap.getLeftHeaderPanel().add(raceInformationHeader);
|
||||
raceMap.getRightHeaderPanel().add(regattaAndRaceTimeInformationHeader);
|
||||
|
||||
// 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, 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
|
||||
if (raceboardViewConfiguration.getActiveCompetitorsFilterSetName() != null) {
|
||||
for (FilterSet<CompetitorDTO, FilterWithUI<CompetitorDTO>> filterSet : competitorSearchTextBox.getCompetitorsFilterSets()
|
||||
.getFilterSets()) {
|
||||
if (filterSet.getName().equals(raceboardViewConfiguration.getActiveCompetitorsFilterSetName())) {
|
||||
competitorSearchTextBox.getCompetitorsFilterSets().setActiveFilterSet(filterSet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
timePanel = new RaceTimePanel(timer, timeRangeWithZoomModel, stringMessages, raceTimesInfoProvider,
|
||||
raceboardViewConfiguration.isCanReplayDuringLiveRaces(), isScreenLargeEnoughToOfferChartSupport);
|
||||
timeRangeWithZoomModel.addTimeZoomChangeListener(timePanel);
|
||||
raceTimesInfoProvider.addRaceTimesInfoProviderListener(timePanel);
|
||||
raceSelectionProvider.addRaceSelectionChangeListener(timePanel);
|
||||
timePanel.onRaceSelectionChange(raceSelectionProvider.getSelectedRaces());
|
||||
}
|
||||
|
||||
/**
|
||||
* @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, 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<?>>();
|
||||
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,
|
||||
errorReporter, userAgent, this, autoSelectMedia);
|
||||
leaderboardAndMapViewer = new SideBySideComponentViewer(leaderboardPanel, raceMap, mediaPlayerManagerComponent, components, stringMessages, userService, editMarkPassingPanel);
|
||||
componentViewers.add(leaderboardAndMapViewer);
|
||||
for (ComponentViewer componentViewer : componentViewers) {
|
||||
mainPanel.add(componentViewer.getViewerWidget());
|
||||
}
|
||||
boolean showLeaderboard = getConfiguration().isShowLeaderboard() && isScreenLargeEnoughToInitiallyDisplayLeaderboard;
|
||||
setLeaderboardVisible(showLeaderboard);
|
||||
if (isScreenLargeEnoughToOfferChartSupport) {
|
||||
setWindChartVisible(getConfiguration().isShowWindChart());
|
||||
setCompetitorChartVisible(getConfiguration().isShowCompetitorsChart());
|
||||
}
|
||||
// make sure to load leaderboard data for filtering to work
|
||||
if (!showLeaderboard) {
|
||||
leaderboardPanel.setVisible(true);
|
||||
leaderboardPanel.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private <SettingsType extends AbstractSettings> void addSettingsMenuItem(MenuBar settingsMenu, final Component<SettingsType> component) {
|
||||
if (component.hasSettings()) {
|
||||
settingsMenu.addItem(component.getLocalizedShortName(), new Command() {
|
||||
public void execute() {
|
||||
new SettingsDialog<SettingsType>(component, stringMessages).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
/* 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,
|
||||
/* showSelectionCheckbox */ true, raceTimesInfoProvider, /* autoExpandLastRaceColumn */ false,
|
||||
/* don't adjust the timer's delay from the leaderboard; control it solely from the RaceTimesInfoProvider */ false,
|
||||
/*autoApplyTopNFilter*/ false, /*showCompetitorFilterStatus*/ false);
|
||||
}
|
||||
|
||||
private void setComponentVisible(ComponentViewer componentViewer, Component<?> component, boolean visible) {
|
||||
component.setVisible(visible);
|
||||
componentViewer.forceLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the collapsable panel for the leaderboard open or close, if in <code>CASCADE</code> view mode.<br />
|
||||
* Displays or hides the leaderboard, if in <code>ONESCREEN</code> view mode.<br /><br />
|
||||
*
|
||||
* The race board should be completely rendered before this method is called, or a few exceptions could be thrown.
|
||||
*
|
||||
* @param visible <code>true</code> if the leaderboard shall be open/visible
|
||||
*/
|
||||
public void setLeaderboardVisible(boolean visible) {
|
||||
setComponentVisible(leaderboardAndMapViewer, leaderboardPanel, visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the collapsable panel for the wind chart open or close, if in <code>CASCADE</code> view mode.<br />
|
||||
* Displays or hides the wind chart, if in <code>ONESCREEN</code> view mode.<br /><br />
|
||||
*
|
||||
* The race board should be completely rendered before this method is called, or a few exceptions could be thrown.
|
||||
*
|
||||
* @param visible <code>true</code> if the wind chart shall be open/visible
|
||||
*/
|
||||
public void setWindChartVisible(boolean visible) {
|
||||
setComponentVisible(leaderboardAndMapViewer, windChart, visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the collapsable panel for the competitor chart open or close, if in <code>CASCADE</code> view mode.<br />
|
||||
* Displays or hides the competitor chart, if in <code>ONESCREEN</code> view mode.<br /><br />
|
||||
*
|
||||
* The race board should be completely rendered before this method is called, or a few exceptions could be thrown.
|
||||
*
|
||||
* @param visible <code>true</code> if the competitor chart shall be open/visible
|
||||
*/
|
||||
public void setCompetitorChartVisible(boolean visible) {
|
||||
setComponentVisible(leaderboardAndMapViewer, competitorChart, visible);
|
||||
}
|
||||
|
||||
public RaceTimePanel getTimePanel() {
|
||||
return timePanel;
|
||||
}
|
||||
|
||||
protected SailingServiceAsync getSailingService() {
|
||||
return sailingService;
|
||||
}
|
||||
|
||||
protected String getRaceBoardName() {
|
||||
return raceBoardName;
|
||||
}
|
||||
|
||||
protected void setRaceBoardName(String raceBoardName) {
|
||||
this.raceBoardName = raceBoardName;
|
||||
}
|
||||
|
||||
protected ErrorReporter getErrorReporter() {
|
||||
return errorReporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRaceSelectionChange(List<RegattaAndRaceIdentifier> selectedRaces) {
|
||||
}
|
||||
|
||||
public RaceBoardViewConfiguration getConfiguration() {
|
||||
return raceboardViewConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatedLeaderboard(LeaderboardDTO leaderboard) {
|
||||
leaderboardAndMapViewer.setLeftComponentWidth(leaderboardPanel.getContentPanel().getOffsetWidth());
|
||||
if (editMarkPassingPanel != null) {
|
||||
editMarkPassingPanel.setLeaderboard(leaderboard);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void currentRaceSelected(RaceIdentifier raceIdentifier, RaceColumnDTO raceColumn) {
|
||||
if (!currentRaceHasBeenSelectedOnce) {
|
||||
FleetDTO fleet = raceColumn.getFleet(raceIdentifier);
|
||||
String seriesName = raceColumn.getSeriesName();
|
||||
if (LeaderboardNameConstants.DEFAULT_SERIES_NAME.equals(seriesName)) {
|
||||
seriesName = "";
|
||||
}
|
||||
String fleetForRaceName = fleet==null?"":fleet.getName();
|
||||
if (fleetForRaceName.equals(LeaderboardNameConstants.DEFAULT_FLEET_NAME)) {
|
||||
fleetForRaceName = "";
|
||||
} else {
|
||||
fleetForRaceName = (seriesName.isEmpty() ? "" : " - ") + fleetForRaceName;
|
||||
}
|
||||
final Label raceNameLabel = new Label(stringMessages.race() + " " + raceColumn.getRaceColumnName());
|
||||
raceNameLabel.setStyleName("RaceName-Label");
|
||||
final Label raceAdditionalInformationLabel = new Label(seriesName + fleetForRaceName);
|
||||
raceAdditionalInformationLabel.setStyleName("RaceSeriesAndFleet-Label");
|
||||
raceInformationHeader.clear();
|
||||
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");
|
||||
String link = "/gwt/Home.html";
|
||||
if (debugParam != null && !debugParam.isEmpty()) {
|
||||
link += "?gwt.codesvr=" + debugParam;
|
||||
}
|
||||
link += "#EventPlace:eventId="+eventId.toString();
|
||||
link += "&navigationTab=Regatta&leaderboardName=" + URLEncoder.encode(leaderboardName);
|
||||
regattaNameAnchor.setHref(link);
|
||||
} else {
|
||||
String leaderboardGroupNameParam = Window.Location.getParameter("leaderboardGroupName");
|
||||
if(leaderboardGroupNameParam != null) {
|
||||
Map<String, String> leaderboardGroupLinkParameters = new HashMap<String, String>();
|
||||
leaderboardGroupLinkParameters.put("showRaceDetails", "true");
|
||||
leaderboardGroupLinkParameters.put("leaderboardGroupName", leaderboardGroupNameParam);
|
||||
String leaderBoardGroupLink = EntryPointLinkFactory.createLeaderboardGroupLink(leaderboardGroupLinkParameters);
|
||||
regattaNameAnchor.setHref(leaderBoardGroupLink);
|
||||
} else {
|
||||
// fallback
|
||||
regattaNameAnchor.setHref("javascript:window.history.back();");
|
||||
}
|
||||
}
|
||||
regattaNameAnchor.setStyleName("RegattaName-Anchor");
|
||||
Label raceTimeLabel = computeRaceInformation(raceColumn, fleet);
|
||||
raceTimeLabel.setStyleName("RaceTime-Label");
|
||||
regattaAndRaceTimeInformationHeader.clear();
|
||||
regattaAndRaceTimeInformationHeader.add(regattaNameAnchor);
|
||||
regattaAndRaceTimeInformationHeader.add(raceTimeLabel);
|
||||
currentRaceHasBeenSelectedOnce = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UIObject getXPositionUiObject() {
|
||||
return timePanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UIObject getYPositionUiObject() {
|
||||
return timePanel;
|
||||
}
|
||||
|
||||
private Label computeRaceInformation(RaceColumnDTO raceColumn, FleetDTO fleet) {
|
||||
Label raceInformationLabel = new Label();
|
||||
raceInformationLabel.setStyleName("Race-Time-Label");
|
||||
DateTimeFormat formatter = DateTimeFormat.getFormat("E d/M/y");
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+23
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+334
-305
@@ -1,305 +1,334 @@
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel.Direction;
|
||||
import com.google.gwt.user.client.ui.LayoutPanel;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.RequiresResize;
|
||||
import com.google.gwt.user.client.ui.ScrollPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwt.user.client.ui.WidgetCollection;
|
||||
import com.sap.sailing.domain.common.security.Roles;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.media.MediaManagementControl;
|
||||
import com.sap.sailing.gwt.ui.client.media.MediaPlayerManager;
|
||||
import com.sap.sailing.gwt.ui.client.media.MediaPlayerManager.PlayerChangeListener;
|
||||
import com.sap.sailing.gwt.ui.client.media.MediaPlayerManagerComponent;
|
||||
import com.sap.sailing.gwt.ui.client.media.MediaSingleSelectionControl;
|
||||
import com.sap.sailing.gwt.ui.client.shared.charts.EditMarkPassingsPanel;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.settings.AbstractSettings;
|
||||
import com.sap.sse.gwt.client.shared.components.Component;
|
||||
import com.sap.sse.gwt.client.shared.components.ComponentViewer;
|
||||
import com.sap.sse.gwt.client.shared.components.SettingsDialog;
|
||||
import com.sap.sse.security.shared.DefaultRoles;
|
||||
import com.sap.sse.security.ui.client.UserService;
|
||||
import com.sap.sse.security.ui.client.UserStatusEventHandler;
|
||||
import com.sap.sse.security.ui.shared.UserDTO;
|
||||
|
||||
/**
|
||||
* Component Viewer that uses a {@link TouchSplitLayoutPanel} to display its components.
|
||||
*
|
||||
* TODO: Refactor to make sure it is really only performing operations that are related to view. Currently it is digging
|
||||
* too deep into components and setting titles or even creating video buttons.
|
||||
*/
|
||||
public class SideBySideComponentViewer implements ComponentViewer, UserStatusEventHandler {
|
||||
|
||||
private static final int DEFAULT_SOUTH_SPLIT_PANEL_HEIGHT = 200;
|
||||
private final int MIN_LEADERBOARD_WIDTH = 432; // works well for 505 and ESS
|
||||
|
||||
/**
|
||||
* Absolute Panel that informs its children about a resize
|
||||
*/
|
||||
class ResizableAbsolutePanel extends AbsolutePanel implements RequiresResize {
|
||||
public void onResize() {
|
||||
WidgetCollection children = getChildren();
|
||||
for (Widget widget : children) {
|
||||
if (widget instanceof RequiresResize) {
|
||||
((RequiresResize) widget).onResize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final LeaderboardPanel leftComponent;
|
||||
private final Component<?> rightComponent;
|
||||
private final List<Component<?>> components;
|
||||
private final ScrollPanel leftScrollPanel;
|
||||
private final StringMessages stringMessages;
|
||||
private final Button mediaSelectionButton;
|
||||
private final Button mediaManagementButton;
|
||||
private final EditMarkPassingsPanel markPassingsPanel;
|
||||
|
||||
private LayoutPanel mainPanel;
|
||||
|
||||
private TouchSplitLayoutPanel splitLayoutPanel;
|
||||
private int savedSplitPosition = -1;
|
||||
private boolean layoutForLeftComponentForcedOnce = false;
|
||||
|
||||
public SideBySideComponentViewer(final LeaderboardPanel leftComponentP, final Component<?> rightComponentP,
|
||||
final MediaPlayerManagerComponent mediaPlayerManagerComponent, List<Component<?>> components,
|
||||
final StringMessages stringMessages, UserService userService, EditMarkPassingsPanel markPassingsPanel) {
|
||||
this.stringMessages = stringMessages;
|
||||
this.leftComponent = leftComponentP;
|
||||
this.rightComponent = rightComponentP;
|
||||
this.components = components;
|
||||
this.mediaSelectionButton = createMediaSelectionButton(mediaPlayerManagerComponent);
|
||||
this.mediaManagementButton = createMediaManagementButton(mediaPlayerManagerComponent);
|
||||
this.markPassingsPanel = markPassingsPanel;
|
||||
|
||||
userService.addUserStatusEventHandler(this);
|
||||
|
||||
mediaPlayerManagerComponent.setPlayerChangeListener(new PlayerChangeListener() {
|
||||
|
||||
public void notifyStateChange(){
|
||||
String caption;
|
||||
String tooltip;
|
||||
switch (mediaPlayerManagerComponent.getAssignedMediaTracks().size()) {
|
||||
case 0:
|
||||
caption = stringMessages.mediaNoVideosCaption();
|
||||
tooltip = caption;
|
||||
mediaSelectionButton.setVisible(false);
|
||||
break;
|
||||
case 1:
|
||||
mediaSelectionButton.setVisible(true);
|
||||
if(mediaPlayerManagerComponent.isPlaying()){
|
||||
caption = stringMessages.mediaHideVideoCaption();
|
||||
tooltip = stringMessages.mediaHideVideoTooltip();
|
||||
}
|
||||
else{
|
||||
caption = stringMessages.mediaShowVideoCaption();
|
||||
tooltip = stringMessages.mediaShowVideoTooltip(mediaPlayerManagerComponent.getAssignedMediaTracks().iterator().next().title);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mediaSelectionButton.setVisible(true);
|
||||
caption = stringMessages.mediaSelectVideoCaption(mediaPlayerManagerComponent.getAssignedMediaTracks().size());
|
||||
tooltip = stringMessages.mediaSelectVideoTooltip();
|
||||
break;
|
||||
}
|
||||
if (mediaPlayerManagerComponent.isPlaying()) {
|
||||
mediaSelectionButton.addStyleDependentName("mediaplaying");
|
||||
} else {
|
||||
mediaSelectionButton.removeStyleDependentName("mediaplaying");
|
||||
}
|
||||
mediaSelectionButton.setText(caption);
|
||||
mediaSelectionButton.setTitle(tooltip);
|
||||
mediaManagementButton.setVisible(mediaPlayerManagerComponent.allowsEditing());
|
||||
}
|
||||
|
||||
});
|
||||
this.leftScrollPanel = new ScrollPanel();
|
||||
this.leftScrollPanel.add(leftComponentP.getEntryWidget());
|
||||
this.leftScrollPanel.setTitle(leftComponentP.getEntryWidget().getTitle());
|
||||
this.mainPanel = new LayoutPanel();
|
||||
this.mainPanel.setSize("100%", "100%");
|
||||
this.mainPanel.getElement().getStyle().setMarginTop(-12, Unit.PX);
|
||||
this.mainPanel.setStyleName("SideBySideComponentViewer-MainPanel");
|
||||
this.splitLayoutPanel = new TouchSplitLayoutPanel(/* horizontal splitter width */3, /* vertical splitter height */
|
||||
25);
|
||||
this.mainPanel.add(splitLayoutPanel);
|
||||
|
||||
// initialize components - they need to be added before other widgets to get the right width
|
||||
initializeComponents();
|
||||
|
||||
// initialize the leaderboard component
|
||||
savedSplitPosition = MIN_LEADERBOARD_WIDTH;
|
||||
splitLayoutPanel.insert(leftScrollPanel, leftComponent, Direction.WEST, savedSplitPosition);
|
||||
|
||||
// create a panel that will contain the horizontal toggle buttons
|
||||
ResizableAbsolutePanel panelForMapAndHorizontalToggleButtons = new ResizableAbsolutePanel();
|
||||
panelForMapAndHorizontalToggleButtons.add(rightComponent.getEntryWidget());
|
||||
splitLayoutPanel.insert(panelForMapAndHorizontalToggleButtons, rightComponent, Direction.CENTER, 0);
|
||||
|
||||
// add additional toggle buttons panel that currently only contains the video button
|
||||
List<Pair<Button, String>> additionalVerticalButtons = new ArrayList<Pair<Button, String>>();
|
||||
additionalVerticalButtons.add(new Pair<Button, String>(mediaSelectionButton,
|
||||
mediaPlayerManagerComponent.getDependentCssClassName()));
|
||||
if (/* TODO check for correct role; was: user != null */ true) {
|
||||
additionalVerticalButtons.add(new Pair<Button, String>(mediaManagementButton,
|
||||
"managemedia"));
|
||||
}
|
||||
onUserStatusChange(userService.getCurrentUser());
|
||||
|
||||
// ensure that toggle buttons are positioned right
|
||||
splitLayoutPanel.lastComponentHasBeenAdded(this, panelForMapAndHorizontalToggleButtons,
|
||||
additionalVerticalButtons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the video control button that shows or hides the video popup
|
||||
*
|
||||
* @param userAgent
|
||||
*/
|
||||
private Button createMediaSelectionButton(final MediaPlayerManager mediaPlayerManager) {
|
||||
final Button result = new Button();
|
||||
final MediaSingleSelectionControl multiSelectionControl = new MediaSingleSelectionControl(mediaPlayerManager,
|
||||
result, stringMessages);
|
||||
result.addClickHandler(new ClickHandler() {
|
||||
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
if (mediaPlayerManager.getAssignedMediaTracks().size() == 1) {
|
||||
if (mediaPlayerManager.isPlaying()) {
|
||||
mediaPlayerManager.stopAll();
|
||||
} else {
|
||||
mediaPlayerManager.playDefault();
|
||||
|
||||
}
|
||||
} else {
|
||||
multiSelectionControl.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// hide button initially as we defer showing the button to the asynchroneous
|
||||
// task that gets launched by the media service to get video tracks
|
||||
result.setVisible(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the video control button that shows or hides the video popup
|
||||
*
|
||||
* @param userAgent
|
||||
*/
|
||||
private Button createMediaManagementButton(final MediaPlayerManager mediaPlayerManager) {
|
||||
final Button result = new Button(stringMessages.mediaManageMediaCaption());
|
||||
result.setTitle(stringMessages.mediaManageMediaTooltip());
|
||||
// onClick
|
||||
final MediaManagementControl multiSelectionControl = new MediaManagementControl(mediaPlayerManager,
|
||||
result, stringMessages);
|
||||
result.addClickHandler(new ClickHandler() {
|
||||
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
multiSelectionControl.show();
|
||||
}
|
||||
});
|
||||
|
||||
// hide button initially as we defer showing the button to the asynchroneous
|
||||
// task that gets launched by the media service to get video tracks
|
||||
result.setVisible(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void initializeComponents() {
|
||||
for (final Component<?> component : components) {
|
||||
splitLayoutPanel.insert(component.getEntryWidget(), component, Direction.SOUTH, 200);
|
||||
}
|
||||
}
|
||||
|
||||
public <SettingsType extends AbstractSettings> void showSettingsDialog(Component<SettingsType> component) {
|
||||
if (component.hasSettings()) {
|
||||
new SettingsDialog<SettingsType>(component, stringMessages).show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever the layout of {@link TouchSplitLayoutPanel} or other components change. Controls the visibility
|
||||
* based on the {@link Component}s visibility. Each {@link Component} is in charge to not display any data or update
|
||||
* itself when it is not visible.
|
||||
*/
|
||||
public void forceLayout() {
|
||||
if (!leftComponent.isVisible() && rightComponent.isVisible()) {
|
||||
// the leaderboard is not visible, but the map is
|
||||
if (isWidgetInSplitPanel(leftScrollPanel)) {
|
||||
if (leftScrollPanel.getOffsetWidth() > 0) {
|
||||
savedSplitPosition = leftScrollPanel.getOffsetWidth();
|
||||
}
|
||||
splitLayoutPanel.setWidgetVisibility(leftScrollPanel, leftComponent, /* hidden */true,
|
||||
savedSplitPosition);
|
||||
}
|
||||
} else if (leftComponent.isVisible() && rightComponent.isVisible()) {
|
||||
// the leaderboard and the map are visible
|
||||
splitLayoutPanel.setWidgetVisibility(leftScrollPanel, leftComponent, /* hidden */false, savedSplitPosition);
|
||||
} else if (!leftComponent.isVisible() && !rightComponent.isVisible()) {
|
||||
}
|
||||
|
||||
for (Component<?> component : components) {
|
||||
final boolean isComponentVisible = component.isVisible();
|
||||
splitLayoutPanel.setWidgetVisibility(component.getEntryWidget(), component, !isComponentVisible,
|
||||
DEFAULT_SOUTH_SPLIT_PANEL_HEIGHT);
|
||||
}
|
||||
splitLayoutPanel.forceLayout();
|
||||
}
|
||||
|
||||
private boolean isWidgetInSplitPanel(Widget widget) {
|
||||
int widgetIndex = splitLayoutPanel.getWidgetIndex(widget);
|
||||
return widgetIndex >= 0;
|
||||
}
|
||||
|
||||
public Panel getViewerWidget() {
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
public Component<?> getRootComponent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getViewerName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public void setLeftComponentWidth(int width) {
|
||||
// TODO: The information provided by width is wrong
|
||||
// need to find a way to get the correct information
|
||||
if (!layoutForLeftComponentForcedOnce) {
|
||||
savedSplitPosition = MIN_LEADERBOARD_WIDTH;
|
||||
forceLayout();
|
||||
}
|
||||
layoutForLeftComponentForcedOnce = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserStatusChange(UserDTO user) {
|
||||
Button toggleButton = splitLayoutPanel.getAssociatedSplitter(markPassingsPanel).getToggleButton();
|
||||
if (user != null
|
||||
&& (user.hasRole(DefaultRoles.ADMIN.getRolename()) || user.hasRole(Roles.eventmanager.getRolename()))) {
|
||||
toggleButton.setVisible(true);
|
||||
forceLayout();
|
||||
} else {
|
||||
markPassingsPanel.setVisible(false);
|
||||
toggleButton.setVisible(false);
|
||||
forceLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.gwt.ui.raceboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.dom.client.Style;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel.Direction;
|
||||
import com.google.gwt.user.client.ui.LayoutPanel;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.RequiresResize;
|
||||
import com.google.gwt.user.client.ui.ScrollPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwt.user.client.ui.WidgetCollection;
|
||||
import com.sap.sailing.domain.common.security.Roles;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.media.MediaManagementControl;
|
||||
import com.sap.sailing.gwt.ui.client.media.MediaPlayerManager;
|
||||
import com.sap.sailing.gwt.ui.client.media.MediaPlayerManager.PlayerChangeListener;
|
||||
import com.sap.sailing.gwt.ui.client.media.MediaPlayerManagerComponent;
|
||||
import com.sap.sailing.gwt.ui.client.media.MediaSingleSelectionControl;
|
||||
import com.sap.sailing.gwt.ui.client.shared.charts.EditMarkPassingsPanel;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardPanel;
|
||||
import com.sap.sailing.gwt.ui.raceboard.TouchSplitLayoutPanel.Splitter;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.settings.AbstractSettings;
|
||||
import com.sap.sse.gwt.client.shared.components.Component;
|
||||
import com.sap.sse.gwt.client.shared.components.ComponentViewer;
|
||||
import com.sap.sse.gwt.client.shared.components.SettingsDialog;
|
||||
import com.sap.sse.security.shared.DefaultRoles;
|
||||
import com.sap.sse.security.ui.client.UserService;
|
||||
import com.sap.sse.security.ui.client.UserStatusEventHandler;
|
||||
import com.sap.sse.security.ui.shared.UserDTO;
|
||||
|
||||
/**
|
||||
* Component Viewer that uses a {@link TouchSplitLayoutPanel} to display its components.
|
||||
*
|
||||
* TODO: Refactor to make sure it is really only performing operations that are related to view. Currently it is digging
|
||||
* too deep into components and setting titles or even creating video buttons.
|
||||
*/
|
||||
public class SideBySideComponentViewer implements ComponentViewer, UserStatusEventHandler {
|
||||
|
||||
private static final int DEFAULT_SOUTH_SPLIT_PANEL_HEIGHT = 200;
|
||||
private final int MIN_LEADERBOARD_WIDTH = Math.min(432, Window.getClientWidth() - 40); // fallback value "432" works well for 505 and ESS
|
||||
|
||||
/**
|
||||
* Absolute Panel that informs its children about a resize
|
||||
*/
|
||||
class ResizableAbsolutePanel extends AbsolutePanel implements RequiresResize {
|
||||
public void onResize() {
|
||||
WidgetCollection children = getChildren();
|
||||
for (Widget widget : children) {
|
||||
if (widget instanceof RequiresResize) {
|
||||
((RequiresResize) widget).onResize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final LeaderboardPanel leftComponent;
|
||||
private final Component<?> rightComponent;
|
||||
private final List<Component<?>> components;
|
||||
private final ScrollPanel leftScrollPanel;
|
||||
private final StringMessages stringMessages;
|
||||
private final Button mediaSelectionButton;
|
||||
private final Button mediaManagementButton;
|
||||
private final EditMarkPassingsPanel markPassingsPanel;
|
||||
|
||||
private LayoutPanel mainPanel;
|
||||
|
||||
private TouchSplitLayoutPanel splitLayoutPanel;
|
||||
private int savedSplitPosition = -1;
|
||||
private boolean layoutForLeftComponentForcedOnce = false;
|
||||
|
||||
public SideBySideComponentViewer(final LeaderboardPanel leftComponentP, final Component<?> rightComponentP,
|
||||
final MediaPlayerManagerComponent mediaPlayerManagerComponent, List<Component<?>> components,
|
||||
final StringMessages stringMessages, UserService userService, EditMarkPassingsPanel markPassingsPanel) {
|
||||
this.stringMessages = stringMessages;
|
||||
this.leftComponent = leftComponentP;
|
||||
this.rightComponent = rightComponentP;
|
||||
this.components = components;
|
||||
this.mediaSelectionButton = createMediaSelectionButton(mediaPlayerManagerComponent);
|
||||
this.mediaManagementButton = createMediaManagementButton(mediaPlayerManagerComponent);
|
||||
this.markPassingsPanel = markPassingsPanel;
|
||||
userService.addUserStatusEventHandler(this);
|
||||
mediaPlayerManagerComponent.setPlayerChangeListener(new PlayerChangeListener() {
|
||||
public void notifyStateChange() {
|
||||
String caption;
|
||||
String tooltip;
|
||||
switch (mediaPlayerManagerComponent.getAssignedMediaTracks().size()) {
|
||||
case 0:
|
||||
caption = stringMessages.mediaNoVideosCaption();
|
||||
tooltip = caption;
|
||||
mediaSelectionButton.setVisible(false);
|
||||
break;
|
||||
case 1:
|
||||
mediaSelectionButton.setVisible(true);
|
||||
if(mediaPlayerManagerComponent.isPlaying()){
|
||||
caption = stringMessages.mediaHideVideoCaption();
|
||||
tooltip = stringMessages.mediaHideVideoTooltip();
|
||||
}
|
||||
else{
|
||||
caption = stringMessages.mediaShowVideoCaption();
|
||||
tooltip = stringMessages.mediaShowVideoTooltip(mediaPlayerManagerComponent.getAssignedMediaTracks().iterator().next().title);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mediaSelectionButton.setVisible(true);
|
||||
caption = stringMessages.mediaSelectVideoCaption(mediaPlayerManagerComponent.getAssignedMediaTracks().size());
|
||||
tooltip = stringMessages.mediaSelectVideoTooltip();
|
||||
break;
|
||||
}
|
||||
if (mediaPlayerManagerComponent.isPlaying()) {
|
||||
mediaSelectionButton.addStyleDependentName("mediaplaying");
|
||||
} else {
|
||||
mediaSelectionButton.removeStyleDependentName("mediaplaying");
|
||||
}
|
||||
mediaSelectionButton.setText(caption);
|
||||
mediaSelectionButton.setTitle(tooltip);
|
||||
mediaManagementButton.setVisible(mediaPlayerManagerComponent.allowsEditing());
|
||||
}
|
||||
});
|
||||
this.leftScrollPanel = new ScrollPanel();
|
||||
this.leftScrollPanel.add(leftComponentP.getEntryWidget());
|
||||
this.leftScrollPanel.setTitle(leftComponentP.getEntryWidget().getTitle());
|
||||
this.mainPanel = new LayoutPanel() {
|
||||
@Override
|
||||
public void onResize() {
|
||||
int leftWidth = leftScrollPanel.getOffsetWidth();
|
||||
// The left scroll panel is potentially resized to ensure it is not too wide when the screen gets narrower,
|
||||
// e.g. when resizing browser window or changing mobile device orientation. An offset of 40px is used, so
|
||||
// the panels size slider and its toggle button is always accessable if it is open.
|
||||
savedSplitPosition = Math.min(leftWidth > 0 ? leftWidth : savedSplitPosition, Window.getClientWidth() - 40);
|
||||
splitLayoutPanel.setWidgetSize(leftScrollPanel, savedSplitPosition);
|
||||
super.onResize();
|
||||
}
|
||||
};
|
||||
this.mainPanel.setSize("100%", "100%");
|
||||
this.mainPanel.getElement().getStyle().setMarginTop(-12, Unit.PX);
|
||||
this.mainPanel.setStyleName("SideBySideComponentViewer-MainPanel");
|
||||
this.splitLayoutPanel = new TouchSplitLayoutPanel(/* horizontal splitter width */3, /* vertical splitter height */ 25);
|
||||
this.mainPanel.add(splitLayoutPanel);
|
||||
|
||||
// initialize components - they need to be added before other widgets to get the right width
|
||||
initializeComponents();
|
||||
|
||||
// initialize the leaderboard component
|
||||
savedSplitPosition = MIN_LEADERBOARD_WIDTH;
|
||||
splitLayoutPanel.insert(leftScrollPanel, leftComponent, Direction.WEST, savedSplitPosition);
|
||||
|
||||
// create a panel that will contain the horizontal toggle buttons
|
||||
ResizableAbsolutePanel panelForMapAndHorizontalToggleButtons = new ResizableAbsolutePanel();
|
||||
panelForMapAndHorizontalToggleButtons.add(rightComponent.getEntryWidget());
|
||||
splitLayoutPanel.insert(panelForMapAndHorizontalToggleButtons, rightComponent, Direction.CENTER, 0);
|
||||
|
||||
// add additional toggle buttons panel that currently only contains the video button
|
||||
List<Pair<Button, String>> additionalVerticalButtons = new ArrayList<Pair<Button, String>>();
|
||||
additionalVerticalButtons.add(new Pair<Button, String>(mediaSelectionButton,
|
||||
mediaPlayerManagerComponent.getDependentCssClassName()));
|
||||
if (/* TODO check for correct role; was: user != null */ true) {
|
||||
additionalVerticalButtons.add(new Pair<Button, String>(mediaManagementButton,
|
||||
"managemedia"));
|
||||
}
|
||||
onUserStatusChange(userService.getCurrentUser());
|
||||
// ensure that toggle buttons are positioned right
|
||||
splitLayoutPanel.lastComponentHasBeenAdded(this, panelForMapAndHorizontalToggleButtons,
|
||||
additionalVerticalButtons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the video control button that shows or hides the video popup
|
||||
*
|
||||
* @param userAgent
|
||||
*/
|
||||
private Button createMediaSelectionButton(final MediaPlayerManager mediaPlayerManager) {
|
||||
final Button result = new Button();
|
||||
final MediaSingleSelectionControl multiSelectionControl = new MediaSingleSelectionControl(mediaPlayerManager,
|
||||
result, stringMessages);
|
||||
result.addClickHandler(new ClickHandler() {
|
||||
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
if (mediaPlayerManager.getAssignedMediaTracks().size() == 1) {
|
||||
if (mediaPlayerManager.isPlaying()) {
|
||||
mediaPlayerManager.stopAll();
|
||||
} else {
|
||||
mediaPlayerManager.playDefault();
|
||||
|
||||
}
|
||||
} else {
|
||||
multiSelectionControl.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// hide button initially as we defer showing the button to the asynchroneous
|
||||
// task that gets launched by the media service to get video tracks
|
||||
result.setVisible(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the video control button that shows or hides the video popup
|
||||
*
|
||||
* @param userAgent
|
||||
*/
|
||||
private Button createMediaManagementButton(final MediaPlayerManager mediaPlayerManager) {
|
||||
final Button result = new Button(stringMessages.mediaManageMediaCaption());
|
||||
result.setTitle(stringMessages.mediaManageMediaTooltip());
|
||||
// onClick
|
||||
final MediaManagementControl multiSelectionControl = new MediaManagementControl(mediaPlayerManager,
|
||||
result, stringMessages);
|
||||
result.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
multiSelectionControl.show();
|
||||
}
|
||||
});
|
||||
// hide button initially as we defer showing the button to the asynchronous
|
||||
// task that gets launched by the media service to get video tracks
|
||||
result.setVisible(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void initializeComponents() {
|
||||
for (final Component<?> component : components) {
|
||||
splitLayoutPanel.insert(component.getEntryWidget(), component, Direction.SOUTH, 200);
|
||||
}
|
||||
}
|
||||
|
||||
public <SettingsType extends AbstractSettings> void showSettingsDialog(Component<SettingsType> component) {
|
||||
if (component.hasSettings()) {
|
||||
new SettingsDialog<SettingsType>(component, stringMessages).show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever the layout of {@link TouchSplitLayoutPanel} or other components change. Controls the visibility
|
||||
* based on the {@link Component}s visibility. Each {@link Component} is in charge to not display any data or update
|
||||
* itself when it is not visible.
|
||||
*/
|
||||
public void forceLayout() {
|
||||
if (!leftComponent.isVisible() && rightComponent.isVisible()) {
|
||||
// the leaderboard is not visible, but the map is
|
||||
if (isWidgetInSplitPanel(leftScrollPanel)) {
|
||||
if (leftScrollPanel.getOffsetWidth() > 0) {
|
||||
savedSplitPosition = Math.min(savedSplitPosition, leftScrollPanel.getOffsetWidth());
|
||||
}
|
||||
splitLayoutPanel.setWidgetVisibility(leftScrollPanel, leftComponent, /* hidden */true,
|
||||
savedSplitPosition);
|
||||
}
|
||||
} else if (leftComponent.isVisible() && rightComponent.isVisible()) {
|
||||
// the leaderboard and the map are visible
|
||||
splitLayoutPanel.setWidgetVisibility(leftScrollPanel, leftComponent, /* hidden */false, savedSplitPosition);
|
||||
} else if (!leftComponent.isVisible() && !rightComponent.isVisible()) {
|
||||
}
|
||||
|
||||
for (Component<?> component : components) {
|
||||
final boolean isComponentVisible = component.isVisible();
|
||||
splitLayoutPanel.setWidgetVisibility(component.getEntryWidget(), component, !isComponentVisible,
|
||||
DEFAULT_SOUTH_SPLIT_PANEL_HEIGHT);
|
||||
}
|
||||
splitLayoutPanel.forceLayout();
|
||||
}
|
||||
|
||||
private boolean isWidgetInSplitPanel(Widget widget) {
|
||||
int widgetIndex = splitLayoutPanel.getWidgetIndex(widget);
|
||||
return widgetIndex >= 0;
|
||||
}
|
||||
|
||||
public Panel getViewerWidget() {
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
public Component<?> getRootComponent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getViewerName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public void setLeftComponentWidth(int width) {
|
||||
// TODO: The information provided by width is wrong
|
||||
// need to find a way to get the correct information
|
||||
if (!layoutForLeftComponentForcedOnce) {
|
||||
savedSplitPosition = MIN_LEADERBOARD_WIDTH;
|
||||
forceLayout();
|
||||
}
|
||||
layoutForLeftComponentForcedOnce = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserStatusChange(UserDTO user) {
|
||||
final Splitter associatedSplitter = splitLayoutPanel.getAssociatedSplitter(markPassingsPanel);
|
||||
if (associatedSplitter != null) { // if the panel is not present, the splitter may not be found
|
||||
final Button toggleButton = associatedSplitter.getToggleButton();
|
||||
if (user != null
|
||||
&& (user.hasRole(DefaultRoles.ADMIN.getRolename()) ||
|
||||
user.hasRole(Roles.eventmanager.getRolename()))) {
|
||||
toggleButton.setVisible(true);
|
||||
forceLayout();
|
||||
} else {
|
||||
markPassingsPanel.setVisible(false);
|
||||
toggleButton.setVisible(false);
|
||||
forceLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows/hides the text on left components toggle button by modifying CSS <code>font-size</code> property and adjust
|
||||
* the dragger position by modifying CSS <code>margin-top</code> property.
|
||||
*
|
||||
* @param visible
|
||||
* <code>true</code> to show the button text, <code>false</code> to hide it
|
||||
*/
|
||||
void setLeftComponentToggleButtonTextVisibilityAndDraggerPosition(final boolean visible) {
|
||||
Splitter leftScrollPanelSplitter = splitLayoutPanel.getAssociatedSplitter(leftScrollPanel);
|
||||
if (leftScrollPanelSplitter != null) {
|
||||
Style toggleButtonStyle = leftScrollPanelSplitter.getToggleButton().getElement().getStyle();
|
||||
if (visible) toggleButtonStyle.clearFontSize();
|
||||
else toggleButtonStyle.setFontSize(0, Unit.PX);
|
||||
Style drapperStyle = leftScrollPanelSplitter.getDragger().getElement().getStyle();
|
||||
if (visible) drapperStyle.clearMarginTop();
|
||||
else drapperStyle.setMarginTop(-25, Unit.PX);
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
-2
@@ -613,7 +613,7 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
|
||||
if (lastVerticalSplitter != null) {
|
||||
Panel panel = createToggleButtonPanel(allVerticalSplitters,
|
||||
"gwt-SplitLayoutPanel-NorthSouthToggleButton-Panel", "gwt-SplitLayoutPanel-NorthSouthToggleButton",
|
||||
cm, additionalVerticalButtonsAndStyles);
|
||||
cm, additionalVerticalButtonsAndStyles); // TODO additional buttons will only be displayed if at least one vertical splitter is... on purpose?
|
||||
lastVerticalSplitter.addToogleButtons(panel);
|
||||
lastVerticalSplitter.setVisible(true);
|
||||
lastVerticalSplitter.setDraggerVisible(false);
|
||||
@@ -621,7 +621,7 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
|
||||
ensureVerticalToggleButtonPosition();
|
||||
if (lastHorizontalSplitter != null) {
|
||||
Panel horizontalButtonsPanel = createToggleButtonPanel(allHorizontalSplitters,
|
||||
"gwt-SplitLayoutPanel-EastToggleButton-Panel", "gwt-SplitLayoutPanel-EastToggleButton", cm, null);
|
||||
"gwt-SplitLayoutPanel-EastToggleButton-Panel", "gwt-SplitLayoutPanel-EastToggleButton", cm, /* additional buttons and styles */ null);
|
||||
panelForHorizontalButtons.add(horizontalButtonsPanel);
|
||||
lastHorizontalSplitter.setVisible(false);
|
||||
lastHorizontalSplitter.setDraggerVisible(false);
|
||||
@@ -842,6 +842,24 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size of the given {@link Widget} if it is {@link Widget#isVisible() visible}. Otherwise, the given size
|
||||
* will be persisted as the widgets {@link LayoutData#oldSize old size}.
|
||||
*
|
||||
* @param widget the {@link Widget} to resize
|
||||
* @param size the new size
|
||||
*/
|
||||
public void setWidgetSize(Widget widget, int size) {
|
||||
final Splitter splitter = getAssociatedSplitter(widget);
|
||||
if (splitter != null) {
|
||||
if (widget.isVisible()) {
|
||||
splitter.setAssociatedWidgetSize(size, /* defer */false);
|
||||
} else {
|
||||
((LayoutData) widget.getLayoutData()).oldSize = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void assertIsChild2(Widget widget) {
|
||||
assert (widget == null) || (widget.getParent() == this) : "The specified widget is not a child of this panel";
|
||||
|
||||
+6
-4
@@ -233,6 +233,7 @@ import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.ThresholdBasedResultDiscardingRule;
|
||||
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.persistence.DomainObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoObjectFactory;
|
||||
import com.sap.sailing.domain.persistence.MongoRaceLogStoreFactory;
|
||||
@@ -853,7 +854,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
final RaceColumnDTO raceColumnDTO = columnFactory.createRaceColumnDTO(raceColumn.getName(),
|
||||
raceColumn.isMedalRace(), raceColumn.getExplicitFactor(),
|
||||
raceColumn instanceof RaceColumnInSeries ? ((RaceColumnInSeries) raceColumn).getRegatta().getName() : null,
|
||||
raceColumn instanceof RaceColumnInSeries ? ((RaceColumnInSeries) raceColumn).getSeries().getName() : null);
|
||||
raceColumn instanceof RaceColumnInSeries ? ((RaceColumnInSeries) raceColumn).getSeries().getName() : null,
|
||||
raceColumn instanceof MetaLeaderboardColumn);
|
||||
raceColumnDTOs.add(raceColumnDTO);
|
||||
}
|
||||
return raceColumnDTOs;
|
||||
@@ -1023,7 +1025,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
@Override
|
||||
public void trackWithTracTrac(RegattaIdentifier regattaToAddTo, Iterable<TracTracRaceRecordDTO> rrs, String liveURI, String storedURI,
|
||||
String courseDesignUpdateURI, boolean trackWind, final boolean correctWindByDeclination,
|
||||
final boolean simulateWithStartTimeNow, final boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword)
|
||||
final Duration offsetToStartTimeOfSimulatedRace, final boolean useInternalMarkPassingAlgorithm, String tracTracUsername, String tracTracPassword)
|
||||
throws Exception {
|
||||
logger.info("tracWithTracTrac for regatta " + regattaToAddTo + " for race records " + rrs + " with liveURI " + liveURI
|
||||
+ " and storedURI " + storedURI);
|
||||
@@ -1054,7 +1056,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
new URI(courseDesignUpdateURI), new MillisecondsTimePoint(record.getTrackingStartTime().asMillis()),
|
||||
new MillisecondsTimePoint(record.getTrackingEndTime().asMillis()),
|
||||
getRaceLogStore(), getRegattaLogStore(),
|
||||
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, simulateWithStartTimeNow,
|
||||
RaceTracker.TIMEOUT_FOR_RECEIVING_RACE_DEFINITION_IN_MILLISECONDS, offsetToStartTimeOfSimulatedRace,
|
||||
useInternalMarkPassingAlgorithm, tracTracUsername, tracTracPassword, record.getRaceStatus(), record.getRaceVisibility());
|
||||
if (trackWind) {
|
||||
new Thread("Wind tracking starter for race " + record.getEventName() + "/" + record.getName()) {
|
||||
@@ -2408,7 +2410,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
RaceColumnDTO raceColumnDTO = leaderboardDTO.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, raceDTO);
|
||||
fleetDTO, raceColumn.isMedalRace(), raceIdentifier, raceDTO, raceColumn instanceof MetaLeaderboardColumn);
|
||||
RaceLog raceLog = raceColumn.getRaceLog(fleet);
|
||||
RaceLogTrackingState raceLogTrackingState = raceLog == null ? RaceLogTrackingState.NOT_A_RACELOG_TRACKED_RACE :
|
||||
new RaceLogTrackingStateAnalyzer(raceLog).analyze();
|
||||
|
||||
+3
-1
@@ -309,7 +309,9 @@ public class SimulatorMainPanel extends SimplePanel {
|
||||
timer.setTime(windParams.getStartTime().getTime());
|
||||
int secondsTimeStep = (int) windParams.getTimeStep().asSeconds();
|
||||
timer.setPlaySpeedFactor(secondsTimeStep);
|
||||
timePanel = new TimePanel<TimePanelSettings>(timer, timeRangeProvider, stringMessages, false);
|
||||
timePanel = new TimePanel<TimePanelSettings>(timer, timeRangeProvider, stringMessages, false,
|
||||
/* isScreenLargeEnoughToOfferChartSupport: no wind or competitor chart is shown; use full horizontal
|
||||
* extension of time panel */ false);
|
||||
busyIndicator = new SimpleBusyIndicator(false, 0.8f);
|
||||
simulatorMap = new SimulatorMap(simulatorSvc, stringMessages, errorReporter, xRes, yRes, border, streamletPars,
|
||||
timer, timePanel, windParams, busyIndicator, mode, this, showMapControls,
|
||||
|
||||
+25
@@ -4,6 +4,31 @@
|
||||
<div id="mainContent">
|
||||
<h4 class="articleHeadline">What's New - SAP Sailing Analytics</h4>
|
||||
<div class="innerContent">
|
||||
<h5 class="articleSubheadline">December 2015</h5>
|
||||
|
||||
<ul class="bulletList">
|
||||
<li>New line hover behavior in race map. When the mouse is moved onto a line, for example the start line, a transparent,
|
||||
wider line is activated behind it that acts as a buffer for the thin line, where the text displayed by the hover is still shown.
|
||||
This makes it easier to hover over the lines. These wider lines can be made semi transparent instead of transparent
|
||||
by unticking the corresponding checkbox in the settings of the race map. Furthermore the stroke weight of the wider lines can be
|
||||
configured in the same settings dialog.
|
||||
</li>
|
||||
<li>The race viewer (RaceBoard.html) now intelligently chooses a layout that suits the screen size.
|
||||
When only little horizontal space is available, only the sail number and nationality but not the
|
||||
competitor's long name is displayed by default. When vertical space is scarce, competitor and wind
|
||||
charts are disabled and more horizontal space can be given to the time slider at the bottom. The
|
||||
leaderboard section can then be scaled to smaller widths and will reduce the column widths better
|
||||
than in the past.
|
||||
</li>
|
||||
<li>With the changes described above, the RaceBoard is now also accessible from the races page on mobile devices.
|
||||
</li>
|
||||
<li>For overall / series leaderboards such as a national sailing league or the Extreme Sailing Series, the
|
||||
live status of the overall leaderboard is now indicated. As long as a live race is ongoing, the respective
|
||||
column in the overall leaderboard is highlighted, and a comment is displayed that indicates which regatta
|
||||
is currently still live.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h5 class="articleSubheadline">November 2015</h5>
|
||||
|
||||
<ul class="bulletList">
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sailing.server.gateway.serialization.shared.android</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sailing.server.gateway.serialization.shared.android</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+1
-1
@@ -70,7 +70,7 @@ public class TrackRaceBoatCompetitorMetadataReplicationTest extends AbstractServ
|
||||
trackingParams = com.sap.sailing.domain.tractracadapter.DomainFactory.INSTANCE
|
||||
.createTrackingConnectivityParameters(paramURL, liveURI, storedURI, courseDesignUpdateURI,
|
||||
startOfTracking, endOfTracking, /* delayToLiveInMillis */
|
||||
0l, /* simulateWithStartTimeNow */false, /*ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE,
|
||||
0l, /* offsetToStartTimeOfSimulatedRace */null, /*ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, tracTracUsername, tracTracPassword, "", "");
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ public class TrackRaceReplicationTest extends AbstractServerReplicationTest {
|
||||
trackingParams = com.sap.sailing.domain.tractracadapter.DomainFactory.INSTANCE
|
||||
.createTrackingConnectivityParameters(paramURL, liveURI, storedURI, courseDesignUpdateURI,
|
||||
startOfTracking, endOfTracking, /* delayToLiveInMillis */
|
||||
0l, /* simulateWithStartTimeNow */false, /*ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE,
|
||||
0l, /* offsetToStartTimeOfSimulatedRace */null, /*ignoreTracTracMarkPassings*/ false, EmptyRaceLogStore.INSTANCE,
|
||||
EmptyRegattaLogStore.INSTANCE, tracTracUsername, tracTracPassword, "", "");
|
||||
}
|
||||
|
||||
|
||||
@@ -11,30 +11,30 @@
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-source-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>plugin-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>plugin-source</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-source-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>plugin-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>plugin-source</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,31 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sse.datamining.annotations</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-source-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>plugin-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>plugin-source</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>com.sap.sailing</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>com.sap.sse.datamining.annotations</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-source-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>plugin-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>plugin-source</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -7,6 +7,9 @@ import com.google.gwt.text.client.IntegerParser;
|
||||
import com.google.gwt.text.shared.Renderer;
|
||||
import com.google.gwt.user.client.ui.ValueBox;
|
||||
|
||||
/**
|
||||
* Renders integers in their box without any separators, non-localized, plain.
|
||||
*/
|
||||
public class IntegerBox extends ValueBox<Integer> {
|
||||
private static final Renderer<Integer> RENDERER = new Renderer<Integer>() {
|
||||
public String render(Integer object) {
|
||||
|
||||
+3
@@ -7,4 +7,7 @@ public interface BusyIndicatorResources extends ClientBundle {
|
||||
|
||||
@Source("busy_indicator_circle.gif")
|
||||
ImageResource busyIndicatorCircle();
|
||||
|
||||
@Source("busy_indicator_circle_inverted.gif")
|
||||
ImageResource busyIndicatorCircleInverted();
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.sap.sse.gwt.client.controls.busyindicator;
|
||||
|
||||
|
||||
/**
|
||||
* Allows UI components to observe the busy state of an operation.
|
||||
*/
|
||||
public interface BusyStateChangeListener {
|
||||
|
||||
/**
|
||||
* @param busyState the new busy state
|
||||
*/
|
||||
void onBusyStateChange(boolean busyState);
|
||||
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.sap.sse.gwt.client.controls.busyindicator;
|
||||
|
||||
|
||||
public interface BusyStateProvider {
|
||||
|
||||
void addBusyStateChangeListener(BusyStateChangeListener listener);
|
||||
|
||||
void removeBusyStateChangeListener(BusyStateChangeListener listener);
|
||||
|
||||
void setBusyState(boolean isBusy);
|
||||
|
||||
boolean isBusy();
|
||||
}
|
||||
Loaded 100 of 124 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user