From 13a1776cc0be64d726e7d42cfeaf5315314da74d Mon Sep 17 00:00:00 2001 From: Fredrik Teschke Date: Wed, 23 Apr 2014 20:35:13 +0200 Subject: [PATCH] simplified steps for racelog-tracking --- .../common/dto/AbstractLeaderboardDTO.java | 3 +- .../sailing/domain/common/dto/FleetDTO.java | 1 - ...tDenotableForRaceLogTrackingException.java | 14 ++ .../NotDenotableForTrackingException.java | 14 -- ...NotDenotedForRaceLogTrackingException.java | 14 ++ .../RaceLogRaceTrackerExistsException.java | 14 ++ .../impl/CreateAndTrackWithRaceLogTest.java | 27 +-- .../RaceLogTrackingAdapter.java | 67 +++---- .../impl/RaceLogTrackingAdapterImpl.java | 180 ++++++------------ .../base/impl/BaseRaceColumnListener.java | 84 ++++++++ .../AbstractLeaderboardConfigPanel.java | 15 +- .../adminconsole/LeaderboardConfigPanel.java | 7 +- ...gTrackingEventManagementImagesBarCell.java | 7 +- .../RaceLogTrackingEventManagementPanel.java | 115 +++++------ ...ckingEventManagementRaceImagesBarCell.java | 10 - .../sailing/gwt/ui/client/SailingService.java | 25 ++- .../gwt/ui/client/SailingServiceAsync.java | 5 - .../gwt/ui/server/SailingServiceImpl.java | 71 ++----- 18 files changed, 328 insertions(+), 345 deletions(-) create mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/NotDenotableForRaceLogTrackingException.java delete mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/NotDenotableForTrackingException.java create mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/NotDenotedForRaceLogTrackingException.java create mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/RaceLogRaceTrackerExistsException.java create mode 100644 java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/BaseRaceColumnListener.java diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/AbstractLeaderboardDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/AbstractLeaderboardDTO.java index 998b30ef79a..c109c731c43 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/AbstractLeaderboardDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/AbstractLeaderboardDTO.java @@ -31,8 +31,7 @@ public abstract class AbstractLeaderboardDTO implements Serializable { public String defaultCourseAreaName; public ScoringSchemeType scoringScheme; public LeaderboardType type; - public boolean isDenotedForRaceLogTracking = false; - public boolean raceLogTrackersCanBeAdded = false; + public boolean isDenotableForRaceLogTracking; private Long delayToLiveInMillisForLatestRace; diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/FleetDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/FleetDTO.java index 1dbdf30dbe0..5b62e59afd4 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/FleetDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/FleetDTO.java @@ -8,7 +8,6 @@ public class FleetDTO extends NamedDTO { private Color color; private int orderNo; - public boolean raceLogTrackerCanBeAdded; public RaceLogTrackingState raceLogTrackingState; public boolean raceLogTrackerExists; public boolean courseDefinitionInRaceLog; diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/NotDenotableForRaceLogTrackingException.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/NotDenotableForRaceLogTrackingException.java new file mode 100644 index 00000000000..296f4e29659 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/NotDenotableForRaceLogTrackingException.java @@ -0,0 +1,14 @@ +package com.sap.sailing.domain.common.racelog.tracking; + +public class NotDenotableForRaceLogTrackingException extends Exception { + + private static final long serialVersionUID = 6721038282862173471L; + + public NotDenotableForRaceLogTrackingException() { + super(); + } + + public NotDenotableForRaceLogTrackingException(String msg) { + super(msg); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/NotDenotableForTrackingException.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/NotDenotableForTrackingException.java deleted file mode 100644 index 5a0e0e0f3b3..00000000000 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/NotDenotableForTrackingException.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.sap.sailing.domain.common.racelog.tracking; - -public class NotDenotableForTrackingException extends Exception { - - private static final long serialVersionUID = 6721038282862173471L; - - public NotDenotableForTrackingException() { - super(); - } - - public NotDenotableForTrackingException(String msg) { - super(msg); - } -} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/NotDenotedForRaceLogTrackingException.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/NotDenotedForRaceLogTrackingException.java new file mode 100644 index 00000000000..badfccb5523 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/NotDenotedForRaceLogTrackingException.java @@ -0,0 +1,14 @@ +package com.sap.sailing.domain.common.racelog.tracking; + +public class NotDenotedForRaceLogTrackingException extends Exception { + + private static final long serialVersionUID = 6721038282862173471L; + + public NotDenotedForRaceLogTrackingException() { + super(); + } + + public NotDenotedForRaceLogTrackingException(String msg) { + super(msg); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/RaceLogRaceTrackerExistsException.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/RaceLogRaceTrackerExistsException.java new file mode 100644 index 00000000000..6f1bb16b2db --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/racelog/tracking/RaceLogRaceTrackerExistsException.java @@ -0,0 +1,14 @@ +package com.sap.sailing.domain.common.racelog.tracking; + +public class RaceLogRaceTrackerExistsException extends RuntimeException { + + private static final long serialVersionUID = 6721038282862173471L; + + public RaceLogRaceTrackerExistsException() { + super(); + } + + public RaceLogRaceTrackerExistsException(String raceLogName) { + super("Tracker for racelog " + raceLogName + " already exists"); + } +} diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/CreateAndTrackWithRaceLogTest.java b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/CreateAndTrackWithRaceLogTest.java index 7e9e576d53c..b562db1e9ce 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/CreateAndTrackWithRaceLogTest.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter.test/src/com/sap/sailing/domain/racelogtracking/test/impl/CreateAndTrackWithRaceLogTest.java @@ -2,7 +2,6 @@ package com.sap.sailing.domain.racelogtracking.test.impl; import static com.sap.sailing.domain.common.impl.Util.size; import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -10,9 +9,7 @@ import static org.junit.Assert.assertTrue; import java.io.FileNotFoundException; import java.net.MalformedURLException; import java.net.URISyntaxException; -import java.util.Collection; import java.util.Collections; -import java.util.Map; import java.util.UUID; import org.junit.Before; @@ -49,7 +46,6 @@ import com.sap.sailing.domain.racelog.tracking.test.mock.MockSmartphoneImeiServi import com.sap.sailing.domain.racelog.tracking.test.mock.SmartphoneImeiIdentifier; import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter; import com.sap.sailing.domain.racelogtracking.impl.RaceLogTrackingAdapterFactoryImpl; -import com.sap.sailing.domain.tracking.RacesHandle; import com.sap.sailing.domain.tracking.Track; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl; @@ -100,7 +96,7 @@ public class CreateAndTrackWithRaceLogTest { public void cantAddBeforeDenoting() throws MalformedURLException, FileNotFoundException, URISyntaxException, Exception { RaceColumn column = leaderboard.getRaceColumnByName(columnName); exception.expect(RaceNotCreatedException.class); - adapter.addRace(service, regatta.getRegattaIdentifier(), leaderboard, column, fleet, -1); + adapter.startTracking(service, leaderboard, column, fleet); } private void testSize(Track track, int expected) { @@ -115,13 +111,9 @@ public class CreateAndTrackWithRaceLogTest { RaceColumn column = leaderboard.getRaceColumnByName(columnName); RaceLog raceLog = column.getRaceLog(fleet); - //before denoting, it is not listed as loadable - Map> loadable = adapter.listRaceLogTrackersThatCanBeAdded(service, leaderboard); - assertEquals(0, loadable.size()); - //can denote racelog for tracking assertTrue(raceLog.isEmpty()); - adapter.denoteForRaceLogTracking(service, leaderboard, column, fleet, "race"); + adapter.denoteRaceForRaceLogTracking(service, leaderboard, column, fleet, "race"); assertFalse(raceLog.isEmpty()); //add a mapping and one fix in, one out of mapping @@ -131,24 +123,13 @@ public class CreateAndTrackWithRaceLogTest { gpsFixStore.storeFix(dev1, new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(5), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(5)))); gpsFixStore.storeFix(dev1, new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(15), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(5)))); - //then listed as loadable - loadable = adapter.listRaceLogTrackersThatCanBeAdded(service, leaderboard); - assertEquals(1, loadable.size()); - assertEquals(1, loadable.get(column).size()); - - //now can add - RacesHandle handle = adapter.addRace(service, regatta.getRegattaIdentifier(), leaderboard, column, fleet, -1); - - //no trackedrace yet - assertNull(column.getTrackedRace(fleet)); - CourseBase course = new CourseDataImpl("test"); course.addWaypoint(0, new WaypointImpl(new MarkImpl("mark"))); raceLog.add(factory.createCourseDesignChangedEvent(t(), author, 0, course)); raceLog.add(factory.createRegisterCompetitorEvent(t(), author, 0, comp1)); //start tracking - raceLog.add(factory.createStartTrackingEvent(t(), author, 0)); + adapter.startTracking(service, leaderboard, column, fleet); //now there is a trackedrace TrackedRace race = column.getTrackedRace(fleet); @@ -171,7 +152,7 @@ public class CreateAndTrackWithRaceLogTest { testSize(race.getTrack(comp1), 5); //stop tracking, then no more fixes arrive at race - handle.getRaceTracker().stop(); + service.getRaceTrackerById(raceLog.getId()).stop(); gpsFixStore.storeFix(dev1, new GPSFixMovingImpl(new DegreePosition(0, 0), new MillisecondsTimePoint(8), new KnotSpeedWithBearingImpl(10, new DegreeBearingImpl(5)))); testSize(race.getTrack(comp1), 5); } diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java index 7ce6ef0a07a..32bbe0b29d4 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/RaceLogTrackingAdapter.java @@ -1,17 +1,12 @@ package com.sap.sailing.domain.racelogtracking; -import java.io.FileNotFoundException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.Collection; -import java.util.Map; - +import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.SharedDomainFactory; -import com.sap.sailing.domain.common.RegattaIdentifier; -import com.sap.sailing.domain.common.racelog.tracking.NotDenotableForTrackingException; +import com.sap.sailing.domain.common.racelog.tracking.NotDenotableForRaceLogTrackingException; +import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTrackingException; import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; @@ -20,61 +15,55 @@ import com.sap.sailing.domain.racelog.RaceLogCourseDesignChangedEvent; import com.sap.sailing.domain.racelog.tracking.DefineMarkEvent; import com.sap.sailing.domain.racelog.tracking.DenoteForTrackingEvent; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; +import com.sap.sailing.domain.racelog.tracking.StartTrackingEvent; import com.sap.sailing.domain.racelogtracking.impl.RaceLogRaceTracker; import com.sap.sailing.domain.tracking.GPSFix; -import com.sap.sailing.domain.tracking.RacesHandle; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.server.RacingEventService; -public interface RaceLogTrackingAdapter { +public interface RaceLogTrackingAdapter { /** - * Can be called either to track a new race, or optionally to load a race that is already in the - * {@link RaceLogTrackingState#TRACKING} state, but was closed. + * Performs the necessary steps to ensure that the race is tracked (aka that a {@link TrackedRace} + * is created from the data in this {@code RaceLog}).

+ * The following steps are performed to achieve this: + *

*/ - RacesHandle addRace(RacingEventService service, RegattaIdentifier regattaToAddTo, Leaderboard leaderboard, - RaceColumn raceColumn, Fleet fleet, long timeoutInMilliseconds) throws MalformedURLException, - FileNotFoundException, URISyntaxException, Exception; + void startTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) + throws NotDenotedForRaceLogTrackingException, Exception; + + RaceLogTrackingState getRaceLogTrackingState(RacingEventService service, RaceColumn raceColumn, Fleet fleet); /** - * Lists all races for this leaderboards according to the rules in - * {@link #canRaceBeAdded(RacingEventService, Leaderboard, RaceColumn, Fleet)}. + * Is a {@link RaceLogRaceTracker} already listening on this {@code raceLog}? */ - Map> listRaceLogTrackersThatCanBeAdded(RacingEventService service, Leaderboard leaderboard); - - /** - * Returns {@code true}, if a {@link DenoteForTrackingEvent} exists within the {@link RaceLog}, and if it does not - * not already have an attached {@link TrackedRace}, and if there is no {@link RaceLogRaceTracker} registered for it - * already. - */ - boolean isDenotedForRaceLogTracking(RacingEventService service, RaceColumn raceColumn, Fleet fleet); - - /** - * Returns {@code true}, if a {@link DenoteForTrackingEvent} exists within the {@link RaceLog}, and if it does not - * not already have an attached {@link TrackedRace}, and if there is no {@link RaceLogRaceTracker} registered for it - * already. - */ - boolean canRaceLogTrackerBeAdded(RacingEventService service, RaceColumn raceColumn, Fleet fleet); + boolean isRaceLogRaceTrackerAttached(RacingEventService service, RaceLog raceLog); /** * Denotes the {@link RaceLog} for racelog-tracking, by inserting a {@link DenoteForTrackingEvent}. * - * @throws NotDenotableForTrackingException + * @throws NotDenotableForRaceLogTrackingException * Fails, if no {@link RaceLog}, or a non-empty {@link RaceLog}, or one with attached * {@link TrackedRace} is found already in place. * Also fails, if the {@code leaderboard} is not a {@link RegattaLeaderboard}. */ - void denoteForRaceLogTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, - Fleet fleet, String raceName) throws NotDenotableForTrackingException; + void denoteRaceForRaceLogTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, + Fleet fleet, String raceName) throws NotDenotableForRaceLogTrackingException; /** * Denotes the entire {@link Leaderboard} for racelog-tracking, by calling the - * {@link #denoteForRaceLogTracking(RacingEventService, Leaderboard, RaceColumn, Fleet, String)} method for each - * {@link RaceLog}. + * {@link #denoteRaceForRaceLogTracking(RacingEventService, Leaderboard, RaceColumn, Fleet, String)} method for each + * {@link RaceLog}.

+ * + * Will fail if there one or more of the attached {@code RaceLogs} are not empty.

* * Also, a listener is registered, that denotes every {@link RaceLog} that is added at a later time as well. */ - void denoteForRaceLogTracking(RacingEventService service, Leaderboard leaderboard) - throws NotDenotableForTrackingException; + void denoteLeaderboardForRaceLogTracking(RacingEventService service, Leaderboard leaderboard) + throws NotDenotableForRaceLogTrackingException; /** * Add a fix to the {@link GPSFixStore}, and create a mapping with a virtual device for exactly that timepoint. diff --git a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java index b36751d04a3..75a3b3b3145 100644 --- a/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java +++ b/java/com.sap.sailing.domain.racelogtrackingadapter/src/com/sap/sailing/domain/racelogtracking/impl/RaceLogTrackingAdapterImpl.java @@ -1,10 +1,5 @@ package com.sap.sailing.domain.racelogtracking.impl; -import java.io.FileNotFoundException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -12,37 +7,34 @@ import java.util.logging.Level; import java.util.logging.Logger; import com.sap.sailing.domain.base.BoatClass; -import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.DomainFactory; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.RaceColumn; -import com.sap.sailing.domain.base.RaceColumnListener; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.SharedDomainFactory; import com.sap.sailing.domain.base.Waypoint; +import com.sap.sailing.domain.base.impl.BaseRaceColumnListener; import com.sap.sailing.domain.base.impl.CourseDataImpl; import com.sap.sailing.domain.common.PassingInstruction; import com.sap.sailing.domain.common.RegattaIdentifier; import com.sap.sailing.domain.common.TimePoint; -import com.sap.sailing.domain.common.impl.Function; import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; import com.sap.sailing.domain.common.impl.Util; -import com.sap.sailing.domain.common.impl.Util.Pair; -import com.sap.sailing.domain.common.racelog.tracking.NotDenotableForTrackingException; +import com.sap.sailing.domain.common.racelog.tracking.NotDenotableForRaceLogTrackingException; +import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTrackingException; +import com.sap.sailing.domain.common.racelog.tracking.RaceLogRaceTrackerExistsException; import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState; -import com.sap.sailing.domain.common.racelog.tracking.RaceNotCreatedException; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; -import com.sap.sailing.domain.leaderboard.ResultDiscardingRule; import com.sap.sailing.domain.racelog.RaceLog; import com.sap.sailing.domain.racelog.RaceLogEvent; import com.sap.sailing.domain.racelog.RaceLogEventFactory; -import com.sap.sailing.domain.racelog.RaceLogIdentifier; import com.sap.sailing.domain.racelog.analyzing.impl.LastPublishedCourseDesignFinder; import com.sap.sailing.domain.racelog.tracking.DeviceIdentifier; +import com.sap.sailing.domain.racelog.tracking.StartTrackingEvent; import com.sap.sailing.domain.racelog.tracking.analyzing.impl.RaceLogTrackingStateAnalyzer; import com.sap.sailing.domain.racelogtracking.PingDeviceIdentifierImpl; import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter; @@ -63,54 +55,52 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter { } @Override - public RacesHandle addRace(RacingEventService service, RegattaIdentifier regattaToAddTo, Leaderboard leaderboard, - RaceColumn raceColumn, Fleet fleet, long timeoutInMilliseconds) throws MalformedURLException, - FileNotFoundException, URISyntaxException, RaceNotCreatedException, Exception, RaceNotCreatedException { + public void startTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) + throws NotDenotedForRaceLogTrackingException, Exception { + RaceLog raceLog = raceColumn.getRaceLog(fleet); + RaceLogTrackingState raceLogTrackingState = new RaceLogTrackingStateAnalyzer(raceLog).analyze(); + assert raceLogTrackingState.isForTracking() : new NotDenotedForRaceLogTrackingException(); + RegattaIdentifier regatta = ((RegattaLeaderboard) leaderboard).getRegatta().getRegattaIdentifier(); + + if (! isRaceLogRaceTrackerAttached(service, raceLog)) { + addTracker(service, regatta, leaderboard, raceColumn, fleet, -1); + } + + if (raceLogTrackingState != RaceLogTrackingState.TRACKING) { + RaceLogEvent event = RaceLogEventFactory.INSTANCE.createStartTrackingEvent(MillisecondsTimePoint.now(), + service.getServerAuthor(), raceLog.getCurrentPassId()); + raceLog.add(event); + } + } + + /** + * Adds a {@link RaceLogRaceTracker}. If a {@link StartTrackingEvent} is already present in the {@code RaceLog} + * linked to the {@code raceColumn} and {@code fleet}, a {@code TrackedRace} is created immediately and tracking begins. + * Otherwise, the {@code RaceLogRaceTracker} waits until a {@code StartTrackingEvent} is added to perform these actions. + * The race first has to be denoted for racelog tracking. + */ + private RacesHandle addTracker(RacingEventService service, RegattaIdentifier regattaToAddTo, Leaderboard leaderboard, + RaceColumn raceColumn, Fleet fleet, long timeoutInMilliseconds) throws RaceLogRaceTrackerExistsException, Exception { + RaceLog raceLog = raceColumn.getRaceLog(fleet); + assert ! isRaceLogRaceTrackerAttached(service, raceLog) : new RaceLogRaceTrackerExistsException( + leaderboard.getName() + " - " + raceColumn.getName() + " - " + fleet.getName()); + Regatta regatta = regattaToAddTo == null ? null : service.getRegatta(regattaToAddTo); RaceLogConnectivityParams params = new RaceLogConnectivityParams(service, regatta, raceColumn, fleet, leaderboard, delayToLiveInMillis, domainFactory); return service.addRace(regattaToAddTo, params, timeoutInMilliseconds); } - private Map> findInLeaderboard(Leaderboard leaderboard, - Function, Boolean> includeInResult) { - Map> result = new HashMap<>(); - for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { - for (Fleet fleet : raceColumn.getFleets()) { - if (includeInResult.perform(new Pair<>(raceColumn, fleet))) { - Collection coll = result.get(raceColumn); - if (coll == null) { - coll = new ArrayList<>(); - result.put(raceColumn, coll); - } - coll.add(fleet); - } - } - } - return result; - } - @Override - public Map> listRaceLogTrackersThatCanBeAdded(final RacingEventService service, - Leaderboard leaderboard) { - return findInLeaderboard(leaderboard, new Function, Boolean>() { - @Override - public Boolean perform(Pair in) { - return canRaceLogTrackerBeAdded(service, in.getA(), in.getB()); - } - }); - } - - @Override - public void denoteForRaceLogTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, - Fleet fleet, String raceName) throws NotDenotableForTrackingException { + public void denoteRaceForRaceLogTracking(RacingEventService service, Leaderboard leaderboard, RaceColumn raceColumn, + Fleet fleet, String raceName) throws NotDenotableForRaceLogTrackingException { BoatClass boatClass = null; if (leaderboard instanceof RegattaLeaderboard) { RegattaLeaderboard rLeaderboard = (RegattaLeaderboard) leaderboard; boatClass = rLeaderboard.getRegatta().getBoatClass(); } else { - throw new NotDenotableForTrackingException("Can only denote RegattaLeaderboards for RaceLog-tracking"); + throw new NotDenotableForRaceLogTrackingException("Can only denote races in RegattaLeaderboards for RaceLog-tracking"); } if (raceName == null) { @@ -118,8 +108,8 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter { } RaceLog raceLog = raceColumn.getRaceLog(fleet); - assert raceLog != null : new NotDenotableForTrackingException("No RaceLog found in place"); - assert raceLog.isEmpty() : new NotDenotableForTrackingException("RaceLog is not empty"); + assert raceLog != null : new NotDenotableForRaceLogTrackingException("No RaceLog found in place"); + assert raceLog.isEmpty() : new NotDenotableForRaceLogTrackingException("RaceLog is not empty"); RaceLogEvent event = RaceLogEventFactory.INSTANCE.createDenoteForTrackingEvent(MillisecondsTimePoint.now(), service.getServerAuthor(), raceLog.getCurrentPassId(), raceName, boatClass); @@ -127,99 +117,51 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter { } @Override - public void denoteForRaceLogTracking(final RacingEventService service, final Leaderboard leaderboard) - throws NotDenotableForTrackingException { + public void denoteLeaderboardForRaceLogTracking(final RacingEventService service, final Leaderboard leaderboard) + throws NotDenotableForRaceLogTrackingException { for (RaceColumn column : leaderboard.getRaceColumns()) { for (Fleet fleet : column.getFleets()) { - denoteForRaceLogTracking(service, leaderboard, column, fleet, null); + RaceLog raceLog = column.getRaceLog(fleet); + if (raceLog == null || ! column.getRaceLog(fleet).isEmpty()) { + throw new NotDenotableForRaceLogTrackingException("Not all racelogs in the leaderboard are empty"); + } + } + } + + for (RaceColumn column : leaderboard.getRaceColumns()) { + for (Fleet fleet : column.getFleets()) { + denoteRaceForRaceLogTracking(service, leaderboard, column, fleet, null); } } // add listener, that also denotes all newly added RaceLogs for tracking - leaderboard.addRaceColumnListener(new RaceColumnListener() { - private static final long serialVersionUID = 3229728745966607941L; + leaderboard.addRaceColumnListener(new BaseRaceColumnListener() { + private static final long serialVersionUID = 2058141016872230058L; - @Override - public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {} - - @Override - public void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) {} - - @Override - public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule, - ResultDiscardingRule newDiscardingRule) {} - - @Override - public void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogEvent event) {} - - @Override - public void raceColumnRemovedFromContainer(RaceColumn raceColumn) {} - - @Override - public void raceColumnMoved(RaceColumn raceColumn, int newIndex) {} - @Override public void raceColumnAddedToContainer(RaceColumn raceColumn) { for (Fleet fleet : raceColumn.getFleets()) { try { - denoteForRaceLogTracking(service, leaderboard, raceColumn, fleet, null); - } catch (NotDenotableForTrackingException e) { + denoteRaceForRaceLogTracking(service, leaderboard, raceColumn, fleet, null); + } catch (NotDenotableForRaceLogTrackingException e) { logger.log(Level.WARNING, "Listener could not denote newly added RaceLog for racelog-tracking"); e.printStackTrace(); } } } - - @Override - public boolean isTransient() { - return true; - } - - @Override - public void isStartsWithZeroScoreChanged(RaceColumn raceColumn, boolean newIsStartsWithZeroScore) { } - - @Override - public void isMedalRaceChanged(RaceColumn raceColumn, boolean newIsMedalRace) {} - - @Override - public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, - boolean firstColumnIsNonDiscardableCarryForward) {} - - @Override - public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) {} - - @Override - public void factorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor) {} - - @Override - public void competitorDisplayNameChanged(Competitor competitor, String oldDisplayName, String displayName) {} - - @Override - public boolean canAddRaceColumnToContainer(RaceColumn raceColumn) { - return true; - } }); } @Override - public boolean canRaceLogTrackerBeAdded(RacingEventService service, RaceColumn raceColumn, Fleet fleet) { - if (raceColumn.getTrackedRace(fleet) == null) { - RaceLog raceLog = raceColumn.getRaceLog(fleet); - if (service.getRaceTrackerById(raceLog.getId()) == null) { - RaceLogTrackingState state = new RaceLogTrackingStateAnalyzer(raceLog).analyze(); - return state.isForTracking(); - } - } - return false; + public boolean isRaceLogRaceTrackerAttached(RacingEventService service, RaceLog raceLog) { + return service.getRaceTrackerById(raceLog.getId()) != null; } @Override - public boolean isDenotedForRaceLogTracking(RacingEventService service, RaceColumn raceColumn, Fleet fleet) { - return new RaceLogTrackingStateAnalyzer(raceColumn.getRaceLog(fleet)).analyze().isForTracking(); + public RaceLogTrackingState getRaceLogTrackingState(RacingEventService service, RaceColumn raceColumn, Fleet fleet) { + return new RaceLogTrackingStateAnalyzer(raceColumn.getRaceLog(fleet)).analyze(); } - - private Waypoint duplicateWaypoint(Waypoint waypoint, Map controlPointDuplicationCache, Map markDuplicationCache, SharedDomainFactory baseDomainFactory) { ControlPoint oldCP = waypoint.getControlPoint(); @@ -292,5 +234,5 @@ public class RaceLogTrackingAdapterImpl implements RaceLogTrackingAdapter { service.getServerAuthor(), device, mark, raceLog.getCurrentPassId(), time, time); raceLog.add(mapping); service.getGPSFixStore().storeFix(device, gpsFix); - } + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/BaseRaceColumnListener.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/BaseRaceColumnListener.java new file mode 100644 index 00000000000..6db50b6f3d5 --- /dev/null +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/impl/BaseRaceColumnListener.java @@ -0,0 +1,84 @@ +package com.sap.sailing.domain.base.impl; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.base.RaceColumnListener; +import com.sap.sailing.domain.leaderboard.ResultDiscardingRule; +import com.sap.sailing.domain.racelog.RaceLogEvent; +import com.sap.sailing.domain.racelog.RaceLogIdentifier; +import com.sap.sailing.domain.tracking.TrackedRace; + +/** + * Base implementing class with method stubs. + * @author Fredrik Teschke + * + */ +public abstract class BaseRaceColumnListener implements RaceColumnListener { + private static final long serialVersionUID = 5390243590559755813L; + + @Override + public void trackedRaceLinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) { + } + + @Override + public void trackedRaceUnlinked(RaceColumn raceColumn, Fleet fleet, TrackedRace trackedRace) { + } + + @Override + public void isMedalRaceChanged(RaceColumn raceColumn, boolean newIsMedalRace) { + } + + @Override + public void isStartsWithZeroScoreChanged(RaceColumn raceColumn, boolean newIsStartsWithZeroScore) { + } + + @Override + public void isFirstColumnIsNonDiscardableCarryForwardChanged(RaceColumn raceColumn, + boolean firstColumnIsNonDiscardableCarryForward) { + } + + @Override + public void hasSplitFleetContiguousScoringChanged(RaceColumn raceColumn, boolean hasSplitFleetContiguousScoring) { + } + + @Override + public boolean canAddRaceColumnToContainer(RaceColumn raceColumn) { + return false; + } + + @Override + public void raceColumnAddedToContainer(RaceColumn raceColumn) { + } + + @Override + public void raceColumnRemovedFromContainer(RaceColumn raceColumn) { + } + + @Override + public void raceColumnMoved(RaceColumn raceColumn, int newIndex) { + } + + @Override + public void factorChanged(RaceColumn raceColumn, Double oldFactor, Double newFactor) { + } + + @Override + public void competitorDisplayNameChanged(Competitor competitor, String oldDisplayName, String displayName) { + } + + @Override + public void resultDiscardingRuleChanged(ResultDiscardingRule oldDiscardingRule, + ResultDiscardingRule newDiscardingRule) { + } + + @Override + public void raceLogEventAdded(RaceColumn raceColumn, RaceLogIdentifier raceLogIdentifier, RaceLogEvent event) { + } + + @Override + public boolean isTransient() { + return true; + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java index 0a11aca71df..ee7816e6789 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AbstractLeaderboardConfigPanel.java @@ -21,7 +21,7 @@ import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.view.client.ListDataProvider; import com.google.gwt.view.client.MultiSelectionModel; import com.google.gwt.view.client.SelectionChangeEvent; -import com.google.gwt.view.client.SingleSelectionModel; +import com.google.gwt.view.client.SetSelectionModel; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaNameAndRaceName; import com.sap.sailing.domain.common.dto.FleetDTO; @@ -69,7 +69,7 @@ TrackedRaceChangedListener { protected LabeledAbstractFilterablePanel filterLeaderboardPanel; - protected final SingleSelectionModel raceColumnTableSelectionModel; + protected final SetSelectionModel raceColumnTableSelectionModel; protected List availableLeaderboardList; @@ -117,7 +117,8 @@ TrackedRaceChangedListener { } public AbstractLeaderboardConfigPanel(final SailingServiceAsync sailingService, AdminConsoleEntryPoint adminConsole, - final ErrorReporter errorReporter, StringMessages theStringConstants) { + final ErrorReporter errorReporter, StringMessages theStringConstants, + SetSelectionModel raceColumnTableSelectionModel) { this.stringMessages = theStringConstants; this.sailingService = sailingService; leaderboardList = new ListDataProvider(); @@ -236,7 +237,7 @@ TrackedRaceChangedListener { addColumnsToRacesTable(raceColumnTable); - raceColumnTableSelectionModel = new SingleSelectionModel(); + this.raceColumnTableSelectionModel = raceColumnTableSelectionModel; raceColumnTable.setSelectionModel(raceColumnTableSelectionModel); raceColumnTableSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { public void onSelectionChange(SelectionChangeEvent event) { @@ -420,8 +421,10 @@ TrackedRaceChangedListener { } protected RaceColumnDTOAndFleetDTOWithNameBasedEquality getSelectedRaceColumnWithFleet() { - RaceColumnDTOAndFleetDTOWithNameBasedEquality raceInLeaderboardAndFleetName = raceColumnTableSelectionModel.getSelectedObject(); - return raceInLeaderboardAndFleetName; + if (raceColumnTableSelectionModel.getSelectedSet().isEmpty()) { + return null; + } + return raceColumnTableSelectionModel.getSelectedSet().iterator().next(); } protected String getSelectedLeaderboardName() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java index 84dcc21a0bc..b0e7b6d4a85 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LeaderboardConfigPanel.java @@ -29,6 +29,7 @@ import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.Panel; +import com.google.gwt.view.client.SingleSelectionModel; import com.sap.sailing.domain.common.RegattaIdentifier; import com.sap.sailing.domain.common.RegattaName; import com.sap.sailing.domain.common.RegattaNameAndRaceName; @@ -86,7 +87,7 @@ TrackedRaceChangedListener { public LeaderboardConfigPanel(final SailingServiceAsync sailingService, AdminConsoleEntryPoint adminConsole, final ErrorReporter errorReporter, StringMessages theStringConstants, final boolean showRaceDetails) { - super(sailingService, adminConsole, errorReporter, theStringConstants); + super(sailingService, adminConsole, errorReporter, theStringConstants, new SingleSelectionModel()); this.showRaceDetails = showRaceDetails; } @@ -548,7 +549,7 @@ TrackedRaceChangedListener { */ private void moveSelectedRaceColumnDown() { final String selectedLeaderboardName = getSelectedLeaderboardName(); - final String selectedRaceColumnName = raceColumnTableSelectionModel.getSelectedObject().getA().getRaceColumnName(); + final String selectedRaceColumnName = getSelectedRaceColumnWithFleet().getA().getRaceColumnName(); sailingService.moveLeaderboardColumnDown(getSelectedLeaderboardName(), selectedRaceColumnName, new MarkedAsyncCallback( new AsyncCallback() { @@ -572,7 +573,7 @@ TrackedRaceChangedListener { */ private void moveSelectedRaceColumnUp() { final String selectedLeaderboardName = getSelectedLeaderboardName(); - final String selectedRaceColumnName = raceColumnTableSelectionModel.getSelectedObject().getA().getRaceColumnName(); + final String selectedRaceColumnName = getSelectedRaceColumnWithFleet().getA().getRaceColumnName(); sailingService.moveLeaderboardColumnUp(getSelectedLeaderboardName(), selectedRaceColumnName, new MarkedAsyncCallback( new AsyncCallback() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementImagesBarCell.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementImagesBarCell.java index 7821d029b79..af8a7803c63 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementImagesBarCell.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementImagesBarCell.java @@ -10,7 +10,6 @@ import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; public class RaceLogTrackingEventManagementImagesBarCell extends ImagesBarCell { public static final String ACTION_DENOTE_FOR_RACELOG_TRACKING = "ACTION_DENOTE_FOR_RACELOG_TRACKING"; - public static final String ACTION_ADD_RACELOG_TRACKERS = "ACTION_ADD_RACELOG_TRACKERS"; private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class); private final StringMessages stringMessages; @@ -29,12 +28,10 @@ public class RaceLogTrackingEventManagementImagesBarCell extends ImagesBarCell { ArrayList result = new ArrayList(); StrippedLeaderboardDTO leaderboard = (StrippedLeaderboardDTO) getContext().getKey(); - if (! leaderboard.isDenotedForRaceLogTracking) { + + if (leaderboard.isDenotableForRaceLogTracking) { result.add(new ImageSpec(ACTION_DENOTE_FOR_RACELOG_TRACKING, stringMessages.denoteForRaceLogTracking(), makeImagePrototype(resources.denoteForRaceLogTracking()))); } - if (leaderboard.raceLogTrackersCanBeAdded) { - result.add(new ImageSpec(ACTION_ADD_RACELOG_TRACKERS, stringMessages.addRaceLogTrackers(), makeImagePrototype(resources.addRaceLogTracker()))); - } return result; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementPanel.java index c772d4502fb..a3b05b815eb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementPanel.java @@ -1,14 +1,20 @@ package com.sap.sailing.gwt.ui.adminconsole; +import java.util.Set; + import com.google.gwt.cell.client.FieldUpdater; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.cellview.client.CellTable; import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; import com.google.gwt.user.cellview.client.TextColumn; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.view.client.MultiSelectionModel; import com.google.gwt.view.client.SelectionChangeEvent; import com.google.gwt.view.client.SelectionChangeEvent.Handler; import com.sap.sailing.domain.common.dto.FleetDTO; @@ -25,11 +31,16 @@ import com.sap.sse.gwt.client.dialog.DataEntryDialog; /** * Allows the user to start and stop tracking of races using the RaceLog-tracking connector. */ -public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConfigPanel { +public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConfigPanel { + private Button startTrackingButton; + private MultiSelectionModel multiRaceSelectionModel; + public RaceLogTrackingEventManagementPanel(SailingServiceAsync sailingService, AdminConsoleEntryPoint adminConsole, RegattaRefresher regattaRefresher, ErrorReporter errorReporter, StringMessages stringMessages) { - super(sailingService, adminConsole, errorReporter, stringMessages); + super(sailingService, adminConsole, errorReporter, stringMessages, + new MultiSelectionModel()); + multiRaceSelectionModel = new MultiSelectionModel<>(); } @Override @@ -57,9 +68,7 @@ public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConf leaderboardActionColumn.setFieldUpdater(new FieldUpdater() { @Override public void update(int index, StrippedLeaderboardDTO leaderboardDTO, String value) { - if (RaceLogTrackingEventManagementImagesBarCell.ACTION_ADD_RACELOG_TRACKERS.equals(value)) { - addRaceLogTrackers(leaderboardDTO); - } else if (RaceLogTrackingEventManagementImagesBarCell.ACTION_DENOTE_FOR_RACELOG_TRACKING.equals(value)) { + if (RaceLogTrackingEventManagementImagesBarCell.ACTION_DENOTE_FOR_RACELOG_TRACKING.equals(value)) { denoteForRaceLogTracking(leaderboardDTO); } } @@ -111,12 +120,8 @@ public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConf final String raceColumnName = object.getA().getName(); final String fleetName = object.getB().getName(); boolean editable = object.getB().raceLogTrackingState != RaceLogTrackingState.TRACKING; - if (RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_ADD_RACELOG_TRACKER.equals(value)) { - addRaceLogTracker(object.getA(), object.getB()); - } else if (RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_DENOTE_FOR_RACELOG_TRACKING.equals(value)) { + if (RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_DENOTE_FOR_RACELOG_TRACKING.equals(value)) { denoteForRaceLogTracking(object.getA(), object.getB()); - } else if (RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_START_RACELOG_TRACKING.equals(value)) { - startRaceLogTracking(object.getA(), object.getB()); } else if (RaceLogTrackingEventManagementRaceImagesBarCell.ACTION_COMPETITOR_REGISTRATIONS.equals(value)) { new RaceLogTrackingCompetitorRegistrationsDialog(sailingService, stringMessages, errorReporter, getSelectedLeaderboardName(), object.getA().getName(), object.getB().getName(), editable).show(); @@ -169,6 +174,9 @@ public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConf racesTable.addColumn(trackerStateColumn, stringMessages.trackerStatus()); racesTable.addColumn(raceActionColumn, stringMessages.actions()); racesTable.setWidth("600px"); + + //set multi selection model, overriding single selection model + racesTable.setSelectionModel(multiRaceSelectionModel); } @Override @@ -178,7 +186,34 @@ public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConf protected void addLeaderboardCreateControls(Panel createPanel) {} @Override - protected void addSelectedLeaderboardRacesControls(Panel racesPanel) {} + protected void addSelectedLeaderboardRacesControls(Panel racesPanel) { + startTrackingButton = new Button(stringMessages.startTracking()); + startTrackingButton.setEnabled(false); + racesPanel.add(startTrackingButton); + startTrackingButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + startTracking(raceColumnTableSelectionModel.getSelectedSet()); + } + }); + + raceColumnTableSelectionModel.addSelectionChangeHandler(new Handler() { + @Override + public void onSelectionChange(SelectionChangeEvent event) { + enableStartTrackingButtonIfAppropriateRacesSelected(); + } + }); + } + + private void enableStartTrackingButtonIfAppropriateRacesSelected() { + boolean enable = raceColumnTableSelectionModel.getSelectedSet().size() > 0; + for (RaceColumnDTOAndFleetDTOWithNameBasedEquality race : raceColumnTableSelectionModel.getSelectedSet()) { + if (! race.getB().raceLogTrackingState.isForTracking() || race.getB().raceLogTrackerExists) { + enable = false; + } + } + startTrackingButton.setEnabled(enable); + } @Override protected void leaderboardRaceColumnSelectionChanged() { @@ -216,6 +251,7 @@ public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConf @Override public void onSuccess(Void result) { loadAndRefreshLeaderboard(leaderboard.name, null); + raceColumnTableSelectionModel.clear(); } @Override @@ -231,6 +267,7 @@ public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConf @Override public void onSuccess(Void result) { loadAndRefreshLeaderboard(leaderboard.name, raceColumn.getName()); + raceColumnTableSelectionModel.clear(); } @Override @@ -239,62 +276,30 @@ public class RaceLogTrackingEventManagementPanel extends AbstractLeaderboardConf } }); } + + private void startTracking(Set races) { + final StrippedLeaderboardDTO leaderboard = getSelectedLeaderboard(); - private void addRaceLogTrackers(final StrippedLeaderboardDTO leaderboard) { - final RaceColumnDTOAndFleetDTOWithNameBasedEquality selectedRCFleet = getSelectedRaceColumnWithFleet(); - if (leaderboard.raceLogTrackersCanBeAdded) { - sailingService.addRaceLogTrackers(leaderboard.name, new AsyncCallback() { - @Override - public void onSuccess(Void result) { - loadAndRefreshLeaderboard(leaderboard.name, selectedRCFleet.getA().getName()); - trackedRacesListComposite.regattaRefresher.fillRegattas(); - } + for (RaceColumnDTOAndFleetDTOWithNameBasedEquality race : races) { + final RaceColumnDTO raceColumn = race.getA(); + final FleetDTO fleet = race.getB(); - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Failed to add RaceLog tracker: " + caught.getMessage()); - } - }); - } else { - errorReporter.reportError("No RaceLogTracker can be added for any of the RaceLogs in this leaderboard"); - } - } - - private void addRaceLogTracker(final RaceColumnDTO raceColumn, FleetDTO fleet) { - if (fleet.raceLogTrackerCanBeAdded) { - final StrippedLeaderboardDTO leaderboard = getSelectedLeaderboard(); - sailingService.addRaceLogTracker(leaderboard.name, raceColumn.getName(), fleet.getName(), new AsyncCallback() { + sailingService.startRaceLogTracking(leaderboard.name, raceColumn.getName(), fleet.getName(), + new AsyncCallback() { @Override public void onSuccess(Void result) { loadAndRefreshLeaderboard(leaderboard.name, raceColumn.getName()); trackedRacesListComposite.regattaRefresher.fillRegattas(); + raceColumnTableSelectionModel.clear(); } @Override public void onFailure(Throwable caught) { - errorReporter.reportError("Failed to add RaceLog trackers: " + caught.getMessage()); + errorReporter.reportError("Failed to start tracking " + raceColumn.getName() + " - " + + fleet.getName() + ": " + caught.getMessage()); } }); - } else { - errorReporter.reportError("No RaceLogTracker can be added for the RaceLog of this fleet"); - } - } - - private void startRaceLogTracking(final RaceColumnDTO raceColumn, FleetDTO fleet) { - final StrippedLeaderboardDTO leaderboard = getSelectedLeaderboard(); - sailingService.startRaceLogTracking(leaderboard.name, raceColumn.getName(), fleet.getName(), new AsyncCallback() { - - @Override - public void onSuccess(Void result) { - loadAndRefreshLeaderboard(leaderboard.name, raceColumn.getName()); - trackedRacesListComposite.regattaRefresher.fillRegattas(); - } - - @Override - public void onFailure(Throwable caught) { - errorReporter.reportError("Failed to start tracking: " + caught.getMessage()); - } - }); + } } private void setStartTime(RaceColumnDTO raceColumnDTO, FleetDTO fleetDTO) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementRaceImagesBarCell.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementRaceImagesBarCell.java index 1726520f381..192405fa9d0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementRaceImagesBarCell.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceLogTrackingEventManagementRaceImagesBarCell.java @@ -4,15 +4,12 @@ import java.util.ArrayList; import java.util.List; import com.google.gwt.core.client.GWT; -import com.sap.sailing.domain.common.racelog.tracking.RaceLogTrackingState; import com.sap.sailing.gwt.ui.adminconsole.AbstractLeaderboardConfigPanel.RaceColumnDTOAndFleetDTOWithNameBasedEquality; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.client.shared.components.ImagesBarCell; public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCell { - public final static String ACTION_ADD_RACELOG_TRACKER = "ACTION_ADD_RACELOG_TRACKER"; public final static String ACTION_DENOTE_FOR_RACELOG_TRACKING = "ACTION_DENOTE_FOR_RACELOG_TRACKING"; - public final static String ACTION_START_RACELOG_TRACKING = "ACTION_START_RACELOG_TRACKING"; public final static String ACTION_COMPETITOR_REGISTRATIONS = "ACTION_COMPETITOR_REGISTRATIONS"; public final static String ACTION_DEFINE_COURSE = "ACTION_DEFINE_COURSE"; public final static String ACTION_MAP_DEVICES = "ACTION_MAP_DEVICES"; @@ -31,17 +28,10 @@ public class RaceLogTrackingEventManagementRaceImagesBarCell extends ImagesBarCe protected Iterable getImageSpecs() { List result = new ArrayList(); RaceColumnDTOAndFleetDTOWithNameBasedEquality object = (RaceColumnDTOAndFleetDTOWithNameBasedEquality) getContext().getKey(); - if (object.getB().raceLogTrackerCanBeAdded) { - result.add(new ImageSpec(ACTION_ADD_RACELOG_TRACKER, stringMessages.addRaceLogTracker(), makeImagePrototype(resources.addRaceLogTracker()))); - } if (! object.getB().raceLogTrackingState.isForTracking()) { result.add(new ImageSpec(ACTION_DENOTE_FOR_RACELOG_TRACKING, stringMessages.denoteForRaceLogTracking(), makeImagePrototype(resources.denoteForRaceLogTracking()))); } - if (object.getB().raceLogTrackerExists && object.getB().raceLogTrackingState != RaceLogTrackingState.TRACKING) { - result.add(new ImageSpec(ACTION_START_RACELOG_TRACKING, stringMessages.startRaceLogTracking(), makeImagePrototype(resources.startRaceLogTracking()))); - } - if (object.getB().raceLogTrackingState.isForTracking()) { result.add(new ImageSpec(ACTION_COMPETITOR_REGISTRATIONS, stringMessages.competitorRegistrations(), makeImagePrototype(resources.competitorRegistrations()))); result.add(new ImageSpec(ACTION_DEFINE_COURSE, stringMessages.defineCourse(), makeImagePrototype(resources.defineCourse()))); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index 9213e4b3517..7f398de25b5 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -9,8 +9,8 @@ import java.util.Set; import java.util.UUID; import com.google.gwt.user.client.rpc.RemoteService; -import com.sap.sailing.domain.common.DataImportProgress; import com.sap.sailing.domain.base.RaceDefinition; +import com.sap.sailing.domain.common.DataImportProgress; import com.sap.sailing.domain.common.DetailType; import com.sap.sailing.domain.common.LeaderboardType; import com.sap.sailing.domain.common.MaxPointsReason; @@ -33,12 +33,14 @@ import com.sap.sailing.domain.common.dto.RaceDTO; import com.sap.sailing.domain.common.dto.RegattaCreationParametersDTO; import com.sap.sailing.domain.common.impl.Util.Pair; import com.sap.sailing.domain.common.impl.Util.Triple; +import com.sap.sailing.domain.common.racelog.RacingProcedureType; import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException; -import com.sap.sailing.domain.common.racelog.tracking.RaceNotCreatedException; +import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTrackingException; import com.sap.sailing.domain.common.racelog.tracking.TransformationException; import com.sap.sailing.domain.racelog.RaceLog; +import com.sap.sailing.domain.racelog.Revokable; import com.sap.sailing.domain.racelog.tracking.GPSFixStore; -import com.sap.sailing.domain.common.racelog.RacingProcedureType; +import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter; import com.sap.sailing.gwt.ui.shared.BulkScoreCorrectionDTO; import com.sap.sailing.gwt.ui.shared.CompactRaceMapDataDTO; import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO; @@ -396,15 +398,18 @@ public interface SailingService extends RemoteService { Map importWindFromIgtimi(List selectedRaces) throws Exception; - void addRaceLogTrackers(String leaderboardName) throws Exception, RaceNotCreatedException; - - void addRaceLogTracker(String leaderboardName, String raceColumnName, String fleetName) throws Exception, RaceNotCreatedException; - void denoteForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName) throws Exception; void denoteForRaceLogTracking(String leaderboardName) throws Exception; - void startRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName); + /** + * Performs all the necessary steps to start tracking the race. + * The {@code RaceLog} needs to be denoted for racelog-tracking beforehand. + * + * @see RaceLogTrackingAdapter#startTracking + */ + void startRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName) + throws NotDenotedForRaceLogTrackingException, Exception; void setCompetitorRegistrations(String leaderboardName, String raceColumnName, String fleetName, Set competitors); @@ -441,5 +446,9 @@ public interface SailingService extends RemoteService { void closeOpenEndedDeviceMapping(String leaderboardName, String raceColumnName, String fleetName, DeviceMappingDTO mapping, Date closingTimePoint) throws NoCorrespondingServiceRegisteredException, TransformationException; + /** + * Revoke the events in the {@code RaceLog} that are identified by the {@code eventIds}. + * This only affects such events that implement {@link Revokable}. + */ void revokeRaceLogEvents(String leaderboardName, String raceColumnName, String fleetName, List eventIds); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index e867a802afd..7fd12874521 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -526,11 +526,6 @@ public interface SailingServiceAsync { void getLeaderboardsByEvent(EventDTO event, AsyncCallback> callback); - void addRaceLogTrackers(String leaderboardName, AsyncCallback callback); - - void addRaceLogTracker(String leaderboardName, String raceColumnName, - String fleetName, AsyncCallback callback); - void denoteForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName, AsyncCallback callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index c38f40a19fc..53d1775cafa 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -161,6 +161,7 @@ import com.sap.sailing.domain.common.racelog.FlagPole; import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.common.racelog.tracking.NoCorrespondingServiceRegisteredException; +import com.sap.sailing.domain.common.racelog.tracking.NotDenotedForRaceLogTrackingException; import com.sap.sailing.domain.common.racelog.tracking.TransformationException; import com.sap.sailing.domain.common.racelog.tracking.TypeBasedServiceFinder; import com.sap.sailing.domain.common.racelog.tracking.TypeBasedServiceFinderFactory; @@ -2031,8 +2032,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } else { leaderboardDTO.discardThresholds = null; } - leaderboardDTO.isDenotedForRaceLogTracking = false; - leaderboardDTO.raceLogTrackersCanBeAdded = false; + leaderboardDTO.isDenotableForRaceLogTracking = leaderboard instanceof RegattaLeaderboard; for (RaceColumn raceColumn : leaderboard.getRaceColumns()) { for (Fleet fleet : raceColumn.getFleets()) { RaceDTO raceDTO = null; @@ -2054,13 +2054,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S fleetDTO.raceLogTrackerExists = getService().getRaceTrackerById(raceLog.getId()) != null; fleetDTO.courseDefinitionInRaceLog = new LastPublishedCourseDesignFinder(raceLog).analyze() != null; - if (getRaceLogTrackingAdapter().isDenotedForRaceLogTracking(getService(), raceColumn, fleet)) { - leaderboardDTO.isDenotedForRaceLogTracking = true; - } - - if (getRaceLogTrackingAdapter().canRaceLogTrackerBeAdded(getService(), raceColumn, fleet)) { - leaderboardDTO.raceLogTrackersCanBeAdded = true; - fleetDTO.raceLogTrackerCanBeAdded = true; + if (! raceLog.isEmpty()) { + leaderboardDTO.isDenotableForRaceLogTracking = false; } } } @@ -4024,40 +4019,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } - private void addRaceLogTracker(Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) throws Exception { - RegattaIdentifier regatta = null; - if (leaderboard instanceof RegattaLeaderboard) { - regatta = ((RegattaLeaderboard) leaderboard).getRegatta().getRegattaIdentifier(); - } - - getRaceLogTrackingAdapter().addRace(getService(), regatta, leaderboard, raceColumn, fleet, -1); - } - - @Override - public void addRaceLogTracker(String leaderboardName, - String raceColumnName, String fleetName) throws Exception { - Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); - RaceColumn raceColumn = getService().getLeaderboardByName(leaderboardName).getRaceColumnByName(raceColumnName); - Fleet fleet = raceColumn.getFleetByName(fleetName); - - addRaceLogTracker(leaderboard, raceColumn, fleet); - } - - @Override - public void addRaceLogTrackers(String leaderboardName) throws Exception { - Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); - RaceLogTrackingAdapter adapter = getRaceLogTrackingAdapter(); - - Map> canBeLoaded = adapter.listRaceLogTrackersThatCanBeAdded(getService(), leaderboard); - for (RaceColumn raceColumn : canBeLoaded.keySet()) { - if (canBeLoaded.get(raceColumn) != null) { - for (Fleet fleet : canBeLoaded.get(raceColumn)) { - addRaceLogTracker(leaderboard, raceColumn, fleet); - } - } - } - } - @Override public void denoteForRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName) throws Exception { @@ -4065,13 +4026,13 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S RaceColumn raceColumn = getService().getLeaderboardByName(leaderboardName).getRaceColumnByName(raceColumnName); Fleet fleet = raceColumn.getFleetByName(fleetName); - getRaceLogTrackingAdapter().denoteForRaceLogTracking(getService(), leaderboard, raceColumn, fleet, null); + getRaceLogTrackingAdapter().denoteRaceForRaceLogTracking(getService(), leaderboard, raceColumn, fleet, null); } @Override public void denoteForRaceLogTracking(String leaderboardName) throws Exception { Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); - getRaceLogTrackingAdapter().denoteForRaceLogTracking(getService(), leaderboard); + getRaceLogTrackingAdapter().denoteLeaderboardForRaceLogTracking(getService(), leaderboard); } private RaceLog getRaceLog(String leaderboardName, String raceColumnName, String fleetName) { @@ -4080,16 +4041,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S return raceColumn.getRaceLog(fleet); } - @Override - public void startRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName) { - RaceLog raceLog = getRaceLog(leaderboardName, raceColumnName, fleetName); - - RaceLogEvent event = RaceLogEventFactory.INSTANCE.createStartTrackingEvent(MillisecondsTimePoint.now(), - getService().getServerAuthor(), raceLog.getCurrentPassId()); - - raceLog.add(event); - } - @Override public Iterable getCompetitorRegistrations(String leaderboardName, String raceColumnName, String fleetName) { return convertToCompetitorDTOs( @@ -4397,4 +4348,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S raceLog.add(event); } } + + @Override + public void startRaceLogTracking(String leaderboardName, String raceColumnName, String fleetName) + throws NotDenotedForRaceLogTrackingException, Exception { + Leaderboard leaderboard = getService().getLeaderboardByName(leaderboardName); + RaceColumn raceColumn = leaderboard.getRaceColumnByName(raceColumnName); + Fleet fleet = raceColumn.getFleetByName(fleetName); + + getRaceLogTrackingAdapter().startTracking(getService(), leaderboard, raceColumn, fleet); + } } \ No newline at end of file