Merge branch 'master' into bug4509

Change-Id: I23ff6e0b645ab626284fc95b172243878e022806
This commit is contained in:
Axel Uhl committed 2018-04-12 13:41:37 +02:00
commit 231e83bc2c
18 files changed
+108 -407

No files matched your search

@@ -24,8 +24,6 @@ import com.sap.sailing.dashboards.gwt.client.widgets.startanalysis.rankingtable.
import com.sap.sailing.dashboards.gwt.shared.StartlineAdvantageType;
import com.sap.sailing.dashboards.gwt.shared.dto.StartAnalysisDTO;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sailing.gwt.ui.client.CompetitorColorProvider;
import com.sap.sailing.gwt.ui.client.CompetitorColorProviderImpl;
import com.sap.sailing.gwt.ui.client.RaceCompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
@@ -75,7 +73,6 @@ public class StartAnalysisCard extends Composite implements HasWidgets, StartAna
private SailingServiceAsync sailingServiceAsync;
private StringMessages stringMessages;
private final RaceCompetitorSelectionModel competitorSelectionModel;
private final CompetitorColorProvider colorProvider;
private final double WIND_LINE_ADVANTAGE_DIV_WIDTH_IN_PT = 185;
private final double GEOMETRIC_LINE_ADVANTAGE_DIV_WIDTH_IN_PT = 210;
@@ -87,8 +84,7 @@ public class StartAnalysisCard extends Composite implements HasWidgets, StartAna
stringMessages = StringMessages.INSTANCE;
this.sailingServiceAsync = sailingServiceAsync;
this.raceMapResources = raceMapResources;
colorProvider = new CompetitorColorProviderImpl();
competitorSelectionModel = new RaceCompetitorSelectionModel(/* hasMultiSelection */true, colorProvider);
competitorSelectionModel = new RaceCompetitorSelectionModel(/* hasMultiSelection */true);
competitorSelectionModel.setCompetitors(startAnalysisDTO.getCompetitorDTOsFromStartAnaylsisCompetitorDTOs(),
raceMap);
initWidget(uiBinder.createAndBindUi(this));
@@ -63,7 +63,7 @@ public class CompetitorDTOImpl extends CompetitorWithoutBoatDTOImpl implements C
@Override
public String getShortInfo() {
String result = null;
if (getShortName() != null) {
if (getShortName() != null && !getShortName().trim().isEmpty()) {
result = getShortName();
} else if (getBoat() != null) {
result = getBoat().getSailId() != null ? getBoat().getSailId() : getBoat().getName();
@@ -11,8 +11,9 @@ import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
@@ -62,11 +63,12 @@ import com.sap.sailing.domain.racelogtracking.test.RaceLogTrackingTestHelper;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.RaceHandle;
import com.sap.sailing.domain.tracking.RaceListener;
import com.sap.sailing.domain.tracking.Track;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sailing.server.util.WaitForTrackedRaceUtil;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
@@ -130,7 +132,7 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
Exception {
RaceColumn column = leaderboard.getRaceColumnByName(columnName);
exception.expect(NotDenotedForRaceLogTrackingException.class);
trackRace(column);
trackAndGetRace(column);
}
private void testSize(Track<?> track, int expected) {
@@ -202,15 +204,12 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
raceLog.add(new RaceLogRegisterCompetitorEventImpl(t(), author, 0, comp1, boat1));
raceLog.add(new RaceLogStartOfTrackingEventImpl(t(0), author, /* passId */ 0));
// start tracking
trackRace(column);
// now there is a tracked race
TrackedRace race = column.getTrackedRace(fleet);
TrackedRace race = trackAndGetRace(column);
assertNotNull(race);
RaceLogFixTrackerManager raceLogFixTrackerManager = new RaceLogFixTrackerManager((DynamicTrackedRace) race, sensorFixStore, null);
raceLogFixTrackerManager.waitForTracker();
race.waitForLoadingToFinish();
addFixes1(race, comp1, dev1);
regattaLog.add(new RegattaLogDeviceCompetitorMappingEventImpl(t(), t(), author, 0, comp1, dev1, t(11), t(20)));
@@ -225,21 +224,10 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
addFixes3(race, comp1, dev1);
}
private void trackRace(RaceColumn column) throws NotDenotedForRaceLogTrackingException, Exception {
private TrackedRace trackAndGetRace(RaceColumn column) throws NotDenotedForRaceLogTrackingException, Exception {
final RaceHandle raceHandle = adapter.startTracking(service, leaderboard, column, fleet, /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false);
// The following lines ensure that we received all necessary events from the TrackedRegatta
// When removing a listener we get a Future whose get method will block until all previously triggered events are processed.
final RaceListener raceListener = new RaceListener() {
@Override
public void raceRemoved(TrackedRace trackedRace) {
}
@Override
public void raceAdded(TrackedRace trackedRace) {
}
};
raceHandle.getTrackedRegatta().addRaceListener(raceListener, Optional.empty());
raceHandle.getTrackedRegatta().removeRaceListener(raceListener).get();
raceHandle.getRace();
return WaitForTrackedRaceUtil.waitForTrackedRace(column, fleet, 10);
}
/**
@@ -255,10 +243,7 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
raceLog = column.getRaceLog(fleet);
adapter.denoteRaceForRaceLogTracking(service, leaderboard, column, fleet, "race");
// start tracking
adapter.startTracking(service, leaderboard, column, fleet, /* trackWind */ false, /* correctWindDirectionByMagneticDeclination */ false);
// now there is a trackedrace
TrackedRace race = column.getTrackedRace(fleet);
TrackedRace race = trackAndGetRace(column);
assertNotNull(race);
final TimePoint startTimeInRaceLog = new MillisecondsTimePoint(123456);
final TimePoint endTimeInRaceLog = new MillisecondsTimePoint(234567);
@@ -276,9 +261,8 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
// now remove the tracked race and track again; again, the explicit tracking times in the race log must prevail
service.removeRace(regatta, race.getRace());
trackRace(column);
TrackedRace race2 = column.getTrackedRace(fleet);
assertEquals(explicitStartOfTracking, race2.getStartOfTracking());
TrackedRace race2 = trackAndGetRace(column);
assertEquals(explicitStartOfTracking, waitForStartOfTracking(race2));
assertEquals(explicitEndOfTracking, race2.getEndOfTracking());
}
@@ -300,14 +284,12 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
regattaLog.add(new RegattaLogRegisterCompetitorEventImpl(t(), t(), author, UUID.randomUUID(), comp1));
raceLog.add(new RaceLogStartOfTrackingEventImpl(t(0), author, /* passId */ 0));
trackRace(column);
// now there is a trackedrace
TrackedRace race = column.getTrackedRace(fleet);
TrackedRace race = trackAndGetRace(column);
assertNotNull(race);
RaceLogFixTrackerManager raceLogFixTrackerManager = new RaceLogFixTrackerManager((DynamicTrackedRace) race, sensorFixStore, null);
raceLogFixTrackerManager.waitForTracker();
race.waitForLoadingToFinish();
addFixes1(race, comp1, dev1);
@@ -322,4 +304,35 @@ public class CreateAndTrackWithRaceLogTest extends RaceLogTrackingTestHelper {
raceLogFixTrackerManager.stop(false, /* willBeRemoved */ false);
addFixes3(race, comp1, dev1);
}
/**
* Waits for startOfTracking being available for a given {@link TrackedRace}.
*/
public static TimePoint waitForStartOfTracking(TrackedRace trackedRace) {
final CompletableFuture<TimePoint> future = new CompletableFuture<>();
final AbstractRaceChangeListener listener = new AbstractRaceChangeListener() {
@Override
public void startOfTrackingChanged(TimePoint oldStartOfTracking, TimePoint newStartOfTracking) {
if (newStartOfTracking != null) {
future.complete(newStartOfTracking);
trackedRace.removeListener(this);
}
}
};
trackedRace.addListener(listener);
final TimePoint startOfTracking = trackedRace.getStartOfTracking();
if (startOfTracking != null) {
trackedRace.removeListener(listener);
return startOfTracking;
}
try {
return future.get(10, TimeUnit.SECONDS);
} catch (Exception e) {
trackedRace.removeListener(listener);
return null;
}
}
}
@@ -90,6 +90,7 @@ public class RaceLogFixTrackerManager implements TrackingDataLoader {
} else {
stopTrackerIfStillRunning(/* preemptive */ false, /* willBeRemoved */ false);
}
this.notifyAll();
}
private void addRaceLog(RaceLog raceLog) {
@@ -153,4 +154,11 @@ public class RaceLogFixTrackerManager implements TrackingDataLoader {
}
return false;
}
public synchronized FixLoaderAndTracker waitForTracker() throws InterruptedException {
while (tracker == null) {
this.wait();
}
return tracker;
}
}
@@ -725,7 +725,6 @@ public class TransientCompetitorStoreImpl implements CompetitorStore, Serializab
boatDTO = convertToBoatDTO(boat);
}
CompetitorDTO competitorDTO = new CompetitorDTOImpl(c, boatDTO);
return competitorDTO;
}
@@ -61,7 +61,7 @@ public class RaceEndWithBoatsPresenterImpl extends AutoPlayPresenterConfigured<A
final SingleRaceLeaderboardSettings leaderboardSettings = new SingleRaceLeaderboardSettings(
/* maneuverDetailsToShow */ null, /* legDetailsToShow */ null, /* raceDetailsToShow */ null,
/* overallDetailsToShow */ null, /* delayBetweenAutoAdvancesInMilliseconds */ null,
/* showAddedScores */ false, /* showCompetitorShortNameColumn */ false,
/* showAddedScores */ false, /* showCompetitorShortNameColumn */ true,
/* showCompetitorFullNameColumn */ false, /* isCompetitorNationalityColumnVisible */ false,
/* showCompetitorBoatInfoColumn */ false, /* showRaceRankColumn */ true);
@@ -70,7 +70,7 @@ public class RaceEndWithBoatsPresenterImpl extends AutoPlayPresenterConfigured<A
timer = new com.sap.sse.gwt.client.player.Timer(PlayModes.Live,
PlayStates.Paused,
/* delayBetweenAutoAdvancesInMilliseconds */ LeaderboardEntryPoint.DEFAULT_REFRESH_INTERVAL_MILLIS);
leaderboardPanel = new SingleRaceLeaderboardPanel(null,null,sailingService, new AsyncActionsExecutor(), leaderboardSettings,
leaderboardPanel = new SingleRaceLeaderboardPanel(null, null, sailingService, new AsyncActionsExecutor(), leaderboardSettings,
true, liveRace, competitorSelectionProvider, timer, null,
getSlideCtx().getContextDefinition().getLeaderboardName(), errorReporter, StringMessages.INSTANCE,
false, null, false, null, false, true, false, false, false, new SixtyInchLeaderBoardStyle(true),
@@ -140,11 +140,11 @@ public class LiveRaceWithRacemapAndLeaderBoardPresenterImpl
}
SailingServiceAsync sailingService = getClientFactory().getSailingService();
ErrorReporter errorReporter = getClientFactory().getErrorReporter();
RegattaAndRaceIdentifier lifeRace = getSlideCtx().getLiveRace();
RegattaAndRaceIdentifier liveRace = getSlideCtx().getLiveRace();
ArrayList<String> racesToShow = null;
if (lifeRace != null) {
if (liveRace != null) {
racesToShow = new ArrayList<>();
racesToShow.add(lifeRace.getRaceName());
racesToShow.add(liveRace.getRaceName());
} else {
view.showErrorNoLive(this, panel, new IllegalStateException("No race is live"));
return;
@@ -152,21 +152,20 @@ public class LiveRaceWithRacemapAndLeaderBoardPresenterImpl
final SingleRaceLeaderboardSettings leaderboardSettings = new SingleRaceLeaderboardSettings(
/* maneuverDetailsToShow */ null, /* legDetailsToShow */ null, /* raceDetailsToShow */ null,
/* overallDetailsToShow */ null, /* delayBetweenAutoAdvancesInMilliseconds */ null,
/* showAddedScores */ false, /* showCompetitorShortNameColumn */ false,
/* showAddedScores */ false, /* showCompetitorShortNameColumn */ true,
/* showCompetitorFullNameColumn */ false, /* isCompetitorNationalityColumnVisible */ false,
/* showCompetitorBoatInfoColumn */ false, /* showRaceRankColumn */ true);
timer = new com.sap.sse.gwt.client.player.Timer(
// perform the first request as "live" but don't by default auto-play
PlayModes.Live, PlayStates.Playing,
/* delayBetweenAutoAdvancesInMilliseconds */ LeaderboardEntryPoint.DEFAULT_REFRESH_INTERVAL_MILLIS);
leaderboardPanel = new SingleRaceLeaderboardPanel(null,null,sailingService, new AsyncActionsExecutor(), leaderboardSettings,
true, lifeRace, getPlace().getRaceMapSelectionProvider(), timer, null,
getSlideCtx().getContextDefinition().getLeaderboardName(), errorReporter, StringMessages.INSTANCE,
leaderboardPanel = new SingleRaceLeaderboardPanel(null, null, sailingService, new AsyncActionsExecutor(),
leaderboardSettings, true, liveRace, getPlace().getRaceMapSelectionProvider(), timer, null,
getSlideCtx().getContextDefinition().getLeaderboardName(), errorReporter, StringMessages.INSTANCE,
false, null, false, null, false, true, false, false, false, new SixtyInchLeaderBoardStyle(true),
FlagImageResolverImpl.get());
getPlace().getRaceMap().setQuickRanksDTOProvider(new QuickRanksDTOFromLeaderboardDTOProvider(new RaceCompetitorSet(getPlace().getRaceMapSelectionProvider()), lifeRace));
getPlace().getRaceMap().setQuickRanksDTOProvider(new QuickRanksDTOFromLeaderboardDTOProvider(
new RaceCompetitorSet(getPlace().getRaceMapSelectionProvider()), liveRace));
view.startingWith(this, panel, getPlace().getRaceMap(), leaderboardPanel);
selectionTimer.schedule(SWITCH_COMPETITOR_DELAY);
}
@@ -14,8 +14,8 @@ import com.sap.sailing.gwt.autoplay.client.app.AnimationPanel;
import com.sap.sailing.gwt.autoplay.client.app.AutoPlayClientFactory;
import com.sap.sailing.gwt.autoplay.client.app.AutoPlayPresenterConfigured;
import com.sap.sailing.gwt.settings.client.leaderboard.SingleRaceLeaderboardSettings;
import com.sap.sailing.gwt.ui.client.RaceCompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.FlagImageResolverImpl;
import com.sap.sailing.gwt.ui.client.RaceCompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardEntryPoint;
@@ -97,7 +97,7 @@ public class PreLiveRaceLeaderBoardWithImagePresenterImpl
final SingleRaceLeaderboardSettings leaderboardSettings = new SingleRaceLeaderboardSettings(
/* maneuverDetailsToShow */ null, /* legDetailsToShow */ null, /* raceDetailsToShow */ null,
/* overallDetailsToShow */ null, /* delayBetweenAutoAdvancesInMilliseconds */ null,
/* showAddedScores */ false, /* showCompetitorShortNameColumn */ false,
/* showAddedScores */ false, /* showCompetitorShortNameColumn */ true,
/* showCompetitorFullNameColumn */ false, /* isCompetitorNationalityColumnVisible */ false,
/* showCompetitorBoatInfoColumn */ false, /* showRaceRankColumn */ false);
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.autoplay.client.utils;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import com.google.gwt.core.client.GWT;
@@ -197,16 +198,14 @@ public class AutoplayHelper {
public void raceTimesInfosReceived(Map<RegattaAndRaceIdentifier, RaceTimesInfoDTO> raceTimesInfo,
long clientTimeWhenRequestWasSent, Date serverTimeDuringRequest,
long clientTimeWhenResponseWasReceived) {
// keep the creationTime updated upon liveChanges!
creationTimer.adjustClientServerOffset(clientTimeWhenRequestWasSent, serverTimeDuringRequest,
clientTimeWhenResponseWasReceived);
creationTimer
.setLivePlayDelayInMillis(raceTimesInfo.get(regattaAndRaceIdentifier).delayToLiveInMs);
creationTimer.play();
if (regattaAndRaceIdentifier != null) {
if(!mapAlreadyCreated){
if (!mapAlreadyCreated) {
mapAlreadyCreated = true;
sailingService.getCompetitorBoats(regattaAndRaceIdentifier,
new AsyncCallback<Map<CompetitorDTO, BoatDTO>>() {
@@ -280,16 +279,16 @@ public class AutoplayHelper {
typesToConsiderOnZoom.add(ZoomTypes.BUOYS);
typesToConsiderOnZoom.add(ZoomTypes.BOATS);
RaceMapZoomSettings autoFollowRace = new RaceMapZoomSettings(typesToConsiderOnZoom, true);
RaceMapSettings settings = new RaceMapSettings(autoFollowRace, new RaceMapHelpLinesSettings(), false, 15,
100000l, false, RaceMapSettings.DEFAULT_BUOY_ZONE_RADIUS, false, true, false, false, false, false,
RaceMapSettings.getDefaultManeuvers(), false, false);
RaceMapLifecycle raceMapLifecycle = new RaceMapLifecycle(StringMessages.INSTANCE);
final CompetitorColorProvider colorProvider = new CompetitorColorProviderImpl(currentLiveRace, result);
RaceCompetitorSelectionModel competitorSelectionProvider = new RaceCompetitorSelectionModel(
/* hasMultiSelection */ true, colorProvider);
/* hasMultiSelection */ true, colorProvider, result);
for (Entry<CompetitorDTO, BoatDTO> entry : result.entrySet()) {
competitorSelectionProvider.setBoat(entry.getKey(), entry.getValue());
}
competitorSelectionProvider.setCompetitors(competitors);
RaceMap raceboardPerspective = new RaceMap(null, null, raceMapLifecycle, settings, sailingService,
asyncActionsExecutor, errorReporter, raceboardTimer, competitorSelectionProvider,
@@ -185,7 +185,9 @@ public class CompetitorEditDialog extends DataEntryDialog<CompetitorDTO> {
color = new InvalidColor(iae);
}
}
CompetitorDTO result = new CompetitorDTOImpl(name.getText(), shortName.getText(), color, email.getText(),
CompetitorDTO result = new CompetitorDTOImpl(name.getText(),
shortName.getText().trim().isEmpty() ? null : shortName.getText(), color,
email.getText().trim().isEmpty() ? null : email.getText(),
/* twoLetterIsoCountryCode */ null,
threeLetterIocCountryCode.getValue(threeLetterIocCountryCode.getSelectedIndex()),
/* countryName */ null, competitorToEdit.getIdAsString(),
@@ -46,7 +46,7 @@ public class CompetitorSelectionModel implements CompetitorSelectionProvider {
this.hasMultiSelection = hasMultiSelection;
this.competitorColorProvider = competitorColorProvider;
this.competitorsFilterSet = competitorsFilterSet;
this.allCompetitors = new LinkedHashSet<CompetitorDTO>();
this.allCompetitors = new LinkedHashSet<>();
this.selectedCompetitors = new LinkedHashMap<>();
this.listeners = new HashSet<CompetitorSelectionChangeListener>();
}
@@ -1,313 +0,0 @@
package com.sap.sailing.gwt.ui.client;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sse.common.Color;
import com.sap.sse.common.Util;
import com.sap.sse.common.filter.Filter;
import com.sap.sse.common.filter.FilterSet;
public class CompetitorWithBoatSelectionModel implements CompetitorSelectionProvider {
private final Set<CompetitorDTO> allCompetitors;
/**
* Keys are {@link CompetitorDTO#getIdAsString()} of their values
*/
private final LinkedHashMap<String, CompetitorDTO> selectedCompetitors;
private final Set<CompetitorSelectionChangeListener> listeners;
private final boolean hasMultiSelection;
private FilterSet<CompetitorDTO, Filter<CompetitorDTO>> competitorsFilterSet;
private final CompetitorColorProvider competitorColorProvider;
public CompetitorWithBoatSelectionModel(boolean hasMultiSelection) {
this(hasMultiSelection, new CompetitorColorProviderImpl(), null);
}
public CompetitorWithBoatSelectionModel(boolean hasMultiSelection, CompetitorColorProvider competitorColorProvider) {
this(hasMultiSelection, competitorColorProvider, null);
}
private CompetitorWithBoatSelectionModel(boolean hasMultiSelection, CompetitorColorProvider competitorColorProvider, FilterSet<CompetitorDTO, Filter<CompetitorDTO>> competitorsFilterSet) {
super();
this.hasMultiSelection = hasMultiSelection;
this.competitorColorProvider = competitorColorProvider;
this.competitorsFilterSet = competitorsFilterSet;
this.allCompetitors = new LinkedHashSet<CompetitorDTO>();
this.selectedCompetitors = new LinkedHashMap<>();
this.listeners = new HashSet<CompetitorSelectionChangeListener>();
}
/**
* Adds a competitor to the {@link #getAllCompetitors() set of all competitors}. If the competitor was not yet
* contained, it will be deselected.
*/
public void add(CompetitorDTO competitor) {
add(competitor, true);
}
private void add(CompetitorDTO competitor, boolean notifyListeners) {
if (competitor.getColor() != null) {
competitorColorProvider.addBlockedColor(competitor.getColor());
}
boolean changed = allCompetitors.add(competitor);
if (notifyListeners && changed) {
fireListChanged(getAllCompetitors());
}
}
@Override
public boolean hasMultiSelection() {
return hasMultiSelection;
}
/**
* Removes all competitors. Afterwards, this model is empty. Deselection events are issued for all competitors that
* were selected so far.
*/
public void clear() {
Iterator<CompetitorDTO> selIter = getSelectedCompetitors().iterator();
while (selIter.hasNext()) {
CompetitorDTO selected = selIter.next();
setSelected(selected, false);
selIter = getSelectedCompetitors().iterator();
}
assert selectedCompetitors.isEmpty();
allCompetitors.clear();
fireListChanged(getAllCompetitors());
}
public void addAll(Iterable<CompetitorDTO> competitors) {
boolean changed = false;
for (CompetitorDTO competitor : competitors) {
add(competitor, false);
changed = true;
}
if (changed) {
fireListChanged(getAllCompetitors());
}
}
/**
* Removes the competitor from the {@link #getAllCompetitors() set of all competitor}. If the competitor was previously
* contained and selected, it is deselected first.
*/
public void remove(CompetitorDTO competitor) {
if (isSelected(competitor)) {
setSelected(competitor, false);
}
if (competitor.getColor() != null) {
competitorColorProvider.removeBlockedColor(competitor.getColor());
}
boolean changed = allCompetitors.remove(competitor);
if (changed) {
fireListChanged(getAllCompetitors());
}
}
@Override
public Iterable<CompetitorDTO> getSelectedCompetitors() {
return Collections.unmodifiableCollection(selectedCompetitors.values());
}
@Override
public Iterable<CompetitorDTO> getSelectedFilteredCompetitors() {
Set<CompetitorDTO> result = new HashSet<>(selectedCompetitors.values());
result.retainAll(getFilteredCompetitors());
return result;
}
@Override
public Iterable<CompetitorDTO> getAllCompetitors() {
return Collections.unmodifiableCollection(allCompetitors);
}
@Override
public Collection<CompetitorDTO> getFilteredCompetitors() {
Set<CompetitorDTO> currentFilteredList = new LinkedHashSet<CompetitorDTO>(allCompetitors);
if (competitorsFilterSet != null) {
for (Filter<CompetitorDTO> filter : competitorsFilterSet.getFilters()) {
for (Iterator<CompetitorDTO> i=currentFilteredList.iterator(); i.hasNext(); ) {
CompetitorDTO competitorDTO = i.next();
if (!filter.matches(competitorDTO)) {
i.remove();
}
}
}
}
return currentFilteredList;
}
public void setSelected(CompetitorDTO competitor, boolean selected, CompetitorSelectionChangeListener... listenersNotToNotify) {
if (selected) {
if (allCompetitors.contains(competitor) && !selectedCompetitors.containsKey(competitor.getIdAsString())) {
selectedCompetitors.put(competitor.getIdAsString(), competitor);
fireAddedToSelection(competitor, listenersNotToNotify);
}
} else {
if (selectedCompetitors.containsKey(competitor.getIdAsString())) {
selectedCompetitors.remove(competitor.getIdAsString());
fireRemovedFromSelection(competitor, listenersNotToNotify);
}
}
}
private void fireAddedToSelection(CompetitorDTO competitor, CompetitorSelectionChangeListener... listenersNotToNotify) {
for (CompetitorSelectionChangeListener listener : listeners) {
if (listenersNotToNotify == null || !Arrays.asList(listenersNotToNotify).contains(listener)) {
listener.addedToSelection(competitor);
}
}
}
private void fireRemovedFromSelection(CompetitorDTO competitor, CompetitorSelectionChangeListener... listenersNotToNotify) {
for (CompetitorSelectionChangeListener listener : listeners) {
if (listenersNotToNotify == null || !Arrays.asList(listenersNotToNotify).contains(listener)) {
listener.removedFromSelection(competitor);
}
}
}
private void fireListChanged(Iterable<CompetitorDTO> competitors, CompetitorSelectionChangeListener... listenersNotToNotify) {
for (CompetitorSelectionChangeListener listener : listeners) {
if (listenersNotToNotify == null || !Arrays.asList(listenersNotToNotify).contains(listener)) {
listener.competitorsListChanged(competitors);
}
}
}
@Override
public boolean isSelected(CompetitorDTO competitor) {
return selectedCompetitors.containsKey(competitor.getIdAsString());
}
@Override
public void addCompetitorSelectionChangeListener(CompetitorSelectionChangeListener listener) {
listeners.add(listener);
}
@Override
public void removeCompetitorSelectionChangeListener(CompetitorSelectionChangeListener listener) {
listeners.remove(listener);
}
@Override
public void setSelection(Iterable<CompetitorDTO> newSelection, CompetitorSelectionChangeListener... listenersNotToNotify) {
Set<CompetitorDTO> competitorsToRemoveFromSelection = new HashSet<CompetitorDTO>(selectedCompetitors.values());
for (CompetitorDTO newSelectedCompetitor : newSelection) {
setSelected(newSelectedCompetitor, true, listenersNotToNotify);
competitorsToRemoveFromSelection.remove(newSelectedCompetitor);
}
for (CompetitorDTO competitorToRemoveFromSelection : competitorsToRemoveFromSelection) {
setSelected(competitorToRemoveFromSelection, false, listenersNotToNotify);
}
}
@Override
public void setCompetitors(Iterable<CompetitorDTO> newCompetitors, CompetitorSelectionChangeListener... listenersNotToNotify) {
boolean changed = false;
Map<String, CompetitorDTO> oldCompetitorsToRemove = new HashMap<String, CompetitorDTO>();
for (final CompetitorDTO c : allCompetitors) {
oldCompetitorsToRemove.put(c.getIdAsString(), c);
}
for (CompetitorDTO newCompetitor : newCompetitors) {
// Search by equality, including all CompetitorDTO fields; if equal object is found, leave it in place;
// non-equal objects may still represent the same competitor entity; yet, replace the object to obtain the
// new, changed state; make sure the selection keeps unchanged regarding the selected competitor "entities";
// see also bug 3413 for more background.
if (allCompetitors.contains(newCompetitor)) {
oldCompetitorsToRemove.remove(newCompetitor.getIdAsString()); // the old competitor object remains in allCompetitors; it is equal but doesn't have to be identical to newCompetitor
} else {
boolean selected = isSelected(newCompetitor);
if (selected) {
remove(oldCompetitorsToRemove.get(newCompetitor.getIdAsString()));
oldCompetitorsToRemove.remove(newCompetitor.getIdAsString());
}
add(newCompetitor, false); // due to the equals definition of CompetitorDTOImpl that compares most fields, state changes lead to a replacement here
if (selected) {
// restore selection for replaced element
setSelected(newCompetitor, selected, listenersNotToNotify);
}
changed = true;
}
}
for (CompetitorDTO oldCompetitorToRemove : oldCompetitorsToRemove.values()) {
remove(oldCompetitorToRemove);
changed = true;
}
if (changed) {
fireListChanged(getAllCompetitors(), listenersNotToNotify);
}
}
@Override
public Color getColor(CompetitorDTO competitor) {
return allCompetitors.contains(competitor) ? competitorColorProvider.getColor(competitor) : null;
}
@Override
public FilterSet<CompetitorDTO, Filter<CompetitorDTO>> getCompetitorsFilterSet() {
return competitorsFilterSet;
}
@Override
public FilterSet<CompetitorDTO, Filter<CompetitorDTO>> getOrCreateCompetitorsFilterSet(String nameToAssignToNewFilterSet) {
if (competitorsFilterSet == null) {
competitorsFilterSet = new FilterSet<CompetitorDTO, Filter<CompetitorDTO>>(nameToAssignToNewFilterSet);
}
return getCompetitorsFilterSet();
}
@Override
public void setCompetitorsFilterSet(FilterSet<CompetitorDTO, Filter<CompetitorDTO>> competitorsFilterSet) {
FilterSet<CompetitorDTO, ? extends Filter<CompetitorDTO>> oldFilterSet = this.competitorsFilterSet;
this.competitorsFilterSet = competitorsFilterSet;
if (!Util.equalsWithNull(competitorsFilterSet, oldFilterSet)) {
for (CompetitorSelectionChangeListener listener : listeners) {
listener.filterChanged(oldFilterSet, competitorsFilterSet);
}
}
for (CompetitorSelectionChangeListener listener : listeners) {
listener.filteredCompetitorsListChanged(getFilteredCompetitors());
}
}
@Override
public boolean hasActiveFilters() {
return (competitorsFilterSet != null && !competitorsFilterSet.getFilters().isEmpty()
&& getFilteredCompetitors().size() != allCompetitors.size());
}
@Override
public void clearAllFilters() {
if (hasActiveFilters()) {
Iterator<CompetitorDTO> selIter = getSelectedCompetitors().iterator();
while (selIter.hasNext()) {
CompetitorDTO selected = selIter.next();
setSelected(selected, false);
selIter = getSelectedCompetitors().iterator();
}
competitorsFilterSet = null;
fireListChanged(getAllCompetitors());
}
}
@Override
public int getFilteredCompetitorsListSize() {
return getFilteredCompetitors().size();
}
}
@@ -9,14 +9,17 @@ import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sse.common.Color;
public class RaceCompetitorSelectionModel extends CompetitorSelectionModel implements RaceCompetitorSelectionProvider {
private final Map<CompetitorDTO, BoatDTO> boatsOfCompetitors = new HashMap<>();
private final Map<CompetitorDTO, BoatDTO> boatsOfCompetitors;
public RaceCompetitorSelectionModel(boolean hasMultiSelection) {
super(hasMultiSelection);
boatsOfCompetitors = new HashMap<>();
}
public RaceCompetitorSelectionModel(boolean hasMultiSelection, CompetitorColorProvider competitorColorProvider) {
public RaceCompetitorSelectionModel(boolean hasMultiSelection, CompetitorColorProvider competitorColorProvider, Map<CompetitorDTO, BoatDTO> boatsOfCompetitors) {
super(hasMultiSelection, competitorColorProvider);
this.boatsOfCompetitors = boatsOfCompetitors;
addAll(boatsOfCompetitors.keySet());
}
@Override
@@ -1869,7 +1869,7 @@ selectCompetitorsToEliminate=Select competitors to eliminate
trackedRaceAlreadyLinked=The race is already linked to a race column. Do you really want to change the link?
boatAlreadyLinked=The boat is already linked to a competitor
chooseAAutoplayConfiguration=Choose an autoplay configuration
raceRankShort=Race rank:
raceRankShort=Race rank
showRaceRankColumn=Show race rank
estimatedDistance=Estimated Distance
estimatedTime=Estimated Time
@@ -202,9 +202,9 @@ public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint
final CompetitorColorProvider colorProvider = new CompetitorColorProviderImpl(selectedRaceIdentifier, competitorsAndBoats);
final RaceCompetitorSelectionProvider competitorSelection;
if (showCompetitors) {
competitorSelection = new RaceCompetitorSelectionModel(/* hasMultiSelection */ true, colorProvider);
competitorSelection = new RaceCompetitorSelectionModel(/* hasMultiSelection */ true, colorProvider, competitorsAndBoats);
} else {
competitorSelection = createEmptyFilterCompetitorModel(colorProvider); // show no competitors
competitorSelection = createEmptyFilterCompetitorModel(colorProvider, competitorsAndBoats); // show no competitors
}
final RaceMap raceMap = new RaceMap(null, null, new RaceMapLifecycle(getStringMessages()), raceMapSettings,
sailingService, asyncActionsExecutor, /* errorReporter */ EmbeddedMapAndWindChartEntryPoint.this, timer,
@@ -232,8 +232,8 @@ public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint
timer.setTime(timer.getTime().getTime()-1000l);
}
private RaceCompetitorSelectionProvider createEmptyFilterCompetitorModel(CompetitorColorProvider colorProvider) {
final RaceCompetitorSelectionModel result = new RaceCompetitorSelectionModel(/* hasMultiSelection */ true, colorProvider);
private RaceCompetitorSelectionProvider createEmptyFilterCompetitorModel(CompetitorColorProvider colorProvider, Map<CompetitorDTO, BoatDTO> competitorsAndBoats) {
final RaceCompetitorSelectionModel result = new RaceCompetitorSelectionModel(/* hasMultiSelection */ true, colorProvider, competitorsAndBoats);
final FilterSet<CompetitorDTO, Filter<CompetitorDTO>> filterSet = result.getOrCreateCompetitorsFilterSet("Empty");
filterSet.addFilter(new Filter<CompetitorDTO>() {
@Override public boolean matches(CompetitorDTO object) { return false; }
@@ -211,7 +211,7 @@ public class RaceBoardPanel
timeRangeWithZoomModel = new TimeRangeWithZoomModel();
final CompetitorColorProvider colorProvider = new CompetitorColorProviderImpl(selectedRaceIdentifier, competitorsAndTheirBoats);
competitorSelectionProvider = new RaceCompetitorSelectionModel(/* hasMultiSelection */ true, colorProvider);
competitorSelectionProvider = new RaceCompetitorSelectionModel(/* hasMultiSelection */ true, colorProvider, competitorsAndTheirBoats);
raceMapResources.raceMapStyle().ensureInjected();
RaceMapLifecycle raceMapLifecycle = lifecycle.getRaceMapLifecycle();
@@ -42,8 +42,6 @@ import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.DynamicTrackedRegatta;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.RaceListener;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRaceImpl;
import com.sap.sailing.domain.tracking.impl.DynamicTrackedRegattaImpl;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
@@ -94,20 +92,6 @@ public class StatisticsTest {
private TrackedRaceStatisticsCacheImpl getStatisticsCacheWithRegattaAdded() throws Exception {
TrackedRaceStatisticsCacheImpl trackedRaceStatisticsCache = new TrackedRaceStatisticsCacheImpl();
trackedRaceStatisticsCache.regattaAdded(regatta);
// The following lines ensure that we received all necessary events from the TrackedRegatta
// When removing a listener we get a Future whose get method will block until all previously triggered events are processed.
RaceListener raceListener = new RaceListener() {
@Override
public void raceRemoved(TrackedRace trackedRace) {
}
@Override
public void raceAdded(TrackedRace trackedRace) {
}
};
regatta.addRaceListener(raceListener, Optional.empty());
regatta.removeRaceListener(raceListener).get();
return trackedRaceStatisticsCache;
}
@@ -76,7 +76,12 @@ public class TrackedRaceStatisticsCacheImpl extends AbstractTrackedRegattaAndRac
/**
* For testing purposes only!
*/
public TrackedRaceStatistics getStatisticsWaitingForLatest(TrackedRace trackedRace) {
public TrackedRaceStatistics getStatisticsWaitingForLatest(TrackedRace trackedRace) throws InterruptedException {
synchronized (listeners) {
while (!listeners.containsKey(trackedRace)) {
listeners.wait();
}
}
return cache.get(trackedRace, true);
}
@@ -84,9 +89,12 @@ public class TrackedRaceStatisticsCacheImpl extends AbstractTrackedRegattaAndRac
protected void onRaceAdded(RegattaAndRaceIdentifier raceIdentifier, DynamicTrackedRegatta trackedRegatta,
DynamicTrackedRace trackedRace) {
Listener listener = new Listener(trackedRace);
listeners.put(trackedRace, listener);
trackedRace.addListener(listener);
triggerUpdateDirect(trackedRace);
synchronized (listeners) {
listeners.put(trackedRace, listener);
trackedRace.addListener(listener);
triggerUpdateDirect(trackedRace);
listeners.notifyAll();
}
}
private void triggerUpdateScheduled(final DynamicTrackedRace trackedRace) {
@@ -116,9 +124,12 @@ public class TrackedRaceStatisticsCacheImpl extends AbstractTrackedRegattaAndRac
@Override
protected void onRaceRemoved(DynamicTrackedRace trackedRace) {
Listener listener = listeners.remove(trackedRace);
if (listener != null) {
trackedRace.removeListener(listener);
synchronized (listeners) {
Listener listener = listeners.remove(trackedRace);
if (listener != null) {
trackedRace.removeListener(listener);
}
listeners.notifyAll();
}
// To prevent leakage of TrackedRace instances as keys in the cache,