mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-17 01:31:01 +00:00
Checking only Permission.CAN_REPLAY_DURING_LIVE_RACES to provide
respective functionality (removed url parameter handling)
This commit is contained in:
1 parent
6bb463af27
commit
5ba87eb856
5 files changed
+342
-319
No files matched your search
+1
-1
@@ -79,7 +79,7 @@ public class PlayerActivity extends AbstractActivity {
|
||||
final String defaultMedia = GwtHttpRequestUtils.getStringParameter(RaceBoardViewConfiguration.PARAM_DEFAULT_MEDIA, null /* default */);
|
||||
|
||||
return new RaceBoardViewConfiguration(activeCompetitorsFilterSetName, showLeaderboard,
|
||||
showWindChart, showCompetitorsChart, showViewStreamlets, showViewStreamletColors, showViewSimulation, /* canReplayWhileLiveIsPossible */false, autoSelectMedia, defaultMedia);
|
||||
showWindChart, showCompetitorsChart, showViewStreamlets, showViewStreamletColors, showViewSimulation, autoSelectMedia, defaultMedia);
|
||||
}
|
||||
|
||||
private void createErrorView(String errorMessage, Throwable errorReason, AcceptsOneWidget panel) {
|
||||
|
||||
+334
-299
@@ -1,299 +1,334 @@
|
||||
package com.sap.sailing.gwt.ui.client;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
|
||||
import com.sap.sailing.gwt.ui.shared.MarkPassingTimesDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.gwt.client.player.TimeRangeWithZoomProvider;
|
||||
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.SettingsDialogComponent;
|
||||
|
||||
public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements RaceTimesInfoProviderListener {
|
||||
private final RaceTimesInfoProvider raceTimesInfoProvider;
|
||||
|
||||
private RegattaAndRaceIdentifier selectedRace;
|
||||
private boolean autoAdjustPlayMode;
|
||||
private RaceTimesInfoDTO lastRaceTimesInfo;
|
||||
|
||||
/**
|
||||
* When a marker update is required but min/max are not yet initialized, this flag is set. If later
|
||||
* {@link #setMinMax(Date, Date, boolean)} is invoked and this flag is set, a {@link #redrawAllMarkers(RaceTimesInfoDTO)}
|
||||
* will be issued and the flag is cleared.
|
||||
*/
|
||||
private boolean redrawAllMarkersPendingForMinMaxBeingInitialized;
|
||||
|
||||
public RaceTimePanel(Timer timer, TimeRangeWithZoomProvider timeRangeProvider, StringMessages stringMessages,
|
||||
RaceTimesInfoProvider raceTimesInfoProvider, boolean canReplayWhileLiveIsPossible, boolean isScreenLargeEnoughToOfferChartSupport,
|
||||
RegattaAndRaceIdentifier selectedRaceIdentifier) {
|
||||
super(timer, timeRangeProvider, stringMessages, canReplayWhileLiveIsPossible, isScreenLargeEnoughToOfferChartSupport);
|
||||
this.raceTimesInfoProvider = raceTimesInfoProvider;
|
||||
selectedRace = null;
|
||||
autoAdjustPlayMode = true;
|
||||
selectedRace = selectedRaceIdentifier;
|
||||
if (!raceTimesInfoProvider.containsRaceIdentifier(selectedRace)) {
|
||||
raceTimesInfoProvider.addRaceIdentifier(selectedRace, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the race's start time is already known and the <code>time</code> is before the start we can set the count-down label
|
||||
*/
|
||||
@Override
|
||||
protected String getTimeToStartLabelText(Date time) {
|
||||
String result = null;
|
||||
RaceTimesInfoDTO selectedRaceTimes = raceTimesInfoProvider.getRaceTimesInfo(selectedRace);
|
||||
if (selectedRaceTimes.startOfRace != null) {
|
||||
if (time.before(selectedRaceTimes.startOfRace) || time.equals(selectedRaceTimes.startOfRace)) {
|
||||
long timeToStartInMs = selectedRaceTimes.startOfRace.getTime() - time.getTime();
|
||||
result = timeToStartInMs < 1000 ? stringMessages.start() : stringMessages.timeToStart(DateAndTimeFormatterUtil.formatElapsedTime(timeToStartInMs));
|
||||
} else {
|
||||
long timeSinceStartInMs = time.getTime() - selectedRaceTimes.startOfRace.getTime();
|
||||
result = stringMessages.timeSinceStart(DateAndTimeFormatterUtil.formatElapsedTime(timeSinceStartInMs));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSettings(RaceTimePanelSettings newSettings) {
|
||||
super.updateSettings(newSettings);
|
||||
raceTimesInfoProvider.setRequestInterval(newSettings.getRefreshInterval());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTimePanelSettings getSettings() {
|
||||
RaceTimePanelSettings result = new RaceTimePanelSettings();
|
||||
result.setRefreshInterval(timer.getRefreshInterval());
|
||||
result.setRaceTimesInfo(raceTimesInfoProvider.getRaceTimesInfo(selectedRace));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingsDialogComponent<RaceTimePanelSettings> getSettingsDialogComponent() {
|
||||
return new RaceTimePanelSettingsDialogComponent(getSettings(), stringMessages);
|
||||
}
|
||||
|
||||
private void updateTimeInfo(RaceTimesInfoDTO raceTimesInfo) {
|
||||
if (raceTimesInfo == null) {
|
||||
// in case the race is not tracked anymore we reset the time slider
|
||||
resetTimeSlider();
|
||||
} else {
|
||||
// timer will only accept this update if the delay hasn't been updated explicitly
|
||||
timer.setLivePlayDelayInMillis(raceTimesInfo.delayToLiveInMs);
|
||||
if ((raceTimesInfo.startOfTracking != null || raceTimesInfo.startOfRace != null) &&
|
||||
(raceTimesInfo.newestTrackingEvent != null || raceTimesInfo.endOfRace != null || raceTimesInfo.endOfTracking != null)) {
|
||||
// we set here the min and max of the time slider, the start and end of the race as well as the known
|
||||
// leg markers
|
||||
boolean liveModeToBeMadePossible = isLiveModeToBeMadePossible();
|
||||
setLiveGenerallyPossible(liveModeToBeMadePossible);
|
||||
setJumpToLiveEnablement(liveModeToBeMadePossible && timer.getPlayMode() != PlayModes.Live);
|
||||
if (autoAdjustPlayMode && liveModeToBeMadePossible) {
|
||||
timer.setPlayMode(PlayModes.Live);
|
||||
}
|
||||
updatePlayPauseButtonsVisibility(timer.getPlayMode());
|
||||
if (liveModeToBeMadePossible && !canReplayWhileLiveIsPossible() &&
|
||||
timer.getPlayMode()==PlayModes.Replay && timer.getPlayState()==PlayStates.Playing) {
|
||||
// pause timer because it must not be playing in replay mode while the race is live
|
||||
timer.pause();
|
||||
}
|
||||
|
||||
boolean timerAlreadyInitialized = getFromTime() != null && getToTime() != null && timeSlider.getCurrentValue() != null;
|
||||
if (!timeRangeProvider.isZoomed()) {
|
||||
updateMinMax(raceTimesInfo);
|
||||
if (!timerAlreadyInitialized) {
|
||||
initTimerPosition(raceTimesInfo);
|
||||
}
|
||||
updateLegMarkers(raceTimesInfo);
|
||||
}
|
||||
} else {
|
||||
// the tracked race did not start yet or has no events yet
|
||||
// maybe show a special state for this like "Race did not start yet"
|
||||
}
|
||||
}
|
||||
lastRaceTimesInfo = raceTimesInfo; // TODO bug 3122: when not redrawn yet because min/max not initialized yet, further redraw is disabled by this.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeZoomChanged(Date zoomStartTimepoint, Date zoomEndTimepoint) {
|
||||
super.onTimeZoomChanged(zoomStartTimepoint, zoomEndTimepoint);
|
||||
timeSlider.setZoomed(true);
|
||||
setMinMax(zoomStartTimepoint, zoomEndTimepoint, false);
|
||||
timeSlider.clearMarkersAndLabelsAndTicks();
|
||||
redrawAllMarkers(lastRaceTimesInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeZoomReset() {
|
||||
super.onTimeZoomReset();
|
||||
timeSlider.setZoomed(false);
|
||||
timeSlider.setMinValue(new Double(timeRangeProvider.getFromTime().getTime()), false);
|
||||
timeSlider.setMaxValue(new Double(timeRangeProvider.getToTime().getTime()), false);
|
||||
timeSlider.setCurrentValue(new Double(timer.getTime().getTime()), true);
|
||||
timeSlider.clearMarkersAndLabelsAndTicks();
|
||||
redrawAllMarkers(lastRaceTimesInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* If and only if the {@link #selectedRace}'s timing is described by the {@link #raceTimesInfoProvider} and
|
||||
* according to the timing the current live time point is after the start of tracking or at least after three
|
||||
* minutes before the race, and the current live time point is not after the end of tracking then live mode will be
|
||||
* made possible (<code>true</code> will be returned).
|
||||
*/
|
||||
@Override
|
||||
protected boolean isLiveModeToBeMadePossible() {
|
||||
long liveTimePointInMillis = timer.getLiveTimePointInMillis();
|
||||
RaceTimesInfoDTO lastRaceTimesInfo = raceTimesInfoProvider != null ? raceTimesInfoProvider.getRaceTimesInfo(selectedRace) : null;
|
||||
return lastRaceTimesInfo != null &&
|
||||
((lastRaceTimesInfo.startOfTracking != null && liveTimePointInMillis > lastRaceTimesInfo.startOfTracking.getTime()) ||
|
||||
(lastRaceTimesInfo.startOfRace != null && liveTimePointInMillis > lastRaceTimesInfo.startOfRace.getTime() - RaceTimesCalculationUtil.MIN_TIME_BEFORE_RACE_START)) &&
|
||||
(lastRaceTimesInfo.endOfTracking == null || liveTimePointInMillis <= lastRaceTimesInfo.endOfTracking.getTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playStateChanged(PlayStates playState, PlayModes playMode) {
|
||||
super.playStateChanged(playState, playMode);
|
||||
switch (playMode) {
|
||||
case Replay:
|
||||
autoAdjustPlayMode = false;
|
||||
break;
|
||||
case Live:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the min/max range for the slider bar from <code>newRaceTimesInfo</code> and adjusts the slider bar if
|
||||
* needed. Since we extend the slider bar to the right when playing across the "end of time," we don't want to
|
||||
* constrain it back again here. Therefore, the max value is never reduced here but at best initially set if it
|
||||
* was <code>null</code> before, or extended to a later point in time.
|
||||
*/
|
||||
private void updateMinMax(RaceTimesInfoDTO newRaceTimesInfo) {
|
||||
Util.Pair<Date, Date> raceMinMax = RaceTimesCalculationUtil.caluclateRaceMinMax(timer, newRaceTimesInfo);
|
||||
|
||||
Date min = raceMinMax.getA();
|
||||
Date max = raceMinMax.getB();
|
||||
|
||||
// never reduce max if it was already set
|
||||
if (min != null && max != null && (getToTime() == null || getToTime().before(max))) {
|
||||
setMinMax(min, max, /* fireEvent */ false); // no event because we guarantee time to be between min and max
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMinMax(Date min, Date max, boolean fireEvent) {
|
||||
super.setMinMax(min, max, fireEvent);
|
||||
if (redrawAllMarkersPendingForMinMaxBeingInitialized && timeSlider.isMinMaxInitialized()) {
|
||||
redrawAllMarkers(lastRaceTimesInfo);
|
||||
redrawAllMarkersPendingForMinMaxBeingInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When in {@link PlayModes#Replay} mode, tries to put the {@link #timer} to the time point when the last leg was
|
||||
* finished first. If this time point is not (yet?) known, tries to put the {@link #timer} to the
|
||||
* {@link RaceTimesInfoDTO#endOfRace end of the race}. If that happens to be undefined (<code>null</code>), the
|
||||
* {@link RaceTimesInfoDTO#startOfRace start of the race} is used instead. If that isn't available either, the timer
|
||||
* remains unchanged.
|
||||
* <p>
|
||||
*
|
||||
* When in {@link PlayModes#Live} mode, tries to advance the timer to the time point of the
|
||||
* {@link RaceTimesInfoDTO#timePointOfNewestEvent timePointOfNewestEvent} received from the tracking infrastructure
|
||||
* so far and puts the timer into {@link PlayStates#Playing play mode}.
|
||||
*/
|
||||
private void initTimerPosition(RaceTimesInfoDTO newRaceTimesInfo) {
|
||||
// initialize timer position
|
||||
switch (timer.getPlayMode()) {
|
||||
case Live:
|
||||
if (newRaceTimesInfo.newestTrackingEvent != null) {
|
||||
timer.setTime(newRaceTimesInfo.newestTrackingEvent.getTime());
|
||||
}
|
||||
timer.play();
|
||||
break;
|
||||
case Replay:
|
||||
// set time to start of race
|
||||
if (newRaceTimesInfo.startOfRace != null) {
|
||||
timer.setTime(newRaceTimesInfo.startOfRace.getTime());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expected to be called before {@link #lastRaceTimesInfo} has been updated to <code>newRaceTimesInfo</code>
|
||||
*/
|
||||
private void updateLegMarkers(RaceTimesInfoDTO newRaceTimesInfo) {
|
||||
boolean requiresMarkerUpdate = true;
|
||||
// updating the sliderbar markers requires a lot of time, therefore we need to do this only if required
|
||||
if (lastRaceTimesInfo != null && lastRaceTimesInfo.markPassingTimes.size() == newRaceTimesInfo.markPassingTimes.size()) {
|
||||
requiresMarkerUpdate = false;
|
||||
int numberOfLegs = newRaceTimesInfo.markPassingTimes.size();
|
||||
for (int i = 0; i < numberOfLegs; i++) {
|
||||
if (!Util.equalsWithNull(newRaceTimesInfo.markPassingTimes.get(i).firstPassingDate, lastRaceTimesInfo.markPassingTimes.get(i).firstPassingDate)) {
|
||||
requiresMarkerUpdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((lastRaceTimesInfo.startOfRace == null && newRaceTimesInfo.startOfRace != null)
|
||||
|| (lastRaceTimesInfo.startOfRace != null && newRaceTimesInfo.startOfRace == null)
|
||||
|| (lastRaceTimesInfo.startOfRace != null && newRaceTimesInfo.startOfRace != null
|
||||
&& lastRaceTimesInfo.startOfRace.getTime() != newRaceTimesInfo.startOfRace.getTime())) {
|
||||
requiresMarkerUpdate = true;
|
||||
}
|
||||
if ((lastRaceTimesInfo.endOfRace == null && newRaceTimesInfo.endOfRace != null)
|
||||
|| (lastRaceTimesInfo.endOfRace != null && newRaceTimesInfo.endOfRace == null)
|
||||
|| (lastRaceTimesInfo.endOfRace != null && newRaceTimesInfo.endOfRace != null
|
||||
&& lastRaceTimesInfo.endOfRace.getTime() != newRaceTimesInfo.endOfRace.getTime())) {
|
||||
requiresMarkerUpdate = true;
|
||||
}
|
||||
}
|
||||
if (requiresMarkerUpdate) {
|
||||
if (timeSlider.isMinMaxInitialized()) { // TODO bug 3122 later, the lastRaceTimesInfo will be updated even if not redrawn because min/max not initialized
|
||||
redrawAllMarkers(newRaceTimesInfo);
|
||||
} else {
|
||||
redrawAllMarkersPendingForMinMaxBeingInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void redrawAllMarkers(RaceTimesInfoDTO newRaceTimesInfo) {
|
||||
List<MarkPassingTimesDTO> markPassingTimes = newRaceTimesInfo.getMarkPassingTimes();
|
||||
timeSlider.clearMarkers();
|
||||
if (newRaceTimesInfo.startOfRace != null) {
|
||||
long markerTime = newRaceTimesInfo.startOfRace.getTime();
|
||||
if (!timeSlider.isZoomed() || (timeSlider.isZoomed() && markerTime > timeSlider.getMinValue() && markerTime < timeSlider.getMaxValue())) {
|
||||
timeSlider.addMarker("S", new Double(markerTime));
|
||||
}
|
||||
}
|
||||
int markPassingCounter = 1;
|
||||
for (MarkPassingTimesDTO markPassingTimesDTO: markPassingTimes) {
|
||||
// ignore the start mark passing
|
||||
if (markPassingCounter > 1 && markPassingTimesDTO.firstPassingDate != null) {
|
||||
long markerTime = markPassingTimesDTO.firstPassingDate.getTime();
|
||||
if (!timeSlider.isZoomed() || (timeSlider.isZoomed() && markerTime > timeSlider.getMinValue() && markerTime < timeSlider.getMaxValue())) {
|
||||
timeSlider.addMarker(markPassingTimesDTO.getName(), new Double(markerTime));
|
||||
}
|
||||
}
|
||||
markPassingCounter++;
|
||||
}
|
||||
if (newRaceTimesInfo.endOfRace != null) {
|
||||
long markerTime = newRaceTimesInfo.endOfRace.getTime();
|
||||
if (!timeSlider.isZoomed() || (timeSlider.isZoomed() && markerTime > timeSlider.getMinValue() && markerTime < timeSlider.getMaxValue())) {
|
||||
timeSlider.addMarker("E", new Double(markerTime));
|
||||
}
|
||||
}
|
||||
timeSlider.redraw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceTimesInfosReceived(Map<RegattaAndRaceIdentifier, RaceTimesInfoDTO> raceTimesInfos, long clientTimeWhenRequestWasSent, Date serverTimeDuringRequest, long clientTimeWhenResponseWasReceived) {
|
||||
timer.adjustClientServerOffset(clientTimeWhenRequestWasSent, serverTimeDuringRequest, clientTimeWhenResponseWasReceived);
|
||||
updateTimeInfo(raceTimesInfos.get(selectedRace));
|
||||
}
|
||||
}
|
||||
package com.sap.sailing.gwt.ui.client;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.security.Permission;
|
||||
import com.sap.sailing.domain.common.security.SailingPermissionsForRoleProvider;
|
||||
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
|
||||
import com.sap.sailing.gwt.ui.shared.MarkPassingTimesDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.gwt.client.player.TimeRangeWithZoomProvider;
|
||||
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.SettingsDialogComponent;
|
||||
import com.sap.sse.security.ui.client.UserService;
|
||||
import com.sap.sse.security.ui.client.UserStatusEventHandler;
|
||||
import com.sap.sse.security.ui.shared.UserDTO;
|
||||
|
||||
public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements RaceTimesInfoProviderListener {
|
||||
private final RaceTimesInfoProvider raceTimesInfoProvider;
|
||||
|
||||
private RegattaAndRaceIdentifier selectedRace;
|
||||
private boolean autoAdjustPlayMode;
|
||||
private RaceTimesInfoDTO lastRaceTimesInfo;
|
||||
private boolean hasCanReplayDuringLiveRacesPermission = false;
|
||||
private final UserService userService;
|
||||
private final UserStatusEventHandler userStatusEventHandler = new UserStatusEventHandler() {
|
||||
@Override
|
||||
public void onUserStatusChange(UserDTO user) {
|
||||
RaceTimePanel.this.hasCanReplayDuringLiveRacesPermission = user != null && user.hasPermission(
|
||||
Permission.CAN_REPLAY_DURING_LIVE_RACES.getStringPermission(), SailingPermissionsForRoleProvider.INSTANCE);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* When a marker update is required but min/max are not yet initialized, this flag is set. If later
|
||||
* {@link #setMinMax(Date, Date, boolean)} is invoked and this flag is set, a {@link #redrawAllMarkers(RaceTimesInfoDTO)}
|
||||
* will be issued and the flag is cleared.
|
||||
*/
|
||||
private boolean redrawAllMarkersPendingForMinMaxBeingInitialized;
|
||||
|
||||
|
||||
public RaceTimePanel(UserService userService, Timer timer, TimeRangeWithZoomProvider timeRangeProvider, StringMessages stringMessages,
|
||||
RaceTimesInfoProvider raceTimesInfoProvider, boolean canReplayWhileLiveIsPossible, boolean isScreenLargeEnoughToOfferChartSupport,
|
||||
RegattaAndRaceIdentifier selectedRaceIdentifier) {
|
||||
super(timer, timeRangeProvider, stringMessages, canReplayWhileLiveIsPossible, isScreenLargeEnoughToOfferChartSupport);
|
||||
this.userService = userService;
|
||||
this.raceTimesInfoProvider = raceTimesInfoProvider;
|
||||
selectedRace = null;
|
||||
autoAdjustPlayMode = true;
|
||||
selectedRace = selectedRaceIdentifier;
|
||||
if (!raceTimesInfoProvider.containsRaceIdentifier(selectedRace)) {
|
||||
raceTimesInfoProvider.addRaceIdentifier(selectedRace, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onLoad() {
|
||||
super.onLoad();
|
||||
userService.addUserStatusEventHandler(userStatusEventHandler);
|
||||
userStatusEventHandler.onUserStatusChange(userService.getCurrentUser());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUnload() {
|
||||
super.onUnload();
|
||||
userService.removeUserStatusEventHandler(userStatusEventHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canReplayWhileLiveIsPossible() {
|
||||
return this.hasCanReplayDuringLiveRacesPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the race's start time is already known and the <code>time</code> is before the start we can set the count-down label
|
||||
*/
|
||||
@Override
|
||||
protected String getTimeToStartLabelText(Date time) {
|
||||
String result = null;
|
||||
RaceTimesInfoDTO selectedRaceTimes = raceTimesInfoProvider.getRaceTimesInfo(selectedRace);
|
||||
if (selectedRaceTimes.startOfRace != null) {
|
||||
if (time.before(selectedRaceTimes.startOfRace) || time.equals(selectedRaceTimes.startOfRace)) {
|
||||
long timeToStartInMs = selectedRaceTimes.startOfRace.getTime() - time.getTime();
|
||||
result = timeToStartInMs < 1000 ? stringMessages.start() : stringMessages.timeToStart(DateAndTimeFormatterUtil.formatElapsedTime(timeToStartInMs));
|
||||
} else {
|
||||
long timeSinceStartInMs = time.getTime() - selectedRaceTimes.startOfRace.getTime();
|
||||
result = stringMessages.timeSinceStart(DateAndTimeFormatterUtil.formatElapsedTime(timeSinceStartInMs));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSettings(RaceTimePanelSettings newSettings) {
|
||||
super.updateSettings(newSettings);
|
||||
raceTimesInfoProvider.setRequestInterval(newSettings.getRefreshInterval());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceTimePanelSettings getSettings() {
|
||||
RaceTimePanelSettings result = new RaceTimePanelSettings();
|
||||
result.setRefreshInterval(timer.getRefreshInterval());
|
||||
result.setRaceTimesInfo(raceTimesInfoProvider.getRaceTimesInfo(selectedRace));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingsDialogComponent<RaceTimePanelSettings> getSettingsDialogComponent() {
|
||||
return new RaceTimePanelSettingsDialogComponent(getSettings(), stringMessages);
|
||||
}
|
||||
|
||||
private void updateTimeInfo(RaceTimesInfoDTO raceTimesInfo) {
|
||||
if (raceTimesInfo == null) {
|
||||
// in case the race is not tracked anymore we reset the time slider
|
||||
resetTimeSlider();
|
||||
} else {
|
||||
// timer will only accept this update if the delay hasn't been updated explicitly
|
||||
timer.setLivePlayDelayInMillis(raceTimesInfo.delayToLiveInMs);
|
||||
if ((raceTimesInfo.startOfTracking != null || raceTimesInfo.startOfRace != null) &&
|
||||
(raceTimesInfo.newestTrackingEvent != null || raceTimesInfo.endOfRace != null || raceTimesInfo.endOfTracking != null)) {
|
||||
// we set here the min and max of the time slider, the start and end of the race as well as the known
|
||||
// leg markers
|
||||
boolean liveModeToBeMadePossible = isLiveModeToBeMadePossible();
|
||||
setLiveGenerallyPossible(liveModeToBeMadePossible);
|
||||
setJumpToLiveEnablement(liveModeToBeMadePossible && timer.getPlayMode() != PlayModes.Live);
|
||||
if (autoAdjustPlayMode && liveModeToBeMadePossible) {
|
||||
timer.setPlayMode(PlayModes.Live);
|
||||
}
|
||||
updatePlayPauseButtonsVisibility(timer.getPlayMode());
|
||||
if (liveModeToBeMadePossible && !canReplayWhileLiveIsPossible() &&
|
||||
timer.getPlayMode()==PlayModes.Replay && timer.getPlayState()==PlayStates.Playing) {
|
||||
// pause timer because it must not be playing in replay mode while the race is live
|
||||
timer.pause();
|
||||
}
|
||||
|
||||
boolean timerAlreadyInitialized = getFromTime() != null && getToTime() != null && timeSlider.getCurrentValue() != null;
|
||||
if (!timeRangeProvider.isZoomed()) {
|
||||
updateMinMax(raceTimesInfo);
|
||||
if (!timerAlreadyInitialized) {
|
||||
initTimerPosition(raceTimesInfo);
|
||||
}
|
||||
updateLegMarkers(raceTimesInfo);
|
||||
}
|
||||
} else {
|
||||
// the tracked race did not start yet or has no events yet
|
||||
// maybe show a special state for this like "Race did not start yet"
|
||||
}
|
||||
}
|
||||
lastRaceTimesInfo = raceTimesInfo; // TODO bug 3122: when not redrawn yet because min/max not initialized yet, further redraw is disabled by this.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeZoomChanged(Date zoomStartTimepoint, Date zoomEndTimepoint) {
|
||||
super.onTimeZoomChanged(zoomStartTimepoint, zoomEndTimepoint);
|
||||
timeSlider.setZoomed(true);
|
||||
setMinMax(zoomStartTimepoint, zoomEndTimepoint, false);
|
||||
timeSlider.clearMarkersAndLabelsAndTicks();
|
||||
redrawAllMarkers(lastRaceTimesInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeZoomReset() {
|
||||
super.onTimeZoomReset();
|
||||
timeSlider.setZoomed(false);
|
||||
timeSlider.setMinValue(new Double(timeRangeProvider.getFromTime().getTime()), false);
|
||||
timeSlider.setMaxValue(new Double(timeRangeProvider.getToTime().getTime()), false);
|
||||
timeSlider.setCurrentValue(new Double(timer.getTime().getTime()), true);
|
||||
timeSlider.clearMarkersAndLabelsAndTicks();
|
||||
redrawAllMarkers(lastRaceTimesInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* If and only if the {@link #selectedRace}'s timing is described by the {@link #raceTimesInfoProvider} and
|
||||
* according to the timing the current live time point is after the start of tracking or at least after three
|
||||
* minutes before the race, and the current live time point is not after the end of tracking then live mode will be
|
||||
* made possible (<code>true</code> will be returned).
|
||||
*/
|
||||
@Override
|
||||
protected boolean isLiveModeToBeMadePossible() {
|
||||
long liveTimePointInMillis = timer.getLiveTimePointInMillis();
|
||||
RaceTimesInfoDTO lastRaceTimesInfo = raceTimesInfoProvider != null ? raceTimesInfoProvider.getRaceTimesInfo(selectedRace) : null;
|
||||
return lastRaceTimesInfo != null &&
|
||||
((lastRaceTimesInfo.startOfTracking != null && liveTimePointInMillis > lastRaceTimesInfo.startOfTracking.getTime()) ||
|
||||
(lastRaceTimesInfo.startOfRace != null && liveTimePointInMillis > lastRaceTimesInfo.startOfRace.getTime() - RaceTimesCalculationUtil.MIN_TIME_BEFORE_RACE_START)) &&
|
||||
(lastRaceTimesInfo.endOfTracking == null || liveTimePointInMillis <= lastRaceTimesInfo.endOfTracking.getTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playStateChanged(PlayStates playState, PlayModes playMode) {
|
||||
super.playStateChanged(playState, playMode);
|
||||
switch (playMode) {
|
||||
case Replay:
|
||||
autoAdjustPlayMode = false;
|
||||
break;
|
||||
case Live:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the min/max range for the slider bar from <code>newRaceTimesInfo</code> and adjusts the slider bar if
|
||||
* needed. Since we extend the slider bar to the right when playing across the "end of time," we don't want to
|
||||
* constrain it back again here. Therefore, the max value is never reduced here but at best initially set if it
|
||||
* was <code>null</code> before, or extended to a later point in time.
|
||||
*/
|
||||
private void updateMinMax(RaceTimesInfoDTO newRaceTimesInfo) {
|
||||
Util.Pair<Date, Date> raceMinMax = RaceTimesCalculationUtil.caluclateRaceMinMax(timer, newRaceTimesInfo);
|
||||
|
||||
Date min = raceMinMax.getA();
|
||||
Date max = raceMinMax.getB();
|
||||
|
||||
// never reduce max if it was already set
|
||||
if (min != null && max != null && (getToTime() == null || getToTime().before(max))) {
|
||||
setMinMax(min, max, /* fireEvent */ false); // no event because we guarantee time to be between min and max
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMinMax(Date min, Date max, boolean fireEvent) {
|
||||
super.setMinMax(min, max, fireEvent);
|
||||
if (redrawAllMarkersPendingForMinMaxBeingInitialized && timeSlider.isMinMaxInitialized()) {
|
||||
redrawAllMarkers(lastRaceTimesInfo);
|
||||
redrawAllMarkersPendingForMinMaxBeingInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When in {@link PlayModes#Replay} mode, tries to put the {@link #timer} to the time point when the last leg was
|
||||
* finished first. If this time point is not (yet?) known, tries to put the {@link #timer} to the
|
||||
* {@link RaceTimesInfoDTO#endOfRace end of the race}. If that happens to be undefined (<code>null</code>), the
|
||||
* {@link RaceTimesInfoDTO#startOfRace start of the race} is used instead. If that isn't available either, the timer
|
||||
* remains unchanged.
|
||||
* <p>
|
||||
*
|
||||
* When in {@link PlayModes#Live} mode, tries to advance the timer to the time point of the
|
||||
* {@link RaceTimesInfoDTO#timePointOfNewestEvent timePointOfNewestEvent} received from the tracking infrastructure
|
||||
* so far and puts the timer into {@link PlayStates#Playing play mode}.
|
||||
*/
|
||||
private void initTimerPosition(RaceTimesInfoDTO newRaceTimesInfo) {
|
||||
// initialize timer position
|
||||
switch (timer.getPlayMode()) {
|
||||
case Live:
|
||||
if (newRaceTimesInfo.newestTrackingEvent != null) {
|
||||
timer.setTime(newRaceTimesInfo.newestTrackingEvent.getTime());
|
||||
}
|
||||
timer.play();
|
||||
break;
|
||||
case Replay:
|
||||
// set time to start of race
|
||||
if (newRaceTimesInfo.startOfRace != null) {
|
||||
timer.setTime(newRaceTimesInfo.startOfRace.getTime());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expected to be called before {@link #lastRaceTimesInfo} has been updated to <code>newRaceTimesInfo</code>
|
||||
*/
|
||||
private void updateLegMarkers(RaceTimesInfoDTO newRaceTimesInfo) {
|
||||
boolean requiresMarkerUpdate = true;
|
||||
// updating the sliderbar markers requires a lot of time, therefore we need to do this only if required
|
||||
if (lastRaceTimesInfo != null && lastRaceTimesInfo.markPassingTimes.size() == newRaceTimesInfo.markPassingTimes.size()) {
|
||||
requiresMarkerUpdate = false;
|
||||
int numberOfLegs = newRaceTimesInfo.markPassingTimes.size();
|
||||
for (int i = 0; i < numberOfLegs; i++) {
|
||||
if (!Util.equalsWithNull(newRaceTimesInfo.markPassingTimes.get(i).firstPassingDate, lastRaceTimesInfo.markPassingTimes.get(i).firstPassingDate)) {
|
||||
requiresMarkerUpdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((lastRaceTimesInfo.startOfRace == null && newRaceTimesInfo.startOfRace != null)
|
||||
|| (lastRaceTimesInfo.startOfRace != null && newRaceTimesInfo.startOfRace == null)
|
||||
|| (lastRaceTimesInfo.startOfRace != null && newRaceTimesInfo.startOfRace != null
|
||||
&& lastRaceTimesInfo.startOfRace.getTime() != newRaceTimesInfo.startOfRace.getTime())) {
|
||||
requiresMarkerUpdate = true;
|
||||
}
|
||||
if ((lastRaceTimesInfo.endOfRace == null && newRaceTimesInfo.endOfRace != null)
|
||||
|| (lastRaceTimesInfo.endOfRace != null && newRaceTimesInfo.endOfRace == null)
|
||||
|| (lastRaceTimesInfo.endOfRace != null && newRaceTimesInfo.endOfRace != null
|
||||
&& lastRaceTimesInfo.endOfRace.getTime() != newRaceTimesInfo.endOfRace.getTime())) {
|
||||
requiresMarkerUpdate = true;
|
||||
}
|
||||
}
|
||||
if (requiresMarkerUpdate) {
|
||||
if (timeSlider.isMinMaxInitialized()) { // TODO bug 3122 later, the lastRaceTimesInfo will be updated even if not redrawn because min/max not initialized
|
||||
redrawAllMarkers(newRaceTimesInfo);
|
||||
} else {
|
||||
redrawAllMarkersPendingForMinMaxBeingInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void redrawAllMarkers(RaceTimesInfoDTO newRaceTimesInfo) {
|
||||
List<MarkPassingTimesDTO> markPassingTimes = newRaceTimesInfo.getMarkPassingTimes();
|
||||
timeSlider.clearMarkers();
|
||||
if (newRaceTimesInfo.startOfRace != null) {
|
||||
long markerTime = newRaceTimesInfo.startOfRace.getTime();
|
||||
if (!timeSlider.isZoomed() || (timeSlider.isZoomed() && markerTime > timeSlider.getMinValue() && markerTime < timeSlider.getMaxValue())) {
|
||||
timeSlider.addMarker("S", new Double(markerTime));
|
||||
}
|
||||
}
|
||||
int markPassingCounter = 1;
|
||||
for (MarkPassingTimesDTO markPassingTimesDTO: markPassingTimes) {
|
||||
// ignore the start mark passing
|
||||
if (markPassingCounter > 1 && markPassingTimesDTO.firstPassingDate != null) {
|
||||
long markerTime = markPassingTimesDTO.firstPassingDate.getTime();
|
||||
if (!timeSlider.isZoomed() || (timeSlider.isZoomed() && markerTime > timeSlider.getMinValue() && markerTime < timeSlider.getMaxValue())) {
|
||||
timeSlider.addMarker(markPassingTimesDTO.getName(), new Double(markerTime));
|
||||
}
|
||||
}
|
||||
markPassingCounter++;
|
||||
}
|
||||
if (newRaceTimesInfo.endOfRace != null) {
|
||||
long markerTime = newRaceTimesInfo.endOfRace.getTime();
|
||||
if (!timeSlider.isZoomed() || (timeSlider.isZoomed() && markerTime > timeSlider.getMinValue() && markerTime < timeSlider.getMaxValue())) {
|
||||
timeSlider.addMarker("E", new Double(markerTime));
|
||||
}
|
||||
}
|
||||
timeSlider.redraw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void raceTimesInfosReceived(Map<RegattaAndRaceIdentifier, RaceTimesInfoDTO> raceTimesInfos, long clientTimeWhenRequestWasSent, Date serverTimeDuringRequest, long clientTimeWhenResponseWasReceived) {
|
||||
timer.adjustClientServerOffset(clientTimeWhenRequestWasSent, serverTimeDuringRequest, clientTimeWhenResponseWasReceived);
|
||||
updateTimeInfo(raceTimesInfos.get(selectedRace));
|
||||
}
|
||||
}
|
||||
+3
-9
@@ -17,8 +17,6 @@ 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.security.Permission;
|
||||
import com.sap.sailing.domain.common.security.SailingPermissionsForRoleProvider;
|
||||
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
|
||||
import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel;
|
||||
import com.sap.sailing.gwt.ui.client.MediaService;
|
||||
@@ -87,14 +85,11 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
|
||||
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*/);
|
||||
// TODO Remove CAN_REPLAY_DURING_LIVE_RACES url parameter handling (which is used as fallback) after successful adaption of user permissions
|
||||
final boolean canReplayWhileLiveIsPossible = getUserService().getCurrentUser().hasPermission(Permission.CAN_REPLAY_DURING_LIVE_RACES.getStringPermission(),
|
||||
SailingPermissionsForRoleProvider.INSTANCE) || 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);
|
||||
showWindChart, showCompetitorsChart, showViewStreamlets, showViewStreamletColors, showViewSimulation, autoSelectMedia, defaultMedia);
|
||||
sailingService.getRaceboardData(regattaName, raceName, leaderboardName, leaderboardGroupName, eventId, new AsyncCallback<RaceboardDataDTO>() {
|
||||
@Override
|
||||
public void onSuccess(RaceboardDataDTO result) {
|
||||
@@ -102,8 +97,7 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
|
||||
// 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);
|
||||
checkUrlParameters(result, showMapControls, isScreenLargeEnoughToOfferChartSupport);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -122,7 +116,7 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
|
||||
vp.add(new Label(message));
|
||||
}
|
||||
|
||||
private void checkUrlParameters(RaceboardDataDTO raceboardData, boolean canReplayWhileLiveIsPossible, boolean showMapControls,
|
||||
private void checkUrlParameters(RaceboardDataDTO raceboardData, boolean showMapControls,
|
||||
boolean isScreenLargeEnoughToOfferChartSupport) {
|
||||
if (!raceboardData.isValidLeaderboard()) {
|
||||
createErrorPage(getStringMessages().noSuchLeaderboard());
|
||||
|
||||
+2
-2
@@ -238,8 +238,8 @@ public class RaceBoardPanel extends SimplePanel implements LeaderboardUpdateList
|
||||
}
|
||||
}
|
||||
}
|
||||
timePanel = new RaceTimePanel(timer, timeRangeWithZoomModel, stringMessages, raceTimesInfoProvider,
|
||||
raceboardViewConfiguration.isCanReplayDuringLiveRaces(), isScreenLargeEnoughToOfferChartSupport, selectedRaceIdentifier);
|
||||
timePanel = new RaceTimePanel(userService, timer, timeRangeWithZoomModel, stringMessages, raceTimesInfoProvider,
|
||||
false, isScreenLargeEnoughToOfferChartSupport, selectedRaceIdentifier);
|
||||
timeRangeWithZoomModel.addTimeZoomChangeListener(timePanel);
|
||||
raceTimesInfoProvider.addRaceTimesInfoProviderListener(timePanel);
|
||||
}
|
||||
|
||||
+2
-8
@@ -10,7 +10,6 @@ public class RaceBoardViewConfiguration {
|
||||
private final boolean showWindChart;
|
||||
private final boolean showCompetitorsChart;
|
||||
private final String activeCompetitorsFilterSetName;
|
||||
private final boolean canReplayDuringLiveRaces;
|
||||
private final boolean autoSelectMedia;
|
||||
private final String defaultMedia;
|
||||
private final boolean showViewStreamlets;
|
||||
@@ -34,11 +33,11 @@ public class RaceBoardViewConfiguration {
|
||||
public RaceBoardViewConfiguration() {
|
||||
this(/* activeCompetitorsFilterSetName */ null, /* showLeaderboard */ true,
|
||||
/* showWindChart */ false, /* showCompetitorsChart */ false, /* showViewStreamlets */ false, /* showViewStreamletColors */ false, /* showViewSimulation */ false,
|
||||
/* canReplayDuringLiveRaces */false, /* autoSelectMedia */false, null);
|
||||
/* autoSelectMedia */false, null);
|
||||
}
|
||||
|
||||
public RaceBoardViewConfiguration(String activeCompetitorsFilterSetName, boolean showLeaderboard,
|
||||
boolean showWindChart, boolean showCompetitorsChart, boolean showViewStreamlets, boolean showViewStreamletColors, boolean showViewSimulation, boolean canReplayDuringLiveRaces,
|
||||
boolean showWindChart, boolean showCompetitorsChart, boolean showViewStreamlets, boolean showViewStreamletColors, boolean showViewSimulation,
|
||||
boolean autoSelectMedia, String defaultMedia) {
|
||||
this.activeCompetitorsFilterSetName = activeCompetitorsFilterSetName;
|
||||
this.showLeaderboard = showLeaderboard;
|
||||
@@ -47,7 +46,6 @@ public class RaceBoardViewConfiguration {
|
||||
this.showViewStreamlets = showViewStreamlets;
|
||||
this.showViewStreamletColors = showViewStreamletColors;
|
||||
this.showViewSimulation = showViewSimulation;
|
||||
this.canReplayDuringLiveRaces = canReplayDuringLiveRaces;
|
||||
this.autoSelectMedia = autoSelectMedia;
|
||||
this.defaultMedia = defaultMedia;
|
||||
}
|
||||
@@ -80,10 +78,6 @@ public class RaceBoardViewConfiguration {
|
||||
return activeCompetitorsFilterSetName;
|
||||
}
|
||||
|
||||
public boolean isCanReplayDuringLiveRaces() {
|
||||
return canReplayDuringLiveRaces;
|
||||
}
|
||||
|
||||
public boolean isAutoSelectMedia() {
|
||||
return autoSelectMedia;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user