show ORC PCS leg editing actions for tracked races only if they have an ORC PCS-based ranking metric

Change-Id: I2f1b85da262dc2b679cf8a879d03fd81d9efcd75
This commit is contained in:
Axel Uhl committed 2019-10-22 14:44:34 +02:00
1 parent e502f5bf90
commit 09e43b5e41
14 files changed
+97 -31

No files matched your search

@@ -1,5 +1,6 @@
package com.sap.sailing.domain.common.dto;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.security.SecuredDomainType;
@@ -38,18 +39,25 @@ public class RaceDTO extends BasicRaceDTO implements SecuredDTO {
private String regattaName;
public String boatClass;
private RankingMetrics rankingMetricType;
public RaceDTO() {}
public RaceDTO(RegattaAndRaceIdentifier raceIdentifier, TrackedRaceDTO trackedRace, boolean isCurrentlyTracked) {
public RaceDTO(RegattaAndRaceIdentifier raceIdentifier, TrackedRaceDTO trackedRace, boolean isCurrentlyTracked, RankingMetrics rankingMetricType) {
super(raceIdentifier, trackedRace);
this.regattaName = raceIdentifier.getRegattaName();
this.isTracked = isCurrentlyTracked;
this.rankingMetricType = rankingMetricType;
}
public RegattaAndRaceIdentifier getRaceIdentifier() {
return new RegattaNameAndRaceName(regattaName, getName());
}
public RankingMetrics getRankingMetricType() {
return rankingMetricType;
}
public String getRegattaName() {
return regattaName;
}
@@ -197,7 +197,7 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl implements Domain
PlacemarkOrderDTO racePlaces = withGeoLocationData ? getRacePlaces(trackedRace) : null;
TrackedRaceDTO trackedRaceDTO = createTrackedRaceDTO(trackedRace);
RaceDTO raceDTO = new RaceDTO(raceIdentifier, trackedRaceDTO, trackedRegattaRegistry.isRaceBeingTracked(
trackedRace.getTrackedRegatta().getRegatta(), trackedRace.getRace()));
trackedRace.getTrackedRegatta().getRegatta(), trackedRace.getRace()), trackedRace.getRankingMetric().getType());
raceDTO.places = racePlaces;
updateRaceDTOWithTrackedRaceData(trackedRace, raceDTO);
return raceDTO;
@@ -41,6 +41,7 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.common.orc.ORCCertificate;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveCourse;
import com.sap.sailing.domain.common.orc.ORCPerformanceCurveLeg;
@@ -115,6 +116,11 @@ public class ORCPerformanceCurveByImpliedWindRankingMetric extends AbstractRanki
updateCourseFromRaceLogs();
}
@Override
public RankingMetrics getType() {
return RankingMetrics.ORC_PERFORMANCE_CURVE_BY_IMPLIED_WIND;
}
private void initializeListeners() {
certificatesAndCourseAndScratchBoatFromRaceLogUpdater = createCertificatesFromRaceLogAndCourseAndScratchBoatUpdater();
certificatesFromRegattaLogUpdater = createCertificatesFromRegattaLogUpdater();
@@ -13,6 +13,7 @@ import java.util.logging.Logger;
import org.apache.commons.math.FunctionEvaluationException;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.orc.ORCPerformanceCurve;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
@@ -39,6 +40,11 @@ public class ORCPerformanceCurveRankingMetric extends ORCPerformanceCurveByImpli
super(trackedRace);
}
@Override
public RankingMetrics getType() {
return RankingMetrics.ORC_PERFORMANCE_CURVE;
}
/**
* As opposed to before 2015 when implied wind was the only ranking criterion at all times, in 2015
* it was decided to rank based on corrected times, and corrected times shall be computed not by mapping
@@ -5,6 +5,7 @@ import java.util.HashSet;
import java.util.Set;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindLegTypeAndLegBearingAndORCPerformanceCurveCache;
import com.sap.sse.common.TimePoint;
@@ -29,6 +30,11 @@ public class ORCPerformanceCurveRankingMetricLeaderForBaseline extends ORCPerfor
super(trackedRace);
}
@Override
public RankingMetrics getType() {
return RankingMetrics.ORC_PERFORMANCE_CURVE_LEADER_FOR_BASELINE;
}
@Override
protected Competitor getBaseLineCompetitorForAbsoluteCorrectedTimes(TimePoint timePoint,
WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
@@ -8,6 +8,7 @@ import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
@@ -27,6 +28,11 @@ public class OneDesignRankingMetric extends NonPerformanceCurveRankingMetric {
super(trackedRace);
}
@Override
public RankingMetrics getType() {
return RankingMetrics.ONE_DESIGN;
}
@Override
public Comparator<Competitor> getRaceRankingComparator(TimePoint timePoint, WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
return new RaceRankComparator(getTrackedRace(), timePoint, cache);
@@ -6,6 +6,7 @@ import java.util.function.Function;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
@@ -141,6 +142,8 @@ public interface RankingMetric extends Serializable {
* @return the tracked race to which this ranking metric is specific
*/
TrackedRace getTrackedRace();
RankingMetrics getType();
default Comparator<Competitor> getRaceRankingComparator(TimePoint timePoint) {
return getRaceRankingComparator(timePoint, new LeaderboardDTOCalculationReuseCache(timePoint));
@@ -11,6 +11,7 @@ import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.Mile;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedLeg;
import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor;
@@ -76,6 +77,11 @@ public class TimeOnTimeAndDistanceRankingMetric extends NonPerformanceCurveRanki
this.timeOnDistanceFactorNauticalMile = timeOnDistanceFactorInSecondsPerNauticalMile;
}
@Override
public RankingMetrics getType() {
return RankingMetrics.TIME_ON_TIME_AND_DISTANCE;
}
/**
* Ranks the competitors by their average corrected velocity made good, determined by the following formula:
*
@@ -7,6 +7,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Supplier;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -124,8 +125,14 @@ public abstract class CourseManagementWidget implements IsWidget {
return mainPanel;
}
/**
* @param showOrcPcsLegEditActions
* Depending on the ranking metric it may or may not make sense to show the user the actions to maintain
* ORC PCS leg data. By default, these actions are enabled, particularly to cover the case where this
* widget is used without an existing {@code TrackedRace} and only with a race log.
*/
public CourseManagementWidget(final SailingServiceAsync sailingService, ErrorReporter errorReporter,
final StringMessages stringMessages, final UserService userService) {
final StringMessages stringMessages, final UserService userService, final Supplier<Boolean> showOrcPcsLegEditActions) {
this.sailingService = sailingService;
this.errorReporter = errorReporter;
this.stringMessages = stringMessages;
@@ -162,7 +169,7 @@ public abstract class CourseManagementWidget implements IsWidget {
mainPanel.setWidget(1, 1, controlPointsBtnsPanel);
mainPanel.setWidget(1, 2, marksBtnsPanel);
final AccessControlledActionsColumn<WaypointDTO, WaypointImagesBarCell> waypointsActionColumn = create(
new WaypointImagesBarCell(stringMessages, waypoints.getDataProvider()), userService,
new WaypointImagesBarCell(stringMessages, waypoints.getDataProvider(), showOrcPcsLegEditActions), userService,
s -> securedDtoForWaypointsPermissionCheck);
// update permission for tracked race is required for deleting waypoints...
waypointsActionColumn.addAction(DefaultActions.DELETE.name(), DefaultActions.UPDATE,
@@ -405,7 +412,7 @@ public abstract class CourseManagementWidget implements IsWidget {
}).show();
}
public void refresh(){};
public abstract void refresh();
protected void updateWaypointsAndControlPoints(RaceCourseDTO raceCourseDTO, String leaderboardName) {
this.sailingService.getLeaderboardWithSecurity(leaderboardName,
@@ -431,7 +438,6 @@ public abstract class CourseManagementWidget implements IsWidget {
waypoints.getDataProvider().getList().clear();
multiMarkControlPoints.getDataProvider().getList().clear();
waypoints.getDataProvider().getList().addAll(raceCourseDTO.waypoints);
Map<String, ControlPointDTO> noDuplicateCPs = new HashMap<>();
for (ControlPointDTO controlPoint : raceCourseDTO.getControlPoints()) {
if (controlPoint instanceof GateDTO) {
@@ -439,9 +445,7 @@ public abstract class CourseManagementWidget implements IsWidget {
}
}
multiMarkControlPoints.getDataProvider().getList().addAll(noDuplicateCPs.values());
updateWaypointButtons();
final boolean hasUpdatePermission = userService.hasPermission(securedDTO, DefaultActions.UPDATE);
insertWaypointAfter.setVisible(hasUpdatePermission);
insertWaypointBefore.setVisible(hasUpdatePermission);
@@ -9,6 +9,7 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.common.orc.impl.ORCPerformanceCurveLegImpl;
import com.sap.sailing.gwt.ui.client.RegattaRefresher;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
@@ -35,7 +36,7 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
RegattaRefresher regattaRefresher, final StringMessages stringMessages, final UserService userService) {
super(sailingService, userService, errorReporter, regattaRefresher, /* actionButtonsEnabled */ false, stringMessages);
courseManagementWidget = new CourseManagementWidget(sailingService, errorReporter, stringMessages,
userService) {
userService, ()->selectedRaceHasOrcPcsRankingMetric()) {
@Override
protected void save() {
sailingService.updateRaceCourse(singleSelectedRace, createWaypointPairs(), new AsyncCallback<Void>() {
@@ -94,18 +95,20 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
}
private void refreshORCPerformanceCurveLegs() {
sailingService.getORCPerformanceCurveLegInfo(singleSelectedRace,
new AsyncCallback<Map<Integer, ORCPerformanceCurveLegImpl>>() {
@Override
public void onSuccess(Map<Integer, ORCPerformanceCurveLegImpl> result) {
refreshORCPerformanceCurveLegs(result);
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Could not load ORC Performance Curve leg information: " + caught.getMessage());
}
});
if (singleSelectedRace != null) {
sailingService.getORCPerformanceCurveLegInfo(singleSelectedRace,
new AsyncCallback<Map<Integer, ORCPerformanceCurveLegImpl>>() {
@Override
public void onSuccess(Map<Integer, ORCPerformanceCurveLegImpl> result) {
refreshORCPerformanceCurveLegs(result);
}
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError("Could not load ORC Performance Curve leg information: " + caught.getMessage());
}
});
}
}
};
FlowPanel courseManagementPanel = new FlowPanel();
@@ -134,6 +137,13 @@ public class RaceCourseManagementPanel extends AbstractRaceManagementPanel {
this.selectedRaceContentPanel.add(buttonsPanel);
}
private boolean selectedRaceHasOrcPcsRankingMetric() {
final RankingMetrics rankingMetricType = selectedRaceDTO == null ? null : selectedRaceDTO.getRankingMetricType();
return rankingMetricType == RankingMetrics.ORC_PERFORMANCE_CURVE ||
rankingMetricType == RankingMetrics.ORC_PERFORMANCE_CURVE_BY_IMPLIED_WIND ||
rankingMetricType == RankingMetrics.ORC_PERFORMANCE_CURVE_LEADER_FOR_BASELINE;
}
@Override
void refreshSelectedRaceData() {
courseManagementWidget.refresh();
@@ -30,7 +30,7 @@ public class RaceLogCourseManagementWidget extends CourseManagementWidget {
public RaceLogCourseManagementWidget(final SailingServiceAsync sailingService, final ErrorReporter errorReporter,
final StringMessages stringMessages, final String leaderboardName, final String raceColumnName,
final String fleetName, final UserService userService) {
super(sailingService, errorReporter, stringMessages, userService);
super(sailingService, errorReporter, stringMessages, userService, /* always show ORC OCS leg data actions */ ()->true);
this.leaderboardName = leaderboardName;
this.raceColumnName = raceColumnName;
this.fleetName = fleetName;
@@ -2,6 +2,7 @@ package com.sap.sailing.gwt.ui.adminconsole;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import com.google.gwt.core.client.GWT;
import com.google.gwt.view.client.ListDataProvider;
@@ -15,9 +16,12 @@ public class WaypointImagesBarCell extends DefaultActionsImagesBarCell {
private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class);
private final StringMessages stringMessages;
private final ListDataProvider<WaypointDTO> waypointList;
private final Supplier<Boolean> showOrcPcsLegActions;
public WaypointImagesBarCell(final StringMessages stringMessages, ListDataProvider<WaypointDTO> waypointList) {
public WaypointImagesBarCell(final StringMessages stringMessages, ListDataProvider<WaypointDTO> waypointList,
Supplier<Boolean> showOrcPcsLegActions) {
super(stringMessages);
this.showOrcPcsLegActions = showOrcPcsLegActions;
this.stringMessages = stringMessages;
this.waypointList = waypointList;
}
@@ -27,10 +31,12 @@ public class WaypointImagesBarCell extends DefaultActionsImagesBarCell {
final WaypointDTO waypoint = (WaypointDTO) getContext().getKey();
final List<ImageSpec> imageSpecs = new ArrayList<>();
imageSpecs.add(getDeleteImageSpec());
if (waypoint != waypointList.getList().get(0)) {
imageSpecs.add(new ImageSpec(ACTION_ORC_PCS_DEFINE_LEG, stringMessages.actionDefineLegForOrcPcs(), resources.orcPcsDefineLegIcon()));
} else {
imageSpecs.add(new ImageSpec(ACTION_ORC_PCS_DEFINE_ALL_LEGS, stringMessages.actionDefineAllLegsForOrcPcs(), resources.orcPcsDefineAllLegsIcon()));
if (showOrcPcsLegActions.get()) {
if (waypoint != waypointList.getList().get(0)) {
imageSpecs.add(new ImageSpec(ACTION_ORC_PCS_DEFINE_LEG, stringMessages.actionDefineLegForOrcPcs(), resources.orcPcsDefineLegIcon()));
} else {
imageSpecs.add(new ImageSpec(ACTION_ORC_PCS_DEFINE_ALL_LEGS, stringMessages.actionDefineAllLegsForOrcPcs(), resources.orcPcsDefineAllLegsIcon()));
}
}
return imageSpecs;
}
@@ -1278,12 +1278,16 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
RegattaAndRaceIdentifier raceIdentifier = new RegattaNameAndRaceName(regatta.getName(), r.getName());
TrackedRace trackedRace = getService().getExistingTrackedRace(raceIdentifier);
TrackedRaceDTO trackedRaceDTO = null;
final RankingMetrics rankingMetricType;
if (trackedRace != null) {
trackedRaceDTO = getBaseDomainFactory().createTrackedRaceDTO(trackedRace);
rankingMetricType = trackedRace.getRankingMetric().getType();
} else {
rankingMetricType = null;
}
Map<CompetitorDTO, BoatDTO> competitorAndBoatDTOs = baseDomainFactory.convertToCompetitorAndBoatDTOs(r.getCompetitorsAndTheirBoats());
RaceWithCompetitorsAndBoatsDTO raceDTO = new RaceWithCompetitorsAndBoatsDTO(raceIdentifier, competitorAndBoatDTOs,
trackedRaceDTO, getService().isRaceBeingTracked(regatta, r));
trackedRaceDTO, getService().isRaceBeingTracked(regatta, r), rankingMetricType);
if (trackedRace != null) {
SecurityDTOUtil.addSecurityInformation(getSecurityService(), raceDTO, trackedRace.getIdentifier());
getBaseDomainFactory().updateRaceDTOWithTrackedRaceData(trackedRace, raceDTO);
@@ -1993,7 +1997,7 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
.convertToCompetitorAndBoatDTOs(race.getCompetitorsAndTheirBoats());
TrackedRaceDTO trackedRaceDTO = getBaseDomainFactory().createTrackedRaceDTO(trackedRace);
raceDTO = new RaceWithCompetitorsAndBoatsDTO(raceIdentifier, competitorsAndBoats, trackedRaceDTO,
getService().isRaceBeingTracked(regatta, race));
getService().isRaceBeingTracked(regatta, race), trackedRace.getRankingMetric().getType());
if (trackedRace != null) {
getBaseDomainFactory().updateRaceDTOWithTrackedRaceData(trackedRace, raceDTO);
}
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.shared;
import java.util.Collection;
import java.util.Map;
import com.sap.sailing.domain.common.RankingMetrics;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.dto.BoatDTO;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
@@ -19,8 +20,8 @@ public class RaceWithCompetitorsAndBoatsDTO extends RaceDTO {
RaceWithCompetitorsAndBoatsDTO() {}
public RaceWithCompetitorsAndBoatsDTO(RegattaAndRaceIdentifier raceIdentifier, Map<CompetitorDTO, BoatDTO> competitorsAndBoats,
TrackedRaceDTO trackedRace, boolean isCurrentlyTracked) {
super(raceIdentifier, trackedRace, isCurrentlyTracked);
TrackedRaceDTO trackedRace, boolean isCurrentlyTracked, RankingMetrics rankingMetricType) {
super(raceIdentifier, trackedRace, isCurrentlyTracked, rankingMetricType);
this.competitorsAndBoats = competitorsAndBoats;
}