Merge remote-tracking branch 'origin/master'

This commit is contained in:
Axel Uhl
2013-02-05 20:55:03 +01:00
14 changed files with 130 additions and 61 deletions
@@ -12,7 +12,7 @@ import static com.sap.sailing.domain.common.SortingOrder.*;
*
*/
public enum DetailType implements Serializable {
DISTANCE_TRAVELED(0, ASCENDING), AVERAGE_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING), RACE_RANK(0, ASCENDING), REGATTA_RANK(0, ASCENDING),
DISTANCE_TRAVELED(0, ASCENDING), AVERAGE_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING), RACE_RANK(0, ASCENDING), REGATTA_RANK(0, ASCENDING), OVERALL_RANK(0, ASCENDING),
RANK_GAIN(0, DESCENDING), NUMBER_OF_MANEUVERS(0, ASCENDING), CURRENT_SPEED_OVER_GROUND_IN_KNOTS(2, DESCENDING),
ESTIMATED_TIME_TO_NEXT_WAYPOINT_IN_SECONDS(1, ASCENDING), VELOCITY_MADE_GOOD_IN_KNOTS(2, DESCENDING),
GAP_TO_LEADER_IN_SECONDS(0, ASCENDING), GAP_CHANGE_SINCE_LEG_START_IN_SECONDS(0, ASCENDING),
@@ -25,6 +25,9 @@ public interface LeaderboardGroup extends Renamable {
void removeLeaderboard(Leaderboard leaderboard);
void removeAllLeaderboards(Collection<Leaderboard> leaderboards);
void clearLeaderboards();
/**
* @return The overall leaderboard of this group or null if there is none.
*/
Leaderboard getOverallLeaderboard();
void setOverallLeaderboard(Leaderboard leaderboard);
}
@@ -22,6 +22,8 @@ public class DetailTypeFormatter {
return stringMessages.rank();
case REGATTA_RANK:
return stringMessages.regattaRank();
case OVERALL_RANK:
return stringMessages.overallRank();
case NUMBER_OF_MANEUVERS:
return stringMessages.numberOfManeuvers();
case CURRENT_SPEED_OVER_GROUND_IN_KNOTS:
@@ -131,6 +133,7 @@ public class DetailTypeFormatter {
// Cases for detail types without unit, so that an empty string is returned.
case RACE_RANK:
case REGATTA_RANK:
case OVERALL_RANK:
case CURRENT_LEG:
case TACK:
case JIBE:
@@ -210,6 +213,8 @@ public class DetailTypeFormatter {
return stringMessages.rankTooltip();
case REGATTA_RANK:
return stringMessages.regattaRankTooltip();
case OVERALL_RANK:
return stringMessages.overallRankTooltip();
case RANK_GAIN:
return stringMessages.rankGainTooltip();
case TACK:
@@ -493,4 +493,7 @@ public interface StringMessages extends Messages {
String status();
String regattaRank();
String regattaRankTooltip();
String overallRank();
String overallRankTooltip();
String noDataFound();
}
@@ -61,6 +61,8 @@ rank=Rank
rankTooltip=Competitor''s rank in the race
regattaRank=Regatta Rank
regattaRankTooltip=Competitor''s rank in the regatta
overallRank=Overall Rank
overallRankTooltip=Competitor''s rank in the series
totalRank=Total rank
collapse=-
expand=+
@@ -493,4 +495,5 @@ carryColumnTooltip=Points carried over from previous races.
totalsColumnTooltip=The total of all points of a competitor in the regatta.
windData=Wind data
gpsData=GPS data
status=Status
status=Status
noDataFound=No data found
@@ -61,6 +61,8 @@ rank=Platz
rankTooltip=Platzierung des Teilnehmers im Rennen
regattaRank=Platz in der Regatta
regattaRankTooltip=Platzierung des Teilnehmers in der Regatta
overallRank=Platz in der Serie
overallRankTooltip=Platzierung des Teilnehmers in der Serie
totalRank=Gesamtplatz
collapse=-
expand=+
@@ -494,4 +496,5 @@ carryColumnTooltip=Übertrag vergangener Rennen
totalsColumnTooltip=Summe aller Punkte eines Teilnehmers in der Regatta
windData=Winddaten
gpsData=GPS-Daten
status=Status
status=Status
noDataFound=Keine Daten gefunden
@@ -2112,7 +2112,7 @@ public class LeaderboardPanel extends FormPanel implements TimeListener, PlaySta
}
private boolean shallExpandRaceColumn(RaceColumnDTO raceColumnDTO) {
return showRaceDetails && raceColumnDTO.hasTrackedRaces();
return showRaceDetails && raceColumnDTO.hasTrackedRaces() && raceColumnDTO.hasGPSData() && raceColumnDTO.hasWindData();
}
private void removeUnusedRaceColumns(LeaderboardDTO leaderboard) {
@@ -488,11 +488,13 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
for (Fleet fleet : raceColumn.getFleets()) {
TimePoint latestTimePointAfterQueryTimePointWhenATrackedRaceWasLive = null;
RegattaAndRaceIdentifier raceIdentifier = null;
RaceDTO race = null;
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
final FleetDTO fleetDTO = convertToFleetDTO(fleet);
if (trackedRace != null) {
raceIdentifier = new RegattaNameAndRaceName(trackedRace.getTrackedRegatta().getRegatta()
.getName(), trackedRace.getRace().getName());
race = createRaceDTO(false, raceIdentifier, trackedRace);
if (trackedRace.hasStarted(timePoint) && trackedRace.hasGPSData() && trackedRace.hasWindData()) {
TimePoint liveTimePointForTrackedRace = timePoint;
final TimePoint endOfRace = trackedRace.getEndOfRace();
@@ -502,10 +504,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
latestTimePointAfterQueryTimePointWhenATrackedRaceWasLive = liveTimePointForTrackedRace;
}
}
// Note: the RaceColumnDTO won't be created by the following addRace call because it has been created
// above by the result.createEmptyRaceColumn call
result.addRace(raceColumn.getName(), raceColumn.getExplicitFactor(), fleetDTO,
raceColumn.isMedalRace(), raceIdentifier, /* StrippedRaceDTO */ null);
raceColumn.isMedalRace(), raceIdentifier, race);
if (latestTimePointAfterQueryTimePointWhenATrackedRaceWasLive != null) {
raceColumnDTO.setWhenLastTrackedRaceWasLive(fleetDTO, latestTimePointAfterQueryTimePointWhenATrackedRaceWasLive.asDate());
}
@@ -2078,17 +2081,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
delayToLiveInMillisForLatestRace = trackedRace.getDelayToLiveInMillis();
}
raceIdentifier = new RegattaNameAndRaceName(trackedRace.getTrackedRegatta().getRegatta().getName(), trackedRace.getRace().getName());
// Optional: Getting the places of the race
PlacemarkOrderDTO racePlaces = withGeoLocationData ? getRacePlaces(trackedRace) : null;
TrackedRaceDTO trackedRaceDTO = new TrackedRaceDTO();
trackedRaceDTO.startOfTracking = trackedRace.getStartOfTracking() == null ? null : trackedRace.getStartOfTracking().asDate();
trackedRaceDTO.hasWindData = trackedRace.hasWindData();
trackedRaceDTO.hasGPSData = trackedRace.hasGPSData();
raceDTO = new RaceDTO(raceIdentifier, trackedRaceDTO, getService().isRaceBeingTracked(trackedRace.getRace()));
raceDTO.places = racePlaces;
raceDTO.startOfRace = trackedRace.getStartOfRace() == null ? null : trackedRace.getStartOfRace().asDate();
raceDTO.endOfRace = trackedRace.getEndOfRace() == null ? null : trackedRace.getEndOfRace().asDate();
raceDTO = createRaceDTO(withGeoLocationData, raceIdentifier, trackedRace);
if (trackedRace.hasStarted(now) && trackedRace.hasGPSData() && trackedRace.hasWindData()) {
TimePoint liveTimePointForTrackedRace = now;
final TimePoint endOfRace = trackedRace.getEndOfRace();
@@ -2109,6 +2102,21 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
return leaderboardDTO;
}
private RaceDTO createRaceDTO(boolean withGeoLocationData, RegattaAndRaceIdentifier raceIdentifier, TrackedRace trackedRace) {
// Optional: Getting the places of the race
PlacemarkOrderDTO racePlaces = withGeoLocationData ? getRacePlaces(trackedRace) : null;
TrackedRaceDTO trackedRaceDTO = new TrackedRaceDTO();
trackedRaceDTO.startOfTracking = trackedRace.getStartOfTracking() == null ? null : trackedRace.getStartOfTracking().asDate();
trackedRaceDTO.hasWindData = trackedRace.hasWindData();
trackedRaceDTO.hasGPSData = trackedRace.hasGPSData();
RaceDTO raceDTO = new RaceDTO(raceIdentifier, trackedRaceDTO, getService().isRaceBeingTracked(trackedRace.getRace()));
raceDTO.places = racePlaces;
raceDTO.startOfRace = trackedRace.getStartOfRace() == null ? null : trackedRace.getStartOfRace().asDate();
raceDTO.endOfRace = trackedRace.getEndOfRace() == null ? null : trackedRace.getEndOfRace().asDate();
return raceDTO;
}
private PlacemarkOrderDTO getRacePlaces(TrackedRace trackedRace) {
Pair<Placemark, Placemark> startAndFinish = getStartFinishPlacemarksForTrackedRace(trackedRace);
PlacemarkOrderDTO racePlaces = new PlacemarkOrderDTO();
@@ -2503,6 +2511,15 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName);
result = leaderboard == null ? null : (double) leaderboard.getTotalRankOfCompetitor(competitor, timePoint);
break;
case OVERALL_RANK:
if (leaderboardGroupName == null || leaderboardGroupName.isEmpty()) {
break;
}
LeaderboardGroup group = getService().getLeaderboardGroupByName(leaderboardGroupName);
Leaderboard overall = group.getOverallLeaderboard();
result = overall == null ? null : (double) overall.getTotalRankOfCompetitor(competitor, timePoint);
break;
default:
throw new UnsupportedOperationException("Theres currently no support for the enum value '"
+ dataType + "' in this method.");
@@ -2536,9 +2553,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
try {
for (MarkPassing markPassing : competitorMarkPassings) {
MillisecondsTimePoint time = new MillisecondsTimePoint(markPassing.getTimePoint().asMillis());
markPassingsData.add(new Triple<String, Date, Double>(markPassing.getWaypoint().getName(),
time.asDate(),
getCompetitorRaceDataEntry(detailType, trackedRace, competitor, time, leaderboardGroupName, leaderboardName)));
Double competitorMarkPassingsData = getCompetitorRaceDataEntry(detailType, trackedRace, competitor, time, leaderboardGroupName, leaderboardName);
if (competitorMarkPassingsData != null) {
markPassingsData.add(new Triple<String, Date, Double>(markPassing.getWaypoint()
.getName(), time.asDate(), competitorMarkPassingsData));
}
}
} finally {
trackedRace.unlockAfterRead(competitorMarkPassings);
@@ -2547,8 +2566,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
if (startTime != null && endTime != null) {
for (long i = startTime.asMillis(); i <= endTime.asMillis(); i += stepSizeInMs) {
MillisecondsTimePoint time = new MillisecondsTimePoint(i);
raceData.add(new Pair<Date, Double>(time.asDate(), getCompetitorRaceDataEntry(detailType, trackedRace,
competitor, time, leaderboardGroupName, leaderboardName)));
Double competitorRaceData = getCompetitorRaceDataEntry(detailType, trackedRace, competitor, time, leaderboardGroupName, leaderboardName);
if (competitorRaceData != null) {
raceData.add(new Pair<Date, Double>(time.asDate(), competitorRaceData));
}
}
}
result.setCompetitorData(competitorDTO, new CompetitorRaceDataDTO(competitorDTO, detailType, markPassingsData, raceData));
@@ -112,7 +112,12 @@ public class CompetitorsRaceDataDTO implements IsSerializable {
}
public boolean isEmpty() {
return competitorsData.isEmpty();
for (CompetitorRaceDataDTO competitorRaceData : competitorsData.values()) {
if (!competitorRaceData.getRaceData().isEmpty()) {
return false;
}
}
return true;
}
public boolean contains(CompetitorDTO competitor) {
@@ -155,6 +155,46 @@ public class RaceColumnDTO extends NamedDTO implements IsSerializable {
return result;
}
public boolean containsRace(RaceIdentifier preSelectedRace) {
return trackedRaceIdentifiersPerFleet.values().contains(preSelectedRace);
}
public boolean hasTrackedRaces() {
Set<RegattaAndRaceIdentifier> raceIdentifiers = new HashSet<RegattaAndRaceIdentifier>(trackedRaceIdentifiersPerFleet.values());
raceIdentifiers.remove(null);
return !raceIdentifiers.isEmpty();
}
public void addFleet(FleetDTO fleet) {
fleets.add(fleet);
}
private Date getWhenLastTrackedRaceWasLive(FleetDTO fleet) {
return whenLastTrackedRaceWasLiveByFleet.get(fleet);
}
public void setWhenLastTrackedRaceWasLive(FleetDTO fleet, Date whenLastTrackedRaceWasLive) {
this.whenLastTrackedRaceWasLiveByFleet.put(fleet, whenLastTrackedRaceWasLive);
}
public boolean hasGPSData() {
for (RaceDTO race : racesPerFleet.values()) {
if (race != null && race.trackedRace != null && race.trackedRace.hasGPSData) {
return true;
}
}
return false;
}
public boolean hasWindData() {
for (RaceDTO race : racesPerFleet.values()) {
if (race != null && race.trackedRace != null && race.trackedRace.hasWindData) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
final int prime = 31;
@@ -194,26 +234,4 @@ public class RaceColumnDTO extends NamedDTO implements IsSerializable {
return false;
return true;
}
public boolean containsRace(RaceIdentifier preSelectedRace) {
return trackedRaceIdentifiersPerFleet.values().contains(preSelectedRace);
}
public boolean hasTrackedRaces() {
Set<RegattaAndRaceIdentifier> raceIdentifiers = new HashSet<RegattaAndRaceIdentifier>(trackedRaceIdentifiersPerFleet.values());
raceIdentifiers.remove(null);
return !raceIdentifiers.isEmpty();
}
public void addFleet(FleetDTO fleet) {
fleets.add(fleet);
}
private Date getWhenLastTrackedRaceWasLive(FleetDTO fleet) {
return whenLastTrackedRaceWasLiveByFleet.get(fleet);
}
public void setWhenLastTrackedRaceWasLive(FleetDTO fleet, Date whenLastTrackedRaceWasLive) {
this.whenLastTrackedRaceWasLiveByFleet.put(fleet, whenLastTrackedRaceWasLive);
}
}
@@ -75,6 +75,7 @@ public abstract class AbstractChartPanel<SettingsType extends ChartSettings> ext
private static final int MAX_SERIES_POINTS = 10000;
private final Label noCompetitorsSelectedLabel;
private final Label noDataFoundLabel;
private final CompetitorSelectionProvider competitorSelectionProvider;
private DetailType selectedDetailType;
@@ -115,6 +116,8 @@ public abstract class AbstractChartPanel<SettingsType extends ChartSettings> ext
setSize("100%", "100%");
noCompetitorsSelectedLabel = new Label(stringMessages.selectAtLeastOneCompetitor() + ".");
noCompetitorsSelectedLabel.setStyleName("abstractChartPanel-importantMessageOfChart");
noDataFoundLabel = new Label(stringMessages.noDataFound() + ".");
noDataFoundLabel.setStyleName("abstractChartPanel-importantMessageOfChart");
createChart();
setSelectedDetailType(detailType);
@@ -225,7 +228,11 @@ public abstract class AbstractChartPanel<SettingsType extends ChartSettings> ext
hideLoading();
if (result != null) {
updateChartSeries(result, append);
if (result.isEmpty()) {
setWidget(noDataFoundLabel);
} else {
updateChartSeries(result, append);
}
} else {
if (!append) {
clearChart();
@@ -499,8 +506,7 @@ public abstract class AbstractChartPanel<SettingsType extends ChartSettings> ext
} else {
chart.getYAxis().setAxisTitleText(label);
}
chart.getYAxis().setReversed(
selectedDetailType == DetailType.WINDWARD_DISTANCE_TO_OVERALL_LEADER || selectedDetailType == DetailType.GAP_TO_LEADER_IN_SECONDS);
chart.getYAxis().setReversed(isYAxisReversed());
final NumberFormat numberFormat = DetailTypeFormatter.getNumberFormat(selectedDetailType);
chart.setToolTip(new ToolTip().setEnabled(true).setFormatter(new ToolTipFormatter() {
@Override
@@ -522,6 +528,14 @@ public abstract class AbstractChartPanel<SettingsType extends ChartSettings> ext
return hasDetailTypeChanged;
}
private boolean isYAxisReversed() {
return selectedDetailType == DetailType.WINDWARD_DISTANCE_TO_OVERALL_LEADER ||
selectedDetailType == DetailType.GAP_TO_LEADER_IN_SECONDS ||
selectedDetailType == DetailType.RACE_RANK ||
selectedDetailType == DetailType.REGATTA_RANK ||
selectedDetailType == DetailType.OVERALL_RANK;
}
@Override
public void onRaceSelectionChange(List<RegattaAndRaceIdentifier> selectedRaces) {
if (selectedRaces != null && !selectedRaces.isEmpty()) {
@@ -22,7 +22,6 @@ import org.moxieapps.gwt.highcharts.client.ToolTipFormatter;
import org.moxieapps.gwt.highcharts.client.labels.AxisLabelsData;
import org.moxieapps.gwt.highcharts.client.labels.AxisLabelsFormatter;
import org.moxieapps.gwt.highcharts.client.labels.XAxisLabels;
import org.moxieapps.gwt.highcharts.client.labels.YAxisLabels;
import org.moxieapps.gwt.highcharts.client.plotOptions.LinePlotOptions;
import org.moxieapps.gwt.highcharts.client.plotOptions.Marker;
import org.moxieapps.gwt.highcharts.client.plotOptions.Marker.Symbol;
@@ -87,7 +86,7 @@ public class LeaderboardRankChart extends SimplePanel implements RequiresResize,
@Override
public String format(ToolTipData toolTipData) {
String seriesName = toolTipData.getSeriesName();
return "<b>" + seriesName + ":</b> " + stringMessages.rankNAfterRace(-toolTipData.getYAsLong(),
return "<b>" + seriesName + ":</b> " + stringMessages.rankNAfterRace(toolTipData.getYAsLong(),
raceColumnNames.get((int) toolTipData.getXAsLong()));
}
}));
@@ -99,14 +98,7 @@ public class LeaderboardRankChart extends SimplePanel implements RequiresResize,
}
}));
chart.getYAxis().setAllowDecimals(false).setStartOnTick(true).setEndOnTick(true).setAxisTitleText(stringMessages.rank())
.setShowFirstLabel(false).setShowLastLabel(false)
.setLabels(new YAxisLabels().setFormatter(new AxisLabelsFormatter() {
@Override
public String format(AxisLabelsData axisLabelsData) {
// invert signum to ensure best are at the top
return "" + (-axisLabelsData.getValueAsLong());
}
}));
.setShowFirstLabel(false).setShowLastLabel(false).setReversed(true);
if (compactChart) {
chart.setSpacingBottom(10).setSpacingLeft(10).setSpacingRight(10).setSpacingTop(2)
.setOption("legend/margin", 2)
@@ -145,12 +137,13 @@ public class LeaderboardRankChart extends SimplePanel implements RequiresResize,
if (Util.isEmpty(competitorSelectionProvider.getSelectedCompetitors()) ||
competitorSelectionProvider.isSelected(competitor)) {
Series series = getOrCreateSeries(competitor);
series.addPoint(raceNumber, rank, /* redraw */ false, /* shift */ false, /* animation */ false);
unusedSeries.remove(series);
if (!chartSeries.contains(series)) {
chart.addSeries(series);
chartSeries.add(series);
}
series.addPoint(raceNumber, -rank, /* redraw */ false, /* shift */ false, /* animation */ false);
}
rank++;
}
@@ -31,6 +31,7 @@ public class MultiChartSettingsComponent extends AbstractChartSettingsComponent<
availableDetailsTypes.add(DetailType.CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
availableDetailsTypes.add(DetailType.RACE_RANK);
availableDetailsTypes.add(DetailType.REGATTA_RANK);
availableDetailsTypes.add(DetailType.OVERALL_RANK);
}
@Override
@@ -143,7 +143,7 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
for(RegattaDTO regattaDTO: regattaDTOs) {
regattasByName.put(regattaDTO.name, regattaDTO);
}
createdPageContent();
createPageContent();
}
@Override
@@ -152,7 +152,7 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
}
});
} else {
createdPageContent();
createPageContent();
}
} else {
errorReporter.reportError(stringMessages.noLeaderboardGroupWithNameFound(leaderboardGroupName));
@@ -165,7 +165,7 @@ public class LeaderboardGroupPanel extends FormPanel implements HasWelcomeWidget
});
}
private void createdPageContent() {
private void createPageContent() {
if (!isEmbedded) {
Label groupNameLabel = new Label(leaderboardGroup.name + ":");
groupNameLabel.setStyleName(STYLE_NAME_PREFIX + "GroupName");